1 ###########################################################################
5 # Copyright (c) Kitware Inc.
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
11 # http://www.apache.org/licenses/LICENSE-2.0.txt
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.
19 ###########################################################################
23 # CTK/CMake/ctkMacroParseArguments.cmake
24 # CTK/CMake/ctkMacroGeneratePluginManifest.cmake
26 #! \brief Build a CTK plug-in.
28 #! This macro takes the usual arguments for building
29 #! a shared library using Qt. Additionally, it generates
30 #! plugin meta-data by creating a MANIFEST.MF text file
31 #! which is embedded in the share library as a Qt resource.
33 #! The following variables can be set in a file named
34 #! manifest_headers.cmake, which will then be read by
37 #! - Plugin-ActivationPolicy
39 #! - Plugin-ContactAddress
41 #! - Plugin-Description
51 macro(ctkMacroBuildPlugin)
52 CtkMacroParseArguments(MY
53 "EXPORT_DIRECTIVE;SRCS;MOC_SRCS;MOC_OPTIONS;UI_FORMS;INCLUDE_DIRECTORIES;EXPORTED_INCLUDE_SUFFIXES;TARGET_LIBRARIES;RESOURCES;CACHED_RESOURCEFILES;TRANSLATIONS;OUTPUT_DIR"
54 "TEST_PLUGIN;NO_INSTALL"
58 # Keep parameter 'INCLUDE_DIRECTORIES' for backward compatiblity
61 if(NOT DEFINED MY_EXPORT_DIRECTIVE)
62 message(FATAL_ERROR "EXPORT_DIRECTIVE is mandatory")
65 # Print a warning if the project name does not match the directory name
66 get_filename_component(_dir_name ${CMAKE_CURRENT_SOURCE_DIR} NAME)
67 string(REPLACE "." "_" _dir_name_with_ ${_dir_name})
68 if(NOT _dir_name_with_ STREQUAL ${PROJECT_NAME})
69 message(WARNING "Discouraged mismatch of plug-in project name [${PROJECT_NAME}] and top-level directory name [${CMAKE_CURRENT_SOURCE_DIR}].")
73 set(lib_name ${PROJECT_NAME})
75 # Plug-in target names must contain at leas one _
76 if(NOT lib_name MATCHES _)
77 message(FATAL_ERROR "The plug-in project name ${lib_name} must contain at least one '_' character")
80 # Plugin are expected to be shared library
81 set(MY_LIBRARY_TYPE "SHARED")
83 # Clear the variables for the manifest headers
84 set(Plugin-ActivationPolicy )
86 set(Plugin-ContactAddress )
87 set(Plugin-Copyright )
88 set(Plugin-Description )
94 set(Plugin-SymbolicName )
101 # Since the test plug-ins are not considered when calculating
102 # target dependencies via DGraph, we add the dependencies
104 #message("${lib_name}_DEPENDENCIES ${MY_TARGET_LIBRARIES}")
105 list(APPEND ${lib_name}_DEPENDENCIES ${MY_TARGET_LIBRARIES})
108 # If a file named manifest_headers.cmake exists, read it
109 set(manifest_headers_dep )
110 if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/manifest_headers.cmake")
111 include(${CMAKE_CURRENT_SOURCE_DIR}/manifest_headers.cmake)
112 set(manifest_headers_dep "${CMAKE_CURRENT_SOURCE_DIR}/manifest_headers.cmake")
115 string(REPLACE "_" "." Plugin-SymbolicName ${lib_name})
117 # --------------------------------------------------------------------------
119 if(MY_EXPORTED_INCLUDE_SUFFIXES)
120 set(${lib_name}_INCLUDE_SUFFIXES ${MY_EXPORTED_INCLUDE_SUFFIXES}
121 CACHE INTERNAL "List of exported plugin include dirs")
124 foreach(_suffix ${MY_EXPORTED_INCLUDE_SUFFIXES})
125 list(APPEND my_includes ${CMAKE_CURRENT_SOURCE_DIR}/${_suffix})
128 set(${lib_name}_INCLUDE_SUFFIXES ""
129 CACHE INTERNAL "List of exported plugin include dirs")
134 list(APPEND my_includes
135 ${CMAKE_CURRENT_SOURCE_DIR}
136 ${CMAKE_CURRENT_BINARY_DIR}
139 # Add the include directories from the plugin dependencies
140 # and external dependencies
141 ctkFunctionGetIncludeDirs(my_includes ${lib_name})
143 if(CMAKE_VERSION VERSION_LESS 2.8.12)
149 if(CTK_QT_VERSION VERSION_LESS "5")
150 # Add Qt include dirs and defines
151 include(${QT_USE_FILE})
153 find_package(Qt5 COMPONENTS LinguistTools REQUIRED)
156 # Add the library directories from the external project
157 ctkFunctionGetLibraryDirs(my_library_dirs ${lib_name})
163 set(MY_LIBRARY_EXPORT_DIRECTIVE ${MY_EXPORT_DIRECTIVE})
164 set(MY_EXPORT_HEADER_PREFIX "${lib_name}_")
165 set(MY_LIBNAME ${lib_name})
168 ${CTK_EXPORT_HEADER_TEMPLATE}
169 ${CMAKE_CURRENT_BINARY_DIR}/${MY_EXPORT_HEADER_PREFIX}Export.h
172 "${dynamicHeaders};${CMAKE_CURRENT_BINARY_DIR}/${MY_EXPORT_HEADER_PREFIX}Export.h")
174 # Make sure variable are cleared
180 if (CTK_QT_VERSION VERSION_GREATER "4")
182 if(Qt5Core_VERSION VERSION_GREATER "5.2.0")
183 set(target TARGET ${lib_name})
186 # this is a workaround for Visual Studio. The relative include paths in the generated
187 # moc files can get very long and can't be resolved by the MSVC compiler.
188 foreach(moc_src ${MY_MOC_SRCS})
189 QT5_WRAP_CPP(MY_MOC_CPP ${moc_src} OPTIONS -f${moc_src} -DHAVE_QT5 ${MY_MOC_OPTIONS} ${target})
192 QT5_WRAP_UI(MY_UI_CPP ${MY_UI_FORMS})
193 if(DEFINED MY_RESOURCES)
194 QT5_ADD_RESOURCES(MY_QRC_SRCS ${MY_RESOURCES})
198 # this is a workaround for Visual Studio. The relative include paths in the generated
199 # moc files can get very long and can't be resolved by the MSVC compiler.
200 foreach(moc_src ${MY_MOC_SRCS})
201 QT4_WRAP_CPP(MY_MOC_CPP ${moc_src} OPTIONS -f${moc_src} ${MY_MOC_OPTIONS} TARGET ${lib_name})
204 QT4_WRAP_UI(MY_UI_CPP ${MY_UI_FORMS})
205 if(DEFINED MY_RESOURCES)
206 QT4_ADD_RESOURCES(MY_QRC_SRCS ${MY_RESOURCES})
209 # Add the generated manifest qrc file
210 set(manifest_qrc_src )
211 ctkFunctionGeneratePluginManifest(manifest_qrc_src
212 ACTIVATIONPOLICY ${Plugin-ActivationPolicy}
213 CATEGORY ${Plugin-Category}
214 CONTACT_ADDRESS ${Plugin-ContactAddress}
215 COPYRIGHT ${Plugin-Copyright}
216 DESCRIPTION ${Plugin-Description}
217 DOC_URL ${Plugin-DocURL}
219 LICENSE ${Plugin-License}
221 REQUIRE_PLUGIN ${Require-Plugin}
222 SYMBOLIC_NAME ${Plugin-SymbolicName}
223 VENDOR ${Plugin-Vendor}
224 VERSION ${Plugin-Version}
225 CUSTOM_HEADERS ${Custom-Headers}
228 if(manifest_headers_dep)
229 set_property(SOURCE ${manifest_qrc_src} APPEND
230 PROPERTY OBJECT_DEPENDS ${manifest_headers_dep})
232 list(APPEND MY_QRC_SRCS ${manifest_qrc_src})
234 # Create translation files (.ts and .qm)
235 set(_plugin_qm_files )
236 set(_plugin_cached_resources_in_binary_tree )
237 set(_translations_dir "${CMAKE_CURRENT_BINARY_DIR}/CTK-INF/l10n")
239 set_source_files_properties(${MY_TRANSLATIONS}
240 PROPERTIES OUTPUT_LOCATION ${_translations_dir})
241 if(CTK_QT_VERSION VERSION_GREATER "4")
242 qt5_create_translation(_plugin_qm_files ${MY_SRCS} ${MY_UI_FORMS} ${MY_TRANSLATIONS})
244 QT4_CREATE_TRANSLATION(_plugin_qm_files ${MY_SRCS} ${MY_UI_FORMS} ${MY_TRANSLATIONS})
249 foreach(_qm_file ${_plugin_qm_files})
250 file(RELATIVE_PATH _relative_qm_file ${CMAKE_CURRENT_BINARY_DIR} ${_qm_file})
251 list(APPEND _plugin_cached_resources_in_binary_tree ${_relative_qm_file})
255 set(_plugin_cached_resources_in_source_tree )
256 if(MY_CACHED_RESOURCEFILES)
257 foreach(_cached_resource ${MY_CACHED_RESOURCEFILES})
258 if(IS_ABSOLUTE "${_cached_resource}")
259 # create a path relative to the current binary dir
260 file(RELATIVE_PATH _relative_cached_resource ${CMAKE_CURRENT_BINARY_DIR} ${_cached_resource})
261 list(APPEND _plugin_cached_resources_in_binary_tree ${_relative_cached_resource})
263 list(APPEND _plugin_cached_resources_in_source_tree ${_cached_resource})
268 # Add any other additional resource files
269 if(_plugin_cached_resources_in_source_tree OR _plugin_cached_resources_in_binary_tree)
270 string(REPLACE "." "_" _plugin_symbolicname ${Plugin-SymbolicName})
271 ctkMacroGeneratePluginResourcefile(MY_QRC_SRCS
272 NAME ${_plugin_symbolicname}_cached.qrc
273 PREFIX ${Plugin-SymbolicName}
274 RESOURCES ${_plugin_cached_resources_in_source_tree}
275 BINARY_RESOURCES ${_plugin_cached_resources_in_binary_tree})
278 source_group("Resources" FILES
284 source_group("Generated" FILES
291 add_library(${lib_name} ${MY_LIBRARY_TYPE}
299 if(NOT CMAKE_VERSION VERSION_LESS 2.8.12)
300 target_include_directories(${lib_name}
301 PUBLIC "$<BUILD_INTERFACE:${my_includes}>"
302 "$<INSTALL_INTERFACE:${CTK_INSTALL_PLUGIN_INCLUDE_DIR}/${Plugin-SymbolicName}>"
304 if(CTK_QT_VERSION VERSION_LESS "5")
305 # Add Qt include dirs to the target
306 target_include_directories(${lib_name} PUBLIC ${QT_INCLUDE_DIR})
307 foreach(module QT3SUPPORT QTOPENGL QTASSISTANT QTDESIGNER QTMOTIF QTNSPLUGIN
308 QAXSERVER QAXCONTAINER QTDECLARATIVE QTSCRIPT QTSVG QTUITOOLS QTHELP
309 QTWEBKIT PHONON QTSCRIPTTOOLS QTMULTIMEDIA QTXMLPATTERNS QTGUI QTTEST
310 QTDBUS QTXML QTSQL QTNETWORK QTCORE)
311 if (QT_USE_${module} OR QT_USE_${module}_DEPENDS)
312 if (QT_${module}_FOUND)
313 target_include_directories(${lib_name} PUBLIC ${QT_${module}_INCLUDE_DIR})
319 find_package(Qt5LinguistTools REQUIRED)
322 if(MY_TEST_PLUGIN AND CTK_QT_VERSION VERSION_GREATER "4")
323 find_package(Qt5Test REQUIRED)
324 if(CMAKE_VERSION VERSION_LESS 2.8.12)
325 target_link_libraries(${lib_name} Qt5::Test)
327 target_link_libraries(${lib_name} PRIVATE Qt5::Test)
331 # Set the output directory for the plugin
333 set(output_dir_suffix "/${MY_OUTPUT_DIR}")
335 set(output_dir_suffix "")
338 foreach(type RUNTIME LIBRARY ARCHIVE)
339 if(NOT DEFINED CTK_PLUGIN_${type}_OUTPUT_DIRECTORY AND CMAKE_${type}_OUTPUT_DIRECTORY)
340 # Put plug-ins by default into a "plugins" subdirectory
341 set(CTK_PLUGIN_${type}_OUTPUT_DIRECTORY "${CMAKE_${type}_OUTPUT_DIRECTORY}/plugins")
344 if(IS_ABSOLUTE "${CTK_PLUGIN_${type}_OUTPUT_DIRECTORY}")
345 set(plugin_${type}_output_dir "${CTK_PLUGIN_${type}_OUTPUT_DIRECTORY}${output_dir_suffix}")
346 elseif(CMAKE_${type}_OUTPUT_DIRECTORY)
347 set(plugin_${type}_output_dir "${CMAKE_${type}_OUTPUT_DIRECTORY}/${CTK_PLUGIN_${type}_OUTPUT_DIRECTORY}${output_dir_suffix}")
349 set(plugin_${type}_output_dir "${CMAKE_CURRENT_BINARY_DIR}/${CTK_PLUGIN_${type}_OUTPUT_DIRECTORY}${output_dir_suffix}")
353 # Test plug-ins will always be put in a separate directory
354 if(CMAKE_${type}_OUTPUT_DIRECTORY)
355 set(plugin_${type}_output_dir "${CMAKE_${type}_OUTPUT_DIRECTORY}/test_plugins")
357 set(plugin_${type}_output_dir "${PROJECT_BINARY_DIR}/test_plugins")
362 set(plugin_compile_flags "-DQT_PLUGIN")
363 ctkFunctionGetCompilerVisibilityFlags(plugin_compile_flags)
365 # Apply properties to the library target.
366 set_target_properties(${lib_name} PROPERTIES
367 COMPILE_FLAGS "${plugin_compile_flags}"
368 RUNTIME_OUTPUT_DIRECTORY ${plugin_RUNTIME_output_dir}
369 LIBRARY_OUTPUT_DIRECTORY ${plugin_LIBRARY_output_dir}
370 ARCHIVE_OUTPUT_DIRECTORY ${plugin_ARCHIVE_output_dir}
374 if(NOT MY_TEST_PLUGIN AND NOT MY_NO_INSTALL)
376 install(TARGETS ${lib_name} EXPORT CTKExports
377 RUNTIME DESTINATION ${CTK_INSTALL_PLUGIN_DIR} COMPONENT RuntimePlugins
378 LIBRARY DESTINATION ${CTK_INSTALL_PLUGIN_DIR} COMPONENT RuntimePlugins
379 ARCHIVE DESTINATION ${CTK_INSTALL_PLUGIN_DIR} COMPONENT Development)
383 ${MY_TARGET_LIBRARIES}
387 list(APPEND my_libs ssp) # add stack smash protection lib
390 if(CMAKE_VERSION VERSION_LESS 2.8.12)
391 target_link_libraries(${lib_name} ${my_libs})
393 target_link_libraries(${lib_name} PUBLIC ${my_libs})
396 if(NOT MY_TEST_PLUGIN)
397 set(${CMAKE_PROJECT_NAME}_PLUGIN_LIBRARIES ${${CMAKE_PROJECT_NAME}_PLUGIN_LIBRARIES} ${lib_name} CACHE INTERNAL "CTK plugins" FORCE)
400 if(NOT MY_TEST_PLUGIN AND NOT MY_NO_INSTALL)
402 file(GLOB headers "${CMAKE_CURRENT_SOURCE_DIR}/*.h" "${CMAKE_CURRENT_SOURCE_DIR}/*.tpp")
406 DESTINATION ${CTK_INSTALL_PLUGIN_INCLUDE_DIR}/${Plugin-SymbolicName} COMPONENT Development