Finally I have some video footage of the exhibition we made some work for a couple of months ago. The project is described in my projects section here.
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
// // Shared.xcconfig // OgreCocoa // // 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.
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 havent posted anything in ages! So many half finished projects!
Anyway, I have a kinect project to work on for somebody. I have had a kinect for ages and got libfreekinect working but never really did anything with it. Since then OpenNI released a whole framework that provides things such has skeleton and gesture tracking. Thats a whole lot of work done for you for free!
This instructions for installation etc… on Mac OS X can be found here http://developkinect.com/resource/mac-os-x/install-openni-nite-and-sensorkinect-mac-os-x. You will need to have macports up and running and be familiar on how to install applications from it. This is easy to find on google.
Its worth noting that to get this to run on OS X you need to install a separate driver that is not provided by OpenNI. I thought I had done this, but when I ran any examples i got the error “cannot find port” or something like that. So after installing it a second time all the examples ran. It is all well and good getting the samples running but you need to be able to manipulate them to shape it in to your own work. So, to an IDE!
I had a quick look at using eclipse, for the more cross platform friendly building but I havent got it to work yet. Its only a linking issue cause by OS X frameworks, so shouldn’t take much longer. In the mean time here is house to get it working in XCode. Again someone has already done it for me http://davidbliss.com/getting-up-and-running-with-openni-and-nite-o. I was focussing my attention on the UserTracker example so copied the source in to a new XCode project and followed the methods provided by the previous link. Alas, it did not quite work. The linker could not find /usr/lib/libXnVFeatures.dylib, so rename it to /usr/lib/libXnVFeatures_1_5_2.dylib, or create a dynamic link to /usr/lib/libXnVFeatures_1_5_2.dylib, and the same for /usr/lib/libXnVHandGenerator_1_5_2.dylib. Everything now compiles.
Running the program exits immediately because it cannot open some file. After some trial and error of copying over folders and files from the examples folder, it turned out to be ../../Config/SamplesConfig.xml. So, the user tracking works, and shows a nice skeleton of a user moving around. Im hoping to next link up OpenFrameworks and manipulate
I am currently developing on 3 platforms at work so I am trying to manage the source code in a tidy manner and version each module etc… Shared object files in linux and dll’s in windows have always been pretty easy but I have not tried to created a dylib (.so equivalent) in mac xcode before. I have made it work, im not sure if its the correct way but its linking and runs.
First i had a standard command line program that I wanted as a library so I went to the project settings and changed Mach-O Type to Dynamic library. This means the compiler does not look for a main function.
Next I need to rename the output file. For this I find the target in the project explorer, right click and get info, build tab. In the packaging sections change Product name to name.dylib. Build the project and it should now produce you a shared library file.
To use this library in another project you need to make a few further steps.
First add the associated header file directory to the header search path in the project settings.
Secondly add the directory of the library file to the library search path.
Finally create a new group in the project explorer named “libs” or something similar and drag the library file to this group. When you build it should all link up and execute. I have had some issues where the executable cannot find the library. With a brief googling it seems that xcode at least at one time had a conflict of build versions unless the library file is not in the execution directory. I hope to resolve this, but for now I just copy the library file over.