summaryrefslogtreecommitdiffstats
path: root/CMake/Documentation.cmake
blob: 1df0960a4e43d8e9f39c887da1ebc9d8e60d063d (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
# po4a/docbook documentation support for CMake
# - see documentation of add_docbook()
#
# Copyright (C) 2016 Julian Andres Klode <jak@debian.org>.
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation files
# (the "Software"), to deal in the Software without restriction,
# including without limitation the rights to use, copy, modify, merge,
# publish, distribute, sublicense, and/or sell copies of the Software,
# and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.


find_path(DOCBOOK_XSL manpages/docbook.xsl
         # Debian
         /usr/share/xml/docbook/stylesheet/docbook-xsl
         /usr/share/xml/docbook/stylesheet/nwalsh
         # OpenSUSE
         /usr/share/xml/docbook/stylesheet/nwalsh/current
         # Arch
          /usr/share/xml/docbook/xsl-stylesheets
         # Fedora
         /usr/share/sgml/docbook/xsl-stylesheets
         # Fink
         ${CMAKE_INSTALL_PREFIX}/share/xml/xsl/docbook-xsl
         # FreeBSD
         ${CMAKE_INSTALL_PREFIX}/share/xsl/docbook/
         NO_DEFAULT_PATH)

if(NOT DOCBOOK_XSL)
    message(FATAL_ERROR "Could not find docbook xsl")
endif()

configure_file(${CMAKE_CURRENT_SOURCE_DIR}/docbook-text-style.xsl.cmake.in
                ${CMAKE_CURRENT_BINARY_DIR}/docbook-text-style.xsl)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/docbook-html-style.xsl.cmake.in
                ${CMAKE_CURRENT_BINARY_DIR}/docbook-html-style.xsl)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/manpage-style.xsl.cmake.in
                ${CMAKE_CURRENT_BINARY_DIR}/manpage-style.xsl)


# Split up a string of the form DOCUMENT[.DOCUMENT][.LANGUAGE][.SECTION].EXTENSION
#
# There might be up to two parts in the document name. The language must be
# a two char language code like de, or a 5 char code of the form de_DE.
function(po4a_components doc lang sec ext translated_full_document)
    get_filename_component(name ${translated_full_document} NAME)
    string(REPLACE "." ";" name "${name}")          # Make it a list

    list(GET name 0 _doc)   # First element is always the document
    list(GET name 1 _lang)  # Second *might* be a language
    list(GET name -2 _sec)  # Second-last *might* be a section
    list(GET name -1 _ext)  # Last element is always the file type

    # If the language code is neither a file type, nor a section, nor a language
    # assume it is part of the file name and use the next component as the lang.
    if(_lang AND NOT _lang MATCHES "^(xml|dbk|[0-9]|[a-z][a-z]|[a-z][a-z]_[A-Z][A-Z])$")
        set(_doc "${_doc}.${_lang}")
        list(GET name 2 _lang)
    endif()
    # If no language is present, we get a section; both not present => type
    if(_lang MATCHES "xml|dbk|[0-9]")
        set(_lang "")
    endif()
    if(NOT _sec MATCHES "^[0-9]$")        # A (manpage) section must be a number
        set(_sec "")
    endif()

    set(${doc} ${_doc} PARENT_SCOPE)
    set(${lang} ${_lang} PARENT_SCOPE)
    set(${sec} ${_sec} PARENT_SCOPE)
    set(${ext} ${_ext} PARENT_SCOPE)
endfunction()


# Process one document
function(po4a_one stamp_out out full_document language deps)
    path_join(full_path "${CMAKE_CURRENT_SOURCE_DIR}" "${full_document}")
    if (full_document MATCHES "\.ent$")
        set(dest "${language}/${full_document}")
        set(full_dest "${dest}")
    else()
        po4a_components(document _ section ext "${full_document}")

        # Calculate target file name
        set(dest "${language}/${document}.${language}")
        if(section)
            set(dest "${dest}.${section}")
        endif()
        set(full_dest "${dest}.${ext}")
    endif()

    # po4a might drop files not translated enough, so build a stamp file
    set(stamp ${CMAKE_CURRENT_BINARY_DIR}/${dest}.po4a-stamp)
    add_custom_command(
        OUTPUT ${stamp}
        COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/${language}
        COMMAND po4a --previous --no-backups
                     --package-name='${PROJECT_NAME}-doc'
                     --package-version='${PACKAGE_VERSION}'
                     --msgid-bugs-address='${PACKAGE_MAIL}'
                     --translate-only ${full_dest}
                     --srcdir ${CMAKE_CURRENT_SOURCE_DIR}
                     --destdir ${CMAKE_CURRENT_BINARY_DIR}
                      ${CMAKE_CURRENT_SOURCE_DIR}/po4a.conf
        COMMAND ${CMAKE_COMMAND} -E touch ${stamp}
        COMMENT "Generating ${full_dest} (or dropping it)"
        DEPENDS ${full_document} ${deps} po/${language}.po
    )
    # Return result
    set(${stamp_out} ${stamp} PARENT_SCOPE)
    set(${out} ${CMAKE_CURRENT_BINARY_DIR}/${full_dest} PARENT_SCOPE)
endfunction()

function(xsltproc_one)
    set(generated "")
    set(options HTML TEXT MANPAGE)
    set(oneValueArgs STAMP STAMP_OUT FULL_DOCUMENT)
    set(multiValueArgs INSTALL DEPENDS)
    cmake_parse_arguments(DOC "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

    po4a_components(document language section ext "${DOC_FULL_DOCUMENT}")

    # Default parameters
    set(params
        --nonet
        --xinclude
        --stringparam chunk.quietly yes
        --stringparam man.output.quietly yes
        --path ${PROJECT_SOURCE_DIR}/vendor/${CURRENT_VENDOR}/
        --path ${CMAKE_CURRENT_SOURCE_DIR}/
    )

    # Parameters if localized
    if(language)
        list(APPEND params -stringparam l10n.gentext.default.language ${language})
    endif()

    path_join(full_input_path ${CMAKE_CURRENT_SOURCE_DIR} ${DOC_FULL_DOCUMENT})

    if (DOC_MANPAGE)
        if (language)
        set(manpage_output "${CMAKE_CURRENT_BINARY_DIR}/${language}/${document}.${section}")
        else()
        set(manpage_output "${CMAKE_CURRENT_BINARY_DIR}/${document}.${section}")
        endif()
        set(manpage_stylesheet "${CMAKE_CURRENT_BINARY_DIR}/manpage-style.xsl")
        set(manpage_params)

        install(FILES ${manpage_output}
                DESTINATION ${CMAKE_INSTALL_MANDIR}/${language}/man${section}
                OPTIONAL)
    endif()
    if (DOC_HTML)
        if (language)
        set(html_output "${CMAKE_CURRENT_BINARY_DIR}/${language}/${document}.${language}.html")
        else()
        set(html_output "${CMAKE_CURRENT_BINARY_DIR}/${document}.html")
        endif()
        set(html_params --stringparam base.dir ${html_output})
        set(html_stylesheet "${CMAKE_CURRENT_BINARY_DIR}/docbook-html-style.xsl")
        install(DIRECTORY ${html_output}
                DESTINATION ${DOC_INSTALL}
                OPTIONAL)

    endif()
    if (DOC_TEXT)
        if (language)
        set(text_output "${CMAKE_CURRENT_BINARY_DIR}/${language}/${document}.${language}.text")
        else()
        set(text_output "${CMAKE_CURRENT_BINARY_DIR}/${document}.text")
        endif()
        set(text_params --stringparam base.dir ${text_output})
        set(text_stylesheet "${CMAKE_CURRENT_BINARY_DIR}/docbook-text-style.xsl")

        file(RELATIVE_PATH text_output_relative ${CMAKE_CURRENT_BINARY_DIR} ${text_output})

        add_custom_command(OUTPUT ${text_output}.w3m-stamp
                            COMMAND ${PROJECT_SOURCE_DIR}/CMake/run_if_exists.sh
                                    --stdout ${text_output}
                                    ${text_output}.html
                                    env LC_ALL=C.UTF-8 w3m -cols 78 -dump
                                    -o display_charset=UTF-8
                                    -no-graph -T text/html ${text_output}.html
                            COMMAND ${CMAKE_COMMAND} -E touch ${text_output}.w3m-stamp
                            COMMENT "Generating ${text_output_relative} (if not dropped by po4a)"
                            DEPENDS "${text_output}.html.xsltproc-stamp"
                            )
        list(APPEND generated ${text_output}.w3m-stamp)

        install(FILES ${text_output}
                DESTINATION ${DOC_INSTALL}
                OPTIONAL)
        set(text_output "${text_output}.html")
    endif()

    foreach(type in manpage html text)
        if (NOT ${type}_output)
            continue()
        endif()

        set(output ${${type}_output})
        set(stylesheet ${${type}_stylesheet})
        set(type_params ${${type}_params})
        file(RELATIVE_PATH output_relative ${CMAKE_CURRENT_BINARY_DIR} ${output})

        add_custom_command(OUTPUT ${output}.xsltproc-stamp
                COMMAND ${PROJECT_SOURCE_DIR}/CMake/run_if_exists.sh
                        ${full_input_path}
                        xsltproc ${params} ${type_params} -o ${output}
                                 ${stylesheet}
                                 ${full_input_path}
                COMMAND ${CMAKE_COMMAND} -E touch ${output}.xsltproc-stamp
                COMMENT "Generating ${output_relative} (if not dropped by po4a)"
                DEPENDS ${DOC_STAMP} ${DOC_DEPENDS})

        list(APPEND generated ${output}.xsltproc-stamp)
    endforeach()

    set(${DOC_STAMP_OUT} ${generated} PARENT_SCOPE)
endfunction()


# add_docbook(Name [ALL] [HTML] [TEXT] [MANPAGE]
#             [INSTALL install dir]
#             [DEPENDS depend ...]
#             [DOCUMENTS documents ...]
#             [LINGUAS lingua ...])
#
# Generate a target called name with all the documents being converted to
# the chosen output formats and translated to the chosen languages using po4a.
#
# For the translation support, the po4a.conf must be written so that
# translations for a document guide.xml are written to LANG/guide.LANG.xml,
# and for a manual page man.5.xml to a file called LANG/man.LANG.5.xml.
#
# The guide and manual page names may also contain a second component separated
# by a dot, it must however not be a valid language code.
#
# Note that po4a might chose not to generate a translated manual page for a
# given language if the translation rate is not high enough. We deal with this
# by creating stamp files.
function(add_docbook target)
    set(generated "")
    set(options HTML TEXT MANPAGE ALL)
    set(oneValueArgs)
    set(multiValueArgs INSTALL DOCUMENTS LINGUAS TRANSLATED_ENTITIES DEPENDS)
    cmake_parse_arguments(DOC "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

    if (DOC_HTML)
        list(APPEND formats HTML)
    endif()
    if (DOC_TEXT)
        list(APPEND formats TEXT)
    endif()
    if (DOC_MANPAGE)
        list(APPEND formats MANPAGE)
    endif()

    foreach(document ${DOC_TRANSLATED_ENTITIES})
        foreach(lang ${DOC_LINGUAS})
            po4a_one(po4a_stamp po4a_out ${document} "${lang}" "")
            list(APPEND DOC_DEPENDS ${po4a_stamp})
        endforeach()
    endforeach()

    foreach(document ${DOC_DOCUMENTS})
        foreach(lang ${DOC_LINGUAS})
            po4a_one(po4a_stamp po4a_out ${document} "${lang}" "${DOC_DEPENDS}")
            xsltproc_one(STAMP_OUT xslt_stamp
                         STAMP ${po4a_stamp}
                         FULL_DOCUMENT ${po4a_out}
                         INSTALL ${DOC_INSTALL}
                         ${formats})

            list(APPEND stamps ${xslt_stamp})
        endforeach()
            xsltproc_one(STAMP_OUT xslt_stamp
                         STAMP ${document}
                         FULL_DOCUMENT ${document}
                         INSTALL ${DOC_INSTALL}
                         ${formats})

            list(APPEND stamps ${xslt_stamp})
    endforeach()

    if (DOC_ALL)
        add_custom_target(${target} ALL DEPENDS ${stamps})
    else()
        add_custom_target(${target} DEPENDS ${stamps})
    endif()
endfunction()

# Add an update-po4a target
function(add_update_po4a target pot header)
    set(WRITE_HEADER "")

    if (header)
        set(WRITE_HEADER
            COMMAND sed -n "/^\#$/,$p" ${pot} > ${pot}.headerfree
            COMMAND cat ${header} ${pot}.headerfree > ${pot}
            COMMAND rm ${pot}.headerfree
        )
    endif()
    add_custom_target(${target}
        COMMAND po4a --previous --no-backups --force --no-translations
                --msgmerge-opt --add-location=file
                --porefs file
                --package-name=${PROJECT_NAME}-doc --package-version=${PACKAGE_VERSION}
                --msgid-bugs-address=${PACKAGE_MAIL} po4a.conf
        ${WRITE_HEADER}
        VERBATIM
        WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
    )
endfunction()