CMake 学习笔记 02 - 更复杂的项目
CMake 学习笔记 02 - 更复杂的项目
源代码见 https://github.com/fengyc/cmake-tutorial
源代码目录组织
一般的项目,会划分为多个子目录,每个子目录中包含不同的模块,并定义好模块间的依赖关系。出于项目组织的需要,还会划分为 src 、 doc 、 tool/utils 、 build 等目录。
以第一个 helloworld 项目为例,现在把源代码 main.c 放到 src 目录下,并将生成的内容放到 bin 目录下,形成 helloworld2 。
每个子目录下都需要一个 CMakeLists.txt,src 中的 CMakeLists.txt 内容如下::
ADD_EXECUTABLE(hello main.c)
如果这个子目录生成的是一个库,那么可用 ADD_LIBRARY
指令。
顶层目录的 CMakeLists.txt 内容如下 ::
PROJECT(HELLO)
ADD_SUBDIRECTORY(src bin)
ADD_SUBDIRECTORY
指令用于向项目添加子目录,用法为 ADD_SUBDIRECTORY(源代码目录 Binary目录)
。如果不加 Binary 目录,相当于直接在构建目录中对应的源代码目录中保存中间生成的文件。通过 SET 指令,指定 EXECUTABLE_OUTPUT_PATH
和 LIBRARY_OUTPUT_PATH
,可覆盖之前设置的目标输出,如 ::
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
(PROJECT_BINARY_DIR
为构建目录,即 build 目录)
整个目录树如下 ::
.
├── CMakeLists.txt
└── src
├── CMakeLists.txt
└── main.c
同样可建立 build 目录,然后进行外部构建 ::
mkdir build
(cd build; cmake ..; build)
这时,会在 build/bin
目录下生成 hello
可执行文件。
安装
cmake 的 INSTALL 指令用于进行安装,它使用到 CMAKE_INSTALL_PREFIX
用于指定安装位置。执行时用 ::
cmake -DCMAKE_INSTALL_PREFIX=/usr/local install
进行安装。
INSTALL 可安装目标文件(生成的文件)、普通文件、非目标可执行文件等等。
安装目标文件如下 ::
INSTALL(TARGETS targets...
[
[ARCHIVE|LIBRARY|RUNTIME]
[DESTINATION <dir>]
[PERMISSIONS permissions...]
[CONFIGURATIONS [Debug|Release|...]]
[COMPONENT <component>]
[OPTIONAL]
] [...])
TARGETS 后面为通过 ADD_EXECUTABLE
和 ADD_LIBRARY
添加的目标,类型 RUNTIME 为可执行目标文件,ARCHIVE 为静态类库,LIBRARY 为动态类库,DESTINATION 为目标路径,通常是用相对于 CMAKE_INSTALL_PREFIX
的路径。这里不需要关注目标文件生成时的具体路径,cmake 会自动进行寻找,如 ::
INSTALL(TARGETS myrun mylib mystaticlib
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib
ARCHIVE DESTINATION libstatic)
非目标普通文件或可执行文件,如一些辅助脚本 ::
INSTALL(FILES|PROGRAMS files... DESTINATION <dir>
[PERMISSIONS permissions...]
[CONFIGURATIONS [Debug|Release|...]]
[COMPONENT <component>]
[RENAME <name>] [OPTIONAL])
如 ::
INSTALL(FILES my.conf DESTINATION etc/${PROJECT_NAME})
INSTALL(PROGRAMS my.sh DESTINATION bin)
FILES 和 PROGRAMS 的区别在于安装后的文件默认权限不同,PROGRAMS 自动加上可执行。
安装源代码中的目录 ::
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...]]
[...])
如 ::
INSTALL(DIRECTORY init/ DESTINATION /etc/init
PATTERN "*.conf")
目录列表中路径写法需要注意,它是相对于源代码中的路径,abc
表示拷贝整个目录(包含目录本身),abc/
表示只拷贝目录内的内容(不包含目录本身)。
更新项目
现在更新项目来支持安装,复制 helloworld2 整个项目到 helloworld3 。
往里面加入 doc/hello.txt
,随便写点东西。在源代码根目录加一个 README 文件,随便写点东西。加入一个 runhello.sh 文件,调用 hello,内容为 ::
#!/bin/sh
./hello
修改顶层目录上的 CMakeLists.txt,增加安装内容,整个文件内容为 ::
PROJECT(HELLO)
ADD_SUBDIRECTORY(src)
INSTALL(PROGRAMS runhello.sh DESTINATION bin)
INSTALL(FILES README DESTINATION share/doc/${PROJECT_NAME})
INSTALL(DIRECTORY doc/ DESTINATION share/doc/${PROJECT_NAME})
修改 src 中的 CMakeLists.txt,增加安装内容 ::
ADD_EXECUTABLE(hello main.c)
INSTALL(TARGETS hello DESTINATION bin)
用 (cd build; cmake -DCMAKE_INSTALL_PREFIX=$PWD/usr ..; make install)
进行构建,以及在 build 目录的 usr 下进行安装。在默认情况下,CMAKE_INSTALL_PREFIX
为 /usr/local
,这里改为 build 中的 usr 。