C++ 如何正确链接库与 cmake?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/39598323/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 14:50:39  来源:igfitidea点击:

How to properly link libraries with cmake?

c++openglcmakeundefined-reference

提问by Cache Staheli

I can't get the additional libraries I am working with to link into my project properly.

我无法获得正在使用的其他库以正确链接到我的项目。

I am using CLion, which uses cmake to build it's projects. I am trying to use several libraries in conjunction with OpenGL to texture some objects. I initially built it in Visual Studio, because I couldn't ever figure out how to get cmake to work with Clion. However, now that the code is all working (in Visual Studio, anyways), I want to be able to use CLion for it, because that is my preferred IDE.

我正在使用 CLion,它使用 cmake 来构建它的项目。我正在尝试将几个库与 OpenGL 结合使用来对某些对象进行纹理处理。我最初在 Visual Studio 中构建它,因为我无法弄清楚如何让 cmake 与 Clion 一起工作。但是,既然代码都可以运行(无论如何在 Visual Studio 中),我希望能够使用 CLion,因为这是我首选的 IDE。

I am still new to cmake, and I don't understand what I am doing wrong with my CMakeLists.txt. Here is what I have:

我还是 cmake 的新手,我不明白我的CMakeLists.txt. 这是我所拥有的:

cmake_minimum_required(VERSION 3.3)
project(texture_mapping)
find_package(OpenGL REQUIRED)
link_directories(${OPENGL_gl_LIBRARY})

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")

set(SOURCE_FILES main.cpp camera.h display.h display.cpp mesh.cpp mesh.h obj_loader.cpp obj_loader.h shader.cpp shader.h stb_image.c stb_image.h texture.cpp texture.h transform.h)

link_directories(texture_mapping ${PROJECT_SOURCE_DIR}/lib)

add_executable(texture_mapping ${SOURCE_FILES})

target_include_directories(texture_mapping PUBLIC ${PROJECT_SOURCE_DIR}/include)
target_link_libraries(texture_mapping SDL2 SDL2main SDL2test glew32 glew32s ${OPENGL_gl_LIBRARY})

I tweaked it until it didn't give me any more errors in CLion, but the header files are still not recognized in my code.

我调整了它,直到它在 CLion 中不再给我任何错误,但我的代码中仍然无法识别头文件。

Here is the structure of my project:
project structure

这是我的项目的结构:
项目结构

So, I put all of the libraries I needed, but it doesn't appear to be recognizing them in the code. Clion recognizes them in the project (they aren't appearing red with errors), but when it is built (when I attempt to run it in CLion), I get these errors:

所以,我把所有我需要的库都放进去了,但它似乎没有在代码中识别它们。Clion 在项目中识别它们(它们不会因错误而显示为红色),但是在构建时(当我尝试在 CLion 中运行它时),我收到以下错误:

CMakeFiles\texture_mapping.dir/objects.a(mesh.cpp.obj): In function `ZN4MeshD2Ev':
...texture-mapping/mesh.cpp:30: undefined reference to `_imp____glewDeleteVertexArrays'
CMakeFiles\texture_mapping.dir/objects.a(mesh.cpp.obj): In function `ZN4Mesh8InitMeshERK12IndexedModel':
...texture-mapping/mesh.cpp:36: undefined reference to `_imp____glewGenVertexArrays'
...texture-mapping/mesh.cpp:37: undefined reference to `_imp____glewBindVertexArray'
...texture-mapping/mesh.cpp:39: undefined reference to `_imp____glewGenBuffers'
...texture-mapping/mesh.cpp:40: undefined reference to `_imp____glewBindBuffer'
...texture-mapping/mesh.cpp:41: undefined reference to `_imp____glewBufferData'
...texture-mapping/mesh.cpp:43: undefined reference to `_imp____glewEnableVertexAttribArray'
...texture-mapping/mesh.cpp:44: undefined reference to `_imp____glewVertexAttribPointer'
...texture-mapping/mesh.cpp:46: undefined reference to `_imp____glewBindBuffer'
...texture-mapping/mesh.cpp:47: undefined reference to `_imp____glewBufferData'
...texture-mapping/mesh.cpp:49: undefined reference to `_imp____glewEnableVertexAttribArray'
...texture-mapping/mesh.cpp:50: undefined reference to `_imp____glewVertexAttribPointer'
...texture-mapping/mesh.cpp:52: undefined reference to `_imp____glewBindBuffer'
...texture-mapping/mesh.cpp:53: undefined reference to `_imp____glewBufferData'
...texture-mapping/mesh.cpp:55: undefined reference to `_imp____glewBindVertexArray'
...texture-mapping/mesh.cpp:56: undefined reference to `_imp____glewBindVertexArray'
CMakeFiles\texture_mapping.dir/objects.a(mesh.cpp.obj): In function `ZN4Mesh4DrawEv':
...texture-mapping/mesh.cpp:61: undefined reference to `_imp____glewBindVertexArray'
...texture-mapping/mesh.cpp:65: undefined reference to `_imp____glewBindVertexArray'
CMakeFiles\texture_mapping.dir/objects.a(shader.cpp.obj): In function `ZN6ShaderC2ERKSs':
...texture-mapping/shader.cpp:5: undefined reference to `_imp____glewCreateProgram'
...texture-mapping/shader.cpp:11: undefined reference to `_imp____glewAttachShader'
...texture-mapping/shader.cpp:14: undefined reference to `_imp____glewBindAttribLocation'
...texture-mapping/shader.cpp:15: undefined reference to `_imp____glewBindAttribLocation'
...texture-mapping/shader.cpp:17: undefined reference to `_imp____glewLinkProgram'
...texture-mapping/shader.cpp:20: undefined reference to `_imp____glewValidateProgram'
...texture-mapping/shader.cpp:23: undefined reference to `_imp____glewGetUniformLocation'
CMakeFiles\texture_mapping.dir/objects.a(shader.cpp.obj): In function `ZN6Shader4BindEv':
...texture-mapping/shader.cpp:28: undefined reference to `_imp____glewUseProgram'
CMakeFiles\texture_mapping.dir/objects.a(shader.cpp.obj): In function `ZN6Shader6UpdateERK9TransformRK6Camera':
...texture-mapping/shader.cpp:35: undefined reference to `_imp____glewUniformMatrix4fv'
CMakeFiles\texture_mapping.dir/objects.a(shader.cpp.obj): In function `ZN6ShaderD2Ev':
...texture-mapping/shader.cpp:42: undefined reference to `_imp____glewDetachShader'
...texture-mapping/shader.cpp:43: undefined reference to `_imp____glewDeleteShader'
...texture-mapping/shader.cpp:46: undefined reference to `_imp____glewDeleteProgram'
CMakeFiles\texture_mapping.dir/objects.a(shader.cpp.obj): In function `ZN6Shader16CheckShaderErrorEjjbRKSs':
...texture-mapping/shader.cpp:79: undefined reference to `_imp____glewGetProgramiv'
...texture-mapping/shader.cpp:81: undefined reference to `_imp____glewGetShaderiv'
...texture-mapping/shader.cpp:86: undefined reference to `_imp____glewGetProgramInfoLog'
...texture-mapping/shader.cpp:88: undefined reference to `_imp____glewGetShaderInfoLog'
CMakeFiles\texture_mapping.dir/objects.a(shader.cpp.obj): In function `ZN6Shader12CreateShaderERKSsj':
...texture-mapping/shader.cpp:96: undefined reference to `_imp____glewCreateShader'
...texture-mapping/shader.cpp:109: undefined reference to `_imp____glewShaderSource'
...texture-mapping/shader.cpp:110: undefined reference to `_imp____glewCompileShader'
CMakeFiles\texture_mapping.dir/objects.a(texture.cpp.obj): In function `ZN7Texture4BindEj':
...texture-mapping/texture.cpp:36: undefined reference to `_imp____glewActiveTexture'
...texture-mapping/lib/SDL2main.lib(./Win32/Release/SDL_windows_main.obj):(.text+0x24): undefined reference to `SDL_SetMainReady'
...texture-mapping/lib/SDL2main.lib(./Win32/Release/SDL_windows_main.obj):(.text+0x55): undefined reference to `SDL_malloc'
...texture-mapping/lib/SDL2main.lib(./Win32/Release/SDL_windows_main.obj):(.text+0x84): undefined reference to `SDL_wcslen'
...texture-mapping/lib/SDL2main.lib(./Win32/Release/SDL_windows_main.obj):(.text+0xa5): undefined reference to `SDL_iconv_string'
...texture-mapping/lib/SDL2main.lib(./Win32/Release/SDL_windows_main.obj):(.text+0xcf): undefined reference to `SDL_free'
...texture-mapping/lib/SDL2main.lib(./Win32/Release/SDL_windows_main.obj):(.text+0xf4): undefined reference to `SDL_wcslen'
...texture-mapping/lib/SDL2main.lib(./Win32/Release/SDL_windows_main.obj):(.text+0x10f): undefined reference to `SDL_iconv_string'
...texture-mapping/lib/SDL2main.lib(./Win32/Release/SDL_windows_main.obj):(.text+0x143): undefined reference to `SDL_malloc'
...texture-mapping/lib/SDL2main.lib(./Win32/Release/SDL_windows_main.obj):(.text+0x17f): undefined reference to `SDL_free'
...texture-mapping/lib/SDL2main.lib(./Win32/Release/SDL_windows_main.obj):(.text+0x18b): undefined reference to `SDL_free'
...texture-mapping/lib/SDL2main.lib(./Win32/Release/SDL_windows_main.obj):(.text+0x1d6): undefined reference to `SDL_isspace'
...texture-mapping/lib/SDL2main.lib(./Win32/Release/SDL_windows_main.obj):(.text+0x295): undefined reference to `SDL_isspace'
...texture-mapping/lib/SDL2main.lib(./Win32/Release/SDL_windows_main.obj):(.text+0x3a2): undefined reference to `SDL_ShowSimpleMessageBox'

Basically, errors with every usage of SDL and glew, but not glm, which is strange.

基本上,每次使用 SDL 和 glew 都会出错,但不是 glm,这很奇怪。

What am I doing wrong with my CMakeLists.txt?

我做错了什么CMakeLists.txt

回答by The Quantum Physicist

My recommendation is to start simple, and then complicate your project further.

我的建议是从简单的开始,然后使您的项目进一步复杂化。

Let me try to explain how linking works in CMake. The idea is that you build modulesin CMake, and link them together. Let's ignore header files for now, as they can be all included in your source files.

让我试着解释一下 CMake 中的链接是如何工作的。这个想法是你在 CMake 中构建模块,并将它们链接在一起。让我们暂时忽略头文件,因为它们都可以包含在您的源文件中。

Say you have file1.cpp, file2.cpp, main.cpp. You add them to your project with:

假设您有 file1.cpp、file2.cpp、main.cpp。您可以通过以下方式将它们添加到您的项目中:

ADD_LIBRARY(LibsModule 
    file1.cpp
    file2.cpp
)

Now you added them to a module called LibsModule. Keep that in mind. Say you want to link to pthreadfor example that's already in the system. You can combine it with LibsModuleusing the command:

现在您将它们添加到名为LibsModule. 记在脑子里。假设您要链接到pthread例如系统中已有的链接。您可以将其与LibsModule使用以下命令结合使用:

target_link_libraries(LibsModule -lpthread)

And if you want to link a static library to that too, you do this:

如果你也想链接一个静态库,你可以这样做:

target_link_libraries(LibsModule liblapack.a)

And if you want to add a directory where any of these libraries are located, you do this:

如果要添加任何这些库所在的目录,请执行以下操作:

target_link_libraries(LibsModule -L/home/user/libs/somelibpath/)

Now you add an executable, and you link it with your main file:

现在添加一个可执行文件,并将其与主文件链接:

ADD_EXECUTABLE(MyProgramExecBlaBla main.cpp)

(I added BlaBla just to make it clear that the name is custom). And then you link LibsModulewith your executable module MyProgramExecBlaBla

(我添加了 BlaBla 只是为了表明名称是自定义的)。然后你链接LibsModule到你的可执行模块MyProgramExecBlaBla

target_link_libraries(MyProgramExecBlaBla LibsModule)

And this will do it.

这将做到。

What I see in your CMake file is a lot of redundancy. For example, why do you have texture_mapping, which is an executable module in your include directories? So you need to clean this up and follow the simple logic I explained. Hopefully it works.

我在你的 CMake 文件中看到的是很多冗余。例如,为什么texture_mapping你的包含目录中有一个可执行模块?所以你需要清理它并遵循我解释的简单逻辑。希望它有效。



In summary, it looks like this:

总之,它看起来像这样:

project (MyProgramExecBlaBla)  #not sure whether this should be the same name of the executable, but I always see that "convention"
cmake_minimum_required(VERSION 2.8)

ADD_LIBRARY(LibsModule 
    file1.cpp
    file2.cpp
)

target_link_libraries(LibsModule -lpthread)
target_link_libraries(LibsModule liblapack.a)
target_link_libraries(LibsModule -L/home/user/libs/somelibpath/)
ADD_EXECUTABLE(MyProgramExecBlaBla main.cpp)
target_link_libraries(MyProgramExecBlaBla LibsModule)

The most important thing to understand is the module structure, where you create modules and link them all together with your executable. Once this works, you can complicate your project further with more details. Good luck!

要了解的最重要的事情是模块结构,您可以在其中创建模块并将它们与可执行文件链接在一起。一旦成功,您可以使用更多细节进一步复杂化您的项目。祝你好运!



Note: Keep in mind that this is the simple way to use CMake. The better cross-platform way would be using find_package, which locates a package/library, and provides the libraries and includes in CMake variables so that you could link your program to them. Here's how to do this for boost, for example.

注意:请记住,这是使用 CMake 的简单方法。更好的跨平台方式是使用find_package,它定位包/库,并提供库和包含在 CMake 变量中,以便您可以将程序链接到它们。例如,这是为 boost 执行此操作的方法