什么是cmake
依据其官网的界说,cmake是一个开源跨渠道的,用于构建、测试和打包软件的一个套件东西。与cmake相关的几个概念需求明晰,如GCC,make和makefile。
- GCC:GCC是GNU Compiler Collection(便是GNU编译器套件),也能够简单认为是编译器,它能够编译许多种编程言语(括C、C++、Objective-C、Fortran、Java等等)
- make:make东西能够看成是一个智能的批处理东西,它本身并没有编译和链接的功能,而是用类似于批处理的方法经过调用makefile文件中用户指定的指令来进行编译和链接的。
- makefile,makefile便是GCC指令的调集,make东西就依据makefile中的指令进行编译和链接的
- cmake,当项目非常大时,手写makefile会非常烦碎,而且不同渠道makefile也会不同,所以cmake便是能够依据CMakeLists.txt自动生成makefile。
入门实践
咱们已经关于cmake有了一个总体上的认识,接下来就经过官方供给的几个比如介绍下怎么运用cmake。
构建单个源文件
项目只有一个源文件,结构如下,咱们一般会新建一个目录存储cmake运转的产物,这儿我新建了一个build目录。
├── CMakeLists.txt
├── build
└── main.cc
main.cc的内容如下
#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.txt的内容如下:
# Cmake的最低版本号的要求
cmake_minimum_required (VERSION 2.8)
# 项目信息
project (Demo1)
# 指定生成方针
add_executable(Demo main.cc)
在build目录下执行cmake .. 然后执行make指令就能够得到Demo1的可执行文件。
同一个目录,多个源文件
假如咱们将Demo1中main.cc的power函数抽取出来放到MathFunctions.cc中,项目结构如下:
├── CMakeLists.txt
├── MathFunctions.cc
├── MathFunctions.h
├── build
└── main.cc
那么该怎么编译呢,咱们能够经过在add_executable指令中增加将MathFunctions.cc,作用如下add_executable(Demo main.cc MathFunctions.cc),可是假如有许多文件的情况下,一个文件一个文件的增加很麻烦,cmake供给了aux_source_directory指令,该指令会查找指定目录下一切的源文件,然后将成果存到指定的变量名。CMakeLists.txt文件内容如下
# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8)
# 项目信息
project (Demo2)
# 查找目录下的一切源文件
# 并将称号保存到 DIR_SRCS 变量
aux_source_directory(. DIR_SRCS)
# 指定生成方针
add_executable(Demo ${DIR_SRCS})
多个目录多个源文件
现在咱们将MathFounction.h和MathFounction.cpp移动到math目录下,项目结构如下:
├── CMakeLists.txt
├── build
├── main.cc
└── math
├── CMakeLists.txt
├── MathFunctions.cc
└── MathFunctions.h
面对这种情况咱们需求在Demo3目录下和math目录下各自编写一个CmakeLists.txt文件,咱们能够将math目录里面的文件编译成静态库再由main函数调用。
Demo3目录下的CMakeLists.txt内容如下
# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8)
# 项目信息
project (Demo3)
# 查找目录下的一切源文件
# 并将称号保存到 DIR_SRCS 变量
aux_source_directory(. DIR_SRCS)
# 增加 math 子目录
add_subdirectory(math)
# 指定生成方针
add_executable(Demo ${DIR_SRCS})
# 增加链接库
target_link_libraries(Demo MathFunctions)
add_subdictory(math)指明本项目包含一个子目录math,这样,math目录下的CMakeLists.txt文件和源代码也会被运用,最终一行target_link_libraries指明可执行文件需求链接一个名为MathFunctions的链接库。math目录下CMakeLists.txt内容如下
# 查找当时目录下的一切源文件
# 并将称号保存到 DIR_LIB_SRCS 变量
aux_source_directory(. DIR_LIB_SRCS)
# 指定生成 MathFunctions 链接库
add_library (MathFunctions ${DIR_LIB_SRCS})
该文件中运用指令add_library将src目录中源文件编译为静态链接库
自界说编译选项
CMake答应为项目增加编译选项,从而能够依据用户的环境和要求挑选最合适的编译方案,例如能够将MathFunctions库设置为一个可选的库,假如该选项为ON,则运用该库界说的函数来进行运算,否则就调用标准库的数学函数库。
为了完成这样的意图咱们需求在顶层的CMakeLists.txt中增加该选项,其内容如下
cmake_minimum_required (VERSION 2.8)
# 项目信息
project (Demo4)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
# 是否运用自己的 MathFunctions 库
option (USE_MYMATH
"Use provided math 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生成,经过这样的机制能够经过预界说一些参数和变量来控制代码的生成,config.h.in内容如下:
#cmakedefine USE_MYMATH
其间的option指令增加了一个USE_MYMATH选项,并且默认值为ON。之后依据USE_MYMATH变量的值决定是否运用我门自己编写的MathFounctions库
然后需求更改main.cc文件让其依据USE_MYMATH的值确认是否调用标准库,内容如下:
#include <stdio.h>
#include <stdlib.h>
#include <config.h>
#ifdef USE_MYMATH
#include <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,这个文件预界说了 USE_MYMATH 的值。但咱们并不直接编写这个文件,而是由CMake依据config.h.in自动生成。
最终
这篇文章主要介绍了cmake的简单运用,更多文章能够关注公众号QStack。