【编译工具】CMake【梳理】(编辑中)

本文详细介绍CMake的基础语法和高级用法,包括项目设置、文件管理、编译路径自定义及安装打包等内容。并通过实例演示如何组织项目结构,实现源码、文档及脚本的统一管理与安装。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

【接触CMake有一段时间了,基于自己的经验再总结下,迭代下理解版本】

一、语法篇
    对于快速上手的需求不需要通读所有的技巧,选些重要的来进行记录,冷门、偏门的后期补充。
  • PROJECT指令
语法格式:PROJECT(projectname [CXX][C][Java])
语法讲解:方括号中内容为可选,意为工程所支持语言。该语法含义为指定工程名称,当语言列表为空时,代表支持所有语言
  • 几个隐式指令 
1、两个cmake变量
语法格式:<projectname>_BINARY_DIR、<projectname>_SOURCE_DIR
语法讲解:projectname为project指令定义的工程名称,这两个变量代表工程所在的路径。cmake还预定义了PROJECT_BINARY_DIR和PROJECT_SOURCE_DIR变量,
它们值分别跟HELLO_BINARY_DIR和HELLO_SOURCE_DIR一致,是个范称,即使修改了工程名称,也不会影响这两个变量。如果使用了<projectname>_SOURCE_DIR, 修改工程名称后,需要同时修改这些变量。
  • set指令      
语法格式:SET(VAR [VALUE][CACHE TYPE DOCSTRING [FORCE]])
语法讲解:显示地定义变量。
例       如:单个源文件set(SRC_LIST hhh.cxx),多个源文件时set(SRC_LIST t1.cxx t2.cxx t3.cxx)
  • MESSAGE指令
语法格式:MESSAGE([SEND_ERROR | STATUS | FATAL_ERROR] "message to display" ...)
语法讲解:SEND_ERROR产生错误,生成过程被跳过,STATUS输出前缀为一的信息,FATAL_ERROR立即终止所有cmake过程,通常用STATUS比较多
例       如:MESSAGE(STATUS, "This is a Binary dir ", ${PROJECT_BINARY_DIR})

  • ADD_SUBDIRECTORY指令
语法格式:ADD_SUBDIRECTORY (source_dir [binary_dir] [EXCLUDE_FROM_ALL])
语法讲解:用于向当前工程添加存放源文件的子目录,并可指定中间二进制和目标二进制存放位置。EXCLUDE_FROM_ALL参数为将这个目录从编译过程中排除。
例      如:ADD_SUBDIRECTORY (src bin)
将src子目录加入工程,并指定编译输出(包含编译中间结果)路径为bin目录。如果不进行bin目录指定,那么编译结果(包括中间结果)都存放在build/src目录 对应),指定bin目录后,相当于在编译时将src重命名为bin,所有的中间结果和目标二进制都将存放在bin目录
WARNING:注意SUBDIRS指令,一般不推荐使用。语法为SUBDIRS(dir1 dir2....),它可以一次添加多个子目录,并且即使外部编译,子目录体系仍然会被保存
如果将上面示例ADD_SUBDIRECTORY(src bin)修改为SUBDIRS(src),那么在build目录中将出现一个src目录,生成的目标代码hello将存放在src目录中。

自定义保存目标二进制文件位置时,不论是SUBDIRS还是ADD_SUBDIRECTORY指令(不论是否制定编译输出目录),都可用SET指令重新定义EXECUTABLE_OUTPUT_PATH和LIBRARY_OUTPUT_PATH变量来指定最终的目标二进制位置(指最终生成的hello或最终共享库,不包含编译生成的中间文件),

如:SET (EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)

      SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
BINARY_DIR目录指的是编译发生的当前目录,如果是内部编译,则相当于SOURCE_DIR目录,即为工程代码所在目录;如果是外部编译,指的是外部编译所在目录,即为本例中build目录,故上述代码执行的输出路径为:build/bin和库的输出路径为build/lib。这两条指令写在哪个目录下的CMakeLists.txt文件中呢?一个简单原则:在哪里ADD_EXECUTABLE或ADD_LIBRARY,如果需要改变目标存放路径,就在哪里加入上述定义。在本例则为src下的CMakeLists.txt
  • 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后面连接的是source目录的相对路径, 务必注意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,不包含目录名为CVS目录,对于scripts/*文件指定权限为OWNER_EXECUTE OWNER_WRITE OWNER_READ GROUP_EXECUTE GROUP_READ

安装时CMAKE脚本执行
INSTALL([[SCRIPT <file>] [CODE <code>]] [...])
SCRIPT参数用于在安装时调用cmake脚本文件(也就是<abc>.cmake文件)
CODE参数用于执行CMAKE指令,必须以双引号括起来。比如:
INSTALL(CODE “MESSAGE (”Sample install message.")"),安装还有几个被标记为过时的指令,比如INSTALL_FILES等,这些指令已经不推荐再使用
  • ads
......待续
  • 基本常用语法规则
1、变量使用${}方式取值,可用加引号的方式表达(“${}”),但在IF控制语句中直接使用变量名。${ } 表示引用变量,是cmake的变量应用方式。在if控制语句中,变量时直 接使用变量名引用,而不需要${}。如果使用了${}去应用变量,if会去判断名为${}所代表值的变量,那是不存在的

2、指令_(参数1_参数2....)
  _表示在格式上中间用空格隔开。参数使用括弧扩起,参数之间使用空格或分号分开
 如:add_executable (Tutorial tutorial.cxx)


3、指令不分大小写,参数和变量区分大小写。一般建议全部使用大写指令
  如: MESSAGE(STATUS "This is SOURCE dir" ${PROJECT_SOURCE_DIR})
 也可写成:MESSAGE(STATUS "This is SOURCE dir ${PROJECT_SOURCE_DIR}")

  • 一些技巧
1、cmake语法非常灵活,如SET (SRC_LIST main.cxx)也可以写成SET (SRC_LIST "main.cxx"),但是如果当源文件的文件名是fu nc.cxx(中间含有空格)时这时就必须使 用双引号,如果写成SET (SRC_LIST fu nc.cxx)则会出错,提示找不到fu、nc.cxx这两个文件,此时应写成SET (SRC_LIST "fu nc.cxx")。此外,cmake还可以忽略掉source 列表中的源文件后缀,它会在本目录下自动查找源文件,同时参数也可用分号来进行分割,不过不建议这样做

2、make clean 对构建结果进行清理
    (补充make一些常见命令作对比,后期有专题介绍)
   make 根据makefile编译源代码,链接,生成目标文件,可执行文件
   make clean清除上次make命令所产生的object文件(后缀为.o文件)及可执行文件
   make install将编译成功的可执行文件安装到系统目录中,一般为/usr/local/bin目录
   make dist 产生发布软件包文件(即distribution package)将可执行文件和相关文件打包成一个tar.gz压缩的文件用来作为发布软件的软件包。它一般在当前目录下生成一  个名字类似“PACKAGE-VERSION.tar.gz”文件。PACKAGE和VERSION是configure.in中定义的AM_INIT_AUTOMAKE(PACKAGE_VRESION)
   make distcheck 生成发布软件包并对其进行测试检查,以确定发布包的正确性。这个操作将自动把压缩包文件解开,然后执行configure命令,并且执行make来编译不出         现错误,最后提示软件包准备好,可以发布
   make distclean类似make clean,但同时也将configure生成的文件全部删除掉,包括makefile。也就是make distclean要删除所有文件,而make clean则删除之前编译的  可执行文件及配置文件
3、cmake不支持make distclean
内部构建与外部构建
内部构建:会生成一些无法自动删除的中间文件
外部构建:另外建立目录,将中间文件保存在编译目录。外部构建对原有工程没有任何影响,所有动作全部发生在编译目录
cmake推荐外部构建

4、如何安装打包代码、安装代码

打包

两种方法:一种从代码编译后直接make install安装,一种是打包时指定目录安装

如:

DESTDIR=

install:

mkdir -p $(DESTDIR)/usr/bin

install -m 755 hello $(DESTDIR)/usr/bin

可通过:

make install

将hello直接安装到/usr/bin目录,也可通过

make install DESTDIR=/tmp/test

将它安装在/tmp/test/usr/bin目录,打包时经常被使用。稍微复杂一点还需定义PREFIX,一般autotools工程,会运行这样指令:

./configure -prefix=/usr或者./configure --prefix=/usr/local

来指定PREFIX,即将上面Makefile改写为:

DESTDIR=

PREFIX=/usr

install:

mkdir -p $(DESTDIR)/$(PREFIX)/bin

install -m 755 hello $(DESTDIR)/$(PREFIX)/bin


安装:

安装时引入一个新的cmake指令INSTALL和一个非常有用的变量:CMAKE_INSTALL_PREFIX,它的默认路径定义为:/usr/local

CMAKE_INSTALL_PREFIX类似于configure脚本的-prefix。常见使用方法为:cmake -DCMAKE_INSTALL_PREFIX=/usr.


二、cmake进阶用法
采用外部构建(out-of-source),在工程目录下build目录
需求:
1、为工程添加一个子目录src,用来放置工程源码
2、添加一个子目录doc,用来放置工程文档
3、在工程目录添加文本文件COPYRIGHT,README
4、在工程目录添加一个runhello.sh脚本,用来调用hello二进制
5、将构建后的目标文件放入构建目录bin子目录中
6、最终安装这些文件:将hello二进制文件与runhello.sh安装至/usr/local/bin,将doc目录内容以及COPYRIGHT/README安装到/usr/share/doc/cmake/,将                               在/backup/cmake/目录下建立目录,将工程中的main.cxx和CMakeLists.txt拷贝到目录中

实现:

1、准备

在/backup/cmake/目录下建立t2目录

在t1工程的main.cxx和CMakeLists.txt拷贝到t2目录

2、添加子目录src



三、参考文档
   1、make clean 与make distclean 区别 http://www.cnblogs.com/hnrainll/archive/2011/06/08/2075052.html


   2、cmake教程 http://wenku.baidu.com/view/83a51d150b4e767f5acfceee.html


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值