6

automake を使用するプロジェクトで、奇妙なリンク エラーが発生します。私がやっていることはマニュアルから見るとかなり単純に思えるので、何が間違っているのだろうか...

私のプロジェクトには 3 つのフォルダーがあります。

  • src/common では、いくつかの C++ ファイルを libube-common.a 静的ライブラリにコンパイルします。
  • src/engine で、いくつかのファイルを libube-engine.a 静的ライブラリにコンパイルします。
  • src/client には ... ご想像のとおり、 libue-client.a と、私のメインである ube.cpp という 1 つのファイルがあります。

各ライブラリは、次のような 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.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

しかし、明らかに私はどこかを台無しにしたので、どんなアイデアでも大歓迎です!!

ありがとう

PH


編集:ライブラリ自体は機能しているようですが、リンクの問題のようです。テストケースプログラムをそれらに対してリンクできます。これが私がすることです:

フォルダー src/common/tests には、単体テストを実行する common-tests.cpp というメインがあります。common-tests ビンは、ライブラリ libube-common.a に対してリンクされています (これらは単体テストであるため、ライブラリ内にあるオブジェクトのみが必要です)。

# 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 によって生成された行に追加する方法がわかりません ...)

4

1 に答える 1

5

これはライブラリの順序付けの問題である可能性が最も高く、ライブラリが「一般的」であるほど、最後のリンク行で発生するはずです。具体的には、GNU ld はシンボルのライブラリを1 回だけ読み取り、ライブラリから他のすべてのシンボルを破棄してから、次のライブラリ命令に進みます。さまざまな解決策がありますが ('ld' については man ページを参照)、最も簡単な方法は、Makefile.am の行を並べ替えて、クライアントとエンジンのライブラリのに libube-common.a を配置することです。

Darwin ld にはこの動作がなく、デフォルトですべてのライブラリ シンボルが保持されることに注意してください (リンク中にさらに多くのメモリを使用する可能性があります)。

于 2010-01-11T14:06:23.680 に答える