简介

  • cmake 常用的技巧

vscode中cmake项目配置文件手动修改编译器路径

在 VSCode 中,如果你想为 CMake 项目手动配置编译器路径,可以通过修改 CMakeSettings.json 或者 .vscode/settings.json 文件来实现。以下是配置步骤:

1. 使用 CMakeSettings.json

CMake 支持通过 CMakeSettings.json 来设置不同的构建配置,比如指定编译器路径。创建或修改项目根目录中的 CMakeSettings.json 文件,添加类似下面的配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
{
  "configurations": [
    {
      "name": "x64-Debug",
      "generator": "Ninja",
      "configurationType": "Debug",
      "buildRoot": "${projectDir}\\out\\build\\${name}",
      "installRoot": "${projectDir}\\out\\install\\${name}",
      "cmakeCommandArgs": "",
      "buildCommandArgs": "",
      "ctestCommandArgs": "",
      "variables": [
        {
          "name": "CMAKE_C_COMPILER",
          "value": "C:/Path/To/Your/Compiler/gcc.exe"
        },
        {
          "name": "CMAKE_CXX_COMPILER",
          "value": "C:/Path/To/Your/Compiler/g++.exe"
        }
      ]
    }
  ]
}

这会告诉 CMake 使用指定的编译器路径。

2. 使用 .vscode/settings.json

你也可以直接在 VSCode 的工作区配置中设置编译器路径,方法是修改 .vscode/settings.json 文件:

1
2
3
4
5
6
7
8
9
{
  "cmake.cmakePath": "C:/Path/To/CMake/cmake.exe",
  "cmake.generator": "Ninja",
  "cmake.buildDirectory": "${workspaceFolder}/build",
  "cmake.environment": {
    "CC": "C:/Path/To/Your/Compiler/gcc.exe",
    "CXX": "C:/Path/To/Your/Compiler/g++.exe"
  }
}

这里 cmake.environment 变量用于指定 C 和 C++ 编译器路径。

3. 通过 CMakeLists.txt 文件

你也可以在 CMakeLists.txt 中直接添加设置编译器的指令:

1
2
set(CMAKE_C_COMPILER "C:/Path/To/Your/Compiler/gcc.exe")
set(CMAKE_CXX_COMPILER "C:/Path/To/Your/Compiler/g++.exe")

4. 使用 cmake-kits.json

VSCode 的 CMake Tools 扩展提供了一种通过 cmake-kits.json 来管理编译器的方式。你可以在 .vscode/cmake-kits.json 中定义编译器路径:

1
2
3
4
5
6
7
8
9
[
  {
    "name": "GCC",
    "compilers": {
      "C": "C:/Path/To/Your/Compiler/gcc.exe",
      "CXX": "C:/Path/To/Your/Compiler/g++.exe"
    }
  }
]

然后在 VSCode 的 CMake Tools 扩展中选择这个编译器套件。

5. 选择编译器

如果你已经配置了多个编译器,可以通过命令面板(Ctrl+Shift+P)打开 CMake: Select a Kit,然后从列表中选择你配置的编译器。

这几种方式都可以帮助你手动指定 CMake 项目的编译器路径。

cmake 静态链接库顺序问题

  • 默认情况下要求被依赖的库放在依赖它的库后面,当一个程序或共享库依赖的静态库较多时,可能会陷入解决链接问题的坑中。如果对静态库不熟悉,需要结构nm等工具来解决顺序问题。

  • 如果去掉顺序的烦恼和痛苦,可以采用如下方法

    1
    2
    3
    4
    5
    6
    7
    8
    
    target_link_libraries(
      x
      -Wl,--start-group
      libX1.a
      libX3.a
      libX2.a
      -Wl,--end-group
    )
    

cmake 设置编译线程数量

在使用 CMake 构建项目时,你可以通过设置编译器选项来指定编译时使用的线程数量。具体步骤如下:

  1. 使用 cmake 命令配置项目: 例如,你可以在项目根目录中运行以下命令来生成构建文件:
    1
    
    cmake -S . -B build
    
  2. 使用 cmake --build 命令进行构建并指定线程数量: 使用 --parallel 选项可以指定编译时使用的线程数量。例如,如果你想使用 8 个线程来进行编译,可以运行以下命令:
    1
    
    cmake --build build --parallel 8
    

这样,CMake 会根据你指定的线程数量来并行执行构建任务,从而加快编译速度。

完整的流程示例如下:

1
2
cmake -S . -B build
cmake --build build --parallel 8

此外,你还可以直接在 makeninja 命令中指定线程数量(假设你使用的是这些生成器):

  • 对于 make 生成器:
    1
    
    make -j8
    
  • 对于 ninja 生成器:
    1
    
    ninja -j8
    

CMake 会根据你的项目配置选择合适的生成器并使用相应的构建工具。

CMakeLists.txt 编译性能参数配置

CMakeLists.txt 中配置编译性能参数,可以通过一些特定的编译选项和设置来优化编译时间和资源使用。以下是一些常见的方法和配置选项,可以用来提升编译性能:

1. 使用 CMAKE_BUILD_TYPE

通过设置 CMAKE_BUILD_TYPE 可以启用特定的编译器优化选项。例如,在开发过程中可以设置为 Debug,在发布时设置为 Release。使用 Release 模式可以启用优化选项,从而减少生成的代码大小和提升执行性能。

1
set(CMAKE_BUILD_TYPE Release)

2. 使用 CMAKE_CXX_FLAGSCMAKE_C_FLAGS

可以为编译器指定一些优化选项,比如 -O2 或者 -O3,这些选项可以启用更多的编译器优化,从而提升生成代码的性能。

1
2
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O2")

3. 使用 CMAKE_LINKER_FLAGS

对于链接阶段,可以设置 CMAKE_EXE_LINKER_FLAGSCMAKE_SHARED_LINKER_FLAGS 来优化链接器的行为。

1
2
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--as-needed")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--as-needed")

4. 启用并行链接

某些编译器和链接器支持并行链接,可以显著减少链接时间。对于 GNU 链接器,可以使用 -Wl,--parallel

1
2
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--parallel")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--parallel")

5. 使用 ccache

ccache 是一个编译缓存工具,可以显著减少重复编译的时间。要在 CMake 中启用 ccache

1
2
3
4
5
find_program(CCACHE_PROGRAM ccache)
if(CCACHE_PROGRAM)
    set(CMAKE_C_COMPILER_LAUNCHER ${CCACHE_PROGRAM})
    set(CMAKE_CXX_COMPILER_LAUNCHER ${CCACHE_PROGRAM})
endif()

6. 使用 Ninja 生成器

Ninja 是一个快速的构建系统,通常比默认的 Make 更快。要使用 Ninja,可以在 CMake 配置阶段指定生成器:

1
cmake -G Ninja ..

CMakeLists.txt 中没有直接指定 Ninja 的方法,但可以通过命令行来指定。

7. 预编译头文件

预编译头文件可以显著减少编译时间,特别是当项目包含大量头文件时。可以通过 target_precompile_headers 指令来设置预编译头文件:

1
target_precompile_headers(my_target PRIVATE precompiled.h)

8. 使用编译选项优化

根据不同的编译器,可以启用一些特定的优化选项。例如,针对 GCC,可以启用以下选项:

1
2
3
4
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native -flto")
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=native -flto")
endif()

完整示例

以下是一个包含上述多个优化配置的 CMakeLists.txt 示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
cmake_minimum_required(VERSION 3.14)
project(MyProject)

# 设置编译类型
set(CMAKE_BUILD_TYPE Release)

# 编译器优化选项
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2 -march=native -flto")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O2 -march=native -flto")

# 链接器优化选项
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--as-needed -Wl,--parallel")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--as-needed -Wl,--parallel")

# 启用 ccache
find_program(CCACHE_PROGRAM ccache)
if(CCACHE_PROGRAM)
    set(CMAKE_C_COMPILER_LAUNCHER ${CCACHE_PROGRAM})
    set(CMAKE_CXX_COMPILER_LAUNCHER ${CCACHE_PROGRAM})
endif()

# 预编译头文件
target_precompile_headers(MyTarget PRIVATE precompiled.h)

# 项目源文件
add_executable(MyTarget main.cpp)

通过在 CMakeLists.txt 中添加这些配置,可以显著提升编译性能并减少系统资源的使用。

cmake 子项目设置二进制文件保存路径

要设置子项目的二进制文件保存路径,你可以在使用 add_subdirectory() 函数添加子项目时,通过第二个参数 binary_dir 来指定。

假设你有如下的项目结构:

1
2
3
4
5
6
7
8
9
10
project_root/
    CMakeLists.txt
    src/
        CMakeLists.txt
        file1.cpp
        file2.cpp
    test/
        CMakeLists.txt
        test1.cpp
        test2.cpp

如果你希望将子项目的二进制文件保存在不同的目录中,可以像这样在父项目的 CMakeLists.txt 中设置:

1
2
3
4
5
cmake_minimum_required(VERSION 3.10)
project(MyProject)

add_subdirectory(src bin/src)
add_subdirectory(test bin/test)

在这个例子中,src 子项目的二进制文件将保存在 project_root/bin/src 目录中,而 test 子项目的二进制文件将保存在 project_root/bin/test 目录中。

如果不指定 binary_dir 参数,子项目的二进制文件将默认保存在子项目目录下的 bin 目录中。

cmake 在子项目中设置头文件包含目录

在 CMake 中,你可以在子项目中使用 target_include_directories() 函数来设置头文件包含目录。这个函数用于为指定的目标(例如库或可执行文件)设置头文件搜索路径。假设你有如下的项目结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
project_root/
    CMakeLists.txt
    src/
        CMakeLists.txt
        file1.cpp
        file2.cpp
        include/
            header1.h
            header2.h
    test/
        CMakeLists.txt
        test1.cpp
        test2.cpp

src/CMakeLists.txt 中,你可以这样设置头文件包含目录:

1
target_include_directories(my_target_name PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)

在这个例子中,my_target_name 是你在 src/CMakeLists.txt 中定义的目标名称,${CMAKE_CURRENT_SOURCE_DIR} 表示当前源码目录的路径,${CMAKE_CURRENT_SOURCE_DIR}/include 就是 include 目录的路径。使用 PUBLIC 关键字可以将这个头文件包含目录设置为公开的,这意味着这个目录将会被导出到依赖这个目标的其他目标中。

test/CMakeLists.txt 中,你也可以类似地设置头文件包含目录:

1
target_include_directories(test_target_name PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../src/include)

在这个例子中,test_target_name 是你在 test/CMakeLists.txt 中定义的目标名称,${CMAKE_CURRENT_SOURCE_DIR}/../src/include 是相对于 test 目录的父目录 src/include 的路径。使用 PRIVATE 关键字可以将这个头文件包含目录设置为私有的,这意味着这个目录只对当前目标有效,不会被导出到依赖当前目标的其他目标中。

cmake 打印目标的头文件路径和编译选项

要打印目标的头文件路径和编译选项,您可以使用 get_target_property 命令来获取目标的属性。以下是一个示例代码,假设您的目标名为 my_target

1
2
3
4
5
6
7
# 获取目标的头文件路径
get_target_property(TARGET_INCLUDE_DIRECTORIES my_target INCLUDE_DIRECTORIES)
message(STATUS "My target include directories: ${TARGET_INCLUDE_DIRECTORIES}")

# 获取目标的编译选项
get_target_property(TARGET_COMPILE_OPTIONS my_target COMPILE_OPTIONS)
message(STATUS "My target compile options: ${TARGET_COMPILE_OPTIONS}")

这段代码将打印出目标 my_target 的头文件路径和编译选项。您可以根据需要获取和打印其他属性。

cmake find_package 配置opencv库

配置 OpenCV 库时,通常会使用 CMake 的 find_package 命令。以下是一个简单的示例,展示如何在 CMake 中配置和链接 OpenCV 库:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
cmake_minimum_required(VERSION 3.12)
project(MyProject)

# 使用 find_package 查找并配置 OpenCV 库
find_package(OpenCV REQUIRED)

# 输出找到的 OpenCV 库信息
message("OpenCV_INCLUDE_DIRS: ${OpenCV_INCLUDE_DIRS}")
message("OpenCV_LIBRARIES: ${OpenCV_LIBRARIES}")

# 添加可执行文件,并链接 OpenCV 库
add_executable(MyExecutable main.cpp)
target_include_directories(MyExecutable PRIVATE ${OpenCV_INCLUDE_DIRS})
target_link_libraries(MyExecutable PRIVATE ${OpenCV_LIBRARIES})

在上述代码中:

  • find_package(OpenCV REQUIRED) 用于查找并配置 OpenCV 库。REQUIRED 表示如果找不到 OpenCV 库,将产生一个错误。
  • OpenCV_INCLUDE_DIRS 包含了 OpenCV 库的头文件目录。
  • OpenCV_LIBRARIES 包含了 OpenCV 库的链接库的名称。
  • add_executable 添加了一个可执行文件,并使用 target_include_directories 将 OpenCV 库的头文件目录包含进来,使用 target_link_libraries 将 OpenCV 库链接到可执行文件中。

确保 OpenCV 已经安装在你的系统中,或者你可以使用 CMake 的 ExternalProject 或其他方法在 CMake 中构建 OpenCV。

此外,find_package 还可以通过指定版本号和特定组件来细化查找过程。例如:

1
find_package(OpenCV 4.5.1 REQUIRED COMPONENTS core imgproc highgui)

这将查找并配置 OpenCV 版本为 4.5.1,并确保包含了 core、imgproc 和 highgui 组件。

cmake find_package 配置gflags库

当使用 CMake 的 find_package 配置 gflags 库时,你需要确保 gflags 库的 CMake 模块文件 Findgflags.cmake 被正确找到并使用。以下是一个简单的例子,演示如何在 CMake 中使用 find_package 配置 gflags 库:

1
2
3
4
5
6
7
8
9
10
11
12
13
cmake_minimum_required(VERSION 3.12)
project(MyProject)

# 使用 find_package 查找 gflags 库
find_package(gflags REQUIRED)

# 输出找到的 gflags 库信息
message("gflags_INCLUDE_DIRS: ${gflags_INCLUDE_DIRS}")
message("gflags_LIBRARIES: ${gflags_LIBRARIES}")

# 添加可执行文件,并链接 gflags 库
add_executable(MyExecutable main.cpp)
target_link_libraries(MyExecutable PRIVATE gflags)

在上述代码中:

  • find_package(gflags REQUIRED) 用于查找并配置 gflags 库。REQUIRED 表示如果找不到 gflags 库,将产生一个错误。
  • gflags_INCLUDE_DIRS 包含了 gflags 库的头文件目录。
  • gflags_LIBRARIES 包含了 gflags 库的链接库的名称。
  • add_executable 添加了一个可执行文件,并使用 target_link_librariesgflags 库链接到可执行文件中。

确保 gflags 库已经安装在系统中,或者你可以使用 ExternalProject 或其他方法在 CMake 中构建 gflags

此外,如果你的项目中还用到其他外部库,可能需要在 find_package 后面添加其他库的查找,以确保这些库的依赖关系也得到正确配置。

最后,记得在 CMakeLists.txt 中引入 main.cpp 或其他源代码文件,以确保它们被编译到可执行文件中。