Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Making Xcode embed necessary dylibs

I'm trying to do something pretty simple and typical, which is use dynamically linked libraries in my Xcode project and then deploy with all the necessary libraries embedded.

However I must be doing something the wrong way, because Xcode 8 won't allow me to embed .dylib files, only frameworks! The picture below is what happens when I try to add anything to Embedded Binaires, the dylibs just don't show up, and Add Other... adds them to the project but not to Embedded Binaries.

Xcode not allowing me to add any of the dylibs as embedded binaries

There must be a very simple way to do it but I just can't find it...

Epilogue

So apparently since I do need to run a script that calls install_lib_tool I made a pretty universal script that will change anything that has /local/ in its path to the path of the embedded copy:

#!/bin/sh

app=$BUILT_PRODUCTS_DIR/$EXECUTABLE_PATH
fw_path=$BUILT_PRODUCTS_DIR/$FRAMEWORKS_FOLDER_PATH
app_dyl_list=(`ls $fw_path | grep dylib`)

function change_paths {
    local bin=$1
    echo change_path $bin
    dyl_list=(`otool -L $bin | grep local | awk '{print $1}'`)

    for dyl in ${dyl_list[*]}; do
        libname=$(basename $dyl)
        libname=${libname%%.*}
        actual_libname=(`ls $fw_path | grep $libname | xargs basename`)
        install_name_tool -change $dyl "@executable_path/../Frameworks/$actual_libname" $bin
        printf "\t%s edited\n" $actual_libname
    done
}

change_paths $app
for dyl_bin in ${app_dyl_list[*]}; do
    change_paths $fw_path/$dyl_bin
done

Then all it takes is adding a Run Script step after the copying of the dylibs to just run it with no arguments (the environment variables contain everything needed).

like image 317
Michel Rouzic Avatar asked Feb 03 '17 11:02

Michel Rouzic


People also ask

Should Xcframework be embedded?

While debugging in the simulator, Xcode would load all frameworks needed even if they're set as "Do Not Embed". However, if you directly run app or debug in the real device, "image not load" would occur for those frameworks set as "Do Not Embed". So, we should embed all third-party frameworks I think.

What is embedded binaries in XCode?

3 Answers. Save this answer. Show activity on this post. Embedded binaries are binary files that are copied to your application bundle when you build the project.


1 Answers

I never used "Embedded Libraries", but instead a copy phase to copy all needed 3rd party libs and those created by the various targets in the project. You can simply drag dylibs you wanna copy from the "Frameworks" and "Products" outline nodes into this copy phase (or add them via the "+" button). XCode will also automatically sign each lib, if that's enabled (which it is by default):

enter image description here

Take also a look at the "Installation Directory" setting. You should set this value to @executable_path/../Frameworks (provided this is your actual framework folder, at least that is the recommended one). The value is used by XCode to set the ID for your dylib and is essential to make them load correctly

enter image description here

You can also use a tool like MacDependency to check the details of your .app, .dylib and .framework packages. It will show you also which other dylibs a library depends on and under which path it expect them. That path must be the same as the ID of the linked library or loading will fail.

Another very useful tool is otool, which comes with XCode. It gives similar infos like MacDependency and more. Here is a list of dependencies for a dylib with paths and versions expected by it:

Mikes-iMac:Debug mike$ otool -L libcdbc.dylib
libcdbc.dylib:
    @executable_path/../Frameworks/libcdbc.dylib (compatibility version 1.0.0, current version 1.0.0)
    @executable_path/../Frameworks/libwbbase.dylib (compatibility version 1.0.0, current version 1.0.0)
    @executable_path/../Frameworks/libgrt.dylib (compatibility version 1.0.0, current version 1.0.0)
    @executable_path/../Frameworks/libgmodule-2.0.0.dylib (compatibility version 3401.0.0, current version 3401.2.0)
    @executable_path/../Frameworks/libgthread-2.0.0.dylib (compatibility version 3401.0.0, current version 3401.2.0)
    @executable_path/../Frameworks/libglib-2.0.0.dylib (compatibility version 3401.0.0, current version 3401.2.0)
    @executable_path/../Frameworks/libmysqlcppconn.7.1.1.8.dylib (compatibility version 7.0.0, current version 7.1.1)
    /usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 307.4.0)
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1238.0.0)

Another discussion about loader paths is here: How to set dyld_library_path in Xcode.

If your app or a library you created expects dylibs from a system location instead of a relative one then it could mean you linked the wrong lib to it. In the "Link Binary" build phase you can select the libraries to link against and the selection dialog lists all your project targets there. Also for the linker list you can simply drag a dylib from the "Products" node in your project outline into it to make the setting. Also for such libs the requirement to set a proper path holds true. You can do that with a script that changes the ID after the copy phase or you keep a copy of these libs somewhere else, change the IDs of them once (e.g. after you downloaded them) and copy them from there to your final app.

like image 171
Mike Lischke Avatar answered Sep 30 '22 19:09

Mike Lischke