CMake 是一个跨平台的构建系统生成工具,在Linux环境下使用CMake来构建C/C++项目时,使用CMakeLists.txt实现项目快速构建。下面使用CMake命令构建项目:
1. 构建一个简单项目的CMakeLists.txt
对于以下简单的项目目录
├── CMakeLists.txt
└── test.cpp
CMakeLists.txt内容如下
cmake_minimum_required(VERSION 3.10)
project(test LANGUAGES C CXX)
add_executable(test_project test.cpp)
-
cmake_minimum_required用于指定本项目CMake的最低版本要求,如果CMake的版本低于指定的版本要求,则会报错。
-
project定义项目的名称和语言,MyProject是项目的名称,它会被赋值给cmake的预定义变量 ${PROJECT_NAME},并且可以在整个 CMakeLists.txt 文件中使用这个变量来引用项目名称。LANGUAGES C CXX表示项目使用的编程语言。在这个例子中,表示项目使用C和C++语言。
-
add_executable: 添加源文件和目标并生成一个可执行文件,并指定该可执行文件的所有源文件列表,如果源文件过多,推荐使用
aux_source_directory(. SRC_LIST) add_executable(test_project ${SRC_LIST})
-
aux_source_directory表示将当前路径的所有源文件列表添加到SRC_LIST变量中,就可以使用${SRC_LIST}作为add_executable的源文件列表。
2. 生成可执行文件
-
在当前目录创建build文件夹,原因是cmake可以直接使用上一级目录的CMakeLists.txt自动生成Makefile,这样能够保证生成的文件不会与源文件混在一起,此时目录和CMakeLists.txt如下
├── build ├── CMakeLists.txt └── test.cpp
cmake_minimum_required(VERSION 3.1) project(test LANGUAGES C CXX) aux_source_directory(. SRC_LIST) add_executable(test_project ${SRC_LIST})
-
在build目录下执行cmake,构建系统文件
cmake ..
-
再使用make命令自动编译源代码、链接库文件,并生成当前文件或库
make
-
构建成功后,在build目录如下
├── CMakeCache.txt
├── CMakeFiles
├── cmake_install.cmake
├── Makefile
└── test_project -
test_project是生成的可执行文件,能够直接运行
3. 多级目录项目构建
在实际项目中,通常会将项目分成多个目录,每个目录包含一个或多个源文件和头文件,通常需要每个目录都有一个CMakeLists.txt文件,在Ubuntu环境,例如有如下嵌套型的目录结构:
└── test
├── CMakeLists.txt
├── example
│ ├── CMakeLists.txt
│ ├── demo
│ │ ├── CMakeLists.txt
│ │ ├── demo.cpp
│ │ └── demo.hpp
│ ├── example.cpp
│ └── example.hpp
├── include
│ ├── CMakeLists.txt
│ ├── detail.cpp
│ └── detail.hpp
└── test.cpp
-
对于内层的目录test/example/demo/CMakeLists.txt如下:
aux_source_directory(. t_SRCS) add_library(demo ${t_SRCS})
-
aux_source_directory命令来获取源文件列表,然后使用add_library创建一个库,add_library一般有动态库和静态库两种形式,STATIC表示生成静态库,SHARED表示生成动态库(默认为静态库):
- add_library(库名 STATIC 源文件列表)
- add_library(库名 SHARED 源文件列表)
-
对于外层的目录test/example/CMakeLists.txt如下,:
aux_source_directory(. SRCS) aux_source_directory(demo DEMO_SRCS) include_directories(demo) add_library(example ${SRCS} ${DEMO_SRCS})
-
除了包含example目录的源文件外,需要再将子目录demo加到变量中,使用include_directories指定编译器在编译源文件时搜索头文件的路径(仅影响项目路径,不影响生成的构建目标),最后使用add_library生成一个当前目录的库。
-
同样,对于test/include/CMakeLists.txt如下:
aux_source_directory(. SRCS) add_library(include ${SRCS})
-
test/CMakeLists.txt如下:
cmake_minimum_required(VERSION 3.1) project(test) aux_source_directory(. SRC_LIST) add_subdirectory(example) add_subdirectory(include) add_executable(test_project ${SRC_LIST}) target_link_libraries(test_project example include)
-
使用add_subdirectory命令向当前工程添加存放源文件的子目录example和include,并在指定的子目录中查找 CMakeLists.txt文件,并将其内容包含到当前构建中
-
最后需要使用target_link_libraries,为目标文件链接库文件,稍大型项目需要注意链接顺序,一般为:直接依赖库-间接依赖库-系统库
-
在build目录下进行构建,结果如下:
成功运行
4. 添加编译选项
项目中会有添加编译选项需求,如指定语言版本,设置编译器调试标志,设置交叉编译等,可以通过指定语句添加,也可通过SET命令定义或修改变量和cmake的预定义变量实现,SET用法:
SET(VARIABLE_NAME value)
-
SET与预定义变量结合示例:
set(CROSS_COMPILE ON) set(CMAKE_SYSTEM_NAME Linux)
-
表示开启交叉编译,并指定当前系统为Linux
SET(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g")
-
设置调试标志,$ENV{CXXFLAGS}是从环境变量中获取现有的CXXFLAGS,-O0表示关闭所有优化,-Wall表示启用所有常见的警告信息,-g表示生成调试信息
以下给出一些常用的预定义变量:
CMAKE_SOURCE_DIR:根CMakeLists.txt所在的目录路径。
CMAKE_BINARY_DIR:构建目录的路径。
PROJECT_SOURCE_DIR:当前项目的根目录路径。
PROJECT_BINARY_DIR:当前项目的构建目录路径。
CMAKE_CURRENT_SOURCE_DIR:当前处理的CMakeLists.txt所在的目录路径。
CMAKE_CURRENT_BINARY_DIR:当前处理的构建目录路径。
CMAKE_COMMAND:CMake可执行文件的完整路径。
CMAKE_C_COMPILER:C编译器的路径。
CMAKE_CXX_COMPILER:C++编译器的路径。
CMAKE_BUILD_TYPE:构建类型(如Debug、Release)。
CMAKE_SYSTEM_NAME:系统名称(如Linux、Windows)。
CMAKE_SIZEOF_VOID_P:指针大小(用于判断32位或64位)。
-
cmake中同样可以使用if else和比较运算符用于条件判断,可以与预定义变量结合使用,基本用法如下:
set(VALUE 10) if(CMAKE_SIZEOF_VOID_P EQUAL 8) message("message") elseif(VALUE GREATER 5) message("VALUE is greater than 5") else() message("VALUE is less than or equal to 5") endif()
推荐一个c/c++内容学习平台
https://github.com/0voice