How can I link a dynamic library in Xcode? - c++

I am currently developing a program in Qt and it uses the library libqextserialport.1.dylib.
I build it and run in x-code and it spits back:
dyld: Library not loaded: libqextserialport.1.dylib
Referenced from: /Users/samuelreh/Desktop/QtOpenCV/build/Debug/QtOpenCV.app/Contents/MacOS/QtOpenCV
Reason: image not found
The library is located in /Users/samuelreh/Desktop/QtOpenCV/qextserialport/build/.
I can run my program by changing to the executable folder /Users/samuelreh/Desktop/QtOpenCV/build/Debug/QtOpenCV.app/Contents/MacOS/ and entering:
install_name_tool -change libqextserialport.1.dylib /Users/samuelreh/Desktop/QtOpenCV/qextserialport/build/libqextserialport.1.dylib QtOpenCV
I know there is probably many solutions besides this. Anybody know the best / most-elegant / easiest to do from x-code?

I've just done exactly this, with a Module Bundle project. This was being included into a larger project with a separate executable.
I added a "Copy dylibs to frameworks" step, which copied the dylibs to /Foobar.bundle/Contents/Frameworks/Foobar/. Then I added a Run Script Phase to run as the final step, to fix the install names of the dylibs in the executable:
install_name_tool -change libBobDylan.dylib #executable_path/../Plugins/Foobar.bundle/Contents/Frameworks/Foobar/libBobDylan.dylib path/to/build/product/Foobar.Bundle/Contents/MacOS/Foobar
Of course, libBobDylan.dylib also linked to libBillyIdol.dylib. So I had to add another Run Script Phase at the very start of the Target to fix the install names here:
install_name_tool -change libBillyIdol.dylib #executable_path/../Plugins/FooBar.bundle/Contents/Frameworks/Foobar/libBillyIdol.dylib local/path/to/libBobDylan.dylib
I had over a dozen of these to link against; I had to persuade the supplier of the dylibs to pad their header to accommodate my many install_name changes ...

If I understand your problem correctly, your app is building fine, no errors when linking, but when you try to launch it the library cannot be found.
That's not surprising, since the dylib file is in some arbitrary directory not on the system path. You either need to copy it into /usr/lib (probably not a good idea) or include it in the application bundle. The latter is probably the better approach.
I've never tried it, but apparently you need to use a Copy Files Build Phase to put the dylib inside your bundle and then configure Xcode so that your executable will know where to find it.

You just drag the library from the directory onto your Xcode project, best into resources but it does not matter (I believe). I tried with and without checking the 'copy files into bundle' and it work in both cases, not sure if you need to include it in bundle for deployment.
I've tested this with sqlite3 and cocoa application (cocoa-touch).

Related

How can I bundle a dylib within a Mac app bundle in Qt?

I have an application and a dylib that it links against. It is my understanding that the application bundle should contain the dylib. Is that correct?
Is there a way to copy the dylib to the application bundle when built?
Thanks,
Alan
Is there a way to copy the dylib to the application bundle when built?
Well, sure -- with a little shell scripting, anything is possible. :)
In your build script, after you've called macdeployqt, but before you've done any code-signing, you'd copy the .dylib file over into the Contents/Frameworks inside your .app folder.
The trick after that is convincing the executable to look for the library in its new location rather than the location it was in when you linked the executable. (If you do a "otool -L ./MyProgram.app/Contents/MacOS/MyProgram" you will see the places where the program is looking for shared libraries, and you will see that it is not looking for your .dylib file in the Frameworks folder, yet)
To do that you use the install_name_tool command, e.g.:
install_name_tool -change /the/old/path/to/the_library_name.dylib "#executable_path/../Frameworks/the_library_name.dylib" ./MyProgram.app/Contents/MacOS/MyProgram
After doing that you can run "otool -L" on your executable again to verify to your satisfaction that the executable is now set to look for the .dylib file inside the Frameworks folder.

How to distribute code with qt?

I've got C++ application which is using Qt, I'm building it with cmake and linking using following:
target_link_libraries(myApp Qt5::Widgets Qt5::OpenGL ...)
it works fine but when I'm trying to distribute it it's failing because of missing qt libraries.
I was trying to get libraries from my local qt installation Qt/5.4/clang_64/lib/QtCore.Framework/Versions/5/QtCore and other with similar paths and put them near myApp but it doesn't help. It's still trying to get those libraries from local qt installation and if I rename folder of local qt installation it fails.
How to distribute my applications which is using qt libraries on OSX/Mac?
Qt 5.5 comes with a helper tool called macdeployqt. You can run it from the command line, it will produce a valid .app (or even a .dmg containing the app if you ask for it). It's fairly straightforward to use, there are only a few options (like creating a dmg output, using debug libraries...) if you depend only on Qt.
If you have more dependancies that are dynamically linked, then you'll probably need to embed them as well in the application bundle (the .app folder).
From the QT site:
But when you are deploying the application, your users may not have the Qt frameworks installed in the specified location. For that reason, you must either provide the frameworks in an agreed upon location, or store the frameworks in the bundle itself. Regardless of which solution you choose, you must make sure that the frameworks return the proper identification name for themselves, and that the application will look for these names. Luckily we can control this with the install_name_tool command-line tool.
The install_name_tool works in two modes, -id and -change. The -id mode is for libraries and frameworks, and allows us to specify a new identification name. We use the -change mode to change the paths in the application.
Let's test this out by copying the Qt frameworks into the Plug & Paint bundle. Looking at otool's output for the bundle, we can see that we must copy both the QtCore and QtGui frameworks into the bundle. We will assume that we are in the directory where we built the bundle.
mkdir plugandpaint.app/Contents/Frameworks cp -R
/path/to/Qt/lib/QtCore.framework
plugandpaint.app/Contents/Frameworks cp -R /path/to/Qt/lib/QtGui.framework
plugandpaint.app/Contents/Frameworks
First we create a Frameworks directory inside the bundle. This follows the Mac OS X application convention. We then copy the frameworks into the new directory. Since frameworks contain symbolic links, and we want to preserve them, we use the -R option.
install_name_tool -id
#executable_path/../Frameworks/QtCore.framework/Versions/4.0/QtCore
plugandpaint.app/Contents/Frameworks/QtCore.framework/Versions/4.0/QtCore
install_name_tool -id
#executable_path/../Frameworks/QtGui.framework/Versions/4.0/QtGui
plugandpaint.app/Contents/Frameworks/QtGui.framework/Versions/4.0/QtGui
Then we run install_name_tool to set the identification names for the frameworks. The first argument after -id is the new name, and the second argument is the framework which identification we wish to change. The text #executable_path is a special dyld variable telling dyld to start looking where the executable is located. The new names specifies that these frameworks will be located "one directory up and over" in the Frameworks directory.
install_name_tool -change
path/to/Qt/lib/QtCore.framework/Versions/4.0/QtCore
#executable_path/../Frameworks/QtCore.framework/Versions/4.0/QtCore
plugandpaint.app/Contents/MacOs/plugandpaint install_name_tool -change path/to/qt/lib/QtGui.framework/Versions/4.0/QtGui
#executable_path/../Frameworks/QtGui.framework/Versions/4.0/QtGui
plugandpaint.app/Contents/MacOs/plugandpaint
Now, the dynamic linker knows where to look for QtCore and QtGui. Then we must make the application aware of the library locations as well using install_name_tool's -change mode. This basically comes down to string replacement, to match the identification names that we set for the frameworks.
Finally, since the QtGui framework depends on QtCore, we must remember to change the reference for QtGui:
install_name_tool -change
path/to/Qt/lib/QtCore.framework/Versions/4.0/QtCore
#executable_path/../Frameworks/QtCore.framework/Versions/4.0/QtCore
plugandpaint.app/Contents/Frameworks/QtGui.framework/Versions/4.0/QtGui
After all this we can run otool again and see that the application
will look in the right locations.

How do I build and use a dynamic library on Mac OS X?

I have a very simple question that I've been trying to figure out for the last 6 hours or so. I want to simply build a dynamic library on Mac OS X, and then build an application using that library. I've created the .dylib and compiled the test application with it, but when I run the application I get:
Joes-Mac-Pro:Desktop Joe$ ./test
dyld: Library not loaded: ./lib/simple_library.dylib
Referenced from: /Users/Joe/Desktop/./test
Reason: image not found
Trace/BPT trap: 5
I've tried making a lib folder in the executable directory and putting the dylib inside, same error. I've tried putting the dylib in the executable path itself, same error. I've tried using install_name_tool to change the path to the dylib in the executable, nothing changes, same error. I've tried building the test application with -headerpad_max_install_names and then using install_name_tool to change the path. Still nothing changes. Same error.
Is what I'm trying to do not possible with the Mac operating system? I'm new to this platform, and am used to things like this working without a hitch on Windows and GNU/Linux. Also, I'm trying to do all this with the command line. I would very much prefer to avoid XCode.
Edit: Oops, I derped. Turns out I made a typo in my install_name_tool arguments. It's working fine now.
install_name_tool is the right tool.
Try otool your_binary to see which dylib are missing.
Also be sure your binary and the linked library are build for the same architectures.
You'll need to ensure that DYLD_LIBRARY_PATH includes the directory where your library resides.
DYLD_LIBRARY_PATH
This is a colon separated list of directories that contain libraries. The dynamic linker searches these directo-
ries before it searches the default locations for libraries. It allows you to test new versions of existing
libraries.
For each library that a program uses, the dynamic linker looks for it in each directory in DYLD_LIBRARY_PATH in
turn. If it still can't find the library, it then searches DYLD_FALLBACK_FRAMEWORK_PATH and DYLD_FALL-
BACK_LIBRARY_PATH in turn.
Use the -L option to otool(1). to discover the frameworks and shared libraries that the executable is linked
against.
The various details of dynamic linking are documented in the dyld man page.

How can I get Xcode to link and debug an app with Boost Filesystem?

TL;DR
Objective-C app linked with static library that dynamic links Boost Filesystem. App can be run from output directory using Terminal, but trying to run from Xcode debugger or Finder gives error dyld: Library not loaded: libboost_filesystem.dylib <snip> Reason: image not found.
Problem
In my Xcode project I have a structure that looks like this:
MainProject (Objective-C)
- static_lib_that_uses_filesystem (C++)
To get everything to link, I added libboost_system and libboost_filesystem dylibs to the "Link Binary with Libraries" build phase in MainProject.
When I try to run the app from either Xcode or Finder I get:
sharedlibrary apply-load-rules all
warning: Unable to read symbols for libboost_filesystem.dylib (file not found).
warning: Unable to read symbols from "libboost_filesystem.dylib" (not yet mapped into memory).
warning: Unable to read symbols for libboost_system.dylib (file not found).
warning: Unable to read symbols from "libboost_system.dylib" (not yet mapped into memory).
[Switching to process 43957 thread 0x0]
dyld: Library not loaded: libboost_filesystem.dylib
Referenced from: /Users/ssteele/Library/Developer/Xcode/DerivedData/MainProject-dqrhyuarllykslftblocjdzxlran/Build/Products/Debug/MainProject.app/Contents/MacOS/MainProject
Reason: image not found
I added a build stage to copy the dylibs to the Frameworks directory in the bundle, this doesn't help. I changed this to copy them to the Executables directory which also didn't help.
Having them in the Executables directory does allow me to run the app from Terminal.
How can I get the app to find the dylibs when run from Finder/Xcode?
Background Info
I'm using Xcode 4.2 on Lion and currently targeting Lion only. I built my shared libraries for filesystem like this:
./b2 threading=multi macosx-version=10.7 --with-filesystem stage
This creates libboost_system.dylib, libboost_filesystem.dylib, and also .a equivalents in the stage/lib directory, I'm referencing them in the project directly from there.
Dynamic libs (dylibs) on OSX bake in the path that they should be loaded from. For example...
/usr/lib/some_awesome.dylib.
When you link to a dylib, the linker embeds this path in your executable as the place to look for it at runtime. This is fine and easy with installed libs, but for relative path linking it's more complicated.
When you build the boost libs, they just get their names embedded rather than a full or relative path (i.e. libboost_system.dylib rather than /usr/lib/libboost_filesystem.dylib). You should be able to change this with the dll-path option, but that seems broken currently.
To fix your problem you either need to get the correct path relative to your application embedded (e.g. #executable_path/libwhatever.dylib) into the dylibs somehow, which would probably require the bjam dll-path option to work, or instead you can fix your executable to look in a different location.
To do this, use something like the following as a script step in your build:
install_name_tool -change libboost_filesystem.dylib #executable_path/libboost_filesystem.dylib$BUILT_PRODUCTS_DIR/$EXECUTABLE_PATH
Note that if you have multiple dylibs that reference each other with broken paths, you'll need to fix the paths between them too, e.g.
install_name_tool -change libboost_system.dylib #executable_path/libboost_system.dylib$BUILT_PRODUCTS_DIR/$EXECUTABLE_FOLDER_PATH/libboost_filesystem.dylib
The following is a good article on this: Creating working dylibs
The issue is that boost needs to be installed e.g. b2 ..... install. This copies the libraries and headers into /usr/local/lib and /usr/local/include.
OSX dynamic libraries only run from the directory that they are built for.
You can change the install directory by using the -prefix argument to boost build. However the libraries would still need to be in the same directory for all users.
There should be a way of building boost as a framework and/or embedding #executable_path in the library.
An alternative is to use boost's static libraries - build the static only or delete the dynamic ones, Xcode looks for dynamic before static. If using static then the path to the libraries does not matter at run time as all the code is now in the executable.
I think you need to add the path to the directory where you saved libboost_filesystem.a in the "library search paths"
Click on your project profile -> build settings -> expand "Search path" -> "library search paths"

How can I find libraries to load them dynamically with dlopen

In the project I am working on, we provide the possibility to dynamically load additional features. For that we use dlopen.
To find this libraries we have something we call module path. There we have a default path, where the shared libraries are (a lot of them are shipped).
At the moment we have two default paths: we first look in the build directory for the shared library and afterwards in the install directory. This is because it should also be possible to run the application without installing it (so in that case it needs to look first in the build directory).
Now the problem ist, if a user builds the application from source and installs it with make install, the libraries in her build directory are loaded by default. This will result in a crash. So it only works if the user afterwards removes or renames the build directory.
No the question: is there a trick (either by C++ or by the build system) to know whether the application is installed or not. The problem is, that the functionality is implemented in a shared library and the implemented way to search for modules has to work also for other applications that link against our library (so we can not rely on the path of the executable). We use CMake as a build system.
To make the situation even harder, the solution has to work on Windows, Linux and Mac OS X.
EDIT:
I further investigated and the problem is more complicated. This is the situation:
There is a small executable a
Furthermore there is a "main" library main.so
then there is a dynamically loaded library lib.so
lib.so links against main.so
The problem is, that lib.so has the absolute path to main.so in the build directory in its rpath. Thanks to the tip of #MSalters I now was able to make a hack to make sure to load the correct version of lib.so (the one in the install directory) but since it has the build path in the rpath it loads the wrong main.so (so in fact there are two copies of main.so in the memory - this messes things up).
Is there a way to remove this reference to the build path from the library? I tried all options of cmake related to rpath without success
Can't you check where the executable itself is? If it's in the build directories, use build libraries -- if it's in the install, use install?
getcwd() has equivalents on all of those platforms, but it might not be what you want -- it depends on how you run the executable.
To get the process's location is system specific, I think, but it shouldn't be too hard to wrap that.
The installed version should not have the build directory in the rpath.
You might want to do the linking twice (once for the build version and once for the installed version). Usually, on *nix systems, the installed binary has some static path where it tries to find plugins. You might define some environment variable (or command-line argument) to overload it for the build execution (and use a wrapper script to set it in the build environment).
Check how it is solved by some projects (Firefox for example).
I don't know much about windows system but I think the standard way of doing this is to search plugins in the same directory as the executable.