01 Cmake使用
Published on 2024-06-27 08:34 in 分类: Cpp , 并行计算 with 真真夜夜
分类: Cpp , 并行计算

01 Cmake使用

感谢up主 双笙子佯谬:https://space.bilibili.com/263032155

学C++从Cmake开始

1. 简介和基础概念

  • CMake 简介和优势:

    • CMake 是一个跨平台的开源构建系统生成工具,用于管理软件构建过程中的编译、链接和安装步骤。
    • 主要优势包括跨平台性(能够在多种操作系统上生成本地构建文件)、简化构建过程、与各种编译器和工具链的兼容性。
  • CMakeLists.txt 文件结构和基本语法:

    • cmake_minimum_required:指定运行该 CMakeLists.txt 所需的最低 CMake 版本。
    • project 命令:定义项目名称和支持的语言。

2. 构建目标和管理

  • 创建和管理构建目标:

    • 使用 add_executable 命令创建可执行文件目标。
    • 使用 add_library 命令创建静态或动态库目标。
    • 示例:
      add_executable(myapp main.cpp)
      add_library(mylib STATIC lib1.cpp lib2.cpp)
      
  • 链接库文件:

    • 使用 target_link_libraries 命令将库文件链接到目标。
    • 示例:
      target_link_libraries(myapp PRIVATE mylib)
      

3. 多文件项目管理

  • 组织和管理多个源文件:

    • 使用 add_subdirectory 命令添加子目录并管理子项目。
    • 示例:
      add_subdirectory(submodule)
      
  • 合理组织头文件和源文件:

    • 确保头文件和源文件的适当组织,使项目结构清晰和可维护性高。

4. 编译选项和宏定义

  • 添加编译器选项:

    • 使用 target_compile_options 命令添加特定的编译器选项。
    • 示例:
      target_compile_options(myapp PRIVATE -Wall -O2)
      
  • 定义预处理器宏:

    • 使用 target_compile_definitions 命令定义预处理器宏。
    • 示例:
      target_compile_definitions(myapp PRIVATE MY_MACRO)
      

5. 第三方库的集成

  • 纯头文件库的集成和使用:

    • 将纯头文件库的 include 目录添加到项目中。
    • 示例:
      include_directories(path/to/library/include)
      
  • 使用外部库:

    • 使用 find_package 查找系统安装的库并集成到项目中。
    • 示例:
      find_package(Boost REQUIRED)
      target_include_directories(myapp PRIVATE ${Boost_INCLUDE_DIRS})
      target_link_libraries(myapp PRIVATE ${Boost_LIBRARIES})
      

6. 高级功能和技巧

  • 自定义构建过程:

    • 使用自定义命令和自定义目标以实现特定的构建需求。
    • 示例:
      add_custom_command(OUTPUT output_file
                         COMMAND command_to_generate_output
                         DEPENDS input_file)
      
  • 特定平台和编译器的处理:

    • 根据不同的平台和编译器设置不同的选项和路径。
    • 示例:
      if (UNIX)
          target_compile_options(myapp PRIVATE -pthread)
      endif()
      

7. 实战案例和最佳实践

IMAGE_DESCRIPTION

CMakeLists.txt

# 设置 CMake 最低版本要求为 3.12
cmake_minimum_required(VERSION 3.12)

# 定义项目名称为 hellocmake,并指定使用的编程语言为 C++ (CXX)
project(hellocmake LANGUAGES CXX)

# 添加子目录 hellolib和mathlib,执行其中的 CMakeLists.txt 文件
add_subdirectory(hellolib)
add_subdirectory(mathlib)

# 创建可执行文件 a.out,将 main.cpp 添加为源文件
add_executable(a.out main.cpp)

# 链接 hellolib mathlib 库到 a.out 可执行文件,使用 PUBLIC 修饰符表示 hellolib mathlib的依赖关系会传播到 a.out
target_link_libraries(a.out PUBLIC hellolib mathlib)

hellolib/CMakeLists.txt

# 在当前目录创建名为 hellolib 的静态库,包含 hello.cpp 文件
add_library(hellolib STATIC hello.cpp)

# 将当前目录(包含 hellolib 的目录)添加到 hellolib 库的头文件搜索路径中
target_include_directories(hellolib PUBLIC .)

hellolib/hello.h

#pragma once

void hello();

hellolib/hello.cpp

#include <cstdio>

#include "hello.h"

void hello() {
    printf("Hello, world!\n");
}

mathlib/CMakeLists.txt

add_library(mathlib SHARED math.cpp)

target_include_directories(mathlib PUBLIC .)

mathlib/math.h

#pragma once

int add(int a, int b);
int subtract(int a, int b);

mathlib/math.cpp

#include "math.h"

int add(int a, int b) {
    return a + b;
}

int subtract(int a, int b) {
    return a - b;
}

main.cpp

#include <cstdio>
#include "hello.h"
#include "math.h"

int main() {
    hello();

    int result_add = add(5, 3);
    int result_subtract = subtract(5, 3);

    printf("5 + 3 = %d\n", result_add);
    printf("5 - 3 = %d\n", result_subtract);

    return 0;
}

8. CMake 与现代 C++ 开发

  • 支持现代 C++ 标准的配置方法:

    • 设置编译器标志以支持 C++11、C++14、C++17 等新标准。
    • 示例:
      set(CMAKE_CXX_STANDARD 17)
      
  • 使用现代工具链和测试框架的集成:

    • 配置和集成 Google Test、Catch2 等测试框架。
    • 示例:
      include(GoogleTest)
      add_executable(tests test1.cpp test2.cpp)
      target_link_libraries(tests PRIVATE GTest::GTest GTest::Main)
      

9. 其他一些细节

objdump -D 反汇编

  • 功能说明:
    • objdump -D 是一个命令行工具,用于查看可执行文件或目标文件的反汇编内容。
    • 反汇编显示了机器码指令对应的汇编语言表示,帮助开发人员理解程序在底层的执行过程和优化代码。

ldd

  • 功能说明:
    • ldd 命令用于打印可执行文件或共享库文件所依赖的动态链接库(共享对象)列表。
    • 在 Linux 系统上特别有用,可以检查程序运行时所需的共享库是否存在,并显示它们的路径。

静态库与动态库

  • 静态库功能说明:

    • 静态库(Static Library)是一种编译链接后形成的文件,包含了多个目标文件的归档文件(通常以 .a.lib 扩展名保存)。
    • 静态库在链接阶段被整合到可执行文件中,使得可执行文件可以在没有其他依赖的情况下运行。
    • 删除.a文件后,a.out仍然可以运行
  • 动态库功能说明:

    • 动态库(Dynamic Library)是一种在运行时加载并链接的库文件,以共享对象(Shared Object)的形式存在(通常以 .so 扩展名保存)。
    • 动态库可以在多个程序间共享,减少内存占用,但需要在运行时通过动态链接器加载到内存中。
    • 删除.a文件后,a.out不可以运行

头文件的导入

  • C/C++ 中的 #include 指令可以用来包含头文件。
  • 双引号 " 形式的 #include
    • 例如 #include "example.h"
    • 预处理器会先在当前源文件所在的目录中查找 example.h 文件。
    • 如果找不到,则会继续在包含该源文件的文件所在目录、项目指定的其他目录等地方查找。
  • 尖括号 <> 形式的 #include
    • 例如 #include <example.h>
    • 预处理器会直接在系统的标准头文件目录中(如 /usr/include/usr/local/include 等)查找 example.h 文件。
    • 这种形式通常用于包含标准库或者第三方库的头文件,因为这些头文件通常不在当前项目的源代码目录中。

防止重复导入 #pragma once

  • 功能说明:
    • #pragma once 是一种预处理器指令,用于防止同一个头文件被多次包含。
    • 替代传统的 #ifndef/#define 宏保护方式,更简洁且通常有更好的性能表现。

CMakeLists其他说明

# 除了头文件搜索目录以外,还有这些选项,PUBLIC 和 PRIVATE 对他们同理:
target_include_directories(myapp PUBLIC /usr/include/eigen3)  # 添加头文件搜索目录
target_link_libraries(myapp PUBLIC hellolib)                  # 添加要链接的库
target_add_definitions(myapp PUBLIC MY_MACRO=1)               # 添加一个宏定义
target_add_definitions(myapp PUBLIC -DMY_MACRO=1)             # 与 MY_MACRO=1 等价
target_compile_options(myapp PUBLIC -fopenmp)                 # 添加编译器命令行选项
target_sources(myapp PUBLIC hello.cpp other.cpp)              # 添加要编译的源文件

# 以及可以通过下列指令(不推荐使用),把选项加到所有接下来的目标去:
include_directories(/opt/cuda/include)                        # 添加头文件搜索目录
link_directories(/opt/cuda)                                   # 添加库文件的搜索路径
add_definitions(MY_MACRO=1)                                   # 添加一个宏定义
add_compile_options(-fopenmp)                                 # 添加编译器命令行选项
posted @   真真夜夜  阅读(23)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
点击右上角即可分享
微信分享提示