首页 > 其他分享 >创建一个CMake项目

创建一个CMake项目

时间:2025-01-17 20:59:56浏览次数:3  
标签:src MyExecutable CMake MyLib 项目 创建 add cpp include

本文将演示如何使用 CMake 管理一个中等复杂度的项目,从创建项目到编译和运行的整个过程,涵盖了从基本配置到高级特性的实际应用。

实战内容如下:

  1. 创建 CMakeLists.txt 文件:定义项目、库、可执行文件和测试。
  2. 编写源代码和测试:编写代码和测试文件。
  3. 创建构建目录:保持源代码目录整洁。
  4. 配置项目:生成构建系统文件。
  5. 编译项目:生成目标文件。
  6. 运行可执行文件:执行程序。
  7. 运行测试:验证功能正确性。
  8. 使用自定义命令和目标:执行额外操作。
  9. 跨平台和交叉编译:支持不同平台和架构。

构建一个简单的 C++ 项目
假设我们有一个项目,包含一个主程序和一个库,库中有两个不同的功能模块。

项目结构如下:

MyProject/
├── CMakeLists.txt
├── src/
│   ├── main.cpp
│   ├── lib/
│   │   ├── module1.cpp
│   │   ├── module2.cpp
│   ├── include/
│       └── mylib.h
│	└── CMakeLists.txt
└── tests/
    ├── test_main.cpp
    └── CMakeLists.txt

1. 创建 CMakeLists.txt 文件

1.1 根目录 CMakeLists.txt 文件

cmake_minimum_required(VERSION 3.10)   # 指定最低 CMake 版本
project(MyProject VERSION 1.0)          # 定义项目名称和版本

# 设置 C++ 标准
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# 包含头文件路径
include_directories(${PROJECT_SOURCE_DIR}/src/include)

# 添加子目录
add_subdirectory(src)
add_subdirectory(tests)

解释

  • cmake_minimum_required(VERSION 3.10): 确保使用的 CMake 版本至少是 3.10,以支持后续使用的 CMake 特性。
  • project(MyProject VERSION 1.0): 声明项目名称为 MyProject 并指定版本号为 1.0。CMake 会创建一些与项目相关的变量,如 PROJECT_NAMEPROJECT_VERSION
  • set(CMAKE_CXX_STANDARD 11)set(CMAKE_CXX_STANDARD_REQUIRED ON): 将 C++ 标准设置为 C++11,并强制要求使用该标准。
  • include_directories(${PROJECT_SOURCE_DIR}/src/include): 将 src/include 目录添加到包含目录列表中,这样编译器可以找到相应的头文件。
  • add_subdirectory(src)add_subdirectory(tests): 指示 CMake 处理 srctests 子目录下的 CMakeLists.txt 文件。

1.2 src 目录 CMakeLists.txt 文件

# 创建库目标
add_library(MyLib STATIC
    lib/module1.cpp
    lib/module2.cpp
)

# 指定库的头文件
target_include_directories(MyLib PUBLIC ${CMAKE_SOURCE_DIR}/src/include)

# 创建可执行文件目标
add_executable(MyExecutable main.cpp)

# 链接库到可执行文件
target_link_libraries(MyExecutable PRIVATE MyLib)

解释

  • add_library(MyLib STATIC lib/module1.cpp lib/module2.cpp): 创建一个名为 MyLib 的静态库,使用 module1.cppmodule2.cpp 作为源文件。
  • target_include_directories(MyLib PUBLIC ${CMAKE_SOURCE_DIR}/src/include): 将 src/include 目录添加到 MyLib 的公共包含目录中,这意味着任何链接 MyLib 的目标都可以使用这些头文件。
  • add_executable(MyExecutable main.cpp): 创建一个名为 MyExecutable 的可执行文件,使用 main.cpp 作为源文件。
  • target_link_libraries(MyExecutable PRIVATE MyLib): 将 MyLib 库链接到 MyExecutable 可执行文件,并且该链接关系是私有的,意味着 MyExecutable 的依赖不会传递给其他依赖 MyExecutable 的目标。

1.3 tests 目录 CMakeLists.txt 文件

# 查找 GTest 包
find_package(GTest REQUIRED)
include_directories(${GTEST_INCLUDE_DIRS})

# 创建测试目标
add_executable(TestMyLib test_main.cpp)

# 链接库和 GTest 到测试目标
target_link_libraries(TestMyLib PRIVATE MyLib ${GTEST_LIBRARIES})

解释

  • find_package(GTest REQUIRED): 查找 Google Test 测试框架包,REQUIRED 表示如果找不到该包将导致 CMake 报错。
  • include_directories(${GTEST_INCLUDE_DIRS}): 将 Google Test 的包含目录添加到包含目录列表中。
  • add_executable(TestMyLib test_main.cpp): 创建一个名为 TestMyLib 的可执行测试程序,使用 test_main.cpp 作为源文件。
  • target_link_libraries(TestMyLib PRIVATE MyLib ${GTEST_LIBRARIES}): 将 MyLib 库和 Google Test 库链接到 TestMyLib 测试可执行文件,同样是私有的链接关系。

2. 编写源代码和测试

2.1 src/main.cpp 文件代码

#include <iostream>
#include "mylib.h"

int main() {
    std::cout << "Hello, CMake!" << std::endl;
    return 0;
}

解释

  • 包含了 iostream 用于标准输入输出,mylib.h 应该包含了 MyLib 库的相关声明。
  • main() 函数输出一条消息并返回 0。

2.2 src/lib/module1.cpp 文件代码

#include "mylib.h"

// Implementation of module1

解释

  • 包含 mylib.h 头文件,这是 MyLib 库的一部分,应该在此文件中实现 module1 的具体功能,但这里只是一个占位。

2.3 src/lib/module2.cpp 文件代码

#include "mylib.h"

// Implementation of module2

解释

  • 类似 module1.cpp,包含 mylib.h 并应该实现 module2 的具体功能,这里未给出具体实现。

2.4 src/include/mylib.h 文件代码

#ifndef MYLIB_H
#define MYLIB_H

// Declarations of module functions

#endif // MYLIB_H

解释

  • 这是一个典型的头文件保护宏,避免头文件被重复包含。在 #ifndef#endif 之间应该包含 MyLib 库中函数的声明,但这里没有给出具体声明。

2.5 tests/test_main.cpp 文件代码

#include <gtest/gtest.h>

// Test cases for MyLib
TEST(MyLibTest, BasicTest) {
    EXPECT_EQ(1, 1);
}

解释

  • 包含 Google Test 的头文件 gtest/gtest.h
  • 使用 TEST 宏定义了一个名为 MyLibTest 的测试套件,其中包含一个名为 BasicTest 的测试用例,该测试用例使用 EXPECT_EQ 断言来验证 1 是否等于 1,这是一个非常简单的测试,通常可以在此基础上添加更多复杂的测试逻辑。

3. 创建构建目录

mkdir build
cd build

解释

  • 创建一个名为 build 的目录,这是一个良好的实践,可以将生成的构建文件与源代码分离,使源代码目录保持整洁。
  • 进入 build 目录,后续的 CMake 操作将在此目录中进行。

4. 配置项目

cmake..

解释

  • 运行 cmake.. 命令,.. 表示 CMake 会查找上一级目录中的 CMakeLists.txt 文件,并根据该文件生成构建系统文件(如 Makefile 或 Visual Studio 项目文件等)。

5. 编译项目

make

解释

  • 使用 make 命令进行编译,该命令将根据 build 目录中生成的构建文件(如 Makefile)编译源文件,生成目标文件(可执行文件和库文件)。

6. 运行可执行文件

./MyExecutable

解释

  • 执行生成的可执行文件 MyExecutable,将输出 Hello, CMake!

7. 运行测试

./TestMyLib

解释

  • 执行测试可执行文件 TestMyLib,将运行 test_main.cpp 中定义的测试用例,这里只有一个简单的测试,用于验证 1 是否等于 1

8. 使用自定义命令和目标

8.1 自定义命令

add_custom_command(
    TARGET MyExecutable
    POST_BUILD
    COMMAND ${CMAKE_COMMAND} -E echo "Build complete!"
)

解释

  • add_custom_command 用于添加一个自定义命令,这里添加到 MyExecutable 目标的 POST_BUILD 阶段。
  • COMMAND ${CMAKE_COMMAND} -E echo "Build complete!" 表示在构建完成 MyExecutable 后,使用 CMake 的 -E 选项执行 echo 命令输出 Build complete!

8.2 自定义目标

add_custom_target(run
    COMMAND ${CMAKE_BINARY_DIR}/MyExecutable
    DEPENDS MyExecutable
)

解释

  • add_custom_target 创建一个名为 run 的自定义目标。
  • COMMAND ${CMAKE_BINARY_DIR}/MyExecutable 表示该目标的命令是执行 MyExecutable 可执行文件。
  • DEPENDS MyExecutable 表示 run 目标依赖于 MyExecutable,当 MyExecutable 被更新时,run 目标会重新执行。

9. 跨平台和交叉编译

9.1 指定平台

cmake -DCMAKE_SYSTEM_NAME=Linux..

解释

  • 通过 -DCMAKE_SYSTEM_NAME=Linux 命令行选项告诉 CMake 要构建的目标系统是 Linux 系统,CMake 会根据这个信息调整生成的构建文件。

9.2 使用工具链文件

set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)

解释

  • 创建一个工具链文件 toolchain.cmake,设置 CMAKE_SYSTEM_NAMELinuxCMAKE_SYSTEM_PROCESSORarm,用于指定构建的系统是 Linux 且处理器是 ARM 架构。
  • cmake -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake.. 命令使用该工具链文件进行构建,这对于交叉编译非常有用,例如在 x86 主机上为 ARM 平台编译代码。

标签:src,MyExecutable,CMake,MyLib,项目,创建,add,cpp,include
From: https://blog.csdn.net/ke_wu/article/details/145124274

相关文章

  • ✨️ 2024年终总结 - 23岁正是折腾的年纪 从开发到产品 | 日本旅行 | 捣鼓项目 | 技术写
    序毕业一年多了,按照大家通常采用的“四舍五入”的算法,我已经是一个有两年经验的工程师了。在写这篇24年总结的时候,先回看了一下23年的总结,不得不感叹时间真的过得好快,明明感觉大学毕业也没多久,但竟然已经是一年多前的事情了。再回看24年,在工作和生活方面也找到了一个不错的......
  • go项目zero中自定义sdk的引用与使用规范
    在Go项目中,`gomodtidy`命令会自动删除没有直接引用的依赖。如果你的项目中某个SDK被引用但是没有在业务代码中直接使用,`gomodtidy`可能会将其清理掉,因为它被认为是"未使用"的依赖。如果你希望保留这些依赖(例如某些SDK),可以采取以下几种方法:###1.显式调用SDK中......
  • 企业项目管理工具选择:多维度评估,精准决策
    企业在选择适合自己的项目管理工具时,需要考虑多个因素以确保所选工具能够满足企业的具体需求和目标。以下是一些建议的步骤和考虑因素:一、明确需求●梳理业务:企业需要梳理自己的业务,明确项目类型、规模、复杂度以及参与人员等。●需求分析:基于业务梳理,进行需求分析,确定项目......
  • 科技项目怎么查新
    对于许多刚开始从事科研的宝宝们来说,好不容易完成了一项科技发明,想要参加比赛以证明自己的科研水平并让项目获得更高的认可,但是却被告知需要出具相关的查新报告。很多宝宝可能就会懵掉,只知道查新报告是证明项目新颖性的材料,但是对科技项目的查新流程、如何开具查新报告不甚了......
  • 第3.5.1章 Ceres库最全总结及在机器人SLAM方面的项目应用实例
    以下是关于Ceres库的详细介绍:目录Ceres库的用途Ceres库头文件分类及应用场景Ceres库头文件中函数和类的用法及代码实例机器人SLAM方面的项目应用实例及高频函数和类Ceres库的用途Ceres库是一个开源的C++库,主要用于解决非线性最小二乘问题。它提供了一种灵活且高效......
  • 【前端进阶】在AI浪潮下前端如何结合应用于程序中,如:Brain.js创建模型
    前端和人工智能(AI)的结合可以创造非常丰富的用户体验,从简单的基于规则的交互到复杂的机器学习模型驱动的功能。在Web应用程序中集成AI可以增强用户交互、个性化内容推荐、图像和语音识别、自然语言处理等。前端与AI的结合应用聊天机器人(Chatbots):通过集成NLP(自然语言处理)技......
  • 新项目如何开展测试工作
    有同学问了这样一个问题:一个新项目,测试团队进组较早,目前需求没定,但架构设计已经完成的差不多了,这个阶段测试团队可以做哪些事情?对于稳定的项目来说,需求基本都是在已有功能上进行迭代。无论研发测试交付流程,还是基础技术设施建设,都已经趋于完善。团队内部各成员的协作配合也有了......
  • 基于JAVA中的spring框架和jsp实现驾驶知识学习和评测系统项目【附项目源码+论文说明】
    摘要在21世纪这个信息高度发达,并且高速流通的时代,计算机的普及以及计算机网络技术的应用,让大量普通人能够有机会接触到比以往更多的知识。作为一个以传播知识为主要职能的机构——学校,建立一个自己的精品课程网站是十分必要的事情,这不仅能使更多的人享用宝贵的教育资料源,同时......
  • Camel-AI项目模块详解
    前提内容快捷键在Pycharm中使用ctrl+F12查看类中所有方法查看某一个类中的方法的实现类:鼠标点到方法名字上右键→goto→Implementationscamel项目目录如下:camel/├──agents/#智能体相关代码├──models/#模型集成与管理├......
  • 基于JAVA中的spring框架和jsp实现大学生综合测评系统项目【内附项目源码+论文说明】
    摘要大学生综合测评系统是一款以大学生德智体等综合成绩进行评测的系统, 其开发基于B/S模式的网上评测的实现,采用的是JSP+sqlserver数据库为主要模式。在线评测平台是凌架于互联网系统上的一个评测平台,是地面评测系统的一种延伸和互补,也是实现无纸化评测的主要工具。当下在......