CMake实战

本文不介绍cmake命令使用方法,也不讲CMakeLists.txt的语法,有需要的读者可以看我另外相关的文章即可(此为实战篇)。

本文核心讲解添加版本支持、添加编译库支持、添加编译选项支持、添加库版本信息、添加多文件支持、添加安装路劲支持、添加测试验证支持、添加依赖函数与头文件与库文件支持、添加三方库依赖搜索支持、添加生成中间文件支持、添加生成发行版本安装包支持等功能

本文共分14章,为了便于学习,内容组织如下:

  • 前面1~7章为基本常用方法,可满足大部分项目需求;

  • 接下来三(8~10)章节非常简单,用于支持依赖的检测,便于学习人员歇口气;

  • 后面的11~14章为高级功能,可以查询未知依赖、生成中间依赖文件,还可以制作标准的安装包。

废话少说,直接上主菜(复杂的解释也略过了)。有需要的,可以联系我获取每章节的实例。

一、基本工程

最简单的工程是编译一个源文件,并生成一个可执行文件。CMakeLists.txt仅仅只需要3行:


cmake_minimum_required(VERSION 2.8)

project(Tutorial)

add_executable(Tutorial tutorial.cxx)

对应的tutorial.cxx源码用于计算输入数据的平方根:


// A simple program that computes the suqare 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;

}

将tutorial.cxx与CMakeLists.txt放在同一目录,创建build目录,并编译、运行,结果如下:


$ mkdir build

$ ls

build  CMakeLists.txt  tutorial.cxx

$ cd build/

$ cmake ..

-- The C compiler identification is GNU 4.8.5

-- The CXX compiler identification is GNU 4.8.5

-- Check for working C compiler: /usr/bin/cc

-- Check for working C compiler: /usr/bin/cc -- works

-- Detecting C compiler ABI info

-- Detecting C compiler ABI info - done

-- Detecting C compile features

-- Detecting C compile features - done

-- Check for working CXX compiler: /usr/bin/c++

-- Check for working CXX compiler: /usr/bin/c++ -- works

-- Detecting CXX compiler ABI info

-- Detecting CXX compiler ABI info - done

-- Detecting CXX compile features

-- Detecting CXX compile features - done

-- Configuring done

-- Generating done

-- Build files have been written to: /work/study/Studied_Module/Module/cmake/basic_point/build

$ make

Scanning dependencies of target Tutorial

[ 50%] Building CXX object CMakeFiles/Tutorial.dir/tutorial.cxx.o

[100%] Linking CXX executable Tutorial

[100%] Built target Tutorial

$ ./Tutorial

Usage: ./Tutorial number

$ ./Tutorial 9

The square root of 9 is 3

二、添加配置头文件

有时候我们需要为我们的代码添加版本信息,或者其他相关的配置信息。我们当然可以通过直接添加配置的头文件来实现,不过通过CMakeLists.txt来实现会更加的灵活。下面是基于前面例子实现添加版本信息的CMakeLists.txt:


cmake_minimum_required(VERSION 2.8)

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}/TutorialConfig.h.in"

"${PROJECT_BINARY_DIR}/TutorialConfig.h"

)

# add the binary tree to the search path for include files

# so that we will find TutorialConfig.h

include_directories("${PROJECT_BINARY_DIR}")

# add the executable

add_executable(Tutorial tutorial.cxx)

上面指定TutorialConfig.h由TutorialConfig.h.in文件生成。TutorialConfig.h.in的内容如下:


// the configured options and settings for Tutorial

#define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@

#define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@

当CMake配置这个头文件时,@Tutorial_VERSION_MAJOR@和@Tutorial_VERSION_MINOR@的值将被CMakeLists.txt文件中的值替换(注意两边的名字要一致)。

接下来我们修改tutorial.cxx源码,看是如何使用CMakeLists.txt定义的版本的:


// A simple program that computes the suqare 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;

}

建立build目录,再次编译结果如下:


$ mkdir build

$ ls

build  CMakeLists.txt  TutorialConfig.h.in  tutorial.cxx

$ cd build/

$ cmake ..

-- The C compiler identification is GNU 4.8.5

-- The CXX compiler identification is GNU 4.8.5

-- Check for working C compiler: /usr/bin/cc

-- Check for working C compiler: /usr/bin/cc -- works

-- Detecting C compiler ABI info

-- Detecting C compiler ABI info - done

-- Detecting C compile features

-- Detecting C compile features - done

-- Check for working CXX compiler: /usr/bin/c++

-- Check for working CXX compiler: /usr/bin/c++ -- works

-- Detecting CXX compiler ABI info

-- Detecting CXX compiler ABI info - done

-- Detecting CXX compile features

-- Detecting CXX compile features - done

-- Configuring done

-- Generating done

-- Build files have been written to: /work/study/Studied_Module/Module/cmake/basic_version/build

$ make

Scanning dependencies of target Tutorial

[ 50%] Building CXX object CMakeFiles/Tutorial.dir/tutorial.cxx.o

[100%] Linking CXX executable Tutorial

[100%] Built target Tutorial

$ ./Tutorial

./Tutorial Version 1.0

Usage: ./Tutorial number

$ ./Tutorial 16

The square root of 16 is 4

总结:添加配置头文件的流程如下:

  1. 在CMakeLists.txt中通过set命令设置自己命名的变量;

  2. 添加配置文件说明:


configure_file (

"${PROJECT_SOURCE_DIR}/TutorialConfig.h.in"

"${PROJECT_BINARY_DIR}/TutorialConfig.h"

)

  1. 创建配置文件*.h.in,并使用@variable@来访问第一步在CMakeLists.txt通过set定义的变量,使用C/C++的标准#define来定义;

  2. 在C/C++源码中通过include包含编译生成的配置头文件;

  3. 在C/C++源码中直接使用#define宏定义的名称。

三、添加一个库

继续基于前面的实例,我们将计算平方根的方法提取出来,做成一个mysqrt.cxx源文件库放在MathFunctions目录,我们提供的算法名称为mysqrt()。源码如下:


$ cd MathFunctions/

$ cat mysqrt.h

#ifndef MYSQRT_H__

#define MYSQRT_H__

double mysqrt(double x);

#endif

$ cat mysqrt.cxx

#include <stdio.h>

#include <stdlib.h>

#include <math.h>

double mysqrt(double x)

{

double g = x;

while(fabs(g*g - x) > 0.000001)

{

g = (g+x/g)/2;

}

return g;

}

在MathFunctions目录中添加子CMakeLists.txt,编译生成库文件:


$ cat CMakeLists.txt

cmake_minimum_required(VERSION 2.8)

project(MathFunctions)

add_library(MathFunctions SHARED mysqrt.cxx)

接下来修改顶层CMakeLists.txt,添加子目录MathFunctions的编译支持,添加头文件依赖路径,并添加依赖的库说明:


include_directories("${PROJECT_SOURCE_DIR}/MathFunctions")

add_library(MathFuncions)

# add the executable

add_executable(Tutorial tutorial.cxx)

add_link_libraries(Tutorial MathFunctions)

最后,修改tutorial.cxx源码,添加代码调用我们自己的mysqrt()函数(这里同时调用,还可以验证我们的算法是否正确):


    double inputValue = atof(argv[1]);

double outputValue = sqrt(inputValue);

fprintf(stdout, "The square root of %g is %g\n", inputValue, outputValue);

outputValue = mysqrt(inputValue);

fprintf(stdout, "The square root of %g is %g\n", inputValue, outputValue);

四、添加编译选项

继续接着前面的实例,我们添加了自己的mysqrt()函数,但是我们并不一定都是使用自己的mysqrt()函数,当系统提供了sqrt()时,我们肯定希望调用系统标准的函数。也就是说,我们需要根据系统情况,动态选择调用方法。

我们当然可以通过在头文件中添加编译选项来实现,不过通过CMakeLists.txt来实现将更加灵活有趣。

首先,我们定义一个编译宏USE_MYMATH(在顶层CMakeLists.txt):


# should we use our own math functions ?

option(USE_MYMATH

    "Use tutorial provided math implementation" ON)

这将告诉CMake默认打开USE_MYMATH,当然也可以通过ccmake或者编译选项来重新配置。接下来我们在顶层CMakeLists.txt同时添加依赖库的说明:


# add the MathFunctions library ?

#

if (USE_MYMATH)

    include_directories("${PROJECT_SOURCE_DIR}/MathFunctions")

    add_subdirectory(MathFunctions)

    set(EXTRA_LIBS ${EXTRA_LIBS} MathFunctions)

#endif(USE_MYMATH)

# add the executable

add_executable(Tutorial tutorial.cxx)

target_link_libraries(Tutorial ${EXTRA_LIBS})

注意:上面添加的USE_MYMATH选项的option命令,必须在configure_file命令之前,否则其默认ON的配置将会无效

接下来,修改tutorial.cxx源代码,添加条件编译代码:


// A simple program that computes the suqare root of a number

#include <stdio.h>

#include <stdlib.h>

#include <math.h>

#include "TutorialConfig.h"

#ifdef USE_MYMATH

#include "mysqrt.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);

fprintf(stdout, "The square root of %g is %g(use tutorial mysqrt())\n", inputValue, outputValue);

#else

double outputValue = sqrt(inputValue);

fprintf(stdout, "The square root of %g is %g(use system sqrt())\n", inputValue, outputValue);

#endif

return 0;

}

最后,在TutorialConfig.h.in中添加支持,以便在CMake命令行传入不同的编译选项时生成不同的TutorialConfig.h文件:


#cmakedefine USE_MYMATH

创建build目录,并编译验证结果如下:

使用mysqrt():


$ mkdir build

$ ls

build  CMakeLists.txt  MathFunctions  TutorialConfig.h.in  tutorial.cxx

$ cd build/

[study@konishi build]$ cmake -DUSE_MYMATH=True ..

-- The C compiler identification is GNU 4.8.5

-- The CXX compiler identification is GNU 4.8.5

-- Check for working C compiler: /usr/bin/cc

-- Check for working C compiler: /usr/bin/cc -- works

-- Detecting C compiler ABI info

-- Detecting C compiler ABI info - done

-- Detecting C compile features

-- Detecting C compile features - done

-- Check for working CXX compiler: /usr/bin/c++

-- Check for working CXX compiler: /usr/bin/c++ -- works

-- Detecting CXX compiler ABI info

-- Detecting CXX compiler ABI info - done

-- Detecting CXX compile features

-- Detecting CXX compile features - done

-- Configuring done

-- Generating done

-- Build files have been written to: /work/study/Studied_Module/Module/cmake/04_basic_options/build

$ make

Scanning dependencies of target MathFunctions

[ 25%] Building CXX object MathFunctions/CMakeFiles/MathFunctions.dir/mysqrt.cxx.o

[ 50%] Linking CXX shared library libMathFunctions.so

[ 50%] Built target MathFunctions

Scanning dependencies of target Tutorial

[ 75%] Building CXX object CMakeFiles/Tutorial.dir/tutorial.cxx.o

[100%] Linking CXX executable Tutorial

[100%] Built target Tutorial

$ ./Tutorial

./Tutorial Version 1.0

Usage: ./Tutorial number

$ ./Tutorial  12

The square root of 12 is 3.4641(use tutorial mysqrt())

使用系统的sqrt():


$ mkdir build

$ ls

build  CMakeLists.txt  MathFunctions  TutorialConfig.h.in  tutorial.cxx

$ cd build/

$ cmake -DUSE_MYMATH=False ..

-- The C compiler identification is GNU 4.8.5

-- The CXX compiler identification is GNU 4.8.5

-- Check for working C compiler: /usr/bin/cc

-- Check for working C compiler: /usr/bin/cc -- works

-- Detecting C compiler ABI info

-- Detecting C compiler ABI info - done

-- Detecting C compile features

-- Detecting C compile features - done

-- Check for working CXX compiler: /usr/bin/c++

-- Check for working CXX compiler: /usr/bin/c++ -- works

-- Detecting CXX compiler ABI info

-- Detecting CXX compiler ABI info - done

-- Detecting CXX compile features

-- Detecting CXX compile features - done

-- Configuring done

-- Generating done

-- Build files have been written to: /work/study/Studied_Module/Module/cmake/04_basic_options/build

$ make

Scanning dependencies of target Tutorial

[ 50%] Building CXX object CMakeFiles/Tutorial.dir/tutorial.cxx.o

[100%] Linking CXX executable Tutorial

[100%] Built target Tutorial

[study@konishi build]$ ./Tutorial

./Tutorial Version 1.0

Usage: ./Tutorial number

$ ./Tutorial 13

The square root of 13 is 3.60555(use system sqrt())

总结:添加配置选项的流程如下:

还有 69% 的精彩内容
©著作权归作者所有,转载或内容合作请联系作者
支付 ¥1.68 继续阅读
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容