如果你要

  1. 在cmake中创建一些目标,做cleancopy等操作
  2. 在cmake某些对象编译之后,再做某些操作(延迟执行)

就可以使用add_custom_commandadd_custom_target

自定义目标add_custom_target

add_custom_target的用处:增加一个没有输出的目标,使得它总是被构建

  1. add_custom_target(Name [ALL] [command1 [args1...]]
  2. [COMMAND command2 [args2...] ...]
  3. [DEPENDS depend depend depend ... ]
  4. [BYPRODUCTS [files...]]
  5. [WORKING_DIRECTORY dir]
  6. [COMMENT comment]
  7. [JOB_POOL job_pool]
  8. [VERBATIM] [USES_TERMINAL]
  9. [COMMAND_EXPAND_LISTS]
  10. [SOURCES src1 [src2...]])

这个命令参数有点多,其实不需要全部了解

例:拷贝文件与拷贝文件夹

  1. cmake_minimum_required(VERSION 3.0)
  2. project(test)
  3. # 添加一个名为CopyTask的自定义目标
  4. ## 注:但这个目标没有输出(动态库、静态库、可执行文件)
  5. add_custom_target(CopyTask
  6. #第一个命令
  7. COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/config ${CMAKE_CURRENT_SOURCE_DIR}/etc
  8. #第二个命令
  9. COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/log.txt ${CMAKE_CURRENT_SOURCE_DIR}/etc
  10. #如果还有命令,可以继续添加
  11. )
  1. ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/config ${CMAKE_CURRENT_SOURCE_DIR}/etc
  2. ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/log.txt ${CMAKE_CURRENT_SOURCE_DIR}/etc

这两条命令,都是调用cmake.exe进行操作的,一个是拷贝文件夹,一个是拷贝文件

  • ${CMAKE_COMMAND}的值是D:/software/CMake/bin/cmake.exe
  • cmake.exe -E是Cmake的命令模式,具体可以运行cmake --helpcmake -E查看帮助文档

自定义命令add_custom_command

用途:将自定义构建规则添加到生成的构建系统

自定义命令有两种使用场景:生成文件、构建事件

生成文件

第一种是输出模式,即OUTPUT。用在生成文件的场景中,即添加一个定制命令来生成文件。

  1. add_custom_command(OUTPUT output1 [output2 ...]
  2. COMMAND command1 [ARGS] [args1...]``
  3. [COMMAND command2 [ARGS] [args2...] ...]
  4. [MAIN_DEPENDENCY depend]
  5. [DEPENDS [depends...]]
  6. [BYPRODUCTS [files...]]
  7. [IMPLICIT_DEPENDS <lang1> depend1
  8. [<lang2> depend2] ...]
  9. [WORKING_DIRECTORY dir]
  10. [COMMENT comment]
  11. [DEPFILE depfile]
  12. [JOB_POOL job_pool]
  13. [VERBATIM] [APPEND] [USES_TERMINAL]
  14. [COMMAND_EXPAND_LISTS])

参数简述:

  • OUTPUT:指定命令预期产生的输出文件。如果输出文件的名称是相对路径,即相对于当前的构建的源目录路径;
  • COMMAND:指定要在构建时执行的命令行;
  • DEPENDS:指定命令所依赖的文件;
  • COMMENT:在构建时执行命令之前显示给定消息;
  • WORKING_DIRECTORY:使用给定的当前工作目录执行命令。如果它是相对路径,它将相对于对应于当前源目录的构建树目录;
  • DEPFILE:为生成器指定一个.d depfile .d文件保存通常由自定义命令本身发出的依赖关系;
  • MAIN_DEPENDENCY:指定命令的主要输入源文件;
  • BYPRODUCTS:指定命令预期产生的文件。

例:拷贝文件与拷贝文件夹

  1. cmake_minimum_required(VERSION 3.0)
  2. project(test)
  3. # 添加一个名字为COPY_RES的自定义命令
  4. # 模式为output
  5. add_custom_command(OUTPUT COPY_RES
  6. # 第一条命令:拷贝目录
  7. COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/config ${CMAKE_CURRENT_SOURCE_DIR}/etc
  8. # 第二条命令:拷贝文件
  9. COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/log.txt ${CMAKE_CURRENT_SOURCE_DIR}/etc
  10. )
  11. # 添加一个名字为CopyTask的自定义目标
  12. add_custom_target(CopyTask ALL DEPENDS COPY_RES)
  13. ### 该目标依赖于COPY_RES,COPY_RES是上面添加的自定义命令

构建事件

另一种是构建事件:为某个Target添加一个定制命令,这个命令会在某个时间触发

触发的时间点有三种选项:

参数 含义
PRE_BUILD 在target build之前触发这个命令(即生成前事件)
PRE_LINK 在编译源代码之后,链接二进制文件(或库文件)之前触发命令
POST_BUILD 在Target所有规则均运行后触发命令(即生成后事件)
  1. add_custom_command(TARGET <target>
  2. PRE_BUILD | PRE_LINK | POST_BUILD
  3. COMMAND command1 [ARGS] [args1...]
  4. [COMMAND command2 [ARGS] [args2...] ...]
  5. [BYPRODUCTS [files...]]
  6. [WORKING_DIRECTORY dir]
  7. [COMMENT comment]
  8. [VERBATIM] [USES_TERMINAL])
  • TARGET:指定命令运行的目标;
  • COMMAND:指定要在构建时执行的命令行;
  • COMMENT:在构建时执行命令之前显示给定消息;
  • WORKING_DIRECTORY:使用给定的当前工作目录执行命令。如果它是相对路径,它将相对于对应于当前源目录的构建树目录;
  • BYPRODUCTS:指定命令预期产生的文件。

例:拷贝文件与拷贝文件夹

  1. cmake_minimum_required(VERSION 3.0)
  2. project(test)
  3. # 添加一个名字为CopyTask的目标
  4. add_custom_target(CopyTask)
  5. # 注意:add_custom_command需要写在add_custom_target之后,否则将cmake不通过
  6. # 添加一个自定义命令
  7. add_custom_command(TARGET CopyTask
  8. POST_BUILD
  9. COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/config ${CMAKE_CURRENT_SOURCE_DIR}/etc
  10. COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/log.txt ${CMAKE_CURRENT_SOURCE_DIR}/etc
  11. )

execute_process

其他例子

生成后构建C#工程

  1. set(csc csc.exe)
  2. # 添加一个自定义命令
  3. ADD_CUSTOM_COMMAND(TARGET #模式为“构建事件”
  4. cxx_module_name POST_BUILD #cxx_module_name目标生成后进行触发
  5. COMMAND #具体命令
  6. #第一条命令
  7. ${csc}
  8. #该命令的参数
  9. -t:library -platform:x64 "${csharp_depends_libs}"
  10. -out:${CSHARP_LIBRARY_OUTPUT_PATH}\\${project_name}.dll
  11. -langversion:default
  12. -doc:${CSHARP_LIBRARY_OUTPUT_PATH}\\${project_name}.xml
  13. ${csharp_srcs} #.cs文件列表
  14. )

附:csc.exe的位置与帮助文档
image.png

综合示例:生成dotnet工程

https://github.com/Mizux/cmake-swig.git

  1. #寻找dotnet的执行文件,需要安装dotnet
  2. # Find dotnet cli
  3. find_program(DOTNET_EXECUTABLE NAMES dotnet)
  4. if(NOT DOTNET_EXECUTABLE)
  5. message(FATAL_ERROR "Check for dotnet Program: not found")
  6. else()
  7. message(STATUS "Found dotnet Program: ${DOTNET_EXECUTABLE}")
  8. endif()
  9. ###接下来是一组lib或者可执行程序。这里选取Mizux.Foo.runtime.<RID>, Mizux.Foo和Mizux.FooApp分析
  10. ############################
  11. ## .Net Runtime Package ##
  12. ############################
  13. message(STATUS ".Net runtime project: ${DOTNET_NATIVE_PROJECT}")
  14. set(DOTNET_NATIVE_PATH ${PROJECT_BINARY_DIR}/dotnet/${DOTNET_NATIVE_PROJECT})
  15. message(STATUS ".Net runtime project build path: ${DOTNET_NATIVE_PATH}")
  16. # *.csproj.in contains:
  17. # CMake variable(s) (@PROJECT_NAME@) that configure_file() can manage and
  18. # generator expression ($<TARGET_FILE:...>) that file(GENERATE) can manage.
  19. configure_file(
  20. ${PROJECT_SOURCE_DIR}/dotnet/${DOTNET_PACKAGE}.runtime.csproj.in
  21. ${DOTNET_NATIVE_PATH}/${DOTNET_NATIVE_PROJECT}.csproj.in
  22. @ONLY) ###替换其中@xxx@的变量
  23. ### dotnet/Mizux.Foo.runtime.csproj.in 复制到 build/dotnet/Mizux.Foo.runtime/csproj.in 并替换其中@xxx@的变量
  24. file(GENERATE
  25. OUTPUT ${DOTNET_NATIVE_PATH}/$<CONFIG>/${DOTNET_NATIVE_PROJECT}.csproj.in
  26. INPUT ${DOTNET_NATIVE_PATH}/${DOTNET_NATIVE_PROJECT}.csproj.in)
  27. ###根据build/dotnet/Mizux.Foo.runtime.csproj.in 产生文件 build/dotnet/Release/Mizux.Foo.runtime.csproj.in
  28. ###其中$<xxx>的部分会被替换
  29. add_custom_command(
  30. OUTPUT ${DOTNET_NATIVE_PATH}/${DOTNET_NATIVE_PROJECT}.csproj
  31. ###build/dotnet/Mizux.Foo.runtime.linux-x64/Mizux.Foo.runtime.linux-x64.csproj
  32. DEPENDS ${DOTNET_NATIVE_PATH}/$<CONFIG>/${DOTNET_NATIVE_PROJECT}.csproj.in
  33. COMMAND ${CMAKE_COMMAND} -E copy ./$<CONFIG>/${DOTNET_NATIVE_PROJECT}.csproj.in ${DOTNET_NATIVE_PROJECT}.csproj
  34. ###build/dotnet/Release/Mizux.Foo.runtime.csproj.in 复制到
  35. ### build/dotnet/Mizux.Foo.runtime.linux-x64/Mizux.Foo.runtime.linux-x64.csproj
  36. WORKING_DIRECTORY ${DOTNET_NATIVE_PATH}
  37. )
  38. add_custom_target(dotnet_native_package
  39. DEPENDS ${DOTNET_NATIVE_PATH}/${DOTNET_NATIVE_PROJECT}.csproj
  40. COMMAND ${CMAKE_COMMAND} -E make_directory packages
  41. COMMAND ${DOTNET_EXECUTABLE} build -c Release ${DOTNET_NATIVE_PROJECT}/${DOTNET_NATIVE_PROJECT}.csproj
  42. COMMAND ${DOTNET_EXECUTABLE} pack -c Release ${DOTNET_NATIVE_PROJECT}/${DOTNET_NATIVE_PROJECT}.csproj
  43. BYPRODUCTS
  44. dotnet/${DOTNET_NATIVE_PROJECT}/bin
  45. dotnet/${DOTNET_NATIVE_PROJECT}/obj
  46. WORKING_DIRECTORY dotnet
  47. )
  48. add_dependencies(dotnet_native_package mizux-dotnetnative-native)

参考文章

  1. 【CMake】cmake的add_custom_command和add_custom_target指令