find_asciidoc_bits.cmake revision 0bbfda8a
1# 2# Find and setup asciidoc[tor] bits 3# 4 5 6# First see if we can find the programs 7find_program(ASCIIDOCTOR asciidoctor) 8find_program(ASCIIDOC asciidoc) 9find_program(A2X a2x) 10find_program(DBLATEX dblatex) 11find_program(XMLTO xmlto) 12 13 14# If we have asciidoctor, we need to figure out the version, as manpage 15# output is relatively new. 16if(ASCIIDOCTOR) 17 execute_process( 18 COMMAND ${ASCIIDOCTOR} --version 19 RESULT_VARIABLE _adoctor_result 20 OUTPUT_VARIABLE _adoctor_verout 21 ERROR_QUIET 22 ) 23 if(NOT ${_adoctor_result} EQUAL "0") 24 # Err... 25 message(WARNING "Unexpected result trying asciidoctor --version.") 26 set(_adoctor_verout "Asciidoctor 0.0.0 FAKE") 27 endif() 28 unset(_adoctor_result) 29 30 # Break out the version. 31 set(_adoctor_veregex "Asciidoctor ([0-9]+\\.[0-9]+\\.[0-9]+).*") 32 string(REGEX REPLACE ${_adoctor_veregex} "\\1" 33 ASCIIDOCTOR_VERSION ${_adoctor_verout}) 34 unset(_adoctor_verout) 35 unset(_adoctor_veregex) 36 message(STATUS "Found asciidoctor (${ASCIIDOCTOR}) version ${ASCIIDOCTOR_VERSION}") 37 38 # 1.5.3 is the first release that can write manpages natively. This 39 # means 1.5.3 dev versions after a certain point can as well; assume 40 # anybody running a 1.5.3 dev is keeping up well enough that it can 41 # DTRT too. We assume any version can do HTML. 42 set(ASCIIDOCTOR_CAN_MAN 0) 43 set(ASCIIDOCTOR_CAN_HTML 1) 44 set(ASCIIDOCTOR_CAN_DBXML 1) 45 if(${ASCIIDOCTOR_VERSION} VERSION_GREATER "1.5.2") 46 set(ASCIIDOCTOR_CAN_MAN 1) 47 elseif(${ASCIIDOCTOR_VERSION} VERSION_LESS "0.0.1") 48 set(ASCIIDOCTOR_CAN_HTML 0) 49 set(ASCIIDOCTOR_CAN_DBXML 0) 50 endif() 51 52 # dblatex PDF output works fine with docbook5. xmlto/docbook XSL 53 # manpage generation doesn't, so it has to override this. 54 set(ASCIIDOCTOR_DB_VER 5) 55endif(ASCIIDOCTOR) 56 57 58# For asciidoc, it doesn't really matter, but look up the version for 59# cosmetics anyway 60if(ASCIIDOC) 61 execute_process( 62 COMMAND ${ASCIIDOC} --version 63 RESULT_VARIABLE _adoc_result 64 OUTPUT_VARIABLE _adoc_verout 65 ERROR_QUIET 66 ) 67 if(NOT ${_adoc_result} EQUAL "0") 68 # Err... 69 message(WARNING "Unexpected result trying asciidoc --version.") 70 set(_adoc_verout "asciidoc 0.0.0") 71 endif() 72 unset(_adoc_result) 73 74 # Break out the version. 75 set(_adoc_veregex "asciidoc ([0-9]+\\.[0-9]+\\.[0-9]+).*") 76 string(REGEX REPLACE ${_adoc_veregex} "\\1" 77 ASCIIDOC_VERSION ${_adoc_verout}) 78 unset(_adoc_verout) 79 unset(_adoc_veregex) 80 message(STATUS "Found asciidoc (${ASCIIDOC}) version ${ASCIIDOC_VERSION}") 81 82 # Can always do both, unless horked 83 if(${ASCIIDOC_VERSION} VERSION_GREATER "0.0.0") 84 set(ASCIIDOC_CAN_MAN 1) 85 set(ASCIIDOC_CAN_HTML 1) 86 set(ASCIIDOC_CAN_DBXML 1) 87 endif() 88 89 # This is an example of 'horked'... 90 if(NOT A2X) 91 set(ASCIIDOC_CAN_MAN 0) 92 endif() 93 94 # Only docbook version python asciidoc supports 95 set(ASCIIDOC_DB_VER 45) 96endif(ASCIIDOC) 97 98 99# dblatex lets us build PDF's from the DocBook XML. This is pretty 100# fringe and not part of normal builds, so try to minimize the impact of 101# the checks. 102if(DBLATEX) 103 # Don't really care about the version, so save the extra checks 104 if(0) 105 execute_process( 106 COMMAND ${DBLATEX} --version 107 RESULT_VARIABLE _dblatex_result 108 OUTPUT_VARIABLE _dblatex_verout 109 ERROR_QUIET 110 ) 111 if(NOT ${_dblatex_result} EQUAL "0") 112 # Err... 113 message(WARNING "Unexpected result trying dblatex --version.") 114 set(_dblatex_verout "dblatex 0.0.0 FAKE") 115 endif() 116 unset(_dblatex_result) 117 118 # Break out the version. 119 set(_dblatex_veregex "dblatex version ([0-9]+\\.[0-9]+\\.[0-9]+).*") 120 string(REGEX REPLACE ${_dblatex_veregex} "\\1" 121 DBLATEX_VERSION ${_dblatex_verout}) 122 unset(_dblatex_verout) 123 unset(_dblatex_veregex) 124 message(STATUS "Found dblatex (${DBLATEX}) version ${DBLATEX_VERSION}") 125 else() 126 message(STATUS "Found dblatex (${DBLATEX})") 127 endif() 128 129 # I guess it works... 130 set(DBLATEX_CAN_PDF 1) 131endif(DBLATEX) 132 133 134# xmlto is another frontend for DocBook XML -> stuff. It can indirect 135# through dblatex (like we just do manually above) or through fop for PDF 136# output, but also knows how to invoke xsltproc to generate manpage 137# output, which gives us another route from adoc -> XML -> manpage. And 138# potentially other formats, if we start caring. 139if(XMLTO) 140 # Don't really care about the version, so save the extra checks 141 if(0) 142 execute_process( 143 COMMAND ${XMLTO} --version 144 RESULT_VARIABLE _xmlto_result 145 OUTPUT_VARIABLE _xmlto_verout 146 ERROR_QUIET 147 ) 148 if(NOT ${_xmlto_result} EQUAL "0") 149 # Err... 150 message(WARNING "Unexpected result trying xmlto --version.") 151 set(_xmlto_verout "xmlto 0.0.0 FAKE") 152 endif() 153 unset(_xmlto_result) 154 155 # Break out the version. 156 set(_xmlto_veregex "xmlto version ([0-9]+\\.[0-9]+\\.[0-9]+).*") 157 string(REGEX REPLACE ${_xmlto_veregex} "\\1" 158 XMLTO_VERSION ${_xmlto_verout}) 159 unset(_xmlto_verout) 160 unset(_xmlto_veregex) 161 message(STATUS "Found xmlto (${XMLTO}) version ${XMLTO_VERSION}") 162 else() 163 message(STATUS "Found xmlto (${XMLTO})") 164 endif() 165 166 # I guess it can do whatever... 167 set(XMLTO_CAN_STUFF 1) 168endif(XMLTO) 169 170 171 172 173# 174# Generator functions for creating targets for the various 175# transformations. 176# 177 178# Lot of boilerplate in all of them 179macro(_ad_mk_boilerplate PROG OUT) 180 # Minimal seatbelt 181 set(my_usage "${PROG}_mk_${OUT}(<output> <input> [DEPENDS <deps>] [COMMENT <comment>])") 182 cmake_parse_arguments( 183 _ARGS 184 "" 185 "COMMENT" 186 "DEPENDS" 187 ${ARGN} 188 ) 189 if(_ARGS_UNPARSED_ARGUMENTS) 190 message(FATAL_ERROR ${my_usage}) 191 endif() 192 193 # Always depend on the input file, maybe on more 194 set(dependancies ${ADFILE}) 195 if(_ARGS_DEPENDS) 196 list(APPEND dependancies ${_ARGS_DEPENDS}) 197 endif() 198 199 # Come up with some comment or other 200 if(NOT _ARGS_COMMENT) 201 get_filename_component(basename ${OUTFILE} NAME) 202 set(_ARGS_COMMENT "Generating ${basename} with ${PROG}") 203 endif() 204endmacro(_ad_mk_boilerplate) 205 206 207# Build a manpage via asciidoctor 208function(asciidoctor_mk_manpage OUTFILE ADFILE) 209 # Guard 210 if(NOT ASCIIDOCTOR_CAN_MAN) 211 message(FATAL_ERROR "asciidoctor can't do man") 212 endif() 213 214 _ad_mk_boilerplate(asciidoctor manpage ${ARGN}) 215 216 # Setup the rule 217 add_custom_command(OUTPUT ${OUTFILE} 218 DEPENDS ${dependancies} 219 COMMAND ${ASCIIDOCTOR} -b manpage -o ${OUTFILE} ${ADFILE} 220 COMMENT ${_ARGS_COMMENT} 221 ) 222endfunction(asciidoctor_mk_manpage) 223 224 225# Build a manpage via asciidoc (technically, a2x) 226function(a2x_mk_manpage OUTFILE ADFILE) 227 # Guard 228 if(NOT A2X OR NOT ASCIIDOC_CAN_MAN) 229 message(FATAL_ERROR "asciidoc/a2x can't do man") 230 endif() 231 232 _ad_mk_boilerplate(a2x manpage ${ARGN}) 233 234 # a2x gives us very little control over input/output files, so we 235 # have to do some vaguely stupid dances. In theory, -D works for the 236 # manpage output, but it's doc'd not to and will warn, so don't even 237 # try. The result is that it always puts the outfile file next to 238 # the input. So we make a temporary dir (with a hopefully unique 239 # name) and do all our stuff in there. 240 get_filename_component(basedir ${ADFILE} DIRECTORY) 241 while(1) 242 string(RANDOM rndstr) 243 set(a2x_tmpdir "${basedir}/a2x.${rndstr}") 244 if(NOT IS_DIRECTORY ${a2x_tmpdir}) 245 break() 246 endif() 247 endwhile() 248 file(MAKE_DIRECTORY ${a2x_tmpdir}) 249 250 # This had better already be named "someprog.somesection.adoc", 251 # because a2x is going to magically figure the program and section 252 # name from the contents and make that output file. 253 get_filename_component(inbasename ${ADFILE} NAME) 254 string(REGEX REPLACE "(.*)\\.adoc$" "\\1" outbasename ${inbasename}) 255 if(NOT outbasename) 256 message(FATAL_ERROR "Can't figure output for ${inbasename}") 257 endif() 258 259 # In/out tmpfile names 260 set(a2x_intmp "${a2x_tmpdir}/${inbasename}") 261 set(a2x_outtmp "${a2x_tmpdir}/${outbasename}") 262 263 add_custom_command(OUTPUT ${OUTFILE} 264 DEPENDS ${dependancies} 265 COMMAND cp ${ADFILE} ${a2x_intmp} 266 COMMAND ${A2X} --doctype manpage --format manpage ${a2x_intmp} 267 COMMAND mv ${a2x_outtmp} ${OUTFILE} 268 COMMAND rm ${a2x_intmp} 269 COMMENT ${_ARGS_COMMENT} 270 ) 271endfunction(a2x_mk_manpage) 272 273 274# Build a manpage via xmlto 275function(xmlto_mk_manpage OUTFILE XMLFILE) 276 # Guard 277 if(NOT XMLTO) 278 message(FATAL_ERROR "xmlto can't do man") 279 endif() 280 281 _ad_mk_boilerplate(xmlto manpage ${ARGN}) 282 283 # As with a2x, this had better already be named 284 # "someprog.somesection.xml" because we have so little control over 285 # the output location. 286 get_filename_component(inbasename ${XMLFILE} NAME) 287 string(REGEX REPLACE "(.*)\\.xml$" "\\1" outbasename ${inbasename}) 288 if(NOT outbasename) 289 message(FATAL_ERROR "Can't figure output for ${inbasename}") 290 endif() 291 292 get_filename_component(basedir ${XMLFILE} DIRECTORY) 293 add_custom_command(OUTPUT ${OUTFILE} 294 DEPENDS ${XMLFILE} ${dependancies} 295 COMMAND ${XMLTO} 296 --skip-validation 297 -o ${basedir} 298 # This apparently doesn't work right... 299 --stringparam 'man.endnotes.list.enabled=0' 300 man ${XMLFILE} 301 COMMENT ${_ARGS_COMMENT} 302 ) 303 304 # Set various overrides. Note that this leads to rather worse PDF 305 # output. If we ever decide to make xmlto a more likely part of the 306 # process, we probably need to rework things so we generate a 307 # different XML for the manpage path vs. the PDF path... 308 set(OVERRIDE_DTYPE manpage PARENT_SCOPE) 309 310 # This does _very_ poorly [currently?] with DocBook 5 output. 311 if(ASCIIDOCTOR_CAN_DBXML) 312 set(_addg "; downgrading asciidoctor output to docbook45") 313 set(ASCIIDOCTOR_DB_VER 45 PARENT_SCOPE) 314 endif() 315 316 message(WARNING "Using xmlto manpage generation${_addg}. This " 317 "will compromise the quality of PDF output.") 318endfunction(xmlto_mk_manpage) 319 320 321 322# Build HTML output with asciidoctor 323function(asciidoctor_mk_html OUTFILE ADFILE) 324 # Guard 325 if(NOT ASCIIDOCTOR_CAN_HTML) 326 message(FATAL_ERROR "asciidoctor can't do html") 327 endif() 328 329 _ad_mk_boilerplate(asciidoctor html ${ARGN}) 330 331 # Setup the rule 332 add_custom_command(OUTPUT ${OUTFILE} 333 DEPENDS ${dependancies} 334 COMMAND ${ASCIIDOCTOR} -atoc -anumbered -o ${OUTFILE} ${ADFILE} 335 COMMENT ${_ARGS_COMMENT} 336 ) 337endfunction(asciidoctor_mk_html) 338 339 340# And the asciidoc HTML 341function(asciidoc_mk_html OUTFILE ADFILE) 342 # Guard 343 if(NOT ASCIIDOC_CAN_HTML) 344 message(FATAL_ERROR "asciidoc can't do html") 345 endif() 346 347 _ad_mk_boilerplate(asciidoc html ${ARGN}) 348 349 # Setup the rule 350 add_custom_command(OUTPUT ${OUTFILE} 351 DEPENDS ${dependancies} 352 COMMAND ${ASCIIDOC} -atoc -anumbered -o ${OUTFILE} ${ADFILE} 353 COMMENT ${_ARGS_COMMENT} 354 ) 355endfunction(asciidoc_mk_html) 356 357 358# Building DocBook XML 359function(asciidoctor_mk_docbook OUTFILE ADFILE) 360 # Guard 361 if(NOT ASCIIDOCTOR_CAN_DBXML) 362 message(FATAL_ERROR "asciidoctor can't do DocBook") 363 endif() 364 365 _ad_mk_boilerplate(asciidoctor docbook ${ARGN}) 366 367 set(DTYPE article) 368 if(OVERRIDE_DTYPE) 369 set(DTYPE ${OVERRIDE_DTYPE}) 370 endif() 371 372 add_custom_command(OUTPUT ${OUTFILE} 373 DEPENDS ${dependancies} 374 COMMAND ${ASCIIDOCTOR} -b docbook${ASCIIDOCTOR_DB_VER} 375 -d ${DTYPE} -o ${OUTFILE} ${ADFILE} 376 COMMENT "${_ARGS_COMMENT} (docbook${ASCIIDOCTOR_DB_VER},${DTYPE})" 377 ) 378endfunction(asciidoctor_mk_docbook) 379 380function(asciidoc_mk_docbook OUTFILE ADFILE) 381 # Guard 382 if(NOT ASCIIDOC_CAN_DBXML) 383 message(FATAL_ERROR "asciidoc can't do DocBook") 384 endif() 385 386 _ad_mk_boilerplate(asciidoc docbook ${ARGN}) 387 388 set(DTYPE article) 389 if(OVERRIDE_DTYPE) 390 set(DTYPE ${OVERRIDE_DTYPE}) 391 endif() 392 393 add_custom_command(OUTPUT ${OUTFILE} 394 DEPENDS ${dependancies} 395 COMMAND ${ASCIIDOC} -b docbook${ASCIIDOC_DB_VER} 396 -d ${DTYPE} -o ${OUTFILE} ${ADFILE} 397 COMMENT "${_ARGS_COMMENT} (docbook${ASCIIDOC_DB_VER},${DTYPE})" 398 ) 399endfunction(asciidoc_mk_docbook) 400 401 402# PDF via dblatex 403function(dblatex_mk_pdf OUTFILE XMLFILE) 404 if(NOT DBLATEX_CAN_PDF) 405 message(FATAL_ERROR "dblatex can't do PDF") 406 endif() 407 408 _ad_mk_boilerplate(dblatex pdf ${ARGN}) 409 410 # Passes through to LaTeX geometry. 411 # Likely choices: letterpaper, a4paper 412 if(NOT DBLATEX_PAPERSIZE) 413 set(DBLATEX_PAPERSIZE "a4paper") 414 endif() 415 416 add_custom_command(OUTPUT ${OUTFILE} 417 DEPENDS ${XMLFILE} ${dependancies} 418 COMMAND ${DBLATEX} 419 -tpdf 420 -Pdoc.collab.show=0 421 -Platex.output.revhistory=0 422 -Ppaper.type=${DBLATEX_PAPERSIZE} 423 -Ppage.margin.top=2cm 424 -Ppage.margin.bottom=2cm 425 -o ${OUTFILE} ${XMLFILE} 426 COMMENT ${_ARGS_COMMENT} 427 ) 428endfunction(dblatex_mk_pdf) 429