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
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!