diff options
author | Julian Andres Klode <jak@debian.org> | 2016-08-08 21:53:46 +0200 |
---|---|---|
committer | Julian Andres Klode <jak@debian.org> | 2016-08-10 16:17:18 +0200 |
commit | 10ec2d23f14cf5d3e4835d9bcb57d0937f803e6a (patch) | |
tree | 6b94f158da77f56a59099078a178bb5832f2d9a7 /CMake | |
parent | 0d04a4987feb9ec45ddfa03270e20f76cae02a84 (diff) | |
download | apt-10ec2d23f14cf5d3e4835d9bcb57d0937f803e6a.tar.gz |
CMake: Rewrite existing Documentation support and add doxygen
This can now build all documentation. It should also be fairly
reusable for other projects, as long as they follow the same
naming scheme for the po4a output files and set the PACKAGE_*
variables used here.
We could have done all translations in a single call to po4a
like the makefile based buildsystem does. While that would
have made the output slightly nicer, this solution offers a
huge performance gain because it can translate the documents
in parallel, which also means that the xsltproc stage does not
have to wait for all translations to be done first.
You might think that the add_custom_command() should list the
actual output files as BYPRODUCTS. This is not true however:
Because the files are not always generated, Ninja will think
missing byproducts mean that the target is out of date - which
is not what we want.
Finally, also add the missing doxygen support. Note that the
packaging script cleans up some md5 and map files created by
doxygen, otherwise it is fairly boring.
Diffstat (limited to 'CMake')
-rw-r--r-- | CMake/Documentation.cmake | 335 | ||||
-rwxr-xr-x | CMake/run_if_exists.sh | 16 |
2 files changed, 259 insertions, 92 deletions
diff --git a/CMake/Documentation.cmake b/CMake/Documentation.cmake index 98e07176b..9e7135ea4 100644 --- a/CMake/Documentation.cmake +++ b/CMake/Documentation.cmake @@ -1,4 +1,7 @@ -# Copyright (C) 2009, 2016 Julian Andres Klode <jak@debian.org>. +# 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 @@ -20,115 +23,263 @@ # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -function(add_docbook target sourcefiles installdest) - foreach(file ${sourcefiles}) - get_filename_component(relfile ${file} NAME) - string(REPLACE ".dbk" "" manual ${relfile}) - get_filename_component(absolute ${file} ABSOLUTE) - - add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${manual}.html/ - COMMAND xsltproc --nonet --novalid --xinclude - --stringparam base.dir ${CMAKE_CURRENT_BINARY_DIR}/${manual}.html/ - --path ${CMAKE_CURRENT_SOURCE_DIR}/../vendor/${CURRENT_VENDOR}/ - --path ${CMAKE_CURRENT_SOURCE_DIR}/ - ${CMAKE_CURRENT_SOURCE_DIR}/docbook-html-style.xsl - ${absolute} - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - DEPENDS ${file} - ) - set(commands ${commands} ${CMAKE_CURRENT_BINARY_DIR}/${manual}.html) - if (NOT ${installdest} EQUAL "" ) - install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${manual}.html - DESTINATION ${installdest}) - endif() - endforeach(file ${sourcefiles}) - add_custom_target(${target} ALL DEPENDS ${commands}) +# 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() -function(add_po4a type master po target deps) - add_custom_command(OUTPUT ${target} - COMMAND po4a-translate --keep 0 -f ${type} -m ${master} - -p ${po} -l ${target} - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - DEPENDS ${deps} ${master} ${po}) +# Process one document +function(po4a_one stamp_out out full_document language deps) + path_join(full_path "${CMAKE_CURRENT_SOURCE_DIR}" "${full_document}") + po4a_components(document _ section ext "${full_document}") + + # Calculate target file name + set(dest "${language}/${document}.${language}") + if(section) + set(dest "${dest}.${section}") + 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}-doc' + --package-version='${PACKAGE_VERSION}' + --msgid-bugs-address='${PACKAGE_MAIL}' + --translate-only ${dest}.${ext} + --srcdir ${CMAKE_CURRENT_SOURCE_DIR} + --destdir ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/po4a.conf + COMMAND ${CMAKE_COMMAND} -E touch ${stamp} + COMMENT "Generating ${dest}.${ext} (or dropping it)" + DEPENDS ${full_document} ${deps} po/${language}.po + ) + # Return result + set(${stamp_out} ${stamp} PARENT_SCOPE) + set(${out} ${CMAKE_CURRENT_BINARY_DIR}/${dest}.${ext} 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}) -# Macro for XML man pages. -function(add_xml_manpages target manpages translations entities) - foreach(manpage ${manpages}) - string(LENGTH ${manpage} manpage_length) - math(EXPR manpage_length ${manpage_length}-1) - string(SUBSTRING ${manpage} ${manpage_length} 1 section) - - add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${manpage} - COMMAND xsltproc --path ${CMAKE_CURRENT_SOURCE_DIR}/../vendor/${CURRENT_VENDOR}/ - --path ${CMAKE_CURRENT_SOURCE_DIR}/ - ${CMAKE_CURRENT_SOURCE_DIR}/manpage-style.xsl - ${CMAKE_CURRENT_SOURCE_DIR}/${manpage}.xml - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${manpage}.xml - DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/manpage-style.xsl - ) + 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_SOURCE_DIR}/manpage-style.xsl") + + 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_SOURCE_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_SOURCE_DIR}/docbook-text-style.xsl") - set(commands ${commands} ${CMAKE_CURRENT_BINARY_DIR}/${manpage}) + file(RELATIVE_PATH text_output_relative ${CMAKE_CURRENT_BINARY_DIR} ${text_output}) - install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${manpage} - DESTINATION ${CMAKE_INSTALL_MANDIR}/man${section}) + 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) - # Add the translations for the manpage. - foreach(translation ${translations}) - set(entities) - # transdir = shortcut to the output directory for translations. - set(transdir ${CMAKE_CURRENT_BINARY_DIR}/${translation}) + install(FILES ${text_output} + DESTINATION ${DOC_INSTALL} + OPTIONAL) + set(text_output "${text_output}.html") + endif() - add_po4a(docbook ${manpage}.xml po/${translation}.po - ${transdir}/${manpage}.xml "${ent_cmds}") + 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 ${transdir}/${manpage} - COMMAND xsltproc --path ${CMAKE_CURRENT_SOURCE_DIR}/../vendor/${CURRENT_VENDOR}/ - --path ${CMAKE_CURRENT_SOURCE_DIR}/ - --stringparam l10n.gentext.default.language ${translation} - ${CMAKE_CURRENT_SOURCE_DIR}/manpage-style.xsl - ${transdir}/${manpage}.xml - WORKING_DIRECTORY ${transdir} - DEPENDS ${transdir}/${manpage}.xml - DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/manpage-style.xsl) + 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}) - set(nls-cmd ${nls-cmd} ${transdir}/${manpage}) - install(FILES ${transdir}/${manpage} - DESTINATION ${CMAKE_INSTALL_MANDIR}/${translation}/man${section}) + list(APPEND generated ${output}.xsltproc-stamp) + endforeach() + + set(${DOC_STAMP_OUT} ${generated} PARENT_SCOPE) +endfunction() - endforeach(translation ${translations}) - endforeach(manpage ${manpages}) - add_custom_target(${target} ALL DEPENDS ${commands}) - # Sort the list of the translations. - list(SORT nls-cmd) - add_custom_target(nls-${target} ALL DEPENDS ${nls-cmd}) +# 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(multiValueArgs INSTALL DOCUMENTS LINGUAS 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_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 "") -function(add_manpages target manpages translations) - foreach(man ${manpages}) - string(LENGTH ${man} manpage_length) - math(EXPR manpage_length ${manpage_length}-1) - string(SUBSTRING ${man} ${manpage_length} 1 section) - install(FILES ${man} DESTINATION ${CMAKE_INSTALL_MANDIR}/man${section}) - - if (USE_NLS) - foreach(translation ${translations}) - set(transdir ${CMAKE_CURRENT_BINARY_DIR}/${translation}) - add_po4a(man ${man} po/${translation}.po ${transdir}/${man} "") - install(FILES ${transdir}/${man} - DESTINATION ${CMAKE_INSTALL_MANDIR}/${translation}/man${section}) - set(files ${files} ${transdir}/${man}) - endforeach(translation ${translations}) - endif() - endforeach(man ${manpages}) - add_custom_target(${target} ALL DEPENDS ${files}) + 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 noline,wrap + --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() diff --git a/CMake/run_if_exists.sh b/CMake/run_if_exists.sh new file mode 100755 index 000000000..97edd4c1a --- /dev/null +++ b/CMake/run_if_exists.sh @@ -0,0 +1,16 @@ +#!/bin/sh +# Small helper for running a command +out="" +if [ "$1" = "--stdout" ]; then + out="$2" + shift 2 +fi + +if [ -e "$1" ]; then + shift + if [ "$out" ]; then + exec "$@" > $out + else + exec "$@" + fi +fi |