I've created a CLI version of my OS X app (which is an App Bundle). In my bundle version there's a pre-compiled .dylib that is normally placed within the directory where the executable resides.
This won't work for the command line version - is there a way to embed it within my executable?
If you want to distribute only binary version of your application which related of dylib's you may do this in next ways:
1. make pkg installer which will put dylib somewhere in the system
2. most of 3rd parties libraries supports building of static version (*.a) itself as well as dynamic version. So you can build static version of your libraries and link statically with them.
Related
I have created a MAC application with libraries 'libmysqlclient.a' and 'libmysqlclient.18.dylib' with Objective-C language in Xcode 6.3.1 in OSX Yosemite 10.10.3. Its working fine when running through Xcode. And I also archived the .app file to install the app in my MAC, its also working fine. But when i tried to install it in another mac, app crashed and shows the message
"dyld: Library not loaded: libmysqlclient.18.dylib Referenced from: /Users/developer/Documents/UntitledFolder/UserName/SampleApp.app/Contents/MacOS/SampleApp Reason: image not found".
From this message i understand that the particular MAC does not have “libmysqlclient.18.dylib”. So, here my question is "Is it mandatory that each MAC should have the library to install and run the application?". Can anyone give me the solution for this with detailed format of creating the .app file and installing it in other MAC systems.
Thanks in Advance.
You have included both a static (.a) and a dynamic (.dylib) library with your app. that do the same thing. A static library compiles into your program, making it larger. A dynamic library ships with your app. or is already install on your target system. If you ship it with your app., it should be in the Frameworks folder of your app. (you create this folder in Build Phases, Copy File). Use install_name_tool -id to set the library install name to #executable_path\..\Frameworks and also in Build Settings, set Runpath Search Paths to the same.
Can cmake configuration files also be used to automatically extend the system PATH variable to include the directory paths to all the installed executable applications and if it is possible (and a standard practice), how can I do this?
This way, as soon as I configure all the CMakeLists.txt files and everything compiles (and hopefully runs) nicely, I can start using the applications, and the path configuration would be packaged together with the build process. I am working with Linux and my code is written in C++, but since cmake is cross-platform, the question extends to other systems as well.
I'm unaware of any capability in CMake to do this. However, we based what we do what Cantera does. They upgraded to SCONS recently instead of their old build system, but the idea still applies.
Anyway, there's a script that CMake configures with the paths during the configure step and then installs somewhere. So once built on Linux, one would run make install then source ~/setup_cantera and it sets up all the variables needed.
We do the same thing for our libraries built with CMake. It's possible to detect which shell the user is running and configure an appropriate template script.
I am dealing with a weird behavior of XCode:
dyld: Library not loaded: /Library/Frameworks/SBJson.framework/Versions/A/SBJson
Basically it ignores my Runpath Search Path (LD_RUNPATH_SEARCH_PATHS) configuration that is actually #loader_path/../Frameworks.
I am not able to load any embedded framework in this moment :/
otool says
otool -L /Users/kilian/Library/Developer/Xcode/DerivedData/r-ghohkslxtxgpnuepmblogfjtuefx/Build/Products/Debug/r.app/Contents/MacOS/r
/Users/kilian/Library/Developer/Xcode/DerivedData/r-ghohkslxtxgpnuepmblogfjtuefx/Build/Products/Debug/r.app/Contents/MacOS/r:
/System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa (compatibility version 1.0.0, current version 19.0.0)
/Library/Frameworks/SBJson.framework/Versions/A/SBJson (compatibility version 1.0.0, current version 37.0.0)
/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation (compatibility version 300.0.0, current version 945.0.0)
/usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 169.3.0)
/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit (compatibility version 45.0.0, current version 1186.0.0)
P.S. If you're wondering if I added the copy to framework build phase, the answer is yes.
The short version
The problem is that when you built SBJSON.framework, the install name wasn't configured to use #rpath. As a result, when your app goes to load the dynamic library, it's looking in /Library/Frameworks instead of where your app's runpath tells it to look.
To fix it, you need to change a build setting on the SBJSON.framework target. Change the the Dynamic Library Install Name setting to #rpath/${EXECUTABLE_PATH}. Then just build again, linking against the newly-built framework, and you're good to go.
The long version
Frameworks are, at the core, just dynamic libraries. This means that the code contained in the library is not embedded into your app, but rather pulled in from the SBJSON.framework bundle at runtime. In order to do this, your app needs to know where to look for the dynamic library.
The way this works is that when you link against a framework, the linker doesn't actually embed the whole library into your app. Instead, it just adds a small section that tells the app where to find the library when it runs. Of course, that means that the compiler has to know where the library will be at runtime. It finds that information by looking at the "Install Name" of the dynamic library.
A dynamic library's "Install Name" is essentially just the path where the library is expected to be. Historically, most dynamic libraries and frameworks have been shared system-wide. Things like Foundation.framework and CoreData.framework, for example, live in /System/Library/Frameworks, and all apps can reasonably expect to find them there. Thus, when CoreData.framework is built, its install name is set to /System/Library/Frameworks/.... When Xcode links your app against Core Data, it looks at the framework's install name and tells it to load in the framework at that path when the app is launched.
That's all fine and well, but it doesn't help you when you need to embed a framework inside your app. You don't know where the app will be located on the system at runtime. The user may run it from /Applications, but they might also run it from ~/Downloads. There's no single path you could provide as the install name that would always correctly point to the framework at runtime.
To deal with this, you can set the framework's install name to #loader_path/../Frameworks. When the dynamic loader sees #loader_path, it replaces it with the path of the currently-loading app. Using this install name would allow the framework to be installed inside the Frameworks folder of any app.
However, things still aren't perfect. The framework is still dictating where it should be placed. If another app wanted to place the framework inside a Libraries folder instead, for example, it's out of luck. The framework is in charge of where it can be placed, instead of the app. This is an inversion of the dependency tree, and is not ideal. The app should be able to load the framework from wherever it wants to stash it, regardless of what other frameworks do.
Thus, in OS X 10.5, #rpath was introduced. If the install name of a dylib or framework begins with #rpath, then the loader will turn around and ask the app what it's "Runpath search paths" are, and substitute those in. This allows the app to specify where its frameworks will live. By using #rpath, the framework delegates the decision back to the app. The app can use #loader_path if it wants, or can specify an absolute path if it wants. It could even specify a shared folder that a whole suite of apps will use.
Your problem
So, on to your problem. You're correctly setting the app's runpath search path to #loader_path/../Frameworks. However, the framework's install name isn't using #rpath; in fact, it's still using a hard-coded path to /Library/Frameworks/.... Since the framework's install name doesn't use #rpath, the app's runpaths aren't even consulted. It's simply trying to link in SBJSON from the /Library folder. Since it's not there, your app crashes before it even launches.
You need to change the install name of the SBJSON framework to use #rpath. Set the Dynamic Library Install Name setting to #rpath/${EXECUTABLE_PATH}. (${EXECUTABLE_PATH} is the relative path to the internal dynamic library, from the folder containing the framework.)
Once you've built the framework with the new install name, you should be able to link against the new framework, make sure it's copied into the app bundle's Frameworks/ folder, and you're good to go!
P.S. If this isn't all clear, Mike Ash did a pretty nice review of #rpath and friends. You can find it here.
Installed FreeImage through MacPorts. Everything looked to be OK, but when I builded my app and tried to launch on other computer where is no MacPorts and no FreeImage installed it says
dyld: Library not loaded: /opt/local/lib/libfreeimage.3.dylib
Referenced from: /Users/development/Library/Developer/Xcode/DerivedData/freeimage-dxsornyaxqlkyubqwsrlkgszvxhy/Build/Products/Debug/freeimage.app/Contents/MacOS/freeimage
Reason: image not found
Shouldn't it copy library files together with my project? I added them to my project's build phases "Copy files" list. They are being copied to my app's bundle. But when I try to link them, I get same error. I don't know why but app is still looking for library in /opt/local/lib. How can I fix it so that I could use FreeImage at my project and run it at any computer?
When you install through MacPorts the library is installed in /opt/local/lib, not in your project path. Even if you copy the whole project, the *dylib libraries won't be copied because they are usually in /opt/local/lib.
I believe you have two options here: install FreeImage in every computer that you want to run your application, or copy the libfreeimage.3.dylib to the same folder where your binnary is and, if both systems are similar, that should work. If the two computers are different in terms of operating system version, hardware architecture, etc... then probably the .dylib that you have won't be compatible for the other computer.
Another thing you might want to consider is to modify your DYLD_LIBRARY_PATH variable, which specifies the paths in which the OS will look for libraries when linking. See this answer for more information.
I installed ImageMagick through MacPorts. So all library files are in /opt/local/lib and headers in /opt/local/include/ImageMagick. It works OK on my mac. In xCode Build Settings - > Search Paths everything looks to be set OK.
Added library files to Linked Frameworks and Libraries
When I build my app it looks to be working. But when I try to run builded app on other computer where ImageMagick is not installed there comes this error message:
How can I fix it to make users to be able use my app without needing to additionally install ImageMagick and so on? How to link it that needed library files would come with my app (in project bundle)?
Af of now your linking library is referred from /opt/local/lib/ ---
Solution for your issue:
Make sure where ever app is installed suport library is installed to right location
Carry the dynamic library with app bundle and refere the dyld from the app bundle which will be relative to app bundle launch path.
Update: If you are looking for the second option --- With this option your library will be placed inside your app bundle ... so app can refer the library from the app bundle.
The precompiled dynamic library can be carried with the application -- in xCode --> Go to Build Phases for the target --> Build Phase (copy files) ... this will make sure your dynamic library is copied to into your app bundle ...
Update “install name” inside each dynamic library --- You can use 'otool' command to know present install path of your precompiled library and you can precompiled library install path using'install_name_tool' command in your terminal.
No support for it from ImageMagick forum, no support from StackOverflow, so I guess its impossible...