重要指令
- cmake_minimum_required 指定CMAKE的最小版本
- 语法cmake_minimum_required(VERSION versionNumber [FATAL_ERROR])
# CMake最小版本要求为2.8.3
cmake_minimum_required(VERSION 2.8.3)
- project- 定义工程名称,并可指定工程支持的语言
- 语法:project(projectname [CXX] [C] [Java])
# 指定工程名为demo
project(demo)
- set- 显式的定义变量
- 语法:set(VAR [VALUE] [CACHE TYPE DOCSTRING [FORCE]])
# 定义SRC变量,其值为sayhello.cpp hello.cpp
set(SRC sayhello.cpp hello.cpp)
- include_directories - 向工程添加多个特定的头文件搜索路径 —>相当于指定g++编译器的-I参数
- 语法:include_directories([AFTER|BEFORE] [SYSTEM] dir1 dir2 …)
# 将/usr/include/myincludefolder 和 ./include 添加到头文件搜索路径
include_directories(/usr/include/myincludefolder ./include)
- ink_directories- 向工程添加多个特定的库文件搜索路径 —>相当于指定g++编译器的-L参数
- 语法:link_directories(dir1 dir2 …)
# 将/usr/lib/mylibfolder 和 ./lib 添加到库文件搜索路径
link_directories(/usr/lib/mylibfolder ./lib)
- add_compile_options - 添加编译参数
# 添加编译参数 -Wall -std=c++11 -O2
add_compile_options(-Wall -std=c++11 -O2)
- add_executable- 生成可执行文件
- add_executable(exe_name source1 source 2)
# 编译main.cpp生成可执行文件main
add_executable(main main.cpp)
- target_link_libraries- 为 target 添加需要链接的共享库—>相同于指定g++编译器-l参数
- 语法:target_link_libraries(target library1<debug | optimized> library2…)
# 将hello动态库文件链接到可执行文件main
target_link_libraries(main hello)
- add_subdirectory - 向当前工程添加存放源文件的子目录,并可以指定中间二进制和目标二进制存放的位置
- 语法: add_subdirectory(source_dir [binary_dir] [EXCLUDE_FROM_ALL])
# 添加src子目录,src中需有一个CMakeLists.txt
add_subdirectory(src)
- aux_source_directory - 发现一个目录下所有的源代码文件并将列表存储在一个变量中,这个指令临时被用来自动构建源文件列表
- 语法:aux_source_directory(dir VARIABLE)
# 定义SRC变量,其值为当前目录下所有的源代码文件
aux_source_directory(. SRC)
# 编译SRC变量所代表的源代码文件,生成main可执行文件
add_executable(main ${SRC})
构建方式
- 内部构建(in-source build):和源码在一起build,会显得杂乱无章
# 在当前目录下,编译本目录的CMakeLists.txt,生成Makefile和其他文件
cmake .
# 执行make命令,生成target
make
- 外部构建(out-of-source build):将编译输出文件与源文件放到不同目录中
# 1. 在当前目录下,创建build文件夹
mkdir build
# 2. 进入到build文件夹
cd build
# 3. 编译上级目录的CMakeLists.txt,生成Makefile和其他文件
cmake ..
# 4. 执行make命令,生成target
make
常用变量
- CMAKE_CXX_FLAGS g++编译选项
# 在CMAKE_CXX_FLAGS编译选项后追加-std=c++11
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
- CMAKE_BUILD_TYPE编译类型(Debug, Release)
# 设定编译类型为debug,调试时需要选择debug
set(CMAKE_BUILD_TYPE Debug)
# 设定编译类型为release,发布时需要选择release
set(CMAKE_BUILD_TYPE Release)
-
CMAKE_BINARY_DIR, PROJECT_BINARY_DIR, _BINARY_DIR
- 这三个变量指代的内容是一致的。
- 如果是 in source build,指的是工程顶层目录
- 如果是 out-of-source 编译,值得是工程编译发生目录(build)
-
CMAKE_BINARY_DIR, PROJECT_BINARY_DIR, _BINARY_DIR
- 这三个变量指代的内容是一致的,不论采用何种编译方式,都是工程顶层目录
-
EXECUTABLE_OUTPUT_PATH:可执行文件输出的存放路径
-
LIBRARY_OUTPUT_PATH:库文件输出的存放路径
-
CMAKE_CXX_COMPILER:指定C++编译器
单个源文件
这时的源文件
#include <stdio.h>
#include <stdlib.h>
/**
* power - Calculate the power of number.
* @param base: Base value.
* @param exponent: Exponent value.
*
* @return base raised to the power exponent.
*/
double power(double base, int exponent)
{
int result = base;
int i;
if (exponent == 0) {
return 1;
}
for(i = 1; i < exponent; ++i){
result = result * base;
}
return result;
}
int main(int argc, char *argv[])
{
if (argc < 3){
printf("Usage: %s base exponent \n", argv[0]);
return 1;
}
double base = atof(argv[1]);
int exponent = atoi(argv[2]);
double result = power(base, exponent);
printf("%g ^ %d is %g\n", base, exponent, result);
return 0;
}
因为这时只有一个源文件,所以cmakelists也比较简单.
这里需要讲一下main函数的输入main(int argc, char *argv[])
- argc 是 argument count的缩写,表示传入main函数的参数个数;
- argv 是 argument vector的缩写,表示传入main函数的参数序列或指针,并且第一个参数argv[0]一定是程序的名称,并且包含了程序所在的完整路径,所以确切的说需要我们输入的main函数的参数个数应该是argc-1个
# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8)
# 项目信息
project (Demo1)
# 指定生成目标
add_executable(Demo main.cc)
这是最简单的cmakelists, 其包含
- cmake_minimum_required: 指定运行此配置文件所需的 CMake 的最低版本
- project:参数值是 Demo1,该命令表示项目的名称是 Demo1 。
- add_executable: 将名为 main.cc 的源文件编译成一个名称为 Demo 的可执行文件。
将上述文件配置好后,依次执行
cmake .
make
可得到一个可执行文件Demo
多个源文件
同一个目录
MathFunctions.cc
/**
* power - Calculate the power of number.
* @param base: Base value.
* @param exponent: Exponent value.
*
* @return base raised to the power exponent.
*/
double power(double base, int exponent)
{
int result = base;
int i;
if (exponent == 0) {
return 1;
}
for(i = 1; i < exponent; ++i){
result = result * base;
}
return result;
}
MathFunctions.h
#ifndef POWER_H
#define POWER_H
extern double power(double base, int exponent);
#endif
main.cc
#include <stdio.h>
#include <stdlib.h>
#include "MathFunctions.h"
int main(int argc, char *argv[])
{
if (argc < 3){
printf("Usage: %s base exponent \n", argv[0]);
return 1;
}
double base = atof(argv[1]);
int exponent = atoi(argv[2]);
double result = power(base, exponent);
printf("%g ^ %d is %g\n", base, exponent, result);
return 0;
}
CMakeLists.txt
# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8)
# 项目信息
project (Demo2)
# 指定生成目标
add_executable(Demo main.cc MathFunctions.cc)
相对于第一个cmakelist。这里仅仅在add_executable里添加了一个MathFunctions.cc
如果文件过多,一个个的添加,太麻烦了
这时我们可以使用aux_source_directory命令
该命令会查找指定目录下的所有源文件,然后将结果存进指定变量名
格式 aux_source_directory(<dir> <variable>) (目录 将所有源文件加入变量名)
新的CMakeLists.txt
# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8)
# 项目信息
project (Demo2)
# 查找当前目录下的所有源文件
# 并将名称保存到 DIR_SRCS 变量
aux_source_directory(. DIR_SRCS)
# 指定生成目标
add_executable(Demo ${DIR_SRCS})
不同一个目录
这时由于main和函数不在同一个文件夹中,所以需要对main中的include进行修改
#include "math/MathFunctions.h"
主函数和mathFunction不在一个目录,这时需要在Demo3和math文件夹中各编写一个CMakeLists.txt文件。math文件夹中的cmakelists主要是将文件编译成静态库,再由main函数调用
# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8)
# 项目信息
project (Demo3)
# 查找当前目录下的所有源文件
# 并将名称保存到 DIR_SRCS 变量
aux_source_directory(. DIR_SRCS)
# 添加 math 子目录
add_subdirectory(math)
# 指定生成目标
add_executable(Demo main.cc)
# 添加链接库
target_link_libraries(Demo MathFunctions)
add_subdirectory(math) 包含子目录,使子目录的cmakelists也可被处理
target_link_libraries指明main函数需要一个MathFunctions的库
除此之外,我们还需要在math文件夹下添加一个CmakeLists.txt,目的是让其能编译成静态库
add_library (MathFunctions ${DIR_LIB_SRCS}) 将源文件编译成MathFunctions库
# 查找当前目录下的所有源文件
# 并将名称保存到 DIR_LIB_SRCS 变量
aux_source_directory(. DIR_LIB_SRCS)
# 生成链接库
add_library (MathFunctions ${DIR_LIB_SRCS})
自定义编译选项
将自定义的库作为一个可选项
例如,可以将 MathFunctions 库设为一个可选的库,如果该选项为 ON ,就使用该库定义的数学函数来进行运算。否则就调用标准库中的数学函数库。
CMakeLists.txt
# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8)
# 项目信息
project (Demo4)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
# 是否使用自己的 MathFunctions 库
option (USE_MYMATH
"Use provided maths implementation" ON)
# 加入一个配置头文件,用于处理 CMake 对源码的设置
configure_file (
"${PROJECT_SOURCE_DIR}/config.h.in"
"${PROJECT_BINARY_DIR}/config.h"
)
# 是否加入 MathFunctions 库
if (USE_MYMATH)
include_directories ("${PROJECT_SOURCE_DIR}/math")
add_subdirectory (math)
set (EXTRA_LIBS ${EXTRA_LIBS} MathFunctions)
endif (USE_MYMATH)
# 查找当前目录下的所有源文件
# 并将名称保存到 DIR_SRCS 变量
aux_source_directory(. DIR_SRCS)
# 指定生成目标
add_executable (Demo ${DIR_SRCS})
target_link_libraries (Demo ${EXTRA_LIBS})
- configure_file 命令用于加入一个配置头文件 config.h ,这个文件由 CMake 从
config.h.in 生成,通过这样的机制,将可以通过预定义一些参数和变量来控制代码的生成。- set(CMAKE_INCLUDE_CURRENT_DIR ON) 使得能够包含本地新生成的config.h
- option命令添加了一个 USE_MYMATH 选项,并且默认值为 ON 。
- 判断句根据USE_MYMATH的值,开决定是否编译库
main也需要修改。根据USE_MYMATH的值决定用哪个库
#include <stdio.h>
#include <stdlib.h>
#include "config.h"
#ifdef USE_MYMATH
#include "math/MathFunctions.h"
#else
#include <math.h>
#endif
int main(int argc, char *argv[])
{
if (argc < 3){
printf("Usage: %s base exponent \n", argv[0]);
return 1;
}
double base = atof(argv[1]);
int exponent = atoi(argv[2]);
#ifdef USE_MYMATH
printf("Now we use our own Math library. \n");
double result = power(base, exponent);
#else
printf("Now we use the standard library. \n");
double result = pow(base, exponent);
#endif
printf("%g ^ %d is %g\n", base, exponent, result);
return 0;
}
编写 config.h.in 文件
上述main文件include了config.h 文件,这个文件预定义了 USE_MYMATH 的值。但我们并不直接编写这个文件,为了方便从 CMakeLists.txt 中导入配置,我们编写一个 config.h.in 文件,内容如下
#cmakedefine USE_MYMATH
编译项目,这时我们可使用交互式编译方式,编译该项目
# 交互式配置界面
ccmake .
# 完成配置
c
# 生成Makefile
g
Reference
5. C++ main函数中参数argc和argv含义及用法
6. CMAKE入门实战
7. cmake tutorials