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

2024-01-11

您有一个支持 CMake 的库项目。您需要在另一个库或可执行文件中使用它。如何使用CMake查找并链接到库?您可能有以下偏好:

  • 编写尽可能少的样板代码
  • 将链接库的内部细节与消费目标解耦

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

add_executable(myexe ...)
target_link_libraries(myexe mylib::mylib)

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

The myapp project

我们有一个可执行的目标myapp。我们将它与mylib,它是在自己的构建树中构建的。在里面CMakeLists.txt of myapp我们找到并指定mylib作为一个依赖项myexe:

find_package(mylib REQUIRED)
...
add_executable(myexe ...)
target_link_libraries(myexe mylib::mylib)

我们来看看如何设置mylib和构建myexe使这项工作成功。

The mylib project

的目录布局mylib:

mylib
- CMakeLists.txt
- mylib.c
+ include
  - mylib.h # single public header

In the CMakeLists.txt of mylib我们需要创建目标并指定其源文件:

add_library(mylib mylib.c include/mylib.h)

公共标头mylib.h将被包含为#include "mylib.h"两者均由mylib和客户mylib:

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

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

target_include_directories(mylib PUBLIC
    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
    $<INSTALL_INTERFACE:include>)

我们正在使用PUBLIC此处的选项,因为在公共接口上需要此标头mylib. Use PRIVATE对于包含内部路径mylib.

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

    set_target_properties(mylib PROPERTIES PUBLIC_HEADER  include/mylib.h")

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

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

install(TARGETS mylib
    EXPORT mylib-targets
    PUBLIC_HEADER DESTINATION include
    ARCHIVE DESTINATION lib
    LIBRARY DESTINATION lib
    RUNTIME DESTINATION bin)

覆盖静态库的所有标准安装位置所需的目标列表,dll's and so的。如果您确定您的库将专门构建为静态库,则单个DESTINATION lib会成功的。

有趣的部分是EXPORT选项。它分配目标列表(目前,它只是mylib) 到标识符mylib-targets。该标识符将在下一个命令中用于生成和安装一些特殊文件,这些文件使find_package(mylib)在消耗项目中工作:

install(EXPORT mylib-targets
    NAMESPACE mylib::
    FILE mylib-config.cmake
    DESTINATION lib/cmake/mylib)

该命令生成多个文件:

  • 每个构建配置(调试、发布等)都有一个文件,它描述了库文件和与配置相关的参数
  • 一个描述与配置无关的参数的文件,还包括所有与配置相关的文件。由于该文件也可以单独用作配置模块,因此我们只需将其重命名为mylib-config.cmake

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

建筑mylib

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

mkdir build
cd build
cmake -DCMAKE_INSTALL_PREFIX=$PWD/../out ../mylib

并构建并安装库:

cmake --build . --target install

建筑myexe

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

mkdir build
cd build
cmake -DCMAKE_PREFIX_PATH=$PWD/../out ../myexe
cmake --build .

关于构建多个配置的注意事项

通常我们需要构建多个配置(Debug, Release)。一个关键问题是指定与配置相关的文件名或安装位置。例如,您可以设置默认值DEBUG_POSTFIX图书馆项目的属性:

set(CMAKE_DEBUG_POSTFIX d)

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

如果您使用 makefile 风格的 CMake 生成器,您可以通过设置来控制构建配置CMAKE_BUILD_TYPE多变的:

cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=$PWD/../out ../mylib
cmake --build . --target install

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

cmake --build . --target install --clean-first

如果您使用的是多重配置 IDE 生成器,例如Xcode or Visual Studio,您需要在构建时指定配置:

cmake -DCMAKE_INSTALL_PREFIX=$PWD/../out ../mylib
cmake --build . --target install --config Release

参考

您可以克隆和构建这个存储库 https://github.com/tamaskenez/stackoverflow-cmake-find-link-example其中包含mylib and myexe项目(在 Windows 和 Linux 上测试)。

查看CMake 文档 http://www.cmake.org/cmake/help/v3.3。最重要的相关命令是:

  • 添加库 http://www.cmake.org/cmake/help/v3.3/command/add_library.html
  • 目标链接库 http://www.cmake.org/cmake/help/v3.3/command/target_link_libraries.html
  • 查找包 http://www.cmake.org/cmake/help/v3.3/command/find_package.html
  • install http://www.cmake.org/cmake/help/v3.3/command/install.html
  • 目标包含目录 http://www.cmake.org/cmake/help/v3.3/command/target_include_directories.html
  • 目标编译定义 http://www.cmake.org/cmake/help/v3.3/command/target_compile_definitions.html

以及两篇详细的文章:

  • 构建系统 http://www.cmake.org/cmake/help/v3.3/manual/cmake-buildsystem.7.html
  • Packages http://www.cmake.org/cmake/help/v3.3/manual/cmake-packages.7.html
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何使用 CMake 使用 install-export 和 find_package 查找并链接到库? 的相关文章

随机推荐

  • 防止同时触摸多个按钮

    在iOS中 是否有办法防止包含多个按钮 兄弟 的UIView同时被触摸 例如 可以通过两次触摸同时点击两个并排的不重叠按钮 设置 UIView exclusiveTouch
  • 如何为 Maven/Surefire 和 Eclipse 加载不同的 logback 配置

    我想在 Eclipse 和 Maven surefire 插件 中为我的单元测试使用不同的默认 logback 配置 基本上 我希望将测试期间生成的任何日志发送到 Eclipse 中的控制台或 Maven 的文件 目前 我有一个包含两个附加
  • Java Applet 中的背景图像

    如何在 Java Applet 中设置背景图像 假设我希望 background gif 成为我的 java applet 类中的背景 但我该怎么做呢 我认为没有一个函数可以做到这一点 但是您可以扩展一个Panel 它可以充当一个简单的组件
  • backbone.js 的跨浏览器如何?

    我们正在使用多种浏览器类型 网络 移动设备 平板电脑和智能电视 我们正在为我们的 mvc 寻找backbone js backbone js 是否有任何已知的跨浏览器限制 我认为这与 Backbone 关系不大 而与您使用的 HTML 和
  • 什么是陈旧状态?

    我在维基百科上阅读有关对象池模式的内容 http en wikipedia org wiki Object pool http en wikipedia org wiki Object pool 并且它提到 危险的陈旧状态 陈旧 状态到底是
  • Python 2 和 Python 3 中 exec 函数的行为

    以下代码给出了不同的输出Python2 and in Python3 from sys import version print version def execute a st b 42 exec b nprint b b format
  • 使用 npm 如何将包下载为 zip 格式,并将其所有依赖项包含在包中

    我想做的是下载包含所有依赖项的软件包 以便将它们传输到另一台没有互联网连接的计算机上并安装在那里 所以情况是 下载包 到 zip tarball 任何文件 而不安装它 下载的文件中包含其所有依赖项 正确的版本及其依赖项的依赖项 将文件传输到
  • Git:无法从一台计算机推送

    我的一位同事在他的机器上从 git 推送更改时遇到了问题 如果他登录到另一台机器 他可以很好地推送 但是从他的机器上 当他尝试推送时 他会收到以下错误 D Projects test1 best practices gt git push
  • 当有许多(数千个)SVG 元素时,为什么 D3.js 平移比缩放慢?

    当 svg 包含许多元素时 D3 js 平移似乎比缩放更慢且更不稳定 我在 JSFiddle 上做了一个例子http jsfiddle net cornhundred cfeu1ws2 10 http jsfiddle net cornhu
  • 如何将原始套接字绑定到特定端口?

    我目前正在从事一项编程任务 作业是实现客户端 网络模拟器和服务器 客户端将数据包传递给网络模拟器 网络模拟器将数据包传递给服务器 反之亦然 分配的前提是我只能使用原始套接字 所以我将创建自己的 IP 和 UDP 标头 我已经用wiresha
  • 使用where语句批量更新mysql

    如何批量更新mysql数据 如何定义这样的东西 UPDATE table WHERE column1 somevalues SET column2 othervalues 具有一些值 例如 VALUES 160009 160010 1600
  • webflux 请求处理程序中 ServerRequest 返回 null 主体

    我已经在 Spring WebFlux 应用程序中设置了身份验证 身份验证机制似乎工作正常 例如 以下代码用于设置安全Web过滤器链 Bean public SecurityWebFilterChain securityWebFilterC
  • AngularJS - 充当单选按钮的 3 按钮组

    使用离子框架 http ionicframework com 我正在尝试创建一组充当单选按钮的三个按钮 如果我点击早餐 我希望午餐和晚餐恢复到正常 白色 状态 早餐变成蓝色 使用我当前的代码 我无法让这个功能工作 尽管我可以让按钮稍微随机地
  • 如何为 groupby DataFrame 创建滚动百分比

    我正在尝试计算每种产品的每月变化百分比 这是我到目前为止所拥有的 我将其用于涉及单个产品的 DataFrame 我对如何将计算应用于包含许多产品和许多月份的结果集感到困惑 示例数据框 product desc activity month
  • 计算整个表的哈希值的最快方法[重复]

    这个问题在这里已经有答案了 我们需要能够计算外部环境的表哈希并将其与内部环境中预先计算的哈希进行比较 这样做的目的是确保外部环境中的数据不被 流氓 数据库管理员篡改 用户坚持这个功能 目前 我们通过计算每个列值的单独散列 对列散列执行位异或
  • python 全局名称“self”未定义

    刚开始学习 python 我确信这是一个愚蠢的问题 但我正在尝试这样的事情 def setavalue self self myname harry def printaname print Name self myname def mai
  • 获取计算高度 - Javascript - 不是 jQuery

    我有两个并排的 div 设置为自动高度 我希望它们具有相同的高度 因此我将它们组合为数组的成员 我递归遍历数组并将最高的高度设置为最高的高度 问题是我尝试获取计算高度的所有操作都导致了错误的值 我已经尝试过以下方法 els x curren
  • 是否值得缓存 Delphi 内存管理器创建的对象?

    我有一个可以创建和销毁数千个对象的应用程序 是否值得缓存和重用对象 或者 Delphi 的内存管理器足够快 多次创建和销毁对象并不是那么大的开销 与跟踪缓存相反 当我说值得时 我当然在寻找以提高性能 根据最近的测试 如果对象创建并不昂贵 即
  • 使用 Outlook 对象模型,我可以获得在 Outlook 联系人中看到的字段吗

    我可以使用 Outlook 对象模型查看全局地址簿 但无论如何使用 csharp 的 Outlook 对象模型我可以获得一个人的以下属性 城市 州 国家 地区 别名 标题 电话 我似乎无法在 AddressEntry 对象上找到这些属性 编
  • 如何使用 CMake 使用 install-export 和 find_package 查找并链接到库?

    您有一个支持 CMake 的库项目 您需要在另一个库或可执行文件中使用它 如何使用CMake查找并链接到库 您可能有以下偏好 编写尽可能少的样板代码 将链接库的内部细节与消费目标解耦 理想情况下 该库的用法应该如下所示 add execut