CMAKE 常见语法总结

流程

  • cmake用来产生跨平台的编译文件。cmake跨平台,它可以根据不同平台、不同的编译器,生成相应的Makefile配置文件。在 Linux/Unix 平台,生成 makefile,在 Mac平台,可以生成 xcode,在 Windows 平台,可以生成 MSVC 的工程文件。
  • ./configure 是用来检测你的安装平台的目标特征的。比如它会检测你是不是有CC或GCC,并不是需要CC或GCC,它是个shell脚本。
  • make 是用来编译的,它从Makefile中读取指令,然后编译。
  • make install是用来安装的,它也从Makefile中读取指令,安装到指定的位置。
  • CMake ---------> makefile (包含调用gcc的命令)------------> make工具 ---------------> 编译链接源文件。CMake 根据CMakeLists.txt生成makefile, make工具根据makefiel文件源文件进行编译和链接产生二进制文件。

include_directories()

   对于第三方依赖的头文件可用include_directories()添加依赖的头文件。 include_directories([AFTER|BEFORE] [SYSTEM] dir1 [dir2 ...])
它相当于g++选项中的-I参数的作用,也相当于环境变量中增加路径到CPLUS_INCLUDE_PATH变量的作用,可以用相对路径。
   对于在gcc默认搜索路径如/usr/include 和 /usr/local/include内的头文件可以不用include_directories,会默认搜索到,对于非默认路径下的头文件需要加include_directories,如
include_directories(../../../thirdparty/comm/include)
可以通过include_directories(${PROJECT_SOURCE_DIR})添加一个目录级别较高的目录,不一定是头文件的直属父目录,可以在引用头文件的时候写明目录级别,如

#include "util/tc_epoll_server.h"
#include "servant/AppProtocol.h"
#include "tup/Tars.h"
include_directories的目录至少包含util servant tup这三个子目录。

link_directories(directory1 directory2 …)

  添加需要链接的库文件目录LINK_DIRECTORIES语法:它相当于g++命令的-L选项的作用,也相当于环境变量中增加LD_LIBRARY_PATH的路径的作用。link_directories("/home/server/third/lib"),后面可以直接用名字表示link该目录下的文件库。

   link_libraries: The target_link_libraries() command should be preferred whenever possible. Library dependencies are chained automatically, so directory-wide specification of link libraries is rarely needed. 应尽可能首选target_link_libraries()命令。 库依赖项是自动链接的,因此很少需要链接库的目录范围规范。


link_libraries(library1 library2 …)

  • 直接是全路径link_libraries(“/home/server/third/lib/libcommon.a”)
  • 只有库名,cmake会自动去所包含的目录搜索 ,包括add_subdirectory() 中生成的库, 如 link_libraries(iconv)
  • 也可以链接多个link_libraries("/opt/MATLAB/R2012a/bin/glnxa64/libeng.so" "/opt/MATLAB/R2012a/bin/glnxa64/libmx.so")

add_library()

   add_library该指令的主要作用就是将指定的源文件生成链接文件,然后添加到工程中去。可加set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)把生成的库输出到指定的路径下。一般子目录中使用,父目录可以add到生成的库。 该指令常用的语法如下:
add_library(<name> [STATIC | SHARED | MODULE] [EXCLUDE_FROM_ALL] [source1] [source2] [...])
   其中<name>表示库文件的名字,直接写名字即可,不要写lib,会自动加上前缀,该库文件会根据命令里列出的源文件来创建。
   而STATIC、SHARED和MODULE的作用是指定生成的库文件的类型。STATIC库是目标文件的归档文件,在链接其它目标的时候使用。SHARED库会被动态链接(动态链接库),在运行时会被加载。MODULE库是一种不会被链接到其它目标中的插件,但是可能会在运行时使用dlopen-系列的函数。如果没有类型被显式指定,这个选项将会根据变量BUILD_SHARED_LIBS的当前值是否为真决定是STATIC还是SHARED。
   默认状态下,库文件将会在于源文件目录树的构建目录树的位置被创建,该命令也会在这里被调用。而语法中的source1 source2分别表示各个源文件。
例如:
aux_source_directory(. DIR_LIB_SRCS)
add_library (MathFunctions ${DIR_LIB_SRCS})


TARGET_LINK_LIBRARIES(target library1 library2 …)

   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)
# 以下写法都可以: 
target_link_libraries(myProject comm)       # 连接libhello.so库,默认优先链接动态库
target_link_libraries(myProject libcomm.a)  # 显示指定链接静态库
target_link_libraries(myProject libcomm.so) # 显示指定链接动态库
 
# 再如:
target_link_libraries(myProject libcomm.so)  #这些库名写法都可以。
target_link_libraries(myProject comm)
target_link_libraries(myProject -lcomm)


add_subdirectory()

add_subdirectory(source_dir [binary_dir] [EXCLUDE_FROM_ALL])
    这条命令的作用是为构建添加一个子路径。source_dir选项指定了CMakeLists.txt源文件和代码文件的位置。如果source_dir是一个相对路径,那么source_dir选项会被解释为相对于当前的目录,但是它也可以是一个绝对路径。binary_dir选项指定了输出文件的路径。如果binary_dir是相对路径,它将会被解释为相对于当前输出路径,但是它也可以是一个绝对路径。在source_dir指定路径下的CMakeLists.txt将会在当前输入文件的处理过程执行到该命令之前,立即被CMake处理。
   如果指定了EXCLUDE_FROM_ALL选项,在子路径下的目标默认不会被包含到父路径的ALL目标里,并且也会被排除在IDE工程文件之外。用户必须显式构建在子路径下的目标,比如一些示范性的例子工程就是这样。典型地,子路径应该包含它自己的project()命令调用,这样会在子路径下产生一份完整的构建系统(比如VS IDE的solution文件)。注意,目标间的依赖性要高于这种排除行为。如果一个被父工程构建的目标依赖于在这个子路径下的目标,被依赖的目标会被包含到父工程的构建系统中,以满足依赖性的要求。
   父目录会注册add_subdirectory子目录中的PROJECT_SOURCE/BINARY_DIR的宏信息,只有CMakeList中定义了project()才有当前目录下定义的相关目录宏。子目录中的目录宏可以在父目录中的CMakeList中使用,而父目录的后续add_subdirectory中所有的子目录也可以使用此宏定义。


aux_source_directory(< dir > < variable > )

   查找目录< dir >下的所有源文件并将名称保存到< variable > 变量


add_definitions(-D XXX)

通过add_definitions添加编译选项, 向C/CPP添加宏定义,相当于gcc中的-D,参数之间用空格分割。GCC编译时增加宏定义-D标识符,相当于宏定义#define 标识符。
gcc -DDEBUG :-D 后面直接跟宏命,相当于定义这个宏,默认这个宏的内容是1
gcc -DNAME=Peter: -D 后面跟 key=value 表示定义key这个宏,它的内容是value。

set(_USE_OPENTRACKING $ENV{_USE_OPENTRACKING})
if(_USE_OPENTRACKING)
set(OPENTRACKING_INC "/usr/local/include")
add_definitions(-D_USE_OPENTRACKING=${_USE_OPENTRACKING})
endif()

cmake与环境变量

  • 使用$ENV{NAME}指令就可以调用系统的环境变量了。
    MESSAGE(STATUS “HOME dir: $ENV{HOME}”)
  • 设置环境变量的方式是:SET(ENV{变量名} 值)
  • 读取环境变量时要在ENV前加$符号,而写和if判断是否定义时,ENV{JAVA_HOME}指代变量名所以不加$符号

CMAKE_INCLUDE_PATH与CMAKE_LIBRARY_PATH

  • CMAKE_INCLUDE_PATH:cmake中头文件包含路径的环境变量。可以通过在bash中使用环境变量的形式(如export)进行设置值,也可以在cmake文件中使用set关键字进行设置,set(CMAKE_INCLUDE_PATH "include_path")
    export CMAKE_INCLUDE_PATH=xxxxx

  • CMAKE_INCLUDE_PATH需要配合 FIND_FILE() 以及 FIND_PATH() 使用。如果头文件没有存放在常规路径(/usr/include, /usr/local/include等),则可以通过这些变量就行弥补。如果不使用 FIND_FILE 和 FIND_PATH的话,CMAKE_INCLUDE_PATH,没有任何作用。

  • find_path用于查找包含的头文件,其查找顺序为:
    1)从CMAKE_INCLUDE_PATH中查找。
    2)从系统默认头目录即/usr/include、/usr/local/inlucde中查找。

  • CMAKE_LIBRARY_PATH:cmake中库文件路径的环境变量。CMAKE_LIBRARY_PATH需配合 FIND_LIBRARY() 使用。否则没有任何作用.

  • find_library用于查找包含的库文件,其查找顺序为:
    1)从CMAKE_LIBRARY_PATH中查找。
    2)从系统默认库目录即/usr/lib、/usr/local/lib中查找。


find_package()

  • find_package(NAME, REQUIRED)命令是用来查找name依赖包的,理想情况下,find_package()把一整个依赖包的头文件包含路径、库路径、库名字、版本号等情况都获取到,后续只管用就好了。
  • find_package在一些目录中查找OpenCV的配置文件。找到后,find_package会将头文件目录设置到${NAME_INCLUDE_DIRS}中,将链接库设置到${NAME_LIBS}中。
  • REQUIRED可选字段。表示一定要找到包,找不到的话就立即停掉整个cmake。而如果不指定REQUIRED则cmake会继续执行。

add_custom_command()与add_custom_target()


add_custom_target(Name [ALL] [command1 [args1...]]
                  [COMMAND command2 [args2...] ...]
                  [DEPENDS depend depend depend ... ]
                  [BYPRODUCTS [files...]]
                  [WORKING_DIRECTORY dir]
                  [COMMENT comment]
                  [JOB_POOL job_pool]
                  [VERBATIM] [USES_TERMINAL]
                  [COMMAND_EXPAND_LISTS]
                  [SOURCES src1 [src2...]])

用Name选项给定的名字添加一个目标,这个目标会引发给定的那些COMMAND命令。这个目标没有输出文件,并且总是被认为是过时的,即使那些命令试图去创建一个与该目标同名的文件。


cmake_minimum_required(VERSION 3.0)
project(test)

add_custom_target(CpTask
  COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/config ${CMAKE_CURRENT_SOURCE_DIR}/etc
  COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/log.txt ${CMAKE_CURRENT_SOURCE_DIR}/etc
  )
运行该CMakeLists.txt:
cmake ..
make CpTask

这段代码的目的就是将config文件夹的内容和log.txt文件复制到新的etc文件夹内。
add_custom_target生成一个目标CopyTask,该目标是用来复制文件夹或者复制文件的!也就是COMMAND中定义的操作。其中:${CMAKE_COMMAND}是CMake的路径,-E使CMake运行命令而不是构建,copy_directory和copy是cmake_command_line,再后面两个就是command_line的参数。当然,生成文件不仅仅只能是复制,还可以是其他的操作。而这些COMMAND操作,都在command_line中规定了。至于cmake_command_line的内容,可参考cmake的官方资料:Run a Command-Line Tool。

该命令的其他一些参数的含义:
ALL:表明该目标会被添加到默认的构建目标,使得它每次都被运行;
COMMAND:指定要在构建时执行的命令行;
DEPENDS:指定命令所依赖的文件;
COMMENT:在构建时执行命令之前显示给定消息;
WORKING_DIRECTORY:使用给定的当前工作目录执行命令。如果它是相对路径,它将相对于对应于当前源目录的构建树目录;
BYPRODUCTS:指定命令预期产生的文件。

add_custom_command(OUTPUT output1 [output2 ...]
                   COMMAND command1 [ARGS] [args1...]``
                   [COMMAND command2 [ARGS] [args2...] ...]
                   [MAIN_DEPENDENCY depend]
                   [DEPENDS [depends...]]
                   [BYPRODUCTS [files...]]
                   [IMPLICIT_DEPENDS <lang1> depend1
                                    [<lang2> depend2] ...]
                   [WORKING_DIRECTORY dir]
                   [COMMENT comment]
                   [DEPFILE depfile]
                   [JOB_POOL job_pool]
                   [VERBATIM] [APPEND] [USES_TERMINAL]
                   [COMMAND_EXPAND_LISTS])
                   
//这种命令格式定义了一条生成指定的文件(文件组)的命令。

cmake_minimum_required(VERSION 3.0)
project(test)

add_custom_command(OUTPUT COPY_RES
  COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/config ${CMAKE_CURRENT_SOURCE_DIR}/etc
  COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/log.txt ${CMAKE_CURRENT_SOURCE_DIR}/etc
  )

add_custom_target(CopyTask ALL DEPENDS COPY_RES)

add_custom_target生成一个目标CopyTask,该目标依赖于COPY_RES。而对于COPY_RES而言,它实际上是用来复制文件夹或者复制文件的!也就是COMMAND中定义的操作。


CMAKE的install 定制安装规则

  • CMAKE_INSTALL_PREFIX: 安装路径的前缀。修改cmake文件,加入:
    SET(CMAKE_INSTALL_PREFIX < install_path >)要加在 PROJECT(< project_name>) 之后。
  • 确定安装路径前缀后可在CMAKE中增加install指令。

1.目标文件的安装

install(TARGETS targets... [EXPORT <export-name>]
        [[ARCHIVE|LIBRARY|RUNTIME|FRAMEWORK|BUNDLE|
          PRIVATE_HEADER|PUBLIC_HEADER|RESOURCE]
         [DESTINATION <dir>]
         [INCLUDES DESTINATION [<dir> ...]]
         [PERMISSIONS permissions...]
         [CONFIGURATIONS [Debug|Release|...]]
         [COMPONENT <component>]
         [OPTIONAL] [NAMELINK_ONLY|NAMELINK_SKIP]
        ] [...])

   INSTALL指令用于定义安装规则,安装的内容可以包括目标二进制、动态库、静态库以及 文件、目录、脚本等。参数中的TARGETS后面跟的就是我们通过ADD_EXECUTABLE或者ADD_LIBRARY定义的 目标文件,可能是可执行二进制、动态库、静态库。目标类型也就相对应的有三种,ARCHIVE特指静态库,LIBRARY特指动态库,RUNTIME 特指可执行目标二进制。
   DESTINATION定义了安装的路径,如果路径以/开头,那么指的是绝对路径,这时候 CMAKE_INSTALL_PREFIX其实就无效了。如果你希望使用CMAKE_INSTALL_PREFIX来 定义安装路径,就要写成相对路径,即不要以/开头,那么安装后的路径就是 ${CMAKE_INSTALL_PREFIX}/<DESTINATION定义的路径>。


INSTALL(TARGETS run dylib staticlib
       RUNTIME DESTINATION bin
       LIBRARY DESTINATION lib
       ARCHIVE DESTINATION libstatic
)

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

2、目录的安装

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这个目录的内容会被安装在目标路径下;
如果目录名不以/结尾,那么这个目录将被安装为目标路径下的abc,如果目录名以/结尾, 代表将这个目录中的内容安装到目标路径,但不包括这个目录本身。
PATTERN用于使用正则表达式进行过滤,
PERMISSIONS用于指定PATTERN过滤后的文件权限。

install(DIRECTORY build/servers/ DESTINATION deploy/framework/servers
        PATTERN "tars*"
        PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ GROUP_EXECUTE GROUP_READ)
        
install(DIRECTORY deploy DESTINATION ./ 
        PATTERN "*.sh"
        PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ GROUP_EXECUTE GROUP_READ)
        ```
        
 将当前Source目录的相对路径build/servers/安装到${CMAKE_INSTALL_PREFIX}/deploy/framework/servers下。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值