zoukankan      html  css  js  c++  java
  • CMake快速入门教程

    前言

    Make工具因遵循不同的规范和标准,执行的Makefile的格式也是不同。主流的Make工具包括:

    • GNU Make
    • QT的qmake
    • 微软的 MS nmake
    • BSD的 pmake

    每个平台都有自己的工具,则带来了很大的平台兼容性问题。CMake是一种跨平台的编译工具。

    准备阶段:

    • 安装cmake
    • 编写CMake配置文件CMakeLists.txt

    基本流程:

    • 执行cmake PATH或者ccmake PATH命令,将CMakeLists.tx文件转化为所需要的Makefile文件。其中PATH为CMAKLISTs.txt所在的目录
    • 执行make命令,编译原码生成可执行程序,或者库文件

    单目录,单文件

    一个简单的样例:

    # CMake的最低版本要求
    cmake_minimum_required (VERIONS 2.8)
    
    # 项目信息
    project(Demo)
    
    # 指定生成目标
    add_executable(Demo demo.cc)
    

    语法规则:

    • 命令、空格、注释组成
    • 命令是不区分大小写的
    • 符号#后面内容为注释
    • 参数之间使用空格分隔

    单目录,多文件

    在实际项目中,一般不会只有一个demo.cc源码文件,常为一个目录下多个源文件。假设目录结构如下:

    ./Demo
      |-- main.cc
      |-- foo.cc
      |-- foo.h
    

    此时的CMakeLists.txt内容可以更新为如下:

    # CMake的最低版本要求
    cmake_minimum_required (VERIONS 2.8)
    
    # 项目信息
    project(Demo)
    
    # 指定生成目标
    add_executable(Demo demo.cc foo.cc)
    

    即只需要在add_executable里把依赖的foo.cc源文件添加进来即可。

    但引入另一个问题:新增的源文件越来越多,总不能一个个手动加进来吧?

    cmake中有 aux_source_directory命令,会查找指定目录下所有源文件,并存放到指定的变量名中:

    # CMake的最低版本要求
    cmake_minimum_required (VERIONS 2.8)
    
    # 项目信息
    project(Demo)
    
    # 查找当前目录下所有源文件
    aux_source_directory(. DIR_SRCS)
    
    # 指定生成目标
    add_executable(Demo ${DIR_SRCS})
    

    多目录,多文件

    针对一个项目中包含了多了层级目录,且每个目录下都包含一些源文件。若目录结构如下:

    ./Demo
      |-- main.cc
      |-- utils
      		|-- foo.cc
      		|-- foo.h
    

    我们需要分别在Demoutils目录下各自编写一个CMakeLists.txt文件。

    为了方便,可以先将utils目录里的文件编译成静态库,再由main函数调用。

    根目录中的CMakeLists.txt

    # CMake的最低版本要求,如果不满足则报错
    cmake_minimum_required (VERIONS 2.8 FATAL_ERROR)
    
    # 项目信息
    project(Demo)
    
    # 添加 math 子目录
    add_subdirectory(utils)
    
    # 指定生成目标
    add_executable(Demo main.cc)
    
    # 添加链接库
    target_link_libraries(Demo utils)
    
    • add_subdirectory表示会处理子目录下的CMakeLists.txt和源代码
    • target_link_libraries表示main执行文件需要链接一个名为utils的链接库

    utils目录中的CMakeLists.txt

    # 查找当前目录下的所有源文件、并保存到 DIR_LIB_SRCS 变量中
    aux_source_directory(. DIR_LIB_SRCS)
    
    # 生成链接库
    add_library(utils ${DIR_LIB_SRCS})
    
    • add_library会将所有源文件编译为静态链接库

    其他编译选项

    如下是一个项目的CMakeLists.txt:

    cmake_minimum_required(VERSION 2.8)
    
    project(Demo)
    
    # 定一个开关选项,支持cmake时通过 -DUSE_MYUTILS=OFF 指定
    option(USE_MYUITLS "whether use customized math" ON)
    
    # 自定义分支逻辑
    if(USE_MYUITLS)
      include_directories("{PROJECT_SOURCE_DIR}/utils")
      add_subdirectory(utils)
      set(EXTRA_LIBS ${EXTRA_LIBS} utils)
    endif(USE_MYUITLS)
    
    # 查找目录下所有源文件
    aux_source_directory(. DIR_SRCS)
    # 添加执行文件
    add_executable(Demo ${DIR_SRCS})
    # 链接静态库
    target_link_libraries(Demo ${EXTRA_LIBS})
    

    关于option的生效机制,这里详细解释下。如main.cc中的代码:

    #include <stdio.h>
    #include <stdlib.h>
    #include "config.h"  // 此头文件是cmake自动生成的
    
    #ifdef USE_PYUTILS
      #include "utils/foo.h"
    #else
      #include <foo.h>  // 假设标准库有foo.h头文件
    #endif
    

    为了打通CMakeLists.txt一键便携式配置,我们需要编写一个config.h.in文件:

    #cmakedefine USE_MYUTILS
    

    这样,在执行cmake命令时,就可以根据配置的参数,自动生成option相关的头文件。若指定-DUSE_MYUTILS=ON时,config.h中的内容为:

    #define USE_MYUTILS
    

    若为OFF时,则config.h的内容为:

    /* #undef USE_MYUTILS */
    

    安装和测试

    camke支持安装测试,通过在生成Makefile后,使用make installmake test来执行。

    接上述样例,首先在utils/CMakeLists.txt中加上如下内容:

    # 指定utils库的安装路径
    install(TARGETS utils DESTINATION bin)
    install(FILES utils.h DESTINATION include)
    

    Demo/CMakeLists.txt添加如下内容:

    # 指定安装路径
    install(TARGETS Demo DESTINATION bin)
    install(FILES "${PROJECT_BINARY}/config.h" DESTINATION include)
    

    原理 & 流程:

    • cmake编译产出的Demo文件和库libUtils.o文件将会被复制到/usr/local/bin
    • 头文件utils.hconfig.h则会被赋值到/use/local/include
    • 可以通过CMKAE_INSTALL_PREFIX修改默认安装的根目录/usr/local

    关于测试,CMake提供一个称为CTest的测试工具,通过add_test命令添加:

    # 启用测试
    enable_testing()
    
    # 测试程序是否成功运行, arg*为函数接收的参数
    add_test(test_run Demo arg1 arg2)
    
    add_test(test_usage Demo)
    set_tests_properties(test_usage PROPERTIES PASS_REGULAR_EXPRESSION "Usage: .....")
    
    add_test(test_result Demo 10 2)
    # 测试输出的结果是否包含字符串 "is 100"
    set_tests_properties(test_result PROPERTIES PASS_REGULAR_EXPRESSION "is 100")
    

    支持gdb

    CMake支持gdb的方式很简单,只需指定Debug模式下开启-g,一个简单的样例如下:

    set(CMAKE_BUILD_TYPE "Debug")
    # debug模式下编译选项
    set(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g -ggdb")
    # release模式下编译选项
    set(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall")
    

    小结

    • CMake的语法主要以命令、空格、参数来组成

    • 可以通过 set(<variable> <value>)设置变量的值

    • if语法

      if(<condition>)
        <commands>
      elseif(<condition>) # optional block, can be repeated
        <commands>
      else()              # optional block
        <commands>
      endif()
      
    • for语法

      # usage 1:
      foreach(<loop_var> <items>)
        <commands>
      endforeach()
      
      # usage 2:
      foreach(<loop_var> RANGE <stop>)
      
    • while语法

      while(<condition>)
        <commands>
      endwhile()
      

    附录:

  • 相关阅读:
    Linux计划任务Crontab实例详解教程
    配置Linux任务计划
    全局变量报错:UnboundLocalError: local variable 'l' referenced before assignment
    Multipath多路径冗余全解
    Ubuntu 查看文件以及磁盘空间大小管理
    转载
    grep的用法
    Python标准库06 子进程 (subprocess包)
    Python与shell的3种交互方式介绍
    python和shell变量互相传递的几种方法
  • 原文地址:https://www.cnblogs.com/CocoML/p/13744610.html
Copyright © 2011-2022 走看看