I am having a pretty strange linking error in a project that uses automake. What I do seems pretty simple from the manual, so I really wonder what I can doing wrong ...
My project has three folders :
- src/common, in which I compile a number of C++ files into a libube-common.a static lib
- src/engine, in which I compile a number of files into a libube-engine.a static lib
- src/client, in which ... you guessed it, libue-client.a , and also one file ube.cpp that is my main
Each of the libraries is compiled with a Makefile.am like this :
noinst_LIBRARIES=libube-common.a
libube_common_a_SOURCES=gettext.h lua_helper.hpp \
silent_ostream.hpp \
logging.hpp logging.cpp \
logger_interface.hpp \
... etc ...
AM_CPPFLAGS=-DSRCDIR=\"${srcdir}\" \
-DLUADIR=\"${luadir}\" \
-Wall -Werror \
-I$(srcdir)/../../include \
$(LUA_INCLUDE) \
$(BOOST_CPPFLAGS)
This results in the various objects being built with a line like :
g++ -DHAVE_CONFIG_H -I. -I../../../../../src/common -I../.. -DSRCDIR=\"../../../../../src/common\" -DLUADIR=\"\" -Wall -Werror -I../../../../../src/common/../../include -I/usr/include/lua5.1 -I/usr/include -g -O2 -MT logging.o -MD -MP -MF .deps/logging.Tpo -c -o logging.o ../../../../../src/common/logging.cpp
And all of them are put in the library with :
ar cru libube-common.a logging.o prefix_resource_resolver.o stat_file_checker.o
ranlib libube-common.a
All of this seems good and well, I can even linked some little tests programs against the library (inside the same makefile)
Then, in the Makefile.am of my main program, I asked to link against the local libraries :
ube_LDADD=../common/libube-common.a \
../engine/libube-engine.a \
libube-client.a \
... other libs ...
And that's where I get errors like this :
g++ -g -O2 -o ube ube.o ../common/libube-common.a ../engine/libube-engine.a libube- client.a -L/usr/include/lua5.1/lib -llua5.1 -lm -ldl -L/usr/lib -lSDL -lSDL_image -lpng -ltiff -ljpeg -lz -lSDL_ttf -lfreetype -lSDL_mixer -lSDL_mixer -lSDL_ttf -lSDL_image
libube-client.a(game_loop.o): In function `Logging::debug_ostream(std::basic_string<char, std::char_traits<char>, std::allocator<char> >)':
(...) logging.hpp:54: undefined reference to `Logging::get_ostream(LogLevel::Level, std::basic_string<char, std::char_traits<char>, std::allocator<char> >)'
(...)logging.hpp:54: undefined reference to `Logging::get_ostream(LogLevel::Level, std::basic_string<char, std::char_traits<char>, std::allocator<char> >)'
At first I though it was because of some static symbols, but I also get the issue with non-static ones.
I checked the generated libs, and it seem to contain the symbol properly :
~/prj/ube/builds/linux/current/src/common$ nm -C libube-common.a | grep logging.o -C 20
logging.o:
00000010 t global constructors keyed to _ZN7Logging15disable_loggingEv
00000000 V guard variable for Logging::get_instance()::s_local_instance
000000b0 T Logging::get_ostream(LogLevel::Level, std::string)
00000000 T Logging::disable_logging()
00000040 T Logging::is_category_enabled(LogLevel::Level, std::string&)
U std::ios_base::Init::Init()
U std::ios_base::Init::~Init()
00000000 b std::__ioinit
U __cxa_atexit
U __dso_handle
U __gxx_personality_v0
The only fix is to explicitely link against my .o files (by adding them to the ube_LDADD line ... but that kinda defies the idea of using a library !!)
I seem to have been following the manual : http://www.gnu.org/software/hello/manual/automake/Linking.html#Linking
But ovbiously I messed up somewhere, so any idea is welcome !!
Thanks
PH
EDIT : The library in itself seems to work, it seems to be a linking issue. I can link my test cases programs agaist them. Here is what I do :
In folder src/common/tests, there is a main called common-tests.cpp that runs unit tests ; the common-tests bin is linked against the library libube-common.a (it only needs objects that are inside the lib, since those are unit tests)
# There is one program that aggreatates all tests cases
check_PROGRAMS = common-tests
common_tests_SOURCES= tests/common_tests.cpp \
tests/prefix_resource_resolver_test.cpp \
tests/mock_file_checker.hpp \
tests/stat_file_checker_test.cpp
# The program needs to be compiled against the local lib
common_tests_LDADD=libube-common.a -L$(top_srcdir)/lib -lgtest -lgmock -llua -ldl
# This means common-tests is run when using 'make check'.
TESTS = common-tests
When running make check, the test program is compiled this way :
g++ -g -O2 -o common-tests common_tests.o prefix_resource_resolver_test.o stat_file_checker_test.o libube-common.a -L../../../../../lib -lgtest -lgmock -llua -ldl -lSDL_mixer -lSDL_ttf -lSDL_image
And things work perfectly. The only difference I can see is that in this case the library is right next to the executable to link ... could this really make any difference ?
Also, I tried using options like -Wl,--whole-archive but it did not help (plus I don't know how to add them to the Automake-generated line ...)