I think I may have cracked it…
The problem is, when compiling against 3rd party libraries in Xcode, the rpath search path for libraries that the executable uses to find libraries first, is inherited in from the library itself. So if the library is in /usrl/lib thats where the executable will look. Thats fine if the machine running your code has the library installed, but in the fashion of how Mac OS X makes application bundles with all dependencies residing inside, this doesn’t quite work. In fact xcode provides a copy build phase for libs/plugins. So you copy your libs across and yet your already compiled code does not know to look there.
The solution is to use install_name_change on both the dependencies and the main executable. Lets deal with your dependencies first. I will assume they are now all in the same plugin folder post build code.app/Contents/Plugins/…
Using otool -D lib.dylib returns the path that is presented by that library to the compiler. To change it you can use install_name_change with the argument -id.
install_name_tool -id “@executable_path/../Plugins/lib.dylib” lib.dylib
This alters the relative path of lib.dylib to the plugins folder of your bundle. Next you need to change each path in the main executable. You can find out the dependencies and their expected path of the executable using otool -L. For each dependency that needs changing use install_name_tool again with the argument -change.
install_name_tool -change “/usr/lib/lib.dylib” “@executable_path/../Plugins/lib.dylib” applicationname
This passes in the current expected path(found out using otool), then the new path, and finally the file you wish to make the operation on. Once you get a few libs worked out its worth chucking it in to a shell script to save you time. It seems odd to me that XCode does not make this easier for you considering how it encourages self encased bundles so much. There may be a more elegant way to do it, but I have not found it let.
I have been banging my head against the table trying to port some code from ubuntu to mac os x using both the ogre and openNI libraries. Although I used XCode quite a lot, its never to create gui type applications, and when it has been its been using GTK graphics libraries. So it seems that Ogre requires access to the Cocoa API to run on OS X, much to my original thought that I could get away with not using object-c. In my pursuit I discovered a few useful tricks about XCode that are worth remembering.
Firstly the project setting tool in XCode is perfectly functional but sometimes a bit hard to navigate and lacking in the ability to source control the configuration. There is a more elegant and effective alternative though. Reading this great post it explains how to use xcconfig files, as a text based settings file that you can add comments to, and of course source control. This simplest way to start is to create a new xcconfig file, and literally cmd+c cmd+v from the settings window in to the file. It then translates the settings window parameters in to the variable names. Using this as a base you can configure and specifics yourself. Then when you have your config file ready, open the settings for your target, and in the bottom right there is a small drop down to assign a config file to that target’s build.
It can be as simple as this
// Created by AstroBoy on 22/04/2012.
// Copyright 2012 __MyCompanyName__. All rights reserved.
ARCHS = $(ARCHS_STANDARD_32_64_BIT)
SDKROOT = macosx10.6
ONLY_ACTIVE_ARCH = YES
PREBINDING = NO
HEADER_SEARCH_PATHS = /opt/local/include/ /usr/include/ni /usr/include/nite /OgreSDK/Dependencies/include
LIBRARY_SEARCH_PATHS = /usr/lib /opt/local/lib/ /OgreSDK/Dependencies/lib/Release
GCC_OPTIMIZATION_LEVEL = 0
GCC_C_LANGUAGE_STANDARD = gnu99
GCC_WARN_ABOUT_RETURN_TYPE = YES
GCC_WARN_UNUSED_VARIABLE = YES
The second thing I noticed is that there is a naming conflict between openframeworks and ogre3d. Openframeworks provided a good easy way to install the openNI libraries with an ofaddon, but it was cheating a little bit. So I have just used to installed openNI drivers from openNI.
Finally whilst trying to ignore objective-c and use normal c/c++ I tried to link to the Ogre library files without using the framework provided by the ogre sdk, I came up against rpath(unix) issues, or LD_DYLIB_INSTALL_NAME(Xcode). rpath is a parameter applied to a library at compilation then determines where the library can be found during execution. So for example, this works well with the XCode bundle system where you can place your libraries in the ../Plugins folder. This means the system LD_LIBRARY_PATH does not need to be set to the location of the libraries, because when you compile the main executable against the library it will know where to look during execution. Of course, this works when you set it during compilation of the library, and realise you needed to do so. If you are unsure of where an executable is going to look for its dependencies you can use ldd(unix) or otool(mac) on the file to display the search paths (see a previous post). Anyway, if for any reason you want to set this in XCode, there is a setting called D_DYLIB_INSTALL_NAME, which should be set to something like @executable_path/../Plugins/libx.dylib, if you are going to place libx.dylib in the plugins folder of the bundled. Also make sure you place this library in a copy build phase within XCode.
Next time I should finally have a working example of openNI working with Ogre3D through XCode as a distributable application.
Want to find out the dependencies of an executable? on the command line use ldd for linux, or otool for mac. This will give you a list of all the libraries that the executable needs and whether it can find them. Its very useful when things dont link up!
Apparently I am too lazy to walk from one desk to another, so I wanted a way to graphically ssh from my macbook to a ubuntu unit. Having done this linux to linux before it pretty much works out of the box after you install openssh-server through the package manager. Next just type ‘email@example.com -X’ where the username is an account on the machine and IP is the IP of the host machine. The -X argument pipes the graphics from any application you load through to your client machine.
Mac os x doesn’t use the same graphics tools as linux, but you have an application that does, X11.app. so open up a terminal in os x and ssh -x to the host, enter your password. You should be at the user account home. Try a simple gui program such as xeyes or gedit. It should open up the X11 app which will in turn load your app from the host machine.
At the first try this did not work from the os x terminal, complaining about gtk errors. I opened up X11 standalone, and used its built in terminal. This worked fine, so I closed down X11, and tried with the os x terminal again and it worked. You may just need to open X11 once before trying this. Anyway, evidence….
I might be using Ogre3D as a rendering tool for a kinect project. Ive used it on windows and linux a couple of years ago but not mac os x 10.6.8. Here is how to build from source with XCode.
- Download 1.7.4 source for linux/os x and dependancies http://www.ogre3d.org/download/source
- Follow ogre_src_v1-7-4/BuildingOgre.txt. The pre-built dependancies were enough for me.
- Open Ogre xcode project created by cmake in the new build directory
- I noticed in one of the cmake file I looked at “# CMake 2.8.2 has a bug that creates unusable Xcode projects when using ARCHS_STANDARD_32_BIT” … so make sure make only for 64 bit.
- If not all the targets build in one go, then build them individually starting with ogre main.
- The samples are built as libraries kept in lib, and the demo application is in bin.
I constantly tell people to use Doxygen (a great time saving auto code documenting tool). It works great in most IDEs but not Xcode because Xcode does not recognise the syntax layout used by Doxygen. I just discovered a solution! If you go here someone has made a great Ruby script to auto generate the comment templates in response to a short cut key. It wasn’t quite perfect for me though, because it missed out the ‘*’ and indentation spacing so I made a few modifications. My version is here.