前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布

CMake

作者头像
小飞侠xp
发布2019-01-03 09:57:19
1.7K0
发布2019-01-03 09:57:19
举报

理论上来说,任意一个c++程序都可以使用g++来编译,但当程序规模越来越大时,一个工程可能有许多的文件夹和源文件,这时输入的编译命令将会越来越长。因此,对于C++使用一些工程管理工具会更加高效。这里我们使用CMake。 在一个CMake工程中,我们会使用cmake命令生成一个Makefile文件,然后,用make命令根据这个 makefile文件的内容来编译整个工程。

入门案例:单个源文件
  1. 编写 CMakeLists.txt 首先编写 CMakeLists.txt 文件,并保存在与 main.cc 源文件同个目录下:
代码语言:javascript
复制
# 声明要求的cmake最低版本
cmake_minimum_required (VERSION 2.8)
# 声明一个cmake工程
project (HelloSLAM)
# 添加一个可执行程序
#语法 :add_executable(程序名 源代码文件)
add_executable(Demo main.cc)

CMakeLists.txt 文件用于告诉cmake我们要对这个目录下的文件做什么事情,CmakeLists.txt 文件的内容需要遵守cmake的语法。

编译项目

在当前目录执行 cmake . ,得到 Makefile 后再使用 make 命令编译得到 Demo1 可执行文件。

代码语言:javascript
复制
cmake .

得到Makefile后再使用make命令编译得到Demo1可执行文件

多个源文件

上面的例子只有单个源文件,现在假如把power函数单独写进一个名为MathFunctions的源文件里,使得这个工程变成如下形式:

代码语言:javascript
复制
./Demo2
    |
    +--- main.cc
    |
    +--- MathFunctions.cc
    |
    +--- MathFunctions.h

这个时候,CMakeLists.txt 可以改成如下的形式:

代码语言:javascript
复制
# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8)
# 项目信息
project (Demo2)
# 指定生成目标
add_executable(Demo main.cc MathFunctions.cc)

唯一的改动只是在 add_executable命令中增加了一个 MathFunctions.cc源文件。这样写当然没什么问题,但是如果源文件很多,把所有源文件的名字都加进去将是一件烦人的工作。更省事的方法是使用aux_source_directory命令,该命令会查找指定目录下的所有源文件,然后将结果存进指定变量名。其语法如下:

代码语言:javascript
复制
aux_source_directory(<dir> <variable>)

因此,可以修改 CMakeLists.txt 如下:

代码语言:javascript
复制
# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8)
# 项目信息
project (Demo2)
# 查找当前目录下的所有源文件
# 并将名称保存到 DIR_SRCS 变量
aux_source_directory(. DIR_SRCS)
# 指定生成目标
add_executable(Demo ${DIR_SRCS})

这样,CMake 会将当前目录所有源文件的文件名赋值给变量DIR_SRCS ,再指示变量 DIR_SRCS中的源文件需要编译成一个名称为Demo 的可执行文件。

多个目录,多个源文件

现在进一步将 MathFunctions.hMathFunctions.cc文件移动到 math 目录下。

代码语言:javascript
复制
./Demo3
    |
    +--- main.cc
    |
    +--- math/
          |
          +--- MathFunctions.cc
          |
          +--- MathFunctions.h

对于这种情况,需要分别在项目根目录 Demo3 和 math 目录里各编写一个 CMakeLists.txt 文件。为了方便,我们可以先将 math 目录里的文件编译成静态库再由 main 函数调用。 根目录中的 CMakeLists.txt :

代码语言:javascript
复制
# 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)

该文件添加了下面的内容: 第3行,使用命令 add_subdirectory指明本项目包含一个子目录 math,这样 math 目录下的CMakeLists.txt文件和源代码也会被处理 。第6行,使用命令 target_link_libraries 指明可执行文件 main 需要连接一个名为 MathFunctions 的链接库 。

子目录中的 CMakeLists.txt:

代码语言:javascript
复制
# 查找当前目录下的所有源文件
# 并将名称保存到 DIR_LIB_SRCS 变量
aux_source_directory(. DIR_LIB_SRCS)
# 生成链接库
add_library (MathFunctions ${DIR_LIB_SRCS})

在该文件中使用命令 add_librarysrc 目录中的源文件编译为静态链接库。

自定义编译选项

CMake 允许为项目增加编译选项,从而可以根据用户的环境和需求选择最合适的编译方案。

例如,可以将 MathFunctions 库设为一个可选的库,如果该选项为 ON ,就使用该库定义的数学函数来进行运算。否则就调用标准库中的数学函数库。 修改 CMakeLists 文件 第一步是在顶层的 CMakeLists.txt 文件中添加该选项:

代码语言:javascript
复制
# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8)
# 项目信息
project (Demo4)
# 加入一个配置头文件,用于处理 CMake 对源码的设置
configure_file (
  "${PROJECT_SOURCE_DIR}/config.h.in"
  "${PROJECT_BINARY_DIR}/config.h"
  )
# 是否使用自己的 MathFunctions 库
option (USE_MYMATH
       "Use provided math implementation" ON)
# 是否加入 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})

其中:

  1. 第7行的 configure_file 命令用于加入一个配置头文件 config.h ,这个文件由 CMake 从 config.h.in 生成,通过这样的机制,将可以通过预定义一些参数和变量来控制代码的生成。
  2. 第13行的 option 命令添加了一个 USE_MYMATH 选项,并且默认值为 ON
  3. 第17行根据 USE_MYMATH 变量的值来决定是否使用我们自己编写的 MathFunctions 库。
修改 main.cc文件

之后修改 main.cc]文件,让其根据 USE_MYMATH 的预定义值来决定是否调用标准库还是 MathFunctions 库:

代码语言:javascript
复制
#include 
#include 
#include "config.h"
#ifdef USE_MYMATH
  #include "math/MathFunctions.h"
#else
  #include 
#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 文件

上面的程序值得注意的是第2行,这里引用了一个 config.h 文件,这个文件预定义了 USE_MYMATH 的值。但我们并不直接编写这个文件,为了方便从 CMakeLists.txt 中导入配置,我们编写一个 config.h.in文件,内容如下:

代码语言:javascript
复制
#cmakedefine USE_MYMATH

这样 CMake 会自动根据 CMakeLists 配置文件中的设置自动生成 config.h 文件

编译项目 现在编译一下这个项目,为了便于交互式的选择该变量的值,可以使用 ccmake 命令

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019.01.02 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 入门案例:单个源文件
  • 编译项目
  • 多个源文件
  • 多个目录,多个源文件
  • 自定义编译选项
  • 修改 main.cc文件
  • 编写 config.h.in 文件
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档