ctkMacroBuildPlugin.cmake 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408
  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(Qt5LinguistTools 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. if(MY_MOC_SRCS)
  157. # this is a workaround for Visual Studio. The relative include paths in the generated
  158. # moc files can get very long and can't be resolved by the MSVC compiler.
  159. foreach(moc_src ${MY_MOC_SRCS})
  160. QT5_WRAP_CPP(MY_MOC_CPP ${moc_src} OPTIONS -f${moc_src} -DHAVE_QT5 TARGET ${lib_name})
  161. endforeach()
  162. endif()
  163. QT5_WRAP_UI(MY_UI_CPP ${MY_UI_FORMS})
  164. if(DEFINED MY_RESOURCES)
  165. QT5_ADD_RESOURCES(MY_QRC_SRCS ${MY_RESOURCES})
  166. endif()
  167. else()
  168. if(MY_MOC_SRCS)
  169. # this is a workaround for Visual Studio. The relative include paths in the generated
  170. # moc files can get very long and can't be resolved by the MSVC compiler.
  171. foreach(moc_src ${MY_MOC_SRCS})
  172. QT4_WRAP_CPP(MY_MOC_CPP ${moc_src} OPTIONS -f${moc_src} TARGET ${lib_name})
  173. endforeach()
  174. endif()
  175. QT4_WRAP_UI(MY_UI_CPP ${MY_UI_FORMS})
  176. if(DEFINED MY_RESOURCES)
  177. QT4_ADD_RESOURCES(MY_QRC_SRCS ${MY_RESOURCES})
  178. endif()
  179. endif()
  180. # Add the generated manifest qrc file
  181. set(manifest_qrc_src )
  182. ctkFunctionGeneratePluginManifest(manifest_qrc_src
  183. ACTIVATIONPOLICY ${Plugin-ActivationPolicy}
  184. CATEGORY ${Plugin-Category}
  185. CONTACT_ADDRESS ${Plugin-ContactAddress}
  186. COPYRIGHT ${Plugin-Copyright}
  187. DESCRIPTION ${Plugin-Description}
  188. DOC_URL ${Plugin-DocURL}
  189. ICON ${Plugin-Icon}
  190. LICENSE ${Plugin-License}
  191. NAME ${Plugin-Name}
  192. REQUIRE_PLUGIN ${Require-Plugin}
  193. SYMBOLIC_NAME ${Plugin-SymbolicName}
  194. VENDOR ${Plugin-Vendor}
  195. VERSION ${Plugin-Version}
  196. CUSTOM_HEADERS ${Custom-Headers}
  197. )
  198. if(manifest_headers_dep)
  199. set_property(SOURCE ${manifest_qrc_src} APPEND
  200. PROPERTY OBJECT_DEPENDS ${manifest_headers_dep})
  201. endif()
  202. list(APPEND MY_QRC_SRCS ${manifest_qrc_src})
  203. # Create translation files (.ts and .qm)
  204. set(_plugin_qm_files )
  205. set(_plugin_cached_resources_in_binary_tree )
  206. set(_translations_dir "${CMAKE_CURRENT_BINARY_DIR}/CTK-INF/l10n")
  207. if(MY_TRANSLATIONS)
  208. set_source_files_properties(${MY_TRANSLATIONS}
  209. PROPERTIES OUTPUT_LOCATION ${_translations_dir})
  210. if(CTK_QT_VERSION VERSION_GREATER "4")
  211. qt5_create_translation(_plugin_qm_files ${MY_SRCS} ${MY_UI_FORMS} ${MY_TRANSLATIONS})
  212. else()
  213. QT4_CREATE_TRANSLATION(_plugin_qm_files ${MY_SRCS} ${MY_UI_FORMS} ${MY_TRANSLATIONS})
  214. endif()
  215. endif()
  216. if(_plugin_qm_files)
  217. foreach(_qm_file ${_plugin_qm_files})
  218. file(RELATIVE_PATH _relative_qm_file ${CMAKE_CURRENT_BINARY_DIR} ${_qm_file})
  219. list(APPEND _plugin_cached_resources_in_binary_tree ${_relative_qm_file})
  220. endforeach()
  221. endif()
  222. set(_plugin_cached_resources_in_source_tree )
  223. if(MY_CACHED_RESOURCEFILES)
  224. foreach(_cached_resource ${MY_CACHED_RESOURCEFILES})
  225. if(IS_ABSOLUTE "${_cached_resource}")
  226. # create a path relative to the current binary dir
  227. file(RELATIVE_PATH _relative_cached_resource ${CMAKE_CURRENT_BINARY_DIR} ${_cached_resource})
  228. list(APPEND _plugin_cached_resources_in_binary_tree ${_relative_cached_resource})
  229. else()
  230. list(APPEND _plugin_cached_resources_in_source_tree ${_cached_resource})
  231. endif()
  232. endforeach()
  233. endif()
  234. # Add any other additional resource files
  235. if(_plugin_cached_resources_in_source_tree OR _plugin_cached_resources_in_binary_tree)
  236. string(REPLACE "." "_" _plugin_symbolicname ${Plugin-SymbolicName})
  237. ctkMacroGeneratePluginResourcefile(MY_QRC_SRCS
  238. NAME ${_plugin_symbolicname}_cached.qrc
  239. PREFIX ${Plugin-SymbolicName}
  240. RESOURCES ${_plugin_cached_resources_in_source_tree}
  241. BINARY_RESOURCES ${_plugin_cached_resources_in_binary_tree})
  242. endif()
  243. source_group("Resources" FILES
  244. ${MY_RESOURCES}
  245. ${MY_UI_FORMS}
  246. ${MY_TRANSLATIONS}
  247. )
  248. source_group("Generated" FILES
  249. ${MY_QRC_SRCS}
  250. ${MY_MOC_CPP}
  251. ${MY_UI_CPP}
  252. ${_plugin_qm_files}
  253. )
  254. add_library(${lib_name} ${MY_LIBRARY_TYPE}
  255. ${MY_SRCS}
  256. ${MY_MOC_CPP}
  257. ${MY_UI_CPP}
  258. ${MY_QRC_SRCS}
  259. ${_plugin_qm_files}
  260. )
  261. if(NOT CMAKE_VERSION VERSION_LESS 2.8.12)
  262. target_include_directories(${lib_name}
  263. PUBLIC "$<BUILD_INTERFACE:${my_includes}>"
  264. "$<INSTALL_INTERFACE:${CTK_INSTALL_PLUGIN_INCLUDE_DIR}/${Plugin-SymbolicName}>"
  265. )
  266. if(CTK_QT_VERSION VERSION_LESS "5")
  267. # Add Qt include dirs to the target
  268. target_include_directories(${lib_name} PUBLIC ${QT_INCLUDE_DIR})
  269. foreach(module QT3SUPPORT QTOPENGL QTASSISTANT QTDESIGNER QTMOTIF QTNSPLUGIN
  270. QAXSERVER QAXCONTAINER QTDECLARATIVE QTSCRIPT QTSVG QTUITOOLS QTHELP
  271. QTWEBKIT PHONON QTSCRIPTTOOLS QTMULTIMEDIA QTXMLPATTERNS QTGUI QTTEST
  272. QTDBUS QTXML QTSQL QTNETWORK QTCORE)
  273. if (QT_USE_${module} OR QT_USE_${module}_DEPENDS)
  274. if (QT_${module}_FOUND)
  275. target_include_directories(${lib_name} PUBLIC ${QT_${module}_INCLUDE_DIR})
  276. endif ()
  277. endif ()
  278. endforeach()
  279. endif()
  280. else()
  281. find_package(Qt5LinguistTools REQUIRED)
  282. endif()
  283. if(MY_TEST_PLUGIN AND CTK_QT_VERSION VERSION_GREATER "4")
  284. find_package(Qt5Test REQUIRED)
  285. if(CMAKE_VERSION VERSION_LESS 2.8.12)
  286. target_link_libraries(${lib_name} Qt5::Test)
  287. else()
  288. target_link_libraries(${lib_name} PRIVATE Qt5::Test)
  289. endif()
  290. endif()
  291. # Set the output directory for the plugin
  292. if(MY_OUTPUT_DIR)
  293. set(output_dir_suffix "/${MY_OUTPUT_DIR}")
  294. else()
  295. set(output_dir_suffix "")
  296. endif()
  297. foreach(type RUNTIME LIBRARY ARCHIVE)
  298. if(NOT DEFINED CTK_PLUGIN_${type}_OUTPUT_DIRECTORY AND CMAKE_${type}_OUTPUT_DIRECTORY)
  299. # Put plug-ins by default into a "plugins" subdirectory
  300. set(CTK_PLUGIN_${type}_OUTPUT_DIRECTORY "${CMAKE_${type}_OUTPUT_DIRECTORY}/plugins")
  301. endif()
  302. if(IS_ABSOLUTE "${CTK_PLUGIN_${type}_OUTPUT_DIRECTORY}")
  303. set(plugin_${type}_output_dir "${CTK_PLUGIN_${type}_OUTPUT_DIRECTORY}${output_dir_suffix}")
  304. elseif(CMAKE_${type}_OUTPUT_DIRECTORY)
  305. set(plugin_${type}_output_dir "${CMAKE_${type}_OUTPUT_DIRECTORY}/${CTK_PLUGIN_${type}_OUTPUT_DIRECTORY}${output_dir_suffix}")
  306. else()
  307. set(plugin_${type}_output_dir "${CMAKE_CURRENT_BINARY_DIR}/${CTK_PLUGIN_${type}_OUTPUT_DIRECTORY}${output_dir_suffix}")
  308. endif()
  309. if(MY_TEST_PLUGIN)
  310. # Test plug-ins will always be put in a separate directory
  311. if(CMAKE_${type}_OUTPUT_DIRECTORY)
  312. set(plugin_${type}_output_dir "${CMAKE_${type}_OUTPUT_DIRECTORY}/test_plugins")
  313. else()
  314. set(plugin_${type}_output_dir "${PROJECT_BINARY_DIR}/test_plugins")
  315. endif()
  316. endif()
  317. endforeach()
  318. set(plugin_compile_flags "-DQT_PLUGIN")
  319. ctkFunctionGetCompilerVisibilityFlags(plugin_compile_flags)
  320. # Apply properties to the library target.
  321. set_target_properties(${lib_name} PROPERTIES
  322. COMPILE_FLAGS "${plugin_compile_flags}"
  323. RUNTIME_OUTPUT_DIRECTORY ${plugin_RUNTIME_output_dir}
  324. LIBRARY_OUTPUT_DIRECTORY ${plugin_LIBRARY_output_dir}
  325. ARCHIVE_OUTPUT_DIRECTORY ${plugin_ARCHIVE_output_dir}
  326. PREFIX "lib"
  327. )
  328. if(NOT MY_TEST_PLUGIN AND NOT MY_NO_INSTALL)
  329. # Install rules
  330. install(TARGETS ${lib_name} EXPORT CTKExports
  331. RUNTIME DESTINATION ${CTK_INSTALL_PLUGIN_DIR} COMPONENT RuntimePlugins
  332. LIBRARY DESTINATION ${CTK_INSTALL_PLUGIN_DIR} COMPONENT RuntimePlugins
  333. ARCHIVE DESTINATION ${CTK_INSTALL_PLUGIN_DIR} COMPONENT Development)
  334. endif()
  335. set(my_libs
  336. ${MY_TARGET_LIBRARIES}
  337. )
  338. if(MINGW)
  339. list(APPEND my_libs ssp) # add stack smash protection lib
  340. endif()
  341. if(CMAKE_VERSION VERSION_LESS 2.8.12)
  342. target_link_libraries(${lib_name} ${my_libs})
  343. else()
  344. target_link_libraries(${lib_name} PUBLIC ${my_libs})
  345. endif()
  346. if(NOT MY_TEST_PLUGIN)
  347. set(${CMAKE_PROJECT_NAME}_PLUGIN_LIBRARIES ${${CMAKE_PROJECT_NAME}_PLUGIN_LIBRARIES} ${lib_name} CACHE INTERNAL "CTK plugins" FORCE)
  348. endif()
  349. if(NOT MY_TEST_PLUGIN AND NOT MY_NO_INSTALL)
  350. # Install headers
  351. file(GLOB headers "${CMAKE_CURRENT_SOURCE_DIR}/*.h" "${CMAKE_CURRENT_SOURCE_DIR}/*.tpp")
  352. install(FILES
  353. ${headers}
  354. ${dynamicHeaders}
  355. DESTINATION ${CTK_INSTALL_PLUGIN_INCLUDE_DIR}/${Plugin-SymbolicName} COMPONENT Development
  356. )
  357. endif()
  358. endmacro()