Deploy.cmake 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  1. #[[
  2. Warning: This module depends on `qmcorecmd` after installation.
  3. ]] #
  4. if(NOT QMSETUP_CORECMD_EXECUTABLE)
  5. message(FATAL_ERROR "QMSETUP_CORECMD_EXECUTABLE not defined. Add find_package(qmsetup) to CMake first.")
  6. endif()
  7. if(NOT DEFINED QMSETUP_APPLOCAL_DEPS_PATHS)
  8. set(QMSETUP_APPLOCAL_DEPS_PATHS)
  9. endif()
  10. if(NOT DEFINED QMSETUP_APPLOCAL_DEPS_PATHS_DEBUG)
  11. set(QMSETUP_APPLOCAL_DEPS_PATHS_DEBUG ${QMSETUP_APPLOCAL_DEPS_PATHS})
  12. endif()
  13. if(NOT DEFINED QMSETUP_APPLOCAL_DEPS_PATHS_RELEASE)
  14. set(QMSETUP_APPLOCAL_DEPS_PATHS_RELEASE ${QMSETUP_APPLOCAL_DEPS_PATHS})
  15. endif()
  16. if(NOT DEFINED QMSETUP_APPLOCAL_DEPS_PATHS_RELWITHDEBINFO)
  17. set(QMSETUP_APPLOCAL_DEPS_PATHS_RELWITHDEBINFO ${QMSETUP_APPLOCAL_DEPS_PATHS_RELEASE})
  18. endif()
  19. if(NOT DEFINED QMSETUP_APPLOCAL_DEPS_PATHS_MINSIZEREL)
  20. set(QMSETUP_APPLOCAL_DEPS_PATHS_MINSIZEREL ${QMSETUP_APPLOCAL_DEPS_PATHS_RELEASE})
  21. endif()
  22. include_guard(DIRECTORY)
  23. #[[
  24. Record searching paths for Windows Executables, must be called before calling `qm_win_applocal_deps`
  25. or `qm_deploy_directory` if your project supports Windows.
  26. WARNING: This function is deprecated.
  27. qm_win_record_deps(<target>)
  28. ]] #
  29. function(qm_win_record_deps _target)
  30. if(NOT WIN32)
  31. return()
  32. endif()
  33. set(_paths)
  34. get_target_property(_link_libraries ${_target} LINK_LIBRARIES)
  35. foreach(_item IN LISTS _link_libraries)
  36. if(NOT TARGET ${_item})
  37. continue()
  38. endif()
  39. get_target_property(_imported ${_item} IMPORTED)
  40. if(_imported)
  41. get_target_property(_path ${_item} LOCATION)
  42. if(NOT _path OR NOT ${_path} MATCHES "\\.dll$")
  43. continue()
  44. endif()
  45. set(_path "$<TARGET_PROPERTY:${_item},LOCATION_$<CONFIG>>")
  46. else()
  47. get_target_property(_type ${_item} TYPE)
  48. if(NOT ${_type} MATCHES "SHARED_LIBRARY")
  49. continue()
  50. endif()
  51. set(_path "$<TARGET_FILE:${_item}>")
  52. endif()
  53. list(APPEND _paths ${_path})
  54. endforeach()
  55. if(NOT _paths)
  56. return()
  57. endif()
  58. set(_deps_file "${CMAKE_CURRENT_BINARY_DIR}/${_target}_deps_$<CONFIG>.txt")
  59. file(GENERATE OUTPUT ${_deps_file} CONTENT "$<JOIN:${_paths},\n>")
  60. set_target_properties(${_target} PROPERTIES QMSETUP_DEPENDENCIES_FILE ${_deps_file})
  61. endfunction()
  62. #[[
  63. Automatically copy dependencies for Windows Executables after build.
  64. qm_win_applocal_deps(<target>
  65. [CUSTOM_TARGET <target>]
  66. [FORCE] [VERBOSE]
  67. [EXTRA_SEARCHING_PATHS <path...>]
  68. [EXTRA_TARGETS <target...>]
  69. [OUTPUT_DIR <dir>]
  70. [EXCLUDE <pattern...>]
  71. )
  72. ]] #
  73. function(qm_win_applocal_deps _target)
  74. if(NOT WIN32)
  75. return()
  76. endif()
  77. set(options FORCE VERBOSE)
  78. set(oneValueArgs TARGET CUSTOM_TARGET OUTPUT_DIR)
  79. set(multiValueArgs EXTRA_SEARCHING_PATHS EXTRA_TARGETS EXCLUDE)
  80. cmake_parse_arguments(FUNC "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
  81. # Get output directory and deploy target
  82. set(_out_dir)
  83. set(_deploy_target)
  84. if(FUNC_CUSTOM_TARGET)
  85. set(_deploy_target ${FUNC_CUSTOM_TARGET})
  86. if(NOT TARGET ${_deploy_target})
  87. add_custom_target(${_deploy_target})
  88. endif()
  89. else()
  90. set(_deploy_target ${_target})
  91. endif()
  92. if(FUNC_OUTPUT_DIR)
  93. set(_out_dir ${FUNC_OUTPUT_DIR})
  94. else()
  95. set(_out_dir "$<TARGET_FILE_DIR:${_target}>")
  96. endif()
  97. if(NOT _out_dir)
  98. message(FATAL_ERROR "qm_win_applocal_deps: cannot determine output directory.")
  99. endif()
  100. # Get dep files
  101. set(_dep_files)
  102. _qm_win_get_all_dep_files(_dep_files ${_target})
  103. foreach(_item IN LISTS FUNC_EXTRA_TARGETS)
  104. _qm_win_get_all_dep_files(_dep_files ${_item})
  105. endforeach()
  106. # Prepare command
  107. set(_args)
  108. if(FUNC_FORCE)
  109. list(APPEND _args -f)
  110. endif()
  111. if(FUNC_VERBOSE)
  112. list(APPEND _args -V)
  113. endif()
  114. # Add extra searching paths
  115. foreach(_item IN LISTS FUNC_EXTRA_SEARCHING_PATHS)
  116. list(APPEND _args "-L${_item}")
  117. endforeach()
  118. # Add global extra searching paths
  119. if(CMAKE_BUILD_TYPE)
  120. string(TOUPPER ${CMAKE_BUILD_TYPE} _build_type_upper)
  121. if(QMSETUP_APPLOCAL_DEPS_PATHS_${_build_type_upper})
  122. foreach(_item IN LISTS QMSETUP_APPLOCAL_DEPS_PATHS_${_build_type_upper})
  123. get_filename_component(_item ${_item} ABSOLUTE BASE_DIR ${CMAKE_SOURCE_DIR})
  124. list(APPEND _args "-L${_item}")
  125. endforeach()
  126. elseif(QMSETUP_APPLOCAL_DEPS_PATHS)
  127. foreach(_item IN LISTS QMSETUP_APPLOCAL_DEPS_PATHS)
  128. get_filename_component(_item ${_item} ABSOLUTE BASE_DIR ${CMAKE_SOURCE_DIR})
  129. list(APPEND _args "-L${_item}")
  130. endforeach()
  131. endif()
  132. else()
  133. foreach(_item IN LISTS QMSETUP_APPLOCAL_DEPS_PATHS)
  134. get_filename_component(_item ${_item} ABSOLUTE BASE_DIR ${CMAKE_SOURCE_DIR})
  135. list(APPEND _args "-L${_item}")
  136. endforeach()
  137. endif()
  138. foreach(_item IN LISTS _dep_files)
  139. list(APPEND _args "-@${_item}")
  140. endforeach()
  141. foreach(_item IN LISTS FUNC_EXCLUDE)
  142. list(APPEND _args -e ${_item})
  143. endforeach()
  144. list(APPEND _args "$<TARGET_FILE:${_target}>")
  145. add_custom_command(TARGET ${_deploy_target} POST_BUILD
  146. COMMAND ${QMSETUP_CORECMD_EXECUTABLE} deploy ${_args}
  147. WORKING_DIRECTORY ${_out_dir}
  148. VERBATIM
  149. )
  150. endfunction()
  151. #[[
  152. Add deploy command when install project, not available in debug mode.
  153. qm_deploy_directory(<install_dir>
  154. [FORCE] [STANDARD] [VERBOSE]
  155. [LIBRARY_DIR <dir>]
  156. [EXTRA_PLUGIN_PATHS <path>...]
  157. [EXTRA_SEARCHING_PATHS <path>...]
  158. [PLUGINS <plugin>...]
  159. [PLUGIN_DIR <dir>]
  160. [QML <qml>...]
  161. [QML_DIR <dir>]
  162. [WIN_TARGETS <target>...]
  163. [COMMENT <comment>]
  164. )
  165. PLUGINS: Qt plugins, in format of `<category>/<name>`
  166. PLUGIN_DIR: Qt plugins destination
  167. EXTRA_PLUGIN_PATHS: Extra Qt plugins searching paths
  168. QML: Qt qml directories
  169. QML_DIR: Qt qml destination
  170. LIBRARY_DIR: Extra library destination
  171. EXTRA_SEARCHING_PATHS: Extra library searching paths
  172. ]] #
  173. function(qm_deploy_directory _install_dir)
  174. set(options FORCE STANDARD VERBOSE)
  175. set(oneValueArgs LIBRARY_DIR PLUGIN_DIR QML_DIR COMMENT)
  176. set(multiValueArgs EXTRA_PLUGIN_PATHS PLUGINS QML WIN_TARGETS EXTRA_SEARCHING_PATHS)
  177. cmake_parse_arguments(FUNC "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
  178. # Get qmake
  179. if((FUNC_PLUGINS OR FUNC_QML) AND NOT DEFINED QT_QMAKE_EXECUTABLE)
  180. if(TARGET Qt${QT_VERSION_MAJOR}::qmake)
  181. get_target_property(QT_QMAKE_EXECUTABLE Qt${QT_VERSION_MAJOR}::qmake IMPORTED_LOCATION)
  182. elseif((FUNC_PLUGINS AND NOT FUNC_EXTRA_PLUGIN_PATHS) OR FUNC_QML)
  183. message(FATAL_ERROR "qm_deploy_directory: qmake not defined. Add find_package(Qt5 COMPONENTS Core) to CMake to enable.")
  184. endif()
  185. endif()
  186. # Set values
  187. qm_set_value(_lib_dir FUNC_LIBRARY_DIR "${_install_dir}/${QMSETUP_SHARED_LIBRARY_CATEGORY}")
  188. qm_set_value(_plugin_dir FUNC_PLUGIN_DIR "${_install_dir}/plugins")
  189. qm_set_value(_qml_dir FUNC_QML_DIR "${_install_dir}/qml")
  190. # Prepare commands
  191. set(_args
  192. -i "${_install_dir}"
  193. -m "${QMSETUP_CORECMD_EXECUTABLE}"
  194. --plugindir "${_plugin_dir}"
  195. --libdir "${_lib_dir}"
  196. --qmldir "${_qml_dir}"
  197. )
  198. if(QT_QMAKE_EXECUTABLE)
  199. list(APPEND _args --qmake "${QT_QMAKE_EXECUTABLE}")
  200. endif()
  201. # Add Qt plugins
  202. foreach(_item IN LISTS FUNC_PLUGINS)
  203. list(APPEND _args --plugin "${_item}")
  204. endforeach()
  205. # Add QML modules
  206. foreach(_item IN LISTS FUNC_QML)
  207. list(APPEND _args --qml "${_item}")
  208. endforeach()
  209. # Add extra plugin paths
  210. foreach(_item IN LISTS FUNC_EXTRA_PLUGIN_PATHS)
  211. list(APPEND _args --extra "${_item}")
  212. endforeach()
  213. # Add extra searching paths
  214. foreach(_item IN LISTS FUNC_EXTRA_SEARCHING_PATHS)
  215. list(APPEND _args -L "${_item}")
  216. endforeach()
  217. # Add global extra searching paths
  218. if(CMAKE_BUILD_TYPE)
  219. string(TOUPPER ${CMAKE_BUILD_TYPE} _build_type_upper)
  220. if(QMSETUP_APPLOCAL_DEPS_PATHS_${_build_type_upper})
  221. foreach(_item IN LISTS QMSETUP_APPLOCAL_DEPS_PATHS_${_build_type_upper})
  222. get_filename_component(_item ${_item} ABSOLUTE BASE_DIR ${CMAKE_SOURCE_DIR})
  223. list(APPEND _args -L "${_item}")
  224. endforeach()
  225. elseif(QMSETUP_APPLOCAL_DEPS_PATHS)
  226. foreach(_item IN LISTS QMSETUP_APPLOCAL_DEPS_PATHS)
  227. get_filename_component(_item ${_item} ABSOLUTE BASE_DIR ${CMAKE_SOURCE_DIR})
  228. list(APPEND _args -L "${_item}")
  229. endforeach()
  230. endif()
  231. else()
  232. foreach(_item IN LISTS QMSETUP_APPLOCAL_DEPS_PATHS)
  233. get_filename_component(_item ${_item} ABSOLUTE BASE_DIR ${CMAKE_SOURCE_DIR})
  234. list(APPEND _args -L "${_item}")
  235. endforeach()
  236. endif()
  237. if(WIN32)
  238. set(_dep_files)
  239. if(FUNC_WIN_TARGETS)
  240. _qm_win_get_all_dep_files(_dep_files ${FUNC_WIN_TARGETS})
  241. endif()
  242. foreach(_item IN LISTS _dep_files)
  243. list(APPEND _args -@ "${_item}")
  244. endforeach()
  245. set(_script_quoted "cmd /c \"${QMSETUP_MODULES_DIR}/scripts/windeps.bat\"")
  246. else()
  247. set(_script_quoted "bash \"${QMSETUP_MODULES_DIR}/scripts/unixdeps.sh\"")
  248. endif()
  249. # Add options
  250. if(FUNC_FORCE)
  251. list(APPEND _args "-f")
  252. endif()
  253. if(FUNC_STANDARD)
  254. list(APPEND _args "-s")
  255. endif()
  256. if(FUNC_VERBOSE)
  257. list(APPEND _args "-V")
  258. endif()
  259. set(_args_quoted)
  260. foreach(_item IN LISTS _args)
  261. set(_args_quoted "${_args_quoted}\"${_item}\" ")
  262. endforeach()
  263. set(_comment_code)
  264. if(FUNC_COMMENT)
  265. set(_comment_code "message(STATUS \"${FUNC_COMMENT}\")")
  266. endif()
  267. # Add install command
  268. install(CODE "
  269. ${_comment_code}
  270. execute_process(
  271. COMMAND ${_script_quoted} ${_args_quoted}
  272. WORKING_DIRECTORY \"${_install_dir}\"
  273. COMMAND_ERROR_IS_FATAL ANY
  274. )
  275. ")
  276. endfunction()
  277. # ----------------------------------
  278. # Private functions
  279. # ----------------------------------
  280. function(_qm_win_get_all_dep_files _out)
  281. # Get searching paths
  282. macro(get_recursive_dynamic_dependencies _current_target _result)
  283. get_target_property(_deps ${_current_target} LINK_LIBRARIES)
  284. if(_deps)
  285. foreach(_dep IN LISTS _deps)
  286. if(NOT TARGET ${_dep})
  287. continue()
  288. endif()
  289. get_target_property(_type ${_dep} TYPE)
  290. if(_type STREQUAL "SHARED_LIBRARY")
  291. list(APPEND ${_result} ${_dep})
  292. endif()
  293. get_recursive_dynamic_dependencies(${_dep} ${_result})
  294. endforeach()
  295. endif()
  296. endmacro()
  297. set(_visited_targets ${ARGN})
  298. foreach(_target ${ARGN})
  299. set(_all_deps)
  300. get_recursive_dynamic_dependencies(${_target} _all_deps)
  301. foreach(_cur_dep IN LISTS _all_deps)
  302. if(${_cur_dep} IN_LIST _visited_targets)
  303. continue()
  304. endif()
  305. list(APPEND _visited_targets ${_cur_dep})
  306. endforeach()
  307. endforeach()
  308. set(_dep_files)
  309. foreach(_target IN LISTS _visited_targets)
  310. # Add file
  311. get_target_property(_file ${_target} QMSETUP_DEPENDENCIES_FILE)
  312. if(NOT _file)
  313. continue()
  314. endif()
  315. list(APPEND _dep_files ${_file})
  316. endforeach()
  317. set(${_out} ${_dep_files} PARENT_SCOPE)
  318. endfunction()