2012-12-07 54 views
6

我有兩個簡單的文件:升壓試驗 - '未定義的參考' 錯誤

runner.cpp:

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

和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() 

進行編譯,我使用:

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

我得到以下錯誤:

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 

我在MinGW上使用g ++ 4.7.2,boost 1.52.0。

僅在嘗試編譯test1.cpp時出現同樣的錯誤 - 「多主定義」除外。

我在官方文檔中閱讀了很長一段時間,但在關於鏈接選項的細節上很少見。當我編譯提升庫時,除了unit_test_framework,我也得到了prg_exec_monitortest_exec_monitor;也許我應該連接這些莫名其妙?我嘗試了很多組合,但都導致了某種未定義的參考鏈接器錯誤。

完成升壓產生的庫列表 - 我把它們都在項目的根:

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

使用g ++,你需要把你的庫(-lwhatever)源後或目標文件(即'g ++ -I/e/code/boost_1_52_0 -o runner runner.cpp test1.cpp -lboost_unit_test_framework')。鏈接[here](http://www.network-theory.co.uk/docs/gccintro/gccintro_18.html)。有可能你還需要爲你的'-I/e/code/boost_1_52_0'增加一個'-L/path/to/libraries'。 – 2012-12-07 18:18:05

+1

[This answer](http:// stackoverflow。com/a/2907582/1252091)似乎與你所做的非常相似。 – 2012-12-07 18:33:06

+0

@llonesmiz確實,把對象工作後的lib。 '-L.'也是需要的,並且lib需要作爲'-lboost_unit_test_framework-mgw47-mt-1_52'傳遞。將它作爲'-lboost_unit_test_framework'傳遞會導致鏈接錯誤。但是,當我懷疑它可能找不到lib時,我給了'-lfoo'之類的東西,它抱怨沒有這樣的lib存在。在查閱了[這個頁面](http://www.mingw.org/wiki/HOWTO_Specify_the_Location_of_External_Libraries_for_use_with_MinGW)關於默認的MinGW lib路徑之後,我發現在這些文件夾中有一個'libboost_unit_test_framework.a'。 –

回答

18

的幫助從@llonesmiz,確定了一些問題。

1.圖書館需要指定對象和使用它們的來源。

如上所述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.資源庫路徑應該被明確指定。

如果未指定lib路徑,則鏈接程序可能會查找默認文件夾的一系列 中的庫,從而加載預期的不同庫。這是我的情況發生了什麼 - 我想鏈接boost_unit_test_framework,但沒有 指定一個路徑,因爲我認爲鏈接器會查看當前文件夾。 這就是運行時發生的情況,畢竟如果dllexe位於相同的文件夾 中,它會找到它。

我發現它有點奇怪,鏈接器會找到lib,因爲它是 ,名稱爲ibboost_unit_test_framework-mgw47-mt-1_52.dll。當我試圖鏈接到 一個不存在的lib時,鏈接器抱怨,所以我認爲這不是 問題,並且MinGW的鏈接器忽略這些後綴。

經過一番研究,我找到了this article about MinGW library paths。 MinGW搜索庫的文件夾可以在gcc -print-search-dirs的輸出中找到。 文章還包含了一些bash魔法使該輸出的意義:

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

這將打印這些文件夾的一個很好的列表。 gcc不是,默認情況下, 查看當前目錄中的庫。我查看了其中的每一個,並發現正在加載的 庫 - libboost_unit_test_framework.a,一個靜態庫。

這讓成亮值得一提的另一個問題:

3.靜態與動態鏈接

我沒有指定我是否要boost_unit_test_framework靜態或動態鏈接。 在這種情況下,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是在Unix動態庫的擴展 - 在Windows上,相當於是dll

那麼,什麼情況是,gcc在尋找libboost_unit_test_framework.dll 所有它的默認文件夾,但無法找到它。然後它尋找 libboost_unit_test_framework.a,並靜態鏈接。這導致 鏈接錯誤,因爲源具有#define BOOST_TEST_DYN_LINK和 因此預計將動態鏈接庫。

爲了實施靜態或動態鏈接,鏈接器選項-Wl,-Bstatic-Wl,-Bdynamic 發揮作用,如here所述。

如果我知道我想要的動態鏈接鏈接:

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

這將失敗,因爲鏈接將無法找到dll

4.Summary

的問題是:其中其中用它們

  • 的lib路徑未指定
  • 聯WASN的類型來源前指定

    1. 庫沒有指定
    2. 庫的名稱不正確

    最後,工作命令:

    $ 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

    優秀的答案。主要的多重定義問題是否也解決了這個問題?我打算在不久的將來使用類似的東西,我相信這會有很大的幫助。 – 2012-12-08 13:41:58

    +0

    @llonesmiz,是的。我仍然不確定它爲什麼發生;無法用新的庫文件重現。 –

    +0

    你的目錄顯示每個庫的兩個版本。一個在名稱中間有一個「-d-」,另一個沒有。例如,'libboost_unit_test_framework-mgw47-mt-1_52.a'和'libboost_unit_test_framework-mgw47-mt-d-1_52.a'。你是怎麼知道使用哪些的? – Brick