美文网首页
CMake搭建项目工程(2)-CMake控制命令、函数与宏、安装

CMake搭建项目工程(2)-CMake控制命令、函数与宏、安装

作者: WalkeR_ZG | 来源:发表于2019-04-13 23:57 被阅读0次

    CMake+GoogleTest搭建项目工程(1)-C/C++编译及CMake那些事
    本篇主要阐述CMake的其他常用命令,并给出一个示例代码。

    CMake控制命令

    if else endif指令
    if(expression)
        command(……)
    else(expression)
        command(……)
    endif(expression)
    
    if elseif endif指令
    if(expression_1)
       command(……)
    elseif(expression_2)
       command(……)
    elseif(expression_3)
       command(……)
    endif(expression_1)
    

    if的判断条件:
    如果expression是变量,则当expression为:空、0、N、 NO、 OFF、 FALSE、 NOTFOUND 、expression_NOTFOUND 时,表达式为假,其余为真。
    同时支持与(and)、或(or)、非(not)的语义,与常规语言的与或非含义一致。

    while指令
    while(expression)
        command(……)
    endwhile(expression)       
    

    与常规编程语言的while一致。

    foreach
    //var依次取列表arg中的值
    foreach(var arg1 arg2……)
        command(……)
    endforeach(var)
    
    //var从0到total以1为步长增加
    foreach(var range total)
        command(……)
    endforeach(var)
    
    //var从start到end, 以step为步长增加
    foreach(var range start end step)
        command(……)
    endforeach(var)
    

    CMake宏与函数

    • CMake的函数与宏可用的变量
    name description
    ARGC 函数实参的个数
    ARGV 所有实参列表
    ARGN 保留函数形参列表以后的所有参数列表。
    ARGV0 函数第1个实参
    ARGV1 函数第2个实参
    依次类推 依次类推
    function
    function(<name> [arg1 [arg2 [arg3 ...]]])
        COMMAND1(ARGS ...)
        COMMAND2(ARGS ...)
        ...
    endfunction(<name>)
    
    macro
    macro(<name> [arg1 [arg2 [arg3 ...]]])
        COMMAND1(ARGS ...)
        COMMAND2(ARGS ...)
        ...
    endmacro(<name>)
    
    macro与function的区别

    macro是CMake的宏定义,function为CMake的函数,其差异与C语言中宏和函数的差异类似,我们对比以下代码:

    cmake_minimum_required(VERSION 2.8)
    set(v1 "ABC")
    set(v2 "XYZ")
    
    macro(Macro v1 v2)
      message("ARGC = ${ARGC} ARGV = ${ARGV}")
      message("ARGV0 = ${ARGV0} ARGV1 = ${ARGV1} ARGN = ${ARGN}")
      message("----------------------------")
      message("v1 = ${v1} v2 = ${v2}")
      set(v1 "abc")
      set(v2 "xyz")
      message("v1 = ${v1} v2 = ${v2}")
    endmacro()
    
    Macro(${v1} v2 x y z)
    message("v1 = ${v1} v2 = ${v2}")
    
    message("----------------------------")
    
    set(v1 "ABC")
    set(v2 "XYZ")
    function(Function  v1 v2)
      message("v1 = ${v1} v2 = ${v2}")
      set(v1 "abc")
      set(v2 "xyz" PARENT_SCOPE)
      message("v1 = ${v1} v2 = ${v2}")
    endfunction()
    
    Function(${v1} v2)
    message("v1 = ${v1} v2 = ${v2}")
    

    它的输出结果为

    ARGC = 5 ARGV = ABC;v2;x;y;z
    ARGV0 = ABC ARGV1 = v2 ARGN = x;y;z
    ----------------------------
    v1 = ABC v2 = v2
    v1 = ABC v2 = v2
    v1 = abc v2 = xyz
    ----------------------------
    v1 = ABC v2 = v2
    v1 = abc v2 = v2
    v1 = ABC v2 = xyz
    

    通过上面的代码,我们首先可以看到marco与function的可用变量ARG*,同时可以看出marco与function的差异:

    1. marco没有SCOPE的概念,只是字符串的替换,有些类似于C语言中的define,在预处理阶段就进行了字符串的替换,通过v1的值的打印即可看出
    2. function有SCOPE的概念,虽然marco与function都完成了v2的赋值,但marco是字符串的替换,而function的入参写为v2形式,并且需要加上PARENT_SCOPE。

    CMake安装 (install)

    CMake install一般用于库、头文件的安装,当然也可以安装目录,我们写好CMakeLists.txt后在build目录执行cmake生成makefile,之后执行make进行编译,编译是不会进行安装的(这也是install用于安装文件与file的差别),需要额外执行make install进行安装。

    目标文件的安装
    INSTALL(TARGETS targets... [[ARCHIVE|LIBRARY|RUNTIME]
                    [DESTINATION <dir>]
                    [PERMISSIONS permissions...]
                    [CONFIGURATIONS
                    [Debug|Release|...]]
                    [COMPONENT <component>]
                    [OPTIONAL]] )
    

    作用:目标文件的安装,目标文件TARGETS 后面跟的可以是二进制可执行文件(ADD_EXECUTABLE的target)或库文件(ADD_LIBRARY的target)。目标类型分为三种,ARCHIVE特指静态库,LIBRARY特指动态库,RUNTIME 特指可执行目标二进制。可以一次安装多个目标文件。

    普通文件的安装
    INSTALL(FILES files... DESTINATION <dir>
                  [PERMISSIONS permissions...]
                  [CONFIGURATIONS [Debug|Release|...]]
                  [COMPONENT <component>]
                  [RENAME <name>] [OPTIONAL])
    

    作用:一般文件的安装,可以指定访问权限,如果默认不定义权限PERMISSIONS,安装后的权限为:OWNER_WRITE & OWNER_READ & GROUP_READ & WORLD_READ。

    非目标文件的可执行程序安装
    INSTALL(PROGRAMS files... DESTINATION <dir>
         [PERMISSIONS permissions...]
         [CONFIGURATIONS [Debug|Release|...]]
         [COMPONENT <component>]
         [RENAME <name>] [OPTIONAL])
    

    作用:非目标文件的可执行程序安装,默认的权限为OWNER_EXECUTE & GROUP_EXECUTE & WORLD_EXECUTE。

    目录的安装
    INSTALL(DIRECTORY dirs... DESTINATION <dir>
         [FILE_PERMISSIONS permissions...]
         [DIRECTORY_PERMISSIONS permissions...]
         [USE_SOURCE_PERMISSIONS]
         [CONFIGURATIONS [Debug|Release|...]]
         [COMPONENT <component>]
         [[PATTERN <pattern> | REGEX <regex>]
         [EXCLUDE] [PERMISSIONS permissions...]])
    

    作用:目录的安装。特别注意:如果目录名以 /结束,则代表将这个目录中的内容安装到目标路径,但不包括这个目录本身;如果目录名不以/结尾,那么这个目录将被安装为目标路径下。

    下面以一个例子对上述内容有个形象的认识,文件目录下存在Add.h,Add.cc 和CMakeLists.txt分别如下:(需求将Add.h安装到/usr/local/WalkeR-ZG/include目录下,将静态库文件libadd.a安装到/usr/local/WalkeR-ZG/lib目录下)
    Add.h:

    int add(int a, int b);
    

    Add.cc:

    #include "Add.h"
    int add(int a, int b){
        return a + b;
    }
    

    CMakeLists.txt:

    cmake_minimum_required(VERSION 2.8)
    set(CMAKE_INSTALL_PREFIX /usr/local/WalkeR-ZG)
    add_library(add STATIC Add.cc)
    target_include_directories(add PRIVATE include "${PROJECT_SOURCE_DIR}")
    install(TARGETS add ARCHIVE DESTINATION lib)
    install(FILES Add.h DESTINATION include)
    

    CMake模块

    CMake模块主要的作用是当我们需要使用外部库时,需要知道外部库的头文件和链接库的位置,CMake模块主要就给出了头文件及链接库的查找方法。
    模块使用find_package(xxx)被调用,每个模块会定义如下变量:

    • xxx__FOUND:用来判断模块是否被找到,如果没有找到,根据工程的需要关闭某些特性、给出提醒或者中止编译。
    • xxx_INCLUDE_DIR: 头文件的目录
    • xxx_LIBRARY (xxx_LIBRARIES):库文件目录

    find_package(xxx)用来调用预定义在CMAKE_MODULE_PATH下的Findxxx.cmake模块,你也可以自己定义Find<name> 模块,通过SET(CMAKE_MODULE_PATH dir)将其放入工程的某个目录供工程使用。
    结合上面给出的代码编译安装的Add的头文件及静态库,编写一个cmake的模块。目录结构如下:
    顶层目录是demo目录,存在一个子目录cmake用于放模块。代码和CMakeLists.txt直接放在demo目录下。
    main.cc:

    #include <Add.h>
    #include <iostream>
    
    int main(){
        int a = add(3, 4);
        std::cout<<a<<std::endl;
        return 0;
    }
    

    CMakeLists.txt:

    cmake_minimum_required(VERSION 2.8)
    set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake/")
    find_package(Add)
    if(Add_FOUND)
        add_executable(demo main.cc)
        target_include_directories(demo PRIVATE Add_INCLUDE_DIR)
        target_link_libraries(demo Add_LIBRARY)
    else(Add_FOUND)
        message(FATAL_ERROR "Add cannot find!!!")
    endif(Add_FOUND)
    

    cmake/FindAdd.cmake:

    find_path(Add_INCLUDE_DIR Add.h /usr/local/WalkeR-ZG/include)
    find_library(Add_LIBRARY libadd.a /usr/local/WalkeR-ZG/lib)
    if (Add_INCLUDE_DIR AND Add_LIBRARY)
        set(Add_FOUND TRUE)
    endif(Add_INCLUDE_DIR AND Add_LIBRARY)
    
    if(Add_FOUND)
        if(NOT Add_FIND_QUIETLY)
        message(STATUS "Found Add: ${Add_LIBRARY}")
        endif(NOT Add_FIND_QUIETLY)
    endif(Add_FOUND)
    

    CMake的内容粗略阐述完毕。

    WalkeR_ZG

    相关文章

      网友评论

          本文标题:CMake搭建项目工程(2)-CMake控制命令、函数与宏、安装

          本文链接:https://www.haomeiwen.com/subject/qaarbqtx.html