# **********************************************************
# Copyright (c) 2012-2021 Google, Inc. All rights reserved.
# Copyright (c) 2009-2010 VMware, Inc. All rights reserved.
# **********************************************************
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# * Neither the name of VMware, Inc. nor the names of its contributors may be
# used to endorse or promote products derived from this software without
# specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL VMWARE, INC. OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
# DAMAGE.
###########################################################################
# Usage:
# + Add a custom command to invoke this script in the docs build dir
# + Assumes a favicon.ico is present in the target build dir
#
# Args:
# + DOXYGEN_EXECUTABLE : path to doxygen
# + doxygen_ver : version of doxygen
# + version_number : version number to put in the docs
# + module_string_long : replacement text for Modules
# + module_string_short : replacement text for Module
# + files_string : replacement text for Files; optional
# + structs_string : replacement text for Data Structures; optional
# + home_url : home page URL
# + home_title : home page title
# + logo_imgfile : image file with logo
# + embeddable : whether to edit content for jekyll embedding
# + proj_srcdir : project base source dir, for editing titles
# + proj_bindir : project base binary dir, for editing titles
#
###########################################################################
# Any quotes carry over and it's simplest to assume not there.
string(REPLACE "\"" "" module_string_long ${module_string_long})
string(REPLACE "\"" "" module_string_short ${module_string_short})
if (DEFINED files_string)
string(REPLACE "\"" "" files_string ${files_string})
endif ()
if (DEFINED structs_string)
string(REPLACE "\"" "" structs_string ${structs_string})
endif ()
string(REPLACE "\"" "" home_url ${home_url})
string(REPLACE "\"" "" home_title ${home_title})
string(REPLACE "\"" "" logo_imgfile ${logo_imgfile})
# First, generate header.html and footer.html suitable for current
# doxygen version and then tweak them.
# Note that we must generate a css file and we must name it doxygen.css
# or else we have to later copy it to html dir.
execute_process(COMMAND
${DOXYGEN_EXECUTABLE} -w html header.html footer.html doxygen.css
RESULT_VARIABLE doxygen_w_result
ERROR_VARIABLE doxygen_w_error
OUTPUT_QUIET
)
if (doxygen_w_result OR doxygen_w_error)
message(FATAL_ERROR "*** ${DOXYGEN_EXECUTABLE} failed: ***\n${doxygen_w_error}")
endif (doxygen_w_result OR doxygen_w_error)
# Add favicon to header
file(READ ${CMAKE_CURRENT_BINARY_DIR}/header.html string)
string(REGEX REPLACE
"<title>"
"<link rel=\"shortcut icon\" type=\"image/x-icon\" href=\"favicon.ico\"/>\n<title>"
string "${string}")
if (doxygen_ver VERSION_LESS "1.7.0")
# For some reason older doxygen doesn't replace its own vars w/ custom header
string(REGEX REPLACE "\\$relpath\\$" "" string "${string}")
endif ()
if (embeddable)
# Add jekyll header.
set(string "---
title: \"$title\"
layout: default
---
${string}")
endif ()
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/header.html "${string}")
# Tweak footer to have version
file(READ ${CMAKE_CURRENT_BINARY_DIR}/footer.html string)
set(foot "<img border=0 src=\"favicon.png\"> ")
set(foot "${foot} $projectname version ${version_number} --- $datetime")
set(foot "${foot} <img border=0 src=\"favicon.png\">")
# Recent doxygen
string(REGEX REPLACE "\\$generated.*doxygenversion" "${foot}" string "${string}")
# Older doxygen
string(REGEX REPLACE "Generated.*doxygenversion" "${foot}" string "${string}")
# Prefer center to default float:right
string(REGEX REPLACE "class=\"footer\""
"class=\"footer\" style=\"float:none;text-align:center\""
string "${string}")
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/footer.html "${string}")
if (doxygen_ver STRGREATER "1.7.2")
# Create a layout file so we can control the treeview index
execute_process(COMMAND
${DOXYGEN_EXECUTABLE} -l
RESULT_VARIABLE doxygen_l_result
ERROR_VARIABLE doxygen_l_error
OUTPUT_QUIET
)
if (doxygen_l_result OR doxygen_l_error)
message(FATAL_ERROR "*** ${DOXYGEN_EXECUTABLE} failed: ***\n${doxygen_l_error}")
endif (doxygen_l_result OR doxygen_l_error)
file(READ ${CMAKE_CURRENT_BINARY_DIR}/DoxygenLayout.xml string)
# Rename "Modules" (done below for older doxygen)
string(REGEX REPLACE
"tab type=\"modules\" visible=\"yes\" title=\"\""
"tab type=\"modules\" visible=\"yes\" title=\"${module_string_long}\""
string "${string}")
if (doxygen_ver STRGREATER "1.7.5")
# Add link to home page (done below for older doxygen; skipped for 1.7.3-1.7.5)
string(REGEX REPLACE
"</navindex>"
"<tab type=\"user\" url=\"${home_url}\" title=\"${home_title}\"/>\n</navindex>"
string "${string}")
endif ()
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/DoxygenLayout.xml "${string}")
endif ()
# Run doxygen and fail on warnings.
# Now update to latest doxygen. Suppress warnings since they're misleading:
# they say "please run doxygen -u" but we're currently doing just that.
execute_process(COMMAND
${DOXYGEN_EXECUTABLE}
RESULT_VARIABLE doxygen_u_result
ERROR_VARIABLE doxygen_u_error
OUTPUT_QUIET
)
if (doxygen_u_result OR doxygen_u_error)
message(FATAL_ERROR "*** ${DOXYGEN_EXECUTABLE} failed: ***\n${doxygen_u_error}")
endif (doxygen_u_result OR doxygen_u_error)
# Doxygen does not put header.html on the top-level frame so we add favicon manually
file(READ ${CMAKE_CURRENT_BINARY_DIR}/html/index.html string)
string(REGEX REPLACE
"<title>"
"<link rel=\"shortcut icon\" type=\"image/x-icon\" href=\"favicon.ico\"/>\n<title>"
string "${string}")
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/html/index.html "${string}")
if (embeddable)
# We need to make some edits for insertion into our jekyll site.
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/html/keywords.js "---\nlayout: null\n---\n")
file(GLOB all_html ${CMAKE_CURRENT_BINARY_DIR}/html/*.html)
foreach (html ${all_html})
file(READ ${html} string)
# Remove headers and body tag.
string(REGEX REPLACE "<!-- HTML header.*<body>\n" "" string "${string}")
# Remove body and html close tags.
string(REGEX REPLACE "</body>.*</html>\n" "" string "${string}")
# Remove full paths.
string(REGEX REPLACE "\ntitle: \"${proj_bindir}" "\ntitle: \"" string "${string}")
string(REGEX REPLACE "\ntitle: \"${proj_srcdir}" "\ntitle: \"" string "${string}")
# Add permalink to front matter so the web site hides the docs/ subdir.
get_filename_component(linkname ${html} NAME)
string(REGEX REPLACE "(\nlayout: default\n)" "\\1permalink: /${linkname}\n"
string "${string}")
# Our images are in an images/ subdir.
string(REGEX REPLACE "<img src=\"" "<img src=\"/images/" string "${string}")
string(REGEX REPLACE
"<object type=\"image/svg\\+xml\" data=\""
"<object type=\"image/svg+xml\" data=\"/images/"
string "${string}")
# Ensure that strings that look like Jekyll tags are not interpreted as such.
# We add the Jekyll raw-endraw tags around "{%" and "%}" separately. We use
# a random suffix for jekyll_raw_tag and jekyll_endraw_tag to reduce the
# possibility of a conflict with an actual use of these strings.
string(REGEX REPLACE "{%" "jekyll_raw_tag_f00d{%jekyll_endraw_tag_f00d" string "${string}")
string(REGEX REPLACE "%}" "jekyll_raw_tag_f00d%}jekyll_endraw_tag_f00d" string "${string}")
string(REGEX REPLACE "jekyll_raw_tag_f00d" "{% raw %}" string "${string}")
string(REGEX REPLACE "jekyll_endraw_tag_f00d" "{% endraw %}" string "${string}")
# Collect type info for keyword searches with direct anchor links (else the
# search finds the page but the user then has to manually search within the long
# page -- and there are no doygen options to split each onto its own page).
# The format here is the javascript object used by search.js to set up lunr.
# XXX: This is fragile and highly dependent on the precise doxygen output.
get_filename_component(fname ${html} NAME_WE)
# The ;'s mess up the MATCHALL results so we remove them.
string(REPLACE ";" "_" nosemis "${string}")
string(REGEX MATCHALL "<tr class=\"memitem[^\n]*</tr>" types "${nosemis}")
foreach (type ${types})
string(REGEX MATCH "href=\"[^\"]+\"" url "${type}")
string(REGEX REPLACE "href=\"([^\"]+)\"" "\\1" url "${url}")
string(REGEX MATCH "\">[_a-zA-Z0-9]+</a>" name "${type}")
string(REGEX REPLACE "\">([_a-zA-Z0-9]+)</a>" "\\1" name "${name}")
if (name STREQUAL "")
continue ()
endif ()
# Support searching by partial names.
set(extra "")
string(REPLACE "_" " " separate "${name}")
if (NOT separate STREQUAL name)
set(extra "${extra} ${separate}")
endif ()
set(prefix "${name}")
while (prefix MATCHES "[^_]_[^_]")
string(REGEX REPLACE "_[^_]*$" "" prefix "${prefix}")
set(extra "${extra} ${prefix}")
endwhile ()
set(keywords "window.data[\"${fname}-${name}\"]={\
\"name\":\"${fname}-${name}\",\
\"title\":\"${name} in ${fname} header\",\
\"url\":\"${url}\",\
\"content\":\"${name} ${extra}\"};\n")
file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/html/keywords.js "${keywords}")
endforeach ()
# Similarly, put in explicit search entries for sections so searches go
# straight to the anchor link.
string(REGEX MATCHALL "\n<h1><a class=\"anchor\" id=\"[^\"]*\"></a>\n[^\n]+</h1>"
sections "${nosemis}")
foreach (section ${sections})
string(REGEX REPLACE ".* id=\"([^\"]+)\".*" "\\1" id "${section}")
string(REGEX REPLACE ".*</a>\n([^<]+)</h1>" "\\1" name "${section}")
if (name STREQUAL "" OR id STREQUAL "" OR name MATCHES "<")
message(FATAL_ERROR "Failed to find section name or anchor: ${section}")
endif ()
set(url "/${fname}.html#${id}")
# Quotes cause JavaScript syntax errors.
string(REPLACE "\"" "" name "${name}")
# Spaces would be ok but it feels nicer w/o them in the key.
string(REPLACE " " "_" key "${name}")
set(keywords "window.data[\"${fname}-${key}\"]={\
\"name\":\"${fname}-${key}\",\
\"title\":\"${name}\",\
\"url\":\"${url}\",\
\"content\":\"${name}\"};\n")
file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/html/keywords.js "${keywords}")
endforeach ()
file(WRITE ${html} "${string}")
endforeach ()
# We leverage the javascript menu from the non-embedded version.
file(GLOB all_js ${CMAKE_CURRENT_BINARY_DIR}/../html/*.js)
set(found_user_docs OFF)
foreach (js ${all_js})
if (js MATCHES "navtree.js" OR
js MATCHES "resize.js" OR
js MATCHES "navtreeindex")
continue ()
endif ()
file(READ ${js} string)
# Ask jekyll to inline, instead of just naming for JS.
string(REGEX REPLACE ", \"([^\"]+)\" \\]" ", {% include_relative \\1.js %} ]"
string "${string}")
if (js MATCHES "navtreedata.js")
# Add a jekyll header.
set(string "---\npermalink: /navtreedata.js\n---\n${string}")
# Remove the index array from navtreedata.js.
string(REGEX REPLACE "var NAVTREEINDEX =[^;]*;" "" string "${string}")
# Remove one layer from navtreedata.js.
string(REGEX REPLACE "\n *\\[ \"DynamoRIO\", \"index.html\", \\[" ""
string "${string}")
# Remove the home page at the end.
string(REGEX REPLACE "\n[^\n]*DynamoRIO Home Page[^\n]*\n" "" string "${string}")
# Insert a layer in navtreedata.js, using the end of the top layer we removed.
string(REGEX REPLACE "\n( *\\[ \"Deprecated List)"
"\n[ \"API Reference\", \"files.html\", [\n\\1"
string "${string}")
if (NOT string MATCHES "Extension API")
message(FATAL_ERROR "Cannot find menu entry for page \"Extension API\"")
endif ()
string(REGEX MATCH "\n[^\n]+\"Extension API\"[^\n]+\n" ext_entry "${string}")
string(REPLACE "${ext_entry}" "\n" string "${string}")
else ()
# Remove name so we can inline.
string(REGEX REPLACE "var [^\n]* =\n" "" string "${string}")
# End in a comma for inlining.
string(REGEX REPLACE "\\];" "]," string "${string}")
# Update directory index names which are hashes that differ between the
# treeview and embed generations.
string(REGEX MATCHALL "\"[a-zA-Z_0-9]+\", \"dir_[a-f0-9]+\\.html\""
dir_hashes "${string}")
foreach (dir_hash ${dir_hashes})
string(REGEX REPLACE "\"([a-zA-Z_0-9]+)\".*" "\\1" key "${dir_hash}")
# We go search the dir_*.html embed files looking for key.
file(GLOB dir_html ${CMAKE_CURRENT_BINARY_DIR}/html/dir_*.html)
set(found_hash OFF)
foreach (html ${dir_html})
file(READ ${html} html_string)
if (html_string MATCHES "${key} Directory Reference")
get_filename_component(fname ${html} NAME)
string(REGEX REPLACE "\"${key}\", \"dir_[a-f0-9]+\\.html\""
"\"${key}\", \"${fname}\"" string "${string}")
set(found_hash ON)
break ()
endif ()
endforeach ()
if (NOT found_hash)
message(FATAL_ERROR "Cannot find corresonding page for ${key}")
endif ()
endforeach ()
endif ()
if (js MATCHES "page_user_docs.js")
# CMake 3.6+ guarantees the glob is sorted lexicographically, so we've already
# seen navtreedata.js.
set(found_user_docs ON)
if (ext_entry)
if (NOT string MATCHES "Disassembly Library")
message(FATAL_ERROR "Cannot find menu entry for page \"Disassembly Library\"")
endif ()
string(REGEX REPLACE "\n([^\n]+\"Disassembly Library)" "${ext_entry}\\1"
string "${string}")
else ()
message(FATAL_ERROR "Failed to find the menu entries to move")
endif ()
endif ()
# Put the modified contents into our dir.
get_filename_component(fname ${js} NAME)
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/html/${fname} "${string}")
endforeach ()
if (NOT found_user_docs)
message(FATAL_ERROR "Cannot find \"page_user_docs\" menu file")
endif ()
else ()
# Edit navbar.
if (doxygen_ver VERSION_LESS "1.7.3")
# Add link to home page to treeview pane
file(APPEND
${CMAKE_CURRENT_BINARY_DIR}/html/tree.html
"<p> <a target=\"main\" href=\"${home_url}/\">${home_title}</a></p>")
# Add our logo to treeview pane (yes there is no closing </body></html>)
file(APPEND
${CMAKE_CURRENT_BINARY_DIR}/html/tree.html
"<p> <br><img src=\"${logo_imgfile}\"></p>")
else ()
# This is a fragile insertion into the javascript used for the navbar.
# We insert at the end of the final function (initNavTree).
# This works in doxygen 1.7.4-1.8.1.
set(add_logo "
var imgdiv = document.createElement(\"div\");
document.getElementById(\"nav-tree-contents\").appendChild(imgdiv);
var img = document.createElement(\"img\");
imgdiv.appendChild(img);
img.src = \"${logo_imgfile}\";
img.style.marginLeft = \"80px\";
img.style.marginTop = \"30px\";
")
file(READ ${CMAKE_CURRENT_BINARY_DIR}/html/navtree.js string)
string(REGEX REPLACE
"\\}\n*$"
"${add_logo}\n}"
string "${string}")
# Doxygen 1.9.1 has this license-end line.
string(REGEX REPLACE
"\\}\n/\\* @license-end \\*/\n$"
"${add_logo}\n}"
string "${string}")
# While we're here we replace Files and Data Structures, if requested
if (DEFINED files_string)
string(REGEX REPLACE "\"Files\"" "\"${files_string}\"" string "${string}")
endif ()
if (DEFINED structs_string)
string(REGEX REPLACE "\"Data Structures\"" "\"${structs_string}\""
string "${string}")
endif ()
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/html/navtree.js "${string}")
endif ()
endif ()
# For modules/extensions (i#277/PR 540817) we use doxygen groups which show up under
# top-level "Modules" which we rename here
if (doxygen_ver VERSION_LESS "1.7.3")
file(READ ${CMAKE_CURRENT_BINARY_DIR}/html/tree.html string)
string(REGEX REPLACE "Modules" "${module_string_long}" string "${string}")
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/html/tree.html "${string}")
endif ()
if (EXISTS ${CMAKE_CURRENT_BINARY_DIR}/html/modules.html)
file(READ ${CMAKE_CURRENT_BINARY_DIR}/html/modules.html string)
string(REGEX REPLACE "Module" "${module_string_short}" string "${string}")
string(REGEX REPLACE "module" "${module_string_short}" string "${string}")
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/html/modules.html "${string}")
endif ()
# We do not copy samples or favicon for build dir: those are install rules