如何使用cmake正确链接库?

111

我无法正确地将我正在使用的附加库链接到我的项目中。

我正在使用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中不断地调试直到没有错误了,但是头文件在我的代码中仍然没有被识别。

这是我的项目结构:
project structure

我把所有需要的库都放进去了,但是好像在代码中没有被识别。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个回答

207

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

让我试着解释一下CMake中的链接是如何工作的。想法是在CMake中构建模块,然后将它们链接在一起。现在先忽略头文件,因为它们可以全部包含在源文件中。

假设您有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 文件中看到了很多冗余。例如,你为什么要在 include 目录中有一个可执行模块 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变量中,以便您可以将程序链接到它们。例如,这里是如何为boost这样做


1
我该如何为我尝试使用的外部库(SDL2、glew、glm)创建模块?似乎无法使用add_library()与它们一起使用。另外,假设我有一个存储.lib文件的lib/文件夹。如果我使用target_link_libraries(texture_module -L${PROJECT_SOURCE_DIR}/lib),是否会自动将所有的*.lib文件附加到该目标? - Cache Staheli
2
@CacheStaheli 如何链接到这些特定的库,我不是很清楚。但是一旦您找到了正确的方法(与cmake无关),尝试将每个库放在一行中,之后在其工作后尝试将它们全部放在单个target_link_libraries中进行实验。而且,我非常怀疑是否可以通过添加目录来自动添加所有内容。您必须手动链接每个库。-L仅告诉链接器查找您指定的库的位置。 - The Quantum Physicist
谢谢您的回答,我尝试了一整天将SSL与boost::beast链接起来,但第一次尝试就完美解决了。 - Johannes Brunner

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接