cmake-buildsystem研究
综述
详细内容
cmake的构建系统是基于逻辑层上的构造目标的,基本的构造目标有:
可执行文件,库。
由此cmake的基本指令有:
add_excutable() // 可执行文件
add_library() // 库
add_excutable()
add_executable(<name> [WIN32] [MACOSX_BUNDLE]
[EXCLUDE_FROM_ALL]
[source1] [source2 ...])
通过add_exectuable()可以用于添加可执行文件的目标,在以前的版本中,add_exectuable()必须
加上所涉及的源文件,当前的cmake版本有target_sources()指令,可以在之后来添加相关的源文件。
<name>必须全局独特。
可执行文件的生成目录默认在add_executable()执行的目录。
当然可以通过RUNTIME_OUTPUT_DIRECTORY属性进行设置;可以通过
OUTPUT_NAME来修改最后生成的可执行文件的名称。
WIN32如果设置了该参数,则会通知cmake,当前的目标拥有一个WinMain()函数,目标应该是一个Windows的
窗体程序,而不是命令行程序。
以MFC程序为例:
add_definitions(-D_AFXDLL)
set(CMAKE_MFC_FLAG 2) // 1 使用静态MFC库; 2 使用动态MFC库;
add_executable(CMakeSetup WIN32 ${SRCS})
MACOSX_BUNDLE如果设置了该参数,则说明当前是一个可以从Finder启动的界面程序
cmake会以MacOSXBundleInfo.plist.in为模板构造该应用的Info.plist文件,
可以通过设置一下属性来设置文件的基本内容:
MACOSX_BUNDLE_BUNDLE_NAME
// Sets CFBundleName.
MACOSX_BUNDLE_BUNDLE_VERSION
// Sets CFBundleVersion.
MACOSX_BUNDLE_COPYRIGHT
// Sets NSHumanReadableCopyright.
MACOSX_BUNDLE_GUI_IDENTIFIER
// Sets CFBundleIdentifier.
MACOSX_BUNDLE_ICON_FILE
// Sets CFBundleIconFile.
MACOSX_BUNDLE_INFO_STRING
// Sets CFBundleGetInfoString.
MACOSX_BUNDLE_LONG_VERSION_STRING
// Sets CFBundleLongVersionString.
MACOSX_BUNDLE_SHORT_VERSION_STRING
// Sets CFBundleShortVersionString.
要生成的目标(可执行文件或库)可能会依赖第三方库,此时通过target_link_libraries()进行
添加依赖。
add_library(archive archive.cpp zip.cpp lzma.cpp)
// archive是一个静态库
add_executable(zipapp zipapp.cpp)
target_link_libraries(zipapp archive)
EXCLUDE_FROM_ALL参数是用来设置当前目标是否从属于all,如果设置了这个参数,那么在实际编译all的时候,
这个目标不会被编译;只得注意的是,如果设置了这个属性,最后不要实际调用install(target),可能会引发未知
操作
add_executable(<name> IMPORTED [GLOBAL])
// 这个IMPORTED是用来将第三方可执行文件或库引入cmake的构建路径的
// 笔者能想到的用法是,比如qt的moc,doxygen的doxygen.exe以及swig的swig.exe这类
// 用来处理文件的可执行文件
若未设置GLOBAL属性,则name所对应的可执行文件作用于该指令被调用的目录及子目录,
可以通过GLOBAL使其作用域作用于全局。
可以通过设置name的IMPORTED_LOCATION属性来设置库所在的位置:
add_executable(a.exe IMPORTED)
set_target_property(libz IMPORTED_LOCATION ../../3rdpart/libz/bin/a.exe)
在引入第三方可执行文件之后,可以结合add_cunstom_command()来执行需要的操作
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])
add_custom_command(TARGET <target>
PRE_BUILD | PRE_LINK | POST_BUILD
COMMAND command1 [ARGS] [args1...]
[COMMAND command2 [ARGS] [args2...] ...]
[BYPRODUCTS [files...]]
[WORKING_DIRECTORY dir]
[COMMENT comment]
[VERBATIM] [USES_TERMINAL]
[COMMAND_EXPAND_LISTS])
// 用法示例
set(TEST_FILE "log.txt")
add_custom_command(OUTPUT ${TEST_FILE}
COMMAND echo "Generating log.txt file..."
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_LIST_FILE} ${TEST_FILE}
COMMENT "This is a test" )
add_custom_target(Test1 ALL DEPENDS ${TEST_FILE})
// add_cunstom_target()添加的目标是一个虚目标,可以没有这个文件
// cmake每次都会认为该目标过期需要更新
add_custom_command(TARGET Test1
PRE_BUILD
COMMAND echo "executing a fake command"
COMMENT "This command will be executed before building target Test1" )
add_executable(<name> ALIAS <target>)
// ALIAS 假的
// 这个用来添加假目标,提供给另一个cmake的工程使用
// proj 1
add_library(lib1 lib1.cpp)
install(TARGETS lib1 EXPORT lib1Export ${dest_args})
install(EXPORT lib1Export NAMESPACE Upstream:: ${other_args})
add_library(Upstream::lib1 ALIAS lib1)
// proj 2
if (NOT TARGET Upstream::lib1)
find_package(lib1 REQUIRED)
endif()
add_executable(exe1 exe1.cpp)
target_link_libraries(exe1 Upstream::lib1)
add_library()
注意:对库来说,如果是静态库,则RUNTIME_OUTPUT_DIRECTORY,LIBRARY_OUTPUT_DIRECTORY参数无效,用来设置
静态库输出目录的参数为ARCHIVE_OUTPUT_DIRECTORY。
动态库可以通过RUNTIME_OUTPUT_DIRECTORY参数来设置运行时文件的输出目录,通过LIBRARY_OUTPUT_DIRECTORY参数
来设置库文件的输出目录。
add_library(<name> [STATIC | SHARED | MODULE]
[EXCLUDE_FROM_ALL]
[source1] [source2 ...])
add_library(archive SHARED archive.cpp zip.cpp lzma.cpp)
// 此时目标为动态库
add_library(archive STATIC archive.cpp zip.cpp lzma.cpp)
// 此时目标为静态库
// 静态库
add_library(lib_3rdpart_s STATIC IMPORTED)
set_target_property(lib_3rdpart IMPORTED_LOCATION "../../3rdpart/lib_3rdpart_s/lib/lib_3rdpart_s.lib")
// 动态库
add_library(lib_3rdpart_d SHARED IMPORTED)
set_target_property(lib_3rdpart IMPORTED_LOCATION "../../3rdpart/lib_3rdpart_d/lib/lib_3rdpart_s.dll")
set_target_property(lib_3rdpart IMPORTED_IMPLIB "../../3rdpart/lib_3rdpart_d/lib/lib_3rdpart_s.lib")
target_include_directories/target_compile_definitions/target_compile_options
以下三个命令都有PRIVATE,PUBLIC和INTERFACE三种模式
PRIVATE只修改非-INTERFACE变量,INTERFACE只修改INTERFACE变量,PUBLIC修改所有变量
target_compile_definitions(archive
PRIVATE BUILDING_WITH_LZMA
INTERFACE USING_ARCHIVE_LIB
)
target_include_directories()
用于设置INCLUDE_DIRECTORIES,INTERFACE_INCLUDE_DIRECTORIES
编译指令等价于-I或-isystem
target_compile_definitions()
用于设置COMPILE_DEFINITIONS,INTERFACE_COMPILE_DEFINITIONS
编译指令等价于-D或/D
target_compile_options()
用于设置COMPILE_OPTIONS,INTERFACE_COMPILE_OPTIONS
set(srcs archive.cpp zip.cpp)
if (LZMA_FOUND)
list(APPEND srcs lzma.cpp)
endif()
add_library(archive SHARED ${srcs})
if (LZMA_FOUND)
# The archive library sources are compiled with -DBUILDING_WITH_LZMA
target_compile_definitions(archive PRIVATE BUILDING_WITH_LZMA)
endif()
target_compile_definitions(archive INTERFACE USING_ARCHIVE_LIB)
add_executable(consumer)
# Link consumer to archive and consume its usage requirements. The consumer
# executable sources are compiled with -DUSING_ARCHIVE_LIB.
target_link_libraries(consumer archive)
可以通过变量CMAKE_INCLUDE_CURRENT_DIR来设置当前构建目标的包含目录,而不是使用INCLUDE_DIRECTORIES全局的变量。
target_link_libraries()
用于设置依赖
add_library(archive archive.cpp)
target_compile_definitions(archive INTERFACE USING_ARCHIVE_LIB)
add_library(serialization serialization.cpp)
target_compile_definitions(serialization INTERFACE USING_SERIALIZATION_LIB)
add_library(archiveExtras extras.cpp)
target_link_libraries(archiveExtras PUBLIC archive)
target_link_libraries(archiveExtras PRIVATE serialization)
# archiveExtras is compiled with -DUSING_ARCHIVE_LIB
# and -DUSING_SERIALIZATION_LIB
add_executable(consumer consumer.cpp)
# consumer is compiled with -DUSING_ARCHIVE_LIB
target_link_libraries(consumer archiveExtras)