我在使用 automake 的项目中遇到了一个非常奇怪的链接错误。从手册来看,我所做的似乎很简单,所以我真的想知道我会做错什么......
我的项目有三个文件夹:
- src/common,我在其中将一些 C++ 文件编译成一个 libube-common.a 静态库
- src/engine,我在其中将一些文件编译成一个 libube-engine.a 静态库
- src/client,其中......你猜对了, libue-client.a ,还有一个文件 ube.cpp 这是我的主要
每个库都使用 Makefile.am 编译,如下所示:
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)
这导致各种对象使用如下行构建:
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
所有这些都放在图书馆里:
ar cru libube-common.a logging.o prefix_resource_resolver.o stat_file_checker.o
ranlib libube-common.a
所有这些看起来都很好,我什至可以将一些小测试程序与库链接(在同一个 makefile 中)
然后,在我的主程序的 Makefile.am 中,我要求链接到本地库:
ube_LDADD=../common/libube-common.a \
../engine/libube-engine.a \
libube-client.a \
... other libs ...
这就是我得到这样的错误的地方:
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> >)'
起初我虽然是因为一些静态符号,但我也遇到了非静态符号的问题。
我检查了生成的库,它似乎正确包含符号:
~/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
唯一的解决方法是明确链接到我的 .o 文件(通过将它们添加到 ube_LDADD 行......但这有点违背使用库的想法!!)
我似乎一直在关注手册:http ://www.gnu.org/software/hello/manual/automake/Linking.html#Linking
但显然我在某个地方搞砸了,所以欢迎任何想法!
谢谢
酸碱度
编辑:图书馆本身似乎工作,这似乎是一个链接问题。我可以将我的测试用例程序与它们联系起来。这是我所做的:
在文件夹 src/common/tests 中,有一个名为 common-tests.cpp 的 main 运行单元测试;common-tests bin 与库 libube-common.a 链接(它只需要 lib 内的对象,因为这些是单元测试)
# 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
运行 make check 时,测试程序是这样编译的:
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
一切都很完美。我能看到的唯一区别是,在这种情况下,库就在要链接的可执行文件旁边……这真的有什么不同吗?
另外,我尝试使用 -Wl,--whole-archive 之类的选项,但没有帮助(另外我不知道如何将它们添加到 Automake 生成的行...)