Warning, /frameworks/extra-cmake-modules/modules/ECMAddQch.cmake is written in an unsupported language. File is not indexed.

0001 # SPDX-FileCopyrightText: 2016-2017 Friedrich W. H. Kossebau <kossebau@kde.org>
0002 #
0003 # SPDX-License-Identifier: BSD-3-Clause
0004 
0005 #[=======================================================================[.rst:
0006 ECMAddQch
0007 ------------------
0008 
0009 This module provides the ``ecm_add_qch`` function for generating API
0010 documentation files in the QCH format, and the ``ecm_install_qch_export``
0011 function for generating and installing exported CMake targets for such
0012 generated QCH files to enable builds of other software with generation of
0013 QCH files to create links into the given QCH files.
0014 
0015 ::
0016 
0017   ecm_add_qch(<target_name>
0018       NAME <name>
0019       VERSION <version>
0020       QCH_INSTALL_DESTINATION <qchfile_install_path>
0021       TAGFILE_INSTALL_DESTINATION <tagsfile_install_path>
0022       [COMPONENT <component>]
0023       [BASE_NAME <basename>]
0024       [SOURCE_DIRS <dir> [<dir2> [...]]]
0025       [SOURCES <file> [<file2> [...]]]
0026       |MD_MAINPAGE <md_file>]
0027       [INCLUDE_DIRS <incdir> [<incdir2> [...]]]
0028       [IMAGE_DIRS <idir> [<idir2> [...]]]
0029       [EXAMPLE_DIRS <edir> [<edir2> [...]]]
0030       [ORG_DOMAIN <domain>]
0031       [NAMESPACE <namespace>]
0032       [LINK_QCHS <qch> [<qch2> [...]]]
0033       [PREDEFINED_MACROS <macro[=content]> [<macro2[=content]> [...]]]
0034       [BLANK_MACROS <macro> [<macro2> [...]]]
0035       [CONFIG_TEMPLATE <configtemplate_file>]
0036       [VERBOSE]
0037   )
0038 
0039 This macro adds a target called <target_name> for the creation of an API
0040 documentation manual in the QCH format from the given sources.
0041 It currently uses doxygen, future versions might optionally also allow other
0042 tools.
0043 Next to the QCH file the target will generate a corresponding doxygen tag
0044 file, which enables creating links from other documentation into the
0045 generated QCH file.
0046 
0047 It is recommended to make the use of this macro optional, by depending
0048 the call to ``ecm_add_qch`` on a CMake option being set, with a name like
0049 ``BUILD_QCH`` and being ``TRUE`` by default. This will allow the developers to
0050 saves resources on normal source development build cycles by setting this
0051 option to FALSE.
0052 
0053 The macro will set the target properties ``DOXYGEN_TAGFILE``, ``QHP_NAMESPACE``,
0054 ``QHP_NAMESPACE_VERSIONED``, ``QHP_VIRTUALFOLDER`` and ``LINK_QCHS`` to the respective
0055 values, to allow other code access to them, e.g. the macro
0056 ``ecm_install_qch_export``.
0057 To enable the use of the target <target_name> as item for ``LINK_QCHS``
0058 in further ``ecm_add_qch`` calls in the current build,
0059 additionally a target property ``DOXYGEN_TAGFILE_BUILD`` is set, with the path
0060 of the created doxygen tag file in the build dir.
0061 If existing, ``ecm_add_qch`` will use this property instead of
0062 ``DOXYGEN_TAGFILE`` for access to the tags file.
0063 
0064 ``NAME`` specifies the name for the generated documentation.
0065 
0066 ``VERSION`` specifies the version of the library for which the documentation is
0067 created.
0068 
0069 ``BASE_NAME`` specifies the base name for the generated files.
0070 The default basename is ``<name>``.
0071 
0072 ``SOURCE_DIRS`` specifies the dirs (incl. subdirs) with the source files for
0073 which the API documentation should be generated.  Dirs can be relative to
0074 the current source dir. Dependencies to the files in the dirs are not
0075 tracked currently, other than with the ``SOURCES`` argument. So do not use for
0076 sources generated during the build.
0077 Needs to be used when ``SOURCES`` or ``CONFIG_TEMPLATE`` are not used.
0078 
0079 ``SOURCES`` specifies the source files for which the API documentation should be
0080 generated.
0081 Needs to be used when ``SOURCE_DIRS`` or ``CONFIG_TEMPLATE`` are not used.
0082 
0083 ``MD_MAINPAGE`` specifies a file in Markdown format that should be used as main
0084 page. This page will overrule any ``\mainpage`` command in the included
0085 sources.
0086 
0087 ``INCLUDE_DIRS`` specifies the dirs which should be searched for included
0088 headers. Dirs can be relative to the current source dir. Since 5.63.
0089 
0090 ``IMAGE_DIRS`` specifies the dirs which contain images that are included in the
0091 documentation. Dirs can be relative to the current source dir.
0092 
0093 ``EXAMPLE_DIRS`` specifies the dirs which contain examples that are included in
0094 the documentation. Dirs can be relative to the current source dir.
0095 
0096 ``QCH_INSTALL_DESTINATION`` specifies where the generated QCH file will be
0097 installed.
0098 
0099 ``TAGFILE_INSTALL_DESTINATION`` specifies where the generated tag file will be
0100 installed.
0101 
0102 ``COMPONENT`` specifies the installation component name with which the install
0103 rules for the generated QCH file and tag file are associated.
0104 
0105 ``NAMESPACE`` can be used to set a custom namespace <namespace> of the generated
0106 QCH file. The namepspace is used as the unique id by QHelpEngine (cmp.
0107 https://doc.qt.io/qt-5/qthelpproject.html#namespace).
0108 The default namespace is ``<domain>.<name>``.
0109 Needs to be used when ``ORG_DOMAIN`` is not used.
0110 
0111 ``ORG_DOMAIN`` can be used to define the organization domain prefix for the
0112 default namespace of the generated QCH file.
0113 Needs to be used when ``NAMESPACE`` is not used.
0114 
0115 ``LINK_QCHS`` specifies a list of other QCH targets which should be used for
0116 creating references to API documentation of code in external libraries.
0117 For each target <qch> in the list these target properties are expected to be
0118 defined: ``DOXYGEN_TAGFILE``, ``QHP_NAMESPACE`` and ``QHP_VIRTUALFOLDER``.
0119 If any of these is not existing, <qch> will be ignored.
0120 Use the macro ``ecm_install_qch_export`` for exporting a target with these
0121 properties with the CMake config of a library.
0122 Any target <qch> can also be one created before in the same buildsystem by
0123 another call of ``ecm_add_qch``.
0124 
0125 ``PREDEFINED_MACROS`` specifies a list of C/C++ macros which should be handled as
0126 given by the API dox generation tool.
0127 Examples are macros only defined in generated files, so whose
0128 definition might be not available to the tool.
0129 
0130 ``BLANK_MACROS`` specifies a list of C/C++ macro names which should be ignored by
0131 the API dox generation tool and handled as if they resolve to empty strings.
0132 Examples are export macros only defined in generated files, so whose
0133 definition might be not available to the tool.
0134 
0135 ``CONFIG_TEMPLATE`` specifies a custom cmake template file for the config file
0136 that is created to control the execution of the API dox generation tool.
0137 The following CMake variables need to be used:
0138 - ``ECM_QCH_DOXYGEN_QHELPGENERATOR_EXECUTABLE``
0139 - ``ECM_QCH_DOXYGEN_FILEPATH, ECM_QCH_DOXYGEN_TAGFILE``
0140 The following CMake variables can be used:
0141 - ``ECM_QCH_DOXYGEN_PROJECTNAME``
0142 - ``ECM_QCH_DOXYGEN_PROJECTVERSION``
0143 - ``ECM_QCH_DOXYGEN_VIRTUALFOLDER``
0144 - ``ECM_QCH_DOXYGEN_FULLNAMESPACE``
0145 - ``ECM_QCH_DOXYGEN_TAGFILES``
0146 - ``ECM_QCH_DOXYGEN_WARN_LOGFILE``
0147 - ``ECM_QCH_DOXYGEN_QUIET``
0148 There is no guarantue that the other CMake variables currently used in the
0149 default config file template will also be present with the same semantics
0150 in future versions of this macro.
0151 
0152 ``VERBOSE`` tells the API dox generation tool to be more verbose about its
0153 activity.
0154 
0155 The default config file for the API dox generation tool, so the one when not
0156 using ``CONFIG_TEMPLATE``, allows code to handle the case of being processed by
0157 the tool by defining the C/C++ preprocessor macro ``K_DOXYGEN`` when run
0158 (since v5.67.0). For backward-compatibility also the definition
0159 ``DOXYGEN_SHOULD_SKIP_THIS`` is set, but its usage is deprecated.
0160 
0161 Example usage:
0162 
0163 .. code-block:: cmake
0164 
0165   ecm_add_qch(
0166       MyLib_QCH
0167       NAME MyLib
0168       VERSION "0.42.0"
0169       ORG_DOMAIN org.myorg
0170       SOURCE_DIRS
0171           src
0172       LINK_QCHS
0173           Qt5Core_QCH
0174           Qt5Xml_QCH
0175           Qt5Gui_QCH
0176           Qt5Widgets_QCH
0177       BLANK_MACROS
0178           MyLib_EXPORT
0179           MyLib_DEPRECATED
0180       TAGFILE_INSTALL_DESTINATION ${CMAKE_INSTALL_PREFIX}/share/docs/tags
0181       QCH_INSTALL_DESTINATION ${CMAKE_INSTALL_PREFIX}/share/docs/qch
0182       COMPONENT Devel
0183   )
0184 
0185 Example usage (with two QCH files, second linking first):
0186 
0187 .. code-block:: cmake
0188 
0189   ecm_add_qch(
0190       MyLib_QCH
0191       NAME MyLib
0192       VERSION ${MyLib_VERSION}
0193       ORG_DOMAIN org.myorg
0194       SOURCES ${MyLib_PUBLIC_HEADERS}
0195       MD_MAINPAGE src/mylib/README.md
0196       LINK_QCHS Qt5Core_QCH
0197       TAGFILE_INSTALL_DESTINATION ${CMAKE_INSTALL_PREFIX}/share/docs/tags
0198       QCH_INSTALL_DESTINATION ${CMAKE_INSTALL_PREFIX}/share/docs/qch
0199       COMPONENT Devel
0200   )
0201   ecm_add_qch(
0202       MyOtherLib_QCH
0203       NAME MyOtherLib
0204       VERSION ${MyOtherLib_VERSION}
0205       ORG_DOMAIN org.myorg
0206       SOURCES ${MyOtherLib_PUBLIC_HEADERS}
0207       MD_MAINPAGE src/myotherlib/README.md
0208       LINK_QCHS Qt5Core_QCH MyLib_QCH
0209       TAGFILE_INSTALL_DESTINATION ${CMAKE_INSTALL_PREFIX}/share/docs/tags
0210       QCH_INSTALL_DESTINATION ${CMAKE_INSTALL_PREFIX}/share/docs/qch
0211       COMPONENT Devel
0212   )
0213 
0214 ::
0215 
0216   ecm_install_qch_export(
0217       TARGETS [<name> [<name2> [...]]]
0218       FILE <file>
0219       DESTINATION <dest>
0220       [COMPONENT <component>]
0221   )
0222 
0223 This macro creates and installs a CMake file <file> which exports the given
0224 QCH targets <name> etc., so they can be picked up by CMake-based builds of
0225 other software that also generate QCH files (using ``ecm_add_qch``) and
0226 which should include links to the QCH files created by the given targets.
0227 The installed CMake file <file> is expected to be included by the CMake
0228 config file created for the software the related QCH files are documenting.
0229 
0230 ``TARGETS`` specifies the QCH targets which should be exported. If a target does
0231 not exist or does not have all needed properties, a warning will be
0232 generated and the target skipped.
0233 This behaviour might change in future versions to result in a fail instead.
0234 
0235 ``FILE`` specifies the name of the created CMake file, typically with a .cmake
0236 extension.
0237 
0238 ``DESTINATION`` specifies the directory on disk to which the file will be
0239 installed. It usually is the same as the one where the CMake config files
0240 for this software are installed.
0241 
0242 ``COMPONENT`` specifies the installation component name with which the
0243 install rule is associated.
0244 
0245 Example usage:
0246 
0247 .. code-block:: cmake
0248 
0249   ecm_install_qch_export(
0250       TARGETS MyLib_QCH
0251       FILE MyLibQCHTargets.cmake
0252       DESTINATION "${CMAKE_INSTALL_PREFIX}/lib/cmake/MyLib"
0253       COMPONENT Devel
0254   )
0255 
0256 Since 5.36.0.
0257 #]=======================================================================]
0258 
0259 include(${CMAKE_CURRENT_LIST_DIR}/../modules/QtVersionOption.cmake)
0260 include(ECMQueryQt)
0261 
0262 
0263 # Helper method: adding the LINK_QCHS property to a Qt QCH targets, from module base names ("Core" etc.)
0264 # if target does not exist (e.g. because no tagsfile was found), this is a no-op
0265 macro(_ecm_setup_qt_qch_links _module)
0266     set(_target "Qt${QT_MAJOR_VERSION}${_module}_QCH")
0267     if(TARGET ${_target})
0268         set(_linkqchs)
0269         foreach(_linkqch ${ARGN})
0270             list(APPEND _linkqchs "Qt${QT_MAJOR_VERSION}${_linkqch}_QCH")
0271         endforeach()
0272         set_property(TARGET ${_target} PROPERTY LINK_QCHS ${_linkqchs})
0273     endif()
0274 endmacro()
0275 
0276 # Helper method: ensure Qt QCH targets are created
0277 function(_ecm_ensure_qt_qch_targets)
0278     # create QCH targets for Qt
0279     # Ideally one day Qt CMake Config files provide these
0280     if(NOT TARGET Qt${QT_MAJOR_VERSION}Core_QCH)
0281         # get Qt version, if any
0282         find_package(Qt${QT_MAJOR_VERSION}Core CONFIG QUIET)
0283         # lookup tag files
0284         ecm_query_qt(qt_docs_dir QT_INSTALL_DOCS TRY)
0285         find_path(_qtcoreTagsPath qtcore/qtcore.tags
0286             PATHS
0287                 ${qt_docs_dir}
0288         )
0289 
0290         if(Qt${QT_MAJOR_VERSION}Core_FOUND AND _qtcoreTagsPath)
0291             string(REPLACE "." "" _version ${Qt${QT_MAJOR_VERSION}Core_VERSION})
0292             # TODO: properly find each tag file
0293             # TODO: complete list of Qt modules
0294             if (QT_MAJOR_VERSION EQUAL "6")
0295                 set(_module_list
0296                     3D Bluetooth Concurrent Core DBus Gui Location
0297                     Network Nfc Pdf Positioning PrintSupport Qml Quick
0298                     Sensors SerialBus SerialPort Sql StateMachine Svg
0299                     Test TextToSpeech WebChannel WebEngine WebSockets Widgets Xml)
0300             else()
0301                 set(_module_list
0302                     3D Bluetooth Concurrent Core DBus Gui Location
0303                     Network Positioning PrintSupport Qml Quick
0304                     Sensors SerialPort Sql Svg
0305                     WebChannel WebEngine WebSockets Widgets Xml XmlPatterns)
0306             endif()
0307             foreach(_module ${_module_list})
0308                 string(TOLOWER ${_module} _lowermodule)
0309 
0310                 set(_tagfile "${_qtcoreTagsPath}/qt${_lowermodule}/qt${_lowermodule}.tags")
0311                 if(EXISTS "${_tagfile}")
0312                     add_custom_target(Qt${QT_MAJOR_VERSION}${_module}_QCH)
0313                     set_target_properties(Qt${QT_MAJOR_VERSION}${_module}_QCH PROPERTIES
0314                         DOXYGEN_TAGFILE         "${_tagfile}"
0315                         QHP_NAMESPACE           "org.qt-project.qt${_lowermodule}"
0316                         QHP_NAMESPACE_VERSIONED "org.qt-project.qt${_lowermodule}.${_version}"
0317                         QHP_VIRTUALFOLDER       "qt${_lowermodule}"
0318                         IMPORTED TRUE
0319                     )
0320                 endif()
0321             endforeach()
0322             _ecm_setup_qt_qch_links(3D           Gui Core)
0323             _ecm_setup_qt_qch_links(Bluetooth    DBus Core)
0324             _ecm_setup_qt_qch_links(Concurrent   Gui Core)
0325             _ecm_setup_qt_qch_links(DBus         Core)
0326             _ecm_setup_qt_qch_links(Gui          Core)
0327             _ecm_setup_qt_qch_links(Location     Positioning Gui Core)
0328             _ecm_setup_qt_qch_links(Network      Core)
0329             if (QT_MAJOR_VERSION EQUAL "6")
0330                 _ecm_setup_qt_qch_links(Nfc      Core)
0331                 _ecm_setup_qt_qch_links(Pdf      Gui Core)
0332             endif()
0333             _ecm_setup_qt_qch_links(Positioning  Core)
0334             _ecm_setup_qt_qch_links(PrintSupport Widgets Gui Core)
0335             _ecm_setup_qt_qch_links(Qml          Network Core)
0336             _ecm_setup_qt_qch_links(Quick        Qml Network Gui Core)
0337             _ecm_setup_qt_qch_links(Sensors      Core)
0338             if (QT_MAJOR_VERSION EQUAL "6")
0339                 _ecm_setup_qt_qch_links(SerialBus   Core)
0340             endif()
0341             _ecm_setup_qt_qch_links(SerialPort   Core)
0342             _ecm_setup_qt_qch_links(Sql          Core)
0343             if (QT_MAJOR_VERSION EQUAL "6")
0344                 _ecm_setup_qt_qch_links(StateMachine   Core)
0345             endif()
0346             _ecm_setup_qt_qch_links(Svg          Widgets Gui Core)
0347             _ecm_setup_qt_qch_links(Test         Core)
0348             if (QT_MAJOR_VERSION EQUAL "6")
0349                 _ecm_setup_qt_qch_links(TextToSpeech   Core)
0350             endif()
0351             _ecm_setup_qt_qch_links(WebChannel   Qml Core)
0352             _ecm_setup_qt_qch_links(WebEngine    Quick Qml Gui Core)
0353             _ecm_setup_qt_qch_links(WebSockets   Network Core)
0354             _ecm_setup_qt_qch_links(Widgets      Gui Core)
0355             _ecm_setup_qt_qch_links(Xml          Core)
0356             if (QT_MAJOR_VERSION EQUAL "5")
0357                 _ecm_setup_qt_qch_links(XmlPatterns  Network Core)
0358             endif()
0359         endif()
0360     endif()
0361 endfunction()
0362 
0363 # Helper method: collect all qch targets from the LINK_QCHS dependency tree and set result to <var>
0364 function(_ecm_collect_linkable_qch_targets name)
0365     set(_candidate_qchs ${ARGN})
0366     set(_handled_qchs)
0367     set(_good_qchs)
0368     # while unhandled qch targets
0369     while(_candidate_qchs)
0370         # get another unhandled qch target
0371         list(GET _candidate_qchs 0 _qch)
0372         list(REMOVE_AT _candidate_qchs 0)
0373         list(FIND _handled_qchs ${_qch} _index)
0374         # if not already handled
0375         if(_index EQUAL -1)
0376             list(APPEND _handled_qchs ${_qch})
0377             if(TARGET ${_qch})
0378                 # always look at other linked qch targets, also for incomplete targets
0379                 get_property(_link_qchs TARGET ${_qch} PROPERTY LINK_QCHS)
0380                 if(_link_qchs)
0381                     list(APPEND _candidate_qchs ${_link_qchs})
0382                 endif()
0383                 # check if this target has all needed properties
0384                 set(_target_usable TRUE)
0385                 foreach(_propertyname
0386                     DOXYGEN_TAGFILE
0387                     QHP_NAMESPACE
0388                     QHP_VIRTUALFOLDER
0389                 )
0390                     get_target_property(_property ${_qch} ${_propertyname})
0391                     if(NOT _property)
0392                         message(STATUS "No property ${_propertyname} set on ${_qch} when calling ecm_add_qch(). <<${_property}>>")
0393                         set(_target_usable FALSE)
0394                     endif()
0395                 endforeach()
0396                 get_target_property(_tagfile_build ${_qch} DOXYGEN_TAGFILE_BUILD)
0397                 if (NOT _tagfile_build)
0398                     get_target_property(_tagfile ${_qch} DOXYGEN_TAGFILE)
0399                     if(NOT EXISTS ${_tagfile})
0400                         message(STATUS "No such tag file \"${_tagfile}\" found for ${_qch} when calling ecm_add_qch().")
0401                         set(_target_usable FALSE)
0402                     endif()
0403                 endif()
0404                 if(_target_usable)
0405                     list(APPEND _good_qchs ${_qch})
0406                 else()
0407                     message(WARNING "No linking to API dox of ${_qch}.")
0408                 endif()
0409             else()
0410                 message(STATUS "No such target ${_qch} defined when calling ecm_add_qch(), ignored.")
0411             endif()
0412         endif()
0413     endwhile()
0414     set(${name} ${_good_qchs} PARENT_SCOPE)
0415 endfunction()
0416 
0417 
0418 function(ecm_add_qch target_name)
0419     # Parse arguments
0420     set(options VERBOSE)
0421     set(oneValueArgs NAME BASE_NAME QCH_INSTALL_DESTINATION TAGFILE_INSTALL_DESTINATION COMPONENT VERSION NAMESPACE MD_MAINPAGE ORG_DOMAIN CONFIG_TEMPLATE)
0422     set(multiValueArgs SOURCE_DIRS SOURCES INCLUDE_DIRS IMAGE_DIRS EXAMPLE_DIRS PREDEFINED_MACROS BLANK_MACROS LINK_QCHS)
0423     cmake_parse_arguments(ARGS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
0424 
0425     # check required args
0426     foreach(_arg_name NAME QCH_INSTALL_DESTINATION TAGFILE_INSTALL_DESTINATION VERSION)
0427         if(NOT DEFINED ARGS_${_arg_name})
0428             message(FATAL_ERROR "${_arg_name} needs to be defined when calling ecm_add_qch")
0429         endif()
0430     endforeach()
0431     if(NOT DEFINED ARGS_SOURCE_DIRS AND NOT DEFINED ARGS_SOURCES AND NOT DEFINED ARGS_CONFIG_TEMPLATE)
0432         message(FATAL_ERROR "SOURCE_DIRS or SOURCES needs to be defined when calling ecm_add_qch")
0433     endif()
0434     if(DEFINED ARGS_SOURCE_DIRS AND DEFINED ARGS_SOURCES)
0435         message(FATAL_ERROR "Either SOURCE_DIRS or SOURCES, not both, needs to be defined when calling ecm_add_qch")
0436     endif()
0437     if(NOT DEFINED ARGS_ORG_DOMAIN AND NOT DEFINED ARGS_NAMESPACE)
0438         message(FATAL_ERROR "ORG_DOMAIN or NAMESPACE needs to be defined when calling ecm_add_qch")
0439     endif()
0440 
0441     # find required tools
0442     if (NOT DOXYGEN_PATCHED_JSFILESADDED)
0443         set(REQUIRED_DOXYGEN_VERSION 1.8.13)
0444     endif()
0445     find_package(Doxygen ${REQUIRED_DOXYGEN_VERSION} REQUIRED)
0446     if (NOT DOXYGEN_FOUND AND NOT DOXYGEN_PATCHED_JSFILESADDED)
0447         set(doxygen_description_addition " (Or older version patched with https://github.com/doxygen/doxygen/commit/bf9415698e53d79b, pass -DDOXYGEN_PATCHED_JSFILESADDED=ON to cmake if patched)")
0448     endif()
0449     set_package_properties(Doxygen PROPERTIES
0450         TYPE REQUIRED
0451         PURPOSE "Needed for API dox QCH file generation${doxygen_description_addition}"
0452     )
0453 
0454     if (QT_MAJOR_VERSION EQUAL "5")
0455         find_package(QHelpGenerator REQUIRED)
0456         set_package_properties(QHelpGenerator PROPERTIES
0457             TYPE REQUIRED
0458             PURPOSE "Needed for API dox QCH file generation"
0459             DESCRIPTION "Part of Qt5 tools"
0460         )
0461     else()
0462         find_package(Qt6 COMPONENTS ToolsTools CONFIG REQUIRED)
0463         set_package_properties(Qt6ToolsTools PROPERTIES
0464             TYPE REQUIRED
0465             PURPOSE "Needed for API dox QCH file generation"
0466             DESCRIPTION "qhelpgenerator from Qt6 tools"
0467         )
0468         if(TARGET Qt6::qhelpgenerator)
0469             get_target_property(QHelpGenerator_EXECUTABLE Qt6::qhelpgenerator LOCATION)
0470         endif()
0471     endif()
0472 
0473     set(_missing_tools)
0474     if (NOT DOXYGEN_FOUND)
0475         list(APPEND _missing_tools "Doxygen")
0476     endif()
0477     if (NOT QHelpGenerator_FOUND AND NOT TARGET Qt6::qhelpgenerator)
0478         list(APPEND _missing_tools "qhelpgenerator")
0479     endif()
0480 
0481     if (_missing_tools)
0482         message(WARNING "API dox QCH file will not be generated, tools missing: ${_missing_tools}!")
0483     else()
0484         _ecm_ensure_qt_qch_targets()
0485 
0486         # prepare base dirs, working file names and other vars
0487         if (DEFINED ARGS_BASE_NAME)
0488             set(_basename ${ARGS_BASE_NAME})
0489         else()
0490             set(_basename ${ARGS_NAME})
0491         endif()
0492         set(_qch_file_basename "${_basename}.qch")
0493         set(_tags_file_basename "${_basename}.tags")
0494         set(_qch_buildpath "${CMAKE_CURRENT_BINARY_DIR}/${_qch_file_basename}")
0495         set(_tags_buildpath "${CMAKE_CURRENT_BINARY_DIR}/${_tags_file_basename}")
0496         set(_apidox_builddir "${CMAKE_CURRENT_BINARY_DIR}/${_basename}_ECMQchDoxygen")
0497         if (DEFINED ARGS_NAMESPACE)
0498             set(_namespace "${ARGS_NAMESPACE}")
0499         else()
0500             set(_namespace "${ARGS_ORG_DOMAIN}.${ARGS_NAME}")
0501         endif()
0502         string(REPLACE "." "_" _dotLessVersion ${ARGS_VERSION})
0503         set(_versioned_namespace "${_namespace}.${_dotLessVersion}")
0504         set(_sources)
0505         set(_dep_tagfiles)
0506         set(_dep_qch_targets)
0507 
0508         ### Create doxygen config file
0509         set(_doxygenconfig_file "${CMAKE_CURRENT_BINARY_DIR}/${_basename}_ECMQchDoxygen.config")
0510         if (DEFINED ARGS_CONFIG_TEMPLATE)
0511             set(_doxygenconfig_template_file "${ARGS_CONFIG_TEMPLATE}")
0512         else()
0513             set(_doxygenconfig_template_file "${ECM_MODULE_DIR}/ECMQchDoxygen.config.in")
0514         endif()
0515         set(_doxygen_layout_file "${ECM_MODULE_DIR}/ECMQchDoxygenLayout.xml")
0516         # Setup variables used in config file template, ECM_QCH_DOXYGEN_*
0517         set(ECM_QCH_DOXYGEN_OUTPUTDIR "\"${_apidox_builddir}\"")
0518         set(ECM_QCH_DOXYGEN_TAGFILE "\"${_tags_buildpath}\"")
0519         set(ECM_QCH_DOXYGEN_LAYOUTFILE "\"${_doxygen_layout_file}\"")
0520         set(ECM_QCH_DOXYGEN_INCLUDE_PATH)
0521         foreach(_include_DIR IN LISTS ARGS_INCLUDE_DIRS)
0522             if (NOT IS_ABSOLUTE ${_include_DIR})
0523                 set(_include_DIR "${CMAKE_CURRENT_SOURCE_DIR}/${_include_DIR}")
0524             endif()
0525             # concat dirs separated by a break, it is no issue that first has also a leading break
0526             set(ECM_QCH_DOXYGEN_INCLUDE_PATH "${ECM_QCH_DOXYGEN_INCLUDE_PATH} \\\n\"${_include_DIR}\"")
0527         endforeach()
0528         set(ECM_QCH_DOXYGEN_IMAGEDIRS)
0529         foreach(_image_DIR IN LISTS ARGS_IMAGE_DIRS)
0530             if (NOT IS_ABSOLUTE ${_image_DIR})
0531                 set(_image_DIR "${CMAKE_CURRENT_SOURCE_DIR}/${_image_DIR}")
0532             endif()
0533             # concat dirs separated by a break, it is no issue that first has also a leading break
0534             set(ECM_QCH_DOXYGEN_IMAGEDIRS "${ECM_QCH_DOXYGEN_IMAGEDIRS} \\\n\"${_image_DIR}\"")
0535         endforeach()
0536         set(ECM_QCH_DOXYGEN_EXAMPLEDIRS)
0537         foreach(_example_DIR IN LISTS ARGS_EXAMPLE_DIRS)
0538             if (NOT IS_ABSOLUTE ${_example_DIR})
0539                 set(_example_DIR "${CMAKE_CURRENT_SOURCE_DIR}/${_example_DIR}")
0540             endif()
0541             # concat dirs separated by a break, it is no issue that first has also a leading break
0542             set(ECM_QCH_DOXYGEN_EXAMPLEDIRS "${ECM_QCH_DOXYGEN_EXAMPLEDIRS} \\\n\"${_example_DIR}\"")
0543         endforeach()
0544         if (ARGS_MD_MAINPAGE)
0545             if (NOT IS_ABSOLUTE ${ARGS_MD_MAINPAGE})
0546                 set(ARGS_MD_MAINPAGE "${CMAKE_CURRENT_SOURCE_DIR}/${ARGS_MD_MAINPAGE}")
0547             endif()
0548             set(ECM_QCH_DOXYGEN_MAINPAGE_MDFILE "\"${ARGS_MD_MAINPAGE}\"")
0549         else()
0550             set(ECM_QCH_DOXYGEN_MAINPAGE_MDFILE)
0551         endif()
0552         set(ECM_QCH_DOXYGEN_INPUT)
0553         if (ARGS_SOURCE_DIRS)
0554             foreach(_source_DIR IN LISTS ARGS_SOURCE_DIRS)
0555                 if (NOT IS_ABSOLUTE ${_source_DIR})
0556                     set(_source_DIR "${CMAKE_CURRENT_SOURCE_DIR}/${_source_DIR}")
0557                 endif()
0558                 # concat dirs separated by a break, it is no issue that first has also a leading break
0559                 set(ECM_QCH_DOXYGEN_INPUT "${ECM_QCH_DOXYGEN_INPUT} \\\n\"${_source_DIR}\"")
0560             endforeach()
0561             if (ARGS_MD_MAINPAGE)
0562                 set(ECM_QCH_DOXYGEN_INPUT "${ECM_QCH_DOXYGEN_INPUT} \\\n\"${ARGS_MD_MAINPAGE}\"")
0563             endif()
0564             set(ECM_QCH_DOXYGEN_FILE_PATTERNS "*.h *.cpp *.hpp *.hh *.cc *.h++ *.c++ *.hxx *.cxx *.dox *.md")
0565         else()
0566             foreach(_source IN LISTS ARGS_SOURCES)
0567                 if (NOT IS_ABSOLUTE ${_source})
0568                     set(_source "${CMAKE_CURRENT_SOURCE_DIR}/${_source}")
0569                 endif()
0570                 list(APPEND _sources "${_source}")
0571             endforeach()
0572             if (ARGS_MD_MAINPAGE)
0573                 list(FIND _sources ${ARGS_MD_MAINPAGE} _mainpage_index)
0574                 if (_mainpage_index STREQUAL -1)
0575                     list(APPEND _sources "${ARGS_MD_MAINPAGE}")
0576                 endif()
0577             endif()
0578             foreach(_source IN LISTS _sources)
0579                 # concat sources separated by a break, it is no issue that first has also a leading break
0580                 set(ECM_QCH_DOXYGEN_INPUT "${ECM_QCH_DOXYGEN_INPUT} \\\n\"${_source}\"")
0581             endforeach()
0582             set(ECM_QCH_DOXYGEN_FILE_PATTERNS "")
0583         endif()
0584 
0585         set(ECM_QCH_DOXYGEN_PROJECTNAME ${ARGS_NAME})
0586         file(RELATIVE_PATH _builddirrelative_filepath "${_apidox_builddir}/html"  ${_qch_buildpath})
0587         set(ECM_QCH_DOXYGEN_FILEPATH "\"${_builddirrelative_filepath}\"")
0588         set(ECM_QCH_DOXYGEN_PROJECTVERSION ${ARGS_VERSION})
0589         string(TOLOWER ${ARGS_NAME} ECM_QCH_DOXYGEN_VIRTUALFOLDER)
0590         set(ECM_QCH_DOXYGEN_FULLNAMESPACE ${_versioned_namespace})
0591         set(ECM_QCH_DOXYGEN_PREDEFINED_MACROS)
0592         foreach(_macro IN LISTS ARGS_PREDEFINED_MACROS)
0593             # concat dirs separated by a break, it is no issue that first has also a leading break
0594             # wrap each macro in quotes, to handle potential blanks and commas
0595             string(REPLACE "\"" "\\\"" _macro "${_macro}")
0596             set(ECM_QCH_DOXYGEN_PREDEFINED_MACROS "${ECM_QCH_DOXYGEN_PREDEFINED_MACROS} \\\n\"${_macro}\"")
0597         endforeach()
0598         set(ECM_QCH_DOXYGEN_BLANK_MACROS)
0599         foreach(_macro IN LISTS ARGS_BLANK_MACROS)
0600             # concat dirs separated by a break, it is no issue that first has also a leading break
0601             # wrap each macro in quotes, to handle potential blanks and commas
0602             string(REPLACE "\"" "\\\"" _macro "${_macro}")
0603             set(ECM_QCH_DOXYGEN_BLANK_MACROS "${ECM_QCH_DOXYGEN_BLANK_MACROS} \\\n\"${_macro}=\"")
0604         endforeach()
0605 
0606         # create list of tag files for linking other QCH files
0607         set(ECM_QCH_DOXYGEN_TAGFILES)
0608         _ecm_collect_linkable_qch_targets(_link_qchs ${ARGS_LINK_QCHS})
0609         foreach(_link_qch IN LISTS _link_qchs)
0610             list(APPEND _dep_qch_targets ${_link_qch})
0611             get_target_property(_link_qch_tagfile ${_link_qch} DOXYGEN_TAGFILE)
0612             get_target_property(_link_qch_tagfile_build ${_link_qch} DOXYGEN_TAGFILE_BUILD)
0613             get_target_property(_link_qch_namespace ${_link_qch} QHP_NAMESPACE)
0614             get_target_property(_link_qch_virtualfolder ${_link_qch} QHP_VIRTUALFOLDER)
0615             # if same build, then prefer build version over any installed one
0616             if (_link_qch_tagfile_build)
0617                 set(_link_qch_tagfile ${_link_qch_tagfile_build})
0618                 list(APPEND _dep_tagfiles "${_link_qch_tagfile}")
0619             endif()
0620             get_property(_linkqchs TARGET ${_link_qch} PROPERTY LINK_QCHS)
0621             set(_tagfile_entry "\"${_link_qch_tagfile}=qthelp://${_link_qch_namespace}/${_link_qch_virtualfolder}/\"")
0622             # concat dirs separated by a break, it is no issue that first has also a leading break
0623             set(ECM_QCH_DOXYGEN_TAGFILES "${ECM_QCH_DOXYGEN_TAGFILES} \\\n${_tagfile_entry}")
0624         endforeach()
0625 
0626         set(ECM_QCH_DOXYGEN_WARN_LOGFILE "\"${_doxygenconfig_file}.log\"")
0627         if(ARGS_VERBOSE)
0628             set(ECM_QCH_DOXYGEN_QUIET "NO")
0629         else()
0630             set(ECM_QCH_DOXYGEN_QUIET "YES")
0631         endif()
0632         set(ECM_QCH_DOXYGEN_QHELPGENERATOR_EXECUTABLE ${QHelpGenerator_EXECUTABLE})
0633 
0634         # finally create doxygen config file
0635         configure_file(
0636             "${_doxygenconfig_template_file}"
0637             "${_doxygenconfig_file}"
0638             @ONLY
0639         )
0640         # Doxygen warns verbosely about outdated config entries.
0641         # To spare custom code here to generate configuration with no out-dated entries,
0642         # instead make use of the doxygen feature to update configuration files.
0643         execute_process(
0644             COMMAND ${DOXYGEN_EXECUTABLE} -u "${_doxygenconfig_file}"
0645             ERROR_VARIABLE _doxygen_update_error
0646             RESULT_VARIABLE _doxygen_update_result
0647         )
0648         if(NOT ${_doxygen_update_result} STREQUAL "0")
0649             message(WARNING "Updating the doxygen config file failed: ${_doxygen_update_error}")
0650         endif()
0651 
0652         # setup make target
0653         set(_qch_INSTALLPATH ${ARGS_QCH_INSTALL_DESTINATION})
0654         set(_tags_INSTALLPATH ${ARGS_TAGFILE_INSTALL_DESTINATION})
0655         file(RELATIVE_PATH _relative_qch_file ${CMAKE_BINARY_DIR}  ${_qch_buildpath})
0656         file(RELATIVE_PATH _relative_tags_file ${CMAKE_BINARY_DIR}  ${_tags_buildpath})
0657         add_custom_command(
0658             OUTPUT ${_qch_buildpath} ${_tags_buildpath}
0659             COMMENT "Generating ${_relative_qch_file}, ${_relative_tags_file}"
0660             COMMAND cmake -E remove_directory "${ECM_QCH_DOXYGEN_OUTPUTDIR}"
0661             COMMAND cmake -E make_directory "${ECM_QCH_DOXYGEN_OUTPUTDIR}"
0662             COMMAND ${DOXYGEN_EXECUTABLE} "${_doxygenconfig_file}"
0663             DEPENDS
0664                 ${_doxygenconfig_file}
0665                 ${_doxygen_layout_file}
0666                 ${_sources}
0667                 ${_dep_tagfiles}
0668                 ${_dep_qch_targets}
0669         )
0670         add_custom_target(${target_name} ALL DEPENDS ${_qch_buildpath} ${_tags_buildpath})
0671         set_target_properties(${target_name} PROPERTIES
0672             DOXYGEN_TAGFILE "${_qch_INSTALLPATH}/${_tags_file_basename}"
0673             DOXYGEN_TAGFILE_NAME "${_tags_file_basename}"
0674             DOXYGEN_TAGFILE_INSTALLDIR "${_qch_INSTALLPATH}"
0675             DOXYGEN_TAGFILE_BUILD "${_tags_buildpath}"
0676             QHP_NAMESPACE "${_namespace}"
0677             QHP_NAMESPACE_VERSIONED  "${_versioned_namespace}"
0678             QHP_VIRTUALFOLDER "${ECM_QCH_DOXYGEN_VIRTUALFOLDER}"
0679         )
0680         # list as value does not work with set_target_properties
0681         set_property(TARGET ${target_name} PROPERTY LINK_QCHS "${ARGS_LINK_QCHS}")
0682 
0683         if (DEFINED ARGS_COMPONENT)
0684             set(_component COMPONENT ${ARGS_COMPONENT})
0685         else()
0686             set(_component)
0687         endif()
0688 
0689         # setup installation
0690         install(FILES
0691             ${_qch_buildpath}
0692             DESTINATION ${_qch_INSTALLPATH}
0693             ${_component}
0694         )
0695 
0696         install(FILES
0697             ${_tags_buildpath}
0698             DESTINATION ${_tags_INSTALLPATH}
0699             ${_component}
0700         )
0701     endif()
0702 
0703 endfunction()
0704 
0705 
0706 function(ecm_install_qch_export)
0707     set(options )
0708     set(oneValueArgs FILE DESTINATION COMPONENT)
0709     set(multiValueArgs TARGETS)
0710 
0711     cmake_parse_arguments(ARGS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
0712 
0713     if(NOT DEFINED ARGS_FILE)
0714         message(FATAL_ERROR "FILE needs to be defined when calling ecm_install_qch_export().")
0715     endif()
0716 
0717     if(NOT DEFINED ARGS_DESTINATION)
0718         message(FATAL_ERROR "DESTINATION needs to be defined when calling ecm_install_qch_export().")
0719     endif()
0720 
0721     # TARGETS may be empty (and ARGS_TARGETS will not be defined then by cmake_parse_arguments)
0722 
0723     set(_content
0724 "# This file was generated by ecm_install_qch_export(). DO NOT EDIT!
0725 "
0726     )
0727 
0728     foreach(_target IN LISTS ARGS_TARGETS)
0729         set(_target_usable TRUE)
0730 
0731         if (NOT TARGET ${_target})
0732             message(STATUS "No such target ${_target} when calling ecm_install_qch_export().")
0733             set(_target_usable FALSE)
0734         else()
0735             foreach(_propertyname
0736                 DOXYGEN_TAGFILE_NAME
0737                 DOXYGEN_TAGFILE_INSTALLDIR
0738                 QHP_NAMESPACE
0739                 QHP_NAMESPACE_VERSIONED
0740                 QHP_VIRTUALFOLDER
0741             )
0742                 get_target_property(_property ${_target} ${_propertyname})
0743                 if(NOT _property)
0744                     message(STATUS "No property ${_propertyname} set on ${_target} when calling ecm_install_qch_export(). <${_property}>")
0745                     set(_target_usable FALSE)
0746                 endif()
0747             endforeach()
0748         endif()
0749         if(_target_usable)
0750             get_target_property(_tagfile_name ${_target} DOXYGEN_TAGFILE_NAME)
0751             get_target_property(_tagfile_installdir ${_target} DOXYGEN_TAGFILE_INSTALLDIR)
0752             if (NOT IS_ABSOLUTE ${_tagfile_installdir})
0753                 set(_tagfile_installdir "${CMAKE_INSTALL_PREFIX}/${_tagfile_installdir}")
0754             endif()
0755             get_target_property(_namespace ${_target} QHP_NAMESPACE)
0756             get_target_property(_namespace_versioned ${_target} QHP_NAMESPACE_VERSIONED)
0757             get_target_property(_virtualfolder ${_target} QHP_VIRTUALFOLDER)
0758             get_property(_linkqchs TARGET ${_target} PROPERTY LINK_QCHS)
0759             set(_content "${_content}
0760 if (NOT TARGET ${_target})
0761 
0762 add_custom_target(${_target})
0763 set_target_properties(${_target} PROPERTIES
0764     DOXYGEN_TAGFILE \"${_tagfile_installdir}/${_tagfile_name}\"
0765     QHP_NAMESPACE \"${_namespace}\"
0766     QHP_NAMESPACE_VERSIONED \"${_namespace_versioned}\"
0767     QHP_VIRTUALFOLDER \"${_virtualfolder}\"
0768     IMPORTED TRUE
0769 )
0770 set_property(TARGET ${_target} PROPERTY LINK_QCHS ${_linkqchs})
0771 
0772 endif()
0773 "
0774             )
0775         else()
0776             message(STATUS "No target exported for ${_target}.")
0777         endif()
0778     endforeach()
0779 
0780     if (NOT IS_ABSOLUTE ${ARGS_FILE})
0781         set(ARGS_FILE "${CMAKE_CURRENT_BINARY_DIR}/${ARGS_FILE}")
0782     endif()
0783 
0784     file(GENERATE
0785         OUTPUT "${ARGS_FILE}"
0786         CONTENT "${_content}"
0787     )
0788 
0789     if (DEFINED ARGS_COMPONENT)
0790         set(_component COMPONENT ${ARGS_COMPONENT})
0791     else()
0792         set(_component)
0793     endif()
0794     install(
0795         FILES "${ARGS_FILE}"
0796         DESTINATION "${ARGS_DESTINATION}"
0797         ${_component}
0798     )
0799 
0800 endfunction()