使用库编译C++项目

问题描述:

我的朋友在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 –

这是非常有礼貌你提供链接器的库路径。然而,连接器是不知好歹的,通常当他们看到一个未定义的函数引用时,不会自己寻找任何库文件

赞,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