Merge pull request #4937 from xkqian/add_tls13_encrypted_extension

The rebase after the two approvals was simple enough to need only one reviewer.
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 210aba4..cd990ab 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -46,6 +46,11 @@
 
 option(UNSAFE_BUILD "Allow unsafe builds. These builds ARE NOT SECURE." OFF)
 option(MBEDTLS_FATAL_WARNINGS "Compiler warnings treated as errors" ON)
+if(WIN32)
+    option(GEN_FILES "Generate the auto-generated files as needed" OFF)
+else()
+    option(GEN_FILES "Generate the auto-generated files as needed" ON)
+endif()
 
 string(REGEX MATCH "Clang" CMAKE_COMPILER_IS_CLANG "${CMAKE_C_COMPILER_ID}")
 string(REGEX MATCH "GNU" CMAKE_COMPILER_IS_GNU "${CMAKE_C_COMPILER_ID}")
@@ -135,6 +140,22 @@
     endif()
 endfunction(link_to_source)
 
+# Get the filename without the final extension (i.e. convert "a.b.c" to "a.b")
+function(get_name_without_last_ext dest_var full_name)
+    # Split into a list on '.' (but a cmake list is just a ';'-separated string)
+    string(REPLACE "." ";" ext_parts "${full_name}")
+    # Remove the last item if there are more than one
+    list(LENGTH ext_parts ext_parts_len)
+    if (${ext_parts_len} GREATER "1")
+        math(EXPR ext_parts_last_item "${ext_parts_len} - 1")
+        list(REMOVE_AT ext_parts ${ext_parts_last_item})
+    endif()
+    # Convert back to a string by replacing separators with '.'
+    string(REPLACE ";" "." no_ext_name "${ext_parts}")
+    # Copy into the desired variable
+    set(${dest_var} ${no_ext_name} PARENT_SCOPE)
+endfunction(get_name_without_last_ext)
+
 string(REGEX MATCH "Clang" CMAKE_COMPILER_IS_CLANG "${CMAKE_C_COMPILER_ID}")
 
 include(CheckCCompilerFlag)
diff --git a/README.md b/README.md
index dbe6a23..e6924cb 100644
--- a/README.md
+++ b/README.md
@@ -67,6 +67,7 @@
 Any of the following methods are available to generate the configuration-independent files:
 
 * If not cross-compiling, running `make` with any target, or just `make`, will automatically generate required files.
+* On non-Windows systems, when not cross-compiling, CMake will generate the required files automatically.
 * Run `make generated_files` to generate all the configuration-independent files.
 * On Unix/POSIX systems, run `tests/scripts/check-generated-files.sh -u` to generate all the configuration-independent files.
 * On Windows, run `scripts\make_generated_files.bat` to generate all the configuration-independent files.
diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt
index a5d692c..18aff5a 100644
--- a/library/CMakeLists.txt
+++ b/library/CMakeLists.txt
@@ -109,6 +109,44 @@
     ssl_tls13_generic.c
 )
 
+if(GEN_FILES)
+    find_package(Perl REQUIRED)
+
+    file(GLOB error_headers ${CMAKE_CURRENT_SOURCE_DIR}/../include/mbedtls/*.h)
+    add_custom_command(
+        OUTPUT
+            ${CMAKE_CURRENT_BINARY_DIR}/error.c
+        COMMAND
+            ${PERL_EXECUTABLE}
+                ${CMAKE_CURRENT_SOURCE_DIR}/../scripts/generate_errors.pl
+                ${CMAKE_CURRENT_SOURCE_DIR}/../include/mbedtls
+                ${CMAKE_CURRENT_SOURCE_DIR}/../scripts/data_files
+                ${CMAKE_CURRENT_BINARY_DIR}/error.c
+        DEPENDS
+            ${CMAKE_CURRENT_SOURCE_DIR}/../scripts/generate_errors.pl
+            ${error_headers}
+            ${CMAKE_CURRENT_SOURCE_DIR}/../scripts/data_files/error.fmt
+    )
+
+    add_custom_command(
+        OUTPUT
+            ${CMAKE_CURRENT_BINARY_DIR}/version_features.c
+        COMMAND
+            ${PERL_EXECUTABLE}
+                ${CMAKE_CURRENT_SOURCE_DIR}/../scripts/generate_features.pl
+                ${CMAKE_CURRENT_SOURCE_DIR}/../include/mbedtls
+                ${CMAKE_CURRENT_SOURCE_DIR}/../scripts/data_files
+                ${CMAKE_CURRENT_BINARY_DIR}/version_features.c
+        DEPENDS
+            ${CMAKE_CURRENT_SOURCE_DIR}/../scripts/generate_features.pl
+            ${CMAKE_CURRENT_SOURCE_DIR}/../include/mbedtls/mbedtls_config.h
+            ${CMAKE_CURRENT_SOURCE_DIR}/../scripts/data_files/version_features.fmt
+    )
+else()
+    link_to_source(error.c)
+    link_to_source(version_features.c)
+endif()
+
 if(CMAKE_COMPILER_IS_GNUCC)
     set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wmissing-declarations -Wmissing-prototypes")
 endif(CMAKE_COMPILER_IS_GNUCC)
diff --git a/programs/psa/CMakeLists.txt b/programs/psa/CMakeLists.txt
index 23e85fe..26ca73c 100644
--- a/programs/psa/CMakeLists.txt
+++ b/programs/psa/CMakeLists.txt
@@ -4,6 +4,25 @@
     psa_constant_names
 )
 
+if(GEN_FILES)
+    add_custom_command(
+        OUTPUT
+            ${CMAKE_CURRENT_BINARY_DIR}/psa_constant_names_generated.c
+        COMMAND
+            ${MBEDTLS_PYTHON_EXECUTABLE}
+                ${CMAKE_CURRENT_SOURCE_DIR}/../../scripts/generate_psa_constants.py
+                ${CMAKE_CURRENT_BINARY_DIR}
+        WORKING_DIRECTORY
+            ${CMAKE_CURRENT_SOURCE_DIR}/../..
+        DEPENDS
+            ${CMAKE_CURRENT_SOURCE_DIR}/../../scripts/generate_psa_constants.py
+            ${CMAKE_CURRENT_SOURCE_DIR}/../../include/psa/crypto_values.h
+            ${CMAKE_CURRENT_SOURCE_DIR}/../../include/psa/crypto_extra.h
+    )
+else()
+    link_to_source(psa_constant_names_generated.c)
+endif()
+
 foreach(exe IN LISTS executables)
     add_executable(${exe} ${exe}.c $<TARGET_OBJECTS:mbedtls_test>)
     target_link_libraries(${exe} ${mbedcrypto_target})
@@ -11,6 +30,11 @@
 endforeach()
 
 target_include_directories(psa_constant_names PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
+if(GEN_FILES)
+    add_custom_target(generate_psa_constant_names_generated_c
+        DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/psa_constant_names_generated.c)
+    add_dependencies(psa_constant_names generate_psa_constant_names_generated_c)
+endif()
 
 install(TARGETS ${executables}
         DESTINATION "bin"
diff --git a/programs/ssl/CMakeLists.txt b/programs/ssl/CMakeLists.txt
index def9c7c..280bbcf 100644
--- a/programs/ssl/CMakeLists.txt
+++ b/programs/ssl/CMakeLists.txt
@@ -18,23 +18,38 @@
     ssl_server2
 )
 
+if(GEN_FILES)
+    # Inform CMake that the following file will be generated as part of the build
+    # process, so it doesn't complain that it doesn't exist yet. Starting from
+    # CMake 3.20, this will no longer be necessary as CMake will automatically
+    # propagate this information across the tree, for now it's only visible
+    # inside the same directory, so we need to propagate manually.
+    set_source_files_properties(
+        ${CMAKE_CURRENT_BINARY_DIR}/../test/query_config.c
+        PROPERTIES GENERATED TRUE)
+endif()
+
 foreach(exe IN LISTS executables)
     set(extra_sources "")
     if(exe STREQUAL "ssl_client2" OR exe STREQUAL "ssl_server2")
         list(APPEND extra_sources
-            ${CMAKE_CURRENT_SOURCE_DIR}/../test/query_config.c)
+            ssl_test_lib.c
+            ${CMAKE_CURRENT_SOURCE_DIR}/../test/query_config.h
+            ${CMAKE_CURRENT_BINARY_DIR}/../test/query_config.c)
     endif()
     add_executable(${exe} ${exe}.c $<TARGET_OBJECTS:mbedtls_test>
         ${extra_sources})
     target_link_libraries(${exe} ${libs})
     target_include_directories(${exe} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../tests/include)
+    if(exe STREQUAL "ssl_client2" OR exe STREQUAL "ssl_server2")
+        if(GEN_FILES)
+            add_dependencies(${exe} generate_query_config_c)
+        endif()
+        target_include_directories(${exe}
+            PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../test)
+    endif()
 endforeach()
 
-set_property(TARGET ssl_client2 APPEND PROPERTY SOURCES
-    ssl_test_lib.c ${CMAKE_CURRENT_SOURCE_DIR}/../test/query_config.c)
-set_property(TARGET ssl_server2 APPEND PROPERTY SOURCES
-    ssl_test_lib.c ${CMAKE_CURRENT_SOURCE_DIR}/../test/query_config.c)
-
 if(THREADS_FOUND)
     add_executable(ssl_pthread_server ssl_pthread_server.c $<TARGET_OBJECTS:mbedtls_test>)
     target_include_directories(ssl_pthread_server PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../tests/include)
diff --git a/programs/test/CMakeLists.txt b/programs/test/CMakeLists.txt
index a0a1b76..142a831 100644
--- a/programs/test/CMakeLists.txt
+++ b/programs/test/CMakeLists.txt
@@ -27,15 +27,44 @@
     target_link_libraries(cpp_dummy_build ${mbedcrypto_target})
 endif()
 
+if(GEN_FILES)
+    find_package(Perl REQUIRED)
+
+    add_custom_command(
+        OUTPUT
+            ${CMAKE_CURRENT_BINARY_DIR}/query_config.c
+        COMMAND
+            ${PERL}
+                ${CMAKE_CURRENT_SOURCE_DIR}/../../scripts/generate_query_config.pl
+                ${CMAKE_CURRENT_SOURCE_DIR}/../../include/mbedtls/mbedtls_config.h
+                ${CMAKE_CURRENT_SOURCE_DIR}/../../scripts/data_files/query_config.fmt
+                ${CMAKE_CURRENT_BINARY_DIR}/query_config.c
+        DEPENDS
+            ${CMAKE_CURRENT_SOURCE_DIR}/../../scripts/generate_query_config.pl
+            ${CMAKE_CURRENT_SOURCE_DIR}/../../include/mbedtls/mbedtls_config.h
+            ${CMAKE_CURRENT_SOURCE_DIR}/../../scripts/data_files/query_config.fmt
+    )
+    # this file will also be used in another directory, so create a target, see
+    # https://gitlab.kitware.com/cmake/community/-/wikis/FAQ#how-can-i-add-a-dependency-to-a-source-file-which-is-generated-in-a-subdirectory
+    add_custom_target(generate_query_config_c
+        DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/query_config.c)
+else()
+    link_to_source(query_config.c)
+endif()
+
 foreach(exe IN LISTS executables_libs executables_mbedcrypto)
     set(extra_sources "")
     if(exe STREQUAL "query_compile_time_config")
         list(APPEND extra_sources
-            ${CMAKE_CURRENT_SOURCE_DIR}/query_config.c)
+            ${CMAKE_CURRENT_SOURCE_DIR}/query_config.h
+            ${CMAKE_CURRENT_BINARY_DIR}/query_config.c)
     endif()
     add_executable(${exe} ${exe}.c $<TARGET_OBJECTS:mbedtls_test>
         ${extra_sources})
     target_include_directories(${exe} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../tests/include)
+    if(exe STREQUAL "query_compile_time_config")
+        target_include_directories(${exe} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
+    endif()
 
     # This emulates "if ( ... IN_LIST ... )" which becomes available in CMake 3.3
     list(FIND executables_libs ${exe} exe_index)
diff --git a/scripts/generate_query_config.pl b/scripts/generate_query_config.pl
index e3bbaa0..7855c7c 100755
--- a/scripts/generate_query_config.pl
+++ b/scripts/generate_query_config.pl
@@ -14,7 +14,8 @@
 # information is used to automatically generate the body of the query_config()
 # function by using the template in scripts/data_files/query_config.fmt.
 #
-# Usage: ./scripts/generate_query_config.pl without arguments
+# Usage: scripts/generate_query_config.pl without arguments, or
+# generate_query_config.pl config_file template_file output_file
 #
 # Copyright The Mbed TLS Contributors
 # SPDX-License-Identifier: Apache-2.0
@@ -33,15 +34,24 @@
 
 use strict;
 
-my $config_file = "./include/mbedtls/mbedtls_config.h";
+my ($config_file, $query_config_format_file, $query_config_file);
 
-my $query_config_format_file = "./scripts/data_files/query_config.fmt";
-my $query_config_file = "./programs/test/query_config.c";
+if( @ARGV ) {
+    die "Invalid number of arguments - usage: $0 [CONFIG_FILE TEMPLATE_FILE OUTPUT_FILE]" if scalar @ARGV != 3;
+    ($config_file, $query_config_format_file, $query_config_file) = @ARGV;
 
-unless( -f $config_file && -f $query_config_format_file ) {
-    chdir '..' or die;
-    -f $config_file && -f $query_config_format_file
-      or die "Without arguments, must be run from root or a subdirectory\n";
+    -f $config_file or die "No such file: $config_file";
+    -f $query_config_format_file or die "No such file: $query_config_format_file";
+} else {
+    $config_file = "./include/mbedtls/mbedtls_config.h";
+    $query_config_format_file = "./scripts/data_files/query_config.fmt";
+    $query_config_file = "./programs/test/query_config.c";
+
+    unless( -f $config_file && -f $query_config_format_file ) {
+        chdir '..' or die;
+        -f $config_file && -f $query_config_format_file
+          or die "No arguments supplied, must be run from project root or a first-level subdirectory\n";
+    }
 }
 
 # Excluded macros from the generated query_config.c. For example, macros that
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index fbd746e..41dceed 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -13,10 +13,48 @@
     message(FATAL_ERROR "Cannot build test suites without Python 3")
 endif()
 
-# Enable definition of various functions used throughout the testsuite
-# (gethostname, strdup, fileno...) even when compiling with -std=c99. Harmless
-# on non-POSIX platforms.
-add_definitions("-D_POSIX_C_SOURCE=200809L")
+# generated .data files will go there
+file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/suites)
+
+# Get base names for generated files (starting at "suites/")
+execute_process(
+    COMMAND
+        ${MBEDTLS_PYTHON_EXECUTABLE}
+        ${CMAKE_CURRENT_SOURCE_DIR}/../tests/scripts/generate_psa_tests.py
+        --list-for-cmake
+        --directory suites
+    WORKING_DIRECTORY
+        ${CMAKE_CURRENT_SOURCE_DIR}/..
+    OUTPUT_VARIABLE
+        base_generated_data_files)
+
+# Derive generated file paths in the build directory
+set(generated_data_files "")
+foreach(file ${base_generated_data_files})
+    list(APPEND generated_data_files ${CMAKE_CURRENT_BINARY_DIR}/${file})
+endforeach()
+
+if(GEN_FILES)
+    add_custom_command(
+        OUTPUT
+            ${generated_data_files}
+        WORKING_DIRECTORY
+            ${CMAKE_CURRENT_SOURCE_DIR}/..
+        COMMAND
+            ${MBEDTLS_PYTHON_EXECUTABLE}
+            ${CMAKE_CURRENT_SOURCE_DIR}/../tests/scripts/generate_psa_tests.py
+            --directory ${CMAKE_CURRENT_BINARY_DIR}/suites
+        DEPENDS
+            ${CMAKE_CURRENT_SOURCE_DIR}/../tests/scripts/generate_psa_tests.py
+            ${CMAKE_CURRENT_SOURCE_DIR}/../include/psa/crypto_config.h
+            ${CMAKE_CURRENT_SOURCE_DIR}/../include/psa/crypto_values.h
+            ${CMAKE_CURRENT_SOURCE_DIR}/../include/psa/crypto_extra.h
+    )
+else()
+    foreach(file ${base_generated_data_files})
+        link_to_source(${file})
+    endforeach()
+endif()
 
 # Test suites caught by SKIP_TEST_SUITES are built but not executed.
 # "foo" as a skip pattern skips "test_suite_foo" and "test_suite_foo.bar"
@@ -32,10 +70,52 @@
         set(data_name ${suite_name})
     endif()
 
+    # Get the test names of the tests with generated .data files
+    # from the generated_data_files list in parent scope.
+    set(generated_data_names "")
+    foreach(generated_data_file ${generated_data_files})
+        # Get the plain filename
+        get_filename_component(generated_data_name ${generated_data_file} NAME)
+        # Remove the ".data" extension
+        get_name_without_last_ext(generated_data_name ${generated_data_name})
+        # Remove leading "test_suite_"
+        string(SUBSTRING ${generated_data_name} 11 -1 generated_data_name)
+        list(APPEND generated_data_names ${generated_data_name})
+    endforeach()
+
+    if(";${generated_data_names};" MATCHES ";${data_name};")
+        set(data_file
+            ${CMAKE_CURRENT_BINARY_DIR}/suites/test_suite_${data_name}.data)
+    else()
+        set(data_file
+            ${CMAKE_CURRENT_SOURCE_DIR}/suites/test_suite_${data_name}.data)
+    endif()
+
     add_custom_command(
-        OUTPUT test_suite_${data_name}.c
-        COMMAND ${MBEDTLS_PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/scripts/generate_test_code.py -f ${CMAKE_CURRENT_SOURCE_DIR}/suites/test_suite_${suite_name}.function -d ${CMAKE_CURRENT_SOURCE_DIR}/suites/test_suite_${data_name}.data -t ${CMAKE_CURRENT_SOURCE_DIR}/suites/main_test.function -p ${CMAKE_CURRENT_SOURCE_DIR}/suites/host_test.function -s ${CMAKE_CURRENT_SOURCE_DIR}/suites --helpers-file ${CMAKE_CURRENT_SOURCE_DIR}/suites/helpers.function -o .
-        DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/scripts/generate_test_code.py ${mbedtls_target} ${CMAKE_CURRENT_SOURCE_DIR}/suites/helpers.function ${CMAKE_CURRENT_SOURCE_DIR}/suites/main_test.function ${CMAKE_CURRENT_SOURCE_DIR}/suites/host_test.function ${CMAKE_CURRENT_SOURCE_DIR}/suites/test_suite_${suite_name}.function ${CMAKE_CURRENT_SOURCE_DIR}/suites/test_suite_${data_name}.data
+        OUTPUT
+            # The output filename of generate_test_code.py is derived from the -d
+            # input argument.
+            test_suite_${data_name}.c
+        COMMAND
+            ${MBEDTLS_PYTHON_EXECUTABLE}
+            ${CMAKE_CURRENT_SOURCE_DIR}/scripts/generate_test_code.py
+            -f ${CMAKE_CURRENT_SOURCE_DIR}/suites/test_suite_${suite_name}.function
+            -d ${data_file}
+            -t ${CMAKE_CURRENT_SOURCE_DIR}/suites/main_test.function
+            -p ${CMAKE_CURRENT_SOURCE_DIR}/suites/host_test.function
+            -s ${CMAKE_CURRENT_SOURCE_DIR}/suites
+            --helpers-file ${CMAKE_CURRENT_SOURCE_DIR}/suites/helpers.function
+            -o .
+        DEPENDS
+            ${CMAKE_CURRENT_SOURCE_DIR}/scripts/generate_test_code.py
+            ${CMAKE_CURRENT_SOURCE_DIR}/suites/test_suite_${suite_name}.function
+            ${data_file}
+            ${CMAKE_CURRENT_SOURCE_DIR}/suites/main_test.function
+            ${CMAKE_CURRENT_SOURCE_DIR}/suites/host_test.function
+            ${CMAKE_CURRENT_SOURCE_DIR}/suites/helpers.function
+            ${mbedtls_target}
+        BYPRODUCTS
+            test_suite_${data_name}.datax
     )
 
     add_executable(test_suite_${data_name} test_suite_${data_name}.c $<TARGET_OBJECTS:mbedtls_test>)
@@ -55,6 +135,11 @@
     endif()
 endfunction(add_test_suite)
 
+# Enable definition of various functions used throughout the testsuite
+# (gethostname, strdup, fileno...) even when compiling with -std=c99. Harmless
+# on non-POSIX platforms.
+add_definitions("-D_POSIX_C_SOURCE=200809L")
+
 if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_CLANG)
     set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-unused-function")
 endif(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_CLANG)
@@ -170,5 +255,4 @@
     link_to_source(data_files)
     link_to_source(scripts)
     link_to_source(ssl-opt.sh)
-    link_to_source(suites)
 endif()
diff --git a/tests/scripts/all.sh b/tests/scripts/all.sh
index 0991743..595b1ba 100755
--- a/tests/scripts/all.sh
+++ b/tests/scripts/all.sh
@@ -292,7 +292,8 @@
            -iname CMakeFiles -exec rm -rf {} \+ -o \
            \( -iname cmake_install.cmake -o \
               -iname CTestTestfile.cmake -o \
-              -iname CMakeCache.txt \) -exec rm -f {} \+
+              -iname CMakeCache.txt -o \
+              -path './cmake/*.cmake' \) -exec rm -f {} \+
     # Recover files overwritten by in-tree CMake builds
     rm -f include/Makefile include/mbedtls/Makefile programs/*/Makefile
 
@@ -998,7 +999,16 @@
 
 component_test_ref_configs () {
     msg "test/build: ref-configs (ASan build)" # ~ 6 min 20s
-    CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
+    # test-ref-configs works by overwriting mbedtls_config.h; this makes cmake
+    # want to re-generate generated files that depend on it, quite correctly.
+    # However this doesn't work as the generation script expects a specific
+    # format for mbedtls_config.h, which the other files don't follow. Also,
+    # cmake can't know this, but re-generation is actually not necessary as
+    # the generated files only depend on the list of available options, not
+    # whether they're on or off. So, disable cmake's (over-sensitive here)
+    # dependency resolution for generated files and just rely on them being
+    # present (thanks to pre_generate_files) by turning GEN_FILES off.
+    CC=gcc cmake -D GEN_FILES=Off -D CMAKE_BUILD_TYPE:String=Asan .
     tests/scripts/test-ref-configs.pl
 }
 
diff --git a/tests/scripts/generate_psa_tests.py b/tests/scripts/generate_psa_tests.py
index 4c8143f..39fb210 100755
--- a/tests/scripts/generate_psa_tests.py
+++ b/tests/scripts/generate_psa_tests.py
@@ -699,6 +699,10 @@
     parser = argparse.ArgumentParser(description=__doc__)
     parser.add_argument('--list', action='store_true',
                         help='List available targets and exit')
+    parser.add_argument('--list-for-cmake', action='store_true',
+                        help='Print \';\'-separated list of available targets and exit')
+    parser.add_argument('--directory', metavar='DIR',
+                        help='Output directory (default: tests/suites)')
     parser.add_argument('targets', nargs='*', metavar='TARGET',
                         help='Target file to generate (default: all; "-": none)')
     options = parser.parse_args(args)
@@ -708,6 +712,11 @@
         for name in sorted(generator.TARGETS):
             print(generator.filename_for(name))
         return
+    # List in a cmake list format (i.e. ';'-separated)
+    if options.list_for_cmake:
+        print(';'.join(generator.filename_for(name)
+                       for name in sorted(generator.TARGETS)), end='')
+        return
     if options.targets:
         # Allow "-" as a special case so you can run
         # ``generate_psa_tests.py - $targets`` and it works uniformly whether