Sunday, August 3, 2008

-undefined dynamic_lookup (Mac)

I was a little bit confused about MacPython's extension dependency.

Extensions that are part of the standard library are in
/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/lib-dynload (On my machine)
Basically those extensions seemed to be dependent on only libgcc_s.1.dylib and libSystem.B.dylib, not Python at all.


$ otool -L array.so
array.so:
/usr/lib/libgcc_s.1.dylib (compatibility version 1.0.0, current version 1.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 111.0.0)

I was wondering why it was not dependent on Python, while in the extension Python C/API funcs were used.
Python C/API functions are in
/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/config/libpython2.5.a (again on my machine)
which is actually a shared library (dylib) although its file extension is .a, and is a symbolic link to ../../../Python. (P is capital)

$ cd /System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/config
$ nm libpython2.5.a | grep "T "
...(lots of API funcs)...

Should extensions be dependent on it?
If a symbol is not bound to a filename how can we avoid name conflict?
I tested further and found the way to know what file a functions is dependent on.

$ cat a.cpp
#include <stdio.h>
void f()
{
printf("a\n");
}
$ cat b.cpp
#include <stdio.h>
void f()
{
printf("b\n");
}
$ cat main.cpp
int main()
{
void f();
f();
return 0;
}


$ gcc -dynamiclib -arch i386 -o a.dylib a.cpp
$ gcc -dynamiclib -arch i386 -o b.dylib b.cpp
$ gcc main.cpp -dylib a.dylib -dylib b.dylib -lstdc++
$ nm -mg a.out
0000200c (__DATA,__data) external _NXArgc
00002008 (__DATA,__data) external _NXArgv
(undefined [lazy bound]) external __Z1fv (from a)
...

So each function does have a dependency to a certain file, yeah of course
I used the command to array.so,

$ cd /System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/lib-dynload
$ nm -mg array.so
(undefined [lazy bound]) external _PyErr_BadArgument (dynamically looked up)
(undefined [lazy bound]) external _PyErr_Clear (dynamically looked up)

What's (dynamically looked up)?
The answer was a linker option -undefined dynamic_lookup first supported in OSX10.3.
http://developer.apple.com/documentation/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html

$cat fakeb.cpp
$ gcc -dynamiclib -arch i386 -o a.dylib fakeb.cpp
$ gcc -dynamiclib -arch i386 -o b.dylib fakeb.cpp
$ gcc main.cpp -dylib a.dylib -dylib b.dylib -lstdc++
Undefined symbols:
"f()", referenced from:
_main in cca9JLe0.o
ld: symbol(s) not found
collect2: ld returned 1 exit status
$ gcc -dynamiclib -arch i386 -o a.dylib fakeb.cpp
$ gcc -dynamiclib -arch i386 -o b.dylib fakeb.cpp
$ gcc main.cpp -dylib a.dylib -dylib b.dylib -lstdc++ -undefined dynamic_lookup
$ nm -mg a.out
0000200c (__DATA,__data) external _NXArgc
00002008 (__DATA,__data) external _NXArgv
(undefined [lazy bound]) external __Z1fv (dynamically looked up)
...
$ gcc -dynamiclib -arch i386 -o a.dylib a.cpp
$ gcc -dynamiclib -arch i386 -o b.dylib b.cpp
$ ./a.out
a
$ gcc -dynamiclib -arch i386 -o a.dylib fakeb.cpp
$ ./a.out
b

Phew...

No comments: