summaryrefslogtreecommitdiff
path: root/buildsystems/cmake/GtkDocConfig.cmake
blob: 6f1ec4d03065e5c629c91a099c35227ee533d250 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
# CMake macros to use the GtkDoc documentation system
#
# See the GTK-Doc manual (help/manual/C/index.docbook) for an example of how to
# use this.

# Output variables:
#
#   GTKDOC_FOUND            ... set to 1
#
#   GTKDOC_SCAN_EXE         ... the location of the gtkdoc-scan executable
#   GTKDOC_SCANGOBJ_EXE     ... the location of the gtkdoc-scangobj executable
#   GTKDOC_MKDB_EXE         ... the location of the gtkdoc-mkdb executable
#   GTKDOC_MKHTML_EXE       ... the location of the gtkdoc-mkhtml executable
#   GTKDOC_FIXXREF_EXE      ... the location of the gtkdoc-fixxref executable


#=============================================================================
# Copyright 2009 Rich Wareham
# Copyright 2015 Lautsprecher Teufel GmbH
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#=============================================================================

include(CMakeParseArguments)

set(GTKDOC_FOUND 1)

find_program(GTKDOC_SCAN_EXE gtkdoc-scan)
find_program(GTKDOC_SCANGOBJ_EXE gtkdoc-scangobj)
find_program(GTKDOC_MKDB_EXE gtkdoc-mkdb)
find_program(GTKDOC_MKHTML_EXE gtkdoc-mkhtml)
find_program(GTKDOC_FIXXREF_EXE gtkdoc-fixxref)

get_filename_component(_this_dir ${CMAKE_CURRENT_LIST_FILE} PATH)
find_file(GTKDOC_SCANGOBJ_WRAPPER GtkDocScanGObjWrapper.cmake PATH ${_this_dir})

# ::
#
# gtk_doc_add_module(doc_prefix
#                    SOURCE <sourcedir> [...]
#                    XML xmlfile
#                    [LIBRARIES depend1...]
#                    [FIXXREFOPTS fixxrefoption1...]
#                    [IGNOREHEADERS header1...])
#
# Add a module with documentation to be processed with GTK-Doc.
#
# <sourcedir> must be the *full* path to the source directory.
#
# If omitted, xmlfile defaults to the auto generated ${doc_prefix}/${doc_prefix}-docs.xml.
#
# The `gtkdoc-scangobj` program is used to get introspection information for
# the module. You should pass the target(s) to be scanned as LIRARIES. This
# will try to set the correct compiler and link flags for the introspection
# build to use, and the correct LD_LIBRARY_PATH for it to run, and the correct
# dependencies for the doc target.
#
# You *can* also set the compile and link flags manually, using the 'CFLAGS'
# and 'LDFLAGS' options. The 'LDPATH' option controls the LD_LIBRARY_PATH. You
# can also manually add additional targets as dependencies of the
# documentation build with the DEPENDS option.
#
# This function a target named "doc-${doc_prefix}". You will need to manually
# add it to the ALL target if you want it to be built by default, you can do
# something like this:
#
#   gtk_doc_add_module(doc-mymodule
#                      SOURCE ${CMAKE_SOURCE_DIR}/module ${CMAKE_BINARY_DIR}/module
#                      LIBRARIES mylibrary
#                      LIBRARY_DIRS ${GLIB_LIBRARY_DIRS} ${FOO_LIBRARY_DIRS}
#   add_custom_target(all-documentation ALL)
#   add_dependencies(all-documentation doc-mymodule)
#
function(gtk_doc_add_module _doc_prefix)
    set(_one_value_args "XML")
    set(_multi_value_args "FIXXREFOPTS" "IGNOREHEADERS" "LIBRARIES" "LIBRARY_DIRS" "SOURCE" "SUFFIXES"
                          "CFLAGS" "DEPENDS" "LDFLAGS" "LDPATH")
    cmake_parse_arguments("GTK_DOC" "" "${_one_value_args}" "${_multi_value_args}" ${ARGN})

    if(NOT GTK_DOC_SOURCE)
        message(FATAL_ERROR "No SOURCE specified for gtk_doc_add_module ${_doc_prefix}")
    endif()

    set(_xml_file ${GTK_DOC_XML})

    set(_fixxrefopts ${GTK_DOC_FIXXREFOPTS})
    set(_ignore_headers ${GTK_DOC_IGNOREHEADERS})
    set(_libraries ${GTK_DOC_LIBRARIES})
    set(_library_dirs ${GTK_DOC_LIBRARY_DIRS})
    set(_suffixes ${GTK_DOC_SUFFIXES})

    set(_extra_cflags ${GTK_DOC_CFLAGS})
    set(_depends ${GTK_DOC_DEPENDS})
    set(_extra_ldflags ${GTK_DOC_LDFLAGS})
    set(_extra_ldpath ${GTK_DOC_LDPATH})

    if(_suffixes)
        set(_doc_source_suffixes "")
        foreach(_suffix ${_suffixes})
            if(_doc_source_suffixes)
                set(_doc_source_suffixes "${_doc_source_suffixes},${_suffix}")
            else(_doc_source_suffixes)
                set(_doc_source_suffixes "${_suffix}")
            endif(_doc_source_suffixes)
        endforeach(_suffix)
    else(_suffixes)
        set(_doc_source_suffixes "h")
    endif(_suffixes)

    # Parse the LIBRARIES option and collect compile and link flags for those
    # targets.
    foreach(target ${_libraries})
        _gtk_doc_get_cflags_for_target(_target_cflags ${target})
        _gtk_doc_get_ldflags_for_target(_target_ldflags ${target} "${_libraries}")
        list(APPEND _extra_cflags ${_target_cflags})
        list(APPEND _extra_ldflags ${_target_ldflags})
        list(APPEND _extra_ldpath $<TARGET_FILE_DIR:${target}>)

        list(APPEND _depends ${target})
    endforeach()

    # Link directories can't be specified per target, only for every target
    # under a given directory.
    get_property(all_library_directories DIRECTORY PROPERTY LINK_DIRECTORIES)
    foreach(library_dir ${all_library_directories})
        list(APPEND _extra_ldflags ${CMAKE_LIBRARY_PATH_FLAG}${library_dir})
        list(APPEND _extra_ldpath ${library_dir})
    endforeach()

    # a directory to store output.
    set(_output_dir "${CMAKE_CURRENT_BINARY_DIR}/${_doc_prefix}")
    set(_output_dir_stamp "${_output_dir}/dir.stamp")

    # set default sgml file if not specified
    set(_default_xml_file "${_output_dir}/${_doc_prefix}-docs.xml")
    get_filename_component(_default_xml_file ${_default_xml_file} ABSOLUTE)

    # a directory to store html output.
    set(_output_html_dir "${_output_dir}/html")
    set(_output_html_dir_stamp "${_output_dir}/html_dir.stamp")

    # The output files
    set(_output_decl_list "${_output_dir}/${_doc_prefix}-decl-list.txt")
    set(_output_decl "${_output_dir}/${_doc_prefix}-decl.txt")
    set(_output_overrides "${_output_dir}/${_doc_prefix}-overrides.txt")
    set(_output_sections "${_output_dir}/${_doc_prefix}-sections.txt")
    set(_output_types "${_output_dir}/${_doc_prefix}.types")

    set(_output_signals "${_output_dir}/${_doc_prefix}.signals")

    set(_output_unused "${_output_dir}/${_doc_prefix}-unused.txt")
    set(_output_undeclared "${_output_dir}/${_doc_prefix}-undeclared.txt")
    set(_output_undocumented "${_output_dir}/${_doc_prefix}-undocumented.txt")

    set(_output_xml_dir "${_output_dir}/xml")
    set(_output_sgml_stamp "${_output_dir}/sgml.stamp")

    set(_output_html_stamp "${_output_dir}/html.stamp")

    # add a command to create output directory
    add_custom_command(
        OUTPUT "${_output_dir_stamp}" "${_output_dir}"
        COMMAND ${CMAKE_COMMAND} -E make_directory "${_output_dir}"
        COMMAND ${CMAKE_COMMAND} -E touch ${_output_dir_stamp}
        VERBATIM)

    set(_ignore_headers_opt "")
    if(_ignore_headers)
        set(_ignore_headers_opt "--ignore-headers=")
        foreach(_header ${_ignore_headers})
            set(_ignore_headers_opt "${_ignore_headers_opt}${_header} ")
        endforeach(_header ${_ignore_headers})
    endif(_ignore_headers)

    foreach(source_dir ${GTK_DOC_SOURCE})
        set(_source_dirs_opt ${_source_dirs_opt} --source-dir=${source_dir})
    endforeach()

    # add a command to scan the input
    add_custom_command(
        OUTPUT
            "${_output_decl_list}"
            "${_output_decl}"
            "${_output_overrides}"
            "${_output_sections}"
            "${_output_types}"
        DEPENDS
            "${_output_dir_stamp}"
            ${_depends}
        COMMAND
            ${GTKDOC_SCAN_EXE}
            --module=${_doc_prefix}
            ${_ignore_headers_opt}
            ${_source_dirs_opt}
            --rebuild-sections
            --rebuild-types
        WORKING_DIRECTORY ${_output_dir}
        VERBATIM)

    # add a command to scan the input via gtkdoc-scangobj
    # This is such a disgusting hack!
    add_custom_command(
        OUTPUT
            ${_output_signals}
        DEPENDS
            ${_output_types}
        COMMAND ${CMAKE_COMMAND}
            -D "GTKDOC_SCANGOBJ_EXE:STRING=${GTKDOC_SCANGOBJ_EXE}"
            -D "doc_prefix:STRING=${_doc_prefix}"
            -D "output_types:STRING=${_output_types}"
            -D "output_dir:STRING=${_output_dir}"
            -D "EXTRA_CFLAGS:STRING=${_extra_cflags}"
            -D "EXTRA_LDFLAGS:STRING=${_extra_ldflags}"
            -D "EXTRA_LDPATH:STRING=${_extra_ldpath}"
            -P ${GTKDOC_SCANGOBJ_WRAPPER}
        WORKING_DIRECTORY "${_output_dir}"
        VERBATIM)

    set(_copy_xml_if_needed "")
    if(_xml_file)
        get_filename_component(_xml_file ${_xml_file} ABSOLUTE)
        set(_copy_xml_if_needed
            COMMAND ${CMAKE_COMMAND} -E copy "${_xml_file}" "${_default_xml_file}")
    endif(_xml_file)

    set(_remove_xml_if_needed "")
    if(_xml_file)
        set(_remove_xml_if_needed
            COMMAND ${CMAKE_COMMAND} -E remove ${_default_xml_file})
    endif(_xml_file)

    # add a command to make the database
    add_custom_command(
        OUTPUT
            ${_output_sgml_stamp}
            ${_default_xml_file}
        DEPENDS
            ${_output_types}
            ${_output_signals}
            ${_output_sections}
            ${_output_overrides}
            ${_depends}
        ${_remove_xml_if_needed}
        COMMAND ${CMAKE_COMMAND} -E remove_directory ${_output_xml_dir}
        ${_copy_xml_if_needed}
        COMMAND ${GTKDOC_MKDB_EXE}
            --module=${_doc_prefix}
            ${_source_dirs_opt}
            --source-suffixes=${_doc_source_suffixes}
            --output-format=xml
            --main-sgml-file=${_default_xml_file}
        WORKING_DIRECTORY "${_output_dir}"
        VERBATIM)

    # add a command to create html directory
    add_custom_command(
        OUTPUT "${_output_html_dir_stamp}" "${_output_html_dir}"
        COMMAND ${CMAKE_COMMAND} -E make_directory ${_output_html_dir}
        COMMAND ${CMAKE_COMMAND} -E touch ${_output_html_dir_stamp}
        VERBATIM)

    # add a command to output HTML
    add_custom_command(
        OUTPUT
            ${_output_html_stamp}
        DEPENDS
            ${_output_html_dir_stamp}
            ${_output_sgml_stamp}
            ${_xml_file}
            ${_depends}
        ${_copy_xml_if_needed}
        # The binary dir needs adding to --path in order for mkhtml to pick up
        # any version.xml file there might be in there
        COMMAND
            cd ${_output_html_dir} && ${GTKDOC_MKHTML_EXE}
                ${_doc_prefix}
                ${_default_xml_file}
        COMMAND
            cd ${_output_dir} && ${GTKDOC_FIXXREF_EXE}
                --module=${_doc_prefix}
                --module-dir=${_output_html_dir}
                ${_fixxrefopts}
        COMMENT
            "Generating HTML documentation for ${_doc_prefix} module with gtkdoc-mkhtml"
        VERBATIM)

    add_custom_target(doc-${_doc_prefix}
        DEPENDS "${_output_html_stamp}")
endfunction(gtk_doc_add_module)

# These two functions reimplement some of the core logic of CMake, in order
# to generate compiler and linker flags from the relevant target properties.
# It sucks that we have to do this, but CMake's own code for this doesn't seem
# to be reusable -- there's no way to say "tell me the flags that you would
# pass to a linker for this target".

function(_gtk_doc_get_cflags_for_target result_var target)
    get_target_property(target_definitions ${target} COMPILE_DEFINITIONS)
    if(target_definitions)
        list(APPEND cflags ${target_definitions})
    endif()

    get_target_property(target_options ${target} COMPILE_OPTIONS)
    if(target_options)
        list(APPEND cflags ${target_options})
    endif()

    get_target_property(target_include_dirs ${target} INCLUDE_DIRECTORIES)
    foreach(target_include_dir ${target_include_dirs})
        list(APPEND cflags -I${target_include_dir})
    endforeach()

    list(REMOVE_DUPLICATES cflags)
    list(SORT cflags)

    set(${result_var} ${cflags} PARENT_SCOPE)
endfunction()

function(_gtk_doc_get_ldflags_for_target result_var target all_targets)
    get_target_property(target_link_flags ${target} LINK_FLAGS)
    if(target_link_flags)
        list(APPEND ldflags ${target_link_flags})
    endif()

    get_target_property(target_link_libraries ${target} LINK_LIBRARIES)
    foreach(target_library ${target_link_libraries})
        # The IN_LIST operator is new in CMake 3.3, so I've tried to avoid using it.
        list(FIND all_targets ${target_library} target_library_is_explicit_dependency)
        if(NOT ${target_library_is_explicit_dependency} EQUAL -1)
            # This target is part of the current project. We will add it to
            # LDFLAGS explicitly, so don't try to add it with -l<target> as
            # well. In fact, we can't do that, as the containing directory
            # probably won't be in the linker search path, and we can't find
            # that out and add it ourselves.
        elseif(EXISTS ${target_library})
            # Pass the filename directly to the linker.
            list(APPEND ldflags "${target_library}")
        else()
            # Pass -l<filename> to the linker.
            list(APPEND ldflags "${CMAKE_LINK_LIBRARY_FLAG}${target_library}")
        endif()
    endforeach()

    # Link in the actual target, as well.
    list(APPEND ldflags $<TARGET_FILE:${target}>)

    list(REMOVE_DUPLICATES ldflags)
    list(SORT ldflags)

    set(${result_var} ${ldflags} PARENT_SCOPE)
endfunction()