上一个笔记中,从内部构建转向了外部构建,自此之后,将会一直采用外部构建方式,设定构建目录是工程目录下的build目录;
上一个笔记中,工程目录下只有build文件夹、源文件和CMakeLists.txt文件;在简单项目中,这样的目录结构还合适,在以后实际项目中,会有更多源文件,更多依赖的外部第三方库文件等等,目录结构就会更为复杂,先将之前例子进行优化,为以后复杂项目构建打好基础;
之前的目录结构如下:
处理Hello例子的步骤:
1.增加src文件夹,用来存放工程源代码;
2.增加doc文件夹,用来存放这个工程的文档hello.txt;
3.在项目根目录中增加文本文件COPYRIGHT,README;
4.在项目根目录中增加runhello.sh脚本,用来执行hello二进制文件;
5.在cmake后会自动增加build/bin文件夹,用于存放构建后的目标文件;
6.安装可执行文件和.sh文件;
将 hello 二进制与 runhello.sh 安装至/usr/bin;
将doc目录的内容以及COPYRIGHT/README 安装到/usr/share/doc/cmake/t1
更改后的目录结构;
src文件夹下的CMakeLists.txt内容
ADD_EXECUTABLE(hello main.c)
项目根目录下的CMakeLists.txt内容
PROJECT(HELLO)
ADD_SUBDIRECTORY(src bin)
在build目录下,执行cmake …/
执行make后,在bin目录出现hello文件;
bin目录结构如下:
新增指令
ADD_SUBDIRECTORY
ADD_SUBDIRECTORY(source_dir [binary_dir] [EXCLUE_FROM_ALL])
该指令用于向当前项目工程中添加源文件目录,指定中间二进制文件目录以及目标二进制文件存放的目录;
EXCLUE_FROM_ALL参数的含义是将这个目录从编译过程中排除;
ADD_SUBDIRECTORY(src bin)
意思是:将src源文件目录加入工程中,指定编译输出(包含编译中间结果)路径为bin目标,如果bin目录不存在,则自动生成bin目录,如果不指定binary_dir目录,则将使用源文件目录名字,在当前的例子下是build/src/,指定binary_dir目录后,相当于在编译时将src重命名为bin。
SET重定义
cmake中使用EXECUTABLE_OUTPUT_PATH 定义目标二进制可执行文件的存放位置,使用LIBRARY_OUTPUT_PATH 定义目标链接库文件的存放位置;
可以通过SET指令重新定义EXECUTABLE_OUTPUT_PATH和LIBRARY_OUTPUT_PATH变量来指定最终的目标二进制的位置(指最终生成的hello或者最终的共享库,不包含编译生成 的中间文件);
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
EXECUTABLE_OUTPUT_PATH和LIBRARY_OUTPUT_PATH同ADD_EXECUTABLE或ADD_LIBRARY一起写入同一个CMakeLists.txt中。
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])
上面的INSTALL格式可用于安装一般文件,并可以指定访问权限,文件名是此指令所在路径下的相对路径。
如果默认不定义权限PERMISSIONS,安装后文件的权限为: OWNER_WRITE|OWNER_READ|GROUP_READ|WORLD_READ,即644权限(110100100);
非目标文件的可执行程序安装
非目标文件的可执行程序(脚本类文件)安装:
INSTALL(PROGRAMS files... DESTINATION <dir>
[PERMISSIONS permissions...]
[CONFIGURATIONS [Debug|Release|...]]
[COMPONENT <component>]
[RENAME <name>]
[OPTIONAL])
与之前的FILES指令使用方法一样,唯一的不同是安装后权限为:
OWNER_EXECUTE|GROUP_EXECUTE|WORLD_EXECUTE,即755权限(111101101)
目录的安装
INSTALL(DIRECTORY dirs... DESTINATION <dir>
[FILE_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/ DESTIONATION 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 OWNER_WRITE OWNER_READ GROUP_EXECUTE GROUP_READ;
安装时 CMAKE 脚本的执行
INSTALL([[SCRIPT <file>] [CODE <code>]] [...])
SCRIPT 参数用于在安装时调用 cmake 脚本文件(也就是.cmake 文件)
CODE 参数用于执行 CMAKE 指令,必须以双引号括起来。比如:
INSTALL(CODE “MESSAGE(“Sample install message.”)”)
新项目结构
在项目目录t1中增加doc文件夹,doc内随便来一个txt;
增加COPYRIGHT和README文件;
增加runhello.sh,内部写入./hello
更改t1目录下的CMakeLists.txt文件内容:
PROJECT(HELLO)
ADD_SUBDIRECTORY(src bin)
INSTALL(FILES COPYRIGHT README DESTINATION share/doc/cmake/t1)
INSTALL(PROGRAMS runhello.sh DESTINATION bin)
INSTALL(DIRECTORY doc/ DESTINATION share/doc/cmake/t1)
INSTALL(TARGETS hello RUNTIME DESTINATION bin)
1.拷贝COPYRIGHT和README文件到<prefix>/share/doc/cmake/t1目录下;
2.拷贝runhello.sh到<prefix>bin目录下;
3.拷贝doc文件夹内的所有文件到<prefix>/share/doc/cmake/t1目录下;
4.拷贝hello可执行文件到<prefix>bin目录下;
注意:CMAKE_INSTALL_PREFIX默认定义是/usr/local;
在build目录下执行cmake DCMAKE_INSTALL_PREFIX=/tmp/t1/usr …/
执行make
执行make install
在/tmp/t1/usr/bin/下执行runhello.sh
参考资料
1.《cmake 实践》