• CMake学习笔记三:cmake 常用指令


    1 基本指令

    1,ADD_DEFINITIONS

    向 C/C++编译器添加-D 定义,比如:

    DD_DEFINITIONS(-DENABLE_DEBUG -DABC),参数之间用空格分割。

    如果你的代码中定义了#ifdef ENABLE_DEBUG #endif,这个代码块就会生效。


    2,ADD_DEPENDENCIES

    ADD_DEPENDENCIES(target-name depend-target1 depend-target2 ...)

    如果两个targets有依赖关系(通过target_link_libraries解决)并且依赖库也是通过编译源码产生的。这时候一句 add_dependencies 可以在直接编译上层target时,自动检查下层依赖库是否已经生成。没有的话先编译下层依赖库,然后再编译上层target,最后 link depend target。若只有一个targets有依赖关系,一般选择使用 target_link_libraries。


    3,ADD_EXECUTABLE

    ADD_EXECUTABLE(hello main.cpp)

    定义了这个工程会生成一个文件名为 hello 的可执行文件,相关的源文件是mian.cpp。


    4,ADD_LIBRARY

    该指令的主要作用就是将指定的源文件生成链接库文件,然后添加到工程中去。语法如下:

    add_library(<name> [STATIC | SHARED | MODULE] [EXCLUDE_FROM_ALL] [source1] [source2] [...])

    其中<name>表示链接库文件的名字,该链接库文件会根据命令里列出的源文件来创建。而 STATIC、SHARED 和 MODULE 的作用是指定生成的链接库文件的类型,STATIC 为静态链接库,SHARED 为动态链接库,而 MODULE,在使用 dyld 的系统有效,如果不支持 dyld,则被当作 SHARED 对待。 EXCLUDE_FROM_ALL 参数的含义是将这个target排除在all target列表之外,这样当执行make时,这个target就不会被编译。而语法中的source1 source2分别表示各个源文件。


    5,ADD_SUBDIRECTORY

    ADD_SUBDIRECTORY(source_dir [binary_dir] [EXCLUDE_FROM_ALL])

    这个指令用于向当前工程添加存放源文件的子目录,并可以指定中间二进制和目标二进制存放的位置。EXCLUDE_FROM_ALL 参数的含义是将这个子目录的所有target排除在all target列表之外,这样当执行make时,这个子目录的所有target就不会被编译。


    6,CMAKE_MINIMUM_REQUIRED

    CMAKE_MINIMUM_REQUIRED(VERSION versionNumber [FATAL_ERROR])

    检查cmake的版本,要求至少为versionNumber。例如 CMAKE_MINIMUM_REQUIRED(VERSION 2.5 FATAL_ERROR) ,如果 cmake 版本小于 2.5,则出现严重错误,整个过程中止。


    7,INCLUDE_DIRECTORIES

    INCLUDE_DIRECTORIES([AFTER|BEFORE] [SYSTEM] dir1 [dir2 ...])

    指定头文件的搜索路径。例如我现在想要#include "cv.h",但是这个cv.h的路径是 /usr/local/include/opencv,那么总不能在主函数头前写#include “/usr/local/include/opencv/cv.h” 吧,这个时候就用到include_directories了,它提供了一个搜索头文件暂时的根目录,即你可以在 CMakeLists.txt 中写上 include_directories(/usr/local/include) 来让库文件搜索以 /usr/local/include 为基础,然后在main函数前写上 #include “opencv/cv.h" 即可。


    8,LINK_DIRECTORIES
    LINK_DIRECTORIES(directory1 directory2 ...)

    添加需要链接的库文件目录,相当于g++命令的-L选项的作用。 该指令有时候不一定需要,因为find_package和find_library指令可以得到库文件的绝对路径。不过你自己写的动态库文件放在自己新建的目录下时,可以用该指令指定该目录的路径以便工程能够找到。例子如下:

    LINK_DIRECTORIES("/opt/MATLAB/R2012a/bin/glnxa64")


    9,LINK_LIBRARIES 

    LINK_LIBRARIES(library1 library2 ...)

    添加需要链接的库文件路径,注意这里是全路径,要用在add_executable之前。例子如下:

    LINK_LIBRARIES("/opt/MATLAB/R2012a/bin/glnxa64/libeng.so")


    10,TARGET_LINK_LIBRARIES

    TARGET_LINK_LIBRARIES(target library1 <debug | optimized> library2 ...)

    为库或二进制可执行文件添加库链接,要用在add_executable之后。 上述指令中的target是指通过add_executable()和add_library()指令生成已经创建的目标文件。例子如下:

    TARGET_LINK_LIBRARIES(myProject hello),连接libhello.so库
    TARGET_LINK_LIBRARIES(myProject libhello.a)


    11,PKG_CHECK_MODULES

    pkg_check_modules(<PREFIX> [REQUIRED] [QUIET]
                      [NO_CMAKE_PATH] [NO_CMAKE_ENVIRONMENT_PATH]
                      <MODULE> [<MODULE>]*)
    

    pkg_check_modules 是 CMake 自己的 pkg-config 模块 的一个用来简化的封装:你不用再检查 CMake 的版本,加载合适的模块,检查是否被加载,等等,参数和传给 find_package 的一样:先是待返回变量的前缀,然后是包名(pkg-config 的)。这样就定义了<prefix>_INCLUDE_DIRS和其他的这类变量,后续的用法就与 find_package 一致。


    2 find_package 指令

    2.1 原理

    语法如下:

    find_package(<package> [version] [EXACT] [QUIET]
                 [REQUIRED] [[COMPONENTS] [components...]]
                 [NO_POLICY_SCOPE])
    

    功能:采用两种模式搜索外部库。

    [version]参数需要一个版本号,它是正在查找的包应该兼容的版本号(格式是major[.minor[.patch[.tweak]]])。EXACT选项要求该版本号必须精确匹配。QUIET选项将会禁掉包没有被发现时的警告信息。REQUIRED选项表示如果包没有找到的话,cmake的过程会终止,并输出警告信息。在REQUIRED选项之后,或者如果没有指定REQUIRED选项但是指定了COMPONENTS选项,在它们的后面可以列出一些与包相关的部件清单(components list)。

    首先明确一点,cmake本身不提供任何搜索库的便捷方法,所有搜索库并给变量赋值的操作必须由cmake代码完成,比如下面将要提到的FindXXX.cmake和XXXConfig.cmake。只不过,库的作者通常会提供这两个文件,以方便使用者调用。

    搜索有以下两种模式:

    • Module模式:搜索CMAKE_MODULE_PATH指定路径下的FindXXX.cmake文件,执行该文件从而找到XXX库。其中,具体查找库并给XXX_INCLUDE_DIRSXXX_LIBRARIES两个变量赋值的操作由FindXXX.cmake模块完成。
    • Config模式:搜索XXX_DIR指定路径下的XXXConfig.cmake文件,执行该文件从而找到XXX库。其中具体查找库并给XXX_INCLUDE_DIRSXXX_LIBRARIES两个变量赋值的操作由XXXConfig.cmake模块完成。

    两种模式看起来似乎差不多,不过cmake默认采取Module模式,如果Module模式未找到库,才会采取Config模式。如果XXX_DIR路径下找不到XXXConfig.cmake文件,则会找/usr/local/lib/cmake/XXX/中的XXXConfig.cmake文件。总之,Config模式是一个备选策略。通常,库安装时会拷贝一份XXXConfig.cmake到系统目录中,因此在没有显式指定搜索路径时也可以顺利找到。

    若XXX安装时没有安装到系统目录,因此无法自动找到XXXConfig.cmake,可以在CMakeLists.txt最前面添加XXX的搜索路径。

    set(XXX_DIR /home/wjg/projects/XXX/build)   #添加CaffeConfig.cmake的搜索路径
    

    2.2 使用

    当编译一个需要使用第三方库的软件时,我们需要知道:

    去哪儿找头文件 .h 对比GCC的 -I 参数
    去哪儿找库文件 (.so/.dll/.lib/.dylib/…) 对比GCC的 -L 参数
    需要链接的库文件的名字 对比GCC的 -l 参数

    比如说,我们需要一个第三方库 curl,那么我们的 CMakeLists.txt 需要指定头文件目录和库文件,类似:

    include_directiories(/usr/include/curl)
    target_link_libraries(myprogram path/curl.so)
    

    如果借助于cmake提供的finder会怎么样呢?使用cmake的Modules目录下的FindCURL.cmake,相应的CMakeList.txt 文件:

    find_package(CURL REQUIRED)
    include_directories(${CURL_INCLUDE_DIR})
    target_link_libraries(curltest ${CURL_LIBRARY})
    

    为了能支持各种常见的库和包,CMake自带了很多模块。可以通过命令 cmake –help-module-list (输入cmake –help,然后双击Tab会有命令提示)得到你的CMake支持的模块的列表:直接查看模块路径。比如Ubuntu linux上,模块的路径是 ls /usr/share/cmake/Modules/:

    ll -th /usr/share/cmake-3.5/Modules/
    ......
    -rw-r--r--  1 root root  76K Sep 27  2016 FindBoost.cmake
    -rw-r--r--  1 root root 2.7K Mar 24  2016 FindCoin3D.cmake
    -rw-r--r--  1 root root  77K Mar 24  2016 FindCUDA.cmake
    -rw-r--r--  1 root root 3.1K Mar 24  2016 FindCups.cmake
    -rw-r--r--  1 root root 2.4K Mar 24  2016 FindCURL.cmake
    ........
    

    让我们以bzip2库为例。CMake中有个 FindBZip2.cmake 模块。只要使用 find_package(BZip2) 调用这个模块,cmake会自动给一些变量赋值,然后就可以在CMake脚本中使用它们了。变量的列表可以查看cmake模块文件,或者使用命令:

    root@xy:~/cmake_practice/cmake_build/build_demo10# cmake --help-module FindBZip2
    FindBZip2
    ---------
    
    Try to find BZip2
    
    Once done this will define
    ::
    BZIP2_FOUND - system has BZip2
    BZIP2_INCLUDE_DIR - the BZip2 include directory
    BZIP2_LIBRARIES - Link these to use BZip2
    BZIP2_NEED_PREFIX - this is set if the functions are prefixed with BZ2_
    BZIP2_VERSION_STRING - the version of BZip2 found (since CMake 2.8.8)
    

    cmake 会将路径赋值给对应的变量,我们以curl的cmake为例,其部分内容如下:

    find_path(CURL_INCLUDE_DIR NAMES curl/curl.h)
    mark_as_advanced(CURL_INCLUDE_DIR)
    
    # Look for the library (sorted from most current/relevant entry to least).
    find_library(CURL_LIBRARY NAMES
            curl
            # Windows MSVC prebuilts:
            curllib
            libcurl_imp
            curllib_static
            # Windows older "Win32 - MSVC" prebuilts (libcurl.lib, e.g. libcurl-7.15.5-win32-msvc.zip):
            libcurl
            )
    

    比如一个使用bzip2的简单程序,编译器需要知道 bzlib.h 的位置,链接器需要找到bzip2库。(动态链接的话,Unix上是 libbz2.so 类似的文件,Windows上是 libbz2.dll )

    project(helloworld)
    add_executable(helloworld hello.c)
    find_package (BZip2)
    if (BZIP2_FOUND)
        include_directories(${BZIP_INCLUDE_DIRS})
        target_link_libraries (helloworld ${BZIP2_LIBRARIES})
    endif (BZIP2_FOUND)
    

    3 INSTALL 指令

    安装的方法有两种,一种是从代码编译后直接make install安装,一种是打包时的指定目录安装(INSTALL)。

    这里需要引入一个新的cmake 指令 INSTALL和一个非常有用的变量CMAKE_INSTALL_PREFIX。 CMAKE_INSTALL_PREFIX变量类似于configure脚本的 –prefix,常见的使用方法看 起来是这个样子:

    cmake -DCMAKE_INSTALL_PREFIX=/usr .

    INSTALL指令用于定义安装规则,安装的内容可以包括目标二进制、动态库、静态库以及 文件、目录、脚本等。


    INSTALL指令包含了各种安装类型,我们需要一个个分开解释:

    目标文件的安装

    INSTALL(TARGETS targets...
            [[ARCHIVE|LIBRARY|RUNTIME]
                       [DESTINATION <dir>]
                       [PERMISSIONS permissions...]
                       [CONFIGURATIONS
            [Debug|Release|...]]
                       [COMPONENT <component>]
                       [OPTIONAL]
                    ] [...])
    

    参数中的TARGETS后面跟的就是我们通过ADD_EXECUTABLE或者ADD_LIBRARY定义的目标文件,可能是可执行二进制、动态库、静态库。

    目标类型也就相对应的有三种,ARCHIVE特指静态库,LIBRARY特指动态库,RUNTIME特指可执行目标二进制。

    DESTINATION定义了安装的路径,如果路径以/开头,那么指的是绝对路径,这时候 CMAKE_INSTALL_PREFIX其实就无效了。如果你希望使用CMAKE_INSTALL_PREFIX来定义安装路径,就要写成相对路径,即不要以/开头,那么安装后的路径就是${CMAKE_INSTALL_PREFIX}/<DESTINATION定义的路径>。

    举个简单的例子:

    INSTALL(TARGETS myrun mylib mystaticlib
           RUNTIME DESTINATION bin
           LIBRARY DESTINATION lib
           ARCHIVE DESTINATION libstatic
    )
    

    上面的例子会将:

    可执行二进制myrun安装到${CMAKE_INSTALL_PREFIX}/bin目录。
    动态库libmylib安装到${CMAKE_INSTALL_PREFIX}/lib目录。
    静态库libmystaticlib安装到${CMAKE_INSTALL_PREFIX}/libstatic目录。
    特别注意的是你不需要关心TARGETS具体生成的路径,只需要写上TARGETS名称就可以了。


    普通文件的安装

    INSTALL(FILES files... DESTINATION <dir>
             [PERMISSIONS permissions...]
             [CONFIGURATIONS [Debug|Release|...]]
             [COMPONENT <component>]
             [RENAME <name>] [OPTIONAL])
    #可用于安装一般文件,并可以指定访问权限,文件名是此指令所在路径下的相对路径。
    #如果默认不定义权限PERMISSIONS,安装后的权限为,OWNER_WRITE,OWNER_READ,
    #GROUP_READ,和WORLD_READ,即644权限。
    

    非目标文件的可执行程序安装(比如脚本之类)

    INSTALL(PROGRAMS files... DESTINATION <dir>
         [PERMISSIONS permissions...]
         [CONFIGURATIONS [Debug|Release|...]]
         [COMPONENT <component>]
         [RENAME <name>] [OPTIONAL])
    

    跟上面的FILES指令使用方法一样,唯一的不同是安装后权限为:
    OWNER_EXECUTE, GROUP_EXECUTE, 和WORLD_EXECUTE,即755权限


    目录的安装

    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...]] [...])
    

    这里主要介绍其中的DIRECTORY、PATTERN以及PERMISSIONS参数。
    DIRECTORY后面连接的是所在Source目录的相对路径,但务必注意:
    abc和abc/有很大的区别。 abc意味着abc这个目录会安装在目标路径下;abc/意味着abc这个目录的内容会被安装在目标路径下。PATTERN用于使用正则表达式进行过滤, PERMISSIONS用于指定PATTERN过滤后的文件权限。

    我们来看一个例子:

    INSTALL(DIRECTORY icons scripts/ DESTINATION share/myproj
            PATTERN "CVS" EXCLUDE
            PATTERN "scripts/*"
            PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ
            GROUP_EXECUTE GROUP_READ)
    

    这条指令的执行结果是:

    将icons目录安装到 <prefix>/share/myproj,将scripts/中的内容安装到 <prefix>/share/myproj。
    不包含目录名为CVS的目录,对于scripts/*文件指定权限为 OWNER_EXECUTE 不包含目录名为CVS的目录,对于scripts/*文件指定权限为 OWNER_EXECUTE OWNER_WRITE OWNER_READ GROUP_EXECUTE GROUP_READ。


    参考:

    简书 金戈大王-CMake之find_package

    CSDN FishBear_move_on-cmake教程4(find_package使用)

    CSDN WhateverYoung

    《CMake实践》

  • 相关阅读:
    学WPF (1 of n)干啥都有第一次
    程序启动时显示Flash窗体(C#)
    对象序列化后直接获取byte[]的方法
    工程管理(1 of n): 建立用于管理代码开发的注释标记
    发现Visual Studio隐含的大礼包漂亮的Visual Studio图像库
    C# Hello World
    更人性化地控制用户输入(1 of n)
    快手导航 计算机软件网址导航 时空地图TimeGIS
    中国图书馆图书分类法(Chinese Library Classification CLC)的XML文档生成 时空地图TimeGIS
    快手软件 v2.5 发布 时空地图TimeGIS
  • 原文地址:https://www.cnblogs.com/linuxAndMcu/p/10675971.html
Copyright © 2020-2023  润新知