aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMinos Galanakis <minos.galanakis@arm.com>2020-06-03 15:38:03 +0100
committerTamas Ban <tamas.ban@arm.com>2020-09-24 12:49:54 +0000
commitd19a19f161148b97f3ec8ccec7baebd79599f8c4 (patch)
treeb7d1f354d0a33d533b74f7bcdc3b9865b360504e
parent7b95029a5864ce834e9535ce96da92be3f418a54 (diff)
downloadtrusted-firmware-m-d19a19f161148b97f3ec8ccec7baebd79599f8c4.tar.gz
Docs: Decouple from CMAKE and enable sphynx-build.
This patch is reducing the dependency of the documentation to the TrustedFirmware-M build environment. Currently CMake will copy over files from platforms, render the configuration files, sort design documents and invoke the corresponding tools to build the documentation. This patch introduces an environment communicating interface file, which CMAKE will need to populate, before calling the build command. The file copy operation has been moved over to the sphynx-build logic, and the design document’s classification is no longer required by the new user interface. The new implemenatation allows: * Documentation can be built in an identical way through the build system, retaining compatibility with existing tools, such as the CI. * It is now possible to build documentation, by just invoking sphynx-build from the build-docs directory. * Third party tools/services like readthedocs.org can now render the TF-M documentation. * Reduced CMake code size. * Documentation generating logic invokes ‘git describe’ in order to determine a version. The order of precedence is set as: Git Describe Version-> CMake hardcoded version -> Template version. * CMake logic can still toggle parts of the new logic on and off if required. * The full set of TF-M build dependencies are not longer required in order to build documentation. Just the documentation dependencies would suffice. Change-Id: I12e7bbffe9d1adb756329c46da13905e95096381 Signed-off-by: Minos Galanakis <minos.galanakis@arm.com>
-rw-r--r--build_docs/conf.py32
-rw-r--r--cmake/Common/BuildSphinxDoc.cmake78
-rw-r--r--cmake/SphinxCopyDoc.cmake65
-rw-r--r--cmake/SphinxDesignDocStatus.cmake242
-rw-r--r--docs/getting_started/tfm_build_instruction.rst41
-rw-r--r--docs/tfm_env.py.in28
-rw-r--r--doxygen/Doxyfile.in4
-rw-r--r--tools/documentation/tfm_cmake_defaults.py220
-rw-r--r--tools/documentation/tfm_copy_files.py87
9 files changed, 444 insertions, 353 deletions
diff --git a/build_docs/conf.py b/build_docs/conf.py
new file mode 100644
index 0000000000..5a83618266
--- /dev/null
+++ b/build_docs/conf.py
@@ -0,0 +1,32 @@
+# -----------------------------------------------------------------------------
+# Copyright (c) 2020, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+# -----------------------------------------------------------------------------
+#
+# Configuration file override for the Sphinx documentation builder.
+#
+# This file is used when Sphinx build is invoked directly at this level.
+# It will trigger a copy-files operation and render a new configuration
+# using either auto-detected or cmake provided parameters.
+import os
+import sys
+
+# Attempt to find the tools directory by recursing up to five levels of parents
+root_path = os.path.dirname(os.path.abspath(__file__))
+
+for i in range(5):
+ root_path = os.path.dirname(root_path)
+ doc_path = os.path.join(root_path, "tools", "documentation")
+ if os.path.isdir(doc_path):
+ sys.path.insert(0, os.path.abspath(doc_path))
+sys.path.append("./")
+
+# Trigger the copy operation logic
+import tfm_copy_files
+
+# Import the rendered configuration into global scope
+from tfm_cmake_defaults import *
+
+from conf_rendered import *
diff --git a/cmake/Common/BuildSphinxDoc.cmake b/cmake/Common/BuildSphinxDoc.cmake
index ab08319c3c..e95a9277b2 100644
--- a/cmake/Common/BuildSphinxDoc.cmake
+++ b/cmake/Common/BuildSphinxDoc.cmake
@@ -72,14 +72,28 @@ if (NOT SPHINX_NODOC)
set(SPHINXCFG_OUTPUT_PATH "${CMAKE_CURRENT_BINARY_DIR}/doc_sphinx")
set(SPHINX_TMP_DOC_DIR "${CMAKE_CURRENT_BINARY_DIR}/doc_sphinx_in")
-
+ set(SPHINXCFG_CONFIGURED_FILE "${TFM_ROOT_DIR}/build_docs/conf.py")
set(SPHINXCFG_TEMPLATE_FILE "${TFM_ROOT_DIR}/docs/conf.py.in")
- set(SPHINXCFG_CONFIGURED_FILE "${SPHINXCFG_OUTPUT_PATH}/conf.py")
-
- set(SPHINX_DESIGN_DOC_ROOT "${TFM_ROOT_DIR}/docs/design_documents")
- set(SPHINX_TEMPLATE_INDEX_FILE "${SPHINX_DESIGN_DOC_ROOT}/index.rst.in")
- set(SPHINX_CONFIGURED_INDEX_FILE "${SPHINX_TMP_DOC_DIR}/docs/design_documents/index.rst")
- set(SPHINX_MAIN_INDEX_FILE "docs/index.rst")
+ set(SPHINXCFG_ENVIRONMENT_FILE "${TFM_ROOT_DIR}/docs/tfm_env.py.in")
+ set(_PDF_FILE "${SPHINXCFG_OUTPUT_PATH}/latex/TF-M.pdf")
+
+ # Set the build-tool to copy over the files to ${SPHINX_TMP_DOC_DIR~
+ set(SPHINXCFG_COPY_FILES True)
+ # Set the config to render the conf.py. If needed to build it by cmake
+ # set it to False
+ set(SPHINXCFG_RENDER_CONF True)
+
+ # TODO Reference example on how a doxygen build can be requested.
+ # Currently the logic of BuildDoxygenDoc.cmake is still used for
+ # compatibility purposes.
+ set(DOXYCFG_DOXYGEN_BUILD False)
+ if (SPHINXCFG_RENDER_CONF)
+ find_package(Doxygen 1.8.0)
+ set(DOXYCFG_DOXYGEN_CFG_DIR ${TFM_ROOT_DIR}/doxygen)
+ set(DOXYCFG_OUTPUT_PATH ${SPHINXCFG_OUTPUT_PATH}/user_manual)
+ set(DOXYCFG_ECLIPSE_DOCID "org.arm.tf-m-refman")
+ file(MAKE_DIRECTORY ${SPHINXCFG_OUTPUT_PATH}/user_manual)
+ endif()
#Version ID of TF-M.
#TODO: this shall not be hard-coded here. We need a process to define the
@@ -87,44 +101,26 @@ if (NOT SPHINX_NODOC)
set(SPHINXCFG_TFM_VERSION "v1.1")
set(SPHINXCFG_TFM_VERSION_FULL "Version 1.1")
- get_filename_component(_NDX_FILE_DIR ${SPHINX_CONFIGURED_INDEX_FILE} DIRECTORY )
-
#This command does not generates the specified output file and thus it will
#always be run. Any other command or target depending on the "run-allways"
#output will be always executed too.
add_custom_command(OUTPUT run-allways
COMMAND "${CMAKE_COMMAND}" -E echo)
- #Using add_custom_command allows CMake to generate proper clean commands
- #for document generation.
- add_custom_command(OUTPUT "${SPHINX_TMP_DOC_DIR}"
- "${SPHINX_CONFIGURED_INDEX_FILE}"
- #Create target directory for SPHINX_CONFIGURED_INDEX_FILE. Needed
- #by the next command.
- COMMAND "${CMAKE_COMMAND}" -E make_directory "${_NDX_FILE_DIR}"
- #Fill out index.rst template
- COMMAND "${CMAKE_COMMAND}" -D TFM_ROOT_DIR=${TFM_ROOT_DIR}
- -D SPHINX_TEMPLATE_INDEX_FILE=${SPHINX_TEMPLATE_INDEX_FILE}
- -D SPHINX_CONFIGURED_INDEX_FILE=${SPHINX_CONFIGURED_INDEX_FILE}
- -D SPHINX_DESIGN_DOC_ROOT=${SPHINX_DESIGN_DOC_ROOT}
- -P "${TFM_ROOT_DIR}/cmake/SphinxDesignDocStatus.cmake"
- #Copy document files to temp direcotry
- COMMAND "${CMAKE_COMMAND}" -D TFM_ROOT_DIR=${TFM_ROOT_DIR}
- -D DST_DIR=${SPHINX_TMP_DOC_DIR}
- -D BINARY_DIR=${CMAKE_BINARY_DIR}
- -D MASTER_IDX=${SPHINX_MAIN_INDEX_FILE}
- -P "${TFM_ROOT_DIR}/cmake/SphinxCopyDoc.cmake"
- WORKING_DIRECTORY "${TFM_ROOT_DIR}"
- DEPENDS run-allways
- VERBATIM
- )
+ file(REMOVE_RECURSE ${SPHINX_TMP_DOC_DIR})
+ file(MAKE_DIRECTORY ${SPHINX_TMP_DOC_DIR})
+
+ #Call configure file to fill out the message template.
+ configure_file("${SPHINXCFG_ENVIRONMENT_FILE}" "${SPHINX_TMP_DOC_DIR}/tfm_env.py" @ONLY)
+
+ file(COPY "${SPHINXCFG_CONFIGURED_FILE}" DESTINATION ${SPHINX_TMP_DOC_DIR})
add_custom_target(create_sphinx_input
SOURCES "${SPHINX_TMP_DOC_DIR}"
)
add_custom_command(OUTPUT "${SPHINXCFG_OUTPUT_PATH}/html"
- COMMAND "${SPHINX_EXECUTABLE}" -c "${SPHINXCFG_OUTPUT_PATH}" -b html "${SPHINX_TMP_DOC_DIR}" "${SPHINXCFG_OUTPUT_PATH}/html"
+ COMMAND "${SPHINX_EXECUTABLE}" -b html "${SPHINX_TMP_DOC_DIR}" "${SPHINXCFG_OUTPUT_PATH}/html"
WORKING_DIRECTORY "${TFM_ROOT_DIR}"
DEPENDS create_sphinx_input run-allways
COMMENT "Running Sphinx to generate user guide (HTML)."
@@ -145,6 +141,15 @@ if (NOT SPHINX_NODOC)
PATTERN .buildinfo EXCLUDE
)
+ if (DOXYCFG_DOXYGEN_BUILD)
+ #Add the HTML documentation to install content
+ install(DIRECTORY ${SPHINXCFG_OUTPUT_PATH}/user_manual DESTINATION doc
+ EXCLUDE_FROM_ALL
+ COMPONENT user_guide
+ PATTERN .buildinfo EXCLUDE
+ )
+ endif()
+
#If PDF documentation is being made.
if (LATEX_PDFLATEX_FOUND)
if (NOT CMAKE_GENERATOR MATCHES "Makefiles")
@@ -156,10 +161,8 @@ if (NOT SPHINX_NODOC)
message(FATAL_ERROR "CMAKE_MAKE_PROGRAM is not set. This file must be included after the project command is run.")
endif()
- set(_PDF_FILE "${SPHINXCFG_OUTPUT_PATH}/latex/TF-M.pdf")
-
add_custom_command(OUTPUT "${SPHINXCFG_OUTPUT_PATH}/latex"
- COMMAND "${SPHINX_EXECUTABLE}" -c "${SPHINXCFG_OUTPUT_PATH}" -b latex "${SPHINX_TMP_DOC_DIR}" "${SPHINXCFG_OUTPUT_PATH}/latex"
+ COMMAND "${SPHINX_EXECUTABLE}" -b latex "${SPHINX_TMP_DOC_DIR}" "${SPHINXCFG_OUTPUT_PATH}/latex"
WORKING_DIRECTORY "${TFM_ROOT_DIR}"
DEPENDS create_sphinx_input
COMMENT "Running Sphinx to generate user guide (LaTeX)."
@@ -205,7 +208,4 @@ if (NOT SPHINX_NODOC)
-P "${CMAKE_BINARY_DIR}/cmake_install.cmake")
endif()
- #Now instantiate a Sphinx configuration file from the template.
- message(STATUS "Writing Sphinx configuration...")
- configure_file(${SPHINXCFG_TEMPLATE_FILE} ${SPHINXCFG_CONFIGURED_FILE} @ONLY)
endif()
diff --git a/cmake/SphinxCopyDoc.cmake b/cmake/SphinxCopyDoc.cmake
deleted file mode 100644
index 6bf2f073ad..0000000000
--- a/cmake/SphinxCopyDoc.cmake
+++ /dev/null
@@ -1,65 +0,0 @@
-#-------------------------------------------------------------------------------
-# Copyright (c) 2019, Arm Limited. All rights reserved.
-#
-# SPDX-License-Identifier: BSD-3-Clause
-#
-#-------------------------------------------------------------------------------
-
-#Sphinx needs all document files to be under a single directory. This script
-#copies all document files to a temporary directory while keeping the original
-#directory tree (relative location of files) except "docs/index.rst" which is
-#moved to the top level of the new tree.
-#
-# i.e.:
-# <DST_DIR>
-# | All documents from <TFM_ROOT_DIR> plus <TFM_ROOT_DIR>/docs/index.rst
-# |
-# +---docs
-# | |
-# \- all documents from <TFM_ROOT_DIR>/docs except index.rst
-# |
-# +---lib
-# | |
-# | \- All document from <TFM_ROOT_DIR>/lib keeping reativle location
-# ...
-# |
-#
-#Usage:
-# cmake -DDST_DIR=<path to destination> -DTFM_ROOT_DIR=<path to tf-m root> \
-# -DBINARY_DIR=${CMAKE_BINARY_DIR}
-# -DMASTER_IDX=<path to master index.rst> -P SphinxCopyDoc.cmake
-
-#Check input parameters
-foreach(_PARAM IN ITEMS TFM_ROOT_DIR DST_DIR BINARY_DIR MASTER_IDX)
- if (NOT DEFINED ${_PARAM})
- message(FATAL_ERROR "Variable ${_PARAM} is undefined. Please add -D${_PARAM}=<...> when calling this script.")
- endif()
-endforeach()
-
-message(STATUS "Creating document tree for Sphinx under ${DST_DIR}")
-
-#List all document files.
-file(GLOB_RECURSE _COPY_FILES
- LIST_DIRECTORIES false
- RELATIVE "${TFM_ROOT_DIR}"
- "${TFM_ROOT_DIR}/*.md"
- "${TFM_ROOT_DIR}/*.rst"
- "${TFM_ROOT_DIR}/*.png"
- "${TFM_ROOT_DIR}/*.jpg"
- "${TFM_ROOT_DIR}/dco.txt")
-
-#Remove intermediate and final document build outputs.
-foreach(_PATH IN ITEMS BINARY_DIR DST_DIR)
- file(RELATIVE_PATH _REL_DIR ${TFM_ROOT_DIR} ${${_PATH}})
- list(FILTER _COPY_FILES EXCLUDE REGEX "${_REL_DIR}/.*")
-endforeach()
-
-#Copy files with directory tree.
-foreach(_FILE ${_COPY_FILES})
- get_filename_component(_DIR ${_FILE} DIRECTORY)
- if (_FILE STREQUAL MASTER_IDX)
- file(COPY ${_FILE} DESTINATION "${DST_DIR}")
- else()
- file(COPY ${_FILE} DESTINATION "${DST_DIR}/${_DIR}")
- endif()
-endforeach()
diff --git a/cmake/SphinxDesignDocStatus.cmake b/cmake/SphinxDesignDocStatus.cmake
deleted file mode 100644
index ec8279c2cb..0000000000
--- a/cmake/SphinxDesignDocStatus.cmake
+++ /dev/null
@@ -1,242 +0,0 @@
-#-------------------------------------------------------------------------------
-# Copyright (c) 2019-2020, Arm Limited. All rights reserved.
-#
-# SPDX-License-Identifier: BSD-3-Clause
-#
-#-------------------------------------------------------------------------------
-
-#A script to fill out the "toctree" file lists in index.rst.in to put design
-#documents into the correct section based on their state.
-#
-#First rst files are parsed under a defined directory, to identify document
-#status based on value of the ":Status:" field. Each state will have a list
-#being generated to which matching documents are added. These lists are used
-#then to fill template values using configure_file()
-#
-#The ":Status:" field is optional according to design proposal process.
-#Apparently, only the documents in "Accepted" status will be merged and included
-#in Sphinx build. Therefore, a design document without ":Status:" field will be
-#put in "Accepted" category by default.
-#If there are design document drafts in local environment, it is assumed that
-#developers are aware of the status of these drafts and won't be confused.
-#A message will be still thrown out when a design document doesn't contain
-#":Status:" field. It can be removed if more and more design documents don't
-#maintain that field.
-#
-#Functions are used whenever possible to avoid global variable name space
-#pollution.
-#
-
-Include(CMakeParseArguments)
-
-#Set the status value here to avoid any typo or upper/lower case trouble.
-set(ACCEPTED_STATUS "ACCEPTED")
-set(DRAFT_STATUS "DRAFT")
-set(DETAILED_STATUS "DETAILED")
-#"NO_SET" is used to mark documents without status field.
-set(NO_SET "NO_SET")
-#"INVALID_STATUS" is used to mark a document which specifies the status but the
-#status value is invalid or unrecognized.
-set(INVALID_STATUS "INVALID_STATUS")
-
-#This function will search for .rst files in a given directory, read them and
-#check if the ":Status:" field is defined in them. Then will add each file to a
-#list with a name matching the status value.
-#See the definition of _STATE_VALUES below for a list of valid state values.
-#Files without state value will be placed on the both "Accepted" list and
-#"NO_SET" list.
-#State value comparison is case insensitive.
-#
-#The output lists will have the prefix specified in the PREFIX parameter.
-#
-#Inputs:
-# DIR Directory to scan for rst files.
-# PREFIX The prefix of output list variables.
-#
-#Outputs:
-# <prefix>_<state> - list; all files with a valid state value.
-# <prefix>_NO_SET - list; all files without status field.
-# <prefix>_INVALID_STATUS - list; all files with invalid status field.
-#
-#Examples
-# sphinx_categorize_rst(DIR ${TFM_ROOT_DIR}/docs/design_documents
-# PREFIX "DESIGN_DOCS")
-#
-function(sphinx_categorize_rst)
- #Valid state values.
- set(_STATE_VALUES ${DRAFT_STATUS} ${ACCEPTED_STATUS} ${DETAILED_STATUS}
- ${NO_SET} ${INVALID_STATUS})
-
- #No option (on/off) arguments
- set( _OPTIONS_ARGS )
- #Single option arguments (e.g. PROJ_NAME "bubu_project")
- set( _ONE_VALUE_ARGS DIR PREFIX)
- #List arguments (e.g. LANGUAGES C ASM CXX)
- set( _MULTI_VALUE_ARGS )
-
- cmake_parse_arguments(_MY_PARAMS "${_OPTIONS_ARGS}" "${_ONE_VALUE_ARGS}"
- "${_MULTI_VALUE_ARGS}" ${ARGN} )
-
- #Check parameters
- foreach(_PARAM IN LISTS _ONE_VALUE_ARGS)
- if (NOT DEFINED _MY_PARAMS_${_PARAM})
- message(FATAL_ERROR "Parameter ${_PARAM} is missing!")
- endif()
- endforeach()
-
- #Search for .rst files
- file(GLOB_RECURSE _RST_FILES
- LIST_DIRECTORIES False
- ${_MY_PARAMS_DIR}/**.rst)
-
- #Loop over .rst files
- foreach(_FILE IN LISTS _RST_FILES)
- #Read the file and return the first status line.
- file(STRINGS ${_FILE} _CONTENT REGEX ":Status:" LIMIT_COUNT 1)
-
- #Nothing read -> the field is missing
- if (_CONTENT STREQUAL "")
- #If a document doesn't maintain a status field, put it in
- #Accepted list by default.
- list(APPEND _STATUS_${ACCEPTED_STATUS} ${_FILE})
- #Also add the file to the "NO_SET" list. Thus it can be
- #highlighted later.
- list(APPEND _STATUS_${NO_SET} ${_FILE})
- else()
- #convert to upper case for case insensitive matching.
- string(TOUPPER ${_CONTENT} _CONTENT)
-
- #loop over status values
- foreach(_STATUS IN LISTS _STATE_VALUES)
- #convert to upper case for case insensitive matching.
- string(TOUPPER ${_STATUS} _STATUS)
- #does status match the value from the file?
- if (_CONTENT MATCHES ":STATUS:[ ]*${_STATUS}")
- #add it to the list
- list(APPEND _STATUS_${_STATUS} ${_FILE})
- #and exit the loop
- break()
- endif()
-
- #If the status value is invalid.
- if (_STATUS STREQUAL ${INVALID_STATUS})
- list(APPEND _STATUS_${INVALID_STATUS} ${_FILE})
- endif()
- endforeach()
- endif()
- endforeach()
-
- #return the lists to the caller
- foreach(_STATUS IN LISTS _STATE_VALUES)
- string(TOUPPER ${_STATUS} _STATUS)
-
- if (DEFINED _STATUS_${_STATUS})
- set(${_MY_PARAMS_PREFIX}_${_STATUS} ${_STATUS_${_STATUS}}
- PARENT_SCOPE)
- endif()
- endforeach()
-endfunction()
-
-#Configure (fill in) the Sphinx index.rst.in template file.
-#Call sphinx_categorize_rst() to get the .rst files sorted to lists, and then
-#create the list of files for each design document section (convert the CMake
-#lists to properly formatted text).
-#Finally call configure_file() to fill in the values.
-#
-#Inputs:
-# SRC Full path to template index file
-# DST Full patch to configured output file.
-# DOC_DIR Path to design documents directory.
-# DOC_ROOT Path to root directory of documentation
-#
-#Outputs:
-# Configured <DST> file.
-#
-#Examples
-# sphinx_categorize_rst(DIR ${TFM_ROOT_DIR}/docs/design_documents
-# PREFIX "DESIGN_DOCS")
-#
-function(sphinx_configure_index)
- set(_STATE_VALUES ${DRAFT_STATUS} ${ACCEPTED_STATUS} ${DETAILED_STATUS}
- ${DEFAULT_STATUS} ${INVALID_STATUS})
-
- #No option (on/off) arguments
- set( _OPTIONS_ARGS )
- #Single option arguments (e.g. PROJ_NAME "bubu_project")
- set( _ONE_VALUE_ARGS SRC DST DOC_ROOT DOC_DIR)
- #List arguments (e.g. LANGUAGES C ASM CXX)
- set( _MULTI_VALUE_ARGS )
-
- cmake_parse_arguments(_MY_PARAMS "${_OPTIONS_ARGS}" "${_ONE_VALUE_ARGS}"
- "${_MULTI_VALUE_ARGS}" ${ARGN} )
-
- #Check parameters
- foreach(_PARAM IN LISTS _ONE_VALUE_ARGS)
- if (NOT DEFINED _MY_PARAMS_${_PARAM})
- message(FATAL_ERROR "Parameter ${_PARAM} is missing!")
- endif()
- endforeach()
-
- #Assign design documents to lists based on their status
- sphinx_categorize_rst(DIR ${_MY_PARAMS_DOC_DIR} PREFIX "_DD")
-
- #Highlight documents without status field
- if (DEFINED _DD_${NO_SET})
- string(REPLACE ";" "\n \t" _DD_${NO_SET} "${_DD_${NO_SET}}")
- message(" The following documents are put into Accepted category without status field:\n \t${_DD_${NO_SET}}")
- endif()
-
- #Look for invalid documents
- if (DEFINED _DD_${INVALID_STATUS})
- string(REPLACE ";" "\n \t" _DD_${INVALID_STATUS} "${_DD_${INVALID_STATUS}}")
- message(WARNING " The following documents provide invalid status information:\n \t${_DD_${INVALID_STATUS}}")
- endif()
-
- #The document root must be an absolute path
- get_filename_component(_MY_PARAMS_DOC_ROOT "${_MY_PARAMS_DOC_ROOT}"
- ABSOLUTE)
-
- #Loop over status lists
- foreach(_STATUS IN ITEMS ${DRAFT_STATUS} ${DETAILED_STATUS} ${ACCEPTED_STATUS})
- #Create an empty file list for this status
- set(${_STATUS}_DD_LIST "")
- #If the source list is empty go to next iteration
- if (NOT DEFINED _DD_${_STATUS})
- continue()
- endif()
-
- #Loop over files on the list of this status
- foreach(_FILE IN LISTS _DD_${_STATUS})
-
- # Strip path from the filesince index is placed in same location
- get_filename_component(_FILE ${_FILE} NAME)
- #Detailed and Draft files go to the same section
- if (_STATUS STREQUAL ${DETAILED_STATUS})
- set(_STATUS ${DRAFT_STATUS})
- endif()
-
- #Append the file to the output string
- string(APPEND ${_STATUS}_DD_LIST "\n ${_FILE}")
- endforeach()
- endforeach()
-
- #Call configure file to fill out the template.
- configure_file(${_MY_PARAMS_SRC} ${_MY_PARAMS_DST} @ONLY)
-endfunction()
-
-#If being run in script mode (cmake -P) and not included.
-if (DEFINED CMAKE_SCRIPT_MODE_FILE
- AND (CMAKE_CURRENT_LIST_FILE STREQUAL CMAKE_SCRIPT_MODE_FILE))
- #Check input variables.
- foreach(_PARAM IN ITEMS SPHINX_TEMPLATE_INDEX_FILE SPHINX_CONFIGURED_INDEX_FILE
- SPHINX_DESIGN_DOC_ROOT TFM_ROOT_DIR)
- if (NOT DEFINED ${_PARAM})
- message(FATAL_ERROR "Parameter ${_PARAM} is not set!")
- endif()
- endforeach()
-
- sphinx_configure_index(SRC ${SPHINX_TEMPLATE_INDEX_FILE}
- DST ${SPHINX_CONFIGURED_INDEX_FILE}
- DOC_DIR ${SPHINX_DESIGN_DOC_ROOT}
- DOC_ROOT ${TFM_ROOT_DIR})
-endif()
diff --git a/docs/getting_started/tfm_build_instruction.rst b/docs/getting_started/tfm_build_instruction.rst
index 29982c0d68..a8e890b63c 100644
--- a/docs/getting_started/tfm_build_instruction.rst
+++ b/docs/getting_started/tfm_build_instruction.rst
@@ -176,9 +176,17 @@ Further details on how to integrate a new NS app with TF-M are available in the
Building the documentation
==========================
-Please ensure the dependencies for building the firmware and the
-documentation are installed as explained in the
-:doc:`software requirements <tfm_sw_requirement>`.
+Please ensure the dependencies for building the documentation are installed
+as explained in the :doc:`software requirements <tfm_sw_requirement>`. The
+requirements to build the firmware, are only required when using the CMAKE
+method
+
+There are currently two ways of building the documentation:
+- Using the CMake build system as custom targets
+- Manually using the appropriate tools (`sphinx-build`_/ `Doxygen`_)
+
+Using the CMake build-system
+----------------------------
Building PDF output is optional and can be disabled by removing LaTex from the
PATH.
@@ -188,7 +196,7 @@ PATH.
be available.
Building the Reference Manual
------------------------------
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. code-block:: bash
cd <TF-M base folder>
@@ -202,7 +210,7 @@ The documentation files will be available under the directory::
cmake_doc/install/doc/reference_manual
Building the User Guide
------------------------
+^^^^^^^^^^^^^^^^^^^^^^^
.. code-block:: bash
cd <TF-M base folder>
@@ -215,6 +223,26 @@ The documentation files will be available under the directory::
cmake_doc/install/doc/user_guide
+Manually using documentation generation tools
+---------------------------------------------
+
+Invoking Sphinx-build will build both user_guide and reference_manual
+targets.
+
+.. code-block:: bash
+
+ # Build the documentation from build_docs directory
+ cd <TF-M base folder>/ build_docs/
+ sphinx-build ./ user_guide
+
+ # Build the documentation from a custom location
+ # setting the build_docs as input
+
+ # Note that using this method will still generate the reference manual
+ # to the <TF-M base folder>/build_docs/reference_manual
+ cd <TF-M base folder>/OTHER_DIR/OTHER_DIR2
+ sphinx-build <TF-M base folder>/build_docs/ DESIRED_OUTPUT_DIR
+
*********************
Configuring the build
*********************
@@ -344,6 +372,9 @@ The following table describes the differences between the configurations:
.. [7] Profile Small config doesn't cover all the platforms. Please check
Profile Small config files to find out the supported platforms.
+.. _sphinx-build: https://www.sphinx-doc.org/en/master/man/sphinx-build.html
+.. _Doxygen: https://www.doxygen.nl
+
--------------
*Copyright (c) 2017-2020, Arm Limited. All rights reserved.*
diff --git a/docs/tfm_env.py.in b/docs/tfm_env.py.in
new file mode 100644
index 0000000000..b96be484d6
--- /dev/null
+++ b/docs/tfm_env.py.in
@@ -0,0 +1,28 @@
+# -----------------------------------------------------------------------------
+# Copyright (c) 2020, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+# -----------------------------------------------------------------------------
+
+# Interface file between cmake and sphynx-build. Variables will be populated
+# by cmake and evaluated by the Python builder
+
+cmake_env = { "SPHINX_TMP_DOC_DIR": "@SPHINX_TMP_DOC_DIR@",
+ "TFM_ROOT_DIR" : "@TFM_ROOT_DIR@",
+ "PLANTUML_JAR_PATH" : "@PLANTUML_JAR_PATH@",
+ "Java_JAVA_EXECUTABLE" : "@Java_JAVA_EXECUTABLE@",
+ "SPHINX_TMP_DOC_DIR" : "@SPHINX_TMP_DOC_DIR@",
+ "DOXYGEN_EXECUTABLE" : "@DOXYGEN_EXECUTABLE@",
+ "DOXYGEN_DOT_EXECUTABLE" : "@DOXYGEN_DOT_EXECUTABLE@",
+ "DOXYCFG_DOXYGEN_CFG_DIR": "@DOXYCFG_DOXYGEN_CFG_DIR@",
+ "DOXYCFG_OUTPUT_PATH": "@DOXYCFG_OUTPUT_PATH@",
+ "DOXYCFG_DOXYGEN_BUILD": "@DOXYCFG_DOXYGEN_BUILD@",
+ "DOXYCFG_ECLIPSE_DOCID": "@DOXYCFG_ECLIPSE_DOCID@",
+ "SPHINXCFG_TEMPLATE_FILE": "@SPHINXCFG_TEMPLATE_FILE@",
+ "PDF_OUTPUT_FILE": "@_PDF_FILE@",
+ "SPHINXCFG_COPY_FILES": "@SPHINXCFG_COPY_FILES@",
+ "SPHINXCFG_RENDER_CONF": "@SPHINXCFG_RENDER_CONF@",
+ "SPHINXCFG_TFM_VERSION" : "@SPHINXCFG_TFM_VERSION@",
+ "SPHINXCFG_TFM_VERSION_FULL" : "@SPHINXCFG_TFM_VERSION_FULL@"
+ }
diff --git a/doxygen/Doxyfile.in b/doxygen/Doxyfile.in
index 9a1e475041..ccfa60cc68 100644
--- a/doxygen/Doxyfile.in
+++ b/doxygen/Doxyfile.in
@@ -1,5 +1,5 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2018-2019, Arm Limited. All rights reserved.
+# Copyright (c) 2018-2020, Arm Limited. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -58,7 +58,7 @@ PROJECT_BRIEF = Trusted Firmware-M
# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
# the logo to the output directory.
-PROJECT_LOGO = ./doxygen/TrustedFirmware-Logo_icon.png
+PROJECT_LOGO = @TFM_ROOT_DIR@/doxygen/TrustedFirmware-Logo_icon.png
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
# into which the generated documentation will be written. If a relative path is
diff --git a/tools/documentation/tfm_cmake_defaults.py b/tools/documentation/tfm_cmake_defaults.py
new file mode 100644
index 0000000000..e90bd6065e
--- /dev/null
+++ b/tools/documentation/tfm_cmake_defaults.py
@@ -0,0 +1,220 @@
+# -----------------------------------------------------------------------------
+# Copyright (c) 2020, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+# -----------------------------------------------------------------------------
+
+# This module is providing the default parameters for manual Documentation
+# building. ( Without relying on CMake to determine the enviroment )
+#
+# It will however be able to communicate parameters when populated
+# by CMake (using the tfm_env.py file), and use a best-effort approach
+# to determine them when the interface file is not preset.
+
+import os
+import re
+import json
+from subprocess import check_output
+from platform import system
+
+# When called after cmake an evniroment variables file will be present
+try:
+ from tfm_env import cmake_env
+except Exception as E:
+ print("ERROR: Configuration Exception:", E)
+ cmake_env = None
+
+tfm_def_render_cmake = True
+tfm_def_copy_files = True
+tfm_def_build_doxygen = True
+
+
+def find_tfm_root(start_dir=os.path.dirname(os.path.abspath(__file__)),
+ target_files=["license.rst",
+ "dco.txt",
+ "CommonConfig.cmake"],
+ max_depth=5):
+ """ Method which attempts to find the root of the project
+ by traversing parent directoried and attempts to located each of the
+ files included in target_files list"""
+
+ tfm_root = start_dir
+
+ for i in range(max_depth):
+ tfm_root = os.path.dirname(tfm_root)
+ if set(target_files).issubset(set(os.listdir(tfm_root))):
+ return tfm_root
+ return None
+
+
+def find_package(binary_name):
+ """ Attempts to resolve the abolute path for a given application or return
+ empty string is nothing is found"""
+
+ sys_det = system()
+
+ if sys_det == "Windows":
+ cmd = "where"
+ # Window's where requires the extension
+ binary_name = binary_name + ".exe"
+ elif sys_det in ["Darwin", "Linux"]:
+ cmd = "which"
+ try:
+ return check_output([cmd, binary_name]).decode('UTF-8').strip()
+ except Exception as E:
+ return ""
+
+
+def render_cmake_file(config_map, in_file, out_file):
+ """ Read an input file containing CMAKE variables and try to
+ render them based on a configuration map. Variables not listed
+ on the map will be cleared """
+
+ # Read the input file
+ with open(in_file, "r", encoding='utf-8') as F:
+ _data = F.read()
+
+ # Render all config entires included in the map
+ for k, v in config_map.items():
+ v = v.replace("\\", "\\\\")
+ _data = re.sub(r'@%s@' % k, r'%s' % v, _data)
+
+ # Set all remaining entries to blank
+ _data = re.sub(r'@[A-Z\_]+@', "", _data)
+
+ # Create output file
+ with open(out_file, "w", encoding='utf-8') as F:
+ F.write(_data)
+
+
+# Default output director for reference_manual. It should not be empty
+tfm_def_doxy_output_dir = "reference_manual"
+
+
+if cmake_env is None:
+ # #################### Automatic Defaults ( Standalone )################# #
+
+ # Resolve ../../
+ tfm_def_root_dir = find_tfm_root()
+
+ # Set the copy files directory to whatever will be passed to sphynx-build
+ tfm_def_copy_dir = os.path.abspath(os.getcwd())
+
+ # Documentation base path
+ tfm_def_doc_root = os.path.join(tfm_def_root_dir, "docs")
+ tfm_def_copy_doc_root = os.path.join(tfm_def_copy_dir, "docs")
+
+ tfm_def_doxy_root = os.path.join(tfm_def_root_dir, "doxygen")
+
+ tfm_def_doxy_output_dir = os.path.join(tfm_def_copy_dir,
+ tfm_def_doxy_output_dir)
+
+ # Input files ( Files containing CMAKE variables )
+ tfm_def_conf_in_file = os.path.join(tfm_def_doc_root, "conf.py.in")
+ tfm_def_doxygen_in_file = os.path.join(tfm_def_doxy_root, "Doxyfile.in")
+
+ # Attempt to detect plantUML
+ _ubuntu_plantum_loc = "/usr/share/plantuml/plantuml.jar"
+ if "PLANTUML_JAR_PATH" in os.environ.keys():
+ tfm_def_plantum_loc = os.environ["PLANTUML_JAR_PATH"]
+ elif os.path.isfile(_ubuntu_plantum_loc):
+ tfm_def_plantum_loc = _ubuntu_plantum_loc
+ else:
+ tfm_def_plantum_loc = ""
+
+ # Attempt to detect the java interpreter location
+ tfm_def_java_binary = find_package("java")
+ tfm_def_doxygen_loc = find_package("doxygen")
+ tfm_def_doxygen_dot_loc = find_package("dot")
+
+else:
+ # #################### Cmake Defaults ################################## #
+ tfm_def_root_dir = os.path.abspath(cmake_env["TFM_ROOT_DIR"])
+ tfm_def_copy_dir = os.path.abspath(cmake_env["SPHINX_TMP_DOC_DIR"])
+ tfm_def_plantum_loc = os.path.abspath(cmake_env["PLANTUML_JAR_PATH"])
+ tfm_def_java_binary = os.path.abspath(cmake_env["Java_JAVA_EXECUTABLE"])
+ tfm_def_tfm_ver_shrt = cmake_env["SPHINXCFG_TFM_VERSION"]
+ tfm_def_tfm_ver_full = cmake_env["SPHINXCFG_TFM_VERSION_FULL"]
+ tfm_def_conf_in_file = cmake_env["SPHINXCFG_TEMPLATE_FILE"]
+
+ tfm_def_copy_files = True if cmake_env["SPHINXCFG_COPY_FILES"] == "True" \
+ else False
+ tfm_def_render_cmake = True \
+ if cmake_env["SPHINXCFG_RENDER_CONF"] == "True" else False
+
+ tfm_def_build_doxygen = True \
+ if cmake_env["DOXYCFG_DOXYGEN_BUILD"] == "True" else False
+
+ if tfm_def_build_doxygen:
+ tfm_def_doxy_root = cmake_env["DOXYCFG_DOXYGEN_CFG_DIR"]
+ tfm_def_doxygen_in_file = os.path.join(tfm_def_doxy_root,
+ "Doxyfile.in")
+
+ # Documentation base path
+ tfm_def_doc_root = os.path.join(tfm_def_root_dir, "docs")
+ tfm_def_copy_doc_root = os.path.join(tfm_def_copy_dir, "docs")
+
+ # Disable copyfiles for next invocation
+ cmake_env["SPHINXCFG_COPY_FILES"] = "False"
+ with open("tfm_env.py", "w", encoding='utf-8') as F:
+ F.write("cmake_env =" + json.dumps(cmake_env))
+
+
+# Version will be retrieved in that order Git -> Cmake -> Boilerplate
+try:
+ tfm_def_tfm_ver_full = check_output(["git",
+ "describe",
+ "--tags"]).decode('UTF-8').strip()
+ proj, ver, commit_no, git_hash = tfm_def_tfm_ver_full.split("-")
+
+ if (int(commit_no) > 0):
+ tfm_def_tfm_ver_shrt = tfm_def_tfm_ver_full
+ else:
+ tfm_def_tfm_ver_shrt = proj + ver
+
+except Exception as E:
+ try:
+ tfm_def_tfm_ver_shrt
+ except NameError:
+ tfm_def_tfm_ver_shrt = "v1.0.0-B"
+ try:
+ tfm_def_tfm_ver_full
+ except NameError:
+ tfm_def_tfm_ver_full = "v1.0.0-B"
+
+# #################### User Defaults ######################################## #
+
+# Directories, referenced by TF-M root, which may contain releval documents
+# which need to be broughtt over
+document_scan_dirs = ["tools", "platform"]
+
+document_scan_ext = [".rst", ".md", ".jpg", ".png"]
+
+# Other documents that should be added to the root documentation folder
+documents_extra = ["license.rst", "dco.txt"]
+
+# Output files ( After CMAKE variables have been evaluated )
+tfm_def_conf_out_file = os.path.join(tfm_def_copy_dir, "conf_rendered.py")
+if tfm_def_build_doxygen:
+ tfm_def_doxygen_out_file = os.path.join(tfm_def_doxy_root,
+ "DoxyfileCfg.in")
+
+# If env is none, the script is running as standalone. Generate it with the
+# auto-detected values set above
+if cmake_env is None:
+ cmake_env = {"TFM_ROOT_DIR": tfm_def_root_dir,
+ "DOXYGEN_EXECUTABLE": tfm_def_doxygen_loc,
+ "DOXYGEN_DOT_EXECUTABLE": tfm_def_doxygen_dot_loc,
+ "PLANTUML_JAR_PATH": tfm_def_plantum_loc,
+ "SPHINXCFG_TFM_VERSION": tfm_def_tfm_ver_shrt,
+ "SPHINXCFG_TFM_VERSION_FULL": tfm_def_tfm_ver_full,
+ "Java_JAVA_EXECUTABLE": tfm_def_java_binary,
+ "DOXYCFG_OUTPUT_PATH": tfm_def_doxy_output_dir,
+ "DOXYCFG_ECLIPSE_DOCID": "org.arm.tf-m-refman",
+ "DOXYCFG_TFM_VERSION": tfm_def_tfm_ver_full,
+ }
+# Only Override the version
+else:
+ cmake_env["SPHINXCFG_TFM_VERSION"] = tfm_def_tfm_ver_shrt
+ cmake_env["SPHINXCFG_TFM_VERSION_FULL"] = tfm_def_tfm_ver_full
diff --git a/tools/documentation/tfm_copy_files.py b/tools/documentation/tfm_copy_files.py
new file mode 100644
index 0000000000..09226c81c3
--- /dev/null
+++ b/tools/documentation/tfm_copy_files.py
@@ -0,0 +1,87 @@
+# -----------------------------------------------------------------------------
+# Copyright (c) 2020, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+# -----------------------------------------------------------------------------
+
+# Interface module for pre-processing the documentation content
+# before sphynx-build is called
+#
+# It collects files from multiple sources in a intermediate location
+# before calling sphinx-build, thus overriding the limitation
+# of having the documentation share a common root directory.
+#
+# It can be triggered by simply importing the module
+import os
+from shutil import copy2, copytree, rmtree, move
+from glob import glob
+from tfm_cmake_defaults import *
+from subprocess import call
+
+
+def tfm_copy_files():
+ doc_files = []
+
+ # Recursively list all files with extensions and add them
+ for _path in document_scan_dirs:
+ _path = os.path.abspath(os.path.join(tfm_def_root_dir, _path))
+ for ext in document_scan_ext:
+ doc_files.extend([f for f in glob(os.path.join(_path,
+ "**/*%s" % ext),
+ recursive=True)])
+
+ # Add the extra files
+ for _doc_file in documents_extra:
+ _doc_file = os.path.abspath(os.path.join(tfm_def_root_dir, _doc_file))
+ if os.path.isfile(_doc_file):
+ doc_files.append(_doc_file)
+
+ # Clean up all files in target dir except conf.py and tfm_env.py
+ files = [f for f in
+ glob("*", recursive=False) if f not in ["conf.py",
+ tfm_def_conf_out_file,
+ os.path.basename(
+ tfm_def_doxy_output_dir),
+ "tfm_env.py"]]
+ for f in files:
+ if os.path.isfile(f):
+ os.remove(f)
+ elif os.path.isdir(f):
+ rmtree(f)
+
+ # Copy the documentation folder as is
+ copytree(tfm_def_doc_root, tfm_def_copy_doc_root)
+
+ # Move the index to the intermediate build directory
+ # docs/index.rst --> ./index.rst
+ move(os.path.join(tfm_def_copy_doc_root, "index.rst"), tfm_def_copy_dir)
+
+ for df in list(doc_files):
+ # Set the target filename to be cwd + relative to root path of origin
+ target_f = os.path.relpath(df, tfm_def_root_dir)
+ target_f = os.path.join(tfm_def_copy_dir, target_f)
+ # Create path for file (nested) without exception if exists
+ os.makedirs(os.path.dirname(target_f), exist_ok=True)
+ # Copy the file to new location
+ copy2(df, target_f)
+
+
+# Build Doxygen Documnetation
+if tfm_def_build_doxygen:
+ # if conf file is not provided by cmake
+ if tfm_def_render_cmake:
+ render_cmake_file(cmake_env,
+ tfm_def_doxygen_in_file,
+ tfm_def_doxygen_out_file)
+ # Call doxygen to generate the documentation
+ doxygen_bin = find_package("doxygen")
+ call([doxygen_bin, tfm_def_doxygen_out_file])
+
+# Only act if requested by defaults
+if tfm_def_copy_files:
+ tfm_copy_files()
+
+if tfm_def_render_cmake:
+ # Render the conf_py file
+ render_cmake_file(cmake_env, tfm_def_conf_in_file, tfm_def_conf_out_file)