Doc: Add support for Sphinx documentation build.

Technical documentation of TF-M is captured in GitHub flavored
markdown files. This change add support for building HTML and
PDF output of these files using the Sphinx tool.

Change-Id: I8be11256f2c654c248b1974974a5de6190ca0fc3
Signed-off-by: Gyorgy Szing <Gyorgy.Szing@arm.com>
diff --git a/cmake/Common/BuildDoxygenDoc.cmake b/cmake/Common/BuildDoxygenDoc.cmake
index 6f9c6c7..f98c0f9 100644
--- a/cmake/Common/BuildDoxygenDoc.cmake
+++ b/cmake/Common/BuildDoxygenDoc.cmake
@@ -56,7 +56,7 @@
 		set(DOXYGEN_EXECUTABLE "${DOXYGEN_EXECUTABLE}" PARENT_SCOPE)
 		set(DOXYGEN_DOT_EXECUTABLE "${DOXYGEN_DOT_EXECUTABLE}" PARENT_SCOPE)
 		set(PLANTUML_JAR_PATH "${PLANTUML_JAR_PATH}" PARENT_SCOPE)
-		set(_NODOC False PARENT_SCOPE)
+		set(NODOC False PARENT_SCOPE)
 	else()
 		message(WARNING "Some tools are missing for document generation. Document generation target is not created.")
 		set(NODOC True PARENT_SCOPE)
@@ -85,7 +85,7 @@
 	#Version ID of TF-M.
 	#TODO: this shall not be hard-coded here. A process need to defined for
 	#      versioning the document (and TF-M).
-	set(DOXYCFG_TFM_VERSION "v0.01")
+	set(DOXYCFG_TFM_VERSION "v1.0.0-Beta")
 
 	#Using add_custom_command allows CMake to generate proper clean commands
 	#for document generation.
diff --git a/cmake/Common/BuildSphinxDoc.cmake b/cmake/Common/BuildSphinxDoc.cmake
new file mode 100644
index 0000000..7287d05
--- /dev/null
+++ b/cmake/Common/BuildSphinxDoc.cmake
@@ -0,0 +1,169 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2019, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+#This file adds build and install targets to build the Sphinx documentation
+#for TF-M. This currently means the "User Guide". Further documentation
+#builds may be added in the future.
+
+Include(CMakeParseArguments)
+
+#This function will find the location of tools needed to build the
+#documentation. These are:
+#   - Mandatory:
+#        - Sphinx 1.9.0 or higher
+#        - PlantUML and it's dependencies
+#   - Optional
+#        - LateX/PDFLateX
+#
+#Inputs:
+#   none (some global variables might be used by FindXXX modules used. For
+#         details please check the modules used.)
+#Outputs:
+#   SPHINX_NODOC - will be defined and set to true is any mandatory tool is
+#                  missing.
+#   PDFLATEX_COMPILER - path to pdflatex executable
+#   SPHINX_EXECUTABLE - path to sphinx-build
+#   PLANTUML_JAR_PATH - path to PlantUML
+
+#Examples
+#   SphinxFindTools()
+#
+function(SphinxFindTools)
+	find_package(Sphinx)
+
+	#Find additional needed python dependencies.
+	find_package(PythonModules COMPONENTS m2r sphinx-rtd-theme)
+
+	#Find plantUML
+	find_package(PlantUML)
+
+	#Find tools needed for PDF generation.
+	find_package(LATEX COMPONENTS PDFLATEX)
+	if (LATEX_PDFLATEX_FOUND)
+		set (PDFLATEX_COMPILER "${PDFLATEX_COMPILER}" PARENT_SCOPE)
+	endif()
+
+	if (SPHINX_FOUND AND PLANTUML_FOUND AND PY_M2R_FOUND
+			AND PY_SPHINX-RTD-THEME_FOUND)
+		#Export executable locations to global scope.
+		set(SPHINX_EXECUTABLE "${SPHINX_EXECUTABLE}" PARENT_SCOPE)
+		set(PLANTUML_JAR_PATH "${PLANTUML_JAR_PATH}" PARENT_SCOPE)
+		set(SPHINX_NODOC False PARENT_SCOPE)
+	else()
+		message(WARNING "Some tools are missing for Sphinx document generation. Document generation target is not created.")
+		set(SPHINX_NODOC True PARENT_SCOPE)
+	endif()
+endfunction()
+
+#Find the needed tools.
+SphinxFindTools()
+
+#If mandatory tools are missing, skip creating document generation targets.
+#This means missing documentation tools is not a critical error, and building
+#TF-M is still possible.
+if (NOT SPHINX_NODOC)
+	#The Sphinx configuration file needs some project specific configuration.
+	#Variables with SPHINXCFG_ prefix are setting values related to that.
+	#This is where Sphinx output will be written
+	set(SPHINXCFG_OUTPUT_PATH "${CMAKE_CURRENT_BINARY_DIR}/doc_sphinx")
+
+	set(SPHINX_TMP_DOC_DIR "${CMAKE_CURRENT_BINARY_DIR}/doc_sphinx_in")
+
+	set(SPHINXCFG_TEMPLATE_FILE "${TFM_ROOT_DIR}/docs/Conf.py.in")
+	set(SPHINXCFG_CONFIGURED_FILE "${SPHINXCFG_OUTPUT_PATH}/Conf.py")
+
+
+	#Version ID of TF-M.
+	#TODO: this shall not be hard-coded here. We need a process to define the
+	#      version number of the document (and TF-M).
+	set(SPHINXCFG_TFM_VERSION "1.0.0-Beta")
+	set(SPHINXCFG_TFM_VERSION_FULL "Version 1.0.0-Beta")
+
+	#Using add_custom_command allows CMake to generate proper clean commands
+	#for document generation.
+	add_custom_command(OUTPUT "${SPHINX_TMP_DOC_DIR}"
+		COMMAND "${CMAKE_COMMAND}" -D TFM_ROOT_DIR=${TFM_ROOT_DIR} -D DST_DIR=${SPHINX_TMP_DOC_DIR} -P "${TFM_ROOT_DIR}/cmake/SphinxCopyDoc.cmake"
+		WORKING_DIRECTORY "${TFM_ROOT_DIR}"
+		VERBATIM
+		)
+
+	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"
+		WORKING_DIRECTORY "${TFM_ROOT_DIR}"
+		DEPENDS "${SPHINX_TMP_DOC_DIR}"
+		COMMENT "Running Sphinx to generate user guide (HTML)."
+		VERBATIM
+		)
+
+	#Create build target to generate HTML documentation.
+	add_custom_target(doc_userguide
+		COMMENT "Generating User Guide with Sphinx..."
+		#Copy document files from the top level dir to docs
+		SOURCES "${SPHINXCFG_OUTPUT_PATH}/html"
+		)
+
+	#Add the HTML documentation to install content
+	install(DIRECTORY ${SPHINXCFG_OUTPUT_PATH}/html DESTINATION doc/user_guide
+		EXCLUDE_FROM_ALL
+		COMPONENT user_guide
+		PATTERN .buildinfo EXCLUDE
+		)
+
+	#If PDF documentation is being made.
+	if (PDFLATEX_COMPILER)
+		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"
+			WORKING_DIRECTORY "${TFM_ROOT_DIR}"
+			DEPENDS "${SPHINX_TMP_DOC_DIR}"
+			COMMENT "Running Sphinx to generate user guide (LaTeX)."
+			VERBATIM
+			)
+
+		add_custom_command(OUTPUT "${_PDF_FILE}"
+			COMMAND "${CMAKE_MAKE_PROGRAM}" all-pdf
+			WORKING_DIRECTORY ${SPHINXCFG_OUTPUT_PATH}/latex
+			DEPENDS "${SPHINXCFG_OUTPUT_PATH}/latex"
+			COMMENT "Generating PDF version of User Guide..."
+			VERBATIM
+			)
+
+		#We do not use the add_custom_command trick here to get proper clean
+		#command since the clean rules "added" above will remove the entire
+		#doc directory, and thus clean the PDF output too.
+		add_custom_target(doc_userguide_pdf
+			COMMENT "Generating PDF version of TF-M User Guide..."
+			SOURCES "${_PDF_FILE}"
+			VERBATIM)
+
+		#Add the pdf documentation to install content
+		install(FILES "${_PDF_FILE}" DESTINATION "doc/user_guide"
+			RENAME "tf-m_user_guide.pdf"
+			COMPONENT user_guide
+			EXCLUDE_FROM_ALL)
+	else()
+		message(WARNING "PDF generation tools are missing. PDF document generation target is not created.")
+	endif()
+
+	#Generate build target which installs the documentation.
+	if (TARGET doc_userguide_pdf)
+		add_custom_target(install_userguide
+			DEPENDS doc_userguide doc_userguide_pdf
+			COMMAND "${CMAKE_COMMAND}" -DCMAKE_INSTALL_COMPONENT=user_guide
+			-P "${CMAKE_BINARY_DIR}/cmake_install.cmake")
+	else()
+		add_custom_target(install_userguide
+			DEPENDS doc_userguide
+			COMMAND "${CMAKE_COMMAND}" -DCMAKE_INSTALL_COMPONENT=user_guide
+			-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/Common/Utils.cmake b/cmake/Common/Utils.cmake
index 0c3b0d0..452d0bf 100644
--- a/cmake/Common/Utils.cmake
+++ b/cmake/Common/Utils.cmake
@@ -1,31 +1,41 @@
 #-------------------------------------------------------------------------------
-# Copyright (c) 2017, Arm Limited. All rights reserved.
+# Copyright (c) 2017-2019, Arm Limited. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
 #-------------------------------------------------------------------------------
 
-# Append a value to a string if not already present
+
+#Print a message and exit with failure
 #
-# Append an item to a string if no item with matching key is already on the string.
-# This function's intended purpose is to append unique flags to command line switches.
+#Examples:
+#   failure("Something is wrong!")
+
+function(failure)
+	message(FATAL_ERROR "${ARGN}")
+endfunction()
+
+#Append a value to a string if not already present
 #
-# Examples:
-#  string_append_unique_item(STRING C_FLAGS KEY "--target" VAL "--target=armv8m-arm-none-eabi")
+#Append an item to a string if no item with matching key is already on the string.
+#This function's intended purpose is to append unique flags to command line switches.
 #
-# INPUTS:
-#    STRING  - (mandatory) - name of the string to operate on
-#    KEY   - (mandatory) - string to look for
-#    VAL   - (mandatory) - value to put be added to the string
+#Examples:
+#   string_append_unique_item(STRING C_FLAGS KEY "--target" VAL "--target=armv8m-arm-none-eabi")
 #
-# OUTPUTS
-#    STRING is modified as needed.
+#INPUTS:
+#   STRING  - (mandatory) - name of the string to operate on
+#   KEY     - (mandatory) - string to look for
+#   VAL     - (mandatory) - value to put be added to the string
+#
+#OUTPUTS
+#   STRING is modified as needed.
 #
 function(string_append_unique_item)
 	#Parse our arguments
-	set( _OPTIONS_ARGS )					#No option (on/off) arguments (e.g. IGNORE_CASE)
-	set( _ONE_VALUE_ARGS  STRING KEY VAL)	#Single option arguments (e.g. PATH "./foo/bar")
-	set( _MULTI_VALUE_ARGS )		 		#List arguments (e.g. LANGUAGES C ASM CXX)
+	set( _OPTIONS_ARGS )                    #No option (on/off) arguments (e.g. IGNORE_CASE)
+	set( _ONE_VALUE_ARGS  STRING KEY VAL)   #Single option arguments (e.g. PATH "./foo/bar")
+	set( _MULTI_VALUE_ARGS )                #List arguments (e.g. LANGUAGES C ASM CXX)
 	cmake_parse_arguments(_MY_PARAMS "${_OPTIONS_ARGS}" "${_ONE_VALUE_ARGS}" "${_MULTI_VALUE_ARGS}" ${ARGN} )
 
 	#Check mandatory parameters
@@ -42,11 +52,54 @@
 	if(NOT _MY_PARAMS_VAL)
 		failure("string_append_unique_item(): Missing VAL parameter!")
 	endif()
-    set(_VAL ${_MY_PARAMS_VAL})
+	set(_VAL ${_MY_PARAMS_VAL})
 
-    #Scan the string.
-    STRING(REGEX MATCH "( |^) *${_KEY}" _FOUND "${${_STRING}}")
-    if("${_FOUND}" STREQUAL "")
+	#Scan the string.
+	STRING(REGEX MATCH "( |^) *${_KEY}" _FOUND "${${_STRING}}")
+	if("${_FOUND}" STREQUAL "")
 		set(${_STRING} "${${_STRING}}  ${_VAL}" PARENT_SCOPE)
-    endif()
+	endif()
+endfunction()
+
+
+#Convert \ directory separators to / on windows systems
+#
+#Convert the directory separators to forward slash on windows. Avoid
+#conversion if path contains any forward slashes to avoid mixing up cygwin or
+#mingw paths where an extra caharacter is escaped (i.e. "/c/Program\ Files/")
+#
+#Examples:
+#   set(MY_PATH "C:\foo\bar")
+#   win_fix_dir_sep(PATH MY_PATH)
+#
+#INPUTS:
+#   PATH  - (mandatory) - name of the string variable to operate on
+#
+#OUTPUTS
+#   PATH is modified as needed.
+#
+function(win_fix_dir_sep)
+	#Parse our arguments
+	set( _OPTIONS_ARGS )            #No option (on/off) arguments (e.g. IGNORE_CASE)
+	set( _ONE_VALUE_ARGS  PATH )    #Single option arguments (e.g. PATH "./foo/bar")
+	set( _MULTI_VALUE_ARGS )        #List arguments (e.g. LANGUAGES C ASM CXX)
+	cmake_parse_arguments(_MY_PARAMS "${_OPTIONS_ARGS}" "${_ONE_VALUE_ARGS}" "${_MULTI_VALUE_ARGS}" ${ARGN} )
+
+	#Check mandatory parameters
+	if(NOT _MY_PARAMS_PATH)
+		failure("win_fix_dir_sep(): Missing mandatory parameter PATH!")
+	endif()
+	set(_PATH ${_MY_PARAMS_PATH})
+
+	#To avoid trouble on windows change directory separator.
+	if (CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
+		#Do not convert directory separator if there are forward slashes
+		#present. This is to avoid mixing up escaped characters in cygwin
+		#or mingw paths (i.e. c:/Program\ Files/something)
+		string(FIND "${${_PATH}}" "/" _is_found)
+		if (_is_found LESS 0)
+			string(REPLACE "\\" "/" ${_PATH} "${${_PATH}}")
+			set(${_PATH} "${${_PATH}}" PARENT_SCOPE)
+		endif()
+	endif()
 endfunction()