【C/C++编译】CMake定义头文件路径、链接库路径及链接选项:PRIVATE,INTERFACE,PUBLIC

这篇具有很好参考价值的文章主要介绍了【C/C++编译】CMake定义头文件路径、链接库路径及链接选项:PRIVATE,INTERFACE,PUBLIC。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、CMake常用变量

在 CMake 中,有许多常见的变量可用于配置和管理构建过程。以下是一些常见的变量,包括当前源码路径:

  • CMAKE_SOURCE_DIR当前 CMakeLists.txt 所在的源码目录的根路径
  • CMAKE_BINARY_DIR:构建目录的根路径,即构建生成的可执行文件、库和其他构建输出的存放位置
  • CMAKE_CURRENT_SOURCE_DIR:当前处理的 CMakeLists.txt 所在的源码目录的路径。
  • CMAKE_CURRENT_BINARY_DIR:当前处理的 CMakeLists.txt 所在的构建目录的路径。
  • CMAKE_CURRENT_LIST_DIR:当前处理的 CMakeLists.txt 所在的路径(源码目录或构建目录)。
  • CMAKE_CURRENT_LIST_LINE:当前正在处理的 CMakeLists.txt 的行号。
  • CMAKE_MODULE_PATH:一个用于指定额外的 CMake 模块(.cmake 文件)的搜索路径的列表
  • CMAKE_INCLUDE_CURRENT_DIR如果设置为 ON,则在构建过程中自动将当前处理的 CMakeLists.txt 所在的目录添加到包含路径中
  • CMAKE_LIBRARY_OUTPUT_DIRECTORY库文件的输出目录
  • CMAKE_RUNTIME_OUTPUT_DIRECTORY可执行文件的输出目录

以上是一些常用的 CMake 变量,其中包含了当前源码路径相关的变量。您可以在 CMakeLists.txt 文件中使用这些变量来设置路径、配置目录结构以及管理构建过程中的输出位置

二、自定义头文件、链接库路径的方法

自定义头文件路径

可以使用 include_directories 命令来指定自定义的头文件路径。该命令会将指定的路径添加到编译器的头文件搜索路径中

include_directories(path/to/include/dir)

你可以多次调用 include_directories 命令,以添加多个头文件路径。

自定义链接库路径

可以使用 link_directories 命令来指定自定义的链接库路径。该命令会将指定的路径添加到链接器的库搜索路径中

link_directories(path/to/library/dir)

你可以多次调用 link_directories 命令,以添加多个链接库路径

需要注意的是,尽量避免在 CMake 中使用 include_directories 和 link_directories 命令来处理第三方库的头文件和链接库路径。更好的做法是使用 find_package 命令或编写 Find 模块来查找和链接第三方库,这样可以更好地管理依赖关系和跨平台兼容性

另一种实现的命令

另外,对于特定的库,你还可以使用 target_include_directories 命令和 target_link_directories 命令,将自定义的头文件路径和链接库路径应用于特定的目标

target_include_directories(target_name PUBLIC path/to/include/dir)
target_link_directories(target_name PUBLIC path/to/library/dir)

这样可以确保自定义路径只应用于特定的目标,并使得相关路径不会泄漏到其他目标中

通过以上方式,你可以在 CMake 中自定义头文件路径和链接库路径,以满足项目的需求。

两种命令的区别介绍

target_include_directories() 的功能完全可以使用 include_directories() 实现。但是我还是建议使用 target_include_directories()。为什么?保持清晰!

include_directories(header-dir) 是一个全局包含,向下传递。什么意思呢?就是说如果某个目录的 CMakeLists.txt 中使用了该指令,其下所有的子目录默认也包含了header-dir 目录

上述例子中,如果在顶层的 cmake-test/CMakeLists.txt 中加入:

include_directories(hello-world)
include_directories(hello-world/hello)
include_directories(hello-world/world)

那么整个工程的源文件在编译时都会增加:

-I hello-world -I hello-world/hello -I hello-world/world ...

各级子目录中无需使用 target_include_directories() 或者 include_directories()了。如果此时查看详细的编译过程(make VERBOSE=1)就会发现编译过程是一大坨,很不舒服。

当然了,在最终子目录的 CMakeLists.txt 文件中,使用 include_directories() 和 target_include_directories() 的效果是相同的

而使用 target_include/link_directories() 每一个目录都是一个模块,目录内部应将对外和对内的头文件进行区分,由模块的调用者决定模块是否被传递(PRIVATE,INTERFACE,PUBLIC)。

测试工程目录结构:

cmake-test/                 工程主目录,main.c 调用 libhello-world.so
├── CMakeLists.txt
├── hello-world             生成 libhello-world.so,调用 libhello.so 和 libworld.so
│   ├── CMakeLists.txt
│   ├── hello               生成 libhello.so 
│   │   ├── CMakeLists.txt
│   │   ├── hello.c
│   │   └── hello.h         libhello.so 对外的头文件
│   ├── hello_world.c
│   ├── hello_world.h       libhello-world.so 对外的头文件
│   └── world               生成 libworld.so
│       ├── CMakeLists.txt
│       ├── world.c
│       └── world.h         libworld.so 对外的头文件
└── main.c

调用关系:

                                ├────libhello.so
可执行文件────libhello-world.so
                                ├────libworld.so

关键字用法说明:

PRIVATE:私有的。生成 libhello-world.so时,只在 hello_world.c 中包含了 hello.h,libhello-world.so 对外的头文件——hello_world.h 中不包含 hello.h。而且 main.c 不会调用 hello.c 中的函数,或者说 main.c 不知道 hello.c 的存在,那么在 hello-world/CMakeLists.txt 中应该写入:

target_link_libraries(hello-world PRIVATE hello)
target_include_directories(hello-world PRIVATE hello)

INTERFACE:接口。生成 libhello-world.so 时,只在libhello-world.so 对外的头文件——hello_world.h 中包含 了 hello.h, hello_world.c 中不包含 hello.h,即 libhello-world.so 不使用 libhello.so 提供的功能,只使用 hello.h 中的某些信息,比如结构体。但是 main.c 需要使用 libhello.so 中的功能。那么在 hello-world/CMakeLists.txt 中应该写入:

target_link_libraries(hello-world INTERFACE hello)
target_include_directories(hello-world INTERFACE hello)

PUBLIC:公开的。PUBLIC = PRIVATE + INTERFACE。生成 libhello-world.so 时,在 hello_world.c 和 hello_world.h 中都包含了 hello.h。并且 main.c 中也需要使用 libhello.so 提供的功能。那么在 hello-world/CMakeLists.txt 中应该写入:

target_link_libraries(hello-world PUBLIC hello)
target_include_directories(hello-world PUBLIC hello)

实际上,这三个关键字指定的是目标文件依赖项的使用范围(scope)或者一种传递(propagate)。官方说明

可执行文件依赖 libhello-world.so, libhello-world.so 依赖 libhello.so 和 libworld.so

  1. main.c 不使用 libhello.so 的任何功能,因此 libhello-world.so 不需要将其依赖 libhello.so 传递给 main.c,hello-world/CMakeLists.txt 中使用 PRIVATE 关键字;
  2. main.c 使用 libhello.so 的功能,但是libhello-world.so 不使用,hello-world/CMakeLists.txt 中使用 INTERFACE 关键字;
  3. main.c 和 libhello-world.so 都使用 libhello.so 的功能,hello-world/CMakeLists.txt 中使用 PUBLIC 关键字;

补充阅读:
CMake的链接选项:PRIVATE,INTERFACE,PUBLIC

参考链接:
https://zhuanlan.zhihu.com/p/631823872
https://zhuanlan.zhihu.com/p/82244559
仅作学习记录文章来源地址https://www.toymoban.com/news/detail-666236.html

到了这里,关于【C/C++编译】CMake定义头文件路径、链接库路径及链接选项:PRIVATE,INTERFACE,PUBLIC的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Linux编译链接选项静态库--whole-archive,--no-whole-archive

    在使用cmake构建工程时,目标可执行程序可以正常构建,但是运行不符合预期。可执行程序依赖libtool.a静态库,静态库有个全局map,map中存放注册的回调函数。在可执行程序运行时发现map为空,检查代码逻辑,libtool.a中存在注册行为。 1、通过nm定位出相关符号表在libtool.a中存

    2024年02月07日
    浏览(27)
  • 现代CMake高级教程 - 第 3 章:链接库文件

    双笙子佯谬老师的【公开课】现代CMake高级教程课程笔记 main.cpp 调用 mylib.cpp 里的 say_hello 函数 1. 直接链接到一起编译 2. mylib 作为一个静态库 编译: 生成了 libmylib.a: 3. mylib 作为一个动态库 编译: 4. mylib 作为一个对象库 对象库类似于静态库,但不生成 .a 文件,只由 CMake

    2024年02月02日
    浏览(33)
  • cpp文件编译过程 makefile cmake

    直接 gcc 没有-o 的话出来的输出exe文件没有调试信息,相比-o的大小会小一点,只有包含了调试信息文件才可以执行 头文件在编译器的include目录中,编译时 -I 指定库 函数库默认路径在编译器的lib目录中,编译时 -L指定目录,-l 小写L 指定库 函数或者是在别的c与cpp文件中 静态

    2024年02月08日
    浏览(29)
  • AndroidNDK开发——使用Cmake编译生成so文件

    最近做串口开发需要编译不同的so文件,于是查找了各种资料,学习了一下so编译. 直接跑项目或者使用gradle构建so生成的so文件如下:这里大家根据自己的需求配置生成so文件,本文只是举例没有全部生成. 如果不引入so文件初始化和调用时会报错,提示找不到so文件,一定要记

    2024年02月15日
    浏览(31)
  • vscode Cmake 多目录,多文件夹,多文件联合编译配置

    前言:网上好多同学发的都是单目录(一个文件夹下),多个cpp文件的联合编译。对于多文件夹,多目录,多个CPP文件的编译可查询的资料查起来不是很容易。 现在来总结一下: 一、单文件夹(即单目录)下的多.cpp使用code runner 运行代码的方式。               其他博文有

    2024年01月15日
    浏览(40)
  • (不用手动下文件)opencv用CMake编译下载失败解决

    报错信息: 解决思路: 更改cmake文件,使用GitHub Proxy 代理加速 (ghproxy.com)对网址进行转发。、 解决步骤: ① 打开opencv-4.7.0cmakeOpenCVDownload.cmake,在157行下方增加两行: (opencv-4.7.0为 源码文件夹 ,不同版本的名称会不一样,如opencv-4.6.0等等) ② 修改完如下图所示(修改完

    2024年02月03日
    浏览(28)
  • 【交叉编译踩坑指北(一)】windows10下Vscode与Cmake编译生成文件

      工具链版本如下 C:UsersLenovocmake -version cmake version 3.24.2 C:UsersLenovomingw32-make -v GNU Make 4.2.1 Built for x86_64-w64-mingw32   若没有以上工具则进行安装,将bin文件加入到环境变量中, 注意:有的交叉编译器在安装时选择自动加入环境变量可能并不会加入,还是需要手动加入环

    2023年04月15日
    浏览(40)
  • CMake学习笔记:搜索第三方库及头文件路径 find_package()命令

    在实际开发过程中,经常不可避免的会使用到第三方开源库,这些开源库可能是通过apt-get install 命令自动安装到系统目录,也可能是由我们自己下载库的源码然后通过编译安装到指定目录的。 不管哪种方式安装的库文件,如果我们需要在自己的项目中使用这些库,首先面临

    2024年02月06日
    浏览(35)
  • 【VSCode】Windows环境下,VSCode 搭建 cmake 编译环境(通过配置文件配置)

    除了之前的使用 VSCode 插件来编译工程外,我们也可以使用配置文件来编译cmake工程,主要依赖 launch.json 和 tasks.json 文件。 目录 一、下载编译器 1、下载 Windows GCC 2、选择编译器路径 二、配置 debug 环境 1、配置 lauch.json 文件 2、配置 tasks.json 文件 三、编译工程 1、测试工程结

    2024年02月03日
    浏览(36)
  • 彻底解决cmake编译过程中fatal error: OpenNI.h: 没有那个文件或目录

    环境:ubuntu20.04 在cmake编译过程中,最常见的莫过于fatal error: xxxx.h: 没有那个文件或目录,这个问题困扰着很多初学者,原因是没有找到某个头文件,小白版的解决方法,直接把这个头文件的地址写进.cpp源文件或者把头文件地址写进 CMakeLists.txt INCLUDE_DIRECTORIES(头文件地址)。 用

    2024年02月16日
    浏览(33)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包