Changeset View
Changeset View
Standalone View
Standalone View
modules/ECMAddQch.cmake
- This file was added.
1 | #.rst: | ||||
---|---|---|---|---|---|
2 | # ECMAddQch | ||||
3 | # ------------------ | ||||
4 | # | ||||
5 | # This module provides the ``ecm_add_qch`` function for generating API | ||||
6 | # documentation files in the QCH format, and the ``ecm_install_qch_export`` | ||||
7 | # function for generating and installing exported CMake targets for such | ||||
8 | # generated QCH files to enable builds of other software with generation of | ||||
9 | # QCH files to create links into the given QCH files. | ||||
10 | # | ||||
11 | # :: | ||||
12 | # | ||||
13 | # ecm_add_qch(<target_name> | ||||
14 | # NAME <name> | ||||
15 | # VERSION <version> | ||||
16 | # QCH_INSTALL_DESTINATION <qchfile_install_path> | ||||
17 | # TAGFILE_INSTALL_DESTINATION <tagsfile_install_path> | ||||
18 | # [COMPONENT <component>] | ||||
19 | # [BASE_NAME <basename>] | ||||
20 | # [SOURCE_DIRS <dir> [<dir2> [...]]] | ||||
21 | # [SOURCES <file> [<file2> [...]]] | ||||
22 | # |MD_MAINPAGE <md_file>] | ||||
23 | # [IMAGE_DIRS <idir> [<idir2> [...]]] | ||||
24 | # [EXAMPLE_DIRS <edir> [<edir2> [...]]] | ||||
25 | # [ORG_DOMAIN <domain>] | ||||
26 | # [NAMESPACE <namespace>] | ||||
27 | # [LINK_QCHS <qch> [<qch2> [...]]] | ||||
28 | # [PREDEFINED_MACROS <macro[=content]> [<macro2[=content]> [...]]] | ||||
29 | # [BLANK_MACROS <macro> [<macro2> [...]]] | ||||
30 | # [CONFIG_TEMPLATE <configtemplate_file>] | ||||
31 | # [VERBOSE] | ||||
32 | # ) | ||||
33 | # | ||||
34 | # This macro adds a target called <target_name> for the creation of an API | ||||
35 | # documentation manual in the QCH format from the given sources. | ||||
36 | # It currently uses doxygen, future versions might optionally also allow other | ||||
37 | # tools. | ||||
38 | # Next to the QCH file the target will generate a corresponding doxygen tag | ||||
39 | # file, which enables creating links from other documentation into the | ||||
40 | # generated QCH file. | ||||
41 | # | ||||
42 | # If the required tools are not found, the macro will skip creation of the | ||||
43 | # target and only emit a warning, so the use of the macro can be introduced | ||||
44 | # without requiring anyone to also have the needed tools present at that time. | ||||
45 | # This behaviour might change in future versions to result in a fail instead. | ||||
46 | # It is recommended to make the use of this macro optional, by depending | ||||
47 | # the call to ``ecm_add_qch`` on a CMake option being set, with a name like | ||||
48 | # ``BUILD_QCH`` and being TRUE by default. This will allow the developers to | ||||
49 | # saves resources on normal source development build cycles by setting this | ||||
50 | # option to FALSE. | ||||
51 | # | ||||
52 | # The macro will set the target properties DOXYGEN_TAGFILE, QHP_NAMESPACE, | ||||
53 | # QHP_NAMESPACE_VERSIONED, QHP_VIRTUALFOLDER and LINK_QCHS to the respective | ||||
54 | # values, to allow other code access to them, e.g. the macro | ||||
55 | # ``ecm_install_qch_export``. | ||||
56 | # To enable the use of the target <target_name> as item for LINK_QCHS | ||||
57 | # in further ``ecm_add_qch`` calls in the current build, | ||||
58 | # additionally a target property DOXYGEN_TAGFILE_BUILD is set, with the path | ||||
59 | # of the created doxygen tag file in the build dir. | ||||
60 | # If existing, ``ecm_add_qch`` will use this property instead of | ||||
61 | # DOXYGEN_TAGFILE for access to the tags file. | ||||
62 | # | ||||
63 | # NAME specifies the name for the generated documentation. | ||||
64 | # | ||||
65 | # VERSION specifies the version of the library for which the documentation is | ||||
66 | # created. | ||||
67 | # | ||||
68 | # BASE_NAME specifies the base name for the generated files. | ||||
69 | # The default basename is ``<name>``. | ||||
70 | # | ||||
71 | # SOURCE_DIRS specifies the dirs (incl. subdirs) with the source files for | ||||
72 | # which the API documentation should be generated. Dirs can be relative to | ||||
73 | # the current source dir. Dependencies to the files in the dirs are not | ||||
74 | # tracked currently, other than with the SOURCES argument. So do not use for | ||||
75 | # sources generated during the build. | ||||
76 | # Needs to be used when SOURCES or CONFIG_TEMPLATE are not used. | ||||
77 | # | ||||
78 | # SOURCES specifies the source files for which the API documentation should be | ||||
79 | # generated. | ||||
80 | # Needs to be used when SOURCE_DIRS or CONFIG_TEMPLATE are not used. | ||||
81 | # | ||||
82 | # MD_MAINPAGE specifies a file in Markdown format that should be used as main | ||||
83 | # page. This page will overrule any ``\mainpage`` command in the included | ||||
84 | # sources. | ||||
85 | # | ||||
86 | # IMAGE_DIRS specifies the dirs which contain images that are included in the | ||||
87 | # documentation. Dirs can be relative to the current source dir. | ||||
88 | # | ||||
89 | # EXAMPLE_DIRS specifies the dirs which contain examples that are included in | ||||
90 | # the documentation. Dirs can be relative to the current source dir. | ||||
91 | # | ||||
92 | # QCH_INSTALL_DESTINATION specifies where the generated QCH file will be | ||||
93 | # installed. | ||||
94 | # | ||||
95 | # TAGFILE_INSTALL_DESTINATION specifies where the generated tag file will be | ||||
96 | # installed. | ||||
97 | # | ||||
98 | # COMPONENT specifies the installation component name with which the install | ||||
99 | # rules for the generated QCH file and tag file are associated. | ||||
100 | # | ||||
101 | # NAMESPACE can be used to set a custom namespace <namespace> of the generated | ||||
102 | # QCH file. The namepspace is used as the unique id by QHelpEngine (cmp. | ||||
103 | # http://doc.qt.io/qt-5/qthelpproject.html#namespace). | ||||
104 | # The default namespace is ``<domain>.<name>``. | ||||
105 | # Needs to be used when ORG_DOMAIN is not used. | ||||
106 | # | ||||
107 | # ORG_DOMAIN can be used to define the organization domain prefix for the | ||||
108 | # default namespace of the generated QCH file. | ||||
109 | # Needs to be used when NAMESPACE is not used. | ||||
110 | # | ||||
111 | # LINK_QCHS specifies a list of other QCH targets which should be used for | ||||
112 | # creating references to API documenation of code in external libraries. | ||||
113 | # For each target <qch> in the list these target properties are expected to be | ||||
114 | # defined: DOXYGEN_TAGFILE, QHP_NAMESPACE and QHP_VIRTUALFOLDER. | ||||
115 | # If any of these is not existing, <qch> will be ignored. | ||||
116 | # Use the macro ``ecm_install_qch_export`` for exporting a target with these | ||||
117 | # properties with the CMake config of a library. | ||||
118 | # Any target <qch> can also be one created before in the same buildsystem by | ||||
119 | # another call of ``ecm_add_qch``. | ||||
120 | # | ||||
121 | # PREDEFINED_MACROS specifies a list of C/C++ macros which should be handled as | ||||
122 | # given by the API dox generation tool. | ||||
123 | # Examples are macros only defined in generated files, so whose | ||||
124 | # definition might be not available to the tool. | ||||
125 | # | ||||
126 | # BLANK_MACROS specifies a list of C/C++ macro names which should be ignored by | ||||
127 | # the API dox generation tool and handled as if they resolve to empty strings. | ||||
128 | # Examples are export macros only defined in generated files, so whose | ||||
129 | # definition might be not available to the tool. | ||||
130 | # | ||||
131 | # CONFIG_TEMPLATE specifies a custom cmake template file for the config file | ||||
132 | # that is created to control the execution of the API dox generation tool. | ||||
133 | # The following CMake variables need to be used: | ||||
134 | # ECM_QCH_DOXYGEN_PERL_EXECUTABLE, ECM_QCH_DOXYGEN_QHELPGENERATOR_EXECUTABLE, | ||||
135 | # ECM_QCH_DOXYGEN_FILEPATH, ECM_QCH_DOXYGEN_TAGFILE. | ||||
136 | # The following CMake variables can be used: | ||||
137 | # ECM_QCH_DOXYGEN_PROJECTNAME, ECM_QCH_DOXYGEN_PROJECTVERSION, | ||||
138 | # ECM_QCH_DOXYGEN_VIRTUALFOLDER, ECM_QCH_DOXYGEN_FULLNAMESPACE, | ||||
139 | # ECM_QCH_DOXYGEN_TAGFILES, | ||||
140 | # ECM_QCH_DOXYGEN_WARN_LOGFILE, ECM_QCH_DOXYGEN_QUIET. | ||||
141 | # There is no guarantue that the other CMake variables currently used in the | ||||
142 | # default config file template will also be present with the same semantics | ||||
143 | # in future versions of this macro. | ||||
144 | # | ||||
145 | # VERBOSE tells the API dox generation tool to be more verbose about its | ||||
146 | # activity. | ||||
147 | # | ||||
148 | # Example usage: | ||||
149 | # | ||||
150 | # .. code-block:: cmake | ||||
151 | # | ||||
152 | # ecm_add_qch( | ||||
153 | # MyLib_QCH | ||||
154 | # NAME MyLib | ||||
155 | # VERSION "0.42.0" | ||||
156 | # ORG_DOMAIN org.myorg | ||||
157 | # SOURCE_DIRS | ||||
158 | # src | ||||
159 | # LINK_QCHS | ||||
160 | # Qt5Core_QCH | ||||
161 | # Qt5Xml_QCH | ||||
162 | # Qt5Gui_QCH | ||||
163 | # Qt5Widgets_QCH | ||||
164 | # BLANK_MACROS | ||||
165 | # MyLib_EXPORT | ||||
166 | # MyLib_DEPRECATED | ||||
167 | # TAGFILE_INSTALL_DESTINATION ${CMAKE_INSTALL_PREFIX}/share/docs/tags | ||||
168 | # QCH_INSTALL_DESTINATION ${CMAKE_INSTALL_PREFIX}/share/docs/qch | ||||
169 | # COMPONENT Devel | ||||
170 | # ) | ||||
171 | # | ||||
172 | # Example usage (with two QCH files, second linking first): | ||||
173 | # | ||||
174 | # .. code-block:: cmake | ||||
175 | # | ||||
176 | # ecm_add_qch( | ||||
177 | # MyLib_QCH | ||||
178 | # NAME MyLib | ||||
179 | # VERSION ${MyLib_VERSION} | ||||
180 | # ORG_DOMAIN org.myorg | ||||
181 | # SOURCES ${MyLib_PUBLIC_HEADERS} | ||||
182 | # MD_MAINPAGE src/mylib/README.md | ||||
183 | # LINK_QCHS Qt5Core_QCH | ||||
184 | # TAGFILE_INSTALL_DESTINATION ${CMAKE_INSTALL_PREFIX}/share/docs/tags | ||||
185 | # QCH_INSTALL_DESTINATION ${CMAKE_INSTALL_PREFIX}/share/docs/qch | ||||
186 | # COMPONENT Devel | ||||
187 | # ) | ||||
188 | # ecm_add_qch( | ||||
189 | # MyOtherLib_QCH | ||||
190 | # NAME MyOtherLib | ||||
191 | # VERSION ${MyOtherLib_VERSION} | ||||
192 | # ORG_DOMAIN org.myorg | ||||
193 | # SOURCES ${MyOtherLib_PUBLIC_HEADERS} | ||||
194 | # MD_MAINPAGE src/myotherlib/README.md | ||||
195 | # LINK_QCHS Qt5Core_QCH MyLib_QCH | ||||
196 | # TAGFILE_INSTALL_DESTINATION ${CMAKE_INSTALL_PREFIX}/share/docs/tags | ||||
197 | # QCH_INSTALL_DESTINATION ${CMAKE_INSTALL_PREFIX}/share/docs/qch | ||||
198 | # COMPONENT Devel | ||||
199 | # ) | ||||
200 | # | ||||
201 | # :: | ||||
202 | # | ||||
203 | # ecm_install_qch_export( | ||||
204 | # TARGETS [<name> [<name2> [...]]] | ||||
205 | # FILE <file> | ||||
206 | # DESTINATION <dest> | ||||
207 | # [COMPONENT <component>] | ||||
208 | # ) | ||||
209 | # | ||||
210 | # This macro creates and installs a CMake file <file> which exports the given | ||||
211 | # QCH targets <name> etc., so they can be picked up by CMake-based builds of | ||||
212 | # other software that also generate QCH files (using ``ecm_add_qch``) and | ||||
213 | # which should include links to the QCH files created by the given targets. | ||||
214 | # The installed CMake file <file> is expected to be included by the CMake | ||||
215 | # config file created for the software the related QCH files are documenting. | ||||
216 | # | ||||
217 | # TARGETS specifies the QCH targets which should be exported. If a target does | ||||
218 | # not exist or does not have all needed properties, a warning will be | ||||
219 | # generated and the target skipped. | ||||
220 | # This behaviour might change in future versions to result in a fail instead. | ||||
221 | # | ||||
222 | # FILE specifies the name of the created CMake file, typically with a .cmake | ||||
223 | # extension. | ||||
224 | # | ||||
225 | # DESTINATION specifies the directory on disk to which the file will be | ||||
226 | # installed. It usually is the same as the one where the CMake config files | ||||
227 | # for this software are installed. | ||||
228 | # | ||||
229 | # COMPONENT specifies the the installation component name with which the | ||||
230 | # install rule is associated. | ||||
231 | # | ||||
232 | # Example usage: | ||||
233 | # | ||||
234 | # .. code-block:: cmake | ||||
235 | # | ||||
236 | # ecm_install_qch_export( | ||||
237 | # TARGETS MyLib_QCH | ||||
238 | # FILE MyLibQCHTargets.cmake | ||||
239 | # DESTINATION "${CMAKE_INSTALL_PREFIX}/lib/cmake/MyLib" | ||||
240 | # COMPONENT Devel | ||||
241 | # ) | ||||
242 | # | ||||
243 | # Since 5.36.0. | ||||
244 | | ||||
245 | #============================================================================= | ||||
246 | # Copyright 2016-2017 Friedrich W. H. Kossebau <kossebau@kde.org> | ||||
247 | # | ||||
248 | # Redistribution and use in source and binary forms, with or without | ||||
249 | # modification, are permitted provided that the following conditions | ||||
250 | # are met: | ||||
251 | # | ||||
252 | # 1. Redistributions of source code must retain the copyright | ||||
253 | # notice, this list of conditions and the following disclaimer. | ||||
254 | # 2. Redistributions in binary form must reproduce the copyright | ||||
255 | # notice, this list of conditions and the following disclaimer in the | ||||
256 | # documentation and/or other materials provided with the distribution. | ||||
257 | # 3. The name of the author may not be used to endorse or promote products | ||||
258 | # derived from this software without specific prior written permission. | ||||
259 | # | ||||
260 | # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | ||||
261 | # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||||
262 | # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | ||||
263 | # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||||
264 | # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||||
265 | # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||||
266 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||||
267 | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
268 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||||
269 | # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
270 | | ||||
271 | include(CMakeParseArguments) | ||||
272 | include(ECMQueryQmake) | ||||
273 | | ||||
274 | | ||||
275 | # Helper method: adding the LINK_QCHS property to a Qt QCH targets, from module base names ("Core" etc.) | ||||
276 | # if target does not exist (e.g. because no tagsfile was found), this is a no-op | ||||
277 | macro(_ecm_setup_qt_qch_links _module) | ||||
278 | set(_target "Qt5${_module}_QCH") | ||||
279 | if(TARGET ${_target}) | ||||
280 | set(_linkqchs) | ||||
281 | foreach(_linkqch ${ARGN}) | ||||
282 | list(APPEND _linkqchs "Qt5${_linkqch}_QCH") | ||||
283 | endforeach() | ||||
284 | set_property(TARGET ${_target} PROPERTY LINK_QCHS ${_linkqchs}) | ||||
285 | endif() | ||||
286 | endmacro() | ||||
287 | | ||||
288 | # Helper method: ensure Qt QCH targets are created | ||||
289 | function(_ecm_ensure_qt_qch_targets) | ||||
290 | # create QCH targets for Qt | ||||
291 | # Ideally one day Qt CMake Config files provide these | ||||
292 | if(NOT TARGET Qt5Core_QCH) | ||||
293 | # get Qt version, if any | ||||
294 | find_package(Qt5Core CONFIG QUIET) | ||||
295 | # lookup tag files | ||||
296 | query_qmake(qt_docs_dir QT_INSTALL_DOCS) | ||||
297 | find_path(_qtcoreTagsPath qtcore/qtcore.tags | ||||
298 | PATHS | ||||
299 | ${qt_docs_dir} | ||||
300 | ) | ||||
301 | | ||||
302 | if(Qt5Core_FOUND AND _qtcoreTagsPath) | ||||
303 | string(REPLACE "." "" _version ${Qt5Core_VERSION}) | ||||
304 | # TODO: properly find each tag file | ||||
305 | # TODO: complete list of Qt modules | ||||
306 | # qtdbus.tags file missing since 5.0, QTBUG-60933, extra handling? | ||||
307 | foreach(_module | ||||
308 | 3D Bluetooth Concurrent Core DBus Gui Location | ||||
309 | Network Positioning PrintSupport Qml Quick Sensors SerialPort Sql Svg | ||||
310 | WebChannel WebEngine WebSockets Widgets Xml XmlPatterns | ||||
311 | ) | ||||
312 | string(TOLOWER ${_module} _lowermodule) | ||||
313 | | ||||
314 | set(_tagfile "${_qtcoreTagsPath}/qt${_lowermodule}/qt${_lowermodule}.tags") | ||||
315 | if(EXISTS "${_tagfile}") | ||||
316 | add_custom_target(Qt5${_module}_QCH) | ||||
317 | set_target_properties(Qt5${_module}_QCH PROPERTIES | ||||
318 | DOXYGEN_TAGFILE "${_tagfile}" | ||||
319 | QHP_NAMESPACE "org.qt-project.qt${_lowermodule}" | ||||
320 | QHP_NAMESPACE_VERSIONED "org.qt-project.qt${_lowermodule}.${_version}" | ||||
321 | QHP_VIRTUALFOLDER "qt${_lowermodule}" | ||||
322 | IMPORTED TRUE | ||||
323 | ) | ||||
324 | endif() | ||||
325 | endforeach() | ||||
326 | _ecm_setup_qt_qch_links(3D Gui Core) | ||||
327 | _ecm_setup_qt_qch_links(Bluetooth DBus Core) | ||||
328 | _ecm_setup_qt_qch_links(Concurrent Gui Core) | ||||
329 | _ecm_setup_qt_qch_links(DBus Core) | ||||
330 | _ecm_setup_qt_qch_links(Gui Core) | ||||
331 | _ecm_setup_qt_qch_links(Location Positioning Gui Core) | ||||
332 | _ecm_setup_qt_qch_links(Network Core) | ||||
333 | _ecm_setup_qt_qch_links(Positioning Core) | ||||
334 | _ecm_setup_qt_qch_links(PrintSupport Widgets Gui Core) | ||||
335 | _ecm_setup_qt_qch_links(Qml Network Core) | ||||
336 | _ecm_setup_qt_qch_links(Quick Qml Network Gui Core) | ||||
337 | _ecm_setup_qt_qch_links(Sensors Core) | ||||
338 | _ecm_setup_qt_qch_links(SerialPort Core) | ||||
339 | _ecm_setup_qt_qch_links(Sql Core) | ||||
340 | _ecm_setup_qt_qch_links(Svg Widgets Gui Core) | ||||
341 | _ecm_setup_qt_qch_links(WebChannel Qml Core) | ||||
342 | _ecm_setup_qt_qch_links(WebEngine Quick Qml Gui Core) | ||||
343 | _ecm_setup_qt_qch_links(WebSockets Network Core) | ||||
344 | _ecm_setup_qt_qch_links(Widgets Gui Core) | ||||
345 | _ecm_setup_qt_qch_links(Xml Core) | ||||
346 | _ecm_setup_qt_qch_links(XmlPatterns Network Core) | ||||
347 | endif() | ||||
348 | endif() | ||||
349 | endfunction() | ||||
350 | | ||||
351 | # Helper method: collect all qch targets from the LINK_QCHS dependency tree and set result to <var> | ||||
352 | function(_ecm_collect_linkable_qch_targets name) | ||||
353 | set(_candidate_qchs ${ARGN}) | ||||
354 | set(_handled_qchs) | ||||
355 | set(_good_qchs) | ||||
356 | # while unhandled qch targets | ||||
357 | while(_candidate_qchs) | ||||
358 | # get another unhandled qch target | ||||
359 | list(GET _candidate_qchs 0 _qch) | ||||
360 | list(REMOVE_AT _candidate_qchs 0) | ||||
361 | list(FIND _handled_qchs ${_qch} _index) | ||||
362 | # if not already handled | ||||
363 | if(_index EQUAL -1) | ||||
364 | list(APPEND _handled_qchs ${_qch}) | ||||
365 | if(TARGET ${_qch}) | ||||
366 | # always look at other linked qch targets, also for incomplete targets | ||||
367 | get_property(_link_qchs TARGET ${_qch} PROPERTY LINK_QCHS) | ||||
368 | if(_link_qchs) | ||||
369 | list(APPEND _candidate_qchs ${_link_qchs}) | ||||
370 | endif() | ||||
371 | # check if this target has all needed properties | ||||
372 | set(_target_usable TRUE) | ||||
373 | foreach(_propertyname | ||||
374 | DOXYGEN_TAGFILE | ||||
375 | QHP_NAMESPACE | ||||
376 | QHP_VIRTUALFOLDER | ||||
377 | ) | ||||
378 | get_target_property(_property ${_qch} ${_propertyname}) | ||||
379 | if(NOT _property) | ||||
380 | message(STATUS "No property ${_propertyname} set on ${_qch} when calling ecm_add_qch(). <<${_property}>>") | ||||
381 | set(_target_usable FALSE) | ||||
382 | endif() | ||||
383 | endforeach() | ||||
384 | get_target_property(_tagfile_build ${_qch} DOXYGEN_TAGFILE_BUILD) | ||||
385 | if (NOT _tagfile_build) | ||||
386 | get_target_property(_tagfile ${_qch} DOXYGEN_TAGFILE) | ||||
387 | if(NOT EXISTS ${_tagfile}) | ||||
388 | message(STATUS "No such tag file \"${_tagfile}\" found for ${_qch} when calling ecm_add_qch().") | ||||
389 | set(_target_usable FALSE) | ||||
390 | endif() | ||||
391 | endif() | ||||
392 | if(_target_usable) | ||||
393 | list(APPEND _good_qchs ${_qch}) | ||||
394 | else() | ||||
395 | message(WARNING "No linking to API dox of ${_qch}.") | ||||
396 | endif() | ||||
397 | else() | ||||
398 | message(STATUS "No such target ${_qch} defined when calling ecm_add_qch(), ignored.") | ||||
399 | endif() | ||||
400 | endif() | ||||
401 | endwhile() | ||||
402 | set(${name} ${_good_qchs} PARENT_SCOPE) | ||||
403 | endfunction() | ||||
404 | | ||||
405 | | ||||
406 | function(ecm_add_qch target_name) | ||||
407 | # Parse arguments | ||||
408 | set(options VERBOSE) | ||||
409 | set(oneValueArgs NAME BASE_NAME QCH_INSTALL_DESTINATION TAGFILE_INSTALL_DESTINATION COMPONENT VERSION NAMESPACE MD_MAINPAGE ORG_DOMAIN CONFIG_TEMPLATE) | ||||
410 | set(multiValueArgs SOURCE_DIRS SOURCES IMAGE_DIRS EXAMPLE_DIRS PREDEFINED_MACROS BLANK_MACROS LINK_QCHS) | ||||
411 | cmake_parse_arguments(ARGS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) | ||||
412 | | ||||
413 | # check required args | ||||
414 | foreach(_arg_name NAME QCH_INSTALL_DESTINATION TAGFILE_INSTALL_DESTINATION VERSION) | ||||
415 | if(NOT DEFINED ARGS_${_arg_name}) | ||||
416 | message(FATAL_ERROR "${_arg_name} needs to be defined when calling ecm_add_qch") | ||||
417 | endif() | ||||
418 | endforeach() | ||||
419 | if(NOT DEFINED ARGS_SOURCE_DIRS AND NOT DEFINED ARGS_SOURCES AND NOT DEFINED ARGS_CONFIG_TEMPLATE) | ||||
420 | message(FATAL_ERROR "SOURCE_DIRS or SOURCES needs to be defined when calling ecm_add_qch") | ||||
421 | endif() | ||||
422 | if(DEFINED ARGS_SOURCE_DIRS AND DEFINED ARGS_SOURCES) | ||||
423 | message(FATAL_ERROR "Either SOURCE_DIRS or SOURCES, not both, needs to be defined when calling ecm_add_qch") | ||||
424 | endif() | ||||
425 | if(NOT DEFINED ARGS_ORG_DOMAIN AND NOT DEFINED ARGS_NAMESPACE) | ||||
426 | message(FATAL_ERROR "ORG_DOMAIN or NAMESPACE needs to be defined when calling ecm_add_qch") | ||||
427 | endif() | ||||
428 | | ||||
429 | # find required tools | ||||
430 | # TODO: check with doxygen author if perl is really still required, PERL_PATH seems unused in doxygen | ||||
431 | find_package(Perl) | ||||
432 | set_package_properties(Perl PROPERTIES | ||||
433 | PURPOSE "Needed for API dox QCH file generation" | ||||
434 | TYPE OPTIONAL | ||||
435 | ) | ||||
436 | if (NOT DOXYGEN_PATCHED_JSFILESADDED) | ||||
437 | set(REQUIRED_DOXYGEN_VERSION 1.8.13) | ||||
438 | endif() | ||||
439 | find_package(Doxygen ${REQUIRED_DOXYGEN_VERSION}) | ||||
440 | if (NOT DOXYGEN_FOUND AND NOT DOXYGEN_PATCHED_JSFILESADDED) | ||||
441 | 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)") | ||||
442 | endif() | ||||
443 | set_package_properties(Doxygen PROPERTIES | ||||
444 | TYPE OPTIONAL | ||||
445 | PURPOSE "Needed for API dox QCH file generation${doxygen_description_addition}" | ||||
446 | ) | ||||
447 | find_package(QHelpGenerator) | ||||
448 | set_package_properties(QHelpGenerator PROPERTIES | ||||
449 | TYPE OPTIONAL | ||||
450 | PURPOSE "Needed for API dox QCH file generation" | ||||
451 | DESCRIPTION "Part of Qt5 tools" | ||||
452 | ) | ||||
453 | set(_missing_tools) | ||||
454 | if (NOT PERL_FOUND) | ||||
455 | list(APPEND _missing_tools "Perl") | ||||
456 | endif() | ||||
457 | if (NOT DOXYGEN_FOUND) | ||||
458 | list(APPEND _missing_tools "Doxygen") | ||||
459 | endif() | ||||
460 | if (NOT QHelpGenerator_FOUND) | ||||
461 | list(APPEND _missing_tools "qhelpgenerator") | ||||
462 | endif() | ||||
463 | | ||||
464 | if (_missing_tools) | ||||
465 | message(WARNING "API dox QCH file will not be generated, tools missing: ${_missing_tools}!") | ||||
466 | else() | ||||
467 | _ecm_ensure_qt_qch_targets() | ||||
468 | | ||||
469 | # prepare base dirs, working file names and other vars | ||||
470 | if (DEFINED ARGS_BASE_NAME) | ||||
471 | set(_basename ${ARGS_BASE_NAME}) | ||||
472 | else() | ||||
473 | set(_basename ${ARGS_NAME}) | ||||
474 | endif() | ||||
475 | set(_qch_file_basename "${_basename}.qch") | ||||
476 | set(_tags_file_basename "${_basename}.tags") | ||||
477 | set(_qch_buildpath "${CMAKE_CURRENT_BINARY_DIR}/${_qch_file_basename}") | ||||
478 | set(_tags_buildpath "${CMAKE_CURRENT_BINARY_DIR}/${_tags_file_basename}") | ||||
479 | set(_apidox_builddir "${CMAKE_CURRENT_BINARY_DIR}/${_basename}_ECMQchDoxygen") | ||||
480 | if (DEFINED ARGS_NAMESPACE) | ||||
481 | set(_namespace "${ARGS_NAMESPACE}") | ||||
482 | else() | ||||
483 | set(_namespace "${ARGS_ORG_DOMAIN}.${ARGS_NAME}") | ||||
484 | endif() | ||||
485 | string(REPLACE "." "_" _dotLessVersion ${ARGS_VERSION}) | ||||
486 | set(_versioned_namespace "${_namespace}.${_dotLessVersion}") | ||||
487 | set(_sources) | ||||
488 | set(_dep_tagfiles) | ||||
489 | set(_dep_qch_targets) | ||||
490 | | ||||
491 | ### Create doxygen config file | ||||
492 | set(_doxygenconfig_file "${CMAKE_CURRENT_BINARY_DIR}/${_basename}_ECMQchDoxygen.config") | ||||
493 | if (DEFINED ARGS_CONFIG_TEMPLATE) | ||||
494 | set(_doxygenconfig_template_file "${ARGS_CONFIG_TEMPLATE}") | ||||
495 | else() | ||||
496 | set(_doxygenconfig_template_file "${ECM_MODULE_DIR}/ECMQchDoxygen.config.in") | ||||
497 | endif() | ||||
498 | set(_doxygen_layout_file "${ECM_MODULE_DIR}/ECMQchDoxygenLayout.xml") | ||||
499 | # Setup variables used in config file template, ECM_QCH_DOXYGEN_* | ||||
500 | set(ECM_QCH_DOXYGEN_OUTPUTDIR "\"${_apidox_builddir}\"") | ||||
501 | set(ECM_QCH_DOXYGEN_TAGFILE "\"${_tags_buildpath}\"") | ||||
502 | set(ECM_QCH_DOXYGEN_LAYOUTFILE "\"${_doxygen_layout_file}\"") | ||||
503 | set(ECM_QCH_DOXYGEN_IMAGEDIRS) | ||||
504 | foreach(_image_DIR IN LISTS ARGS_IMAGE_DIRS) | ||||
505 | if (NOT IS_ABSOLUTE ${_image_DIR}) | ||||
506 | set(_image_DIR "${CMAKE_CURRENT_SOURCE_DIR}/${_image_DIR}") | ||||
507 | endif() | ||||
508 | # concat dirs separated by a break, it is no issue that first has also a leading break | ||||
509 | set(ECM_QCH_DOXYGEN_IMAGEDIRS "${ECM_QCH_DOXYGEN_IMAGEDIRS} \\\n\"${_image_DIR}\"") | ||||
510 | endforeach() | ||||
511 | set(ECM_QCH_DOXYGEN_EXAMPLEDIRS) | ||||
512 | foreach(_example_DIR IN LISTS ARGS_EXAMPLE_DIRS) | ||||
513 | if (NOT IS_ABSOLUTE ${_example_DIR}) | ||||
514 | set(_example_DIR "${CMAKE_CURRENT_SOURCE_DIR}/${_example_DIR}") | ||||
515 | endif() | ||||
516 | # concat dirs separated by a break, it is no issue that first has also a leading break | ||||
517 | set(ECM_QCH_DOXYGEN_EXAMPLEDIRS "${ECM_QCH_DOXYGEN_EXAMPLEDIRS} \\\n\"${_example_DIR}\"") | ||||
518 | endforeach() | ||||
519 | if (ARGS_MD_MAINPAGE) | ||||
520 | if (NOT IS_ABSOLUTE ${ARGS_MD_MAINPAGE}) | ||||
521 | set(ARGS_MD_MAINPAGE "${CMAKE_CURRENT_SOURCE_DIR}/${ARGS_MD_MAINPAGE}") | ||||
522 | endif() | ||||
523 | set(ECM_QCH_DOXYGEN_MAINPAGE_MDFILE "\"${ARGS_MD_MAINPAGE}\"") | ||||
524 | else() | ||||
525 | set(ECM_QCH_DOXYGEN_MAINPAGE_MDFILE) | ||||
526 | endif() | ||||
527 | set(ECM_QCH_DOXYGEN_INPUT) | ||||
528 | if (ARGS_SOURCE_DIRS) | ||||
529 | foreach(_source_DIR IN LISTS ARGS_SOURCE_DIRS) | ||||
530 | if (NOT IS_ABSOLUTE ${_source_DIR}) | ||||
531 | set(_source_DIR "${CMAKE_CURRENT_SOURCE_DIR}/${_source_DIR}") | ||||
532 | endif() | ||||
533 | # concat dirs separated by a break, it is no issue that first has also a leading break | ||||
534 | set(ECM_QCH_DOXYGEN_INPUT "${ECM_QCH_DOXYGEN_INPUT} \\\n\"${_source_DIR}\"") | ||||
535 | endforeach() | ||||
536 | if (ARGS_MD_MAINPAGE) | ||||
537 | set(ECM_QCH_DOXYGEN_INPUT "${ECM_QCH_DOXYGEN_INPUT} \\\n\"${ARGS_MD_MAINPAGE}\"") | ||||
538 | endif() | ||||
539 | set(ECM_QCH_DOXYGEN_FILE_PATTERNS "*.h *.cpp *.hpp *.hh *.cc *.h++ *.c++ *.hxx *.cxx *.dox *.md") | ||||
540 | else() | ||||
541 | foreach(_source IN LISTS ARGS_SOURCES) | ||||
542 | if (NOT IS_ABSOLUTE ${_source}) | ||||
543 | set(_source "${CMAKE_CURRENT_SOURCE_DIR}/${_source}") | ||||
544 | endif() | ||||
545 | list(APPEND _sources "${_source}") | ||||
546 | endforeach() | ||||
547 | if (ARGS_MD_MAINPAGE) | ||||
548 | list(FIND _sources ${ARGS_MD_MAINPAGE} _mainpage_index) | ||||
549 | if (_mainpage_index STREQUAL -1) | ||||
550 | list(APPEND _sources "${ARGS_MD_MAINPAGE}") | ||||
551 | endif() | ||||
552 | endif() | ||||
553 | foreach(_source IN LISTS _sources) | ||||
554 | # concat sources separated by a break, it is no issue that first has also a leading break | ||||
555 | set(ECM_QCH_DOXYGEN_INPUT "${ECM_QCH_DOXYGEN_INPUT} \\\n\"${_source}\"") | ||||
556 | endforeach() | ||||
557 | set(ECM_QCH_DOXYGEN_FILE_PATTERNS "") | ||||
558 | endif() | ||||
559 | | ||||
560 | set(ECM_QCH_DOXYGEN_PROJECTNAME ${ARGS_NAME}) | ||||
561 | file(RELATIVE_PATH _builddirrelative_filepath "${_apidox_builddir}/html" ${_qch_buildpath}) | ||||
562 | set(ECM_QCH_DOXYGEN_FILEPATH "\"${_builddirrelative_filepath}\"") | ||||
563 | set(ECM_QCH_DOXYGEN_PROJECTVERSION ${ARGS_VERSION}) | ||||
564 | string(TOLOWER ${ARGS_NAME} ECM_QCH_DOXYGEN_VIRTUALFOLDER) | ||||
565 | set(ECM_QCH_DOXYGEN_FULLNAMESPACE ${_versioned_namespace}) | ||||
566 | set(ECM_QCH_DOXYGEN_PREDEFINED_MACROS) | ||||
567 | foreach(_macro IN LISTS ARGS_PREDEFINED_MACROS) | ||||
568 | # concat dirs separated by a break, it is no issue that first has also a leading break | ||||
569 | set(ECM_QCH_DOXYGEN_PREDEFINED_MACROS "${ECM_QCH_DOXYGEN_PREDEFINED_MACROS} \\\n${_macro}") | ||||
570 | endforeach() | ||||
571 | set(ECM_QCH_DOXYGEN_BLANK_MACROS) | ||||
572 | foreach(_macro IN LISTS ARGS_BLANK_MACROS) | ||||
573 | # concat dirs separated by a break, it is no issue that first has also a leading break | ||||
574 | set(ECM_QCH_DOXYGEN_BLANK_MACROS "${ECM_QCH_DOXYGEN_BLANK_MACROS} \\\n${_macro}=\"\"") | ||||
575 | endforeach() | ||||
576 | | ||||
577 | # create list of tag files for linking other QCH files | ||||
578 | set(ECM_QCH_DOXYGEN_TAGFILES) | ||||
579 | _ecm_collect_linkable_qch_targets(_link_qchs ${ARGS_LINK_QCHS}) | ||||
580 | foreach(_link_qch IN LISTS _link_qchs) | ||||
581 | list(APPEND _dep_qch_targets ${_link_qch}) | ||||
582 | get_target_property(_link_qch_tagfile ${_link_qch} DOXYGEN_TAGFILE) | ||||
583 | get_target_property(_link_qch_tagfile_build ${_link_qch} DOXYGEN_TAGFILE_BUILD) | ||||
584 | get_target_property(_link_qch_namespace ${_link_qch} QHP_NAMESPACE) | ||||
585 | get_target_property(_link_qch_virtualfolder ${_link_qch} QHP_VIRTUALFOLDER) | ||||
586 | # if same build, then prefer build version over any installed one | ||||
587 | if (_link_qch_tagfile_build) | ||||
588 | set(_link_qch_tagfile ${_link_qch_tagfile_build}) | ||||
589 | list(APPEND _dep_tagfiles "${_link_qch_tagfile}") | ||||
590 | endif() | ||||
591 | get_property(_linkqchs TARGET ${_link_qch} PROPERTY LINK_QCHS) | ||||
592 | set(_tagfile_entry "\"${_link_qch_tagfile}=qthelp://${_link_qch_namespace}/${_link_qch_virtualfolder}/\"") | ||||
593 | # concat dirs separated by a break, it is no issue that first has also a leading break | ||||
594 | set(ECM_QCH_DOXYGEN_TAGFILES "${ECM_QCH_DOXYGEN_TAGFILES} \\\n${_tagfile_entry}") | ||||
595 | endforeach() | ||||
596 | | ||||
597 | set(ECM_QCH_DOXYGEN_WARN_LOGFILE "\"${_doxygenconfig_file}.log\"") | ||||
598 | if(ARGS_VERBOSE) | ||||
599 | set(ECM_QCH_DOXYGEN_QUIET "NO") | ||||
600 | else() | ||||
601 | set(ECM_QCH_DOXYGEN_QUIET "YES") | ||||
602 | endif() | ||||
603 | set(ECM_QCH_DOXYGEN_PERL_EXECUTABLE "${PERL_EXECUTABLE}") | ||||
604 | set(ECM_QCH_DOXYGEN_QHELPGENERATOR_EXECUTABLE ${QHelpGenerator_EXECUTABLE}) | ||||
605 | | ||||
606 | # finally create doxygen config file | ||||
607 | configure_file( | ||||
608 | "${_doxygenconfig_template_file}" | ||||
609 | "${_doxygenconfig_file}" | ||||
610 | @ONLY | ||||
611 | ) | ||||
612 | | ||||
613 | # setup make target | ||||
614 | set(_qch_INSTALLPATH ${ARGS_QCH_INSTALL_DESTINATION}) | ||||
615 | set(_tags_INSTALLPATH ${ARGS_TAGFILE_INSTALL_DESTINATION}) | ||||
616 | file(RELATIVE_PATH _relative_qch_file ${CMAKE_BINARY_DIR} ${_qch_buildpath}) | ||||
617 | file(RELATIVE_PATH _relative_tags_file ${CMAKE_BINARY_DIR} ${_tags_buildpath}) | ||||
618 | add_custom_command( | ||||
619 | OUTPUT ${_qch_buildpath} ${_tags_buildpath} | ||||
620 | COMMENT "Generating ${_relative_qch_file}, ${_relative_tags_file}" | ||||
621 | COMMAND cmake -E remove_directory "${ECM_QCH_DOXYGEN_OUTPUTDIR}" | ||||
622 | COMMAND cmake -E make_directory "${ECM_QCH_DOXYGEN_OUTPUTDIR}" | ||||
623 | COMMAND ${DOXYGEN_EXECUTABLE} "${_doxygenconfig_file}" | ||||
624 | DEPENDS | ||||
625 | ${_doxygenconfig_file} | ||||
626 | ${_doxygen_layout_file} | ||||
627 | ${_sources} | ||||
628 | ${_dep_tagfiles} | ||||
629 | ${_dep_qch_targets} | ||||
630 | ) | ||||
631 | add_custom_target(${target_name} ALL DEPENDS ${_qch_buildpath} ${_tags_buildpath}) | ||||
632 | set_target_properties(${target_name} PROPERTIES | ||||
633 | DOXYGEN_TAGFILE "${_qch_INSTALLPATH}/${_tags_file_basename}" | ||||
634 | DOXYGEN_TAGFILE_NAME "${_tags_file_basename}" | ||||
635 | DOXYGEN_TAGFILE_INSTALLDIR "${_qch_INSTALLPATH}" | ||||
636 | DOXYGEN_TAGFILE_BUILD "${_tags_buildpath}" | ||||
637 | QHP_NAMESPACE "${_namespace}" | ||||
638 | QHP_NAMESPACE_VERSIONED "${_versioned_namespace}" | ||||
639 | QHP_VIRTUALFOLDER "${ECM_QCH_DOXYGEN_VIRTUALFOLDER}" | ||||
640 | ) | ||||
641 | # list as value does not work with set_target_properties | ||||
642 | set_property(TARGET ${target_name} PROPERTY LINK_QCHS "${ARGS_LINK_QCHS}") | ||||
643 | | ||||
644 | if (DEFINED ARGS_COMPONENT) | ||||
645 | set(_component COMPONENT ${ARGS_COMPONENT}) | ||||
646 | else() | ||||
647 | set(_component) | ||||
648 | endif() | ||||
649 | | ||||
650 | # setup installation | ||||
651 | install(FILES | ||||
652 | ${_qch_buildpath} | ||||
653 | DESTINATION ${_qch_INSTALLPATH} | ||||
654 | ${_component} | ||||
655 | ) | ||||
656 | | ||||
657 | install(FILES | ||||
658 | ${_tags_buildpath} | ||||
659 | DESTINATION ${_tags_INSTALLPATH} | ||||
660 | ${_component} | ||||
661 | ) | ||||
662 | endif() | ||||
663 | | ||||
664 | endfunction() | ||||
665 | | ||||
666 | | ||||
667 | function(ecm_install_qch_export) | ||||
668 | set(options ) | ||||
669 | set(oneValueArgs FILE DESTINATION COMPONENT) | ||||
670 | set(multiValueArgs TARGETS) | ||||
671 | | ||||
672 | cmake_parse_arguments(ARGS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) | ||||
673 | | ||||
674 | if(NOT DEFINED ARGS_FILE) | ||||
675 | message(FATAL_ERROR "FILE needs to be defined when calling ecm_install_qch_export().") | ||||
676 | endif() | ||||
677 | | ||||
678 | if(NOT DEFINED ARGS_DESTINATION) | ||||
679 | message(FATAL_ERROR "DESTINATION needs to be defined when calling ecm_install_qch_export().") | ||||
680 | endif() | ||||
681 | | ||||
682 | # TARGETS may be empty (and ARGS_TARGETS will not be defined then by cmake_parse_arguments) | ||||
683 | | ||||
684 | set(_content | ||||
685 | "# This file was generated by ecm_install_qch_export(). DO NOT EDIT! | ||||
686 | " | ||||
687 | ) | ||||
688 | | ||||
689 | foreach(_target IN LISTS ARGS_TARGETS) | ||||
690 | set(_target_usable TRUE) | ||||
691 | | ||||
692 | if (NOT TARGET ${_target}) | ||||
693 | message(STATUS "No such target ${_target} when calling ecm_install_qch_export().") | ||||
694 | set(_target_usable FALSE) | ||||
695 | else() | ||||
696 | foreach(_propertyname | ||||
697 | DOXYGEN_TAGFILE_NAME | ||||
698 | DOXYGEN_TAGFILE_INSTALLDIR | ||||
699 | QHP_NAMESPACE | ||||
700 | QHP_NAMESPACE_VERSIONED | ||||
701 | QHP_VIRTUALFOLDER | ||||
702 | ) | ||||
703 | get_target_property(_property ${_target} ${_propertyname}) | ||||
704 | if(NOT _property) | ||||
705 | message(STATUS "No property ${_propertyname} set on ${_target} when calling ecm_install_qch_export(). <${_property}>") | ||||
706 | set(_target_usable FALSE) | ||||
707 | endif() | ||||
708 | endforeach() | ||||
709 | endif() | ||||
710 | if(_target_usable) | ||||
711 | get_target_property(_tagfile_name ${_target} DOXYGEN_TAGFILE_NAME) | ||||
712 | get_target_property(_tagfile_installdir ${_target} DOXYGEN_TAGFILE_INSTALLDIR) | ||||
713 | if (NOT IS_ABSOLUTE ${_tagfile_installdir}) | ||||
714 | set(_tagfile_installdir "${CMAKE_INSTALL_PREFIX}/${_tagfile_installdir}") | ||||
715 | endif() | ||||
716 | get_target_property(_namespace ${_target} QHP_NAMESPACE) | ||||
717 | get_target_property(_namespace_versioned ${_target} QHP_NAMESPACE_VERSIONED) | ||||
718 | get_target_property(_virtualfolder ${_target} QHP_VIRTUALFOLDER) | ||||
719 | get_property(_linkqchs TARGET ${_target} PROPERTY LINK_QCHS) | ||||
720 | set(_content "${_content} | ||||
721 | if (NOT TARGET ${_target}) | ||||
722 | | ||||
723 | add_custom_target(${_target}) | ||||
724 | set_target_properties(${_target} PROPERTIES | ||||
725 | DOXYGEN_TAGFILE \"${_tagfile_installdir}/${_tagfile_name}\" | ||||
726 | QHP_NAMESPACE \"${_namespace}\" | ||||
727 | QHP_NAMESPACE_VERSIONED \"${_namespace_versioned}\" | ||||
728 | QHP_VIRTUALFOLDER \"${_virtualfolder}\" | ||||
729 | IMPORTED TRUE | ||||
730 | ) | ||||
731 | set_property(TARGET ${_target} PROPERTY LINK_QCHS ${_linkqchs}) | ||||
732 | | ||||
733 | endif() | ||||
734 | " | ||||
735 | ) | ||||
736 | else() | ||||
737 | message(STATUS "No target exported for ${_target}.") | ||||
738 | endif() | ||||
739 | endforeach() | ||||
740 | | ||||
741 | if (NOT IS_ABSOLUTE ${ARGS_FILE}) | ||||
742 | set(ARGS_FILE "${CMAKE_CURRENT_BINARY_DIR}/${ARGS_FILE}") | ||||
743 | endif() | ||||
744 | | ||||
745 | file(GENERATE | ||||
746 | OUTPUT "${ARGS_FILE}" | ||||
747 | CONTENT "${_content}" | ||||
748 | ) | ||||
749 | | ||||
750 | if (DEFINED ARGS_COMPONENT) | ||||
751 | set(_component COMPONENT ${ARGS_COMPONENT}) | ||||
752 | else() | ||||
753 | set(_component) | ||||
754 | endif() | ||||
755 | install( | ||||
756 | FILES "${ARGS_FILE}" | ||||
757 | DESTINATION "${ARGS_DESTINATION}" | ||||
758 | ${_component} | ||||
759 | ) | ||||
760 | | ||||
761 | endfunction() |