Documentation.cmake 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. # po4a/docbook documentation support for CMake
  2. # - see documentation of add_docbook()
  3. #
  4. # Copyright (C) 2016 Julian Andres Klode <jak@debian.org>.
  5. #
  6. # Permission is hereby granted, free of charge, to any person
  7. # obtaining a copy of this software and associated documentation files
  8. # (the "Software"), to deal in the Software without restriction,
  9. # including without limitation the rights to use, copy, modify, merge,
  10. # publish, distribute, sublicense, and/or sell copies of the Software,
  11. # and to permit persons to whom the Software is furnished to do so,
  12. # subject to the following conditions:
  13. #
  14. # The above copyright notice and this permission notice shall be
  15. # included in all copies or substantial portions of the Software.
  16. #
  17. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  18. # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  19. # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  20. # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  21. # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  22. # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  23. # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  24. # SOFTWARE.
  25. find_path(DOCBOOK_XSL manpages/docbook.xsl
  26. # Debian
  27. /usr/share/xml/docbook/stylesheet/docbook-xsl
  28. /usr/share/xml/docbook/stylesheet/nwalsh
  29. # OpenSUSE
  30. /usr/share/xml/docbook/stylesheet/nwalsh/current
  31. # Arch
  32. /usr/share/xml/docbook/xsl-stylesheets
  33. # Fedora
  34. /usr/share/sgml/docbook/xsl-stylesheets
  35. #Brew
  36. /usr/local/Cellar/docbook-xsl/1.79.1/docbook-xsl/
  37. # Fink
  38. ${CMAKE_INSTALL_PREFIX}/share/xml/xsl/docbook-xsl
  39. # FreeBSD
  40. ${CMAKE_INSTALL_PREFIX}/share/xsl/docbook/
  41. NO_DEFAULT_PATH)
  42. if(NOT DOCBOOK_XSL)
  43. message(FATAL_ERROR "Could not find docbook xsl")
  44. endif()
  45. configure_file(${CMAKE_CURRENT_SOURCE_DIR}/docbook-text-style.xsl.cmake.in
  46. ${CMAKE_CURRENT_BINARY_DIR}/docbook-text-style.xsl)
  47. configure_file(${CMAKE_CURRENT_SOURCE_DIR}/docbook-html-style.xsl.cmake.in
  48. ${CMAKE_CURRENT_BINARY_DIR}/docbook-html-style.xsl)
  49. configure_file(${CMAKE_CURRENT_SOURCE_DIR}/manpage-style.xsl.cmake.in
  50. ${CMAKE_CURRENT_BINARY_DIR}/manpage-style.xsl)
  51. # Split up a string of the form DOCUMENT[.DOCUMENT][.LANGUAGE][.SECTION].EXTENSION
  52. #
  53. # There might be up to two parts in the document name. The language must be
  54. # a two char language code like de, or a 5 char code of the form de_DE.
  55. function(po4a_components doc lang sec ext translated_full_document)
  56. get_filename_component(name ${translated_full_document} NAME)
  57. string(REPLACE "." ";" name "${name}") # Make it a list
  58. list(GET name 0 _doc) # First element is always the document
  59. list(GET name 1 _lang) # Second *might* be a language
  60. list(GET name -2 _sec) # Second-last *might* be a section
  61. list(GET name -1 _ext) # Last element is always the file type
  62. # If the language code is neither a file type, nor a section, nor a language
  63. # assume it is part of the file name and use the next component as the lang.
  64. if(_lang AND NOT _lang MATCHES "^(xml|dbk|[0-9]|[a-z][a-z]|[a-z][a-z]_[A-Z][A-Z])$")
  65. set(_doc "${_doc}.${_lang}")
  66. list(GET name 2 _lang)
  67. endif()
  68. # If no language is present, we get a section; both not present => type
  69. if(_lang MATCHES "xml|dbk|[0-9]")
  70. set(_lang "")
  71. endif()
  72. if(NOT _sec MATCHES "^[0-9]$") # A (manpage) section must be a number
  73. set(_sec "")
  74. endif()
  75. set(${doc} ${_doc} PARENT_SCOPE)
  76. set(${lang} ${_lang} PARENT_SCOPE)
  77. set(${sec} ${_sec} PARENT_SCOPE)
  78. set(${ext} ${_ext} PARENT_SCOPE)
  79. endfunction()
  80. # Process one document
  81. function(po4a_one stamp_out out full_document language deps)
  82. path_join(full_path "${CMAKE_CURRENT_SOURCE_DIR}" "${full_document}")
  83. po4a_components(document _ section ext "${full_document}")
  84. # Calculate target file name
  85. set(dest "${language}/${document}.${language}")
  86. if(section)
  87. set(dest "${dest}.${section}")
  88. endif()
  89. # po4a might drop files not translated enough, so build a stamp file
  90. set(stamp ${CMAKE_CURRENT_BINARY_DIR}/${dest}.po4a-stamp)
  91. add_custom_command(
  92. OUTPUT ${stamp}
  93. COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/${language}
  94. COMMAND po4a --previous --no-backups
  95. --package-name='${PROJECT_NAME}-doc'
  96. --package-version='${PACKAGE_VERSION}'
  97. --msgid-bugs-address='${PACKAGE_MAIL}'
  98. --translate-only ${dest}.${ext}
  99. --srcdir ${CMAKE_CURRENT_SOURCE_DIR}
  100. --destdir ${CMAKE_CURRENT_BINARY_DIR}
  101. ${CMAKE_CURRENT_SOURCE_DIR}/po4a.conf
  102. COMMAND ${CMAKE_COMMAND} -E touch ${stamp}
  103. COMMENT "Generating ${dest}.${ext} (or dropping it)"
  104. DEPENDS ${full_document} ${deps} po/${language}.po
  105. )
  106. # Return result
  107. set(${stamp_out} ${stamp} PARENT_SCOPE)
  108. set(${out} ${CMAKE_CURRENT_BINARY_DIR}/${dest}.${ext} PARENT_SCOPE)
  109. endfunction()
  110. function(xsltproc_one)
  111. set(generated "")
  112. set(options HTML TEXT MANPAGE)
  113. set(oneValueArgs STAMP STAMP_OUT FULL_DOCUMENT)
  114. set(multiValueArgs INSTALL DEPENDS)
  115. cmake_parse_arguments(DOC "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
  116. po4a_components(document language section ext "${DOC_FULL_DOCUMENT}")
  117. # Default parameters
  118. set(params
  119. --nonet
  120. --xinclude
  121. --stringparam chunk.quietly yes
  122. --stringparam man.output.quietly yes
  123. --path ${PROJECT_SOURCE_DIR}/vendor/${CURRENT_VENDOR}/
  124. --path ${CMAKE_CURRENT_SOURCE_DIR}/
  125. )
  126. # Parameters if localized
  127. if(language)
  128. list(APPEND params -stringparam l10n.gentext.default.language ${language})
  129. endif()
  130. path_join(full_input_path ${CMAKE_CURRENT_SOURCE_DIR} ${DOC_FULL_DOCUMENT})
  131. if (DOC_MANPAGE)
  132. if (language)
  133. set(manpage_output "${CMAKE_CURRENT_BINARY_DIR}/${language}/${document}.${section}")
  134. else()
  135. set(manpage_output "${CMAKE_CURRENT_BINARY_DIR}/${document}.${section}")
  136. endif()
  137. set(manpage_stylesheet "${CMAKE_CURRENT_BINARY_DIR}/manpage-style.xsl")
  138. set(manpage_params)
  139. install(FILES ${manpage_output}
  140. DESTINATION ${CMAKE_INSTALL_MANDIR}/${language}/man${section}
  141. OPTIONAL)
  142. endif()
  143. if (DOC_HTML)
  144. if (language)
  145. set(html_output "${CMAKE_CURRENT_BINARY_DIR}/${language}/${document}.${language}.html")
  146. else()
  147. set(html_output "${CMAKE_CURRENT_BINARY_DIR}/${document}.html")
  148. endif()
  149. set(html_params --stringparam base.dir ${html_output})
  150. set(html_stylesheet "${CMAKE_CURRENT_BINARY_DIR}/docbook-html-style.xsl")
  151. install(DIRECTORY ${html_output}
  152. DESTINATION ${DOC_INSTALL}
  153. OPTIONAL)
  154. endif()
  155. if (DOC_TEXT)
  156. if (language)
  157. set(text_output "${CMAKE_CURRENT_BINARY_DIR}/${language}/${document}.${language}.text")
  158. else()
  159. set(text_output "${CMAKE_CURRENT_BINARY_DIR}/${document}.text")
  160. endif()
  161. set(text_params --stringparam base.dir ${text_output})
  162. set(text_stylesheet "${CMAKE_CURRENT_BINARY_DIR}/docbook-text-style.xsl")
  163. file(RELATIVE_PATH text_output_relative ${CMAKE_CURRENT_BINARY_DIR} ${text_output})
  164. add_custom_command(OUTPUT ${text_output}.w3m-stamp
  165. COMMAND ${PROJECT_SOURCE_DIR}/CMake/run_if_exists.sh
  166. --stdout ${text_output}
  167. ${text_output}.html
  168. env LC_ALL=C.UTF-8 w3m -cols 78 -dump
  169. -o display_charset=UTF-8
  170. -no-graph -T text/html ${text_output}.html
  171. COMMAND ${CMAKE_COMMAND} -E touch ${text_output}.w3m-stamp
  172. COMMENT "Generating ${text_output_relative} (if not dropped by po4a)"
  173. DEPENDS "${text_output}.html.xsltproc-stamp"
  174. )
  175. list(APPEND generated ${text_output}.w3m-stamp)
  176. install(FILES ${text_output}
  177. DESTINATION ${DOC_INSTALL}
  178. OPTIONAL)
  179. set(text_output "${text_output}.html")
  180. endif()
  181. foreach(type in manpage html text)
  182. if (NOT ${type}_output)
  183. continue()
  184. endif()
  185. set(output ${${type}_output})
  186. set(stylesheet ${${type}_stylesheet})
  187. set(type_params ${${type}_params})
  188. file(RELATIVE_PATH output_relative ${CMAKE_CURRENT_BINARY_DIR} ${output})
  189. add_custom_command(OUTPUT ${output}.xsltproc-stamp
  190. COMMAND ${PROJECT_SOURCE_DIR}/CMake/run_if_exists.sh
  191. ${full_input_path}
  192. xsltproc ${params} ${type_params} -o ${output}
  193. ${stylesheet}
  194. ${full_input_path}
  195. COMMAND ${CMAKE_COMMAND} -E touch ${output}.xsltproc-stamp
  196. COMMENT "Generating ${output_relative} (if not dropped by po4a)"
  197. DEPENDS ${DOC_STAMP} ${DOC_DEPENDS})
  198. list(APPEND generated ${output}.xsltproc-stamp)
  199. endforeach()
  200. set(${DOC_STAMP_OUT} ${generated} PARENT_SCOPE)
  201. endfunction()
  202. # add_docbook(Name [ALL] [HTML] [TEXT] [MANPAGE]
  203. # [INSTALL install dir]
  204. # [DEPENDS depend ...]
  205. # [DOCUMENTS documents ...]
  206. # [LINGUAS lingua ...])
  207. #
  208. # Generate a target called name with all the documents being converted to
  209. # the chosen output formats and translated to the chosen languages using po4a.
  210. #
  211. # For the translation support, the po4a.conf must be written so that
  212. # translations for a document guide.xml are written to LANG/guide.LANG.xml,
  213. # and for a manual page man.5.xml to a file called LANG/man.LANG.5.xml.
  214. #
  215. # The guide and manual page names may also contain a second component separated
  216. # by a dot, it must however not be a valid language code.
  217. #
  218. # Note that po4a might chose not to generate a translated manual page for a
  219. # given language if the translation rate is not high enough. We deal with this
  220. # by creating stamp files.
  221. function(add_docbook target)
  222. set(generated "")
  223. set(options HTML TEXT MANPAGE ALL)
  224. set(oneValueArgs)
  225. set(multiValueArgs INSTALL DOCUMENTS LINGUAS DEPENDS)
  226. cmake_parse_arguments(DOC "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
  227. if (DOC_HTML)
  228. list(APPEND formats HTML)
  229. endif()
  230. if (DOC_TEXT)
  231. list(APPEND formats TEXT)
  232. endif()
  233. if (DOC_MANPAGE)
  234. list(APPEND formats MANPAGE)
  235. endif()
  236. foreach(document ${DOC_DOCUMENTS})
  237. foreach(lang ${DOC_LINGUAS})
  238. po4a_one(po4a_stamp po4a_out ${document} "${lang}" "${DOC_DEPENDS}")
  239. xsltproc_one(STAMP_OUT xslt_stamp
  240. STAMP ${po4a_stamp}
  241. FULL_DOCUMENT ${po4a_out}
  242. INSTALL ${DOC_INSTALL}
  243. ${formats})
  244. list(APPEND stamps ${xslt_stamp})
  245. endforeach()
  246. xsltproc_one(STAMP_OUT xslt_stamp
  247. STAMP ${document}
  248. FULL_DOCUMENT ${document}
  249. INSTALL ${DOC_INSTALL}
  250. ${formats})
  251. list(APPEND stamps ${xslt_stamp})
  252. endforeach()
  253. if (DOC_ALL)
  254. add_custom_target(${target} ALL DEPENDS ${stamps})
  255. else()
  256. add_custom_target(${target} DEPENDS ${stamps})
  257. endif()
  258. endfunction()
  259. # Add an update-po4a target
  260. function(add_update_po4a target pot header)
  261. set(WRITE_HEADER "")
  262. if (header)
  263. set(WRITE_HEADER
  264. COMMAND sed -n "/^\#$/,$p" ${pot} > ${pot}.headerfree
  265. COMMAND cat ${header} ${pot}.headerfree > ${pot}
  266. COMMAND rm ${pot}.headerfree
  267. )
  268. endif()
  269. add_custom_target(${target}
  270. COMMAND po4a --previous --no-backups --force --no-translations
  271. --msgmerge-opt --add-location=file
  272. --porefs noline,wrap
  273. --package-name=${PROJECT_NAME}-doc --package-version=${PACKAGE_VERSION}
  274. --msgid-bugs-address=${PACKAGE_MAIL} po4a.conf
  275. ${WRITE_HEADER}
  276. VERBATIM
  277. WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
  278. )
  279. endfunction()