ctkMacroBuildPlugin.cmake 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412
  1. ###########################################################################
  2. #
  3. # Library: CTK
  4. #
  5. # Copyright (c) Kitware Inc.
  6. #
  7. # Licensed under the Apache License, Version 2.0 (the "License");
  8. # you may not use this file except in compliance with the License.
  9. # You may obtain a copy of the License at
  10. #
  11. # http://www.apache.org/licenses/LICENSE-2.0.txt
  12. #
  13. # Unless required by applicable law or agreed to in writing, software
  14. # distributed under the License is distributed on an "AS IS" BASIS,
  15. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  16. # See the License for the specific language governing permissions and
  17. # limitations under the License.
  18. #
  19. ###########################################################################
  20. #
  21. # Depends on:
  22. # CTK/CMake/ctkMacroParseArguments.cmake
  23. # CTK/CMake/ctkMacroGeneratePluginManifest.cmake
  24. #
  25. #! \brief Build a CTK plug-in.
  26. #!
  27. #! This macro takes the usual arguments for building
  28. #! a shared library using Qt. Additionally, it generates
  29. #! plugin meta-data by creating a MANIFEST.MF text file
  30. #! which is embedded in the share library as a Qt resource.
  31. #!
  32. #! The following variables can be set in a file named
  33. #! manifest_headers.cmake, which will then be read by
  34. #! this macro:
  35. #!
  36. #! - Plugin-ActivationPolicy
  37. #! - Plugin-Category
  38. #! - Plugin-ContactAddress
  39. #! - Plugin-Copyright
  40. #! - Plugin-Description
  41. #! - Plugin-DocURL
  42. #! - Plugin-Icon
  43. #! - Plugin-License
  44. #! - Plugin-Name
  45. #! - Require-Plugin
  46. #! - Plugin-Vendor
  47. #! - Plugin-Version
  48. #!
  49. #! \ingroup CMakeAPI
  50. macro(ctkMacroBuildPlugin)
  51. CtkMacroParseArguments(MY
  52. "EXPORT_DIRECTIVE;SRCS;MOC_SRCS;MOC_OPTIONS;UI_FORMS;INCLUDE_DIRECTORIES;EXPORTED_INCLUDE_SUFFIXES;TARGET_LIBRARIES;RESOURCES;CACHED_RESOURCEFILES;TRANSLATIONS;OUTPUT_DIR"
  53. "TEST_PLUGIN;NO_INSTALL"
  54. ${ARGN}
  55. )
  56. # Keep parameter 'INCLUDE_DIRECTORIES' for backward compatiblity
  57. # Sanity checks
  58. if(NOT DEFINED MY_EXPORT_DIRECTIVE)
  59. message(FATAL_ERROR "EXPORT_DIRECTIVE is mandatory")
  60. endif()
  61. # Print a warning if the project name does not match the directory name
  62. get_filename_component(_dir_name ${CMAKE_CURRENT_SOURCE_DIR} NAME)
  63. string(REPLACE "." "_" _dir_name_with_ ${_dir_name})
  64. if(NOT _dir_name_with_ STREQUAL ${PROJECT_NAME})
  65. message(WARNING "Discouraged mismatch of plug-in project name [${PROJECT_NAME}] and top-level directory name [${CMAKE_CURRENT_SOURCE_DIR}].")
  66. endif()
  67. # Define library name
  68. set(lib_name ${PROJECT_NAME})
  69. # Plug-in target names must contain at leas one _
  70. if(NOT lib_name MATCHES _)
  71. message(FATAL_ERROR "The plug-in project name ${lib_name} must contain at least one '_' character")
  72. endif()
  73. # Plugin are expected to be shared library
  74. set(MY_LIBRARY_TYPE "SHARED")
  75. # Clear the variables for the manifest headers
  76. set(Plugin-ActivationPolicy )
  77. set(Plugin-Category )
  78. set(Plugin-ContactAddress )
  79. set(Plugin-Copyright )
  80. set(Plugin-Description )
  81. set(Plugin-DocURL )
  82. set(Plugin-Icon )
  83. set(Plugin-License )
  84. set(Plugin-Name )
  85. set(Require-Plugin )
  86. set(Plugin-SymbolicName )
  87. set(Plugin-Vendor )
  88. set(Plugin-Version )
  89. set(Custom-Headers )
  90. if(MY_TEST_PLUGIN)
  91. # Since the test plug-ins are not considered when calculating
  92. # target dependencies via DGraph, we add the dependencies
  93. # manually here
  94. #message("${lib_name}_DEPENDENCIES ${MY_TARGET_LIBRARIES}")
  95. list(APPEND ${lib_name}_DEPENDENCIES ${MY_TARGET_LIBRARIES})
  96. endif()
  97. # If a file named manifest_headers.cmake exists, read it
  98. set(manifest_headers_dep )
  99. if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/manifest_headers.cmake")
  100. include(${CMAKE_CURRENT_SOURCE_DIR}/manifest_headers.cmake)
  101. set(manifest_headers_dep "${CMAKE_CURRENT_SOURCE_DIR}/manifest_headers.cmake")
  102. endif()
  103. string(REPLACE "_" "." Plugin-SymbolicName ${lib_name})
  104. # --------------------------------------------------------------------------
  105. # Include dirs
  106. if(MY_EXPORTED_INCLUDE_SUFFIXES)
  107. set(${lib_name}_INCLUDE_SUFFIXES ${MY_EXPORTED_INCLUDE_SUFFIXES}
  108. CACHE INTERNAL "List of exported plugin include dirs")
  109. set(my_includes )
  110. foreach(_suffix ${MY_EXPORTED_INCLUDE_SUFFIXES})
  111. list(APPEND my_includes ${CMAKE_CURRENT_SOURCE_DIR}/${_suffix})
  112. endforeach()
  113. else()
  114. set(${lib_name}_INCLUDE_SUFFIXES ""
  115. CACHE INTERNAL "List of exported plugin include dirs")
  116. set(my_includes )
  117. endif()
  118. list(APPEND my_includes
  119. ${CMAKE_CURRENT_SOURCE_DIR}
  120. ${CMAKE_CURRENT_BINARY_DIR}
  121. )
  122. # Add the include directories from the plugin dependencies
  123. # and external dependencies
  124. ctkFunctionGetIncludeDirs(my_includes ${lib_name})
  125. if(CMAKE_VERSION VERSION_LESS 2.8.12)
  126. include_directories(
  127. ${my_includes}
  128. )
  129. endif()
  130. if(CTK_QT_VERSION VERSION_LESS "5")
  131. # Add Qt include dirs and defines
  132. include(${QT_USE_FILE})
  133. else()
  134. find_package(Qt5 COMPONENTS LinguistTools REQUIRED)
  135. endif()
  136. # Add the library directories from the external project
  137. ctkFunctionGetLibraryDirs(my_library_dirs ${lib_name})
  138. link_directories(
  139. ${my_library_dirs}
  140. )
  141. set(MY_LIBRARY_EXPORT_DIRECTIVE ${MY_EXPORT_DIRECTIVE})
  142. set(MY_EXPORT_HEADER_PREFIX "${lib_name}_")
  143. set(MY_LIBNAME ${lib_name})
  144. configure_file(
  145. ${CTK_EXPORT_HEADER_TEMPLATE}
  146. ${CMAKE_CURRENT_BINARY_DIR}/${MY_EXPORT_HEADER_PREFIX}Export.h
  147. )
  148. set(dynamicHeaders
  149. "${dynamicHeaders};${CMAKE_CURRENT_BINARY_DIR}/${MY_EXPORT_HEADER_PREFIX}Export.h")
  150. # Make sure variable are cleared
  151. set(MY_MOC_CPP)
  152. set(MY_UI_CPP)
  153. set(MY_QRC_SRCS)
  154. # Wrap
  155. if (CTK_QT_VERSION VERSION_GREATER "4")
  156. set(target)
  157. if(Qt5Core_VERSION VERSION_GREATER "5.2.0")
  158. set(target TARGET ${lib_name})
  159. endif()
  160. if(MY_MOC_SRCS)
  161. # this is a workaround for Visual Studio. The relative include paths in the generated
  162. # moc files can get very long and can't be resolved by the MSVC compiler.
  163. foreach(moc_src ${MY_MOC_SRCS})
  164. QT5_WRAP_CPP(MY_MOC_CPP ${moc_src} OPTIONS -f${moc_src} -DHAVE_QT5 ${MY_MOC_OPTIONS} ${target})
  165. endforeach()
  166. endif()
  167. QT5_WRAP_UI(MY_UI_CPP ${MY_UI_FORMS})
  168. if(DEFINED MY_RESOURCES)
  169. QT5_ADD_RESOURCES(MY_QRC_SRCS ${MY_RESOURCES})
  170. endif()
  171. else()
  172. if(MY_MOC_SRCS)
  173. # this is a workaround for Visual Studio. The relative include paths in the generated
  174. # moc files can get very long and can't be resolved by the MSVC compiler.
  175. foreach(moc_src ${MY_MOC_SRCS})
  176. QT4_WRAP_CPP(MY_MOC_CPP ${moc_src} OPTIONS -f${moc_src} ${MY_MOC_OPTIONS} TARGET ${lib_name})
  177. endforeach()
  178. endif()
  179. QT4_WRAP_UI(MY_UI_CPP ${MY_UI_FORMS})
  180. if(DEFINED MY_RESOURCES)
  181. QT4_ADD_RESOURCES(MY_QRC_SRCS ${MY_RESOURCES})
  182. endif()
  183. endif()
  184. # Add the generated manifest qrc file
  185. set(manifest_qrc_src )
  186. ctkFunctionGeneratePluginManifest(manifest_qrc_src
  187. ACTIVATIONPOLICY ${Plugin-ActivationPolicy}
  188. CATEGORY ${Plugin-Category}
  189. CONTACT_ADDRESS ${Plugin-ContactAddress}
  190. COPYRIGHT ${Plugin-Copyright}
  191. DESCRIPTION ${Plugin-Description}
  192. DOC_URL ${Plugin-DocURL}
  193. ICON ${Plugin-Icon}
  194. LICENSE ${Plugin-License}
  195. NAME ${Plugin-Name}
  196. REQUIRE_PLUGIN ${Require-Plugin}
  197. SYMBOLIC_NAME ${Plugin-SymbolicName}
  198. VENDOR ${Plugin-Vendor}
  199. VERSION ${Plugin-Version}
  200. CUSTOM_HEADERS ${Custom-Headers}
  201. )
  202. if(manifest_headers_dep)
  203. set_property(SOURCE ${manifest_qrc_src} APPEND
  204. PROPERTY OBJECT_DEPENDS ${manifest_headers_dep})
  205. endif()
  206. list(APPEND MY_QRC_SRCS ${manifest_qrc_src})
  207. # Create translation files (.ts and .qm)
  208. set(_plugin_qm_files )
  209. set(_plugin_cached_resources_in_binary_tree )
  210. set(_translations_dir "${CMAKE_CURRENT_BINARY_DIR}/CTK-INF/l10n")
  211. if(MY_TRANSLATIONS)
  212. set_source_files_properties(${MY_TRANSLATIONS}
  213. PROPERTIES OUTPUT_LOCATION ${_translations_dir})
  214. if(CTK_QT_VERSION VERSION_GREATER "4")
  215. qt5_create_translation(_plugin_qm_files ${MY_SRCS} ${MY_UI_FORMS} ${MY_TRANSLATIONS})
  216. else()
  217. QT4_CREATE_TRANSLATION(_plugin_qm_files ${MY_SRCS} ${MY_UI_FORMS} ${MY_TRANSLATIONS})
  218. endif()
  219. endif()
  220. if(_plugin_qm_files)
  221. foreach(_qm_file ${_plugin_qm_files})
  222. file(RELATIVE_PATH _relative_qm_file ${CMAKE_CURRENT_BINARY_DIR} ${_qm_file})
  223. list(APPEND _plugin_cached_resources_in_binary_tree ${_relative_qm_file})
  224. endforeach()
  225. endif()
  226. set(_plugin_cached_resources_in_source_tree )
  227. if(MY_CACHED_RESOURCEFILES)
  228. foreach(_cached_resource ${MY_CACHED_RESOURCEFILES})
  229. if(IS_ABSOLUTE "${_cached_resource}")
  230. # create a path relative to the current binary dir
  231. file(RELATIVE_PATH _relative_cached_resource ${CMAKE_CURRENT_BINARY_DIR} ${_cached_resource})
  232. list(APPEND _plugin_cached_resources_in_binary_tree ${_relative_cached_resource})
  233. else()
  234. list(APPEND _plugin_cached_resources_in_source_tree ${_cached_resource})
  235. endif()
  236. endforeach()
  237. endif()
  238. # Add any other additional resource files
  239. if(_plugin_cached_resources_in_source_tree OR _plugin_cached_resources_in_binary_tree)
  240. string(REPLACE "." "_" _plugin_symbolicname ${Plugin-SymbolicName})
  241. ctkMacroGeneratePluginResourcefile(MY_QRC_SRCS
  242. NAME ${_plugin_symbolicname}_cached.qrc
  243. PREFIX ${Plugin-SymbolicName}
  244. RESOURCES ${_plugin_cached_resources_in_source_tree}
  245. BINARY_RESOURCES ${_plugin_cached_resources_in_binary_tree})
  246. endif()
  247. source_group("Resources" FILES
  248. ${MY_RESOURCES}
  249. ${MY_UI_FORMS}
  250. ${MY_TRANSLATIONS}
  251. )
  252. source_group("Generated" FILES
  253. ${MY_QRC_SRCS}
  254. ${MY_MOC_CPP}
  255. ${MY_UI_CPP}
  256. ${_plugin_qm_files}
  257. )
  258. add_library(${lib_name} ${MY_LIBRARY_TYPE}
  259. ${MY_SRCS}
  260. ${MY_MOC_CPP}
  261. ${MY_UI_CPP}
  262. ${MY_QRC_SRCS}
  263. ${_plugin_qm_files}
  264. )
  265. if(NOT CMAKE_VERSION VERSION_LESS 2.8.12)
  266. target_include_directories(${lib_name}
  267. PUBLIC "$<BUILD_INTERFACE:${my_includes}>"
  268. "$<INSTALL_INTERFACE:${CTK_INSTALL_PLUGIN_INCLUDE_DIR}/${Plugin-SymbolicName}>"
  269. )
  270. if(CTK_QT_VERSION VERSION_LESS "5")
  271. # Add Qt include dirs to the target
  272. target_include_directories(${lib_name} PUBLIC ${QT_INCLUDE_DIR})
  273. foreach(module QT3SUPPORT QTOPENGL QTASSISTANT QTDESIGNER QTMOTIF QTNSPLUGIN
  274. QAXSERVER QAXCONTAINER QTDECLARATIVE QTSCRIPT QTSVG QTUITOOLS QTHELP
  275. QTWEBKIT PHONON QTSCRIPTTOOLS QTMULTIMEDIA QTXMLPATTERNS QTGUI QTTEST
  276. QTDBUS QTXML QTSQL QTNETWORK QTCORE)
  277. if (QT_USE_${module} OR QT_USE_${module}_DEPENDS)
  278. if (QT_${module}_FOUND)
  279. target_include_directories(${lib_name} PUBLIC ${QT_${module}_INCLUDE_DIR})
  280. endif ()
  281. endif ()
  282. endforeach()
  283. endif()
  284. else()
  285. find_package(Qt5LinguistTools REQUIRED)
  286. endif()
  287. if(MY_TEST_PLUGIN AND CTK_QT_VERSION VERSION_GREATER "4")
  288. find_package(Qt5Test REQUIRED)
  289. if(CMAKE_VERSION VERSION_LESS 2.8.12)
  290. target_link_libraries(${lib_name} Qt5::Test)
  291. else()
  292. target_link_libraries(${lib_name} PRIVATE Qt5::Test)
  293. endif()
  294. endif()
  295. # Set the output directory for the plugin
  296. if(MY_OUTPUT_DIR)
  297. set(output_dir_suffix "/${MY_OUTPUT_DIR}")
  298. else()
  299. set(output_dir_suffix "")
  300. endif()
  301. foreach(type RUNTIME LIBRARY ARCHIVE)
  302. if(NOT DEFINED CTK_PLUGIN_${type}_OUTPUT_DIRECTORY AND CMAKE_${type}_OUTPUT_DIRECTORY)
  303. # Put plug-ins by default into a "plugins" subdirectory
  304. set(CTK_PLUGIN_${type}_OUTPUT_DIRECTORY "${CMAKE_${type}_OUTPUT_DIRECTORY}/plugins")
  305. endif()
  306. if(IS_ABSOLUTE "${CTK_PLUGIN_${type}_OUTPUT_DIRECTORY}")
  307. set(plugin_${type}_output_dir "${CTK_PLUGIN_${type}_OUTPUT_DIRECTORY}${output_dir_suffix}")
  308. elseif(CMAKE_${type}_OUTPUT_DIRECTORY)
  309. set(plugin_${type}_output_dir "${CMAKE_${type}_OUTPUT_DIRECTORY}/${CTK_PLUGIN_${type}_OUTPUT_DIRECTORY}${output_dir_suffix}")
  310. else()
  311. set(plugin_${type}_output_dir "${CMAKE_CURRENT_BINARY_DIR}/${CTK_PLUGIN_${type}_OUTPUT_DIRECTORY}${output_dir_suffix}")
  312. endif()
  313. if(MY_TEST_PLUGIN)
  314. # Test plug-ins will always be put in a separate directory
  315. if(CMAKE_${type}_OUTPUT_DIRECTORY)
  316. set(plugin_${type}_output_dir "${CMAKE_${type}_OUTPUT_DIRECTORY}/test_plugins")
  317. else()
  318. set(plugin_${type}_output_dir "${PROJECT_BINARY_DIR}/test_plugins")
  319. endif()
  320. endif()
  321. endforeach()
  322. set(plugin_compile_flags "-DQT_PLUGIN")
  323. ctkFunctionGetCompilerVisibilityFlags(plugin_compile_flags)
  324. # Apply properties to the library target.
  325. set_target_properties(${lib_name} PROPERTIES
  326. COMPILE_FLAGS "${plugin_compile_flags}"
  327. RUNTIME_OUTPUT_DIRECTORY ${plugin_RUNTIME_output_dir}
  328. LIBRARY_OUTPUT_DIRECTORY ${plugin_LIBRARY_output_dir}
  329. ARCHIVE_OUTPUT_DIRECTORY ${plugin_ARCHIVE_output_dir}
  330. PREFIX "lib"
  331. )
  332. if(NOT MY_TEST_PLUGIN AND NOT MY_NO_INSTALL)
  333. # Install rules
  334. install(TARGETS ${lib_name} EXPORT CTKExports
  335. RUNTIME DESTINATION ${CTK_INSTALL_PLUGIN_DIR} COMPONENT RuntimePlugins
  336. LIBRARY DESTINATION ${CTK_INSTALL_PLUGIN_DIR} COMPONENT RuntimePlugins
  337. ARCHIVE DESTINATION ${CTK_INSTALL_PLUGIN_DIR} COMPONENT Development)
  338. endif()
  339. set(my_libs
  340. ${MY_TARGET_LIBRARIES}
  341. )
  342. if(MINGW)
  343. list(APPEND my_libs ssp) # add stack smash protection lib
  344. endif()
  345. if(CMAKE_VERSION VERSION_LESS 2.8.12)
  346. target_link_libraries(${lib_name} ${my_libs})
  347. else()
  348. target_link_libraries(${lib_name} PUBLIC ${my_libs})
  349. endif()
  350. if(NOT MY_TEST_PLUGIN)
  351. set(${CMAKE_PROJECT_NAME}_PLUGIN_LIBRARIES ${${CMAKE_PROJECT_NAME}_PLUGIN_LIBRARIES} ${lib_name} CACHE INTERNAL "CTK plugins" FORCE)
  352. endif()
  353. if(NOT MY_TEST_PLUGIN AND NOT MY_NO_INSTALL)
  354. # Install headers
  355. file(GLOB headers "${CMAKE_CURRENT_SOURCE_DIR}/*.h" "${CMAKE_CURRENT_SOURCE_DIR}/*.tpp")
  356. install(FILES
  357. ${headers}
  358. ${dynamicHeaders}
  359. DESTINATION ${CTK_INSTALL_PLUGIN_INCLUDE_DIR}/${Plugin-SymbolicName} COMPONENT Development
  360. )
  361. endif()
  362. endmacro()