Merge pull request #4259 from CJKay/cmake-config

Add CMake package config file
diff --git a/3rdparty/CMakeLists.txt b/3rdparty/CMakeLists.txt
index 18945e5..fbd0470 100644
--- a/3rdparty/CMakeLists.txt
+++ b/3rdparty/CMakeLists.txt
@@ -1,17 +1,5 @@
-list (APPEND thirdparty_src)
-list (APPEND thirdparty_lib)
-list (APPEND thirdparty_inc_public)
-list (APPEND thirdparty_inc)
-list (APPEND thirdparty_def)
-
 execute_process(COMMAND ${MBEDTLS_PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/../scripts/config.py -f ${CMAKE_CURRENT_SOURCE_DIR}/../include/mbedtls/config.h get MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED RESULT_VARIABLE result)
 
 if(${result} EQUAL 0)
     add_subdirectory(everest)
 endif()
-
-set(thirdparty_src ${thirdparty_src} PARENT_SCOPE)
-set(thirdparty_lib ${thirdparty_lib} PARENT_SCOPE)
-set(thirdparty_inc_public ${thirdparty_inc_public} PARENT_SCOPE)
-set(thirdparty_inc ${thirdparty_inc} PARENT_SCOPE)
-set(thirdparty_def ${thirdparty_def} PARENT_SCOPE)
diff --git a/3rdparty/everest/CMakeLists.txt b/3rdparty/everest/CMakeLists.txt
index d81d995..ff9da7a 100644
--- a/3rdparty/everest/CMakeLists.txt
+++ b/3rdparty/everest/CMakeLists.txt
@@ -1,16 +1,15 @@
-list (APPEND everest_src)
-list (APPEND everest_inc_public)
-list (APPEND everest_inc)
-list (APPEND everest_def)
+add_library(everest
+  library/everest.c
+  library/x25519.c
+  library/Hacl_Curve25519_joined.c)
 
-set(everest_src
-  ${CMAKE_CURRENT_SOURCE_DIR}/library/everest.c
-  ${CMAKE_CURRENT_SOURCE_DIR}/library/x25519.c
-  ${CMAKE_CURRENT_SOURCE_DIR}/library/Hacl_Curve25519_joined.c
-)
-
-list(APPEND everest_inc_public ${CMAKE_CURRENT_SOURCE_DIR}/include)
-list(APPEND everest_inc ${CMAKE_CURRENT_SOURCE_DIR}/include/everest ${CMAKE_CURRENT_SOURCE_DIR}/include/everest/kremlib)
+target_include_directories(everest
+  PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
+         $<BUILD_INTERFACE:${MBEDTLS_DIR}/include>
+         $<INSTALL_INTERFACE:include>
+  PRIVATE include/everest
+          include/everest/kremlib
+          ${MBEDTLS_DIR}/library/)
 
 if(INSTALL_MBEDTLS_HEADERS)
 
@@ -22,7 +21,7 @@
 
 endif(INSTALL_MBEDTLS_HEADERS)
 
-set(thirdparty_src ${thirdparty_src} ${everest_src} PARENT_SCOPE)
-set(thirdparty_inc_public ${thirdparty_inc_public} ${everest_inc_public} PARENT_SCOPE)
-set(thirdparty_inc ${thirdparty_inc} ${everest_inc} PARENT_SCOPE)
-set(thirdparty_def ${thirdparty_def} ${everest_def} PARENT_SCOPE)
+install(TARGETS everest
+  EXPORT MbedTLSTargets
+  DESTINATION ${LIB_INSTALL_DIR}
+  PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index efe3cab..f126f8d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -20,6 +20,8 @@
 # until our infrastructure catches up.
 cmake_minimum_required(VERSION 3.5.1)
 
+include(CMakePackageConfigHelpers)
+
 # https://cmake.org/cmake/help/latest/policy/CMP0011.html
 # Setting this policy is required in CMake >= 3.18.0, otherwise a warning is generated. The OLD
 # policy setting is deprecated, and will be removed in future versions.
@@ -223,7 +225,6 @@
 add_subdirectory(include)
 
 add_subdirectory(3rdparty)
-list(APPEND libs ${thirdparty_lib})
 
 add_subdirectory(library)
 
@@ -302,3 +303,37 @@
                     ${CMAKE_CURRENT_BINARY_DIR}/DartConfiguration.tcl COPYONLY)
     endif()
 endif()
+
+configure_package_config_file(
+    "cmake/MbedTLSConfig.cmake.in"
+    "cmake/MbedTLSConfig.cmake"
+        INSTALL_DESTINATION "cmake")
+
+write_basic_package_version_file(
+    "cmake/MbedTLSConfigVersion.cmake"
+        COMPATIBILITY SameMajorVersion
+        VERSION 2.26.0)
+
+install(
+    FILES "${CMAKE_CURRENT_BINARY_DIR}/cmake/MbedTLSConfig.cmake"
+          "${CMAKE_CURRENT_BINARY_DIR}/cmake/MbedTLSConfigVersion.cmake"
+    DESTINATION "cmake")
+
+export(
+    EXPORT MbedTLSTargets
+    NAMESPACE MbedTLS::
+    FILE "cmake/MbedTLSTargets.cmake")
+
+install(
+    EXPORT MbedTLSTargets
+    NAMESPACE MbedTLS::
+    DESTINATION "cmake"
+    FILE "MbedTLSTargets.cmake")
+
+if(CMAKE_VERSION VERSION_GREATER 3.14)
+    # Do not export the package by default
+    cmake_policy(SET CMP0090 NEW)
+
+    # Make this package visible to the system
+    export(PACKAGE MbedTLS)
+endif()
diff --git a/ChangeLog.d/add-cmake-package-config.txt b/ChangeLog.d/add-cmake-package-config.txt
new file mode 100644
index 0000000..3b73816
--- /dev/null
+++ b/ChangeLog.d/add-cmake-package-config.txt
@@ -0,0 +1,2 @@
+Changes
+   * Add CMake package config generation for CMake projects consuming Mbed TLS.
diff --git a/README.md b/README.md
index 78d3c30..4c3c938 100644
--- a/README.md
+++ b/README.md
@@ -184,6 +184,33 @@
 your value of CFLAGS doesn't override the content provided by cmake (depending
 on the build mode as seen above), it's merely prepended to it.
 
+#### Consuming Mbed TLS
+
+Mbed TLS provides a package config file for consumption as a dependency in other
+CMake projects. You can include Mbed TLS's CMake targets yourself with:
+
+    find_package(MbedTLS)
+
+If prompted, set `MbedTLS_DIR` to `${YOUR_MBEDTLS_INSTALL_DIR}/cmake`. This
+creates the following targets:
+
+- `MbedTLS::mbedcrypto` (Crypto library)
+- `MbedTLS::mbedtls` (TLS library)
+- `MbedTLS::mbedx509` (X509 library)
+
+You can then use these directly through `target_link_libraries()`:
+
+    add_executable(xyz)
+
+    target_link_libraries(xyz
+        PUBLIC MbedTLS::mbedtls
+               MbedTLS::mbedcrypto
+               MbedTLS::mbedx509)
+
+This will link the Mbed TLS libraries to your library or application, and add
+its include directories to your target (transitively, in the case of `PUBLIC` or
+`INTERFACE` link libraries).
+
 #### Mbed TLS as a subproject
 
 Mbed TLS supports being built as a CMake subproject. One can
diff --git a/cmake/MbedTLSConfig.cmake.in b/cmake/MbedTLSConfig.cmake.in
new file mode 100644
index 0000000..b65bbab
--- /dev/null
+++ b/cmake/MbedTLSConfig.cmake.in
@@ -0,0 +1,3 @@
+@PACKAGE_INIT@
+
+include("${CMAKE_CURRENT_LIST_DIR}/MbedTLSTargets.cmake")
diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt
index d6ecba5..14fecff 100644
--- a/library/CMakeLists.txt
+++ b/library/CMakeLists.txt
@@ -82,8 +82,6 @@
     version_features.c
 )
 
-list(APPEND src_crypto ${thirdparty_src})
-
 set(src_x509
     x509.c
     x509_create.c
@@ -175,6 +173,10 @@
     set_target_properties(${mbedcrypto_static_target} PROPERTIES OUTPUT_NAME mbedcrypto)
     target_link_libraries(${mbedcrypto_static_target} PUBLIC ${libs})
 
+    if(TARGET everest)
+        target_link_libraries(${mbedcrypto_static_target} PUBLIC everest)
+    endif()
+
     add_library(${mbedx509_static_target} STATIC ${src_x509})
     set_target_properties(${mbedx509_static_target} PROPERTIES OUTPUT_NAME mbedx509)
     target_link_libraries(${mbedx509_static_target} PUBLIC ${libs} ${mbedcrypto_static_target})
@@ -189,6 +191,10 @@
     set_target_properties(${mbedcrypto_target} PROPERTIES VERSION 2.26.0 SOVERSION 6)
     target_link_libraries(${mbedcrypto_target} PUBLIC ${libs})
 
+    if(TARGET everest)
+        target_link_libraries(${mbedcrypto_target} PUBLIC everest)
+    endif()
+
     add_library(${mbedx509_target} SHARED ${src_x509})
     set_target_properties(${mbedx509_target} PROPERTIES VERSION 2.26.0 SOVERSION 1)
     target_link_libraries(${mbedx509_target} PUBLIC ${libs} ${mbedcrypto_target})
@@ -205,15 +211,14 @@
     # /library needs to be listed explicitly when building .c files outside
     # of /library (which currently means: under /3rdparty).
     target_include_directories(${target}
-        PUBLIC ${MBEDTLS_DIR}/include/
-        PUBLIC ${thirdparty_inc_public}
-        PRIVATE ${MBEDTLS_DIR}/library/
-        PRIVATE ${thirdparty_inc})
-    target_compile_definitions(${target}
-        PRIVATE ${thirdparty_def})
-    install(TARGETS ${target}
-            DESTINATION ${LIB_INSTALL_DIR}
-            PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ)
+        PUBLIC $<BUILD_INTERFACE:${MBEDTLS_DIR}/include/>
+               $<INSTALL_INTERFACE:include/>
+        PRIVATE ${MBEDTLS_DIR}/library/)
+    install(
+        TARGETS ${target}
+        EXPORT MbedTLSTargets
+        DESTINATION ${LIB_INSTALL_DIR}
+        PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ)
 endforeach(target)
 
 set(lib_target "${MBEDTLS_TARGET_PREFIX}lib")
diff --git a/programs/test/cmake_package/.gitignore b/programs/test/cmake_package/.gitignore
new file mode 100644
index 0000000..9ae6b59
--- /dev/null
+++ b/programs/test/cmake_package/.gitignore
@@ -0,0 +1,3 @@
+build
+Makefile
+cmake_package
diff --git a/programs/test/cmake_package/CMakeLists.txt b/programs/test/cmake_package/CMakeLists.txt
new file mode 100644
index 0000000..518d2e9
--- /dev/null
+++ b/programs/test/cmake_package/CMakeLists.txt
@@ -0,0 +1,36 @@
+cmake_minimum_required(VERSION 2.8.12)
+
+#
+# Simulate configuring and building Mbed TLS as the user might do it. We'll
+# skip installing it, and use the build directory directly instead.
+#
+
+set(MbedTLS_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../..")
+set(MbedTLS_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/mbedtls")
+
+execute_process(
+    COMMAND "${CMAKE_COMMAND}"
+        "-H${MbedTLS_SOURCE_DIR}"
+        "-B${MbedTLS_BINARY_DIR}"
+        "-DENABLE_PROGRAMS=NO"
+        "-DENABLE_TESTING=NO")
+
+execute_process(
+    COMMAND "${CMAKE_COMMAND}"
+        --build "${MbedTLS_BINARY_DIR}")
+
+#
+# Locate the package.
+#
+
+set(MbedTLS_DIR "${MbedTLS_BINARY_DIR}/cmake")
+find_package(MbedTLS REQUIRED)
+
+#
+# At this point, the Mbed TLS targets should have been imported, and we can now
+# link to them from our own program.
+#
+
+add_executable(cmake_package cmake_package.c)
+target_link_libraries(cmake_package
+    MbedTLS::mbedcrypto MbedTLS::mbedtls MbedTLS::mbedx509)
diff --git a/programs/test/cmake_package/cmake_package.c b/programs/test/cmake_package/cmake_package.c
new file mode 100644
index 0000000..3f993a0
--- /dev/null
+++ b/programs/test/cmake_package/cmake_package.c
@@ -0,0 +1,53 @@
+/*
+ *  Simple program to test that Mbed TLS builds correctly as a CMake package.
+ *
+ *  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License"); you may
+ *  not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+#if !defined(MBEDTLS_CONFIG_FILE)
+#include "mbedtls/config.h"
+#else
+#include MBEDTLS_CONFIG_FILE
+#endif
+
+#if defined(MBEDTLS_PLATFORM_C)
+#include "mbedtls/platform.h"
+#else
+#include <stdio.h>
+#include <stdlib.h>
+#define mbedtls_fprintf         fprintf
+#define mbedtls_printf          printf
+#define mbedtls_exit            exit
+#define MBEDTLS_EXIT_SUCCESS    EXIT_SUCCESS
+#define MBEDTLS_EXIT_FAILURE    EXIT_FAILURE
+#endif /* MBEDTLS_PLATFORM_C */
+
+#include "mbedtls/version.h"
+
+/* The main reason to build this is for testing the CMake build, so the program
+ * doesn't need to do very much. It calls a single library function to ensure
+ * linkage works, but that is all. */
+int main()
+{
+    /* This version string is 18 bytes long, as advised by version.h. */
+    char version[18];
+
+    mbedtls_version_get_string_full( version );
+
+    mbedtls_printf( "Built against %s\n", version );
+
+    return( 0 );
+}
diff --git a/programs/test/cmake_package_install/.gitignore b/programs/test/cmake_package_install/.gitignore
new file mode 100644
index 0000000..b9b8282
--- /dev/null
+++ b/programs/test/cmake_package_install/.gitignore
@@ -0,0 +1,3 @@
+build
+Makefile
+cmake_package_install
diff --git a/programs/test/cmake_package_install/CMakeLists.txt b/programs/test/cmake_package_install/CMakeLists.txt
new file mode 100644
index 0000000..711a1e5
--- /dev/null
+++ b/programs/test/cmake_package_install/CMakeLists.txt
@@ -0,0 +1,39 @@
+cmake_minimum_required(VERSION 2.8.12)
+
+#
+# Simulate configuring and building Mbed TLS as the user might do it. We'll
+# install into a directory inside our own build directory.
+#
+
+set(MbedTLS_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../..")
+set(MbedTLS_INSTALL_DIR "${CMAKE_CURRENT_BINARY_DIR}/mbedtls")
+set(MbedTLS_BINARY_DIR "${MbedTLS_INSTALL_DIR}${CMAKE_FILES_DIRECTORY}")
+
+execute_process(
+    COMMAND "${CMAKE_COMMAND}"
+        "-H${MbedTLS_SOURCE_DIR}"
+        "-B${MbedTLS_BINARY_DIR}"
+        "-DENABLE_PROGRAMS=NO"
+        "-DENABLE_TESTING=NO"
+        "-DCMAKE_INSTALL_PREFIX=${MbedTLS_INSTALL_DIR}")
+
+execute_process(
+    COMMAND "${CMAKE_COMMAND}"
+        --build "${MbedTLS_BINARY_DIR}"
+        --target install)
+
+#
+# Locate the package.
+#
+
+set(MbedTLS_DIR "${MbedTLS_INSTALL_DIR}/cmake")
+find_package(MbedTLS REQUIRED)
+
+#
+# At this point, the Mbed TLS targets should have been imported, and we can now
+# link to them from our own program.
+#
+
+add_executable(cmake_package_install cmake_package_install.c)
+target_link_libraries(cmake_package_install
+    MbedTLS::mbedcrypto MbedTLS::mbedtls MbedTLS::mbedx509)
diff --git a/programs/test/cmake_package_install/cmake_package_install.c b/programs/test/cmake_package_install/cmake_package_install.c
new file mode 100644
index 0000000..1ae0b84
--- /dev/null
+++ b/programs/test/cmake_package_install/cmake_package_install.c
@@ -0,0 +1,54 @@
+/*
+ * Simple program to test that Mbed TLS builds correctly as an installable CMake
+ * package.
+ *
+ *  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License"); you may
+ *  not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+#if !defined(MBEDTLS_CONFIG_FILE)
+#include "mbedtls/config.h"
+#else
+#include MBEDTLS_CONFIG_FILE
+#endif
+
+#if defined(MBEDTLS_PLATFORM_C)
+#include "mbedtls/platform.h"
+#else
+#include <stdio.h>
+#include <stdlib.h>
+#define mbedtls_fprintf         fprintf
+#define mbedtls_printf          printf
+#define mbedtls_exit            exit
+#define MBEDTLS_EXIT_SUCCESS    EXIT_SUCCESS
+#define MBEDTLS_EXIT_FAILURE    EXIT_FAILURE
+#endif /* MBEDTLS_PLATFORM_C */
+
+#include "mbedtls/version.h"
+
+/* The main reason to build this is for testing the CMake build, so the program
+ * doesn't need to do very much. It calls a single library function to ensure
+ * linkage works, but that is all. */
+int main()
+{
+    /* This version string is 18 bytes long, as advised by version.h. */
+    char version[18];
+
+    mbedtls_version_get_string_full( version );
+
+    mbedtls_printf( "Built against %s\n", version );
+
+    return( 0 );
+}
diff --git a/tests/scripts/all.sh b/tests/scripts/all.sh
index 596e27d..c0771f0 100755
--- a/tests/scripts/all.sh
+++ b/tests/scripts/all.sh
@@ -273,7 +273,7 @@
            -iname CMakeFiles -exec rm -rf {} \+ -o \
            \( -iname cmake_install.cmake -o \
               -iname CTestTestfile.cmake -o \
-              -iname CMakeCache.txt \) -exec rm {} \+
+              -iname CMakeCache.txt \) -exec rm -f {} \+
     # Recover files overwritten by in-tree CMake builds
     rm -f include/Makefile include/mbedtls/Makefile programs/*/Makefile
     git update-index --no-skip-worktree Makefile library/Makefile programs/Makefile tests/Makefile programs/fuzz/Makefile
@@ -284,6 +284,16 @@
     rm -f programs/test/cmake_subproject/Makefile
     rm -f programs/test/cmake_subproject/cmake_subproject
 
+    # Remove any artifacts from the component_test_cmake_as_package test.
+    rm -rf programs/test/cmake_package/build
+    rm -f programs/test/cmake_package/Makefile
+    rm -f programs/test/cmake_package/cmake_package
+
+    # Remove any artifacts from the component_test_cmake_as_installed_package test.
+    rm -rf programs/test/cmake_package_install/build
+    rm -f programs/test/cmake_package_install/Makefile
+    rm -f programs/test/cmake_package_install/cmake_package_install
+
     if [ -f "$CONFIG_BAK" ]; then
         mv "$CONFIG_BAK" "$CONFIG_H"
     fi
@@ -2540,6 +2550,32 @@
     unset MBEDTLS_ROOT_DIR
 }
 
+component_test_cmake_as_package () {
+    msg "build: cmake 'as-package' build"
+    MBEDTLS_ROOT_DIR="$PWD"
+
+    cd programs/test/cmake_package
+    cmake .
+    make
+    if_build_succeeded ./cmake_package
+
+    cd "$MBEDTLS_ROOT_DIR"
+    unset MBEDTLS_ROOT_DIR
+}
+
+component_test_cmake_as_package_install () {
+    msg "build: cmake 'as-installed-package' build"
+    MBEDTLS_ROOT_DIR="$PWD"
+
+    cd programs/test/cmake_package_install
+    cmake .
+    make
+    if_build_succeeded ./cmake_package_install
+
+    cd "$MBEDTLS_ROOT_DIR"
+    unset MBEDTLS_ROOT_DIR
+}
+
 component_test_zeroize () {
     # Test that the function mbedtls_platform_zeroize() is not optimized away by
     # different combinations of compilers and optimization flags by using an