CMake中add_custom_command的使用

      CMake中的add_custom_command命令用于将自定义构建规则添加到生成的构建系统(Add a custom build rule to the generated build system),其格式如下:

add_custom_command(OUTPUT output1 [output2 ...]
                   COMMAND command1 [ARGS] [args1...]
                   [COMMAND command2 [ARGS] [args2...] ...]
                   [MAIN_DEPENDENCY depend]
                   [DEPENDS [depends...]]
                   [BYPRODUCTS [files...]]
                   [IMPLICIT_DEPENDS  depend1
                                    [ depend2] ...]
                   [WORKING_DIRECTORY dir]
                   [COMMENT comment]
                   [DEPFILE depfile]
                   [JOB_POOL job_pool]
                   [VERBATIM] [APPEND] [USES_TERMINAL]
                   [COMMAND_EXPAND_LISTS]) # Generating Files

add_custom_command(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]) # Build Events

      1.Generating Files:添加自定义命令以生成输出。这定义了生成指定输出文件的命令。
      选项包括:
      (1).APPEND:将COMMAND和DEPENDS选项值附加到指定的第一个输出的自定义命令。之前必须已经调用过具有相同输出的此命令。
      (2).BYPRODUCTS:指定命令预期生成的文件。如果副产品(byproduct)名是相对路径,它将相对于当前源目录相对应的构建树目录进行解释。每个副产品文件都将自动标记为GENERATED源文件属性。
      (3).COMMAND:指定要在构建时执行的命令行。如果指定了多个COMMAND,它们将按顺序执行,但不一定组成有状态的shell或batch脚本。可选的ARGS参数是为了向后兼容。
      (4).COMMENT:在构建时执行命令之前显示给定的消息。
      (5).DEPENDS:指定命令所依赖的文件。每个参数都转换为依赖项。如果未指定DEPENDS,则只要缺少OUTPUT,该命令就会运行;如果该命令实际上并未创建OUTPUT,则该规则将始终运行。
      (6).COMMAND_EXPAND_LISTS:COMMAND参数中的列表(list)将被扩展。
      (7).IMPLICIT_DEPENDS:请求扫描输入文件的隐式依赖项。给定的语言指定应使用其相应依赖扫描器的编程语言(programming language).目前仅支持C和CXX语言扫描器。必须为IMPLICIT_DEPENDS列表中的每个文件指定语言。IMPLICIT_DEPENDS选项目前仅支持Makefile生成器,其它生成器将忽略该选项。
      此选项不能与DEPFILE选项同时指定。
      (8).JOB_POOL:为Ninja生成器指定一个池(pool).
      (9).MAIN_DEPENDENCY:指定命令的主要输入源文件。每个源文件最多可以有一个命令将其指定为其主要依赖项。编译命令(即用于库或可执行文件)算作隐式主要依赖项,它会被自定义命令规范悄悄覆盖。
      (10).OUTPUT:指定命令预期生成的输出文件。如果输出名是相对路径,它将相对于当前源目录相对应的构建树目录进行解释。每个输出文件都将自动标记为GENERATED源文件属性。如果自定义命令的输出实际上并未创建为磁盘上的文件,则应使用SYMBOLIC源文件属性对其进行标记。
      (11).USES_TERMINAL:如果可能,该命令将被授予直接访问终端(terminal)的权限。
      (12).VERBATIM:命令的所有参数都将为构建工具正确转义(escaped),以便调用的命令接收每个参数不变。建议使用VERBATIM,因为它可以实现正确的行为。当没有给出VERBATIM时,行为是特定于平台的。
      (13).WORKING_DIRECTORY:使用给定的当前工作目录执行命令。如果是相对路径,会被解释为相对于当前源目录对应的构建树目录。
      (14).DEPFILE:指定一个包含自定义命令依赖项的depfile。它通常由自定义命令本身发出。这个关键字只能在生成器支持的情况下使用。
      DEPFILE不能与Makefile Generators的IMPLICIT_DEPENDS选项同时指定。

message("##CMAKE_COMMAND: ${CMAKE_COMMAND}") # ## CMAKE_COMMAND: /usr/bin/cmake
# 只有在构建时add_custom_command才会真正生效,解析cmake阶段只会判断有无语法错误,在调用add_library命令时才会有xxx.cpp, main.cpp文件生成
# 在build目录下会生成xxx.cpp, main.cpp文件
# add.cpp的md5和COMMENT信息会直接在终端输出
add_custom_command(
    OUTPUT xxx.cpp main.cpp
    COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/source/add.cpp xxx.cpp
    COMMAND ${CMAKE_COMMAND} -E md5sum ${CMAKE_CURRENT_SOURCE_DIR}/source/add.cpp
    COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/samples/sample_add.cpp main.cpp
    COMMENT "**** test cmake command: add_custom_command"
    DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/source/add.cpp
    VERBATIM
)

include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
add_library(add SHARED xxx.cpp)
add_executable(main main.cpp)
target_link_libraries(main add)

      2.Build Events:将自定义命令添加到target,如库或可执行文件.这对于在构建target之前或之后执行操作非常有用。该命令将成为target的一部分,并且仅在构建target本身时执行如果target已构建,则不会执行该命令
      这将定义一个新命令,该命令将与构建指定的关联。必须在当前目录中定义;不能指定在其它目录中定义的target。
      命令何时发生取决于指定以下哪项:
      (1).PRE_BUILD:在Visual Studio Generators上,在target中执行任何其它规则之前运行。在其它生成器(generator)上,在PRE_LINK命令之前运行。
      (2).PRE_LINK:在编译源代码之后但在链接二进制文件(binary)或运行静态库的库管理员(librarian)或存档器工具(archiver tool)之前运行。这不是为add_custom_target命令创建的target定义的。
      (3).POST_BUILD:在执行target中的所有其它规则后运行。
      使用TARGET格式时,project应始终指定上述三个关键字之一。出于向后兼容性(backward compatibility)的原因,如果没有给出这样的关键字,则假定为POST_BUILD,但project应明确提供其中一个关键字以明确他们期望的行为。

include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
add_library(add SHARED ${CMAKE_CURRENT_SOURCE_DIR}/source/add.cpp)

# 在执行add_custom_command前target add已存在,否则会报error: No TARGET 'add' has been created in this directory
# add.cpp的md5和COMMENT信息会直接在终端输出
add_custom_command(TARGET add POST_BUILD
    COMMAND ${CMAKE_COMMAND} -E md5sum ${CMAKE_CURRENT_SOURCE_DIR}/source/add.cpp
    COMMENT "**** test cmake command: add_custom_command"
    VERBATIM
)

      执行测试代码需要多个文件

      build.sh内容如下:

#! /bin/bash

# supported input parameters(cmake commands)
params=(function macro cmake_parse_arguments \
		find_library find_path find_file find_program find_package \
		cmake_policy cmake_minimum_required project include \
		string list set foreach message option if while return \
		math file configure_file \
		include_directories add_executable add_library target_link_libraries install \
		target_sources add_custom_command add_custom_target)

usage()
{
	echo "Error: $0 needs to have an input parameter"

	echo "supported input parameters:"
	for param in ${params[@]}; do
		echo "  $0 ${param}"
	done

	exit -1
}

if [ $# != 1 ]; then
	usage
fi

flag=0
for param in ${params[@]}; do
	if [ $1 == ${param} ]; then
		flag=1
		break
	fi
done

if [ ${flag} == 0 ]; then
	echo "Error: parameter \"$1\" is not supported"
	usage
	exit -1
fi

if [[ ! -d "build" ]]; then
	mkdir build
	cd build
else
	cd build
fi

echo "==== test $1 ===="

# test_set.cmake: cmake -DTEST_CMAKE_FEATURE=$1 --log-level=verbose ..
# test_option.cmake: cmake -DTEST_CMAKE_FEATURE=$1 -DBUILD_PYTORCH=ON ..
cmake -DTEST_CMAKE_FEATURE=$1 ..
# It can be executed directly on the terminal, no need to execute build.sh, for example: cmake -P test_set.cmake
make
# make install # only used in cmake files with install command

      CMakeLists.txt内容如下:

cmake_minimum_required(VERSION 3.22)
project(cmake_feature_usage)

message("#### current cmake version: ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.${CMAKE_PATCH_VERSION}")
include(test_${TEST_CMAKE_FEATURE}.cmake)
message("==== test finish ====")

      test_add_custom_command.cmake内容为上面的所有测试代码段。

      另外还包括三个目录:include,source,samples,它们都是非常简单的实现,仅用于测试,如下:

CMake中add_custom_command的使用_第1张图片

      可能的执行结果如下图所示: 

CMake中add_custom_command的使用_第2张图片

      GitHub: https://github.com/fengbingchun/Linux_Code_Test

 

你可能感兴趣的:(CMake/Makefile,CMake)