-# 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
# 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})
+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()
-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_NAME}-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_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)
- set(commands ${commands} ${CMAKE_CURRENT_BINARY_DIR}/${manpage})
+ 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")
- install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${manpage}
- DESTINATION ${CMAKE_INSTALL_MANDIR}/man${section})
+ file(RELATIVE_PATH text_output_relative ${CMAKE_CURRENT_BINARY_DIR} ${text_output})
- # 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})
+ 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_po4a(docbook ${manpage}.xml po/${translation}.po
- ${transdir}/${manpage}.xml "${ent_cmds}")
+ 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()
- 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)
+ set(output ${${type}_output})
+ set(stylesheet ${${type}_stylesheet})
+ set(type_params ${${type}_params})
+ file(RELATIVE_PATH output_relative ${CMAKE_CURRENT_BINARY_DIR} ${output})
- set(nls-cmd ${nls-cmd} ${transdir}/${manpage})
- install(FILES ${transdir}/${manpage}
- DESTINATION ${CMAKE_INSTALL_MANDIR}/${translation}/man${section})
+ 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})
- endforeach(translation ${translations})
- endforeach(manpage ${manpages})
+ list(APPEND generated ${output}.xsltproc-stamp)
+ endforeach()
- 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})
+ set(${DOC_STAMP_OUT} ${generated} PARENT_SCOPE)
endfunction()
-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})
+# 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 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 "")
+
+ 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()