如何正确地将库与 cmake 链接?

Posted

技术标签:

【中文标题】如何正确地将库与 cmake 链接?【英文标题】:How to properly link libraries with cmake? 【发布时间】:2016-09-20 15:37:30 【问题描述】:

我无法将正在使用的其他库正确链接到我的项目中。

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

我还是 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)

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

这是我的项目的结构:

所以,我放置了所有我需要的库,但它似乎没有在代码中识别它们。 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'

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

我的CMakeLists.txt 做错了什么?

【问题讨论】:

【参考方案1】:

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

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

假设你有 file1.cpp、file2.cpp、main.cpp。您将它们添加到您的项目中:

ADD_LIBRARY(LibsModule 
    file1.cpp
    file2.cpp
)

现在您将它们添加到名为 LibsModule 的模块中。记住这一点。 假设您想链接到pthread,例如系统中已经存在的链接。您可以使用以下命令将其与LibsModule 结合使用:

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)

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

target_link_libraries(MyProgramExecBlaBla LibsModule)

这样就可以了。

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


总而言之,它看起来像这样:

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)

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


注意:请记住,这是使用 CMake 的简单方法。更好的跨平台方法是使用find_package,它定位一个包/库,并提供库并包含在 CMake 变量中,以便您可以将程序链接到它们。以Here's how to do this for boost 为例。

【讨论】:

如何为我尝试使用的外部库(SDL2、glew、glm)创建模块?看来我不能和他们一起使用add_library()。另外,假设我有一个文件夹lib/,其中存储了.lib 文件。如果我使用target_link_libraries(texture_module -L$PROJECT_SOURCE_DIR/lib),是否会自动将所有*.lib 文件附加到该目标? @CacheStaheli 如何链接到这些特定的库,我不太清楚。但是一旦你有了正确的方法(这与 cmake 无关),尝试将它们中的每一个放在一行中,然后在它工作后尝试将它们全部放在一个 target_link_libraries 中。以及是否所有内容都是通过添加目录自动添加的,我对此表示高度怀疑。您必须手动链接每个库。 -L 链接仅告诉链接器在哪里查找您指定的库。

以上是关于如何正确地将库与 cmake 链接?的主要内容,如果未能解决你的问题,请参考以下文章

NDK 与 cmake 的链接库

CMake 将库链接到一个库中

将库链接到另一个应用程序时,cmake 找不到库

将库链接到 cmake 项目中的所有目标

如何使用cmake生成基于静态库的动态链接库

cmake 将外部库与 IMPORT_SONAME ro IMPORT_LOCATION 链接