2010-01-10 4 views
6

J'ai une erreur de liaison assez étrange dans un projet qui utilise automake. Ce que je semble assez simple du manuel, donc je me demande vraiment ce que je peux faire mal ...Référence non définie lors de la compilation des bibliothèques générées par Automake

Mon projet a trois dossiers:

  • src/commune, où je compile un certain nombre de C++ fichiers dans un libube-common.a static lib
  • src/engine, dans lequel je compiler un certain nombre de fichiers dans un libube-engine.a static lib
  • src/client, dans lequel ... vous l'avez deviné, libue-client.a, et aussi un fichier ube.cpp qui est mon principal

Chacune des bibliothèques est compilé avec un Makefile.am comme ceci:

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) 

Il en résulte les divers objets en cours de construction avec une ligne comme:

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 

Et tous sont mis en la bibliothèque:

ar cru libube-common.a logging.o prefix_resource_resolver.o stat_file_checker.o 
ranlib libube-common.a 

Tout cela semble bon et bien, je peux même lié quelques petits programmes de tests contre la bibliothèque (dans le même makefile)

Puis, dans le Makefile.am de mon programme principal, j'ai demandé de lier avec les bibliothèques locales:

ube_LDADD=../common/libube-common.a \ 
     ../engine/libube-engine.a \ 
     libube-client.a \ 
      ... other libs ... 

Et c'est là que je reçois des erreurs comme ceci:

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

Dans un premier temps Je pensais que c'était à cause de certains symboles statiques, mais j'ai aussi le problème avec ceux qui ne sont pas statiques.

J'ai vérifié les libs générés, et il semble contenir le symbole correctement:

~/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 

La seule solution est de lier mes fichiers contre explicitement .o (en les ajoutant à la ligne ... mais ube_LDADD qui défie un peu l'idée d'utiliser une bibliothèque !!)

Il me semble avoir suivi le manuel: http://www.gnu.org/software/hello/manual/automake/Linking.html#Linking

Mais je ovbiously foiré quelque part, de sorte que toute idée est la bienvenue !!

Merci

PH


EDIT: La bibliothèque en elle-même semble fonctionner, il semble être un problème de liaison. Je peux lier mes programmes de cas de test à leur taille. Voici ce que je fais:

Dans le dossier src/common/tests, il y a un principal appelé common-tests.cpp qui exécute des tests unitaires; la poubelle de tests communs est liée à la bibliothèque libube-common.un (dont il a besoin que les objets qui sont à l'intérieur du lib, puisque ce sont des tests unitaires)

# 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 

Lors de l'exécution faire vérifier, le programme de test est compilé de cette façon:

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 

Et les choses fonctionnent parfaitement. La seule différence que je peux voir est que dans ce cas, la bibliothèque est juste à côté de l'exécutable à relier ... cela pourrait-il vraiment faire une différence?

Aussi, j'ai essayé d'utiliser des options comme -Wl, - l'archive complète, mais il n'a pas aidé (plus je ne sais pas comment les ajouter à la ligne générée par Automake ...)

+0

Ces mêmes bibliothèques fonctionnent sur votre plate-forme? Vous pouvez les lier à un petit testcase? – Potatoswatter

+0

Normalement, es, voir mes modifications ... – phtrivier

Répondre

4

Cette est probablement un problème d'ordre dans la bibliothèque - plus une bibliothèque est «commune», plus tard elle doit apparaître dans la dernière ligne de liens. Plus précisément, GNU ld lit les bibliothèques pour les symboles exactement une fois, puis supprime tous les autres symboles de la bibliothèque avant de passer à l'instruction de bibliothèque suivante. Il existe différentes solutions (voir la page de manuel pour 'ld') mais la plus simple est de réorganiser les lignes dans votre Makefile.am pour mettre libube-common.a après les librairies client et moteur. Notez que Darwin ld a et non a ce comportement, il préserve tous les symboles de bibliothèque par défaut (qui utilise potentiellement beaucoup plus de mémoire lors de la liaison).

+0

Vous avez lu dans mon esprit (ou en fait, j'ai lu le vôtre, ou nous avons tous les deux ajouté la même épiphanie en même temps): c'était un problème de commande. Voir, comme mon client lib dépend des librairies du moteur qui dépend des libs communes, je les avais naïvement écrites dans l'ordre common-engine-client. Je viens de changer l'ordre à client - engine-common, et devinez quoi, tout fonctionne. J'étais sur le point de modifier ma question, mais vous obtenez des points pour l'action préventive! Merci à vous et à http://www.network-theory.co.uk/docs/gccintro/gccintro_18.html. – phtrivier

+0

Cela vient de résoudre un problème avec lequel j'ai été coincé pendant des heures :-) – krico

+0

Merci, j'étais coincé aussi .. –

Questions connexes