Search code examples
gccg++shared

Linking C program with C++ library (GCC 4.5+)


I was using gcc/g++ 4.4 to build my project, and now i'm trying to switch to gcc 4.5, but getting odd "undefined reference" errors when linking C program with C++ library. Here is my testcase:

  • source.c

    #ifdef LIBRARY
    extern "C" int one() {
        return 1;
    }
    #else
    #include <stdio.h>
    int one();
    int main() {
        printf ("%i\n", one());
        return 0;
    }
    #endif
    
  • Makefile

    all: clean program
    program: source.c library.so
        $(CC) -L. -lrary -o $@ $<
    library.so: source.c
        $(CXX) -shared -DLIBRARY -fPIC -o $@ $<
    .PHONY: clean
    clean:
        rm -f program library.so
    

Everything works fine while using GCC 4.4:

$ CXX=g++-4.4 CC=gcc-4.4 make
rm -f program library.so
g++-4.4 -shared -DLIBRARY -fPIC -o library.so source.c
gcc-4.4 -L. -lrary -o program source.c

But not working while using GCC 4.5:

$ CXX=g++-4.5 CC=gcc-4.5 make
rm -f program library.so
g++-4.5 -shared -DLIBRARY -fPIC -o library.so source.c
gcc-4.5 -L. -lrary -o program source.c
/tmp/ccC4kNHP.o: In function `main':
source.c:(.text+0xa): undefined reference to `one'
collect2: ld returned 1 exit status
make: *** [program] Error 1

Or GCC 4.6:

$ CXX=g++-4.6 CC=gcc-4.6 make
rm -f program library.so
g++-4.6 -shared -DLIBRARY -fPIC -o library.so source.c
gcc-4.6 -L. -lrary -o program source.c
/tmp/ccxNRNSS.o: In function `main':
source.c:(.text+0xa): undefined reference to `one'
collect2: ld returned 1 exit status
make: *** [program] Error 1

Anyone can shed a light on this issue?

PS: This one was built using 4.6:

$ nm -D library.so
                 w _Jv_RegisterClasses
0000000000201010 A __bss_start
                 w __cxa_finalize
                 w __gmon_start__
0000000000201010 A _edata
0000000000201020 A _end
00000000000005a8 T _fini
0000000000000458 T _init
000000000000055c T one

Solution

  • It is because of linker's --as-needed option being used i.e. the library is not linked until a symbol is actually found in the source which is part of the library. You should move your source files before linking in the compilation command. You could try changing your Makefile rule program from $(CC) -L. -lrary -o $@ $< to $(CC) $< -L. -lrary -o $@. Or alternatively, you could pass --no-as-needed to the linker i.e. $(CC) -Wl,--no-as-needed -L. -lrary -o $@ $<. The first method is better suited to be used.
    Hope this helps!