KF5CoreAddonsMacros.cmake 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. #
  2. # kcoreaddons_desktop_to_json(target desktopfile
  3. # DEFAULT_SERVICE_TYPE | SERVICE_TYPES <file> [<file> [...]]
  4. # [OUTPUT_DIR dir | OUTPUT_FILE file] [COMPAT_MODE])
  5. #
  6. # This macro uses desktoptojson to generate a json file from a plugin
  7. # description in a .desktop file. The generated file can be compiled
  8. # into the plugin using the K_PLUGIN_FACTORY_WITH_JSON (cpp) macro.
  9. #
  10. # All files in SERVICE_TYPES will be parsed by desktoptojson to ensure that the generated
  11. # json uses the right data type (string, string list, int, double or bool) for all of the
  12. # properties. If your application does not have any custom properties defined you should pass
  13. # DEFAULT_SERVICE_TYPE instead. It is an error if neither of these arguments is given.
  14. # This is done in order to ensure that all applications explicitly choose the right service
  15. # type and don't have runtime errors because of the data being wrong (QJsonValue does not
  16. # perform any type conversions).
  17. #
  18. # If COMPAT_MODE is passed as an argument the generated JSON file will be compatible with
  19. # the metadata format used by KPluginInfo (from KService), otherwise it will default to
  20. # the new format that is used by KPluginMetaData (from KCoreAddons).
  21. #
  22. # If OUTPUT_DIR is set the generated file will be created inside <dir> instead of in
  23. # ${CMAKE_CURRENT_BINARY_DIR}
  24. #
  25. # If OUTPUT_FILE is set the generated file will be <file> instead of the default
  26. # ${CMAKE_CURRENT_BINARY_DIR}/$(basename desktopfile).json
  27. # .. note::
  28. # This is only considered porting aid and will be removed in KF6. Please convert the desktop files
  29. # in-source to json using the desktoptojson executable
  30. #
  31. # Example:
  32. #
  33. # kcoreaddons_desktop_to_json(plasma_engine_time plasma-dataengine-time.desktop
  34. # SERVICE_TYPES plasma-dataengine.desktop)
  35. function(kcoreaddons_desktop_to_json target desktop)
  36. message(WARNING "kcoreaddons_desktop_to_json is deprecated and will be removed in KF6. Convert the desktop files to JSON in source using the desktoptojson executable")
  37. get_filename_component(desktop_basename ${desktop} NAME_WE) # allow passing an absolute path to the .desktop
  38. cmake_parse_arguments(DESKTOP_TO_JSON "COMPAT_MODE;DEFAULT_SERVICE_TYPE" "OUTPUT_DIR;OUTPUT_FILE" "SERVICE_TYPES" ${ARGN})
  39. if(DESKTOP_TO_JSON_OUTPUT_FILE)
  40. set(json "${DESKTOP_TO_JSON_OUTPUT_FILE}")
  41. elseif(DESKTOP_TO_JSON_OUTPUT_DIR)
  42. set(json "${DESKTOP_TO_JSON_OUTPUT_DIR}/${desktop_basename}.json")
  43. else()
  44. set(json "${CMAKE_CURRENT_BINARY_DIR}/${desktop_basename}.json")
  45. endif()
  46. if(CMAKE_VERSION VERSION_LESS 2.8.12.20140127 OR "${target}" STREQUAL "")
  47. _desktop_to_json_cmake28(${desktop} ${json} ${DESKTOP_TO_JSON_COMPAT_MODE})
  48. return()
  49. elseif(MSVC_IDE AND CMAKE_VERSION VERSION_LESS 3.0)
  50. # autogen dependencies for visual studio generator are broken until cmake commit 2ed0d06
  51. _desktop_to_json_cmake28(${desktop} ${json} ${DESKTOP_TO_JSON_COMPAT_MODE})
  52. return()
  53. endif()
  54. kcoreaddons_desktop_to_json_crosscompilation_args(_crosscompile_args)
  55. set(command KF5::desktoptojson ${_crosscompile_args} -i ${desktop} -o ${json})
  56. if(DESKTOP_TO_JSON_COMPAT_MODE)
  57. list(APPEND command -c)
  58. endif()
  59. if(DESKTOP_TO_JSON_SERVICE_TYPES)
  60. foreach(type ${DESKTOP_TO_JSON_SERVICE_TYPES})
  61. if(NOT IS_ABSOLUTE "${type}")
  62. if(CMAKE_CROSSCOMPILING)
  63. if (DEFINED KSERVICETYPE_PATH_${type})
  64. set(_guess ${KSERVICETYPE_PATH_${type}})
  65. else()
  66. set(_guess ${CMAKE_SYSROOT}/${KDE_INSTALL_FULL_KSERVICETYPESDIR}/${type})
  67. endif()
  68. if(EXISTS ${_guess})
  69. set(type ${CMAKE_SYSROOT}/${KDE_INSTALL_FULL_KSERVICETYPESDIR}/${type})
  70. else()
  71. message(WARNING "Could not find service type ${type}, tried ${_guess}. Set KSERVICETYPE_PATH_${type} to override this guess.")
  72. endif()
  73. elseif(EXISTS ${KDE_INSTALL_FULL_KSERVICETYPESDIR}/${type})
  74. set(type ${KDE_INSTALL_FULL_KSERVICETYPESDIR}/${type})
  75. endif()
  76. endif()
  77. list(APPEND command -s ${type})
  78. endforeach()
  79. endif()
  80. file(RELATIVE_PATH relativejson ${CMAKE_CURRENT_BINARY_DIR} ${json})
  81. add_custom_command(
  82. OUTPUT ${json}
  83. COMMAND ${command}
  84. WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
  85. DEPENDS ${desktop}
  86. COMMENT "Generating ${relativejson}"
  87. )
  88. set_property(TARGET ${target} APPEND PROPERTY AUTOGEN_TARGET_DEPENDS ${json})
  89. endfunction()
  90. # Internal function to get the additional arguments that should be passed to desktoptojson when cross-compiling
  91. function(kcoreaddons_desktop_to_json_crosscompilation_args output_var)
  92. set(_extra_args)
  93. # When cross-compiling we can't use relative paths since that might find an incompatible file on the host
  94. # using QStandardPaths (or not find any at all e.g. when cross-compiling from macOS).
  95. if(CMAKE_CROSSCOMPILING)
  96. set(_extra_args --strict-path-mode --generic-data-path "${CMAKE_SYSROOT}/${KDE_INSTALL_FULL_DATAROOTDIR}")
  97. endif()
  98. set(${output_var} ${_extra_args} PARENT_SCOPE)
  99. endfunction()
  100. function(_desktop_to_json_cmake28 desktop json compat)
  101. # This function runs desktoptojson at *configure* time, ie, when CMake runs.
  102. # This is necessary with CMake < 3.0.0 because the .json file must be
  103. # generated before moc is run, and there was no way until CMake 3.0.0 to
  104. # define a target as a dependency of the automoc target.
  105. message("Using CMake 2.8 way to call desktoptojson")
  106. get_target_property(DESKTOPTOJSON_LOCATION KF5::desktoptojson LOCATION)
  107. if(compat)
  108. execute_process(
  109. COMMAND ${DESKTOPTOJSON_LOCATION} -i ${desktop} -o ${json} -c
  110. RESULT_VARIABLE result
  111. WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
  112. )
  113. else()
  114. execute_process(
  115. COMMAND ${DESKTOPTOJSON_LOCATION} -i ${desktop} -o ${json}
  116. RESULT_VARIABLE result
  117. WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
  118. )
  119. endif()
  120. if (NOT result EQUAL 0)
  121. message(FATAL_ERROR "Generating ${json} failed")
  122. endif()
  123. endfunction()
  124. #
  125. # kcoreaddons_add_plugin(plugin_name
  126. # [SOURCES <src> [<src> [...]]] # optional since 5.83, required before
  127. # [JSON "pluginname.json"]
  128. # [STATIC]
  129. # [INSTALL_NAMESPACE "servicename"]
  130. # )
  131. #
  132. # This macro helps simplifying the creation of plugins for KPluginFactory
  133. # based systems.
  134. # It will create a plugin given the SOURCES list and the INSTALL_NAMESPACE so that
  135. # the plugin is installed with the rest of the plugins from the same sub-system,
  136. # within ${KDE_INSTALL_PLUGINDIR}.
  137. # The JSON parameter is deprecated since 5.85, because it is not needed when the project is properly set up using
  138. # the ECMSetupQtPluginMacroNames module. In case of plugin export macros provided by the KDE Frameworks this is already done and the parameter
  139. # can be dropped with any older KF5 requirement.
  140. # In case you generate the JSON files during the build it should be manually added to the AUTOGEN_TARGET_DEPENDS property,
  141. # the kcoreaddons_desktop_to_json already does this for the generated file.
  142. # Since 5.89 the macro supports static plugins by passing in the STATIC option.
  143. #
  144. # Example:
  145. # kcoreaddons_add_plugin(kdeconnect_share SOURCES ${kdeconnect_share_SRCS} INSTALL_NAMESPACE "kdeconnect")
  146. #
  147. # Since 5.10.0
  148. function(kcoreaddons_add_plugin plugin)
  149. set(options STATIC)
  150. set(oneValueArgs JSON INSTALL_NAMESPACE)
  151. set(multiValueArgs SOURCES)
  152. cmake_parse_arguments(KCA_ADD_PLUGIN "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
  153. if (NOT KCA_ADD_PLUGIN_INSTALL_NAMESPACE)
  154. message(FATAL_ERROR "Must specify INSTALL_NAMESPACE for ${plugin}")
  155. endif()
  156. if (KCA_ADD_PLUGIN_UNPARSED_ARGUMENTS)
  157. if ("${ECM_GLOBAL_FIND_VERSION}" VERSION_GREATER_EQUAL "5.91.0")
  158. message(FATAL_ERROR "kcoreaddons_add_plugin method call recieved unexpected arguments: ${KCA_ADD_PLUGIN_UNPARSED_ARGUMENTS}")
  159. else()
  160. message(WARNING "kcoreaddons_add_plugin method call recieved unexpected arguments: ${KCA_ADD_PLUGIN_UNPARSED_ARGUMENTS}")
  161. endif()
  162. endif()
  163. string(REPLACE "-" "_" SANITIZED_PLUGIN_NAME ${plugin})
  164. string(REPLACE "." "_" SANITIZED_PLUGIN_NAME ${SANITIZED_PLUGIN_NAME})
  165. if (KCA_ADD_PLUGIN_STATIC)
  166. add_library(${plugin} STATIC ${KCA_ADD_PLUGIN_SOURCES})
  167. target_compile_definitions(${plugin} PRIVATE QT_STATICPLUGIN)
  168. set_property(TARGET ${plugin} PROPERTY AUTOMOC_MOC_OPTIONS -MX-KDE-FileName=${KCA_ADD_PLUGIN_INSTALL_NAMESPACE}/${plugin})
  169. string(REPLACE "/" "_" SANITIZED_PLUGIN_NAMESPACE ${KCA_ADD_PLUGIN_INSTALL_NAMESPACE})
  170. if (NOT ${SANITIZED_PLUGIN_NAME} IN_LIST KCOREADDONS_STATIC_PLUGINS${SANITIZED_PLUGIN_NAMESPACE})
  171. set(KCOREADDONS_STATIC_PLUGINS${SANITIZED_PLUGIN_NAMESPACE} "${KCOREADDONS_STATIC_PLUGINS${SANITIZED_PLUGIN_NAMESPACE}};${SANITIZED_PLUGIN_NAME}" CACHE INTERNAL "list of known static plugins for ${KCA_ADD_PLUGIN_INSTALL_NAMESPACE} namespace, used to generate Q_IMPORT_PLUGIN macros")
  172. endif()
  173. else()
  174. add_library(${plugin} MODULE ${KCA_ADD_PLUGIN_SOURCES})
  175. endif()
  176. if ("${ECM_GLOBAL_FIND_VERSION}" VERSION_GREATER_EQUAL "5.85.0" AND KCA_ADD_PLUGIN_JSON)
  177. message(WARNING "Setting the JSON parameter is deprecated, see function docs for details")
  178. endif()
  179. get_filename_component(json "${KCA_ADD_PLUGIN_JSON}" REALPATH)
  180. set_property(TARGET ${plugin} APPEND PROPERTY AUTOGEN_TARGET_DEPENDS ${json})
  181. if ("${ECM_GLOBAL_FIND_VERSION}" VERSION_GREATER_EQUAL "5.88.0")
  182. target_compile_definitions(${plugin} PRIVATE KPLUGINFACTORY_PLUGIN_CLASS_INTERNAL_NAME=${SANITIZED_PLUGIN_NAME}_factory)
  183. endif()
  184. # If we have static plugins there are no plugins to install
  185. if (KCA_ADD_PLUGIN_STATIC)
  186. return()
  187. endif()
  188. # If find_package(ECM 5.38) or higher is called, output the plugin in a INSTALL_NAMESPACE subfolder.
  189. # See https://community.kde.org/Guidelines_and_HOWTOs/Making_apps_run_uninstalled
  190. # From 5.90 we went back to putting the plugins in a INSTALL_NAMESPACE subfolder in the builddir, but
  191. # without putting that in a "plugins/" dir as that broke running unittests directly on the command line
  192. # (i.e. without using ctest, e.g. in gdb).
  193. if(ECM_GLOBAL_FIND_VERSION VERSION_EQUAL "5.88.0" OR ECM_GLOBAL_FIND_VERSION VERSION_EQUAL "5.89.0")
  194. set_target_properties(${plugin} PROPERTIES
  195. LIBRARY_OUTPUT_DIRECTORY "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/plugins/${KCA_ADD_PLUGIN_INSTALL_NAMESPACE}")
  196. elseif(ECM_GLOBAL_FIND_VERSION VERSION_GREATER_EQUAL "5.38.0")
  197. set_target_properties(${plugin} PROPERTIES
  198. LIBRARY_OUTPUT_DIRECTORY "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/${KCA_ADD_PLUGIN_INSTALL_NAMESPACE}")
  199. endif()
  200. if (NOT KCOREADDONS_INTERNAL_SKIP_PLUGIN_INSTALLATION)
  201. if(NOT ANDROID)
  202. install(TARGETS ${plugin} DESTINATION ${KDE_INSTALL_PLUGINDIR}/${KCA_ADD_PLUGIN_INSTALL_NAMESPACE})
  203. else()
  204. string(REPLACE "/" "_" pluginprefix "${KCA_ADD_PLUGIN_INSTALL_NAMESPACE}")
  205. set_property(TARGET ${plugin} PROPERTY PREFIX "libplugins_")
  206. if(NOT pluginprefix STREQUAL "")
  207. set_property(TARGET ${plugin} APPEND_STRING PROPERTY PREFIX "${pluginprefix}_")
  208. endif()
  209. install(TARGETS ${plugin} DESTINATION ${KDE_INSTALL_PLUGINDIR})
  210. endif()
  211. endif()
  212. endfunction()
  213. # This macro imports the plugins for the given namespace that were
  214. # registered using the kcoreaddons_add_plugin function.
  215. # This includes the K_IMPORT_PLUGIN statements and linking the plugins to the given target.
  216. #
  217. # In case the plugins are used in both the executable and multiple autotests it it recommended to
  218. # bundle the static plugins in a shared lib for the autotests. In case of shared libs the plugin registrations
  219. # will take effect when the test link against it.
  220. #
  221. # Since 5.89
  222. function(kcoreaddons_target_static_plugins app_target plugin_namespace)
  223. cmake_parse_arguments(ARGS "" "LINK_OPTION" "" ${ARGN})
  224. set(IMPORT_PLUGIN_STATEMENTS "#include <kstaticpluginhelpers.h>\n\n")
  225. string(REPLACE "/" "_" SANITIZED_PLUGIN_NAMESPACE ${plugin_namespace})
  226. set(TMP_PLUGIN_FILE "${CMAKE_CURRENT_BINARY_DIR}/kcoreaddons_static_${SANITIZED_PLUGIN_NAMESPACE}_plugins_tmp.cpp")
  227. set(PLUGIN_FILE "${CMAKE_CURRENT_BINARY_DIR}/kcoreaddons_static_${SANITIZED_PLUGIN_NAMESPACE}_plugins.cpp")
  228. foreach(PLUGIN_TARGET_NAME IN LISTS KCOREADDONS_STATIC_PLUGINS${SANITIZED_PLUGIN_NAMESPACE})
  229. if (PLUGIN_TARGET_NAME)
  230. set(IMPORT_PLUGIN_STATEMENTS "${IMPORT_PLUGIN_STATEMENTS}K_IMPORT_PLUGIN(QStringLiteral(\"${plugin_namespace}\"), ${PLUGIN_TARGET_NAME}_factory)\;\n")
  231. target_link_libraries(${app_target} ${ARGS_LINK_OPTION} ${PLUGIN_TARGET_NAME})
  232. endif()
  233. endforeach()
  234. file(WRITE ${TMP_PLUGIN_FILE} ${IMPORT_PLUGIN_STATEMENTS})
  235. execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different ${TMP_PLUGIN_FILE} ${PLUGIN_FILE})
  236. file(REMOVE ${TMP_PLUGIN_FILE})
  237. if(ECM_GLOBAL_FIND_VERSION VERSION_GREATER_EQUAL "5.91.0")
  238. target_sources(${app_target} PRIVATE ${PLUGIN_FILE})
  239. else()
  240. # in case of apps bundling their plugins in a small static lib the linking needs to be public
  241. # see API docs for a better solution in consumer's code.
  242. # Because this will not change the behavior if the plugins are targeted directly to the executable, only
  243. # an ECM version check is used and not an additional option.
  244. target_sources(${app_target} PUBLIC ${PLUGIN_FILE})
  245. endif()
  246. endfunction()
  247. # Clear previously set plugins, otherwise Q_IMPORT_PLUGIN statements
  248. # will fail to compile if plugins got removed from the build
  249. get_directory_property(_cache_vars CACHE_VARIABLES)
  250. foreach(CACHED_VAR IN LISTS _cache_vars)
  251. if (CACHED_VAR MATCHES "^KCOREADDONS_STATIC_PLUGINS")
  252. set(${CACHED_VAR} "" CACHE INTERNAL "")
  253. endif()
  254. endforeach()