Deploy.cmake 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446
  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_LIBRARIES <path>...]
  157. [EXTRA_PLUGIN_PATHS <path>...]
  158. [EXTRA_SEARCHING_PATHS <path>...]
  159. [PLUGINS <plugin>...]
  160. [PLUGIN_DIR <dir>]
  161. [QML <qml>...]
  162. [QML_DIR <dir>]
  163. [WIN_TARGETS <target>...]
  164. [COMMENT <comment>]
  165. )
  166. PLUGINS: Qt plugins, in format of `<category>/<name>`
  167. PLUGIN_DIR: Qt plugins destination
  168. EXTRA_PLUGIN_PATHS: Extra Qt plugins searching paths
  169. QML: Qt qml directories
  170. QML_DIR: Qt qml destination
  171. LIBRARY_DIR: Library destination
  172. EXTRA_LIBRARIES: Extra library names list to deploy
  173. EXTRA_SEARCHING_PATHS: Extra library searching paths
  174. ]] #
  175. function(qm_deploy_directory _install_dir)
  176. set(options FORCE STANDARD VERBOSE)
  177. set(oneValueArgs LIBRARY_DIR PLUGIN_DIR QML_DIR COMMENT)
  178. set(multiValueArgs EXTRA_PLUGIN_PATHS PLUGINS QML WIN_TARGETS EXTRA_SEARCHING_PATHS EXTRA_LIBRARIES)
  179. cmake_parse_arguments(FUNC "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
  180. # Get qmake
  181. if((FUNC_PLUGINS OR FUNC_QML) AND NOT DEFINED QT_QMAKE_EXECUTABLE)
  182. if(TARGET Qt${QT_VERSION_MAJOR}::qmake)
  183. _get_executable_location(Qt${QT_VERSION_MAJOR}::qmake QT_QMAKE_EXECUTABLE)
  184. elseif((FUNC_PLUGINS AND NOT FUNC_EXTRA_PLUGIN_PATHS) OR FUNC_QML)
  185. message(FATAL_ERROR "qm_deploy_directory: qmake not defined. Add find_package(Qt5 COMPONENTS Core) to CMake to enable.")
  186. endif()
  187. endif()
  188. # Set values
  189. qm_set_value(_lib_dir FUNC_LIBRARY_DIR "${_install_dir}/${QMSETUP_SHARED_LIBRARY_CATEGORY}")
  190. qm_set_value(_plugin_dir FUNC_PLUGIN_DIR "${_install_dir}/plugins")
  191. qm_set_value(_qml_dir FUNC_QML_DIR "${_install_dir}/qml")
  192. # Prepare commands
  193. set(_args
  194. -i "${_install_dir}"
  195. -m "${QMSETUP_CORECMD_EXECUTABLE}"
  196. --plugindir "${_plugin_dir}"
  197. --libdir "${_lib_dir}"
  198. --qmldir "${_qml_dir}"
  199. )
  200. set(_searching_paths)
  201. if(QT_QMAKE_EXECUTABLE)
  202. list(APPEND _args --qmake "${QT_QMAKE_EXECUTABLE}")
  203. endif()
  204. # Add Qt plugins
  205. foreach(_item IN LISTS FUNC_PLUGINS)
  206. list(APPEND _args --plugin "${_item}")
  207. endforeach()
  208. # Add QML modules
  209. foreach(_item IN LISTS FUNC_QML)
  210. list(APPEND _args --qml "${_item}")
  211. endforeach()
  212. # Add extra plugin paths
  213. foreach(_item IN LISTS FUNC_EXTRA_PLUGIN_PATHS)
  214. list(APPEND _args --extra "${_item}")
  215. endforeach()
  216. # Add extra searching paths
  217. foreach(_item IN LISTS FUNC_EXTRA_SEARCHING_PATHS)
  218. get_filename_component(_item ${_item} ABSOLUTE)
  219. list(APPEND _searching_paths ${_item})
  220. endforeach()
  221. # Add global extra searching paths
  222. if(CMAKE_BUILD_TYPE)
  223. string(TOUPPER ${CMAKE_BUILD_TYPE} _build_type_upper)
  224. if(QMSETUP_APPLOCAL_DEPS_PATHS_${_build_type_upper})
  225. foreach(_item IN LISTS QMSETUP_APPLOCAL_DEPS_PATHS_${_build_type_upper})
  226. get_filename_component(_item ${_item} ABSOLUTE BASE_DIR ${CMAKE_SOURCE_DIR})
  227. list(APPEND _searching_paths ${_item})
  228. endforeach()
  229. elseif(QMSETUP_APPLOCAL_DEPS_PATHS)
  230. foreach(_item IN LISTS QMSETUP_APPLOCAL_DEPS_PATHS)
  231. get_filename_component(_item ${_item} ABSOLUTE BASE_DIR ${CMAKE_SOURCE_DIR})
  232. list(APPEND _searching_paths ${_item})
  233. endforeach()
  234. endif()
  235. else()
  236. foreach(_item IN LISTS QMSETUP_APPLOCAL_DEPS_PATHS)
  237. get_filename_component(_item ${_item} ABSOLUTE BASE_DIR ${CMAKE_SOURCE_DIR})
  238. list(APPEND _searching_paths ${_item})
  239. endforeach()
  240. endif()
  241. foreach(_item IN LISTS _searching_paths)
  242. list(APPEND _args -L "${_item}")
  243. endforeach()
  244. if(WIN32)
  245. set(_dep_files)
  246. if(FUNC_WIN_TARGETS)
  247. _qm_win_get_all_dep_files(_dep_files ${FUNC_WIN_TARGETS})
  248. endif()
  249. foreach(_item IN LISTS _dep_files)
  250. list(APPEND _args -@ "${_item}")
  251. endforeach()
  252. set(_script_quoted "cmd /c \"${QMSETUP_MODULES_DIR}/scripts/windeps.bat\"")
  253. else()
  254. set(_script_quoted "bash \"${QMSETUP_MODULES_DIR}/scripts/unixdeps.sh\"")
  255. endif()
  256. # Add extra libraries
  257. foreach(_item IN LISTS _searching_paths)
  258. foreach(_lib IN LISTS FUNC_EXTRA_LIBRARIES)
  259. set(_path "${_item}/${_lib}")
  260. if((EXISTS ${_path}) AND(NOT IS_DIRECTORY ${_path}))
  261. list(APPEND _args --copy ${_path} ${_lib_dir})
  262. endif()
  263. endforeach()
  264. endforeach()
  265. # Add options
  266. if(FUNC_FORCE)
  267. list(APPEND _args "-f")
  268. endif()
  269. if(FUNC_STANDARD)
  270. list(APPEND _args "-s")
  271. endif()
  272. if(FUNC_VERBOSE)
  273. list(APPEND _args "-V")
  274. endif()
  275. set(_args_quoted)
  276. foreach(_item IN LISTS _args)
  277. set(_args_quoted "${_args_quoted}\"${_item}\" ")
  278. endforeach()
  279. set(_comment_code)
  280. if(FUNC_COMMENT)
  281. set(_comment_code "message(STATUS \"${FUNC_COMMENT}\")")
  282. endif()
  283. # Add install command
  284. install(CODE "
  285. ${_comment_code}
  286. execute_process(
  287. COMMAND ${_script_quoted} ${_args_quoted}
  288. WORKING_DIRECTORY \"${_install_dir}\"
  289. COMMAND_ERROR_IS_FATAL ANY
  290. )
  291. ")
  292. endfunction()
  293. # ----------------------------------
  294. # Private functions
  295. # ----------------------------------
  296. function(_qm_win_get_all_dep_files _out)
  297. # Get searching paths
  298. macro(get_recursive_dynamic_dependencies _current_target _result)
  299. get_target_property(_deps ${_current_target} LINK_LIBRARIES)
  300. if(_deps)
  301. foreach(_dep IN LISTS _deps)
  302. if(NOT TARGET ${_dep})
  303. continue()
  304. endif()
  305. get_target_property(_type ${_dep} TYPE)
  306. if(_type STREQUAL "SHARED_LIBRARY")
  307. list(APPEND ${_result} ${_dep})
  308. endif()
  309. get_recursive_dynamic_dependencies(${_dep} ${_result})
  310. endforeach()
  311. endif()
  312. endmacro()
  313. set(_visited_targets ${ARGN})
  314. foreach(_target ${ARGN})
  315. set(_all_deps)
  316. get_recursive_dynamic_dependencies(${_target} _all_deps)
  317. foreach(_cur_dep IN LISTS _all_deps)
  318. if(${_cur_dep} IN_LIST _visited_targets)
  319. continue()
  320. endif()
  321. list(APPEND _visited_targets ${_cur_dep})
  322. endforeach()
  323. endforeach()
  324. set(_dep_files)
  325. foreach(_target IN LISTS _visited_targets)
  326. # Add file
  327. get_target_property(_file ${_target} QMSETUP_DEPENDENCIES_FILE)
  328. if(NOT _file)
  329. continue()
  330. endif()
  331. list(APPEND _dep_files ${_file})
  332. endforeach()
  333. set(${_out} ${_dep_files} PARENT_SCOPE)
  334. endfunction()
  335. function(_get_executable_location _target _var)
  336. get_target_property(_path ${_target} IMPORTED_LOCATION)
  337. if(NOT _path)
  338. get_target_property(_path ${_target} IMPORTED_LOCATION_RELEASE)
  339. endif()
  340. if(NOT _path)
  341. get_target_property(_path ${_target} IMPORTED_LOCATION_MINSIZEREL)
  342. endif()
  343. if(NOT _path)
  344. get_target_property(_path ${_target} IMPORTED_LOCATION_RELWITHDEBINFO)
  345. endif()
  346. if(NOT _path)
  347. get_target_property(_path ${_target} IMPORTED_LOCATION_DEBUG)
  348. endif()
  349. if(NOT _path)
  350. message(FATAL_ERROR "Could not find imported location of target: ${_target}")
  351. endif()
  352. set(${_var} ${_path} PARENT_SCOPE)
  353. endfunction()