如何使用CMake使用install-export和find_package查找并链接到库?

tam*_*nez 15 cmake

您有一个启用CMake的库项目.您需要在另一个库或可执行文件中使用它.如何使用CMake查找并链接到库?您可能具有以下首选项:

  • 写尽可能少量的样板代码
  • 将链接库的内部详细信息与使用目标分离

理想情况下,库的用法应如下所示:

add_executable(myexe ...)
target_link_libraries(myexe mylib::mylib)
Run Code Online (Sandbox Code Playgroud)

tam*_*nez 40

让我演示一个具体例子的可能解决方案:

myapp项目

我们有一个可执行目标myapp.我们将它链接起来mylib,它是在自己的构建树中构建的.在CMakeLists.txtmyapp,我们发现,并指定mylib为依赖myexe:

find_package(mylib REQUIRED)
...
add_executable(myexe ...)
target_link_libraries(myexe mylib::mylib)
Run Code Online (Sandbox Code Playgroud)

让我们看看如何设置mylib和构建myexe以使其工作.

mylib项目

目录布局mylib:

mylib
- CMakeLists.txt
- mylib.c
+ include
  - mylib.h # single public header
Run Code Online (Sandbox Code Playgroud)

CMakeLists.txtmylib,我们需要创建目标,并指定它的源文件:

add_library(mylib mylib.c include/mylib.h)
Run Code Online (Sandbox Code Playgroud)

公共头mylib.h将作为#include "mylib.h"双方通过mylib和客户端mylib:

  • mylib本身和mylibCMake项目中构建的其他目标(例如测试)需要include/mylib.hmylib源代码树中找到
  • mylib在自己的项目中建立的客户(如myexe)需要include/mylib.h在其安装位置找到

CMake允许我们指定两个包含路径mylib:

target_include_directories(mylib PUBLIC
    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
    $<INSTALL_INTERFACE:include>)
Run Code Online (Sandbox Code Playgroud)

我们在PUBLIC这里使用选项,因为在公共接口上需要此标头mylib.使用PRIVATE了包括内部的路径mylib.

INSTALL_INTERFACE指定了相对于安装根目录的路径,即,CMAKE_INSTALL_PREFIX.要实际安装公共标头:

    set_target_properties(mylib PROPERTIES PUBLIC_HEADER  include/mylib.h")
Run Code Online (Sandbox Code Playgroud)

我们还需要安装库本身以及所谓的配置模块和相关文件.配置模块是消耗项目将使用的文件,比如myapp查找mylib并获取与其链接所需的所有参数.它类似于pkg-config.pc文件.

我们需要两个相关的install命令.第一个:

install(TARGETS mylib
    EXPORT mylib-targets
    PUBLIC_HEADER DESTINATION include
    ARCHIVE DESTINATION lib
    LIBRARY DESTINATION lib
    RUNTIME DESTINATION bin)
Run Code Online (Sandbox Code Playgroud)

涵盖所有标准安装静态库,位置所需要的目的地列表dll的和so的.如果您确定您的库将仅作为静态库构建,则可以使用单个库DESTINATION lib.

有趣的部分是EXPORT选项.它将目标列表(当前,它是唯一的mylib)分配给标识符mylib-targets.此标识符将在下一个命令中用于生成和安装一些特殊文件,这些文件find_package(mylib)在消费项目中起作用:

install(EXPORT mylib-targets
    NAMESPACE mylib::
    FILE mylib-config.cmake
    DESTINATION lib/cmake/mylib)
Run Code Online (Sandbox Code Playgroud)

此命令生成多个文件:

  • 每个构建配置(Debug,Release等)的一个文件,用于描述库文件和与配置相关的参数
  • 描述配置不可知参数的文件,还包括所有与配置相关的文件.由于此文件也可以单独用作配置模块,我们只需将其重命名为mylib-config.cmake

这些文件将被安装到${CMAKE_INSTALL_PREFIX}/lib/cmake/mylibfind_package(mylib)命令将搜索的许多标准位置之一mylib-config.cmake.

建造 mylib

我们需要在变量中指定一个安装位置CMAKE_INSTALL_PREFIX:

mkdir build
cd build
cmake -DCMAKE_INSTALL_PREFIX=$PWD/../out ../mylib
Run Code Online (Sandbox Code Playgroud)

并构建和安装库:

cmake --build . --target install
Run Code Online (Sandbox Code Playgroud)

建造 myexe

myexe需要知道在哪里寻找mylib.变量CMAKE_PREFIX_PATH可以是路径列表.我们需要指定以前的安装位置:

mkdir build
cd build
cmake -DCMAKE_PREFIX_PATH=$PWD/../out ../myexe
cmake --build .
Run Code Online (Sandbox Code Playgroud)

关于构建多个配置的说明

通常我们需要构建多个配置(Debug,Release).关键问题是指定依赖于配置的文件名或安装位置.例如,您可以DEBUG_POSTFIX为库项目设置属性的默认值:

set(CMAKE_DEBUG_POSTFIX d)
Run Code Online (Sandbox Code Playgroud)

mylib将命名库文件的调试版本libmylibd.lib(或mylibd.lib在Windows上).生成的EXPORT文件将包含已修改的文件名.

如果您正在使用makefile样式的CMake生成器,则可以通过设置CMAKE_BUILD_TYPE变量来控制构建配置:

cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=$PWD/../out ../mylib
cmake --build . --target install
Run Code Online (Sandbox Code Playgroud)

您可能需要为每个配置分别构建目录,或者您可以重用相同的构建目录.在这种情况下,为了安全起见,最好在构建之前明确清理:

cmake --build . --target install --clean-first
Run Code Online (Sandbox Code Playgroud)

如果您使用的是multiconfig IDE生成器,Xcode或者Visual Studio,您需要在构建时指定配置:

cmake -DCMAKE_INSTALL_PREFIX=$PWD/../out ../mylib
cmake --build . --target install --config Release
Run Code Online (Sandbox Code Playgroud)

参考

您可以克隆和构建包含和项目的存储库(在Windows和Linux上测试).mylibmyexe

查看CMake文档.最重要的相关命令是:

和两篇详细的文章: