2019-06-11 20:31:20 +02:00
|
|
|
#
|
|
|
|
# Copyright(c) 2019 Jeroen Koekkoek
|
|
|
|
#
|
|
|
|
# This program and the accompanying materials are made available under the
|
|
|
|
# terms of the Eclipse Public License v. 2.0 which is available at
|
|
|
|
# http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
|
|
|
|
# v. 1.0 which is available at
|
|
|
|
# http://www.eclipse.org/org/documents/edl-v10.php.
|
|
|
|
#
|
|
|
|
# SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
|
|
|
|
#
|
|
|
|
include(FindPackageHandleStandardArgs)
|
|
|
|
|
|
|
|
macro(_Sphinx_find_executable _exe)
|
|
|
|
string(TOUPPER "${_exe}" _uc)
|
|
|
|
# sphinx-(build|quickstart)-3 x.x.x
|
|
|
|
# FIXME: This works on Fedora (and probably most other UNIX like targets).
|
|
|
|
# Windows targets and PIP installs might need some work.
|
|
|
|
find_program(
|
|
|
|
SPHINX_${_uc}_EXECUTABLE
|
|
|
|
NAMES "sphinx-${_exe}-3" "sphinx-${_exe}" "sphinx-${_exe}.exe")
|
|
|
|
|
|
|
|
if(SPHINX_${_uc}_EXECUTABLE)
|
|
|
|
execute_process(
|
|
|
|
COMMAND "${SPHINX_${_uc}_EXECUTABLE}" --version
|
|
|
|
RESULT_VARIABLE _result
|
|
|
|
OUTPUT_VARIABLE _output
|
|
|
|
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
2019-08-02 13:06:43 +02:00
|
|
|
if(_result EQUAL 0 AND _output MATCHES " v?([0-9]+\\.[0-9]+\\.[0-9]+)$")
|
2019-06-11 20:31:20 +02:00
|
|
|
set(SPHINX_${_uc}_VERSION "${CMAKE_MATCH_1}")
|
|
|
|
endif()
|
|
|
|
|
2019-07-31 08:37:41 +02:00
|
|
|
if(NOT TARGET Sphinx::${_exe})
|
|
|
|
add_executable(Sphinx::${_exe} IMPORTED GLOBAL)
|
|
|
|
set_target_properties(Sphinx::${_exe} PROPERTIES
|
|
|
|
IMPORTED_LOCATION "${SPHINX_${_uc}_EXECUTABLE}")
|
|
|
|
endif()
|
2019-06-11 20:31:20 +02:00
|
|
|
set(Sphinx_${_exe}_FOUND TRUE)
|
|
|
|
else()
|
|
|
|
set(Sphinx_${_exe}_FOUND FALSE)
|
|
|
|
endif()
|
|
|
|
unset(_uc)
|
|
|
|
endmacro()
|
|
|
|
|
|
|
|
macro(_Sphinx_find_extension _ext)
|
|
|
|
if(_SPHINX_PYTHON_EXECUTABLE)
|
|
|
|
execute_process(
|
|
|
|
COMMAND ${_SPHINX_PYTHON_EXECUTABLE} -c "import ${_ext}"
|
|
|
|
RESULT_VARIABLE _result)
|
|
|
|
if(_result EQUAL 0)
|
|
|
|
set(Sphinx_${_ext}_FOUND TRUE)
|
|
|
|
else()
|
|
|
|
set(Sphinx_${_ext}_FOUND FALSE)
|
|
|
|
endif()
|
|
|
|
elseif(CMAKE_HOST_WIN32 AND SPHINX_BUILD_EXECUTABLE)
|
|
|
|
# script-build on Windows located under (when PIP is used):
|
|
|
|
# C:/Program Files/PythonXX/Scripts
|
|
|
|
# C:/Users/username/AppData/Roaming/Python/PythonXX/Sripts
|
|
|
|
#
|
|
|
|
# Python modules are installed under:
|
|
|
|
# C:/Program Files/PythonXX/Lib
|
|
|
|
# C:/Users/username/AppData/Roaming/Python/PythonXX/site-packages
|
|
|
|
#
|
|
|
|
# To verify a given module is installed, use the Python base directory
|
|
|
|
# and test if either Lib/module.py or site-packages/module.py exists.
|
|
|
|
get_filename_component(_dirname "${SPHINX_BUILD_EXECUTABLE}" DIRECTORY)
|
|
|
|
get_filename_component(_dirname "${_dirname}" DIRECTORY)
|
|
|
|
if(IS_DIRECTORY "${_dirname}/Lib/${_ext}" OR
|
|
|
|
IS_DIRECTORY "${_dirname}/site-packages/${_ext}")
|
|
|
|
set(Sphinx_${_ext}_FOUND TRUE)
|
|
|
|
else()
|
|
|
|
set(Sphinx_${_ext}_FOUND FALSE)
|
|
|
|
endif()
|
|
|
|
endif()
|
|
|
|
endmacro()
|
|
|
|
|
|
|
|
#
|
|
|
|
# Find sphinx-build and sphinx-quickstart.
|
|
|
|
#
|
|
|
|
_Sphinx_find_executable(build)
|
|
|
|
_Sphinx_find_executable(quickstart)
|
|
|
|
|
|
|
|
#
|
|
|
|
# Verify both executables are part of the Sphinx distribution.
|
|
|
|
#
|
|
|
|
if(SPHINX_BUILD_EXECUTABLE AND SPHINX_QUICKSTART_EXECUTABLE)
|
|
|
|
if(NOT SPHINX_BUILD_VERSION STREQUAL SPHINX_QUICKSTART_VERSION)
|
2019-08-02 13:06:43 +02:00
|
|
|
message(FATAL_ERROR "Versions for sphinx-build (${SPHINX_BUILD_VERSION}) "
|
|
|
|
"and sphinx-quickstart (${SPHINX_QUICKSTART_VERSION}) "
|
2019-06-11 20:31:20 +02:00
|
|
|
"do not match")
|
|
|
|
endif()
|
|
|
|
endif()
|
|
|
|
|
|
|
|
#
|
|
|
|
# To verify the required Sphinx extensions are available, the right Python
|
|
|
|
# installation must be queried (2 vs 3). Of course, this only makes sense on
|
|
|
|
# UNIX-like systems.
|
|
|
|
#
|
|
|
|
if(NOT CMAKE_HOST_WIN32 AND SPHINX_BUILD_EXECUTABLE)
|
|
|
|
file(READ "${SPHINX_BUILD_EXECUTABLE}" _contents)
|
|
|
|
if(_contents MATCHES "^#!([^\n]+)")
|
|
|
|
string(STRIP "${CMAKE_MATCH_1}" _shebang)
|
|
|
|
if(EXISTS "${_shebang}")
|
|
|
|
set(_SPHINX_PYTHON_EXECUTABLE "${_shebang}")
|
|
|
|
endif()
|
|
|
|
endif()
|
|
|
|
endif()
|
|
|
|
|
|
|
|
foreach(_comp IN LISTS Sphinx_FIND_COMPONENTS)
|
|
|
|
if(_comp STREQUAL "build")
|
|
|
|
# Do nothing, sphinx-build is always required.
|
|
|
|
elseif(_comp STREQUAL "quickstart")
|
|
|
|
# Do nothing, sphinx-quickstart is optional, but looked up by default.
|
|
|
|
elseif(_comp STREQUAL "breathe")
|
|
|
|
_Sphinx_find_extension(${_comp})
|
|
|
|
else()
|
|
|
|
message(WARNING "${_comp} is not a valid or supported Sphinx extension")
|
|
|
|
set(Sphinx_${_comp}_FOUND FALSE)
|
|
|
|
continue()
|
|
|
|
endif()
|
|
|
|
endforeach()
|
|
|
|
|
|
|
|
find_package_handle_standard_args(
|
|
|
|
Sphinx
|
2019-07-31 08:37:41 +02:00
|
|
|
VERSION_VAR SPHINX_BUILD_VERSION
|
2019-06-11 20:31:20 +02:00
|
|
|
REQUIRED_VARS SPHINX_BUILD_EXECUTABLE SPHINX_BUILD_VERSION
|
|
|
|
HANDLE_COMPONENTS)
|
|
|
|
|
|
|
|
|
|
|
|
# Generate a conf.py template file using sphinx-quickstart.
|
|
|
|
#
|
|
|
|
# sphinx-quickstart allows for quiet operation and a lot of settings can be
|
|
|
|
# specified as command line arguments, therefore its not required to parse the
|
|
|
|
# generated conf.py.
|
|
|
|
function(_Sphinx_generate_confpy _target _cachedir)
|
|
|
|
if(NOT TARGET Sphinx::quickstart)
|
|
|
|
message(FATAL_ERROR "sphinx-quickstart is not available, needed by"
|
|
|
|
"sphinx_add_docs for target ${_target}")
|
|
|
|
endif()
|
|
|
|
|
|
|
|
if(NOT DEFINED SPHINX_PROJECT)
|
|
|
|
set(SPHINX_PROJECT ${PROJECT_NAME})
|
|
|
|
endif()
|
|
|
|
|
|
|
|
if(NOT DEFINED SPHINX_AUTHOR)
|
|
|
|
set(SPHINX_AUTHOR "${SPHINX_PROJECT} committers")
|
|
|
|
endif()
|
|
|
|
|
|
|
|
if(NOT DEFINED SPHINX_COPYRIGHT)
|
|
|
|
string(TIMESTAMP "%Y, ${SPHINX_AUTHOR}" SPHINX_COPYRIGHT)
|
|
|
|
endif()
|
|
|
|
|
|
|
|
if(NOT DEFINED SPHINX_VERSION)
|
|
|
|
set(SPHINX_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}")
|
|
|
|
endif()
|
|
|
|
|
|
|
|
if(NOT DEFINED SPHINX_RELEASE)
|
|
|
|
set(SPHINX_RELEASE "${PROJECT_VERSION}")
|
|
|
|
endif()
|
|
|
|
|
|
|
|
if(NOT DEFINED SPHINX_LANGUAGE)
|
|
|
|
set(SPHINX_LANGUAGE "en")
|
|
|
|
endif()
|
|
|
|
|
2019-07-31 08:37:41 +02:00
|
|
|
if(NOT DEFINED SPHINX_MASTER)
|
|
|
|
set(SPHINX_MASTER "index")
|
|
|
|
endif()
|
|
|
|
|
2019-06-11 20:31:20 +02:00
|
|
|
set(_known_exts autodoc doctest intersphinx todo coverage imgmath mathjax
|
|
|
|
ifconfig viewcode githubpages)
|
|
|
|
|
|
|
|
if(DEFINED SPHINX_EXTENSIONS)
|
|
|
|
foreach(_ext ${SPHINX_EXTENSIONS})
|
|
|
|
set(_is_known_ext FALSE)
|
|
|
|
foreach(_known_ext ${_known_exsts})
|
|
|
|
if(_ext STREQUAL _known_ext)
|
|
|
|
set(_opts "${opts} --ext-${_ext}")
|
|
|
|
set(_is_known_ext TRUE)
|
|
|
|
break()
|
|
|
|
endif()
|
|
|
|
endforeach()
|
|
|
|
if(NOT _is_known_ext)
|
|
|
|
if(_exts)
|
|
|
|
set(_exts "${_exts},${_ext}")
|
|
|
|
else()
|
|
|
|
set(_exts "${_ext}")
|
|
|
|
endif()
|
|
|
|
endif()
|
|
|
|
endforeach()
|
|
|
|
endif()
|
|
|
|
|
|
|
|
if(_exts)
|
|
|
|
set(_exts "--extensions=${_exts}")
|
|
|
|
endif()
|
|
|
|
|
|
|
|
set(_templatedir "${CMAKE_CURRENT_BINARY_DIR}/${_target}.template")
|
|
|
|
file(MAKE_DIRECTORY "${_templatedir}")
|
|
|
|
execute_process(
|
|
|
|
COMMAND "${SPHINX_QUICKSTART_EXECUTABLE}"
|
|
|
|
-q --no-makefile --no-batchfile
|
|
|
|
-p "${SPHINX_PROJECT}"
|
|
|
|
-a "${SPHINX_AUTHOR}"
|
|
|
|
-v "${SPHINX_VERSION}"
|
|
|
|
-r "${SPHINX_RELEASE}"
|
|
|
|
-l "${SPHINX_LANGUAGE}"
|
2019-07-31 08:37:41 +02:00
|
|
|
--master "${SPHINX_MASTER}"
|
2019-06-11 20:31:20 +02:00
|
|
|
${_opts} ${_exts} "${_templatedir}"
|
|
|
|
RESULT_VARIABLE _result
|
|
|
|
OUTPUT_QUIET)
|
|
|
|
|
|
|
|
if(_result EQUAL 0 AND EXISTS "${_templatedir}/conf.py")
|
|
|
|
file(COPY "${_templatedir}/conf.py" DESTINATION "${_cachedir}")
|
|
|
|
endif()
|
|
|
|
|
|
|
|
file(REMOVE_RECURSE "${_templatedir}")
|
|
|
|
|
|
|
|
if(NOT _result EQUAL 0 OR NOT EXISTS "${_cachedir}/conf.py")
|
|
|
|
message(FATAL_ERROR "Sphinx configuration file not generated for "
|
|
|
|
"target ${_target}")
|
|
|
|
endif()
|
|
|
|
endfunction()
|
|
|
|
|
|
|
|
function(sphinx_add_docs _target)
|
|
|
|
set(_opts)
|
|
|
|
set(_single_opts BUILDER OUTPUT_DIRECTORY SOURCE_DIRECTORY)
|
|
|
|
set(_multi_opts BREATHE_PROJECTS)
|
|
|
|
cmake_parse_arguments(_args "${_opts}" "${_single_opts}" "${_multi_opts}" ${ARGN})
|
|
|
|
|
|
|
|
unset(SPHINX_BREATHE_PROJECTS)
|
|
|
|
|
|
|
|
if(NOT _args_BUILDER)
|
|
|
|
message(FATAL_ERROR "Sphinx builder not specified for target ${_target}")
|
|
|
|
elseif(NOT _args_SOURCE_DIRECTORY)
|
|
|
|
message(FATAL_ERROR "Sphinx source directory not specified for target ${_target}")
|
|
|
|
else()
|
|
|
|
if(NOT IS_ABSOLUTE "${_args_SOURCE_DIRECTORY}")
|
|
|
|
get_filename_component(_sourcedir "${_args_SOURCE_DIRECTORY}" ABSOLUTE)
|
|
|
|
else()
|
|
|
|
set(_sourcedir "${_args_SOURCE_DIRECTORY}")
|
|
|
|
endif()
|
|
|
|
if(NOT IS_DIRECTORY "${_sourcedir}")
|
|
|
|
message(FATAL_ERROR "Sphinx source directory '${_sourcedir}' for"
|
|
|
|
"target ${_target} does not exist")
|
|
|
|
endif()
|
|
|
|
endif()
|
|
|
|
|
|
|
|
set(_builder "${_args_BUILDER}")
|
|
|
|
if(_args_OUTPUT_DIRECTORY)
|
|
|
|
set(_outputdir "${_args_OUTPUT_DIRECTORY}")
|
|
|
|
else()
|
|
|
|
set(_outputdir "${CMAKE_CURRENT_BINARY_DIR}/${_target}")
|
|
|
|
endif()
|
|
|
|
|
|
|
|
|
|
|
|
if(_args_BREATHE_PROJECTS)
|
|
|
|
if(NOT Sphinx_breathe_FOUND)
|
|
|
|
message(FATAL_ERROR "Sphinx extension 'breathe' is not available. Needed"
|
|
|
|
"by sphinx_add_docs for target ${_target}")
|
|
|
|
endif()
|
|
|
|
list(APPEND SPHINX_EXTENSIONS breathe)
|
|
|
|
|
|
|
|
foreach(_doxygen_target ${_args_BREATHE_PROJECTS})
|
|
|
|
if(TARGET ${_doxygen_target})
|
|
|
|
list(APPEND _depends ${_doxygen_target})
|
|
|
|
|
|
|
|
# Doxygen targets are supported. Verify that a Doxyfile exists.
|
|
|
|
get_target_property(_dir ${_doxygen_target} BINARY_DIR)
|
|
|
|
set(_doxyfile "${_dir}/Doxyfile.${_doxygen_target}")
|
|
|
|
if(NOT EXISTS "${_doxyfile}")
|
|
|
|
message(FATAL_ERROR "Target ${_doxygen_target} is not a Doxygen"
|
|
|
|
"target, needed by sphinx_add_docs for target"
|
|
|
|
"${_target}")
|
|
|
|
endif()
|
|
|
|
|
|
|
|
# Read the Doxyfile, verify XML generation is enabled and retrieve the
|
|
|
|
# output directory.
|
|
|
|
file(READ "${_doxyfile}" _contents)
|
|
|
|
if(NOT _contents MATCHES "GENERATE_XML *= *YES")
|
|
|
|
message(FATAL_ERROR "Doxygen target ${_doxygen_target} does not"
|
|
|
|
"generate XML, needed by sphinx_add_docs for"
|
|
|
|
"target ${_target}")
|
|
|
|
elseif(_contents MATCHES "OUTPUT_DIRECTORY *= *([^ ][^\n]*)")
|
|
|
|
string(STRIP "${CMAKE_MATCH_1}" _dir)
|
|
|
|
set(_name "${_doxygen_target}")
|
|
|
|
set(_dir "${_dir}/xml")
|
|
|
|
else()
|
|
|
|
message(FATAL_ERROR "Cannot parse Doxyfile generated by Doxygen"
|
|
|
|
"target ${_doxygen_target}, needed by"
|
|
|
|
"sphinx_add_docs for target ${_target}")
|
|
|
|
endif()
|
|
|
|
elseif(_doxygen_target MATCHES "([^: ]+) *: *(.*)")
|
|
|
|
set(_name "${CMAKE_MATCH_1}")
|
|
|
|
string(STRIP "${CMAKE_MATCH_2}" _dir)
|
|
|
|
endif()
|
|
|
|
|
|
|
|
if(_name AND _dir)
|
|
|
|
if(_breathe_projects)
|
|
|
|
set(_breathe_projects "${_breathe_projects}, \"${_name}\": \"${_dir}\"")
|
|
|
|
else()
|
|
|
|
set(_breathe_projects "\"${_name}\": \"${_dir}\"")
|
|
|
|
endif()
|
|
|
|
if(NOT _breathe_default_project)
|
|
|
|
set(_breathe_default_project "${_name}")
|
|
|
|
endif()
|
|
|
|
endif()
|
|
|
|
endforeach()
|
|
|
|
endif()
|
|
|
|
|
|
|
|
set(_cachedir "${CMAKE_CURRENT_BINARY_DIR}/${_target}.cache")
|
|
|
|
file(MAKE_DIRECTORY "${_cachedir}")
|
|
|
|
file(MAKE_DIRECTORY "${_cachedir}/_static")
|
|
|
|
|
|
|
|
_Sphinx_generate_confpy(${_target} "${_cachedir}")
|
|
|
|
|
|
|
|
if(_breathe_projects)
|
|
|
|
file(APPEND "${_cachedir}/conf.py"
|
|
|
|
"\nbreathe_projects = { ${_breathe_projects} }"
|
|
|
|
"\nbreathe_default_project = '${_breathe_default_project}'")
|
|
|
|
endif()
|
|
|
|
|
|
|
|
add_custom_target(
|
|
|
|
${_target}
|
|
|
|
COMMAND ${SPHINX_BUILD_EXECUTABLE}
|
|
|
|
-b ${_builder}
|
|
|
|
-d "${CMAKE_CURRENT_BINARY_DIR}/${_target}.cache/_doctrees"
|
|
|
|
-c "${CMAKE_CURRENT_BINARY_DIR}/${_target}.cache"
|
|
|
|
"${_sourcedir}"
|
|
|
|
"${_outputdir}"
|
|
|
|
DEPENDS ${_depends})
|
|
|
|
endfunction()
|
|
|
|
|