質問

I've compiled on OSX a shared library with some external dependences (boost, OpenGL):

g++ -dynamiclib -undefined suppress -flat_namespace -o "libMY_LIB.dylib" ./windowbase.o -lGL -lGLU -lGLUT -lboost_system -lboost_thread

No errors, file libMY_LIB.dylib results in Mach-O 64-bit dynamically linked shared library x86_64, and otool -L libMY_LIB.dylib outputs:

libPixelsGL.dylib (compatibility version 0.0.0, current version 0.0.0)
/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib (compatibility version 1.0.0, current version 1.0.0)
/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGLU.dylib (compatibility version 1.0.0, current version 1.0.0)
/System/Library/Frameworks/GLUT.framework/Versions/A/GLUT (compatibility version 1.0.0, current version 1.0.0)
libboost_system.dylib (compatibility version 0.0.0, current version 0.0.0)
libboost_thread.dylib (compatibility version 0.0.0, current version 0.0.0)
/usr/lib/libstdc++.6.dylib (compatibility version 7.0.0, current version 52.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 159.1.0)

Now I try to link an executable against libMY_LIB.dylib, using only functions in MY_LIB.h (and compiled in the lib):

g++ -L"/path/to/MY_LIB" -o "Program" ./main.o -lMY_LIB

but it fails, printing:

Undefined symbols for architecture x86_64:
"boost::system::system_category()", referenced from:
    __static_initialization_and_destruction_0(int, int)in main.o
    boost::mutex::mutex()in main.o
    boost::mutex::lock()    in main.o
    boost::mutex::unlock()    in main.o
"boost::system::generic_category()", referenced from:
    __static_initialization_and_destruction_0(int, int)in main.o
"boost::thread::detach()", referenced from:
    boost::thread::~thread()in main.o
ld: symbol(s) not found for architecture x86_64

Some explanation and/or help?

Thanks!

EDIT

I tried to link the lib without -undefined suppress -flat_namespace flags and the executable with them, and the latter worked. Could please anyone tell me why? May it be boost libs I have were compiled with those flags?

Renewed thanks!

役に立ちましたか?

解決

The most significant issue you have is that you're not linking your application against the libraries that provide the symbols that it uses.

Your error message calls out the main.o contains references to boost::system::system_category(), boost::system::generic_category(), and boost::thread::detach(). Therefore, when linking main.o in to an executable binary you need to link to a library that provides these symbols, in this case by passing -lboost_system -lboost_thread.


As for -undefined suppress -flat_namespace: these options have the effect of moving detection of missing symbols from build time to run time. In general you should avoid using these flags unless you have a very specific need. The reason that building your main executable with these flags "works" is that you've asked told the linker not to generate errors for missing symbols. Since it's ignorant of these symbols it does nothing to ensure that the library that provides them is loaded in to your application's address space at runtime. You're getting lucky since the symbols happen to be provided by libraries that your libMY_LIB.dylib also links to.

For sake of illustration, consider a simple test library, liba.dylib, that exports a function a:

$ cat a.c
int a(void)
{
    return 1;
}
$ cc -dynamiclib -o liba.dylib a.c
$

And a simple application that makes use of this function:

$ cat main.c
#include <stdio.h>

extern int a(void);

int main(int argc, char **argv)
{
    fprintf(stderr, "a: %d\n", a());
    return 0;
}

Now let's look at three approaches to linking that library in to our application.

1) Without specifying the library at all

$ cc -o main main.c 
Undefined symbols for architecture x86_64:
  "_a", referenced from:
      _main in main-JmKbTd.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

This is the case you initially reported seeing in your question.

2) Specifying -undefined suppress -flat_namespace

$ cc -undefined suppress -flat_namespace -o main main.c 
$

That successfully created an executable, but when we run the binary:

$ ./main 
dyld: lazy symbol binding failed: Symbol not found: _a
  Referenced from: /tmp/./main
  Expected in: flat namespace

dyld: Symbol not found: _a
  Referenced from: /tmp/./main
  Expected in: flat namespace

Trace/BPT trap: 5

In this case, the loader at runtime has no idea that it needs to load liba.dylib to find the function a:

$ otool -L main 
main:
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1197.0.0)
$ nm -m main | grep _a
                 (undefined) external _a
$ 

3) Specifying the library correctly

$ cc -L. -la -o main main.c 
$ ./main 
a: 1
$ 

And you can see that the binary main knows both to load liba.dylib and that it is liba.dylib that provides the function a that main uses:

$ otool -L main
main:
    liba.dylib (compatibility version 0.0.0, current version 0.0.0)
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1197.0.0)
$ nm -m main | grep _a
                 (undefined) external _a (from liba)
$ 

In summary, my recommendation is to stop passing -undefined suppress -flat_namespace at all when building your libraries and binaries, and to ensure that each component links to the necessary libraries for the symbols that it uses.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top