Problem with working directory and dynamic library path on OS X

Hi,



I´m actually working on porting some project to OS X using Code::Blocks. First of all, I use Code::Blocks for the Linux port as well - without any problems. I use the Mac Version 8.02-p2. I actually face two problems which might be strongly linked to each other:



1. Dynamic Library path set incorrectly

The following scenario: The project-file for the dynamic library is located in root/dir/subdir, the output-file is written to: root/bin. All paths are given relative, therefore output filename would be: ../../bin/lib.dynlib. The working directory of the dynlib is set to ../../bin. The project compiles and links as intended, alright so far. But now, as soon as I execute the binary it can´t find the dynlib. The working directory is ../bin, that´s the relative path from the binaries project file to the bin-folder. The thing is: According to the output, the dynamic linker tries to find ../../bin/lib.dynlib, what is the output filename of the dynlib. It seems to treat it as a absolute path somehow. I cannot see this behavior under GNU/Linux.

I then thought I might tell the linker manually where to find the dynamic libs by setting the path manually in the linker options via

-Wl,-rpath,../bin

But this didn´t change a thing. What temporarily fixed the thing is to set the dynlib path manually in the terminal session via

DYLD_LIBRARY_PATH=<full path to bin folder>

But this is not really an option. Therefore: How can I fix this?





2. Working directory of libraries

I´m actually not sure whether this is a Code::Blocks-problem, but I guess it is somehow. The working directory (given by getwd()) of the binary is correctly the absolute version of /root/bin. But when I call this function from a library (surprisingly no matter whether this is a static or dynamic one), I get /root. I set the working directories of the dynamic libraries correctly, for instance ../../bin for the above example (setting the relative path). I wonder how it finally becomes /root, I mean I could think of /root/dir/subdir or /root/bin as possible options, but why ../ ?







I tried to find the solution myself, but I couldn´t. I really hope someone can help me.





Thanks a lot & best Regards,



badday





PS: If further information is required, just let me know it 😉

Mac OS X (10.6.8)

Posted on Sep 25, 2011 1:46 AM

Reply
6 replies

Sep 25, 2011 12:37 PM in response to badday_7bf

MacOS X isn't Linux. The native MacOS X dynamic library architecture is based on frameworks instead of one or more known directories. The location of a dynamic library within a framework is hardcoded inside the executable. You can change this using the install_name_tool program in a post-link build script. Then, for example, you could change the absolute path of a shared library to a path relative to the location of the executable.


As for the working directory of an application, that is a value defined at runtime. This is the same on any OS. You can't make any assumptions about the current working directory inside a library. If you need to refer to some data file, it should properly be defined in some configuration file. You can locate the install path for any particular dynamic library or framework and use that if you need to. The structure of frameworks includes just such a compatibility section for libraries that are unaware they have been packaged into a framework.

Sep 26, 2011 9:41 AM in response to etresoft

OK, thanks for your help. Meanwhile I managed to link the dyn. libs linked by the executable itself. I did this with

install_name_tool -change <relative_path_from_project_file>/name.dylib @executable_path/name.dylib $(TARGET_OUTPUT_FILE)


Anyway, I still have trouble with inter-library-dependencies. For instance I´ve got a library a.dylib which needs to be linked against b.dylib. Therefore I tried to add the post build steps to b accordingly:


install_name_tool -change <relative_path>/a.dynlib @loader_path/a.dynlib $(TARGET_OUTPUT_FILE)


However, no matter whether I replace @loader_path by someString, it still looks a up in <relative_path>, as dyld tells me when executing the program. It also tells me that it was referenced from b.


What am I doing wrong?

Sep 26, 2011 10:21 AM in response to badday_7bf

badday_7bf wrote:


What am I doing wrong?

You are still thinking in terms of relative paths. Relative from where? Where is "here"? The concept of "here" only has significance in your current shell process. If your shell spawns some other process, or if you don't have a shell running, there is no "here" to speak of. Everything must be an absolute path. When you add the install_name_tool into your build scripts, you should use one of the Xcode environment variables to get the path the the product being built. I use "$TARGET_BUILD_DIR/$EXECUTABLE_PATH". You may need to do that with the dynamic libraries themselves. I include the required dynamic libraries inside the application bundle and hack them up there. You can also install them into known paths and just use them from there. No hacking of any kind required. You will instead have to create an installer that installs those dependent libraries into the correct locations on the user's machine. If you are targeting the app store, I strongly recommend putting dependent libraries inside the application bundle and hacking them up there.

Sep 27, 2011 7:27 AM in response to etresoft

You are still thinking in terms of relative paths. Relative from where?

During the linking process relative to the project file - this works so far.


When you add the install_name_tool into your build scripts, you should use one of the Xcode environment variables to get the path the the product being built.

As I do not use Xcode this is no option.



In the terminal it says it can´t load ../../../bin/dep_lib.dylib. So I thought this should be changed by

install_name_tool -change ../../../bin/dep_lib.dylib another_path/dep_lib.dylib $(TARGET_OUTPUT_FILE)

However, it is not changed. I did use this way for the executable successfully: The terminal toled me from where it tried to load the file an I changed it accordingly. Anyway, this seems to be different for dynamic libraries. I mean what does install_name_tool do effectively? Doesn´t it mean that whenever [old_path] would be called by the dynamic linker, it is replaced by the [new_path]?


I would no like to use very OS-specific things like making application bundles and stuff.

Sep 27, 2011 9:05 AM in response to badday_7bf

In many respects, Xcode is just a fancy make. Whereas Xcode would use a build script after linking, a makefile would have a 2nd command after the link to fix up the executable with install_name_tool or maybe lipo.


You should never rely on relative paths, even if it works that way. Use environment variables that can be initialized with any path. Then, when you rearrange some directories in your project, you don't have to hunt down and fix relative paths.


Frameworks and bundles are the signs of well-made Mac software. You don't have to use them. You could use an installer requiring root privileges and standard paths. You could also require a shell and dynamic library environment search paths. The correct option depends on your target users and the nature of the software.

This thread has been closed by the system or the community team. You may vote for any posts you find helpful, or search the Community for additional answers.

Problem with working directory and dynamic library path on OS X

Welcome to Apple Support Community
A forum where Apple customers help each other with their products. Get started with your Apple Account.