CMake Tutorial

add_custom_command

例如,Glow中在编译时运行编译得到的InstrGen和NodeGen生成对应的源代码文件,用于接下来的编译。

1
2
3
4
5
6
7
8
9
10
11
12
# AutoGenNodes
set(NODES_HDR ${GLOW_BINARY_DIR}/glow/AutoGenNodes.h)
set(NODES_SRC ${GLOW_BINARY_DIR}/glow/AutoGenNodes.cpp)
set(NODES_DEF ${GLOW_BINARY_DIR}/glow/AutoGenNodes.def)

add_custom_command(OUTPUT
"${NODES_HDR}"
"${NODES_SRC}"
"${NODES_DEF}"
COMMAND NodeGen ${NODES_HDR} ${NODES_SRC} ${NODES_DEF}
DEPENDS NodeGen
COMMENT "NodeGen: Generating nodes." VERBATIM)

在文件改变时拷贝文件到指定目录。

1
2
3
4
add_custom_command(
OUTPUT ${GLOW_BINARY_DIR}/glow/caffe.pb.h
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CAFFE_HDRS} ${GLOW_BINARY_DIR}/glow/caffe.pb.h
DEPENDS ${CAFFE_HDRS})

然而,仅仅这样,命令并不会被执行。除非其OUTPUT时某个target的依赖项。

1
2
3
4
5
6
7
8
9
10
11
add_library(Importer
ProtobufLoader.cpp
Caffe2.cpp
Caffe.cpp
ONNX.cpp
ONNXIFILoader.cpp
ONNXExporter.cpp
${CAFFE_SRCS}
${CAFFE2_SRCS}
${GLOW_BINARY_DIR}/glow/caffe.pb.h
${GLOW_BINARY_DIR}/glow/caffe2.pb.h)

因此一个办法是,作为某个target/library的依赖项;另一办法是专门为某个源文件添加property。
set_property(SOURCE Caffe.cpp APPEND PROPERTY OBJECT_DEPENDS ${GLOW_BINARY_DIR}/glow/caffe.pb.h)

find_package

如何知道某个库是否支持find_package方法呢,如find_package(Protobuf)

  1. find_package使用

macOS
在cmake安装的目录路径$PREFIX/share/cmake/Modules中(如果用brew 默认安装cmake则为/usr/local/Cellar/cmake/share/cmake/Modules),我们可以看到大量的[package].cmake文件,如FindProtobuf.cmake, FindPNG.cmake, FindMPI.cmake等。这些可以看作是默认支持的软件包。

当我们安装gflags,则可以在/usr/local/lib/cmake/中找到gflags/目录,其中包括了gflags-config.cmake等文件。

此外,可以自己编写文件用于find_package.参见cmake文档。

install 命令

参考
CMake的install
SirDigit的博客

install命令并非在cmake或者make编译时运行,而是在编译后执行install时。
以makefile为例,cmake中的install命令会生成到对应的Makefile中,对应make install命令。

CMAKE_INSTALL_PREFIX : 默认安装路径,一般是/usr/local,可以用message命令打印查看。
message(STATUS “${CMAKE_INSTALL_PREFIX}”)

TARGETS版本的install命令

1
2
3
4
5
6
7
8
9
install(TARGETS targets... [EXPORT <export-name>]
[[ARCHIVE|LIBRARY|RUNTIME|FRAMEWORK|BUNDLE|
PRIVATE_HEADER|PUBLIC_HEADER|RESOURCE]
[DESTINATION <dir>]
[PERMISSIONS permissions...]
[CONFIGURATIONS [Debug|Release|...]]
[COMPONENT <component>]
[OPTIONAL] [NAMELINK_ONLY|NAMELINK_SKIP]
] [...])

其中,静态链接库对应ARCHIVE;链接库对应LIBRARY;可执行文件则是RUNTIME。

安装期间要执行脚本或者代码,如打印信息。可以使用CODE或者SCRIPAT版本的install命令,如
install(CODE “MESSAGE(\“some message\”)”)

cmake 命令时的宏-DMACRONAME=XXX

为了实现LEVELDEBUG,即将cmake命令添加-DLEVELDEBUG=5时,当且仅当DEBUG(i) << 中的i>=5时方进行打印。
遇到的问题如下。
1.设置LEVELDEBUG宏

1
2
cmake -DCMAKE_BUILD_TYPE=Debug .. -DLEVELDEBUG=5
vim vim CMakeFiles/testDSL.dir/flags.make

结果
CXX_DEFINES = -DLEVELDEBUG=5

2.命令中去除LEVELDEBUG宏

1
2
cmake -DCMAKE_BUILD_TYPE=Debug ..
vim CMakeFiles/testDSL.dir/flags.make

结果中仍然有该宏。
CXX_DEFINES = -DLEVELDEBUG=5
另外Release模式,该宏还是存在。

3.设置Release模式时,将该宏设置为极大值100.

1
2
3
4
5
6
7
if(LEVELDEBUG)
if(CMAKE_BUILD_TYPE STREQUAL Debug)
add_definitions(-DLEVELDEBUG=${LEVELDEBUG})
else()
add_definitions(-DLEVELDEBUG=100)
endif()
endif ()

测试

1
2
cmake -DCMAKE_BUILD_TYPE=Release ..
vim CMakeFiles/testDSL.dir/flags.make

结果中
CXX_DEFINES = -DLEVELDEBUG=100

4.再次切换回Debug模式

1
2
cmake -DCMAKE_BUILD_TYPE=Debug ..
vim CMakeFiles/testDSL.dir/flags.make

结果仍然恢复为CXX_DEFINES = -DLEVELDEBUG=5
这个5可能来自cache中。有待考证。

相关讨论
cmake: how to check if preprocessor is defined - Stack Overflow