Undefined reference when linking with static library, but successful link when compiling with src

c++, linker-errors, makefile

Solution

I haven't seen all your code, but the problem is most likely caused by how static linking works (http://eli.thegreenplace.net/2013/07/09/library-order-in-static-linking/).

Try changing the order of the libraries, and specifically, try changing this:

$(MODULE_EXE): $(OBJS)
  $(CC) $(LIB_DIRS) $(LIBS) $(LINKER_OPTS) -o $@ $^ 

into this:

$(MODULE_EXE): $(OBJS)
  $(CC) $(LIB_DIRS) $(LINKER_OPTS) -o $@ $^ $(LIBS)

Problem

I'm trying to create a C library, and a C++ test program for the library using Boost::Test. The code that I posted in this question is a simplification of my code, and it displays the exact same problem. Please help! Here's the directory structure. `childlib` is the library I'm trying to create, and `test` is the test program. ``` > tree . `-- src |-- main | |-- c | | `-- childlib.c | |-- childlib.h | `-- makefile `-- test |-- cpp | `-- test.cpp `-- makefile 5 directories, 5 files ``` I can make `childlib` into a static library successfully: ``` > cd src/main > make gcc -c -fPIC -o c/childlib.o c/childlib.c ar rcs libchildlib.a c/childlib.o ranlib libchildlib.a ``` But I can't make my test program by linking with it: ``` > cd ../test/ > make g++ -I. -I../main -Imy_boost_install_dir/include -c -std=c++11 -o cpp/test.o cpp/test.cpp g++ -L../main -Lmy_boost_install_dir/lib -lchildlib -lboost_unit_test_framework -Wl,-rpath=my_boost_install_dir/lib -o test_childlib cpp/test.o cpp/test.o: In function `test_func1::test_method()': test.cpp:(.text+0x15e7e): undefined reference to `childlib_func1()' collect2: error: ld returned 1 exit status make: *** [test_childlib] Error 1 ``` On the other hand, if I run the compilation manually by removing the reference to the static lib and adding childlib.c as a source file, I can make the test program successfully: ``` > g++ -Lmy_boost_install_dir/lib -lboost_unit_test_framework -Wl,-rpath=my_boost_install_dir/lib -o test_childlib cpp/test.o ../main/c/childlib.c > ./test_childlib Running 1 test case... *** No errors detected ``` Here's the various source files. test.cpp: ``` #include <cstdlib> #include <stdint.h> #define BOOST_TEST_MODULE childlib test #include <boost/test/unit_test.hpp> #include <boost/test/included/unit_test.hpp> #include "childlib.h" BOOST_AUTO_TEST_CASE( test_func1 ) { childlib_func1(); BOOST_CHECK(true); } ``` childlib.h: ``` #ifndef CHILDLIB_H_ #define CHILDLIB_H_ void childlib_func1(); #endif /* CHILDLIB_H_ */ ``` and finally childlib.c: ``` #include <stdint.h> void childlib_func1() { return; } ``` The two makefiles are below. `childlib` makefile: Eventually I want to also create a dynamic library but right now it's commented out of `make all`: ``` # childlib CC = gcc SRCS = $(wildcard c/*.c) OBJS = $(SRCS:.c=.o) HDRS = $(wildcard *.h) MODULE_BASE_NAME = childlib MODULE_LIB_A = lib$(MODULE_BASE_NAME).a MODULE_LIB_SO = lib$(MODULE_BASE_NAME).so INCLUDE_DIRS = . INCLUDE = $(addprefix -I,$(INCLUDE_DIRS)) CFLAGS = -c -fPIC all: $(MODULE_LIB_A) # $(MODULE_LIB_SO) $(MODULE_LIB_A): $(OBJS) ar rcs $@ $^ ranlib $@ $(MODULE_LIB_SO): $(OBJS) $(CC) -shared -o $@ $^ .c.o: $(CC) $(CFLAGS) -o $@ $^ clean: -rm -f $(MODULE_LIB_A) $(MODULE_LIB_SO) $(OBJS) -find . -name '*~' -delete ``` Here's the test harness makefile: ``` # test CC = g++ SRCS = $(wildcard cpp/*.cpp) OBJS = $(SRCS:.cpp=.o) MODULE_EXE = test_childlib MAIN_DIR = ../main BOOST_DIR = my_boost_install_dir BOOST_INC_DIR = $(BOOST_DIR)/include BOOST_LIB_DIR = $(BOOST_DIR)/lib BOOST_LIBS = boost_unit_test_framework INCLUDE = $(addprefix -I,. $(MAIN_DIR) $(BOOST_INC_DIR)) LIB_DIRS = $(addprefix -L,$(MAIN_DIR) $(BOOST_LIB_DIR)) LIBS = $(addprefix -l,childlib $(BOOST_LIBS)) LINKER_OPTS = -Wl,-rpath=$(BOOST_LIB_DIR) CFLAGS = -c -std=c++11 all: test test: $(MODULE_EXE) ./$(MODULE_EXE) $(MODULE_EXE): $(OBJS) $(CC) $(LIB_DIRS) $(LIBS) $(LINKER_OPTS) -o $@ $^ .cpp.o: $(CC) $(INCLUDE) $(CFLAGS) -o $@ $^ clean: -rm -f $(MODULE_EXE) $(OBJS) -find . -name '*~' -delete ``` I'm using gcc & g++ 4.8.1. I'm also using boost 1.54.0 compiled with gcc 4.7.2. It seems like I need to just provide the right options to g++ in my test makefile, but I don't know what they are. Can someone please help me link the `childlib` library with my test program?

Original source

Related problems