# # Copyright (c) 2019-2020, New York University and Max Planck Gesellschaft. # # License BSD-3 clause # # Build the documentation based on sphinx and the read_the_doc layout. #
#.rst: # # .. cmake:command:: _BUILD_DOXYGEN # # Use doxygen to parse the C++ source files and generate a corresponding xml # entry. # macro(_BUILD_DOXYGEN)
# Find “doxygen” find_package(Doxygen) if(NOT DOXYGEN_FOUND)
- message(
- FATAL_ERROR
“Doxygen is needed to build the documentation. Please install it correctly”
)
endif()
# Create the doxyfile in function of the current project. If the Doxyfile.in # does not exists, the cmake step stops. configure_file(${DOXYGEN_DOXYFILE_IN} ${DOXYGEN_DOXYFILE} @ONLY IMMEDIATE)
# the doxygen target is generated add_custom_target(
${PROJECT_NAME}_sphinx_doxygen COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYGEN_DOXYFILE} SOURCES ${DOXYGEN_DOXYFILE} # if the file change rebuild WORKING_DIRECTORY ${DOXYGEN_OUTPUT} COMMENT “Building xml doxygen documentation for ${PROJECT_NAME}”)
- set(SPHINX_BUILD_TARGET_DEPEND ${SPHINX_BUILD_TARGET_DEPEND}
${PROJECT_NAME}_sphinx_doxygen)
endmacro(_BUILD_DOXYGEN)
#.rst: # # .. cmake:command:: _BUILD_BREATHE_APIDOC # # Use breathe_apidoc to parse the xml output from Doxygen and generate .rst # files. # macro(_BUILD_BREATHE_APIDOC)
# Find the breathe find_program(BREATHE_APIDOC breathe-apidoc) if(NOT BREATHE_APIDOC)
- message(FATAL_ERROR “breathe-apidoc not found!”
“Please install using: pip3 install breathe”)
endif()
file(MAKE_DIRECTORY ${BREATHE_OUTPUT}) add_custom_target(
${PROJECT_NAME}_breathe_apidoc # Generate the .rst files from the doxygen xml output ${BREATHE_APIDOC} -o ${BREATHE_OUTPUT} ${BREATHE_INPUT} ${BREATHE_OPTION} WORKING_DIRECTORY ${SPHINX_DOC_BUILD_FOLDER} DEPENDS ${PROJECT_NAME}_sphinx_doxygen COMMENT “Building breathe-apidoc for ${PROJECT_NAME}”)
- set(SPHINX_BUILD_TARGET_DEPEND ${SPHINX_BUILD_TARGET_DEPEND}
${PROJECT_NAME}_breathe_apidoc)
endmacro(_BUILD_BREATHE_APIDOC)
#.rst: # # .. cmake:command:: _BUILD_SPHINX_API_DOC # # Use sphinx_apidoc to parse the python files output from Doxygen and generate # .rst files. # macro(_BUILD_SPHINX_API_DOC)
# Find the sphinx-apidoc executable. find_program(SPHINX_APIDOC sphinx-apidoc) if(NOT SPHINX_APIDOC)
- message(FATAL_ERROR “sphinx-apidoc not found!”
“Please install using: pip3 install sphinx”)
endif()
# Create the output file(MAKE_DIRECTORY ${SPHINX_APIDOC_OUTPUT}) add_custom_target(
${PROJECT_NAME}_sphinx_apidoc ${SPHINX_APIDOC} -o ${SPHINX_APIDOC_OUTPUT} ${SPHINX_APIDOC_INPUT} WORKING_DIRECTORY ${SPHINX_APIDOC_OUTPUT} COMMENT “Building sphinx-apidoc for ${PROJECT_NAME}”)
- set(SPHINX_BUILD_TARGET_DEPEND ${SPHINX_BUILD_TARGET_DEPEND}
${PROJECT_NAME}_sphinx_apidoc)
endmacro(_BUILD_SPHINX_API_DOC)
#.rst: # # .. cmake:command:: _BUILD_SPHINX_BUILD # # Use sphinx_build to parse the cmake and rst files previously generated and # generate the final html layout. # macro(_BUILD_SPHINX_BUILD)
# Find the sphinx-apidoc executable. find_program(SPHINX_BUILD sphinx-build) if(NOT SPHINX_BUILD)
- message(FATAL_ERROR “sphinx-apidoc not found!”
“Please install using: pip3 install sphinx”)
endif()
# Create the output file(MAKE_DIRECTORY ${SPHINX_DOC_BUILD_FOLDER}) add_custom_target(
${PROJECT_NAME}_sphinx_html ${SPHINX_BUILD} -M html ${SPHINX_BUILD_INPUT} ${SPHINX_DOC_BUILD_FOLDER} ${SPHINX_OPTION} WORKING_DIRECTORY ${SPHINX_DOC_BUILD_FOLDER} DEPENDS ${SPHINX_BUILD_TARGET_DEPEND} COMMENT “Building sphinx-apidoc for ${PROJECT_NAME}”)
endmacro(_BUILD_SPHINX_BUILD)
#.rst:
#
# .. cmake:command:: _FIND_README
#
# Search for a README with the given file extension and, if found, return
# its name using OUTPUT_VAR
. Example to search for ‘readme.md’::
#
# _FIND_README(readme_file “md”)
#
macro(_FIND_README OUTPUT_VAR EXTENSION)
- file(
GLOB files RELATIVE ${PROJECT_SOURCE_DIR} ${PROJECT_SOURCE_DIR}/*.${EXTENSION})
- foreach(file ${files})
string(TOLOWER ${file} file_lower) if(${file_lower} STREQUAL “readme.${EXTENSION}”)
set(${OUTPUT_VAR} ${file})
endif()
endforeach()
endmacro()
#.rst: # # .. cmake:command:: ADD_SPHINX_DOCUMENTATION # # Process the current project in order to generate a specific documentation # content. This macro generates the appropriate documentation if is detects the # corresponding files:: # * files with the extensions {.h, .cpp, …} generates # the C++ API section. # * the python folder will generate the Python API section. # * the cmake folder will generate the CMake API section. # * the doc folder containing markdown files (.md) will generate the # Additionnal Documentation section. # # The following macros are called in order and if needed:: * :command: # _BUILD_DOXYGEN * :command: _BUILD_BREATHE_APIDOC * :command: # _BUILD_SPHINX_API_DOC * :command: _BUILD_SPHINX_BUILD # # Please refer to the Sphinx paragraph in the General Documentation in this # package for more explanation about the parametrization of the tools. # macro(ADD_SPHINX_DOCUMENTATION)
# All parameters
# Build and install directories set(SPHINX_DOC_BUILD_FOLDER ${CMAKE_BINARY_DIR}/share/docs/sphinx) set(SPHINX_DOC_INSTALL_FOLDER share/${PROJECT_NAME}/docs/sphinx) # Doxygen set(DOXYGEN_DOXYFILE_IN
${MPI_CMAKE_MODULES_RESOURCES_DIR}/sphinx/doxygen/Doxyfile.in)
set(DOXYGEN_DOXYFILE ${SPHINX_DOC_BUILD_FOLDER}/doxygen/Doxyfile) set(DOXYGEN_OUTPUT ${SPHINX_DOC_BUILD_FOLDER}/doxygen) set(DOXYGEN_XML_OUTPUT ${SPHINX_DOC_BUILD_FOLDER}/doxygen/xml) set(DOXYGEN_FILE_PATTERNS “*.h *.hpp *.hh *.cpp *.c *.cc *.hxx”) # Breathe apidoc set(BREATHE_INPUT ${SPHINX_DOC_BUILD_FOLDER}/doxygen/xml) set(BREATHE_OUTPUT ${SPHINX_DOC_BUILD_FOLDER}/breathe_apidoc) set(BREATHE_OPTION -g union,namespace,class,group,struct,file,interface) # Sphinx apidoc set(SPHINX_APIDOC_INPUT ${PROJECT_SOURCE_DIR}/python/${PROJECT_NAME}) set(SPHINX_APIDOC_OUTPUT ${SPHINX_DOC_BUILD_FOLDER}) # Shinx build set(SPHINX_BUILD_INPUT ${SPHINX_DOC_BUILD_FOLDER}) set(SPHINX_BUILD_OUTPUT ${SPHINX_BUILD_INPUT}) set(SPHINX_BUILD_OPTION -Q) # quiet the sphinx output # Make sure the sphinx-build is not executed before the different API are # built. set(SPHINX_BUILD_TARGET_DEPEND “”)
# Parameterize the final layout
# Build the C++ API rst files if needed set(CPP_API “”) string(REPLACE ” ” “;” DOXYGEN_FILE_PATTERNS_LIST ${DOXYGEN_FILE_PATTERNS}) set(CPP_FILES “”) foreach(pattern ${DOXYGEN_FILE_PATTERNS_LIST})
- file(GLOB_RECURSE CPP_FILES_FOUND FOLLOW_SYMLINKS
${PROJECT_SOURCE_DIR}/${pattern})
set(CPP_FILES ${CPP_FILES} ${CPP_FILES_FOUND})
endforeach() if(NOT “${CPP_FILES}” STREQUAL “”)
# Add the C++ API to the main documentation set(CPP_API
“C++ APIn——-n.. toctree::n :maxdepth: 2nn doxygen_indexnn”
) # Associated configuration files configure_file(
${MPI_CMAKE_MODULES_RESOURCES_DIR}/sphinx/sphinx/doxygen_index_one_page.rst.in ${SPHINX_DOC_BUILD_FOLDER}/doxygen_index_one_page.rst @ONLY IMMEDIATE)
- configure_file(
${MPI_CMAKE_MODULES_RESOURCES_DIR}/sphinx/sphinx/doxygen_index.rst.in ${SPHINX_DOC_BUILD_FOLDER}/doxygen_index.rst @ONLY IMMEDIATE)
# Build the doxygen xml files. _build_doxygen() # Generate the .rst corresponding to the doxygen xml _build_breathe_apidoc()
endif() # Build the Python API rst files if needed set(PYTHON_API “”) if(IS_DIRECTORY ${PROJECT_SOURCE_DIR}/python)
# Add the Python API to the main documentation set(PYTHON_API
“Python APIn———-n* Module Indexnn.. toctree::n :maxdepth: 3nn modulesnn”
) # Generate the .rst corresponding to the python module(s) _build_sphinx_api_doc()
endif() # Build the cmake API if needed set(CMAKE_API “”) if(IS_DIRECTORY ${PROJECT_SOURCE_DIR}/cmake)
# Add the cmake files to the main documentation set(CMAKE_API
“CMake APIn———n.. toctree::n :maxdepth: 3nn cmake_docnn”
)
# Create the list of cmake files file(
GLOB_RECURSE CMAKE_FILES_FOUND RELATIVE ${PROJECT_SOURCE_DIR} FOLLOW_SYMLINKS ${PROJECT_SOURCE_DIR}/cmake/*.cmake)
list(SORT CMAKE_FILES_FOUND) set(DOC_CMAKE_MODULE “”) foreach(cmake_file ${CMAKE_FILES_FOUND})
- set(DOC_CMAKE_MODULE
“${DOC_CMAKE_MODULE}${cmake_file}n———————————————————————-nn .. cmake-module:: ${cmake_file}nn”
)
endforeach(cmake_file ${CMAKE_FILES_FOUND})
# Add the cmake documentation to the main doc configure_file(
${MPI_CMAKE_MODULES_RESOURCES_DIR}/sphinx/sphinx/cmake_doc.rst.in ${SPHINX_DOC_BUILD_FOLDER}/cmake_doc.rst @ONLY IMMEDIATE)
# Create a symlink to the cmake folder add_custom_target(
${PROJECT_NAME}_cmake_symlink ${CMAKE_COMMAND} -E create_symlink ${PROJECT_SOURCE_DIR}/cmake ${SPHINX_DOC_BUILD_FOLDER}/cmake WORKING_DIRECTORY ${SPHINX_DOC_BUILD_FOLDER} COMMENT “Add the doc folder to the sphinx build.”)
- set(SPHINX_BUILD_TARGET_DEPEND ${SPHINX_BUILD_TARGET_DEPEND}
${PROJECT_NAME}_cmake_symlink)
endif() # Build the general documentation if needed set(ADDITIONNAL_DOC_PATH “”) if(IS_DIRECTORY ${PROJECT_SOURCE_DIR}/doc)
# Add the general documentation to the main one if needed. set(ADDITIONNAL_DOC_PATH “doc/*”) # Add the cmake files to the main documentation set(GENERAL_DOCUMENTATION
“General Documentationn———————n.. toctree::n :maxdepth: 2nn general_documentationnn”
)
# Create a symlink to the doc folder containing the Markdown files. add_custom_target(
${PROJECT_NAME}_doc_symlink ${CMAKE_COMMAND} -E create_symlink ${PROJECT_SOURCE_DIR}/doc ${SPHINX_DOC_BUILD_FOLDER}/doc WORKING_DIRECTORY ${SPHINX_DOC_BUILD_FOLDER} COMMENT “Add the doc folder to the sphinx build.”)
- set(SPHINX_BUILD_TARGET_DEPEND ${SPHINX_BUILD_TARGET_DEPEND}
${PROJECT_NAME}_doc_symlink)
endif()
# Generate the configuration files set(HEADER “Welcome to ${PROJECT_NAME}’s documentation!”) string(LENGTH ${HEADER} HEADER_LENGTH) set(HEADER_UNDERLINE “”) foreach(i RANGE ${HEADER_LENGTH})
string(CONCAT HEADER_UNDERLINE “${HEADER_UNDERLINE}=”)
endforeach() set(HEADER “${HEADER}n${HEADER_UNDERLINE}”) configure_file(
${MPI_CMAKE_MODULES_RESOURCES_DIR}/sphinx/sphinx/conf.py.in ${SPHINX_DOC_BUILD_FOLDER}/conf.py @ONLY IMMEDIATE)
- configure_file(
${MPI_CMAKE_MODULES_RESOURCES_DIR}/sphinx/sphinx/index.rst.in ${SPHINX_DOC_BUILD_FOLDER}/index.rst @ONLY IMMEDIATE)
- configure_file(
${MPI_CMAKE_MODULES_RESOURCES_DIR}/sphinx/sphinx/general_documentation.rst.in ${SPHINX_DOC_BUILD_FOLDER}/general_documentation.rst @ONLY IMMEDIATE)
# Fetch the readme.md and the license.txt _FIND_README(readme_file “md”) if(NOT readme_file)
# If no “readme.md” is found, let’s check if there is a “readme.rst” _FIND_README(readme_file “rst”)
- if(NOT readme_file)
message(FATAL_ERROR “No readme file found.”)
endif()
endif() add_custom_target(
${PROJECT_NAME}_readme_symlink ${CMAKE_COMMAND} -E create_symlink ${PROJECT_SOURCE_DIR}/${readme_file} ${SPHINX_DOC_BUILD_FOLDER}/readme.md WORKING_DIRECTORY ${SPHINX_DOC_BUILD_FOLDER} COMMENT “Add the readme.md folder to the sphinx build.”)
- add_custom_target(
${PROJECT_NAME}_license_symlink ${CMAKE_COMMAND} -E create_symlink ${PROJECT_SOURCE_DIR}/license.txt ${SPHINX_DOC_BUILD_FOLDER}/license.txt WORKING_DIRECTORY ${SPHINX_DOC_BUILD_FOLDER} COMMENT “Add the license.txt folder to the sphinx build.”)
- set(SPHINX_BUILD_TARGET_DEPEND
${SPHINX_BUILD_TARGET_DEPEND} ${PROJECT_NAME}_readme_symlink ${PROJECT_NAME}_license_symlink)
# We generate the final layout. Mardown files are looked for automatically. _build_sphinx_build()
# install the documentation if(GENERATE_DOCUMENTATION)
- install(DIRECTORY ${SPHINX_DOC_BUILD_FOLDER}/html
DESTINATION ${SPHINX_DOC_INSTALL_FOLDER})
endif()
# Create a dependency on the doc target add_dependencies(doc ${PROJECT_NAME}_sphinx_html)
endmacro(ADD_SPHINX_DOCUMENTATION)