CMake 七步入门
前言
CMake是什么? 官网给出的定义是这样的:”an open-source, cross-platform family of tools designed to build, test and package software”。很容易理解它是一个编译工具,是一个测试工具,也是一个打包工具,它其实就是一个工具箱,可以完成编译,测试以及打包的工作。在使用OpenCV的时候,已经对CMake有了认识。
CMake是跨平台的,这里就win7系统下结合Visual Studio的使用给出一点说明,本文主要内容是基于官方的使用文档,个人认为,官方的文档一直是学习新知识的第一手资料。
Step 1 基础
最简单的应用就是直接利用源码文件来编译可执行程序,利用有这样一份源码,计算一个数的平方根。文件名为tutorial.cpp,代码如下
#tutorial.cpp
// A simple program that computes the square root of a number
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main (int argc, char *argv[])
{
if (argc < 2)
{
fprintf(stdout,"Usage: %s number\n",argv[0]);
return 1;
}
double inputValue = atof(argv[1]);
double outputValue = sqrt(inputValue);
fprintf(stdout,"The square root of %g is %g\n",
inputValue, outputValue);
return 0;
}
这里生成一个简单的VS工程,只需要给出一个有2行命令的CMakeLists.txt文件,文件内容是这样的:
cmake_minimum_required (VERSION 2.6)
project (Tutorial)
add_executable(Tutorial tutorial.cpp)
利用上面CMakeLists文件,可以生成一个名为Tutorial的工程文件。
假设你已安装好CMake程序,并且版本号是2.6以上的。打开CMake,按如图界面操作:
其中源文件路径就是放置上述Tutorial.cpp以及CMakeLists.txt文件的位置,编译路径是一个空目录。配置编译器时,会提示创建build文件夹,点击确定。编译器的配置如图,根据实际情况选择,这里选择VS2010。
点击Generate,生成工程文件,如图:
编译运行结果:
针对上述这样一个简单的CMakeLists.txt,首先我们添加程序的版本号以及工程的配置文件。为配置程序版本号,我们修改CMakeLists.txt:
cmake_minimum_required (VERSION 2.6)
project (Tutorial)
# The version number.
set (Tutorial_VERSION_MAJOR 1)
set (Tutorial_VERSION_MINOR 0)
# configure a header file to pass some of the CMake settings
# to the source code
configure_file (
"${PROJECT_SOURCE_DIR}/config.h.in"
"${PROJECT_BINARY_DIR}/config.h"
)
# add the binary tree to the search path for include files
# so that we will find config.h
include_directories("${PROJECT_BINARY_DIR}")
# add the executable
add_executable(Tutorial tutorial.cpp)
接着,我们在源文件路径下创建一个文件config.h.in,内容为:
// the configured options and settings for Tutorial
#define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@
#define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@
当CMake配置congfig.h文件时,@Tutorial_VERSION_MAJOR@以及
@Tutorial_VERSION_MINOR@的值就会被替换成CMakeLists.txt中设置的值。
最后,我们修改tutorial.cpp,添加包含配置头文件,并使用版本号变量。
// A simple program that computes the square root of a number
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "TutorialConfig.h"
int main (int argc, char *argv[])
{
if (argc < 2)
{
fprintf(stdout,"%s Version %d.%d\n",
argv[0],
Tutorial_VERSION_MAJOR,
Tutorial_VERSION_MINOR);
fprintf(stdout,"Usage: %s number\n",argv[0]);
return 1;
}
double inputValue = atof(argv[1]);
double outputValue = sqrt(inputValue);
fprintf(stdout,"The square root of %g is %g\n",
inputValue, outputValue);
return 0;
}
编译运行结果如图:
step 2 添加依赖库
这里为工程添加一个依赖库,这个库的功能就是计算一个数的平方根。首先,在源文件路径下新建一个子目录MathFunc,定义使用的库函数:头文件MathFunc.h,源文件mysqrt.cpp以及CMakeLists.txt。
//MathFunc.h
double mysqrt(double x);
//mysqrt.cpp
#include "MathFunc.h"
#include <stdio.h>
// a hack square root calculation using simple operations
double mysqrt(double x)
{
if (x <= 0) {
return 0;
}
double result;
double delta;
result = x;
// do ten iterations
int i;
for (i = 0; i < 10; ++i) {
if (result <= 0) {
result = 0.1;
}
delta = x - (result * result);
result = result + 0.5 * delta / result;
fprintf(stdout, "Computing sqrt of %g to be %g\n", x, result);
}
return result;
}
CMakeLists.txt
add_library(MathFunc mysqrt.cpp)
接下来,修改主目录(源文件路径)下的CMakeLists.txt,让主工程能够调用子目录下的库函数,同时,添加一个可选项,可以选择是否使用该库函数。修改如下:
cmake_minimum_required (VERSION 2.6)
project (Tutorial)
# The version number.
set (Tutorial_VERSION_MAJOR 1)
set (Tutorial_VERSION_MINOR 0)
# should we use our own math functions
option(USE_MYMATH "Use tutorial provided math implementation" ON)
# configure a header file to pass some of the CMake settings
# to the source code
configure_file (
"${PROJECT_SOURCE_DIR}/config.h.in"
"${PROJECT_BINARY_DIR}/config.h"
)
# add the binary tree to the search path for include files
# so that we will find config.h
include_directories ("${PROJECT_BINARY_DIR}")
# add the MathFunc library?
if (USE_MYMATH)
include_directories ("${PROJECT_SOURCE_DIR}/MathFunc")
add_subdirectory (MathFunc)
set (EXTRA_LIBS ${EXTRA_LIBS} MathFunc)
endif ()
# add the executable
add_executable (Tutorial tutorial.cpp)
target_link_libraries (Tutorial ${EXTRA_LIBS})
修改主函数代码,如下:
// A simple program that computes the square root of a number
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "config.h"
#ifdef USE_MYMATH
#include "MathFunc.h"
#endif
int main (int argc, char *argv[])
{
if (argc < 2)
{
fprintf(stdout,"%s Version %d.%d\n",
argv[0],
Tutorial_VERSION_MAJOR,
Tutorial_VERSION_MINOR);
fprintf(stdout,"Usage: %s number\n",argv[0]);
return 1;
}
double inputValue = atof(argv[1]);
#ifdef USE_MYMATH
double outputValue = mysqrt(inputValue);
#else
double outputValue = sqrt(inputValue);
#endif
fprintf(stdout,"The square root of %g is %g\n",
inputValue, outputValue);
return 0;
}
最后,修改配置文件config.h.in,在文件末尾添加如下一行内容:
#cmakedefine USE_MYMATH
编译运行结果如图:
step 3 安装与测试
这里将在CMakeLists文件中添加安装规则与测试支持命令。
首先在子目录MathFunc中的CMakeLists.txt添加如下安装指令:
install (TARGETS MathFunc DESTINATION bin)
install (FILES MathFunc.h DESTINATION include)
然后修改主目录下CMakeLists.txt末尾添加如下内容:
# add the install targets
install (TARGETS Tutorial DESTINATION bin)
install (FILES "${PROJECT_BINARY_DIR}/config.h"
DESTINATION include)
在CMake界面中可以设置安装路径,如图:
在VS工程中可看到安装选项,右击生成即可将项目文件安装到指定目录。
在主目录下的CMakeLists.txt结尾可加入测试用例,验证程序是否能正常运行。
include(CTest)
#define a macro to simplify adding tests, then use it
macro (do_test arg result)
add_test (TutorialComp${arg} Tutorial ${arg})
set_tests_properties (TutorialComp${arg}
PROPERTIES PASS_REGULAR_EXPRESSION ${result})
endmacro (do_test)
# do a bunch of result based tests
do_test (25 "25 is 5")
do_test (-25 "-25 is 0")
# does it handle negative numbers
add_test (TutorialNegative Tutorial -25)
set_tests_properties (TutorialNegative PROPERTIES
ASS_REGULAR_EXPRESSION "-25 is 0")
# does it handle small numbers
add_test (TutorialSmall Tutorial 0.0001)
set_tests_properties (TutorialSmall PROPERTIES
ASS_REGULAR_EXPRESSION "0.0001 is 0.01")
# does the usage message work?
add_test (TutorialUsage Tutorial)
set_tests_properties (TutorialUsage PROPERTIES
测试结果:
step 4-7
至此,CMake的应用有了初步了解和认识。CMake还有其他的功能与特性有待了解,比如CheckFunctionExists.cmake 宏的使用,Generated File and Generator的使用,生成安装包文件等等。具体内容可参考这里。
Unicorn Lewis, 04.08.2017