2013-04-15 108 views
0

我的朋友在Windows上的Visual Studio中開發了一個C++遊戲,我想在我的Linux x64機器上編譯它。我對C++不是很熟悉,但我正在命令行嘗試g ++。不過,我只收到一堆未定義的參考錯誤。使用庫編譯C++項目

基本文件結構是:

Libraries/SFML-2.0/lib 
Libraries/SFML-2.0/include 
Libraries/SFML_Linux64/lib 
Libraries/SFML_Linux64/include 
Libraries/Box2D/lib 
Libraries/Box2D/include 
Libraries/Box2DLinux/lib 
Libraries/Box2DLinux/include 
Game 
Game/lib 
Game/includes 
Game/... (other subdirectories) 

我嘗試下面的命令:

g++ -Wall Multiplaya/app.cpp -I Libraries/SFML_Linux64/include/ -I Libraries/Box2DLinux/include/ -L Libraries/SFML_Linux64/lib/ -L Libraries/Box2DLinux/lib/

這是一種錯誤,我得到的(一些線剪斷,並用...替換):

/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../x86_64-linux-gnu/crt1.o: I funktionen "_start": 
(.text+0x20): undefined reference to `main' 
/tmp/ccFXe37c.o: I funktionen "mp::createNetworkThread(void*)": 
app.cpp:(.text+0x10): undefined reference to `worldDataMutex' 
app.cpp:(.text+0x15): undefined reference to `sf::Mutex::lock()' 
... 
/tmp/ccFXe37c.o: I funktionen "mp::App::exec()": 
app.cpp:(.text+0x148): undefined reference to `mp::ResourceHandler::instance()' 
app.cpp:(.text+0x15a): undefined reference to `mp::ResourceHandler::loadTexture(std::string)' 
app.cpp:(.text+0x3d7): undefined reference to `mp::Window::Window(mp::WorldData*)' 
app.cpp:(.text+0x406): undefined reference to `mp::Controller::Controller(mp::World*, mp::Window*)' 
... 
app.cpp:(.text+0x471): undefined reference to `sf::Mutex::unlock()' 
app.cpp:(.text+0x4bb): undefined reference to `sf::Thread::launch()' 
app.cpp:(.text+0x4d7): undefined reference to `sf::Clock::Clock()' 
app.cpp:(.text+0x4e6): undefined reference to `sf::Clock::getElapsedTime() const' 
... 
collect2: fel: ld returnerade avslutningsstatus 1 

(我希望你能l通過瑞典以上。)

+0

得到英文錯誤信息:LC_ALL = C gcc -o foo.o foo.c –

回答

2

這是非常有禮貌你提供鏈接器的庫路徑。然而,連接器是不知好歹的,通常當他們看到一個未定義的函數引用時,不會自己尋找任何庫文件

贊,undefined reference to `sf::Mutex::lock() - 我打賭有libsfml-system.so.2.0Libraries/SFML_Linux64/lib/目錄中的任何東西,其定義爲sf::Mutex::lock()。但鏈接器不關心。您必須在編譯調用結束時說-lsfml-system

這將使g++明白不僅在libstdc++庫中尋找函數,而且在libsfml-system文件中尋找函數。如果g++碰巧在默認或附加(用-L標誌指定)庫目錄中找到這樣的文件,他將使用它來解析對函數調用的引用。

但是你必須明確地告訴它你想扔什麼庫文件,只指定目錄與庫沒有太大的作用。所以,儘量選用

g++ -Wall Multiplaya/app.cpp -I Libraries/SFML_Linux64/include/ -I Libraries/Box2DLinux/include/ -L Libraries/SFML_Linux64/lib/ -L Libraries/Box2DLinux/lib/ -lsfml-system 

如何建立C++程序

C++程序是建立在兩個步驟:第一步是編譯和第二步的鏈接。

在編譯期間,您將源文件轉換爲目標文件 - 包含已編譯機器代碼的東西。現在有一個你必須明白的技巧。也就是說,如果你有a.cpp

// a.cpp 
int f(int x); 

int main() { 
    return f(42); 
} 

你可以用g++ -c a.cpp編譯它,它會得到你的目標文件a.o(編譯代碼),沒有任何編譯錯誤。可是等等!有沒有什麼f()a.cpp的實際定義!

現在,當您進入第二步,鏈接並調用g++ -o test a.o時,它會抱怨有未定義的參考f()。因此,讓b.cpp有這樣的文字:

// b.cpp 
int f(int x) { 
    return 2 * x - 3; 
} 

g++ -c b.cpp編譯,然後進行連接爲g++ -o test a.o b.o - 哇,現在它連接沒有一個錯誤!

發生了什麼事?那麼,當編譯器看到一個函數調用時,它將目標文件放入一個不是真實的指令call,而是一個佔位符,它表示「調用具有諸如此類名稱和諸如此類參數的函數」。然後鏈接程序會獲取一堆目標文件,並將它們縫合在一起。當它看到這樣一個placholder時,它會在給定的對象文件中查找所提到的函數,並將其實際調用而不是佔位符。

所以,C++程序的建設看起來是這樣的:

  1. 對於每個x.cpp文件你有,請撥打g++ -c x.cpp <bunch of flags> -I<include directories>
  2. 然後調用g++ -o resultprogram a.o b.o c.o d.o ... <bunch of flags> -L<library directories> -l<additional libraries>

-l標誌告訴連接,如果他看到一個函數調用,並且在指定的目標文件(ao,bo等)中沒有任何地方定義了這樣的函數,那麼它應該在這個庫中查找。請注意,鏈接器不會查看除您指定的目標文件和/或庫以外的任何目標文件和/或庫(好吧,它也會查找標準C++庫libstdc++,但就是這樣)。

但是,如果你有10個或更多的文件,這個過程是非常無聊的。這就是人們使用「項目文件」和「構建系統」的原因。當Visual Studio構建一個項目時,它會執行我提到的所有步驟:它編譯項目中的每個文件,然後將結果鏈接在一起。在Linux上,您沒有Visual Studio,但是您有make實用程序。我相信有一些工具可以將VS項目轉換爲makefile。

+0

謝謝!這解決了SFML相關的錯誤。正如你所看到的那樣,mp命名空間(Multiplaya,主項目)仍然存在一堆錯誤。如何解決這些問題?代碼可在https://github.com/joniz7/Multiplaya上找到。 – Arild

+0

檢查編輯。 –

+0

我應該創建一個'makefile'嗎?每個Multiplaya'cpp'和'h'文件都應該放在那裏? – Arild