2012-12-07 19 views
6

Mam dwie proste pliki:doładowania testu - 'niezdefiniowane odniesienia' błędy

runner.cpp:

#define BOOST_TEST_DYN_LINK 
#define BOOST_TEST_MODULE Main 
#include <boost/test/unit_test.hpp> 

i test1.cpp:

#define BOOST_TEST_DYN_LINK 
#ifdef STAND_ALONE 
# define BOOST_TEST_MODULE Main 
#endif 
#include <boost/test/unit_test.hpp> 

BOOST_AUTO_TEST_SUITE(Foo) 

BOOST_AUTO_TEST_CASE(TestSomething) 
{ 
    BOOST_CHECK(true); 
} 

BOOST_AUTO_TEST_SUITE_END() 

Aby skompilować, jestem przy użyciu:

$ g++ -I/e/code/boost_1_52_0 -o runner -lboost_unit_test_framework runner.cpp test1.cpp 

Pojawia się następujący błąd:

C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\ccU0cDSz.o:runner.cpp:(.text+0x8c): multiple definition of `main' 
c:/pdev/mingw/bin/../lib/gcc/i686-pc-mingw32/4.7.2/../../../libboost_unit_test_framework.a(unit_test_main.o):unit_test_main.cpp:(.text.startup+0x0): first defined here 
c:/pdev/mingw/bin/../lib/gcc/i686-pc-mingw32/4.7.2/../../../libboost_unit_test_framework.a(unit_test_main.o):unit_test_main.cpp:(.text.startup+0x14): undefined reference to `init_unit_test_suite(int, char**)' 
C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\ccU0cDSz.o:runner.cpp:(.text+0x52): undefined reference to `_imp___ZN5boost9unit_test9framework17master_test_suiteEv' 
C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\ccU0cDSz.o:runner.cpp:(.text+0xb0): undefined reference to `_imp___ZN5boost9unit_test14unit_test_mainEPFbvEiPPc' 
C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\ccU0cDSz.o:runner.cpp:(.text$_ZN5boost9unit_test13test_observerD2Ev[__ZN5boost9unit_test13test_observerD2Ev]+0xe): undefined reference to `_imp___ZTVN5boost9unit_test13test_observerE' 
C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\ccU0cDSz.o:runner.cpp:(.text$_ZN5boost9unit_test13test_observerC2Ev[__ZN5boost9unit_test13test_observerC2Ev]+0xe): undefined reference to `_imp___ZTVN5boost9unit_test13test_observerE' 
C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\ccU0cDSz.o:runner.cpp:(.text$_ZN5boost9unit_test15unit_test_log_tC1Ev[__ZN5boost9unit_test15unit_test_log_tC1Ev]+0x22): undefined reference to `_imp___ZTVN5boost9unit_test15unit_test_log_tE' 
C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\cciSdkmB.o:test1.cpp:(.text+0x88): undefined reference to `_imp___ZN5boost9unit_test15unit_test_log_t14set_checkpointENS0_13basic_cstringIKcEEjS4_' 
C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\cciSdkmB.o:test1.cpp:(.text+0x136): undefined reference to `_imp___ZN5boost10test_tools9tt_detail10check_implERKNS0_16predicate_resultERKNS_9unit_test12lazy_ostreamENS5_13basic_cstringIKcEEjNS1_10tool_levelENS1_10check_typeEjz' 
C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\cciSdkmB.o:test1.cpp:(.text+0x21d): undefined reference to `_imp___ZN5boost9unit_test9ut_detail24auto_test_unit_registrarC1ENS0_13basic_cstringIKcEE' 
C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\cciSdkmB.o:test1.cpp:(.text+0x284): undefined reference to `_imp___ZN5boost9unit_test9ut_detail24auto_test_unit_registrarC1EPNS0_9test_caseEm' 
C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\cciSdkmB.o:test1.cpp:(.text+0x2a4): undefined reference to `_imp___ZN5boost9unit_test9ut_detail24auto_test_unit_registrarC1Ei' 
C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\cciSdkmB.o:test1.cpp:(.text$_ZN5boost9unit_test14make_test_caseERKNS0_9callback0INS0_9ut_detail6unusedEEENS0_13basic_cstringIKcEE[__ZN5boost9unit_test14make_test_caseERKNS0_9callback0INS0_9ut_detail6unusedEEENS0_13basic_cstringIKcEE]+0x1d): undefined reference to `_imp___ZN5boost9unit_test9ut_detail24normalize_test_case_nameENS0_13basic_cstringIKcEE' 
C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\cciSdkmB.o:test1.cpp:(.text$_ZN5boost9unit_test14make_test_caseERKNS0_9callback0INS0_9ut_detail6unusedEEENS0_13basic_cstringIKcEE[__ZN5boost9unit_test14make_test_caseERKNS0_9callback0INS0_9ut_detail6unusedEEENS0_13basic_cstringIKcEE]+0x5b): undefined reference to `_imp___ZN5boost9unit_test9test_caseC1ENS0_13basic_cstringIKcEERKNS0_9callback0INS0_9ut_detail6unusedEEE' 
collect2.exe: error: ld returned 1 exit status 

Używam g ++ 4.7.2 na MinGW, z doładowaniem 1.52.0.

Te same błędy występują przy próbie kompilacji test1.cpp - z wyjątkiem "wielkiej definicji głównej".

Przez dłuższy czas analizowałem oficjalną dokumentację, ale jej brak zawiera szczegółowe informacje dotyczące opcji łączenia. Kiedy skompilowałem biblioteki boost, oprócz unit_test_framework, otrzymałem także prg_exec_monitor i test_exec_monitor; może powinienem jakoś je połączyć? Próbowałem wielu kombinacji, ale wszystkie doprowadziły do ​​pewnego rodzaju niezdefiniowanego błędu linkera referencyjnego.

Pełna lista bibliotek Boost generowane - Mam je wszystkie w katalogu głównym projektu:

libboost_prg_exec_monitor-mgw47-mt-1_52.a 
libboost_prg_exec_monitor-mgw47-mt-1_52.dll 
libboost_prg_exec_monitor-mgw47-mt-1_52.dll.a 
libboost_prg_exec_monitor-mgw47-mt-d-1_52.a 
libboost_prg_exec_monitor-mgw47-mt-d-1_52.dll 
libboost_prg_exec_monitor-mgw47-mt-d-1_52.dll.a 
libboost_test_exec_monitor-mgw47-mt-1_52.a 
libboost_test_exec_monitor-mgw47-mt-d-1_52.a 
libboost_unit_test_framework-mgw47-mt-1_52.a 
libboost_unit_test_framework-mgw47-mt-1_52.dll 
libboost_unit_test_framework-mgw47-mt-1_52.dll.a 
libboost_unit_test_framework-mgw47-mt-d-1_52.a 
libboost_unit_test_framework-mgw47-mt-d-1_52.dll 
libboost_unit_test_framework-mgw47-mt-d-1_52.dll.a 
+1

z G ++ trzeba umieścić swoje bibliotek (-lwhatever) po źródła lub obiektu plików (tj 'g ++ -I/e/code/boost_1_52_0 -o runner runner.cpp test1.cpp -lboost_unit_test_framework'). Link [tutaj] (http://www.network-theory.co.uk/docs/gccintro/gccintro_18.html). Możliwe, że będziesz musiał dodać '-L/path/to/libraries' analogicznie do' -I/e/code/boost_1_52_0'. –

+1

[Ta odpowiedź] (http: // stackoverflow.com/a/2907582/1252091) wydaje się być bardzo podobny do tego, co robisz. –

+0

@llonesmiz rzeczywiście, umieszczanie lib po obiektach działa. '-L' jest również potrzebny, a biblioteka musi zostać przekazana jako' -lboost_unit_test_framework-mgw47-mt-1_52'. Przekazanie go jako '-lboost_unit_test_framework' powoduje błędy linkowania. Jednak gdy podejrzewałem, że może nie znaleźć biblioteki, podałem coś takiego jak '-lfoo' i narzekało, że taka liba istnieje. Po konsultacji z [this page] (http://www.mingw.org/wiki/HOWTO_Specify_the_Location_of_External_Libraries_for_use_with_MinGW) o domyślnych ścieżkach biblioteki MinGW, okazało się, że miałem jeszcze jeden 'libboost_unit_test_framework.a' w jednym z tych folderów. –

Odpowiedz

18

z pomocą @llonesmiz szereg zagadnień zostały zidentyfikowane.

1. Biblioteki muszą być określone po obiektów i źródeł, które z nich korzystają.

Jak opisano here:

The traditional behavior of linkers is to search for external functions from left to right in the libraries specified on the command line. This means that a library containing the definition of a function should appear after any source files or object files which use it. This includes libraries specified with the short-cut -l option, as shown in the following command:

$ gcc -Wall calc.c -lm -o calc (correct order)

With some linkers the opposite ordering (placing the -lm option before the file which uses it) would result in an error,

$ cc -Wall -lm calc.c -o calc (incorrect order)
main.o: In function 'main':
main.o(.text+0xf): undefined reference to 'sqrt'

because there is no library or object file containing sqrt after ‘calc.c’. The option -lm should appear after the file ‘calc.c’

2. ścieżki biblioteka powinny być wyraźnie określone.

Jeśli nie określono ścieżek biblioteki, linker może szukać bibliotek w serii folderów domyślnych, a tym samym załadować inną bibliotekę, a następnie przeznaczoną. Tak właśnie stało się w moim przypadku - chciałem połączyć boost_unit_test_framework, ale nie podałem określenia ścieżki, ponieważ założyłem, że linker będzie wyglądał w bieżącym folderze. Tak właśnie dzieje się w czasie wykonywania - jeśli dll jest w tym samym folderze z exe, znajdzie go.

Znalazłem to trochę dziwne, że linker znalazłby bibliotekę, ponieważ był to o nazwie ibboost_unit_test_framework-mgw47-mt-1_52.dll. Kiedy próbowałem połączyć się z nieistniejącą biblioteką, linker narzekał jednak, więc założyłem, że nie jest to numer , a linker MinGW ignoruje te sufiksy.

Po dalszych badaniach znalazłem this article about MinGW library paths. Foldery MinGW wyszukujące biblioteki można znaleźć w danych wyjściowych gcc -print-search-dirs. Artykuł zawiera również pewne bash magię sensu tego wyjścia:

gcc -print-search-dirs | sed '/^lib/b 1;d;:1;s,/[^/.][^/]*/\.\./,/,;t 1;s,:[^=]*=,:;,;s,;,; ,g' | tr \; \\012 | grep -v '^ */' 

To będzie drukować ładny wykaz tych folderach. gcc będzie nie, domyślnie szukać w bieżącym katalogu dla bibliotek. Zajrzałem do każdego z nich i znalazłem bibliotekę , która była ładowana - libboost_unit_test_framework.a, statyczną bibliotekę.

To prowadzi do światła inny problem warto wspomnieć:

3. Static kontra dynamiczne łączenie

nie precyzuje, czy chcę boost_unit_test_framework związane statycznie lub dynamicznie. W tym przypadku gcc prefers dynamic linking:

Because of these advantages gcc compiles programs to use shared libraries by default on most systems, if they are available. Whenever a static library ‘libNAME.a’ would be used for linking with the option -lNAME the compiler first checks for an alternative shared library with the same name and a ‘.so’ extension.

(so jest rozszerzeniem dla dynamicznych bibliotek na Unix - W systemie Windows, odpowiednik jest dll.)

Więc, co się stało jest to, że gcc szukali libboost_unit_test_framework.dll w wszystkie jego domyślne foldery, ale nie może ich znaleźć. Następnie wyszukało to: libboost_unit_test_framework.a i statycznie połączyło to. Doprowadziło to do błędów łączących, ponieważ źródła mają #define BOOST_TEST_DYN_LINK, a zatem spodziewają się, że będą dynamicznie połączone z biblioteką.

Aby wymusić statyczne lub dynamiczne linkowanie, opcje łącznikowe -Wl,-Bstatic i -Wl,-Bdynamic wchodzić w grę, opisane here.

Jeśli powiem łącznik, który chcę dynamiczne łączenie:

$ g++ -I/e/code/boost_1_52_0 runner.cpp test1.cpp -o runner -Wl,Bdynamic -lboost_unit_test_framework 

ta zakończy się niepowodzeniem, ponieważ łącznik nie będzie w stanie odnaleźć dll.

4.Summary

Problemy były:

  1. biblioteki, gdzie wyszczególnione przed ich źródeł, które wykorzystywane
  2. lib ścieżka nie została określona
  3. typ łączenia waśń Podano
  4. nazwa biblioteki była nieprawidłowa

końcowy, komenda pracy:

$ g++ -I/e/code/boost_1_52_0 -o runner runner.cpp test1.cpp -L. -Wl,-Bdynamic -lboost_unit_test_framework-mgw47-mt-1_52 
+0

Doskonała odpowiedź. Czy problem z wielokrotną definicją głównego rozwiązania został rozwiązany za pomocą tego? Mam zamiar użyć czegoś podobnego w najbliższej przyszłości i jestem pewien, że będzie to bardzo pomocne. –

+0

@llonesmiz, tak było. Nadal nie jestem pewien, dlaczego tak się stało; nie może się powielać z nowszymi bibliotekami. –

+0

Twój katalog pokazuje dwie wersje każdej biblioteki. Jedna z '-d-' w środku nazwy i jedna bez. Na przykład 'libboost_unit_test_framework-mgw47-mt-1_52.a' i' libboost_unit_test_framework-mgw47-mt-d-1_52.a'. Skąd wiesz, z których z tych użyć? – Brick

Powiązane problemy