我的朋友在Windows上用Visual Studio开发了一个C ++游戏,我想在我的Linux x64机器上编译它。我对C ++不是很熟悉,但我在命令行上尝试g ++。但是我只得到一堆未定义的引用错误。
基本文件结构是:
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
(我希望你能看一下上面的瑞典语。)
答案 0 :(得分:2)
为您提供链接器的库路径非常有礼貌。但是,链接器是忘恩负义的单词,并且当它们看到对函数的未定义引用时,通常不会在自己的中查找任何库文件。
赞,undefined reference to `sf::Mutex::lock()
- 我打赌libsfml-system.so.2.0
目录中有Libraries/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 ++程序的构建看起来像这样:
x.cpp
文件,请致电g++ -c x.cpp <bunch of flags> -I<include directories>
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的工具。