English 中文(简体)
Undefined reference when compiling against libraries generated by Automake
原标题:
  • 时间:2010-01-10 16:03:37
  •  标签:
  • c++
  • automake

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 ...)

最佳回答

This is most likely a library ordering issues - the more common a library is, the later it should occur in the final link line. Specifically, GNU ld reads libraries for symbols exactly once, and then discards all other symbols from the library, before moving on to the next library instruction. There s various solutions (see the man page for ld ) but the easiest one is to re-order the lines in your Makefile.am to put libube-common.a after the client and engine libs.

Note that Darwin ld does not have this behaviour, it preserves all library symbols by default (which potentially uses much more memory during linking).

问题回答

暂无回答




相关问题
Undefined reference

I m getting this linker error. I know a way around it, but it s bugging me because another part of the project s linking fine and it s designed almost identically. First, I have namespace LCD. Then I ...

C++ Equivalent of Tidy

Is there an equivalent to tidy for HTML code for C++? I have searched on the internet, but I find nothing but C++ wrappers for tidy, etc... I think the keyword tidy is what has me hung up. I am ...

Template Classes in C++ ... a required skill set?

I m new to C++ and am wondering how much time I should invest in learning how to implement template classes. Are they widely used in industry, or is this something I should move through quickly?

Print possible strings created from a Number

Given a 10 digit Telephone Number, we have to print all possible strings created from that. The mapping of the numbers is the one as exactly on a phone s keypad. i.e. for 1,0-> No Letter for 2->...

typedef ing STL wstring

Why is it when i do the following i get errors when relating to with wchar_t? namespace Foo { typedef std::wstring String; } Now i declare all my strings as Foo::String through out the program, ...

C# Marshal / Pinvoke CBitmap?

I cannot figure out how to marshal a C++ CBitmap to a C# Bitmap or Image class. My import looks like this: [DllImport(@"test.dll", CharSet = CharSet.Unicode)] public static extern IntPtr ...

Window iconification status via Xlib

Is it possible to check with the means of pure X11/Xlib only whether the given window is iconified/minimized, and, if it is, how?

热门标签