Xcode not searching #rpath for dylibs? - xcode

In my Xcode project, I have several dynamic libraries that I built with a prefix of "#rpath/lib". I added a "copy files" build phase that includes these dylibs. They are installed to a folder called lib in Frameworks. I also set a Runpath Search path of "#loader_path/../Frameworks" which should be substituted as #rpath when the executable runs. DLYD looks at my binary's runpath which I examine using tool -l command on the binary. This produces:
Load command 47
cmd LC_RPATH
cmdsize 40
path #loader_path/../Frameworks (offset 12)
So I assume that when my binary runs, DLYD will resolve the path the lib folder via the MACH-O binary.
When I run my project, I use Activity Monitor to examine the files the binary has open. I don't see my dynamic libraries being referenced from #loaderpath/../Frameworks/lib where they reside, instead I see them being referenced from /usr/local/lib.
What Xcode settings do I set so my dynamic libraries are properly found? I used the User-Defined build setting 'DYLD_PRINT_BINDINGS' to see what is linking, and I don't see my libraries being linked even though they are eventually linked against the libraries in /usr/local/lib

I have found the script I developed a while back which I used to copy .dylibs into the .app's Framework directory and detect dependent libraries, fixing the library references using install_name_tool. This should be set as a post-build script.
https://github.com/trojanfoe/xcodedevtools/blob/master/copy_dylibs.py
I haven't tested it for a while. The repo also contains the script I now use to bump build numbers, as per this question of mine.

Related

Make Qt's Debugger Aware of DLL Dependency in CMake (Windows)

In Windows, I have a CMake build under Qt that locates, via a find_library command, an A.lib file that is in a separate directory relative to its A.dll file. The A.lib file is then linked using a target_link_libraries command.
As far as the build goes, CMake has no problem not having the symbols in the .lib file defined until runtime.
At runtime, I use windeployqt to successfully assemble all dependent libraries (indluding the A.dll file) into a separate deploy directory from the build directory, and I'm able to run there just fine.
However, to run via Qt's debugger, Qt runs the executable from the build folder rather than the deploy folder. By default, Qt attempts to add the build library folders to the PATH variable as well. Admirably, it also attempts to scan dependencies such as the Qt libraries and the path to A.lib and adds them to the PATH as well. Unfortunately, it does not add the path to A.dll, resulting in a failed DLL dependency error in the launched thread.
I can easily get around this by adding the path to A.dll to the PATH in Qt's run section of the Project tab. However, I'm curious, is it possible to make Qt catch this dependency via some CMake command and automatically add A.dll to the PATH, similar to how it caught other dependencies correctly? I'm not sure how Qt attempts to find dependencies, but in a previous QMake iteration of the build, the path to A.dll was appended automatically.
As of Qt 7.0.1, Qt added a workaround that allows the user to add dll paths to CMake via a target_link_directories command and have those parsed by Qt from the Cmake file-api to add to the PATH variable in Windows.
This fix is in Qt Creator 7.0.1, see the change summary here:
https://codereview.qt-project.org/c/qt-creator/qt-creator/+/404290
And the issue prompting this change on the official Qt website (which is where I should've looked first):
https://bugreports.qt.io/browse/QTCREATORBUG-27201?workflowName=Qt+Bug+Tracking+v2.4&stepId=8
It should be noted that a workaround for this issue was added to Qt Creator at an earlier point (I'm not sure exactly when) that looked one directory above the \lib folder for a \bin folder (see the code that implements this workaround, and performs the CMake file-api queries in general here).
The latter workaround happened to not work for my particular MSVC-built library folders, since there the lib and bin folders are themselves in folders with architecture and OS information, with a common parent three and two folders above, respectively.
Updating Qt Creator to 7.0.1 and using the target_link_directories command solves this issue.

Deploying cocoa application and its C++ dylib how to pack them?

I am new to cocoa and mac development. I have written an application which is combination of objective-c using cocoa framework and backend written in C++ library dylib.
I am using xcode 4.6 and have the above two projects Cocoa app and my C++ library. C++ is also my own project.
Now it is time for deployment. I want to make a pkg installer for it.
I could run/debug it in the xcode 4.6 because I had added search library path in the object-c project settings to be the output directory of the C++ project. Therefore it could find the dependency and run without crash.
Now in the Objective-C project tree inside the xcode I see products -> mysoftware.app file. if I find the location of this mysoftware.app file in the finder and run it, it crashes. I open the package contents of this app files and I see contentsfollowing structure
contents\(info.plist, MacOS, pkginfo, resources )
I do not see my C++ library in there, when I run mysoftware.app directly double clicking it crashes as it can not find the dylib I see the stack trace in the report window it can not find dylib, complaning that library not found usr/local/lib/mylib.dylib
I have also manually put the dylib file in the .app within the MacOS where my executable is, hoping that it will find the lib from the same directory, it did not , gave the same message above and looking from the the sane location /usr/local/lib/mylib.dylib
So my question is how do I resolve dependency of .app package for deployment, should I need to put the dylib inside the .app package ? how do I do that and then my next step would be to put this single .app thing in the pkg installer,
Thanks
This is what worked for me:
Drag the dylib into your Frameworks.
Add a Copy Files build phase, destination Frameworks and put the dylib there.
Add a Run Script phase which has the following script:
MYLIBNAME=libmylib.dylib
install_name_tool -change /usr/local/lib/$MYLIBNAME #executable_path/../Frameworks/$MYLIBNAME "$BUILT_PRODUCTS_DIR/$EXECUTABLE_PATH"
That's it. The script tells your app to load the dylib from the right place - otherwise it will complain about not finding the dylib at runtime.
Note that you don't need to change anything in the dylib itself - it could be supplied from elsewhere.
I resolved it so I am putting up this answer to help others who want to do the same.
The dylib has to go in one of the sub folders within the application bundle (i.e. mysoftware.app). Could be MacOS, Frameworks or any sub folder we decide to put it in.
The first step is in the target settings of our dylib, we set the install path to be relative to the app bundle (mysoftware.app), so in Xcode target settings of lib I set it to:
#executable_path/../frameworks
You can also use #rpath (You might want to research on that, I think it is more flexible than #executable_path)
Xcode will change the install name as well for our dylib.
Then in the Objective-C project using our dylib in the Project settings -> Build phases -> Link -> we drag our dylib here from the products node of the dylib project.
In the Objective-C/Cocoa project, the last step is to add a build step named copy files, and it should show a combo box telling you the target folder of the bundle. I set it to frameworks (this will depend on that relative path you choose when setting install path of your dylib) . The second part of the 'Copy Files' build step is to provide the souce file to copy. That's our dylib file that we want to pack in the bundle's Frameworks folder. So drag the dylib file from the products (of your dylib project) to the source file of the build step.
And that's it.
Now when we build the Objective-C or Cocoa project, if our build steps and install_path , etc are correctly configured, it should build fine. After a successfull build of the Cocoa project, go to Products -> mysoftware.app -> Locate in the Finder and when you run it, it should run fine. Since the dependency dylib is in the Frameworks folder of the bundle and correctly linked. You can see the package contents of the bundle to see if the Frameworks folder contains your dylib file.
To my surprise, the path where a dylib is stored has to be part of the dylib. So when a project links to this dylib it will copy the same path in itself, so when we run the Cocoa app which was linked to that dylib, it will look for it at exactly the same path which it copied from inside the dylib and we are responsible for telling the dylib where it exists. In the form of install_path, etc.
There are tools to manually update the dylib's install path stored in the Cocoa project using that dylib. If update the path of an existing bundle using these tools it should be changed in the client of the dylib, not required in the dylib itself.
If we've the code then we can change it in Xcode as instructed above.
otool -L my.dylib for example can be used to see the dylib install path of an existing binary lib
install_name_tool -change can be used to update the install path of existing binary lib

How to set dyld_library_path in Xcode

I am new to Xcode and Mac environment. I am using some dynamic and static libraries like boost, Clucene, etc. I have all the libraries under
MyApp.app/Contents/Resources
I want to set this path as the app's dyld_library_path. I tried editing XXX.plist file like
DYLD_LIBRARY_PATH /mypath/xxx
and setting the environment variable and argument in Xcode Nothing work.
but if I run a shell script like below without double clicking the app in my .dmg it works
#!/bin/bash
clear
cd /Volumes/xxx/myapp.app/Contents/MacOS
export DYLD_LIBRARY_PATH="/Volumes/xxx/myapp.app/Contents/Resources"
./myapp
I am sure this is not the proper way to do this. Is there proper way to set dyld_library_path every time I execute my app?
EDIT:
It also works if u mannualy copy all ur library to clients /usr/lib path... i guess this is also not a proper way to do it.
Setting DYLD_LIBRARY_PATH isn't the best way to solve this problem. It's working around the fact that you've misinformed dyld as to where to find your libraries.
If you run otool -L MyApp.app/Contents/MacOS/MyApp you'll see the paths to the libraries that MyApp wants to load. If any library isn't found at the specified path then dyld will look for the library in the locations specified by DYLD_FALLBACK_LIBRARY_PATH. Setting DYLD_LIBRARY_PATH causes dyld to look for the library in the given locations ahead of the path that the otool command above returned.
The best way to solve this problem is to have your application specify the correct location of the libraries to start with so that setting DYLD_LIBRARY_PATH is not necessary. To do this you need to do the following:
Set the library identifier of each of the libraries that you're bundling inside your application to an #rpath-relative value. You can do this using install_name_tool -id #rpath/libFoo.dylib libFoo.dylib.
Add a Copy Files build phase to copy the libraries in to your application wrapper. MyApp.app/Contents/Frameworks is a typical location. MyApp.app/Contents/Resources should be avoided since binaries aren't resources in the usual sense of the term.
Specify a run path search path when linking your application. This gives the linker a list of paths to use to resolve any #rpath variables that it encounters in any load commands. If you're copying the libraries to MyApp.app/Contents/Frameworks you'll want to specify a run path search path of #loader_path/../Frameworks. You can do this via the LD_RUNPATH_SEARCH_PATHS (Runpath Search Paths) configuration setting in Xcode on your application target.
After doing all this you should be able to re-run the otool command mentioned above and see that the paths to your library are using #rpath-relative paths. You should then be able to run otool -lV MyApp.app/Contents/MacOS/MyApp and see an LC_RPATH load command specified with a value of #loader_path/../Frameworks. Finally, you should be able to run your application and see that it finds the libraries within its Frameworks directory without having DYLD_LIBRARY_PATH set!

Setting dylib paths as a XCode build step

I have a Cocoa application as XCode project that has several supplementary bits of functionality as dylib targets.
When XCode builds the project, it places all the build outputs in a single folder: The .app bundle and the dylib files. And when executed from the XCode debugger, the .app launches.
I can't however launch the application from finder.
How do I setup XCode to 'deploy' the app in a standalone state? I have found that I can use ld on the actual app binary to contain a relative path to the dylibs: #executable_path/../../mylib.dylib
Running a script after each build seems wrong: there must be some way (that Im totally missing) to do this easily from inside XCode - it must be a common issue surely?
It looks like that XCode supports having #executable_path, #loader_path and #rpath used in the Target Info > Build > Linking > Dynamic Library Install Name setting (LD_DYLIB_INSTALL_NAME) setting.
The help text says: "Sets an internal "install path" (LC_ID_DYLIB) in a dynamic library. Any clients linked against the library will record that path as the way dyld should locate this library"
This seems very promising, but usability is a problem if I need to link dylibs in multiple paths against a common library - the relative path is going to be different each time.
Running my testapp from finder, I get the following (relevant) error text
Dyld Error Message:
Library not loaded: #executable_path/../../util.dylib
Referenced from: /Volumes/data/Code/TestApp/build/Debug/TestApp.app/Contents/MacOS/TestApp
Reason: image not found
util.dylib is in /Volumes/data/Code/TestApp/build/Debug/ so I am confused :/
You should use a Copy Files build phase to copy the dylib to the app's bundle when building the app. You'll want to copy it to Frameworks. You can then set the install path to #executable_path/../Frameworks/mylib.dylib.

Xcode, building and dylibs

I've looked at a few related questions and cannot seem to find a solution for myself.
Basically I'm using the libmp3lame.dylib in my Xcode project. The install process for lame produced the .dylib and placed it in usr/local/lib and to get Xcode to build and run the project I changed the Library Search Paths to include the above folder. This works fine.
Now it's come to producing a release version and I want to include the .dylib in the bundle so that the user doesn't have to put up with an install phase or anything similar. I created a copy files phase of the target and this dumps the .dylib into the Frameworks folder in the contents of the bundle. However, running otool on the binary shows that instead of using the .dylib inside the bundle, the compiler has linked it to the usr/local/lib version (even if I delete that version).
Looking at the other results in the otool output I have other frameworks being linked to inside the bundle, just not the .dylib. Looking at the properties for both these frameworks and the .dylib in Xcode I can't see any differences other than file type.
My searching suggests I need to use rpath or similar, but I've no clue where to apply this in Xcode.
My workaround for this issue was to do the following in terminal (I've used Automator to, well, automate this):
install_name_tool -id #executable_path/../Frameworks/libmp3lame.0.0.0.dylib ~/path/to/lib/in/app/libmp3lame.0.0.0.dylib
install_name_tool -change /usr/local/lib/libmp3lame.0.dylib #executable_path/../Frameworks/libmp3lame.0.0.0.dylib ~/path/to/app/Contents/MacOS/AppName
Basically swapping the path to the library from the one in the usr local lib to the one included in the bundle.
My tip is to look at the build output, how does it actually run ld?

Resources