CMake include_directories 和 target_include_directories,头文件的搜索顺序

15 篇文章 2 订阅

业务中遇到个问题,引用了 jsoncpp 这个库之后,需要引用其头文件,但其头文件进一步引用了 jsoncpp 安装位置的其他头文件,但如果一台 Linux 机器上在不同的路径安装了两个不同版本的 jsoncpp 库,并且这两个路径都是该项目的头文件包含路径,那么,编译器会先找哪个路径下的头文件呢?带着这个问题,我开始翻阅 camke 的官方文档,由于是全英文版,读起来还是很费劲,因此先翻译出来。
翻译完之后发现,include 的顺序跟翻译关系不大,因此,又将文档翻译写到了后半段,而把实验写到了前半段。

头文件搜索顺序

先说结论,编译器会按照 CMake 脚本给出的 include 路径顺序从头到尾(从左往右)依次搜索,如果在前面找到了相应的头文件,则不再去后面搜索。

实验

目录结构

在这里插入图片描述

文件内容

// include1/includea.h
int i = 1;
// include2/includea.h
int i = 2;
// src/src.cpp
#include "includea.h"
#include <iostream>
using namespace std;
int main() {
	cout << "Hello, " << a << endl;
}
cmake_minimum_required(VERSION 3.10.0)
project(includeorder)
aux_source_directory(${PROJECT_SOURCE_DIR}/src SRC)
add_executable(${PROJECT_NAME} ${SRC})
target_include_directories(${PROJECT_NAME} PRIVATE ${PROJECT_SOURCE_DIR}/include2 ${PROJECT_SOURCE_DIR}/include1)

编译后执行结果:Hello, 2

cmake_minimum_required(VERSION 3.10.0)
project(includeorder)
aux_source_directory(${PROJECT_SOURCE_DIR}/src SRC)
add_executable(${PROJECT_NAME} ${SRC})
target_include_directories(${PROJECT_NAME} PRIVATE ${PROJECT_SOURCE_DIR}/include1 ${PROJECT_SOURCE_DIR}/include2)

编译后执行结果:Hello, 1

文档翻译

include_directories

添加包含路径到构建任务。
include_directories([AFTER|BEFORE] [SYSTEM] dir1 [dir2 ...]
给编译器添加给出的路径,用来搜索包含文件。相对路径将被翻译成相对于当前脚本所在目录的相对路径。
这些包含目录将被添加到当前 CMakeLists 文件的 INCLUDE_DIRECTORIES 目录属性中。他们同时也会被添加到当前 CMakeLists 文件中的每一个构建目标的目标属性中。目标属性的值是被生成器使用的。
这些路径会被默认添加到当前的包含路径列表的尾部,这种默认行为也可以通过修改参数 CMAKE_INCLUDE_DIRECTORIES_BEFOREON 来修改。显式使用 AFTERBEFORE,你可以选择添加到包含列表的头部或者尾部,与默认行为无关。
如果使用 SYSTEM 参数,在某些平台上将会告知编译器这些路径是系统包含路径。使用该参数可以实现一些效果,例如让编译器跳过警告,或者那些固定安装的系统文件不会被认为是依赖项——参考编译器文档。
include_directories 的参数也可以借助语法 “$<…>” 使用 “生成器表达式”,参考 cmake-generator-expressions(7)指南来获取可用表达式。参考 cmake-buildsystem(7) 指南来获取关于定义构建系统属性的更多知识。
**注意:**建议使用 target_include_directores() 指令给单独的构建目标添加包含目录,并可选地传播(propagate)或导出他们给相关依赖(dependents)。

target_include_directories

给构建目标添加包函目录。

target_include_directories(<target> [system] [AFTER|BEFORE]
							<INTERFACE|PUBLIC|PRIVATE> [items1...]
							[<INTERFACE|PUBLIC|PRIVATE> [items2...]...])

针对给定的构建目标(target)定义编译时使用的包含路径。参数 <target> 必须是已被类似于 add_executable() 或者 add_library() 命令创建出来的,并且不能是一个 ALIAS TARGET
明确使用参数AFTERBEFORE,你可以选择添加到尾部或者头部,不受默认行为影响。
参数 INTERFACEPUBLICPRIVATE 被用来指定接下来的参数的作用范围。
PRIVATEPUBLIC 会将 INCLUDE_DIRECOTRIES 属性添加给目标 <target>
PUBLICINTERFACE 参数会将 INTERFACE_INCLUDE_DIRECTORIES 属性添加给目标 <target>
关于 INCLUDE_DIRECTORIESINTERFACE_INCLUDE_DIRECTORIES 的差异请点击链接。
接下来的参数定义了包含目录。
3.11 版本的新功能:允许设置 INTERFACE 参数来影响 导入的目标.
对同一目标重复调用命令将添加按调用顺序相关参数到列表尾部。
在某些平台,使用 SYSTEM 参数可告知编译器这些目录是系统包含目录,这会让编译器忽略警告或者跳过包含相关头文件。此外,系统包含目录会在普通包含目录之后被搜索,无论在列表中的顺序如何。
如果 SYSTEM 参数和 PUBLIC 参数或者 INTERFACE 参数同时使用,这些包含目录会被添加到INTERFACE_SYSTEM_INCLUDE_DIRECTORIES 目标属性。
给到 target_include_directories 的参数可以是使用 $<...> 语法的生成器表达式。参考 cmake-generator-expressions(7)指南来获取可用表达式。参考 cmake-buildsystem(7) 指南来获取关于定义构建系统属性的更多知识。
定义的包含目录可以使绝对路径或相对路径,相对路径将被翻译为相对于当前脚本所在目录(CMAKE_CURRENT_SOURCE_DIR)的路径,转换成一个绝对路径存储在在相关目标属性中。如果路径是以生成器表达式开头的,该路径将被认为是一个绝对路径(有一个例外,下面注明),并且不做任何修改地使用。
以下内容由于跟主题关系不大。不再翻译,暂时贴上原文,有空再翻。
Include directories usage requirements commonly differ between the build-tree and the install-tree. The BUILD_INTERFACE and INSTALL_INTERFACE generator expressions can be used to describe separate usage requirements based on the usage location. Relative paths are allowed within the INSTALL_INTERFACE expression and are interpreted as relative to the installation prefix. Relative paths should not be used in BUILD_INTERFACE expressions because they will not be converted to absolute. For example

target_include_directories(mylib PUBLIC
  $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include/mylib>
  $<INSTALL_INTERFACE:include/mylib>  # <prefix>/include/mylib
)
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
解释根据给出的代码,可以将其转化为以下CMake代码: 复制 cmake_minimum_required(VERSION 3.5) project(UavRectifyLoadLIb LANGUAGES CXX) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_AUTOMOC ON) set(CMAKE_AUTORCC ON) set(CMAKE_AUTOUIC ON) find_package(Qt5Core REQUIRED) add_executable(UavRectifyLoadLIb main.cpp ) target_link_libraries(UavRectifyLoadLIb PRIVATE Qt5::Core UAVAutoRectifyMt UAVAutoRectify UAVAutoRectifyFi DEMDriver Projection IImage_gC opencv_core opencv_highgui opencv_imgproc opencv_features2d opencv_imgcodecs ) target_include_directories(UavRectifyLoadLIb PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../../include/gdal1101 ${CMAKE_CURRENT_SOURCE_DIR}/../include ${CMAKE_CURRENT_SOURCE_DIR}/../../../lib/opencvf249 ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../../usr/local/include ) if(UNIX AND NOT APPLE) target_link_directories(UavRectifyLoadLIb PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../../product/release32 ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../../usr/local/lib ) endif() if(WIN32) if(CMAKE_BUILD_TYPE STREQUAL "Debug") set_target_properties(UavRectifyLoadLIb PROPERTIES RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_CURRENT_SOURCE_DIR}/../../../../RasterManager/bin/Debug ) else() set_target_properties(UavRectifyLoadLIb PROPERTIES RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_CURRENT_SOURCE_DIR}/../../../../RasterManager/bin/release ) endif() else() if(CMAKE_BUILD_TYPE STREQUAL "Debug") set_target_properties(UavRectifyLoadLIb PROPERTIES RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_CURRENT_SOURCE_DIR}/../../../product/release32 ) else() set_target_properties(UavRectifyLoadLIb PROPERTIES RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_CURRENT_SOURCE_DIR}/../../../product/release32 ) endif() endif()
06-11
以下是将给出的代码转化为CMake代码的步骤: 1. 首先,在CMakeLists.txt文件中添加以下内容: ``` cmake_minimum_required(VERSION 3.5) project(UavRectifyLoadLIb LANGUAGES CXX) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_AUTOMOC ON) set(CMAKE_AUTORCC ON) set(CMAKE_AUTOUIC ON) ``` 这些命令设置了编译器版本、项目名称、C++标准、自动生成MOC文件、自动生成RCC文件和自动生成UI文件。 2. 接下来,添加以下代码以查找Qt5Core库: ``` find_package(Qt5Core REQUIRED) ``` 这个命令告诉CMake查找Qt5Core库,并确保它被正确安装。 3. 然后,添加以下代码以创建可执行文件: ``` add_executable(UavRectifyLoadLIb main.cpp ) ``` 这个命令告诉CMake创建一个名为UavRectifyLoadLIb的可执行文件,并将main.cpp文件添加到该文件中。 4. 接下来,添加以下代码以链接所有必要的库: ``` target_link_libraries(UavRectifyLoadLIb PRIVATE Qt5::Core UAVAutoRectifyMt UAVAutoRectify UAVAutoRectifyFi DEMDriver Projection IImage_gC opencv_core opencv_highgui opencv_imgproc opencv_features2d opencv_imgcodecs ) ``` 这个命令告诉CMake链接所有必要的库,并将它们添加到可执行文件中。 5. 最后,添加以下代码以设置包含目录和链接目录: ``` target_include_directories(UavRectifyLoadLIb PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../../include/gdal1101 ${CMAKE_CURRENT_SOURCE_DIR}/../include ${CMAKE_CURRENT_SOURCE_DIR}/../../../lib/opencvf249 ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../../usr/local/include ) if(UNIX AND NOT APPLE) target_link_directories(UavRectifyLoadLIb PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../../product/release32 ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../../usr/local/lib ) endif() if(WIN32) if(CMAKE_BUILD_TYPE STREQUAL "Debug") set_target_properties(UavRectifyLoadLIb PROPERTIES RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_CURRENT_SOURCE_DIR}/../../../../RasterManager/bin/Debug ) else() set_target_properties(UavRectifyLoadLIb PROPERTIES RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_CURRENT_SOURCE_DIR}/../../../../RasterManager/bin/release ) endif() else() if(CMAKE_BUILD_TYPE STREQUAL "Debug") set_target_properties(UavRectifyLoadLIb PROPERTIES RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_CURRENT_SOURCE_DIR}/../../../product/release32 ) else() set_target_properties(UavRectifyLoadLIb PROPERTIES RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_CURRENT_SOURCE_DIR}/../../../product/release32 ) endif() endif() ``` 这个命令告诉CMake设置包含目录和链接目录,并根据不同的操作系统设置输出目录。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

深海Enoch

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值