Migrate Mbed TLS to use LazyFetch

In Mbed TLS 3.2 the necessary functionality was implemented to support
adding Mbed TLS as a CMake package. This makes it possible to use the
FetchContent feature of CMake (and in turn the LazyFetch module of TS)
to download and build Mbed TLS. All of the other external CMake projects
in TS already use the LazyFetch module, which reduces code duplication
by introducing functions that encapsulate the standard "fetch, patch,
configure, build" steps that are necessary for building CMake projects.

This commit replaces the existing Mbed TLS build procedure to use
LazyFetch instead. It also moves the config options of Mbed TLS from
command line arguments in the MbedTLS.cmake file into a dedicated config
file (or in CMake terminology, an "initial CMake cache" file).

Signed-off-by: Balint Dobszay <balint.dobszay@arm.com>
Change-Id: I0aa32f0f847abc3045db4031fefd2cd4e4b684e7
diff --git a/deployments/component-test/component-test.cmake b/deployments/component-test/component-test.cmake
index f8ffe9f..e80b766 100644
--- a/deployments/component-test/component-test.cmake
+++ b/deployments/component-test/component-test.cmake
@@ -1,5 +1,5 @@
 #-------------------------------------------------------------------------------
-# Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -199,7 +199,7 @@
 
 # Mbed TLS provides libmbedcrypto
 include(${TS_ROOT}/external/MbedTLS/MbedTLS.cmake)
-target_link_libraries(component-test PRIVATE mbedcrypto)
+target_link_libraries(component-test PRIVATE MbedTLS::mbedcrypto)
 
 # Qcbor
 include(${TS_ROOT}/external/qcbor/qcbor.cmake)
diff --git a/deployments/crypto/crypto.cmake b/deployments/crypto/crypto.cmake
index 9ca26cd..5b7b58e 100644
--- a/deployments/crypto/crypto.cmake
+++ b/deployments/crypto/crypto.cmake
@@ -46,7 +46,7 @@
 
 # Mbed TLS provides libmbedcrypto
 include(${TS_ROOT}/external/MbedTLS/MbedTLS.cmake)
-target_link_libraries(crypto PRIVATE mbedcrypto)
+target_link_libraries(crypto PRIVATE MbedTLS::mbedcrypto)
 
 #################################################################
 
diff --git a/deployments/env-test/suites/baremetal-tests.cmake b/deployments/env-test/suites/baremetal-tests.cmake
index 6baf1f6..325e238 100644
--- a/deployments/env-test/suites/baremetal-tests.cmake
+++ b/deployments/env-test/suites/baremetal-tests.cmake
@@ -1,5 +1,5 @@
 #-------------------------------------------------------------------------------
-# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -39,7 +39,7 @@
 
 # Mbed TLS provides libmbedcrypto
 include(${TS_ROOT}/external/MbedTLS/MbedTLS.cmake)
-target_link_libraries(env-test PRIVATE mbedcrypto)
+target_link_libraries(env-test PRIVATE MbedTLS::mbedcrypto)
 
 #-------------------------------------------------------------------------------
 #  This test suite depends on platform specific drivers
diff --git a/deployments/libts/linux-pc/CMakeLists.txt b/deployments/libts/linux-pc/CMakeLists.txt
index ecc72ef..515fd71 100644
--- a/deployments/libts/linux-pc/CMakeLists.txt
+++ b/deployments/libts/linux-pc/CMakeLists.txt
@@ -1,5 +1,5 @@
 #-------------------------------------------------------------------------------
-# Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -153,7 +153,7 @@
 
 # Mbed TLS provides libmbedcrypto
 include(${TS_ROOT}/external/MbedTLS/MbedTLS.cmake)
-target_link_libraries(ts PRIVATE mbedcrypto)
+target_link_libraries(ts PRIVATE MbedTLS::mbedcrypto)
 
 # Qcbor
 include(${TS_ROOT}/external/qcbor/qcbor.cmake)
@@ -212,4 +212,4 @@
 protobuf_generate_all(TGT "libts-test" NAMESPACE "protobuf" BASE_DIR "${TS_ROOT}/protocols")
 
 # Mbedcrypto
-target_link_libraries(libts-test PRIVATE mbedcrypto)
+target_link_libraries(libts-test PRIVATE MbedTLS::mbedcrypto)
diff --git a/deployments/platform-inspect/platform-inspect.cmake b/deployments/platform-inspect/platform-inspect.cmake
index 01328b6..77d441a 100644
--- a/deployments/platform-inspect/platform-inspect.cmake
+++ b/deployments/platform-inspect/platform-inspect.cmake
@@ -1,5 +1,5 @@
 #-------------------------------------------------------------------------------
-# Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -50,7 +50,7 @@
 
 # Mbed TLS provides libmbedcrypto
 include(../../../external/MbedTLS/MbedTLS.cmake)
-target_link_libraries(platform-inspect PRIVATE mbedcrypto)
+target_link_libraries(platform-inspect PRIVATE MbedTLS::mbedcrypto)
 
 # Qcbor
 include(${TS_ROOT}/external/qcbor/qcbor.cmake)
diff --git a/deployments/psa-api-test/initial_attestation/iat-api-test.cmake b/deployments/psa-api-test/initial_attestation/iat-api-test.cmake
index 1d2c515..0d8c5ac 100644
--- a/deployments/psa-api-test/initial_attestation/iat-api-test.cmake
+++ b/deployments/psa-api-test/initial_attestation/iat-api-test.cmake
@@ -1,5 +1,5 @@
 #-------------------------------------------------------------------------------
-# Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -53,7 +53,7 @@
 
 # Mbed TLS provides libmbedcrypto
 include(${TS_ROOT}/external/MbedTLS/MbedTLS.cmake)
-target_link_libraries(${PROJECT_NAME} PRIVATE mbedcrypto)
+target_link_libraries(${PROJECT_NAME} PRIVATE MbedTLS::mbedcrypto)
 
 #-------------------------------------------------------------------------------
 #  Advertise PSA API include paths to PSA Arch tests
diff --git a/deployments/ts-demo/ts-demo.cmake b/deployments/ts-demo/ts-demo.cmake
index 9fd8585..f276ca1 100644
--- a/deployments/ts-demo/ts-demo.cmake
+++ b/deployments/ts-demo/ts-demo.cmake
@@ -1,5 +1,5 @@
 #-------------------------------------------------------------------------------
-# Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -52,7 +52,7 @@
 
 # Mbed TLS provides libmbedcrypto
 include(${TS_ROOT}/external/MbedTLS/MbedTLS.cmake)
-target_link_libraries(ts-demo PRIVATE mbedcrypto)
+target_link_libraries(ts-demo PRIVATE MbedTLS::mbedcrypto)
 
 #-------------------------------------------------------------------------------
 #  Define install content.
diff --git a/external/MbedTLS/MbedTLS.cmake b/external/MbedTLS/MbedTLS.cmake
index 17d2981..5c97a15 100644
--- a/external/MbedTLS/MbedTLS.cmake
+++ b/external/MbedTLS/MbedTLS.cmake
@@ -15,155 +15,51 @@
 		CACHE PATH "Mbed TLS installation directory")
 set(MBEDTLS_BUILD_TYPE "Release" CACHE STRING "Mbed TLS build type")
 
-find_library(MBEDCRYPTO_LIB_FILE
-				NAMES libmbedcrypto.a mbedcrypto.a libmbedcrypto.lib mbedcrypto.lib
-				PATHS ${MBEDTLS_INSTALL_DIR}
-				PATH_SUFFIXES "lib"
-				DOC "Location of mberdrypto library."
-				NO_DEFAULT_PATH
+find_package(Python3 REQUIRED COMPONENTS Interpreter)
+
+# Mbed TLS has a custom config script that must be ran before invoking CMake.
+# This script configures which components of the project will get built, in our
+# use case only mbedcrypto is necessary. LazyFetch has a PATCH_COMMAND option
+# that was intended to be used for patching the repo after fetch, but before
+# running CMake. However, it can be "misused" in this case to run the Mbed TLS
+# config script.
+set(GIT_OPTIONS
+	GIT_REPOSITORY ${MBEDTLS_URL}
+	GIT_TAG ${MBEDTLS_REFSPEC}
+	GIT_SHALLOW FALSE
+	PATCH_COMMAND ${Python3_EXECUTABLE} scripts/config.py crypto
 )
 
-set(MBEDCRYPTO_LIB_FILE ${MBEDCRYPTO_LIB_FILE})
-unset(MBEDCRYPTO_LIB_FILE CACHE)
-
-set(MBEDTLS_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/_deps/mbedtls-build")
-
-# Binary not found and it needs to be built.
-if (NOT MBEDCRYPTO_LIB_FILE)
-	# Determine the number of processes to run while running parallel builds.
-	# Pass -DPROCESSOR_COUNT=<n> to cmake to override.
-	if(NOT DEFINED PROCESSOR_COUNT)
-		include(ProcessorCount)
-		ProcessorCount(PROCESSOR_COUNT)
-		set(PROCESSOR_COUNT ${PROCESSOR_COUNT}
-				CACHE STRING "Number of cores to use for parallel builds.")
-	endif()
-
-	# See if the source is available locally
-	find_file(MBEDCRYPTO_HEADER_FILE
-		NAMES crypto.h
-		PATHS ${MBEDTLS_SOURCE_DIR}
-		PATH_SUFFIXES "include/psa"
-		NO_DEFAULT_PATH
-	)
-	set(MBEDCRYPTO_HEADER_FILE ${MBEDCRYPTO_HEADER_FILE})
-	unset(MBEDCRYPTO_HEADER_FILE CACHE)
-
-	# Source not found, fetch it.
-	if (NOT MBEDCRYPTO_HEADER_FILE)
-		include(FetchContent)
-
-		# Checking git
-		find_program(GIT_COMMAND "git")
-		if (NOT GIT_COMMAND)
-			message(FATAL_ERROR "Please install git")
-		endif()
-
-		# Fetching Mbed TLS
-		FetchContent_Declare(
-			mbedtls
-			SOURCE_DIR ${MBEDTLS_SOURCE_DIR}
-			BINARY_DIR ${MBEDTLS_BINARY_DIR}
-			GIT_REPOSITORY ${MBEDTLS_URL}
-			GIT_TAG ${MBEDTLS_REFSPEC}
-			GIT_SHALLOW FALSE
-		)
-
-		# FetchContent_GetProperties exports mbedtls_SOURCE_DIR and mbedtls_BINARY_DIR variables
-		FetchContent_GetProperties(mbedtls)
-		# FetchContent_Populate will fail if the source directory is removed since it will try to
-		# do an "update" and not a "populate" action. As a workaround, remove the subbuild directory.
-		# Note: this fix assumes, the default subbuild location is used.
-		file(REMOVE_RECURSE "${CMAKE_CURRENT_BINARY_DIR}/_deps/mbedtls-subbuild")
-
-		# If the source directory has been moved, the binary dir must be regenerated from scratch.
-		file(REMOVE_RECURSE "${MBEDTLS_BINARY_DIR}")
-
-		if (NOT mbedtls_POPULATED)
-			message(STATUS "Fetching Mbed TLS")
-			FetchContent_Populate(mbedtls)
-		endif()
-		set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${MBEDTLS_SOURCE_DIR})
-	endif()
-
-	# Build mbedcrypto library
-
-	# Convert the include path list to a string. Needed to make parameter passing to
-	# Mbed TLS build work fine.
-	string(REPLACE ";" "\\;" MBEDTLS_EXTRA_INCLUDES "${MBEDTLS_EXTRA_INCLUDES}")
-
-	find_package(Python3 REQUIRED COMPONENTS Interpreter)
-
-	#Configure Mbed TLS to build only mbedcrypto lib
-	execute_process(COMMAND ${Python3_EXECUTABLE} scripts/config.py crypto WORKING_DIRECTORY ${MBEDTLS_SOURCE_DIR})
-
+# Only pass libc settings to Mbed TLS if needed. For environments where the standard
+# library is not overridden, this is not needed.
+if(TARGET stdlib::c)
 	include(${TS_ROOT}/tools/cmake/common/PropertyCopy.cmake)
-
-	# Only pass libc settings to MbedTLS if needed. For environments where the standard
-	# library is not overridden, this is not needed.
-	if(TARGET stdlib::c)
-		# Save libc settings
-		save_interface_target_properties(TGT stdlib::c PREFIX MBEDTLS)
-		# Translate libc settings to set of lists. _lists is not used since we know exactly which translated
-		# variables we need to pass to MbedTLS.
-		translate_interface_target_properties(PREFIX MBEDTLS RES _lists TO_LIST)
-		unset_saved_properties(MBEDTLS)
-		string(REPLACE ";" " " MBEDTLS_CMAKE_C_FLAGS_INIT "${MBEDTLS_CMAKE_C_FLAGS_INIT}")
-		string(REPLACE ";" " " MBEDTLS_CMAKE_EXE_LINKER_FLAGS_INIT "${MBEDTLS_CMAKE_EXE_LINKER_FLAGS_INIT}")
-	else()
-		set(MBEDTLS_CMAKE_C_FLAGS_INIT "")
-		set(MBEDTLS_CMAKE_EXE_LINKER_FLAGS_INIT "")
-		# _lists is set to allow namespace clean-up by calling unset_translated_lists()
-		set(_lists "MBEDTLS_CMAKE_C_FLAGS_INIT;MBEDTLS_CMAKE_EXE_LINKER_FLAGS_INIT")
-	endif()
-
-	#Configure the library
-	execute_process(COMMAND
-		${CMAKE_COMMAND} -E env "CROSS_COMPILE=${CROSS_COMPILE}"
-			${CMAKE_COMMAND}
-				-DCMAKE_BUILD_TYPE=${MBEDTLS_BUILD_TYPE}
-				-DENABLE_PROGRAMS=OFF
-				-DENABLE_TESTING=OFF
-				-DUNSAFE_BUILD=ON
-				-DCMAKE_INSTALL_PREFIX=${MBEDTLS_INSTALL_DIR}
-				-DCMAKE_TOOLCHAIN_FILE=${TS_EXTERNAL_LIB_TOOLCHAIN_FILE}
-				-DCMAKE_TRY_COMPILE_TARGET_TYPE=STATIC_LIBRARY
-				-DEXTERNAL_DEFINITIONS=-DMBEDTLS_USER_CONFIG_FILE="${MBEDTLS_USER_CONFIG_FILE}"
-				-DEXTERNAL_INCLUDE_PATHS=${MBEDTLS_EXTRA_INCLUDES}
-				-DCMAKE_C_FLAGS_INIT=${MBEDTLS_CMAKE_C_FLAGS_INIT}
-				-DCMAKE_EXE_LINKER_FLAGS_INIT=${MBEDTLS_CMAKE_EXE_LINKER_FLAGS_INIT}
-				-GUnix\ Makefiles
-				-S ${MBEDTLS_SOURCE_DIR}
-		 		-B ${MBEDTLS_BINARY_DIR}
-		RESULT_VARIABLE _exec_error
-	)
-	unset_translated_lists(_lists)
-
-	if (_exec_error)
-		message(FATAL_ERROR "Configuration step of Mbed TLS failed with ${_exec_error}.")
-	endif()
-
-	#Build the library
-	execute_process(COMMAND
-			${CMAKE_COMMAND} --build ${MBEDTLS_BINARY_DIR} --parallel ${PROCESSOR_COUNT} --target install
-			RESULT_VARIABLE _exec_error
-		)
-
-	if (_exec_error)
-		message(FATAL_ERROR "Build step of Mbed TLS failed with ${_exec_error}.")
-	endif()
-
-	set(MBEDCRYPTO_LIB_FILE "${MBEDTLS_INSTALL_DIR}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}mbedcrypto${CMAKE_STATIC_LIBRARY_SUFFIX}")
+	# Save libc settings
+	save_interface_target_properties(TGT stdlib::c PREFIX LIBC)
+	# Translate libc settings to CMake code fragment. Will be inserted into
+	# mbedtls-init-cache.cmake.in when LazyFetch configures the file.
+	translate_interface_target_properties(PREFIX LIBC RES _cmake_fragment)
+	unset_saved_properties(LIBC)
 endif()
 
-# Advertise Mbed TLS as the provider of the psa crypto API
-set(PSA_CRYPTO_API_INCLUDE "${MBEDTLS_INSTALL_DIR}/include" CACHE STRING "PSA Crypto API include path")
+include(${TS_ROOT}/tools/cmake/common/LazyFetch.cmake REQUIRED)
+LazyFetch_MakeAvailable(DEP_NAME MbedTLS
+	FETCH_OPTIONS ${GIT_OPTIONS}
+	INSTALL_DIR ${MBEDTLS_INSTALL_DIR}
+	PACKAGE_DIR ${MBEDTLS_INSTALL_DIR}/cmake
+	CACHE_FILE "${TS_ROOT}/external/MbedTLS/mbedtls-init-cache.cmake.in"
+)
+unset(_cmake_fragment)
 
-#Create an imported target to have clean abstraction in the build-system.
-add_library(mbedcrypto STATIC IMPORTED)
-set_property(DIRECTORY ${CMAKE_SOURCE_DIR} APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${MBEDCRYPTO_LIB_FILE})
-set_property(TARGET mbedcrypto PROPERTY IMPORTED_LOCATION ${MBEDCRYPTO_LIB_FILE})
-set_property(TARGET mbedcrypto PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${MBEDTLS_INSTALL_DIR}/include")
+# Link the libraries created by Mbed TLS to libc if needed. For environments where the standard
+# library is not overridden, this is not needed.
 if(TARGET stdlib::c)
-	target_link_libraries(mbedcrypto INTERFACE stdlib::c)
-endif()
\ No newline at end of file
+	foreach(_mbedtls_tgt IN ITEMS "MbedTLS::mbedcrypto" "MbedTLS::mbedx509" "MbedTLS::mbedtls")
+		target_link_libraries(${_mbedtls_tgt} INTERFACE stdlib::c)
+	endforeach()
+	unset(_mbedtls_tgt)
+endif()
+
+# Advertise Mbed TLS as the provider of the PSA Crypto API
+set(PSA_CRYPTO_API_INCLUDE "${MBEDTLS_INSTALL_DIR}/include"
+		CACHE STRING "PSA Crypto API include path")
diff --git a/external/MbedTLS/mbedtls-init-cache.cmake.in b/external/MbedTLS/mbedtls-init-cache.cmake.in
new file mode 100644
index 0000000..62d33ef
--- /dev/null
+++ b/external/MbedTLS/mbedtls-init-cache.cmake.in
@@ -0,0 +1,22 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+set(CMAKE_INSTALL_PREFIX @BUILD_INSTALL_DIR@ CACHE STRING "")
+set(CMAKE_TOOLCHAIN_FILE @TS_EXTERNAL_LIB_TOOLCHAIN_FILE@ CACHE STRING "")
+
+set(ENABLE_PROGRAMS Off CACHE BOOL "")
+set(ENABLE_TESTING Off CACHE BOOL "")
+set(UNSAFE_BUILD On CACHE BOOL "")
+set(EXTERNAL_DEFINITIONS -DMBEDTLS_USER_CONFIG_FILE="@MBEDTLS_USER_CONFIG_FILE@" CACHE STRING "")
+set(EXTERNAL_INCLUDE_PATHS @MBEDTLS_EXTRA_INCLUDES@ CACHE STRING "")
+
+string(TOUPPER @CMAKE_CROSSCOMPILING@ CMAKE_CROSSCOMPILING) # CMake expects TRUE
+if (CMAKE_CROSSCOMPILING)
+	set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY CACHE STRING "")
+endif()
+
+@_cmake_fragment@