【问题标题】:How to link a library that was created from add_subdirectory in CMake?如何链接从 cmake 中的 add_subdirectory 创建的静态库?
【发布时间】:2019-10-06 04:33:58
【问题描述】:

我正在尝试使用依赖于第三方库的 cmake 构建程序。这个第三方库包含一个 CMakeLists.txt 文件,所以我想要做的是将第三方库的源代码保留在我的项目目录中,并使用 add_subdirectory(path/to/lib) 构建它,然后将我的目标链接到第三方库生成的静态库。

我的 CMakeLists.txt:

cmake_minimum_version(VERSION 3.10)
project(my_project)

add_subdirectory("${CMAKE_SOURCE_DIR}/extern/somelib")

# my-code:
# somelib CMakeLists.txt file has a project name: SOMELIB
# which lets me access the directory where the files are built
# on windows it builds to /Release, on mac and linux it just builds
# to the binary dir
set(SOMELIB_LIBS "${SOMELIB_BINARY_DIR}/Release")
add_executable(my_program my_main.cpp)
target_link_libraries(my_program "${SOMELIB_LIBS}/SOMELIB.lib" "${SOMELIB_LIBS}/SOMELIBmain.lib")

然后我创建一个构建目录并从该目录开始:

cmake -G "Visual Studio 15 2017" ..
cmake --build .

构建命令失败并显示“LINK : fatal error LNK1181: cannot open input file 'extern/somelib/Release/SOMELIBmain.lib' ...”

我现在的解决方法是注释掉“#my-code”部分,首先构建生成静态库的 somelib 依赖项,然后取消注释掉 my-code 并再次构建,然后才能正常工作。

如何告诉 CMake 先构建子目录,然后链接到它生成的静态库?

【问题讨论】:

    标签: c++ cmake linker dependencies


    【解决方案1】:

    简答:告诉 CMake 它的目标之间存在依赖关系。

    target_link_libraries(my_program PRIVATE SOMELIB SOMELIBmain)
    

    CMake 将为您评估 SOMELIB 位置并将 my_programSOMELIBSOMELIBmain 链接[1]。适用于 Debug 和 Release 配置,也适用于 Linux。

    您不必担心 CMake 将构建文件放置在何处[2],这就是所谓的“现代 CMake”试图实现的目标。我将在这里仅留下简要说明,但请查看答案底部的链接[3]

    无论如何,关键概念是每当您创建库/可执行文件(目标)时,您都会列出其使用+构建要求以及对其他目标的依赖关系。您使用target_link_libraries(<your_lib> KEYWORD <dependencies>) 声明依赖关系。这样的行不仅会使<you_lib>链接到列出的依赖项,它还将继承它们的使用要求(通常是公共包含目录)并命令CMake在<your_lib>之前构建依赖库。

    它的美妙之处在于,即使 SOMELIB 不遵循现代 CMake 理念(未声明构建/使用要求),您仍然应该能够仅使用这一行代码。

    [1] 我假设 CMake 目标的名称与输出库名称相同,但这不是强制性的。对于 OP 的情况,原来静态库目标以-static 为后缀,所以他不得不写SOMELIB-static SOMELIBmain-static

    [2] 不幸的是,在 Windows 上使用共享库 (DLL) 并不那么容易

    [3] 我将从这篇博文开始:https://pabloariasal.github.io/2018/02/19/its-time-to-do-cmake-right/

    【讨论】:

    • 我尝试用target_link_libraries(my_program PRIVATE SOMELIB SOMELIBmain) 替换target_link_libraries(my_program "${SOMELIB_LIBS}/SOMELIB.lib" "${SOMELIB_LIBS}/SOMELIBmain.lib"),但它仍然给我一个错误,说它找不到'SOMELIB.lib'。我是否需要设置 SOMELIB 的属性来告诉 cmake 它是在哪里构建的?
    • 更新:我查看了我需要构建的库的 CMakeLists.txt 文件,它在构建静态库文件时将“-static”附加到目标名称,这样做:`target_link_libraries(my_program SOMELIB-静态 SOMELIBmain) 有效。谢谢
    • @ns_helloworld 太好了 :) 我会用这句话更新我的答案,供未来的读者参考
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-03
    • 1970-01-01
    • 1970-01-01
    • 2023-03-05
    • 2013-10-28
    相关资源
    最近更新 更多