Search code examples
c++g++ld

Why am I getting a linker error: undefined reference to ...?


Why am I getting this error: undefined reference to `bfopen(char const*, int)'?

I have a shared library that I created that includes a function definition for the function bfopen among others. The name of this library is libfiles.so and it is in a local ext/lib directory to where I am building from.

and I am compiling with:

g++ -std=c++11 -fPIC -g -Wall -D_DEBUG -I$(PWD)/src -I$(PWD)/ext/include -o parser_tst parser_tst.cc $(PWD)/src/parser.o -L$(PWD)/ext/lib -lpthread -lfftw3f -ldsp -lfiles

I've substituted $(PWD) for my working dir. I've looked inside libfiles.so with nm -D ext/lib/libfiles.so and was able to find the function definition listed there so I am at a loss. I also don't get any errors like file does not exist: libfiles.so so it seems like it is at least linking with that file.

Here is a sample of my setup: (all paths are clipped to their local path)

ext/sample/src/test.h:

#ifndef TEST_H
#define TEST_H

int test();

#endif /* TEST_H */

ext/sample/src/test.c:

#include "test.h"

int test() {
    return 0;
}

and here is the cleaned file structure:

.
./ext
./ext/Makefile
./ext/sample
./ext/sample/src
./ext/sample/src/Makefile
./ext/sample/src/test.c
./ext/sample/src/test.h
./ext/sample/tst
./ext/sample/tst/Makefile
./ext/sample/Makefile
./ext/sample/ext
./src
./tst
./tst/test_tst.cc
./tst/Makefile
./Makefile

after calling make build it looks like this:

.
./ext
./ext/Makefile
./ext/sample
./ext/sample/src
./ext/sample/src/Makefile
./ext/sample/src/test.c
./ext/sample/src/test.h
./ext/sample/src/test.o
./ext/sample/tst
./ext/sample/tst/Makefile
./ext/sample/Makefile
./ext/sample/ext
./ext/sample/include
./ext/sample/include/test.h
./ext/sample/lib
./ext/sample/lib/libtest.so
./ext/lib
./ext/lib/libtest.so
./ext/include
./ext/include/test.h
./src
./tst
./tst/test_tst.cc
./tst/Makefile
./Makefile

and finally I call make test which produces the output (including the error):

make  -i -C ./tst
make[1]: Entering directory `$(PWD)/tst'
make all_tst
make[2]: Entering directory `$(PWD)/tst'
g++ -std=c++11 -fPIC -g -Wall -D_DEBUG -I./src -I$(PWD)/ext/include -o test_tst test_tst.cc -L$(PWD)/ext/lib -ltest
test_tst.cc: In function ‘int main(int, char**)’:
test_tst.cc:4:6: warning: unused variable ‘t’ [-Wunused-variable]
  int t = test();
      ^
/tmp/ccMq869q.o: In function `main':
$(PWD)/tst/test_tst.cc:4: undefined reference to `test()'
collect2: error: ld returned 1 exit status
make[2]: [test_tst] Error 1 (ignored)
make[2]: Leaving directory `$(PWD)/tst'
make[1]: Leaving directory `$(PWD)/tst'

I tried using the tcsh equivalent of export (setenv LD_LIBRARY_PATH .) and that didn't help


Solution

  • One possible problem is, that you have ext/sample/src/test.c a C-file, which will compiled as C-code.

    But your application which uses your library is C++ code

    g++ -std=c++11 -fPIC -g -Wall -D_DEBUG -I./src -I$(PWD)/ext/include -o test_tst test_tst.cc -L$(PWD)/ext/lib -ltest
    

    and includes a header, which is in this case also compiled as C++-code from the c++ file but compiled as C-code from your C-file!

    So you should include your header from the c++ code with:

    extern "C" {
    #include "test.h"
    }
    

    How to mix C and C++ code: mix C and C++ code

    The reason why the linker will not find the symbol from the c-file is, that names are "demangled" in C++, because it needs a "trick" to do the function overloading. A better and more detailed explanation can be found here: name mangling