前言
- CMake是一个跨平台的安装编译工具,可以用简单的语句来描述所有平台的安装(编译过程)。
- CMake可以说已经成为大部分C++开源项目标配
1. Cross-platform development
Let’s assume you have some cross-platform project with C++ code shared along different platforms/IDEs. Say you use Visual Studio on Windows, Xcode on OSX and Makefile for Linux: What you will do if you want to add new bar.cpp source file? You have to add it to every tool you use: To keep the environment consistent you have to do the similar update several times. And the most important thing is that you have to do it manually (arrow marked with a red color on the diagram in this case). Of course such approach is error prone and not flexible.
CMake solve this design flaw by adding extra step to development process. You can describe your project in CMakeLists.txt file and use CMake to generate tools you currently interested in using cross-platform CMake code: Same action - adding new bar.cpp file, will be done in one step now:
Note that the bottom part of the diagram was not changed. I.e. you still can keep using your favorite tools like Visual Studio/msbuild , Xcode/xcodebuild and Makefile/make !
2. 语法特性介绍
基本语法格式:指令(参数 1 参数 2…)
- 参数使用括弧括起
- 参数之间使用空格或分号分开
- 指令是大小写无关的,参数和变量是大小写相关的
1 set(HELLO hello.cpp)
2 add_executable(hello main.cpp hello.cpp)
3 ADD_EXECUTABLE(hello main.cpp ${HELLO})
- 变量使用${}方式取值,但是在 IF 控制语句中是直接使用变量名
3. 重要指令和CMake常用变量
3.1 重要指令
- cmake_minimum_required - 指定CMake的最小版本要求
1
2 cmake_minimum_required(VERSION 2.8.3)
语法:cmake_minimum_required(VERSION versionNumber [FATAL_ERROR])
- project - 定义工程名称,并可指定工程支持的语言
1
2 project(HELLOWORLD)
语法:project(projectname [CXX] [C] [Java])
1
2 set(SRC sayhello.cpp hello.cpp)
- include_directories - 向工程添加多个特定的头文件搜索路径 —>相当于指定g++编译器的-I参数
1
2 include_directories(/usr/include/myincludefolder ./include)
- link_directories - 向工程添加多个特定的库文件搜索路径 —>相当于指定g++编译器的-L参数
1
2 link_directories(/usr/lib/mylibfolder ./lib)
- add_library - 生成库文件
1
2 add_library(hello SHARED ${SRC})
语法:add_library(libname [SHARED|STATIC|MODULE] [EXCLUDE_FROM_ALL] source1 source2 … sourceN)
- add_compile_options - 添加编译参数
1
2 add_compile_options(-Wall -std=c++11 -O2)
1
2 add_executable(main main.cpp)
语法:add_library(exename source1 source2 … sourceN)
- target_link_libraries - 为 target 添加需要链接的共享库 —>相同于指定g++编译器-l参数
1
2 target_link_libraries(main hello)
语法:target_link_libraries(target library1library2…)
- add_subdirectory - 向当前工程添加存放源文件的子目录,并可以指定中间二进制和目标二进制存放的位置
1
2 add_subdirectory(src)
语法:add_subdirectory(source_dir [binary_dir] [EXCLUDE_FROM_ALL])
- aux_source_directory - 发现一个目录下所有的源代码文件并将列表存储在一个变量中,这个指令临时被用来自动构建源文件列表
1
2 aux_source_directory(. SRC)
3
4 add_executable(main ${SRC})
语法:aux_source_directory(dir VARIABLE)
3.2 CMake常用变量
- CMAKE_C_FLAGS gcc编译选项
- CMAKE_CXX_FLAGS g++编译选项
1
2 set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
- CMAKE_BUILD_TYPE 编译类型(Debug, Release)
1
2 set(CMAKE_BUILD_TYPE Debug)
3
4 set(CMAKE_BUILD_TYPE Release)
CMAKE_BINARY_DIR PROJECT_BINARY_DIR __BINARY_DIR 1.这三个变量指代的内容是一致的。 2.如果是 in source build,指的就是工程顶层目录。 3.如果是 out-of-source 编译,指的是工程编译发生的目录。 4.PROJECT_BINARY_DIR 跟其他指令稍有区别,不过现在,你可以理解为他们是一致的。
CMAKE_SOURCE_DIR PROJECT_SOURCE_DIR __SOURCE_DIR
- 这三个变量指代的内容是一致的,不论采用何种编译方式,都是工程顶层目录。
- 也就是在 in source build时,他跟 CMAKE_BINARY_DIR 等变量一致。
- PROJECT_SOURCE_DIR 跟其他指令稍有区别,现在,你可以理解为他们是一致的。
CMAKE_C_COMPILER:指定C编译器 CMAKE_CXX_COMPILER:指定C++编译器 EXECUTABLE_OUTPUT_PATH:可执行文件输出的存放路径 LIBRARY_OUTPUT_PATH:库文件输出的存放路径
4 CMake编译工程
CMake目录结构:项目主目录存在一个CMakeLists.txt文件
两种方式设置编译规则:
- 包含源文件的子文件夹包含CMakeLists.txt文件,主目录的CMakeLists.txt通过add_subdirectory添加子目录即可;
- 包含源文件的子文件夹未包含CMakeLists.txt文件,子目录编译规则体现在主目录的CMakeLists.txt中;
4.1 编译流程
在 linux 平台下使用 CMake 构建C/C++工程的流程如下:
- 手动编写
CmakeLists.txt 。 - 执行命令
cmake PATH 生成 Makefile ( PATH 是顶层CMakeLists.txt 所在的目录 )。 - 执行命令
make 进行编译。
4.2 两种构建方式
**内部构建(in-source build):**不推荐使用
内部构建会在同级目录下产生一大堆中间文件,这些中间文件并不是我们最终所需要的,和工程源文件放在一起会显得杂乱无章。
1
2
3
4 cmake .
5
6 make
外部构建(out-of-source build):推荐使用
将编译输出文件与源文件放到不同目录中
1
2
3
4 mkdir build
5
6 cd build
7
8 cmake ..
9 4. 执行make命令,生成target
10 make
5 【实战】CMake代码实践
针对第五章写的两个小项目来写对应的CMakeLists.txt:github地址
5.1 最小CMake工程
1
2 cmake_minimum_required(VERSION 3.0)
3
4
5 project (HELLO)
6
7
8 add_executable(hello_cmake main.cpp)
5.2 多目录工程 - 直接编译
1
2 cmake_minimum_required(VERSION 3.0)
3
4
5 project(SWAP)
6
7
8 include_directories( include )
9
10
11 add_subdirectory( src DIR_SRCS )
12
13
14 add_executable(swap_02 ${TEST_MATH})
15
16
17 target_link_libraries(${FS_BUILD_BINARY_PREFIX}sqrt ${LIBRARIES})
5.3 多目录工程 - 生成库编译
1
2 cmake_minimum_required(VERSION 3.0)
3
4
5 project(SWAP_LIBRARY)
6
7
8 add_compile_options("-Wall -std=c++11")
9
10
11 set( CMAKE_BUILD_TYPE Debug )
12
13
14 set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
15
16
17
18
19
20
21 add_library( swap_library STATIC src/Swap.cpp )
22
23 target_include_directories( swap_lib PUBLIC ${PROJECT_SOURCE_DIR}/include )
24
25
26
27
28
29
30 add_executable( swap_01 main.cpp )
31
32
33 target_link_libraries( swap_01 swap_liby )
|