PDA

View Full Version : Porting Linux app to MacOS X - dynamic libraries


Kickaha
2007-10-04, 14:15
Alright, I'm going bonkers. In the middle of porting a Linux app to MacOS X 10.4, and I've run into what seems to be a very common problem: converting the build system for dynamic libraries. There is no end of 'helpful' advice running around, 99.9% of which seems to boil down to "Try everything" or "Use this magic sequence, it works for some people, nobody knows why". The last .1% seems to be posts of "Got it working! Thanks!" *with no explanation of how*. Bastards.

The build system I'm struggling with is... byzantine. Multiple layers of Makefiles with embedded Perl, custom scripts that don't really *do* much that I can see, other than add obfuscation, etc, etc.

In other words, a pretty normal OSS project. :)

So here's the setup:

1) .o files being archived into .a libs.
2) .a libs being gathered into .dylibs.
3) binaries being built on dylibs.

Simple, no?

The gcc/ld link flags for the linux build are:

CFLAGS throughout are the same: -pipe -Wreturn-type -march=i686 -fPIC -Wunused -Wformat -Wall -Wno-parentheses -Wno-switch -Wno-sign-compare -Wno-unused-parameter

.c%.o:
g++ $(CFLAGS) -o foo.o foo.c

.o%.a:
ar cr foo.a *.o

.a%.dylib:
g++ -L/usr/local/lib -L. -lfoo -o libbar.so -Wl,--enable-new-dtags -shared -Wl,--whole-archive ../lib/[.a libs here] -Wl,--no-whole-archive

No, I don't know why they switch back to --no-whole-archive, I just report what they do.

.dylib%a.out:
g++ $(CFLAGS) -L$(DLLDIR) -Wl,-rpath-link,$(DLLDIR) -L. -o my_executable ../main.c -lMyLib1 -lMyLib2


--------
The analogous (I thought) flags for OS X's build chain are: (first two are the same)

.c%.o:
g++ $(CFLAGS) -o foo.o foo.c

.o%.a:
ar cr foo.a *.o

.a%.dylib:
g++ -L/usr/local/lib -L. -lfoo -o libbar.dylib -dynamiclib -all_load -single_module -flat_namespace -force_flat_namespace -bind_at_load ../lib/[.a libs here]

-shared -> -dynamiclib
--whole-archive -> -all_load
because it's not a MacOS X app -> -single_module -flat_namespace -force_flat_namespace
who the hell knows, see 99.9% reference above -> -bind_at_load

.dylib%a.out:
g++ $(CFLAGS) -fvisibility=default -L$(DLLDIR) -L. -o my_executable ../main.c -lMyLib1 -lMyLib2

The -fvisibility is to make sure that 'older style' auto-export of symbols in dylibs is done.

Of course, this doesn't work, it can't find the second level dependent libraries...

/usr/bin/ld: warning can't open dynamic library: libMyLib3.dylib referenced from: ../dll/libMyLib1.dylib (checking for undefined symbols may be affected) (No such file or directory, errno = 2)
/usr/bin/ld: Undefined symbols:
_FirstUndefSym referenced from libMyLib1 expected to be defined in libMyLib3.dylib

I did an 'export DYLD_LIBRARY_PATH = $(DLLDIR)', *and* set it in the shell. Neither worked. I need a replacement for that -rpath up in the Linux build line, apparently.

Looking through the Makefiles, ranlib is never being invoked directly, but shouldn't that be handled by passing everything through gcc??

I'm getting another 'undefined symbol' error from a .a library that obviously *HAS* the symbol in it (two .o files, one defines, one uses, apparently the one using is bitching... in the *same library* - grr), but let's take this one step at a time.


On writing this up, I'm wondering if the -fvisibility flag should be in the .a%.dylib command...

Wyatt
2007-10-04, 14:19
The build system I'm struggling with is... byzantine. Multiple layers of Makefiles with embedded Perl, custom scripts that don't really *do* much that I can see, other than add obfuscation, etc, etc.

In other words, a pretty normal OSS project. :)
:lol: What app are you trying to port? (Not that it's likely relevant to what your problem is, but other people might be interested in helping out if you said what it was.)

Kickaha
2007-10-04, 14:24
Can't, internal to the corp, confidential, blah blah blah. Trust me, I *wish* I could get help on this. The team that wrote the original has no time/interest in mucking about with OS X's build system. :\

Half the time making this post was sanitizing it of any identifying information... :p

Wyatt
2007-10-04, 14:25
Can't, internal to the corp, confidential, blah blah blah. Trust me, I *wish* I could get help on this. The team that wrote the original has no time/interest in mucking about with OS X's build system. :\
Typical closed-minded corporate morons.

Good luck enlightening the place. Sounds like they could use your help.

Kickaha
2007-10-04, 14:26
So, can you help me or not, ya putz?? :D

Wyatt
2007-10-04, 14:29
So, can you help me or not, ya putz?? :D
Nah, I don't know shit about dynamic libraries. Or programming for OS X in general. :lol:

Unfortunately for me (and you, in this case), I went through programming courses at a college that is so far up Bill Gates' ass they could brush his teeth. Seriously, they do VB and (some) C++. That's all.

Once I finish my degree and I have a bit more time, maybe I'll learn how to do this so I can tell you. :p

This will be another thread I watch in here just for the sake of learning something. I was really just asking those questions early on to try to get an answer out of somebody else so I can learn something. :D

Kickaha
2007-10-04, 15:49
Slacker. :)

MCQ
2007-10-04, 17:54
Hm. Don't know much about build processes (can't figure out our own team's build scripts half the time). Anyways,


I did an 'export DYLD_LIBRARY_PATH = $(DLLDIR)', *and* set it in the shell. Neither worked. I need a replacement for that -rpath up in the Linux build line, apparently.


http://developer.apple.com/releasenotes/DeveloperTools/RN-dyld/

No rpath support
Some other Unix systems have an rpath concept where a final linked image can contain a list of additional directories to use when searching for required libraries. Since Mac OS X uses full paths for libraries instead of searching, rpath is less interesting.


I was going to ask if using the default two-level namespace helps at all, but looking at OS X's port guide, it suggests using the flat_namespace option.

Kickaha
2007-10-04, 17:56
Yeah, that was my take on it as well, re: 2 level vs. flat.

And yes, I found the note about rpath as well - DYLD_LIBRARY_PATH is supposed to be the replacement, in theory. :\

Kickaha
2007-10-04, 19:23
AHA!

You can set a relative path name for the linked in libraries, such as @executable_path or @loader_path. From that same page you linked to:

@loader_path/
Every mach-o final linked image can contain any number of LC_LOAD_DYLIB load commands which the path of a dylib that must be loaded. Usually, it is an absolute path. We also support the path starting with @executable_path/ which means relative to the main executable. This enables the construction of applications that could be installed anywhere. In Mac OS X 10.4, we now support LC_LOAD_DYLIB paths that start with @loader_path/ which means relative to the image containing the LC_LOAD_DYLIB command. This enables the construction of bundles and other "directory trees" of final linked images which can be installed anywhere.

Currently, ld(1) has no options for directly embedding @loader_path into LC_LOAD_DYLIB load command. Instead, you must post-process your final linked images with install_name_tool.

Seems much more supported.

Good rundown of linking here: http://www.cocoadev.com/index.pl?ApplicationLinking