cmake_CMake内置属性解决头文件包含/CMake定义C/C++标准/include_directories()/宏定义

文章目录

  • [第二章 CMake基础语法](#第二章 CMake基础语法)
    • [2.20 CMake内置属性解决头文件包含](#2.20 CMake内置属性解决头文件包含)
      • [2.20.1 CMake内置属性](#2.20.1 CMake内置属性)
      • [2.20.2 测试文件](#2.20.2 测试文件)
      • [2.20.3 解决方法](#2.20.3 解决方法)
      • [2.20.4 探究为什么可生成exe ?](#2.20.4 探究为什么可生成exe ?)
    • [2.21 CMAKE_CXX_STANDARD变量设置C++标准](#2.21 CMAKE_CXX_STANDARD变量设置C++标准)
    • [2.22 include_directories()/target_include_directories()](#2.22 include_directories()/target_include_directories())
    • [2.23 target_sources() 向目标添加源文件](#2.23 target_sources() 向目标添加源文件)
    • [2.24 add_compile_definitions()/target_compile_definition()添加预定义](#2.24 add_compile_definitions()/target_compile_definition()添加预定义)

本文介绍CMake内置属性解决头文件包含、CMake定义C/C++标准、include_directories()和宏定义。

第二章 CMake基础语法

2.20 CMake内置属性解决头文件包含

2.20.1 CMake内置属性

CMake 中定义了很多范围(全局、目录、目标(例如可执行文件或库)源文件 测试 或者 缓存 等 )内置的属性(Property),用于控制CMake的行为和特性,内置属性可直接使用,而无需显式定义。

2.20.2 测试文件

头文件 和 源文件不在一个目录下面。

bash 复制代码
#include <iostream>
#include "a.h"

using namespace std;

void funcA()
{
    cout << "Function A called" << endl;
}

int main()
{
    #ifdef A
        funcA();
    #endif
    cout << "AAAAAA" << endl;
    return 0;
}

CMakeLists.txt文件如下:

bash 复制代码
cmake_minimum_required(VERSION 3.30)

# 项目
project(sourceCmake VERSION 1.2 LANGUAGES CXX)

if(NOT CMAKE_BUILD_TYPE)
    set(CMAKE_BUILD_TYPE Debug CACHE STRING "选择编译类型" FORCE)
endif()

add_executable(A a.cpp)

编译如下:提示无法找到对应的头文件。

2.20.3 解决方法

在源文件中找不到头文件,使用cmake内置属性来解决。

bash 复制代码
cmake_minimum_required(VERSION 3.30)

# 项目
project(sourceCmake VERSION 1.2 LANGUAGES CXX)

if(NOT CMAKE_BUILD_TYPE)
    set(CMAKE_BUILD_TYPE Debug CACHE STRING "选择编译类型" FORCE)
endif()

add_executable(A a.cpp)

# 定义目标属性
set_target_properties(A PROPERTIES  COMPILE_OPTIONS -Wall 
                                    COMPILE_DEFINITIONS "A"
                                    INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}/sub")

#获取目标的属性 
get_target_property(var1 A COMPILE_OPTIONS)
message("COMPILE_OPTIONS=${var1}") 
#  COMPILE_OPTIONS=-Wall

get_target_property(var2 A COMPILE_DEFINITIONS)
message(" COMPILE_DEFINITIONS=${var2}")
# COMPILE_DEFINITIONS=A

get_target_property(var3 A INCLUDE_DIRECTORIES)
message(" INCLUDE_DIRECTORIES=${var3}")
# INCLUDE_DIRECTORIES=E:/cmakeLearning/chap2/13property/sub

上面找不到头文件问题即可解决。

2.20.4 探究为什么可生成exe ?

在目标属性中添加上 INCLUDE_DIRECTORY后,为什么可以包含头文件呢?,使用下面的-v选项查看。

bash 复制代码
PS E:\practice_Code\cmake\25> cmake --build build -v
bash 复制代码
-v 或 --verbose : 启用详细输出,方便查看执行过程。

原理:CMake将设置的目标属性,加入到编译选项中。

2.21 CMAKE_CXX_STANDARD变量设置C++标准

**CMAKE_C_STANDARD :**指定C语高标准、值可以是90 99 11 17 23,当目标创建时作为TARGET属性C_STANDARD的默认值
CMAKE_C_STANDARD_REQUIRED : 设置为ON强制使用C标准,设置为OFF则表示可选。如果指定标准不可用,则可会"囊减"到以前的标准。当目标创建时作为TARGET属性C_STANDARD_REQUIRED的默认值
CMAKE_CXX_STANDARD 指定C++语标准、值可以是98,11,14,17 ,23 26,当目标创建时作为TARGET属性CXX_STANDARD的默认值
CMAKE_CXX_STANDARD_REQUIRED 设置为ON强制使用C++标准,设置为OFF则表示可选,如果指定标准不可用,则可能会"衰减"到以前的标准。当目标创建时作为TARGET属性CXX STANDARD REQUIRED的默认值

CMakeLists.txt

bash 复制代码
cmake_minimum_required(VERSION 3.30)

project(main VERSION 1.0 LANGUAGES CXX)

# 查看C++标准
message("CMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}")
# 变量CMAKE_C_STANDARD=(没设置之前是空置)

# 设置C++ 23 标准
set(CMAKE_CXX_STANDARD 23)
message("CMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}")
# CMAKE_CXX_STANDARD=23

# 严格设置C++标准
set(CMAKE_CXX_STANDARD_REQUIRED ON)

add_executable(main main.cpp)

2.22 include_directories()/target_include_directories()

include_directories() 作用:告诉编译器去哪里找头文件,相当于-I/path/to/dir。设置头文件后,会传递到当前目录以及所有子目录下的所有cmake。

bash 复制代码
	include_directories([AFTER] [BEFORE] [SYSTEM] dir1 [dir2])

参数:

bash 复制代码
AFTER | BEFORE : AFTER 是默认行为,将路径添加到当前include列表的末尾或前边。
SYSTEM : 告诉编译器这些目标在某些平台上是系统包含目录,设置后编译器会忽略这些目录下的头文件产生的警告。
dir : 被添加的目录,相对路径被解释为相对于当前源目录。

include_directories()缺点:它会影响当前目录所有的目标。例如, target A 需要库 X,target B 不需要X, 用include_directories()会导致B也加上X的路径。

因此,现代CMake不推荐使用这个方法设置目标的头文件,而是使用target_include_directories设置目录头文件。

target_include_directories用于给特定的库或可执行文件添加头文件搜索路径,比 include_directories 更精细,不会污染全局,语法如下:

bash 复制代码
target_include_directories(<target> [SYSTEM] [BEFORE] <INTERFACE|PUBLIC|PRIVATE> [items1...] ...)

: 目标,可执行文件或库。

<INTERFACE|PUBLIC|PRIVATE>:为了说明这三个关键字作用,假如现在正在编译一个库MyLib,它依赖头文件目录A;

  • PRIVATE:为MyLib设置私有属性后,只给自己用,链接MyLib的人不能用。
  • INTERFACE: 只给使用这个三方库的人使用,编译这个库时,不能使用指定头文件目录。
  • PUBLIC: 链接库的人和自己都能使用这个头文件。

测试代码,目录如下:

最外层cmake如下:

bash 复制代码
cmake_minimum_required(VERSION 3.30)

project (main VERSION 1.0 LANGUAGES CXX)

set (CMAKE_CXX_STANDARD 23)

set (CMAKE_CXX_STANDARD_REQUIRED ON)

# 调用子目录
add_subdirectory(lib)

add_executable(main app/main.cpp)

target_link_libraries(main PRIVATE mathlib)

库的cmake如下:

bash 复制代码
cmake_minimum_required(VERSION 3.30)

project (mathlib VERSION 1.0 LANGUAGES CXX)

set(SOURCEFILE ${CMAKE_CURRENT_SOURCE_DIR}/source/my_math.cpp)
message("SOURCEFILE=${SOURCEFILE}")

add_library(mathlib STATIC ${SOURCEFILE}) 

# 设置公开:谁调用这个库,都会包含这个目录
target_include_directories(mathlib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)

2.23 target_sources() 向目标添加源文件

向目标添加源文件,使用target_sources(). 语法格式:

bash 复制代码
target_sources(<target> <INTERFACE | PUBLIC | PRIVATE> [items1] <INTERFACE | PUBLIC | PRIVATE> [items2])

参数:由add_executable() 和 add_library() 或 add_custom_target() 等命令创建的目标,并且不能是目标别名。

INTERFACE | PUBLIC | PRIVATE : PUBLIC既给自己用,又给别人用;PRIVATE只给自己用,INTERFACE 只给别人用。

bash 复制代码
cmake_minimum_required(VERSION 3.29)

project(test29)

add_executable(main)
# 向目标加入源文件
target_sources(main PUBLIC main.c PRIVATE a.c PRIVATE b.c)

#获取目标属性
get_target_property( var  main   SOURCES)
message( "目标 SOURCES= ${var}" )
# 目标 SOURCES= main.c;a.c;b.c

get_target_property( var  main   INTERFACE_SOURCES)
message( "目标 INTERFACE_SOURCES= ${var}" )
# 目标 INTERFACE_SOURCES= E:/practice_Code/cmake/29/main.c

2.24 add_compile_definitions()/target_compile_definition()添加预定义

add_compile_definitions() 为当前目录以及子目录下的所有target添加宏定义,相当于在编译时添加 -D MY_MRO=1

语法:

bash 复制代码
add_compile_definitions(<definition> ...)

例如:

bash 复制代码
# 定义一个带值的宏(相当于 #define MAX_BUFFER_SIZE 1024)
add_compile_definitions(MAX_BUFFER_SIZE=1024)

add_compile_definitions 影响当前目录下的所有目标,假如指向给库mathlib添加一个宏,不想给其他target添加宏,推荐使用target_compile_definitions。

target_compile_definitions语法如下:

bash 复制代码
target_compile_definitions(mathlib 
  PRIVATE   MY_LIB_INTERNAL=1  # 只有编译 mathlib 内部代码时可见
  PUBLIC    MY_LIB_API=1       # 编译 mathlib 和 链接 mathlib 的人都可见
  INTERFACE MY_LIB_USER=1      # 只有链接 mathlib 的人可见
)

测试:给main添加一个宏:

bash 复制代码
int main() 
{
#ifdef VERSION_STR
    MyMath math;
    cout << math.add(3, 4) << endl;
#endif
    cout << "hello world" << endl;
    return 0;
}

cmake文件如下:

bash 复制代码
cmake_minimum_required(VERSION 3.30)

project (main VERSION 1.0 LANGUAGES CXX)

set (CMAKE_CXX_STANDARD 23)

set (CMAKE_CXX_STANDARD_REQUIRED ON)

# 调用子目录
add_subdirectory(lib)

add_executable(main app/main.cpp)

target_link_libraries(main PRIVATE mathlib)

# 给main添加一个宏
target_compile_definitions(main PRIVATE VERSION_STR=1)   
相关推荐
番茄灭世神1 天前
使用VScode开发ARM核芯片通用配置
arm开发·vscode·mcu·cmake·clangd·llvm·ninja
charlee442 天前
CMake构建学习笔记31-构建前执行可执行程序
sqlite·cmake·构建·构建前脚本
Mr_WangAndy3 天前
cmake_file(GLOB)详解
cmake·cmake file·cmake文件操作
Tipriest_3 天前
CMake 常用预设命令说明
cmake
加成BUFF3 天前
Qt开发核心工具:CMake与qmake全面解析
开发语言·qt·cmake·qmake
青山是哪个青山4 天前
第二节:CMake 命令行工具与工程生命周期
c++·cmake
青山是哪个青山4 天前
第一节:CMake 简介
linux·c++·cmake
青山是哪个青山4 天前
第三节:CMake 工程实践场景笔记
c++·cmake
张世争6 天前
windows 使用 cmake 方式源码编译 SDL2
windows·cmake·sdl2