How to bundle a C library with a Cocoa application
Mac OS X ships with a ton of useful C libraries that a Cocoa developer can take advantage of. However different versions of OS X ship with different libraries and different versions. Normally if you’re not sure a required library or version will be present on a users machine, you would create an installer to check for it, and then install it if needed. But one of the great things about developing for the Mac is that you can easily include a dependency, such as a dynamic C library, within the application’s bundle. For this howto, we are going to build a Cocoa application that uses the C library libssh2. This library does not ship with OS X, but that’s no problem at all. I’m going to show you how to bundle it with your application so it will run on any users machine.
First thing, let’s create a new Xcode project and call it MySSH. Then create a new Objective-C class and call it TestController.

Next we need to install libssh2. You can do this a couple different ways. The easiest is by grabbing the latest source from here and building it yourself. You could also use a package manager like Fink, or MacPorts. Once installed, we need to locate the dynamic library file called libssh2.1.dylib. I installed from source, so my .dylib file is located in ‘/usr/local/lib’. If you installed with MacPorts it would be in ‘/opt/local/lib’, and Fink installs it somewhere under the ‘/sw’ directory. Once you find yours we need to drag it into our project and drop it in the “Linked Frameworks” directory.

Xcode will prompt you to add the file to your project. Be sure to check the box at that top that says to “Copy items into destination group’s folder” and click “Add”.

Next we have to create a new build phase to copy the library file into our application bundle. In Xcode, in the left column under Targets, control-click on the MySSH target and choose ‘Add’ → ‘New Build Phase’ → ‘New Copy Files Build Phase’. In the popup window select ‘Frameworks’ as the destination and then close it.

Now let’s rename our new build phase from ‘Copy Files’ to ‘Copy Frameworks’ so it’s more clear. Next, while holding down the option key, click and drag the libssh2.1.dylib file from the ‘Linked Frameworks’ group into our new build phase.

What this does now is every time we build the MySSH target it will copy the libssh2.1.dylib from our project into the ‘Frameworks’ directory inside our MySSH.app bundle.
For the next step we need to open up our Terminal, `cd` into our projects directory where the libssh2.1.dylib file is and run the following command:
Linux users will probably recognize this as the `ldd` command. It will display the install name of libssh2 on the top line, followed by the locations of any other libraries it depends on.

The install name for my libssh2 is ‘/usr/local/lib/libssh2.1.dylib’ though yours may differ depending on how you installed it. No matter, since we can’t rely on a user having libssh2 installed in any particular place (or at all) we need to change that path to point to our own libssh2.1.dylib that is in the MySSH.app bundle. For this we use the install_name_tool. Go back to your terminal and from the same directory run the following:
@executable_path/../Frameworks/libssh2.1.dylib \
libssh2.1.dylib
This changes the install_name of our library to a relative path. The ‘@executable_path’ variable represents the path to our application’s binary, and one directory up, in ‘Frameworks’, is where our new build phase copies our library file. If you did this correctly, when you run `otool -L libssh2.1.dylib` again you should see our new relative path on the top line.

Now as I mentioned earlier, the other paths below the install name are all the libraries that libssh2 requires. When bundling your application with a library you must guarantee that all its dependencies exist on the users machine at the path listed. For simplicity I’ve chosen a libssh2 because the libraries that it depends on (libssl, libcrypto, etc.) are all standard on Mac OS X, and are all located in ‘/usr/lib’.
* Note: If you installed libssh2 with MacPorts, pay close attention to the paths listed here. Sometimes when using Macports it will not link against the standard libraries in ‘/usr/lib’ but instead the ones in ‘/opt/local/lib’. If your libssh2 is referencing any libraries in ‘/opt/local/lib’ you will need to change each one using the following command:
/opt/local/lib/$FILE \
/usr/lib/$FILE libssh2.1.dylib
Once your terminal output looks like mine above, we can now start using libssh2 in our application. Let’s go back to Xcode, open our TestController.m and enter the following.
Build and run your application, and you should see the libssh2 version number logged to your console. Now it may seem like we are done at this point but there is still one more step. Remember how our libssh2 was referencing other libraries on our system? Well our MySSH application is no different. Let’s go back to our Terminal and take a look. From our projects directory enter the following:
otool -L MySSH
Can you spot the problem?

The compiled binary is referencing libssh2 from our install path. To fix this we need to add another build phase to run after we compile. Back in Xcode, in the left column under Targets, control-click on the MySSH target and choose ‘Add’ → ‘New Build Phase’ → ‘New Run Script Build Phase’. In the popup window add the following code:
REL_PATH="@executable_path/../Frameworks/libssh2.1.dylib"
install_name_tool -change $ABS_PATH $REL_PATH $TARGET_BUILD_DIR/$EXECUTABLE_PATH
…keeping in mind that your ABS_PATH might be different than mine – it is going to be the path that you have listed for libssh2 in the Terminal output above.

Now everytime we build our application, this build phase will change the path your executable looks for libssh2, to the one inside the MySSH.app bundle. That’s it! Now you can give your application to anyone without them needing to install this library. The application will run completely self contained – and if the user should decide to remove your application they can simply delete the .app file and the library will be removed along with it.
nice post!
thanks a lost
I’m learning cocoa programming.
this helps me a lot.
Thanks for posting this. I’m working on a project that requires libssh2, so this was a perfect introduction. There are a couple of things that gave me issues, however:
1. I needed to copy libssh2.h from /usr/local/include/ into my project, then…
2. add: ‘#include libssh2.h’ to TestController.h
I also put together a simple Cocoa wrapper for libssh2 that includes functions such as running commands over ssh and transferring files over SCP/SFTP. I’ve almost got it clean enough to open source it; I’ll post the link here when it’s available.
I’m really surprised that there isn’t already a framework out there for ssh, or am I missing something?
This was great, but how about another article on how to compile libraries, such as libssh2, for the iPhone? When I try and follow the instructions, it bombs out because “ld: warning: in /Users/freimer/Documents/NetHost/libssh2.1.dylib, file was built for unsupported file format which is not the architecture being linked (i386)
”
Obviously, I will need to build the libssh2 library for the iPhone architecture…
Haven’t tried this yet, but here are some instructions I found on the web:
http://sites.google.com/site/olipion/cross-compilation/libssh2
Thanks to this tutorial, I was able to create a Cocoa Framework called SSHCore to make using libssh2 easier. It’s pretty rough at the moment, but you can check it out on GitHub:
http://github.com/lhagan/SSHCore
I intend to eventually add full iPhone support, but it’s Intel only for the moment.
Hello,
firstly thanks for your Tutorial. I have a problem with your sample code. You say I should type this into my TestController.m:
#import “TestController.h”
#include
But after the include there is no file name. I don’t know which file I have to include! libssh.h isn’t there…
Please Help me!
Gabriel, see my comments above for help with your issue.
You can also take a look at my ssh framework code for more detailed examples. Search on GitHub for SSHCore.
@lhagan omg I’ve copied libssh2.h into my Project and know the sample code runs perfectly! Thx!
@gabriel
Sorry, WordPress munged some of the sample code. It is fixed now.
Very useful, thanks! I was already aware of the install_name_tool and @executablepath, but having all the steps illustrated together in one place was just what I needed.
I get an error when building that states:
“_libssh2_version”, referenced from: -[TestController awakeFromNib] in TestController.o
(symbol(s) not found
Collect2: ld returned 1 exit status.
Any ideas as to why this may be the case?
When I attempt this I get the following error.
Undefined symbols:
“_libssh2_session_init_ex”, referenced from:
-[TestController awakeFromNib] in TestController.o
ld: symbol(s) not found
collect2: ld returned 1 exit status
I used lhagan’s libssh2.1.dylib from his SSHCore framework as I couldn’t manage to get a version compiled myself for x86, just 64 bit.
Thank you for this tutorial. This saved me from a lot of head scratching.
Thanks for the tutorial, although it does not work for me. I have followed the instructions using Xcode 4 and I get a build error: ‘libssh2/libssh2.h’ file not found.
@John
Double check your header search paths in the project preferences.
@nick
Thanks for the reply. There was nothing in the header search paths, so I added:
$(inherited)
“$(SRCROOT)”
These were in the library search paths.
I am actually trying to add libssh, not libssh2.
When I go to type #include <… it drops down with libssh.dylib and not libssh.h as expected.
I am battling on like I'm in a cave with no torch!
Thank you a lot!
Two things to add:
Put Quotes aroud $TARGET_BUILD_DIR/$EXECUTABLE_PATH
This eliminates errors when the product name contains whitespaces.
When the library in question is a custom made library and hence available as a separate XCode project, this project can be added directly to the souce tree, the library (in the corresponding Products folder) can be added to the target (without copying!), the added library can be set as a direct dependency (Target info, first tab) and the library can be added to the “Copy to Frameworks” build phase by dragging it from the source tree to the build phase (again, without copying!). This should set the install name of this library automatically! Not the one of the final product thoug.