cmake

cmake是什么

cross platform make

跨平台的编译工具

c++编译有g++编译器,但是如果有100个文件需要编译呢,你是不是要写100个文件,100000个呢,cmake就是通过在CMakeList.txt中写编译程序,告诉cmake(编译器)怎么去编译这个项目,执行,执行cmake编译器,cmake会执行CMakeList.txt文件,生成makefile指令文件,执行make命令就会对makefile指定的编译内容进行编译;

cmake还可以生成静态库和动态库文件。

cmake--makefile----make

cmake

注意区分cmake和cmake语言;

cmake是构建系统生成器。

而linux上我们默认的构建系统是makefile.

所以,简单理解就是cmake是makefile生成器。

makefile

cmake生成器在makefile中生成编译指令。

linux上查看cmake是否安装

$ cmake --version

作用

我们希望开发出的程序能够在不同的系统环境中运行,比如在LINUX中开发出的的程序能够在Windows和Android系统中运行。这时就需要使用Cmake来进行版本控制。Cmake可以自动生成适合于目标平台的工程文件。

教程

教程链接2---点击头像搜索cmake教程

cmakelists.txt

脚本文件;

通过编写CMakeLists.txt,可以控制生成的Makefile,从而控制编译过程。

编译过程

编译CMakeList.txt脚本文件

cmake 编译cmakelist.txt文件

内部构件

编译的指令为:cmake CMakeLists.txt文件的目录路径。

camke cmakelist.txt文件路径,指定到CMkaeList.txt所在目录即可。

一般cmake .

到指定目录编译cmakelist.txt,编译出来的文件和目录就存在这个文件

外部构建

只需要到build(构建所在路径)下执行:

cmake [CMakeLists.txt路径]

即可。

make编译makefile

make编译makefile生产可执行文件

make后面需要加上makefile所在目录吗。

不需要,也不要加,make直接在makefile所在目录下执行就行。

make参数

make -jx

例如make -j4,就是让4个线程同时,一起编译这个项目。

可以单独编写CMakeLists.txt脚本,不需要增加cmake版本和项目名称,只需要写一些cmake命令,cmake编译即可,例如想要输出一些内容。

set(num 1)
if(NOT num EQUAL -1)
    message("not equal")
endif()

if(num EQUAL -1)
    message("equal")
endif()

cmake命令选项

链接2

-D:

1,指定CMakeLists.txt中已经存在的变量的值;

2,定义一个变量和变量的值,这个变量可以在CMakeLists.txt中使用。

其实第二个本质就是第一个作用,因为如果定义一个变量而不用,是没有意义的。

cmake中的变量不需要提前定义和复制,可以直接使用,然后在通过cmake构建时指定变量和值。

如果不指定变量和值,使用的时候变量的值为空。

option中的选项也是变量。

使用-D设置的变量在CMakeLists.txt中生效,可以设置cmake的内置支持的一些变量控制构建的行为;当然也可以使用自定义的变量,在CMakeLists.txt中自行判断做不同的处理。

 CMAKE_BUILD_TYPE

作用:编译方式的选择

Debug,Release----区别

-S:

就是要编译和构建的文件所在目录,即CMakeLists.txt文件所在目录。

-B:

构建出来的文件要放置的目录

-G:

选择生成器--generator--生成器

cmake --build makefile_dir

使用makefile编译项目。

cmake --target 构造目标

构造目标必须是CMakeLists.txt中指定的可执行文件目标,库,测试或者安装规则等。

也就是必须是add_executable(),add_library()等这些函数指定的对象。

如果target指定构建目标,那么就指挥构建指定的目标,不会构建其他可构建的目标,而不指定target,就会构建所有目标。

生成器

作用

cmake的时候使用指定或者默认的生成器生成构造系统;

比如linux默认生成器--Unix makefiles:

cmake .. 之后生成的文件:

指定生成器为Ninja:

cmake -G Ninja ..之后:

下载生成器

linux上cmake --help只是可以查看平台支持的生成器,使用生成器需要先下载。

linux下载ninja生成器:

sudo apt install ninja-build

编译器

cmake 在linux上在Unix Makefile生成器下默认的是使用C++编译器,其中可能默认是GNU;

配置c和c++交叉编译器文件路径

cmake -S $source_path -B cx_servo_release_build "-DCMAKE_BUILD_TYPE:STRING=Release" \
"-DCMAKE_C_COMPILER:FILEPATH=${arm_gcc_compiler_path_prefix}/arm-linux-gnueabihf-gcc" \
"-DCMAKE_CXX_COMPILER:FILEPATH=${arm_gcc_compiler_path_prefix}/arm-linux-gnueabihf-g++"

cmake --build cx_servo_release_build --target all -j4

cmake --build ----要编译的

和在linux使用make编译一样

为什么不直接使用make

项目构建编译的过程

--target---指定要编译的(makefile中有的)内容

cmake --target命令用于构建或者重新构建CMake项目时,只针对指定的目标进行编译。

在使用CMake编译项目时,通常会使用cmake命令生成编译系统所需的文件,并使用cmake --build命令才能实际进行编译。如果在使用cmake --build命令时,不指定要编译的目标,那么将会编译整个项目,并生成所有的目标。这在项目很大的情况下,编译时间可能会非常长。

使用cmake --target target_name命令,可以将编译过程限制在特定目标上,从而提高编译速度。这些目标可以是构建二进制文件、库文件、测试文件、安装文件等等。例如:

```
cmake --build build --target my_lib
```

以上命令会编译名为my_lib的库文件,而不编译其他目标。

CMakeLists.txt中申明的目标包括两种类型:可执行程序和库文件,您可以在target_name位置指定哪个目标需要进行构建。

需要注意的是,使用这个命令进行编译时,可能需要确保前序的依赖库已经被正确编译并安装,否则可能会出现编译错误。

install

链接

cmake -G"MinGW Makefiles" -B build -DCMAKE_INSTALL_PREFIX=./  -DWITH_SOME_OPTIONS=ON
cmake --build build --parallel 16
cmake --build build --target install

1,编译生成makefle:第一行命令通过-D指定项目编译之后下载到哪里;

2,编译整个项目;

3,编译项目,执行项目的下载。

cmake --build build --target install是用CMake编译项目后将项目安装到指定目录的命令。

这个命令将在build目录下使用CMake生成的Makefile或其他构建系统编译项目,并将项目中的文件复制到指定的安装目录中。这个命令需要使用CMakeLists.txt文件中定义的安装规则,来决定哪些文件需要安装和复制到指定目录中。

构建类型

debug

编译项目,保留调试信息,可以调试,不优化代码,提供给开发人员使用;

release

编译项目,不可以调试,所以不保留调试信息,优化代码以提供执行性能,提供给用户使用。

链接

cmake的字符串

需不需要加双引号

链接

cmake结构层次语句

if---elseif---else---endif

链接

cmake函数

project

project(项目名称 项目版本 支持的语言...)

project(
    hello
    VERSION 1.0.0
    LANGUAGES CXX C)

链接

注意:如果需要PROJECT_SOURCE_DIR这些变量的值,必须先调用这个函数,因为这些变量是这个函数调用之后生成的。

是的,`PROJECT_SOURCE_DIR` 是在 `project()` 函数中由 CMake 自动生成的。`project()` 函数在 CMakeLists.txt 中通常是第一个被调用的函数,用于定义项目名称、版本号、语言和可执行文件的输出路径等信息。

在 `project()` 函数中,CMake 会自动定义一些变量,包括:

- `PROJECT_NAME`:表示项目名称。
- `PROJECT_VERSION`:表示项目版本号。
- `PROJECT_DESCRIPTION`:表示项目描述信息。
- `PROJECT_SOURCE_DIR`:表示项目源代码根目录路径。
- `PROJECT_BINARY_DIR`:表示项目可执行文件输出路径。

其中,`PROJECT_SOURCE_DIR` 表示项目源代码根目录的路径,其默认值为 CMakeLists.txt 所在目录的路径。可以通过 `${PROJECT_SOURCE_DIR}` 变量来引用这个路径,在 CMake 中常用于指定源文件的路径和包含头文件的路径等。

需要注意的是,如果在 CMakeLists.txt 中重新定义了这些变量的值,则会覆盖 `project()` 函数中自动生成的值。因此,建议在使用这些变量时,尽量使用 `project()` 函数中自动生成的默认值,以确保项目能够按照默认的方式正确编译和构建。

string()

string(ASCLL 27 Esc)

以上是将ASCII码27转为对应的的字符(escape按键--Esc),然后赋值给变量Esc。

一般来说,在发送换码符之前,要先发送Escape键(十进制为27,八进制为\033),这样设备就会知道下一个到达的字符是换码符。

换码符的作用

换码符是用来执行一个命令或一项任务的字符,它们不会被打印到屏幕上。

不同的换码符拥有不同的作用。

例如输出颜色

颜色设置

cmake  set(color_off "${Esc}[m")


在 CMake 中,`${Esc}`是一个变量,其值是 ASCII 码值为 27 的 Escape 字符(即 ASCII 码中的 27,通常写作`\033`、`\x1B`、“\e”等)。这个 Escape 字符并不会被直接打印或显示,而是用于控制终端的显示行为,例如改变字符颜色、样式和位置等。

给定`${Esc}[m`的值,它表示将终端的文字属性重置为默认值。在这个 CMake 语句中,set函数的作用是定义一个名为`color_off`的变量,并将`${Esc}[m`字符串赋值给它。这个变量的作用是在 CMake 脚本中设置一个特定的字符串,当需要重置终端的文字属性时,可以使用这个字符串,用于还原输出的文本格式等。直接使用`${Esc}[m`字符串可能不太方便,而使用`color_off`变量则有一定的可读性和易用性。

此外,在 CMake 中可能还会定义其他类似的变量,例如`${Esc}[31m`表示设置终端的输出颜色为红色,`${Esc}[42m`表示设置终端的输出背景颜色为绿色,以此类推。这些变量的作用是为 CMake 程序员提供一些方便的辅助工具,用于控制终端的显示效果,更好地展示程序输出等。

ASCLL码表

官方文档

链接

set

链接

1,定义变量,并给变量赋值变量

变量都是string类型

2,指定不同的C++标准进行文件编译

通过变量指定使用的C++标准u

set(CMAKE_CXX_STANDARD 11)#编译使用的C++标准
set(CMAKE_CXX_EXTENSIONS OFF)#
set(CMAKE_CXX_STANDARD_REQUIRED ON)

前面的字符串是变量。

- `CXX_STANDARD`:用于指定 C++ 标准的版本号,如 11、14、17 等。该变量的默认值是空。如果定义了该变量,则 CMake 会自动使用 `target_compile_features` 函数配置编译器的标准特性。

- `CXX_EXTENSIONS`:用于启用或禁用 C++ 扩展特性。默认情况下,变量值为 ON,表示启用编译器的所有扩展特性。如果设置为 OFF,则表示禁用 C++ 标准中不属于核心语言功能的所有扩展,例如 GNU 扩展。如果没有启用扩展特性,则编译器将会更加符合标准,但可能会导致某些代码不再可编译。

- `CXX_STANDARD_REQUIRED`:用于指定是否需要编译器支持指定的 C++ 标准。默认情况下,该变量为 OFF,即不需要编译器支持指定的 C++ 标准。如果设置为 ON,则表示必须使用指定的标准进行编译(如果编译器不支持指定的标准,则会编译错误)。通常建议将该选项设置为 ON,以确保对 C++ 标准的使用得到正确的保障。

3,指定可执行程序输出路径的宏

 

指定的路径如果不存在会自动创建 

可执行文件指定的源文件必须包含所有需要的源文件,包括main文件。

编译的当前目录

不是CMkaeLists.txt所在目录,是指cmake执行所在目录。

为什么set指定系统变量取值没有用

 因为set中保存的是字符串,你给什么,set指定地方变量中就保存什么

option()

option(<variable> "<help_text>" [value])

定义bool类型的选项变量;

选项的描述;

选项变量的值(值只有ON或者OFF两种)。

在C/C++程序中可以判断option中的变量是否被定义,如果选项变量的值为ON(开启),那么变量就会被定义,那么C/C++中就可以判断成功。

链接

enable_testing()

`enable_testing()` 是 CMake 中一个函数,其作用是启用测试机制。通过调用这个函数,CMake 将自动为项目生成一个可执行文件 ctest,用于运行项目中的测试程序。

注意:测试程序不是enable_testing生成的,enable_testing只是使能,启动,也就是生成ctest用于运行测试程序。

使用 enable_testing() 命令可以启用测试。一定要在根目录下的CMakeLists.txt中开启,不然执行make test时会报错。

官方解释:

为当前目录及以下目录启用测试。----也就是只要在根目录下的CMakeLists.txt中启动enable_testing,就会执行整个项目所有的测试程序,如果没有这个,那么如果我们要执行整个项目的所有可执行程序,就需要我们一个一个的执行。所以,只要我们通过add_test把所有的可执行程序(ad_executable()生成的)增加到测试程序中,那么当某个条件满足时(一般是if(BUILD_TESTS)或者if(BUILD_TESTING))启动enable_testing(),那么整个项目的所有测试程序(与之关联的就是可执行程序)就运行起来了

启用此目录及以下目录的测试。

此命令应位于源目录根目录中 因为 ctest 希望在构建中查找测试文件 目录根目录。

当包含模块时,将自动调用此命令,除非该选项BUILD_TESTING是 关闭。

BUILD_TESTING

是的,`BUILD_TESTING` 是 CMake 内部的一个变量,用于控制项目是否编译测试程序。它的默认值为 ON,表示默认情况下编译测试程序。

在使用 `enable_testing()` 函数启用测试机制之后,`BUILD_TESTING` 变量的值也可以通过 `ctest` 命令的选项进行修改,例如:

```bash
$ ctest -D BUILD_TESTING=OFF
```

通过设置 `-D BUILD_TESTING=OFF` 选项,可以关闭测试程序的编译,也就是不再编译测试用例。这在一些场景下很有用,例如在 release 版本中不需要测试程序的时候。

ctest怎么知道,测试用例是哪个文件呢

在调用 `enable_testing()` 函数之后,可以使用 `add_test()` 函数和 `add_custom_command()` 函数来添加自定义的测试用例。`add_test()` 函数用于将测试用例添加到测试系统中,需要指定测试用例的名称以及命令行命令。`add_custom_command()` 函数用于创建自定义命令,可以在测试系统执行测试用例之前或之后自动调用指定的脚本或程序。

make test参数

链接

使用 `make test` 命令可以自动完成以下几个步骤:

1. 构建测试套件所需的所有依赖库和工具。
2. 编译测试用例。
3. 运行测试用例。
4. 输出测试结果和错误信息。

ctest命令

链接

add_test()

链接

利用可执行文件生成测试程序。

注意:NAME,COMMAND这些指令一定要写,不能省略。

0% tests passed, 1 tests failed out of 

原因:

根据提供的代码,错误出现的可能性有以下几种:

1. `test.c` 文件中存在编译错误,导致 `mytest` 可执行程序无法成功编译。

2. `mytest` 可执行程序没有执行权限,导致在运行 `ctest` 命令时无法执行测试程序。可以尝试使用 `chmod +x mytest` 命令添加可执行权限。

3. `ctest` 命令无法找到测试用例的可执行程序 `mytest`,可能是 `mytest` 可执行程序没有生成或者没有在输出目录中。可以使用 `set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)` 将可执行程序的输出路径设置为 `${PROJECT_BINARY_DIR}/bin`,并重新运行 CMake 和编译项目。若 `mytest` 可执行程序已经生成,但是 `ctest` 命令还是找不到,可以尝试使用 `--build-and-test` 选项运行 `cmake` 命令,例如 `cmake --build ./build --target test --build-and-test`,这样会自动启动构建和测试过程。

测试用例从生成到测试的过程

1,add_executable()--生成可执行程序。

2,add_test()--利用可执行程序生成测试用例。

3,enable_testing()启动测试用例。

4,cmake构建,make编译,make test进行测试。

 add_custom_command()

链接

set_property()

execute_process()

链接

`execute_process()` 是一个函数,用于在 CMake 构建过程中调用外部程序或执行命令行。它可以接受多个参数,包括要执行的命令、参数、工作目录、环境变量等。

例如,以下命令将运行 `ls` 命令并列出当前目录中的所有文件:
execute_process(COMMAND ls)

如果想传递参数,可以在 `execute_process()` 中使用 `ARGS` 参数将它们作为列表传递:
execute_process(COMMAND "echo" "Hello, World!")

有时在执行命令时需要知道当前使用的工作目录,为此,`execute_process()` 提供了 `WORKING_DIRECTORY` 参数:
execute_process(COMMAND "make" "install"

WORKING_DIRECTORY ${CMAKE_BINARY_DIR})

WORKING_DIRECTORY指定在哪个目录下执行这个命令。

此外,可以使用 `OUTPUT_VARIABLE`、`ERROR_VARIABLE` 和 `RESULT_VARIABLE` 参数获取命令的输出、错误输出和返回值。
execute_process(COMMAND "ls" "-l"

OUTPUT_VARIABLE LS_OUT

ERROR_VARIABLE   LS_ERR)
if(LS_ERR)
  message(FATAL_ERROR "ls command failed: ${LS_ERR}")
endif()
message(STATUS "ls command output: ${LS_OUT}")

find_program(git_fp NAMES git REQUIRED)
execute_process(
  COMMAND bash -c "${git_fp} rev-parse --show-toplevel"
  OUTPUT_VARIABLE git_root_dir
  OUTPUT_STRIP_TRAILING_WHITESPACE)

bash -c:
`bash -c` 是一个 Bash 命令,用于以字符串形式执行命令。它将字符串解释为一个命令,并在新的 Bash shell 中执行该命令。语法格式为:

bash -c "command"

其中 `command` 表示要执行的命令,可以是一个简单的命令,也可以是一串由命令与运算符组成的复杂命令。例如:

bash -c "echo Hello, World!"

在这个例子中,`echo Hello, World!` 是要执行的命令。该命令将在新的 Bash shell 中执行,并打印输出 `Hello, World!`。

在 CMake 文件中,`bash -c` 命令通常用于将一些字符串解释为 shell 命令,并在 CMake 中执行。例如,在命令 `execute_process()` 中使用 `bash -c` 可以使 CMake 脚本能够执行类似 shell 脚本的命令。例如,在以下命令中:
execute_process(COMMAND bash -c "ls -l")

`bash -c` 命令将 `ls -l` 解释为一个 shell 命令,并在 CMake 中执行,输出结果类似于在终端中执行 `ls -l` 命令时看到的结果。

`OUTPUT_STRIP_TRAILING_WHITESPACE` 参数用于删除输出的尾随空格。

执行以上命令,并不是在整个系统中.git仓库,而是要在这个项目中寻找.git,所以如果项目中没有.git,就会报错:fatal: not a git repository (or any of the parent directories): .git

解决办法就是在项目需要使用git的目录执行git init。

core_helper_target()

`core_helper_target()` 是一个在 CMake 中自定义的函数,可用于创建一个 CMake 自定义目标,并执行指定的命令或脚本文件。

该函数的定义可能包含以下参数:

- `name`: 新建目标的名称,这个目标不是用来存储命令执行的结果的,而是和命令建立绑定关系,其他对方需要使用这个目标(命令)时,可以直接关联这个目标的名称name;
- `command`: 目标要执行的命令或可执行文件的名称;
- `args`: 要传递给这个命令或可执行文件的参数或脚本的名称或路径;
- `working_dir (可选)`: 目标运行时的工作目录;
- `description (可选)`: 目标的描述信息;
- `is_script (可选)`: 是否为脚本文件类型

搜索源文件

1,aux_source_directory

2,file 

file详情链接

需要指定文件后缀

GLOB:只搜索当前目录

GLOB_RECURSE:搜索当前目录和其子目录(递归搜索)

3,target_source()

`target_sources()` 函数用于向指定的 target (可以是可执行文件或者生成的库文件)添加源代码文件。

所以对于add_library生成库时没有指定源文件时,可以用这个函数为库文件添加源文件。

它的语法如下:
target_sources(target_name
    PUBLIC|PRIVATE|INTERFACE
    [items1...]
    [items2...]
    ...)

其中,`target_name` 是需要添加源代码文件的目标名称,`PUBLIC|PRIVATE|INTERFACE` 对应不同的访问级别,`items` 是需要添加的源代码文件列表,可以是绝对路径或者相对路径。

`target_sources()` 可以多次调用来添加多个源文件的列表。它不会影响编译的顺序,也不会改变源文件的编译方式或选项等属性。它只是将源文件添加到被调用函数的 target 中。

举个例子,如果要为名称为 `foo` 的可执行文件添加两个源文件 `main.cpp` 和 `bar.cpp`,代码如下:
add_executable(foo)
target_sources(foo PRIVATE main.cpp bar.cpp)

在这个例子中,`target_sources()` 被用于将两个源代码文件添加到 `foo` 可执行文件的依赖列表中。这意味着在 `foo` 可执行文件被编译时,它依赖的源代码文件将被编译为目标文件并与可执行文件链接。

权限

1. `PUBLIC`:表示当前目标的依赖项和链接库可以使用该源文件。这意味着,除了主程序外,还有其他程序可能会使用这些源文件。

2. `PRIVATE`:表示只有当前目标自身可以使用该源文件。这意味着,其他程序无法使用这些源文件,即使它们与该目标相关。

3. `INTERFACE`:表示当前目标自身不使用该源文件,但其使用者(即链接该库的其他库或对象)使用该源文件。这意味着,这些源文件仅作为接口可用,可以视为当前目标依赖项的一部分。

搜索路径的类型

1,CMakeList.txt当前路径

2,project_source_dir

PROJECT_SOURCE_DIR是CMake内置变量之一,它代表当前项目根目录的路径。当使用project命令指定项目名称时,CMake会自动设置PROJECT_SOURCE_DIR的默认值为项目根目录的路径(CMakeLists.txt所在的路径)。如果你使用的是子目录CMakeLists.txt,那么PROJECT_SOURCE_DIR将会是子目录的路径。

CMakeList.txt就是写camke的文件。

 搜索文件的格式指定:

在指定的目录后加上:/文件格式即可

指定头文件路径

1,include_directories()

什么时候需要include_directories

头文件不在当前目录

include_direvtories指定的路径问题

include_directories指定的路径只需要指定到文件引用头文件开始的路径即可,不要超过文件中引用的开始路径。

比如spdlog,spdlog中的头文件的开始路径就是spdlog目录,如果你指定到spdlog目录,那编译器就会去spdlog目录下再找spdlog目录,就会xxxx.h file not found.

目录结构:

spdlog头文件路径:

错误指定:

 正确指定:

2,file

file可以通过指定后缀搜索各种文件

file---list实现删除不需要的文件

file(GLOB_RECURSE H_CPP_FILE
    RELATIVE ${PROJECT_SOURCE_DIR}
    "*.h"
    "*.cpp"
    "*.ui"
)
file(GLOB_RECURSE del_file
     RELATIVE ${CMAKE_SOURCE_DIR}
     "include/*"
)

foreach(d_file ${del_file})
    list(REMOVE_ITEM H_CPP_FILE ${d_file})
endforeach()

3,target_inlude_directories

指定目标包含的头文件路径。

<目标>必须是由add_executable()或add_library()之类的命令创建的。

注意:

1,《目标》不能是project创建的项目名称。

2,cmake是按照顺序执行的,所以target_include_directories必须放在add_xxx()之后;

权限:

1. `PUBLIC`:表示头文件路径将同时被添加到当前目标和依赖它的其他目标的头文件搜索路径中。即,这些头文件路径既可以被当前目标自己使用,也可以被依赖它的其他目标使用。

2. `PRIVATE`:表示头文件路径将仅被添加到当前目标的头文件搜索路径中,而不被依赖它的其他目标使用。即,这些头文件路径仅供当前目标使用。

3. `INTERFACE`:表示头文件路径也会同时被添加到依赖当前目标的其他目标的头文件搜索路径中,但不会被当前目标自身所使用。即,这些头文件路径不会影响当前目标,但会影响依赖它的其他目标。

链接

指定不同时期的搜索路径

在设置搜索路径时,可以使用 `$<BUILD_INTERFACE:...>` 和 `$<INSTALL_INTERFACE:...>` 表示不同的搜索路径,解释如下:

- `$<BUILD_INTERFACE:...>` 表示在构建项目时的搜索路径,`...` 表示该路径。
- `$<INSTALL_INTERFACE:...>` 表示在项目安装的搜索路径,`...` 表示该路径。

链接

include_directories和target_include_directories的区别

1,include_加载的头文件对所有的项目没有权限限制。

target_include_有权限限制。

2,include_是全局有效,也就是在一个项目的CMakeLists.txt中使用include_directories添加头文件路径之后,这个项目下的子项目也会被设置这个头文件加载路径,而不需要再在子项目的CMakeLists.txt中再include_directories相同头文件路径。但是注意,也是因为这种情况,需要慎用,否则子项目可能出现头文件加载不到的问题。

target_include_directories 只会为指定目标包含头文件搜索路径。如果想为不同目标设置各自的搜索路径,那么用target_include_directories更合适。

加载cmake文件模块或者文件---include()

.cmake文件

链接

注意,为了使CMakeLists.txt能够找到该文件,需要指定文件完整路径(绝对路径或相对路径),当然如果指定了CMAKE_MODULE_PATH,就可以直接include该目录下的.cmake文件了。

include(test.cmake)表示在当前目录下。

install()

安装文件或者目录(包括库文件)

《本质上就是将指定的文件或者目录复制到指定的目录下》

链接

链接

利用GUNInstallDirs目录变量指定安装目录

链接

可以看模块模块部分的GNUInstallDirs

install的具体使用过程--make insatll

1,install之前,逆必须使用add_library或者add_exectuable生成库文件或者可执行文件,否则:

cmake_minimum_required(VERSION 3.9.0)
project(pro_install)

file(GLOB_RECURSE src
     ${CMAKE_SOURCE_DIR}/*.cpp)

set(LIBRARY_OUTPUT_PATH .)
#add_library(test SHARED ${src})

include(GNUInstallDirs)
message(STATUS "CMAKE_INSTALL_LIBDIR=${CMAKE_INSTALL_LIBDIR}")
install(TARGETS test
       LIBRARY DESTINATION {CMAKE_INSTALL_LIBDIR}
       )
install(FILES test.cpp DESTINATION ../dir)

2,cmake ..构建----make编译之后

完成make编译之后install并没有安装,需要再执行make install之后,需要安装的文件才会执行安装。

看模块GNUInstallDirs部分

模块

GNUInstallDirs( GNUInstallDirs.cmake)---GNU安装目录

GNUInstallDirs 是一个 CMake 模块,它定义了一组由“GNU 编码标准”定义的,跨平台的标准安装目录变量,可在 CMakeLists.txt 文件中使用。这些目录名称涵盖了程序中用到的各种文件类型和安装位置。通过使用 GNUInstallDirs 模块,可以让编译脚本更加可移植。

GNUInstallDirs 定义了许多有用的 CMake 变量,如:

- `CMAKE_INSTALL_PREFIX`:安装前缀(默认值为 `/usr/local`)。
- `CMAKE_INSTALL_LIBDIR`:库目录名称(默认值为 `lib`)。
- `CMAKE_INSTALL_INCLUDEDIR`:头文件目录名称(默认值为 `include`)。
- `CMAKE_INSTALL_DATADIR`:SHARE目录名称(默认值为 `share`)。
- `CMAKE_INSTALL_SYSCONFDIR`:系统配置文件目录名称(默认值为 `/etc`)。
- `CMAKE_INSTALL_BINDIR`:可执行文件目录名称(默认值为 `bin`)。

派生变量 `CMAKE_INSTALL_FULL_XXX` 会将目录名称连接到安装前缀和根目录。例如,`CMAKE_INSTALL_FULL_INCLUDEDIR` 将返回实际的头文件目录(例如 `/usr/local/include`)。

GNUInstallDirs 还包括适用于 Windows 和 macOS 的特殊目录(例如 `CMAKE_INSTALL_APPBUNDLEDIRECTORY` 和 `

GNUInstallDirs中的安装目录默认都是在变量CMAKE_INSTALL_PREFIX中设置的前缀路径下找到其他变量的路径,比如:

CMAKE_INSTALL_LIBDIR的值是lib,那么CMAKE_INSTALL_LIBDIR变量的绝对路径就是:

CMAKE_INSTALL_PREFIX+lib

CMAKE_INSTALL_PREFIX默认值是/usr/local,所以CMAKE_INSTALL_LIBDIR的默认路径就是:

/usr/local/lib

而要在这些系统目录下安装install文件,需要install中设置权限,否则:

设置安装目录前缀--CMAKE_INSTALL_PREFIX

所有其他目录路径的前缀,其他目录都需要加上这个前缀目录,这个是哟个绝对路径,其他百年来的路径只是相对于这个路径下的相对路径。

cmake_minimum_required(VERSION 3.9.0)
project(pro_install)

file(GLOB_RECURSE src
     ${CMAKE_SOURCE_DIR}/*.cpp)

set(LIBRARY_OUTPUT_PATH .)
add_library(test SHARED ${src})

include(GNUInstallDirs)
set(CMAKE_INSTALL_PREFIX ${CMAKE_SOURCE_DIR}/install)
message(STATUS "CMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}")
message(STATUS "CMAKE_INSTALL_LIBDIR=${CMAKE_INSTALL_LIBDIR}")

install(TARGETS test
       LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
       )
install(FILES test.cpp DESTINATION ${CMAKE_SOURCE_DIR}/dir)

什么是安装目录

安装目录是指将软件安装到计算机文件系统中的特定文件夹或目录。安装目录包括可执行文件所在的文件夹、库文件所在的文件夹以及其他必要的文件和目录,例如配置文件、帮助文档、示例文件等。

安装目录通常是在软件发布时和使用文件管理工具或安装程序进行设置的。具体来说,当用户安装软件时,安装程序会将该软件的文件和组件安装到特定的安装路径中。

《就是某些特定的文件需要放入的目录》

安装目录的变量用来干什么

我们可以给GNUInstallDirs中的变量赋值,也就是给这些已经定义好的变量指定我们需要指定的安装目录的路径:

#使用GNUInstallDirs中的变量之前,必须先加载这个模块。
#加载模块
include(GNUInstallDirs)
#使用目录变量---给目录变量指定路径
#这里指定安装目录的前缀
set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/install)

cmake制作动态库和静态库

linux动态库--so

windows动态库--dll 

linux静态库--a

windows静态库--lib

add_library(库名 STATIC|SHARED 源文件......)

动态库有可执行权限

静态库没有可执行权限

链接

add_library(库名,STATIC|SHARED)

没有利用的源文件,表示只需要建立这个库文件。

没有指定库的类型默认生成静态库。

库的使用

需要库和头文件

要形成良好的编程习惯,静态库和动态库不要放在一个目录下,否则如果静态库和动态库同名,引用库会出现问题。

指定库的生产路径

因为动态库具有可执行权限,动态库可以用两个系统变量指定生成的路径:

EXECUTABLE_OUTPUT_PATH,LIBRARY_OUT_PATH;

静态库只能用后面一个。

静态库的生成

库的生成至少需要指定两个东西:

1,头文件路径(因为源文件中包含头文件了);

2,源文件;

如果不指定生成的类型,默认生成静态库。

 动态库的生成

和静态库一样,只需要改变生成的类型关键字就行。

怎么使用库文件

源文件是文本格式,库文件是二进制格式。

使用静态库

link_librairys()

一个类型的参数,可以有多个参数

库文件中含有源文件定义的内容,生成可执行文件我们需要指定的有两个文件:

1,头文件路径(如果在当前目录不需要指定);

2,库文件(及其路径);

系统提供的库只需要提供库名;

自定义的库还需要指定路径;

指定库的路径

link_directories()

注意:这个函数只是用来指定静态库和动态库路径的,不指定库。

多个库就指定多个路径。

使用动态库

target_link_librairies()

两个类型的参数

 动态库加载的位置

动态库的链接应该写生成可执行文件之后,因为只有可执行程序调用动态库,动态库才会被加载到内存,而不是想静态库一样生成可执行程序的过程就需要加载静态库一起打包。

 target_link_library多次加载动态库需统一链接权限风格问

链接

动态库的访问权限

默认情况下,库的链接是具有传递性的。

 权限说明

public 默认;

private 会断层,只能单层继承;

interface 跨越库使用

使用静态库和动态库的区别

静态库文件会放入可执行程序文件,执行前链接静态库文件;

动态库不会 ,执行时需要才去加载和链接动态库;

库的建立到使用

建立---链接

什么东西需要生成库文件

源文件

生成库文件之后怎么用

头文件,库文件。

一些常用的库

pthread

rt

和共享内存有关的文件需要这个库

#include <sys/mman.h>

shm_open()

openGL库

find_package(OpenGL REQUIRED)
target_link_libraries(Model PRIVATE ${OPENGL_LIBRARIES})

在 C++ 中,rt 库是一个非标准库,它是 Realtime Application Programming Interface(实时应用程序编程接口)的缩写,主要提供了一些针对实时应用程序的系统调用和函数。

具体来说,rt 库提供了许多有关实时处理的函数和调用,例如:

- 控制线程优先级,如 `pthread_attr_init`、`pthread_attr_setschedpolicy` 等;
- 控制定时器和时间,如 `clock_gettime`、`timer_create` 等;
- 提供信号处理机制,如 `sigwait`、`sigaddset` 等;
- 实现共享内存和信号量等 IPC 机制,如 `shm_open`、`sem_open` 等。

在使用 rt 库时,需要链接对应的库文件,如 `librt.so` 或 `librt.a`。在Linux系统中,通常需要在编译时指定链接rt库,例如:

```
g++ my_program.cpp -lrt -o my_program
```

需要注意的是,rt 库是一个非标准库,只有在某些需要进行实时处理的应用程序中才会使用到。对于一般的应用程序,一般无需使用此库。

怎么添加可以构建的子目录

add_subdirectory

添加一个子目录并构建该子目录

链接

注意:添加的是子项目所在的目录,不是子项目的project项目名称。

add_dependencies(target depend1 depend2 ...)

用处在于,当一个项目构建的时候,由于依赖关系的存在,所以被依赖的项目总是最先构建,这样就不会出现找不到库而报错。

target---要生成的库或者可执行文件

depend---要生成的库或者可执行文件要链接的库

链接1

链接2

find_package

链接

参数

查找需要的库或者包;

只是查找并获取包和库所在路径还是加载这个包或者库

找到包或者库所在的路径,并加载包或者库中的cmake模块,其中有包或者库的路径变量,我们可以引用这些变量引用这些库或者包。

find_package需不需要指定查找路径

find_package只会在cmake定义的两个变量指定的路径下查找,所以,如果不在两个变量指定的路径下,就需要给这两个变量之一加上指定路径。

链接

find_package需不需要定义变量来获取查找到的路径

不需要,只需要指定包的名称和其他参数。

找到包之后,怎么引用包

find_package会找到指定包中的cmake模块,然后我们可以引用模块中的变量,一般有三个变量:

包名_DIR,包名_INCLUDE_DIRS,包名_LIBS。

find_package会到哪个变量指定的路径中寻找

链接

find_program

链接

作用:

`find_program` 是 CMake 中的一个命令,用于查找指定名称的程序路径它的基本语法如下:
find_program(VAR_NAME program_name [path1 path2 ...])

该命令将查找名称为 `program_name` 的程序,并将其路径存储在名为 `VAR_NAME` 的变量中。它还可以在可选参数 `path1 path2 ...` 中指定要搜索的路径。

例如,以下命令将使用 `find_program` 查找名为 `ccache` 的程序,并将其路径存储在 `FOUND_CCACHE` 变量中:
find_program(FOUND_CCACHE ccache)

这将在搜索系统路径中查找 `ccache` 程序,并将其路径存储在 `FOUND_CCACHE` 变量中。如果找到该程序则返回路径,否则返回空字符串或 macOS 和 Linux 平台上的 NULL 。

如果找到程序,则结果将存储在<VAR>中,除非清除<VAR>,否则不会重复搜索。如果没找到,结果将为<VAR>-NOTFOUND

find_program(git_fp NAMES git REQUIRED)

`find_program()` 函数是一个 CMake 内置函数,用于在系统中查找一个可执行文件并返回其路径。在这个例子中,函数会查找名为 `git` 的程序,并将其路径存储在变量 `git_fp` 中。如果未找到该程序,它将生成一个致命错误并停止 CMake 构建过程。

函数的语法格式为:

```
find_program(variable program [path1 path2 ...])
```

其中 `variable` 表示要定义的变量名,`program` 表示要查找的程序名称,`path1`、`path2` 等表示要在其中查找程序的路径。如果指定了路径,则查找程序时只会在这些路径中查找;如果未指定路径,则会在系统标准路径中查找。

在这个例子中,`NAMES git` 参数指定要查找的程序名称为 `git`,`REQUIRED` 参数表示必须找到该程序,否则将生成一个致命错误并停止 CMake 构建过程。

find_program查找的是程序所在目录还是包含程序本身

找到的路径已知到包含程序文件名本身。

cmake_minimum_required(VERSION 3.9.0)
project(pro_find_program)

find_program(git_path NAMES git REQUIRED)
message(STATUS "git_path=${git_path}")

正是因为包含了程序本身,所以我们才可以用exectute_process去执行程序。

massage

message打印变量值

 massage中打印变量需要像shell一样${}取变量值

message中的输出在哪个阶段输出

cmake 编译阶段

cmake---git---版本的生成

set(GIT_HASH "unknown")
get_git_hash(GIT_HASH)
message(STATUS "Git hash is ${GIT_HASH}")
message(STATUS "Git hash date is ${GIT_HASH_date}")
configure_file(
    "${CMAKE_SOURCE_DIR}/config.h.in"
    "${CMAKE_SOURCE_DIR}/config.h")

自定义模块的添加

# 添加自定义cmake文件目录(自定义的模块),添加模块路径进入cmake系统模块变量列表中
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)

#include模块有两种方式
#1,使用名称为model1.cmake的模块
include(model1.cmake)

#2,不需要后缀
include(model1)

MACRO宏和function函数

宏----宏内部不会对变量取值,必须使用${}符号取值,字符串替换

函数----自动取值,值修改

MACRO()和function()用于定义宏和函数。而宏和函数也都需要调用。

直接传递变量名和变量取值作为宏和函数参数的区别

传过去的是什么,参数就获取什么值;

传递变量名---参数的值就是变量名;

取变量值传递---参数的值就是变量的取值。

execute_process---执行子进程

链接

# get git hash
macro(get_git_hash _git_hash)   # 宏的开始
    find_package(Git QUIET)     # 查找Git,QUIET静默方式不报错
    if(GIT_FOUND)
      //这个进程用于获取commit_id前7位
      execute_process(          # 执行一个子进程
        //子进程中执行git----查看当前分支上最后一次commit的commit_id的前七位
        //${GIT_EXECUTABLE}就是执行git,就像在终端行执行的git
        COMMAND ${GIT_EXECUTABLE} log -1 --pretty=format:%h # 命令
        OUTPUT_VARIABLE ${_git_hash}        # 将以上输出的commit_id前7个hash值存入变量 
                                            #_git_hash指定的变量中
        OUTPUT_STRIP_TRAILING_WHITESPACE    # 删除字符串尾的空白符
        ERROR_QUIET                         # 对执行错误静默
        WORKING_DIRECTORY                   # 在该目录下执行COMMAND命令
          ${CMAKE_CURRENT_SOURCE_DIR}
        )
      //这个进程用于获取指定hash值的时间戳
      execute_process(COMMAND ${GIT_EXECUTABLE} show -s --format=%ci ${${_git_hash}}
           WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
           OUTPUT_VARIABLE _show_output
           OUTPUT_STRIP_TRAILING_WHITESPACE)
        string(REGEX REPLACE "^([0-9][0-9][0-9][0-9]\\-[0-9][0-9]\\-[0-9][0-9]).*"
          "\\1" ${_git_hash}_date ${_show_output})
        //使用;替换空格
        string(REPLACE " " ";" ${_git_hash}_date ${${_git_hash}_date})
        //获取第一个字符串
        list(GET ${_git_hash}_date 0 ${_git_hash}_date)
    endif()
endmacro()                      # 宏的结束

# get git branch
macro(get_git_branch _git_branch)   # 宏的开始
    find_package(Git QUIET)     # 查找Git,QUIET静默方式不报错
    if(GIT_FOUND)
      execute_process(          # 执行一个子进程
        //获取当前 git 仓库所在的分支名称
        COMMAND ${GIT_EXECUTABLE} symbolic-ref --short -q HEAD
        OUTPUT_VARIABLE ${_git_branch}      # 将yishang执行git得到的当前分支名存入 
                                            #_git_branch保存的变量
        OUTPUT_STRIP_TRAILING_WHITESPACE    # 删除字符串尾的换行符
        ERROR_QUIET                         # 对执行错误静默
        WORKING_DIRECTORY                   # 在该目录下执行COMMAND命令
          ${CMAKE_CURRENT_SOURCE_DIR}
        )
    endif()
endmacro()          

configure_file

基本教程

详细教程---版本的生成

cmake中的include指令(.cmake文件/MACRO宏/function函数

configure_file的原理

configure_file会使用CMakeLists.txt中和模板文件.h.in中同名的变量的值替换模板文件中变量所在位置,生成的.h文件。

输出的.h文件需不需要提前创建好

不需要,configure_file会自动创建

版本生成的步骤

1,定义模板文件.h.in文件;

2,编写cmake模块文件--用于获取模板需要的信息;

3,configure_file配置文件即可。

cmake变量值比较

字符串比较

是否相等----STREQUAL

macro(Moo arg)
  if (arg STREQUAL "ABC")
    message("arg1 = ${arg}")
  endif()
  if (${arg} STREQUAL "ABC")
    message("arg2 = ${arg}")
  endif()
endmacro()
message("=== Call macro ===")
Moo(${var})

function(Foo arg)
  if (arg STREQUAL "ABC")
    message("arg1 = ${arg}")
  endif()
  if (${arg} STREQUAL "ABC")
    message("arg2 = ${arg}")
  endif()
endfunction()
message("=== Call function ===")
Foo(${var})

整数比较

set(num 1)
if(NOT num EQUAL -1)
    message("not equal")
endif()

if(num EQUAL -1)
    message("equal")
endif()

 字符串操作

string

set进行字符串拼接

set中字符串的存储形式

每一个存储的字符串都用分号“;”分开;

但是打印的时候是不会打印分号的;

file搜索出来的文件字符串如果指定绝对路径,那么保存的就是绝对路径

list

list--链接

list关键字的作用

list追加字符串--APPEND

set(str1 "aaaaaaaa")
message(STATUS "str1=${str1}")
list(APPEND str1 "bbbb")
message(STATUS "str1=${str1}")

list字符串拼接并不是直接拼接,而是以纷纷好分隔。

所以可以运用于CMAKE_PREFIX_PATH变量的多路径设置。

LIST移除字符串---REMOVE_ITEM

list获取字符串长度---LENGTH

注意:list中存储的是列表的元素,不是一个字符串。

add_executable()

链接

第一个参数是,cmake编译出来的可执行文件的名称,后面的参数是需要的源文件(.cpp)。

function

用于定义一个cmake函数。

以function(<name> ...)开始,endfunction(<name>)结束。

function(<name> [<arg1> ...])
  <commands>
endfunction([<name>])

[]表示可以省略。

链接

cmake_parse_arguments()

解析函数和宏的参数。

cmake_parse_arguments(<prefix> <options> <one_value_keywords>
                      <multi_value_keywords> <args>...)
  • <prefix>前缀:解析出的参数都会按照prefix_参数名的形式形成新的变量。这些变量将保存参数列表中的相应值,如果找不到相关选项,则这些变量将是未定义的。
  • <options>可选值:参数选项,也就是调用函数的时候是否存在这个参数,无论参数是否在参数列表中,它们都将被定义为TRUE或FALSE(参数存在为true)。
  • <one_value_keywords>: 单值参数列表。
  • <multi_value_keywords>: 多值参数列表。
  • <args>...参数: 一般传入${ARGN}即可。

链接1

链接2

CMAKE_CXX_FLAGS---指定编译选项

链接

这个变量是用来设置编译选项的,也就是编译的时候需要用到的选项;

比如使用g++编译增加编译选项:

g++ main.cpp -o main -l pthread

因为是用cmake,所以使用命令加入编译选项;

链接

链接

c++/c的编译选项

链接1

链接2

-pthread和-lpthread

编译选项中指定 -pthread 会附加一个宏定义 -D_REENTRANT ,该宏会导致 libc 头文件选择那些thread-safe的实现。

-ldl

-wl

"g++ -Wl"是将选项传递给链接器(linker)的命令。通过这个命令,可以将链接器的各种选项传递给g++编译器。

在编译C++程序时,g++编译器默认会调用链接器来将各个目标文件链接成一个可执行文件。通过"-Wl"选项,可以将链接器的选项传递给g++编译器,然后再传递给链接器。

例如,将"-L"选项传递给链接器,可以告诉链接器将库文件搜索路径添加到链接列表中,如下所示:

```bash
g++ test.cpp -L/usr/lib -lmylib -Wl,-rpath=/usr/lib
```

上面的命令中,"-L/usr/lib"选项告诉链接器搜索/usr/lib目录下的库文件,"-lmylib"选项告诉链接器链接名为libmylib.so或libmylib.a的库文件。"-Wl,-rpath=/usr/lib"选项告诉链接器将/usr/lib目录添加到运行时库搜索路径中,这样程序在运行时才能找到所需的库文件。

另外,还有一些其他的链接器选项也可以使用"-Wl"来传递给链接器,比如"-static"选项告诉链接器生成静态可执行文件;"-shared"选项告诉链接器生成共享库等。

总之,通过"g++ -Wl"命令可以将链接器的选项传递给g++编译器,从而对最终的可执行文件进行控制和配置。

-Wl,--as-needed 和 -Wl,--no-as-needed

引用检查

逗号不是分隔符,而是-wl的一部分

通过指定 -Wl,--as-needed 选项,链接过程中,链接器会检查所有的依赖库,没有实际被引用的库,不再写入可执行文件头。

-march

"g++ -march"是一个编译器选项,用于指定编译生成的二进制文件的指令集架构(Instruction Set Architecture,简称ISA)。它告诉编译器使用特定的CPU指令和指令集扩展来生成代码,以便能够更好地利用该CPU的性能优势。

例如,"-march=native"选项告诉g++编译器使用本地CPU的指令集和扩展来生成代码,从而获得最佳性能。如果使用"-march=native"选项,则必须在所有使用生成的二进制文件的计算机上使用具有相同指令集架构的CPU。

另一个常见的选项是"-march=x86-64",表示生成64位x86架构的代码,可以在x86-64体系结构的计算机上运行。

除了"-march"选项,还有一些其他的CPU优化选项可以用来控制编译器的优化行为,例如"-O2"选项启用级别2的优化,"-mavx2"选项启用AVX2指令集。

需要注意的是,使用特定的CPU优化选项可能会使得编译生成的二进制文件无法在其他CPU架构的计算机上运行。如果需要编写跨平台的程序,最好不要使用这些优化选项,或者使用默认的优化选项。

使用arm架构

-march=armv7-a

cmake指定使用gdb -g选项编译

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g")

cmake全局变量

什么是cmake全局变量

就是cmake本身定义好的缓存,环境和内置变量,不是用户自定义的,可以在所有的自定义CMakeLists.txt中使用。

ANDROID

QT_VERSION_MAJOR

获取当前Qt版本

CMAKE_CXX_STANDARD

CMAKE_CXX_STANDARD 是指定所使用的 C++ 标准版本。

链接

CMAKE_CXX_STANDARED_REQUIRED

CMAKE_CXX_STANDARD_REQUIRED 表示使用 C++ 标准时,是否必须使用指定的版本。如果将其设置为 ON,则只有在可以使用所指定的 C++ 标准时,才会构建项目。如果将其设置为 OFF,则可以尝试使用较旧的 C++ 标准构建项目。

`CMAKE_CXX_STANDARD_REQUIRED` 是一个布尔值变量,用于指定是否强制使用 `CMAKE_CXX_STANDARD` 中设置的 C++ 版本。如果设置为 `ON`,那么 CMake 会要求编译器必须支持 `CMAKE_CXX_STANDARD` 中设置的 C++ 版本,否则会配置失败。如果设置为 `OFF` 或者未设置,那么如果编译器不支持 `CMAKE_CXX_STANDARD` 中设置的 C++ 版本,CMake 会回退到编译器支持的最新版本---链接

CMAKE_CXX_EXTENSIONS

cmake_cxx_extensions是CMake中的一个变量,用于设置cmake构建时是否支持C++源文件的其他扩展名(即文件后缀名)。在大多数情况下,默认情况下CMake会使用.cpp作为C++源文件的后缀名。

通过设置cmake_cxx_extensions变量,CMake可以识别其他的C++源文件扩展名。这对于具有非标准文件扩展名的C++项目来说非常有用,例如使用.C,.cc或.hpp等扩展名作为C++源文件的项目。

`set(CMAKE_CXX_EXTENSIONS OFF)`指示CMake不使用C++源文件的非标准扩展名。默认情况下,CMake会使用标准的.CPP作为C++源文件的默认扩展名,但是有些开发人员喜欢使用其他的扩展名,例如.cc或.C为其C++源代码文件。如果你设置了`set(CMAKE_CXX_EXTENSIONS ON)`,CMake将会识别这些非标准扩展名并使用它们来识别C++源文件。然而,这不是一个好的做法,因为它会让其他人很难阅读和维护你的代码,甚至C++编译器可能会有问题因为识别不了非标准扩展名。

set(CMAKE_CXX_EXTENSIONS OFF)----不能使用其他的扩展后缀作为c++源文件的后缀名。

set(CMAKE_CXX_EXTENSIONS ON)----可以使用其他的扩展后缀作为c++源文件的后缀名。

CMAKE_MODULE_PATH---include

链接

CMAKE_PREFIX_PATH

指定CMake在查找包和项目所需库文件时的路径。

当项目的库文件或头文件不在CMake默认的查找路径中时,也就是库或者包文件不在可以通过设置CMAKE_PREFIX_PATH变量来为CMake提供额外的查找路径,从而缩短构建时间并提高构建成功率。

指定的是查找路径,后买你紧接着会用find_package()查找库或者包。

这个变量已经属于find_package中的config模式的查找路径了--链接

链接

CMAKE_INCLUDE_CURRENT_DIR

PROJECT_BINARY_DIR

链接

执行cmake ..所在的目录。

PROJECT_SOURCE_DIR

当前CMakeLIsts.txt所在的目录。

CMAKE_BINARY_DIR

同project_binary_dir

CMAKE_SOURCE_DIR

CMAKE_SOURCE_DIR: 最外层CMakeLists.txt所在目录,整个项目的目录。

CMAKE_CURRENT_SOURCE_DIR

CMAKE_CURRENT_SOURCE_DIR:当前项目(一般是子模块)的目录

add_sub(root目录下):

cmake_minimum_required(VERSION 3.22.1)
project(add_sub)

message("root directory output:")
message("PROJECT_SOURCE_DIR:${PROJECT_SOURCE_DIR}")
message("PROJECT_BINARY_DIR:${PROJECT_BINARY_DIR}")
message("CMAKE_SOURCE_DIR:${CMAKE_SOURCE_DIR}")
message("CMAKE_BINARY_DIR:${CMAKE_BINARY_DIR}")
message("CMAKE_CURRENT_SOURCE_DIR:${CMAKE_CURRENT_SOURCE_DIR}")

add_subdirectory(sub)

add_sub下的sub:

cmake_minimum_required(VERSION 3.22.1)
project(sub)

message("sub directory output:")
message("PROJECT_SOURCE_DIR:${PROJECT_SOURCE_DIR}")
message("PROJECT_BINARY_DIR:${PROJECT_BINARY_DIR}")
message("CMAKE_SOURCE_DIR:${CMAKE_SOURCE_DIR}")
message("CMAKE_BINARY_DIR:${CMAKE_BINARY_DIR}")
message("CMAKE_CURRENT_SOURCE_DIR:${CMAKE_CURRENT_SOURCE_DIR}")

add_library(sub test.cpp)
#message("output sub directory")

CMAKE_CURRENT_LIST_DIR

当前项目文件列表(包括CMakeLists.txt)所在目录,同PROJECT_SOURCE_DIR。

CMAKE_POSITION_INDEPENDENT_CODE

`CMAKE_POSITION_INDEPENDENT_CODE` 是 CMake 中的一个变量,用于控制是否编译位置无关的代码(PIC)。

当使用共享库时,需要编译位置无关的代码,以便在共享库被加载到内存时能够进行地址重定向。为了生成位置无关的代码,需要使用 `-fPIC` 编译选项。因此,在构建共享库时,设置 `CMAKE_POSITION_INDEPENDENT_CODE` 为 ON,可以自动将 `-fPIC` 选项添加到编译器的命令行中。

默认情况下,CMake 会根据当前平台自动判断是否需要编译位置无关的代码。如果在构建共享库时遇到位置无关的编译错误,则可能需要手动设置 `CMAKE_POSITION_INDEPENDENT_CODE` 为 ON。

要手动设置 `CMAKE_POSITION_INDEPENDENT_CODE`,可以在 CMakeLists.txt 文件中添加以下代码:

```cmake
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
```

该命令将在 CMake 构建共享库时启用位置无关的代码。

需要注意的是,对于某些平台或编译器,可能不支持 `-fPIC` 选项,因此需要使用其他的位置无关的编译选项。在这种情况下,需要针对具体的平台或编译器进行设置。

CMAKE_INSTALL_PREFIX---make install

prefix--前缀

`CMAKE_INSTALL_PREFIX` 是 CMake 中的一个变量,用于指定安装目录的路径

在使用 CMake 构建项目时,可以使用 `CMAKE_INSTALL_PREFIX` 变量来指定安装目录。例如,通过在 CMakeLists.txt 中添加以下代码可将安装目录设置为 `/usr/local`:

```cmake
set(CMAKE_INSTALL_PREFIX /usr/local)
```

在构建完成后,运行 `make install` 命令将安装构建的文件到指定的目录中。例如,如果要将安装目录设置为 `/usr/local`,则可以使用以下命令将项目安装到该目录中:

```
$ sudo make install
```

需要注意的是,安装目录需要有足够的写入权限才能安装文件。在 Linux 等系统中,一般需要使用超级用户权限才能将文件安装到系统目录中。因此,在运行 `make install` 命令时,需要使用 `sudo` 或其他管理员权限的账户运行。

除了使用 `set(CMAKE_INSTALL_PREFIX ...)` 命令来设置安装目录外,还可以在 CMake 命令行中使用 `-DCMAKE_INSTALL_PREFIX=...` 选项来设置安装目录。

在编写 CMakeLists.txt 文件时,建议始终设置 `CMAKE_INSTALL_PREFIX` 变量,以便在 CMake 构建过程中可以轻松更改安装目录。

什么是安装目录

在 CMake 中,安装目录指的是在构建和安装项目时用于存储生成文件、库和可执行文件的目标目录。在 Linux 和 macOS 等类 Unix 操作系统中,安装目录通常为 `/usr/local/`,而在 Windows 操作系统中,安装目录通常为 `C:\Program Files\` 或 `C:\Program Files (x86)\`。

通过在 CMakeLists.txt 文件中设置 `CMAKE_INSTALL_PREFIX` 变量,可以指定项目的安装目录。例如,通过以下命令将安装目录设置为 `/opt/myproject`:
set(CMAKE_INSTALL_PREFIX /opt/myproject)

在构建和安装项目时,CMake 将使用该目录作为目标安装路径,安装生成的文件、库和可执行文件。这使得用户可以轻松地将项目安装到指定的目录中,并在需要时访问它们。
 

如何将指定的文件安装到安装目录中,并让关联的过程生效

1,设置cmake变量CMAKE_INSTALL_PREFIX的值:

set(CMAKE_INSTALL_PREFIX "${CMAKE_PROJECT_DIR}/install")

2,

RPATH以及相关变量

RPATH是什么

RPATH不是一个变量,而是指和共享库(动态库)相关的一系列CMAKE变量。

在 Linux 和 macOS 等操作系统上,运行时链接器(runtime linker)在查找共享库时,通常会搜索标准的系统库路径。但是在某些情况下,共享库可能未被包含在 PATH 中,或需要从其他特定路径中动态加载。这时候就需要使用 RPATH(`runpath`)来指定共享库的查找路径。
RPATH---运行时链接器查找动态库的路径。

CMAKE_SKIP_RPATH

skip:跳过。

所以从字面意思就是是否要跳过RPATH。

`CMAKE_SKIP_RPATH`是一个CMake变量,它控制是否在生成目标(一般是可执行文件)上设置RPATH。如果设置了`CMAKE_SKIP_RPATH`为TRUE,那么不会在目标上设置RPATH。

CMAKE_SKIP_BUILD_RPATH

`CMAKE_SKIP_BUILD_RPATH`是另一个CMake变量,控制是否在构建目标时设置RPATH。如果设置了`CMAKE_SKIP_BUILD_RPATH`为FALSE,则CMake会在构建目标时将RPATH设置为构建树的路径,以允许测试程序和其他构建目标在构建期间正确地查找到它们的依赖项。如果设置了`CMAKE_SKIP_BUILD_RPATH`为TRUE,则不会在构建目标时将RPATH设置为构建树路径。

CMAKE_BUILD_WITH_INSTALL_RPATH

`CMAKE_BUILD_WITH_INSTALL_RPATH` 是 CMake 中的一个变量,通常用于在 Mac OS X 和 NeXT 平台上设置 RPATH。在这些平台上,应用程序和共享库是使用 `install_name` 路径名进行编译的,可以将 RPATH 设置为这些路径,以在运行时查找程序和库。

如果将 `CMAKE_BUILD_WITH_INSTALL_RPATH` 设置为 TRUE,将会在构建过程中将 `install_name` 路径编码到目标文件中,而不是使用 RPATH 环境变量。这提供了一种在程序和库分发后依然可以动态定位安装路径的方法。通过将 `install_name` 路径编码到目标文件中,运行时链接器可以自动查找所需的程序和库,而无需设置 RPATH 环境变量。

需要注意的是,只有在 Mac OS X 和 NeXT 平台上才使用 `install_name`,在其他平台上不起作用。如果程序和库在不同的路径中安装,则必须在编译之前将路径编码到目标文件中,因此需要使用 `CMAKE_BUILD_WITH_INSTALL_RPATH`。

总的来说,`CMAKE_BUILD_WITH_INSTALL_RPATH` 允许在 Mac OS X 和 NeXT 平台上设置 RPATH,以便使用 `install_name`,而不是在其他平台上设置 RPATH 环境变量。这是一种可靠的跨平台方式来管理共享库和应用程序的依赖关系,减少了跨平台分发和运行的问题。

CMAKE_INSTALL_RPATH

`CMAKE_INSTALL_RPATH` 变量指定一个或多个 RPATH 目录,用于告诉运行时链接器在软件包安装后的运行时期间查找共享库的位置。如果需要指定多个 RPATH 目录,可以将它们用分号隔开(类似于 PATH 的语法)。

例如,以下命令将 `lib` 目录添加到 RPATH:
set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib")

CMAKE_INSTALL_RPATH_USE_LINK_PATH

 `CMAKE_INSTALL_RPATH_USE_LINK_PATH` 变量则表示是否将链接库的目录中的RPATH添加到可执行文件的RPATH中,这样可执行文件就可以从链接的库的目录中找到需要的依赖库。如果不设置该变量,那么即使链接库的目录设置了RPATH,可执行文件也不会使用它。当设置 `CMAKE_INSTALL_RPATH_USE_LINK_PATH` 为 TRUE 时,CMake会在可执行文件的RPATH中添加链接库的目录中的RPATH。

总之就一句话:是否使用链接库中的RPATH。

BUILD_SHARED_LIBS

全局变量--控制这个CMakeLists.txt中生成的库的默认类型为静态库还是动态库。

因为这个值的默认值为OFF,所以add_library()默认生成的都是静态库。

设置生成的库的默认类型为动态库:

set(BUILD_SHARED_LIBS ON)

cmake局部变量

就是一个CMakeLists.txt中定义的变量,如;set(_var OFF),_var就是一个局部变量。

只能在当前CMakeLists.txt文件文件中使用。

局部变量的定义

set(var value)

set设置的变量不能在外部提供给用户设置。

set(USE_LIBRARY OFF)
message(STATIC "Compile sources into library? ${USE_LIBRARY}")

option()

option设置的变量才能在外部提供给用户设置。

option定义的变量相当于C++中的bool类型,在cmake中,这种变量叫开关,值为ON或者OFF。

cmake_dependent_option

cmake_minimum_required(VERSION 3.22.0 FATAL_ERROR)
project(test LANGUAGES CXX)

option(USE_LIBRARY "Compile sources into library" OFF)
include(CMakeDependentOption)
cmake_dependent_option(STATIC_VAR "Compile souces into static library" OFF "USE_LIBRARY" OFF)
cmake_dependent_option(SHARED_VAR "Compile souces into shared library" ON "USE_LIBRARY" OFF)

if(SHARED_VAR)
    set(BUILD_SHARED_LIBS ON)
endif()

list(APPEND _sources sum.h sum.cpp)

if(USE_LIBRARY)
    add_library(sum ${_sources})
    add_executable(main main.cpp)
    target_link_libraries(main sum)
else()
    add_executable(main main.cpp sum.cpp)
endif()

SHARED_VAR依赖于USE_LIBRARY的值,只有USE_LIBRARY的值为NO,SHARED_VAR的值才会被设置为指定的值。

也就是只有被以来的变量的值为真,才会设置以来变量的值,否则以来的变量的值为OFF。

cmake路径指定

指定可执行文件输出路径

AI对话未来丨智能写作对话:
在 CMake 中,可以通过`set(EXECUTABLE_OUTPUT_PATH <dir>)`命令或者在`add_executable`中指定可执行文件的输出路径来指定可执行文件的输出路径。

方法一:

```cmake
# 设置可执行文件输出路径为 build/bin
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)

# 添加可执行文件
add_executable(my_executable main.cpp)
```

方法二:

```cmake
# 添加可执行文件,并指定输出路径为 build/bin
add_executable(my_executable main.cpp)
set_target_properties(my_executable PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin)
```

上述两种方法都是将可执行文件的输出路径设置为`${PROJECT_BINARY_DIR}/bin`,即生成项目的二进制文件目录下的`bin`目录。你也可以将其指定成其他目录,例如:

```cmake
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/build/bin)
```

其中,`${CMAKE_SOURCE_DIR}`表示项目根目录的路径。

需要注意的是,使用方法二中的`set_target_properties`指定可执行文件

输出路径时,针对不同的平台可能需要使用不同的属性名,例如对于 Windows 平台,可以使用`RUNTIME_OUTPUT_DIRECTORY`,对于 Linux 平台,应该使用`LIBRARY_OUTPUT_DIRECTORY`。最好在 CMake 官方文档中查找关于该属性的正确用法。

另外还可以使用生成器表达式来根据构建类型(debug/release)或其他条件动态地指定可执行文件的输出路径,因此也可以灵活地指定可执行文件的输出路径。
 

编译类型设置

CMAKE_BUILD_TYPE

其他关键字

cmake文档

Qt CmakeList.txt怎么添加库

cmake编译,怎么添加图片

1,第一步,需要先创建resources文件夹,并且把图片资源放入resources文件夹;

2,在resources文件夹下建立.qrc文件;

3,CMakeList.txt中把resources文件夹和文件加入项目;

4,编译(构建项目);

(提升)找不到头文件

链接

CMakeList.txt中加入:

INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR})

多级CMakeLists.txt构建添加子模块

1,子模块需要自己指定构建为库:

2,上级模块指定加载子模块并构建;

add_subdirectory

添加一个子目录并构建该子目

add_dependencies(target depend1 depend2 ...)

cmake配置

vscode使用cmake,最好下载cmake 扩展插件--可以让是cmake语言和自动填充。

错误

No CMAKE_CXX_COMPILER could be found

compiler--编译器

没有对应的编译器。

链接

其他关键字

cmake文档

undefine reference的原因---未定义

1,没有链接库文件;

2,编译这个库的编译器不是使用的编译器;

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值