深入理解 CMake 中的 INCLUDE_DIRECTORIES 与 target_include_directories
在使用 CMake 构建系统时,指定头文件的包含路径是非常常见的一步。对于这个任务,CMake 提供了两种主要的命令:INCLUDE_DIRECTORIES 和 target_include_directories。虽然它们看似类似,但它们的作用范围、应用方式以及适用场景却有很大差别。
1. 什么是头文件包含目录?
在编译 C++ 项目时,头文件提供了声明和接口,是源代码文件间相互引用的关键部分。为了告诉编译器去哪里查找这些头文件,通常需要指定一个或多个包含目录(include directories)。如果没有正确设置头文件路径,编译器会报出类似 "file not found" 的错误。因此,如何有效管理和设置这些路径对于构建项目至关重要。
CMake 作为一个跨平台的构建系统,提供了多种方式来为项目设置包含目录,最常用的就是 INCLUDE_DIRECTORIES 和 target_include_directories。
2. INCLUDE_DIRECTORIES —— 全局包含目录
INCLUDE_DIRECTORIES 是 CMake 中最早的用于设置包含路径的命令,它的效果是全局性的。也就是说,当你在 CMake 文件中调用 INCLUDE_DIRECTORIES 时,它会将指定的包含路径应用到当前作用域下的所有目标(targets)。所有在该命令之后的目标都会继承这些包含路径。
语法:
INCLUDE_DIRECTORIES(<directories>)
使用示例:
INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include)
这条指令会将项目根目录下的 include 目录添加为全局的包含目录。这样,所有的目标(如库、可执行文件)都可以从这个目录中查找头文件。
适用场景:
- 小型项目:在简单项目中,只有少量的源文件和库,头文件目录也很集中。此时使用
INCLUDE_DIRECTORIES是一个快速且方便的选择。 - 简单的全局依赖:如果项目中的所有目标都依赖于同一组头文件路径,这种全局设置方式非常有效。
优点:
- 简单易用:只需一次调用,即可为所有目标设置头文件搜索路径。
- 快速实现:适合快速搭建或验证简单项目。
缺点:
- 全局性:一旦设置,后续所有的目标都会使用这些包含目录,难以做到细粒度的控制。这会增加项目规模和复杂性时的管理难度。
- 可维护性差:如果项目变得复杂,全局的包含目录可能会导致不必要的依赖,或者由于头文件冲突而导致编译问题。
- 潜在污染:多个模块共用一组全局的头文件路径,可能会引发意想不到的问题,如头文件覆盖或模块间的耦合度过高。
3. target_include_directories —— 精确控制每个目标的包含目录
为了克服 INCLUDE_DIRECTORIES 的全局性问题,CMake 引入了 target_include_directories 命令,它允许开发者为特定的目标设置包含目录。与 INCLUDE_DIRECTORIES 不同,这个命令具有更强的作用范围控制能力,并且支持三种不同的作用域:PRIVATE、PUBLIC 和 INTERFACE,帮助管理目标之间的依赖关系。
语法:
target_include_directories(<target> [PRIVATE|PUBLIC|INTERFACE] <directories>)
PRIVATE:仅对当前目标可见,依赖于这个目标的其他目标不会继承这些包含目录。PUBLIC:对当前目标和依赖于该目标的其他目标都可见。INTERFACE:当前目标不会使用这些包含目录,但依赖于它的其他目标可以使用。
使用示例:
add_library(MyLibrary mylibrary.cpp) target_include_directories(MyLibrary PUBLIC ${CMAKE_SOURCE_DIR}/include PRIVATE ${CMAKE_SOURCE_DIR}/src )
在这个例子中,MyLibrary 会使用 include 和 src 目录中的头文件:
- PUBLIC 的
include目录不仅会对MyLibrary可见,还会对依赖于MyLibrary的目标可见。 - PRIVATE 的
src目录则仅对MyLibrary自己可见,外部目标不会继承这个路径。
适用场景:
- 大型项目:在复杂的项目中,每个库或模块可能都有自己的依赖和头文件路径。这时,
target_include_directories能提供更加精细的控制。 - 模块化开发:当项目采用模块化或库的方式进行构建时,每个模块的头文件路径通常是独立的。使用
target_include_directories可以避免头文件路径之间的冲突,并且可以很好地管理库与库之间的依赖关系。 - 公共和私有头文件区分:当一个库需要向外部暴露部分头文件(比如库的 API),但不希望暴露其内部实现的头文件时,可以利用
PUBLIC和PRIVATE来进行管理。
优点:
- 精确控制:每个目标可以独立管理自己的包含目录,减少不必要的全局污染。
- 作用域管理:通过
PRIVATE、PUBLIC和INTERFACE,可以更灵活地控制头文件路径的可见性,从而更好地管理模块间的依赖关系。 - 可维护性强:在大型项目中,能够清晰地定义每个模块的头文件依赖,提升代码的可维护性。
缺点:
- 语法复杂:相比
INCLUDE_DIRECTORIES,target_include_directories的语法和概念相对复杂,特别是对于新手来说,可能需要更多的学习时间。 - 初期搭建繁琐:在项目早期搭建阶段,可能会觉得使用
target_include_directories比较繁琐,因为需要为每个目标单独配置头文件路径。
4. INCLUDE_DIRECTORIES 和 target_include_directories 的对比
| 特性 | INCLUDE_DIRECTORIES | target_include_directories |
|---|---|---|
| 作用范围 | 全局 | 仅影响指定目标 |
| 细粒度控制 | 无 | 可以使用 PRIVATE、PUBLIC、INTERFACE |
| 适用项目 | 小型项目,简单头文件依赖 | 大型项目,复杂模块化开发 |
| 维护成本 | 随着项目增大,维护难度增加 | 清晰的依赖管理,维护性较好 |
| 推荐使用场景 | 简单的构建流程 | 精细的目标依赖管理 |
5. 最佳实践
-
优先使用
target_include_directories:在现代 CMake 项目中,尤其是模块化和大型项目,尽量使用target_include_directories来精确控制头文件的包含目录。它能提供更清晰的依赖关系管理,减少不必要的全局污染。 -
分清
PUBLIC、PRIVATE和INTERFACE:合理使用这三者来管理库的头文件依赖。PUBLIC适合对外暴露的 API 头文件,PRIVATE用于内部实现细节,INTERFACE则适合不直接使用但会传递依赖的情况。 -
减少全局依赖:避免滥用
INCLUDE_DIRECTORIES,尤其是在大型项目中,全局的头文件路径可能会引发意想不到的依赖和冲突问题。 -
模块化设计:当项目逐渐复杂化,考虑将项目划分为多个独立模块,每个模块只依赖于自己需要的头文件,使用
target_include_directories来管理这些模块的头文件路径。
结论
在 CMake 中,INCLUDE_DIRECTORIES 和 target_include_directories 都是管理头文件路径的重要工具,但它们适用于不同的场景。INCLUDE_DIRECTORIES 简单直观,但在大型项目中会变得难以维护。相反,target_include_directories 提供了更强大的控制能力,能够为每个目标精确地管理头文件路径。
在现代 CMake 项目中,推荐使用 target_include_directories,因为它能够更好地管理目标之间的依赖,并且有助于保持项目的清晰性和可维护性。
相关文章:
深入理解 CMake 中的 INCLUDE_DIRECTORIES 与 target_include_directories
在使用 CMake 构建系统时,指定头文件的包含路径是非常常见的一步。对于这个任务,CMake 提供了两种主要的命令:INCLUDE_DIRECTORIES 和 target_include_directories。虽然它们看似类似,但它们的作用范围、应用方式以及适用场景却有…...
【不知道原因的问题】java.lang.AbstractMethodError
项目场景: 提示:这里简述项目相关背景: 遇到了一个问题: java.lang.AbstractMethodError 问题描述 提示:这里描述项目中遇到的问题: 在Java开发中,java.lang.AbstractMethodError是一个常见…...
分布式篇(分布式事务)(持续更新迭代)
一、事务 1. 什么是事务 2. 事务目的 3. 事务的流程 4. 事务四大特性 原子性(Atomicity) 一致性(Consistency) 持久性(Durability) 隔离性(Isolation) 5. MySQL VS Oracle …...
[Linux] 逐层深入理解文件系统 (2)—— 文件重定向
标题:[Linux] 逐层深入理解文件系统 (2)—— 文件重定向 个人主页水墨不写bug (图片来源于网络) 目录 一、文件的读取和写入 二、文件重定向的本质 1.手动模拟重定向的过程——把标准输出重定向到redir.txt 2.重定向…...
html+css+js实现Badge 标记
实现效果: 代码实现: <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Badge…...
纯css 轮播图片,鼠标移入暂停 移除继续
核心 滚动: animation: 动画名称 20s linear infinite normal;停止: animation: 动画名称 20s linear infinite paused; 完整例子: html: <div class"carousel-wrapper"><div class"carousel"><div cl…...
iOS GCD的基本使用
一:什么是GCD GCD的全程是:Grand Central Dispatch, 直白的用汉语翻译就是:厉害的中枢调度器. GCD 是iOS 的多线程技术的实现方案,但是它并不是多线程技术,它是“并发解决技术”,是苹果公司研发的,会自动管理线程(这一段定义有点拗口,简单了解就行) GCD会自动管理线程的生命…...
如何设计开发RTSP直播播放器?
技术背景 我们在对接RTSP直播播放器相关技术诉求的时候,好多开发者,除了选用成熟的RTSP播放器外,还想知其然知其所以然,对RTSP播放器的整体开发有个基础的了解,方便方案之作和技术延伸。本文抛砖引玉,做个…...
Java基础系列-一文搞懂自定义排序
java自定义排序 自定义排序的理解: 我们首先看需求:一个二维数组 [[1,3],[8,10],[15,18],[2,6]] 我们的需求是根据集合(二维数组取出来的数据) 左边小的左边这种方式排序 例如1<8 排序方式就是[1,3],[8,10] 此时我们就需…...
扫普通链接二维码打开小程序
1. 2.新增规则(注意下载文件到跟目录下,需要建个文件夹放下载的校验文件) 3.发布 ps:发布后,只能访问正式版本。体验版本如果加了 测试链接http://xxx/xsc/10 那么http://xxx/xsc/aa.....应该都能访问 例如aa101 aa…...
计算机储存与分区
Disk partitioning 盘分区是在辅助储存上创建一个或多个区域,以便可以单独管理每个区域。而这些区域称为分区(partition)。这通常是在为新盘选择分区方案后,需要做的事。 MBR and GPT 分区方案(分区表)有…...
OpenCV之换脸技术:一场面部识别的奇妙之旅
在这个数字化与智能化并进的时代,图像处理技术日益成为连接现实与虚拟世界的桥梁。其中,换脸技术作为一项颇受欢迎且富有挑战性的应用,不仅让人惊叹于技术的魔力,更在娱乐、影视制作等领域展现了无限可能。今天,我们就…...
Linux学习笔记9 文件系统的基础
一、查看文件组织结构 Linux中一切都是文件。 Linux和Win的文件系统不是一个结构,Linux存在的根目录是所有目录的起点。 所有的存储空间和设备共享一个根目录,不同的磁盘块和分区挂载在其下,成为某个子目录的子目录,甚至设备也挂…...
Android OpenGL粒子特效
在本篇,我们将开启一个新的项目,探索粒子的世界。粒子是一种基本的图形元素,它们通常被表示为一组点。通过巧妙地组合一些基础的物理效果,我们能够创造出许多令人惊叹的视觉效果。想象一下,我们可以模拟一个水滴从喷泉…...
5 -《本地部署开源大模型》在Ubuntu 22.04系统下ChatGLM3-6B高效微调实战
在Ubuntu 22.04系统下ChatGLM3-6B高效微调实战 无论是在单机单卡(一台机器上只有一块GPU)还是单机多卡(一台机器上有多块GPU)的硬件配置上启动ChatGLM3-6B模型,其前置环境配置和项目文件是相同的。如果大家对配置过程还…...
dpkg:错误:另外一个进程已经为dpkg前端锁加锁
一、 问题描述 在新装ubuntu系统时,我们常常会遇见dpkg的错误,dpkg:错误:另外一个进程已经为dpkg前端锁加锁,如下图。 二、问题解决 方法一 先执行sudo rm /var/lib/dpkg/lock-frontend然后再继续安装软件包,如果出现问题dpkg:…...
基于SSM服装定制系统的设计
管理员账户功能包括:系统首页,个人中心,用户管理,服装类型管理,服装信息管理,服装定制管理,留言反馈,系统管理 前台账号功能包括:系统首页,个人中心…...
RK3588开发笔记-usb3.0 xhci-hcd控制器挂死问题解决
目录 前言 一、问题现象 二、问题分析 三、问题排查 总结 前言 在使用 RK3588 芯片进行开发的过程中,我遇到了 USB 3.0 xHCI-HCD 控制器外接5G通讯模块偶尔挂死的问题。这个问题导致 USB 设备失去响应,且不能恢复,需要重启整个系统才能恢复使用,针对该问题进行大量测试以…...
深入解析TCP/IP协议:网络通信的基石
1. 引言 TCP/IP 协议是现代计算机网络的核心,它为互联网上的设备提供了通信的基础。在网络通信中,TCP/IP 协议栈是无处不在的,无论是个人设备的浏览器请求,还是大型分布式系统的内部通信,都依赖于它的稳定、高效与可靠…...
基于微信小程序的汽车预约维修系统(lw+演示+源码+运行)
基于微信小程序的汽车预约维修系统 摘要 随着信息技术在管理上越来越深入而广泛的应用,管理信息系统的实施在技术上已逐步成熟。本文介绍了基于微信小程序的汽车预约维修系统的开发全过程。通过分析基于微信小程序的汽车预约维修系统管理的不足,创建了…...
日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻
在如今就业市场竞争日益激烈的背景下,越来越多的求职者将目光投向了日本及中日双语岗位。但是,一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧?面对生疏的日语交流环境,即便提前恶补了…...
springboot 百货中心供应链管理系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,百货中心供应链管理系统被用户普遍使用,为方…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)
HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...
k8s从入门到放弃之Ingress七层负载
k8s从入门到放弃之Ingress七层负载 在Kubernetes(简称K8s)中,Ingress是一个API对象,它允许你定义如何从集群外部访问集群内部的服务。Ingress可以提供负载均衡、SSL终结和基于名称的虚拟主机等功能。通过Ingress,你可…...
电脑插入多块移动硬盘后经常出现卡顿和蓝屏
当电脑在插入多块移动硬盘后频繁出现卡顿和蓝屏问题时,可能涉及硬件资源冲突、驱动兼容性、供电不足或系统设置等多方面原因。以下是逐步排查和解决方案: 1. 检查电源供电问题 问题原因:多块移动硬盘同时运行可能导致USB接口供电不足&#x…...
学校招生小程序源码介绍
基于ThinkPHPFastAdminUniApp开发的学校招生小程序源码,专为学校招生场景量身打造,功能实用且操作便捷。 从技术架构来看,ThinkPHP提供稳定可靠的后台服务,FastAdmin加速开发流程,UniApp则保障小程序在多端有良好的兼…...
AspectJ 在 Android 中的完整使用指南
一、环境配置(Gradle 7.0 适配) 1. 项目级 build.gradle // 注意:沪江插件已停更,推荐官方兼容方案 buildscript {dependencies {classpath org.aspectj:aspectjtools:1.9.9.1 // AspectJ 工具} } 2. 模块级 build.gradle plu…...
Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...
Unity | AmplifyShaderEditor插件基础(第七集:平面波动shader)
目录 一、👋🏻前言 二、😈sinx波动的基本原理 三、😈波动起来 1.sinx节点介绍 2.vertexPosition 3.集成Vector3 a.节点Append b.连起来 4.波动起来 a.波动的原理 b.时间节点 c.sinx的处理 四、🌊波动优化…...
搭建DNS域名解析服务器(正向解析资源文件)
正向解析资源文件 1)准备工作 服务端及客户端都关闭安全软件 [rootlocalhost ~]# systemctl stop firewalld [rootlocalhost ~]# setenforce 0 2)服务端安装软件:bind 1.配置yum源 [rootlocalhost ~]# cat /etc/yum.repos.d/base.repo [Base…...
