Commit cf3c4ea291 for openssl.org
commit cf3c4ea2912dbdf883f0f4e6d01d5caf73f88da9
Author: Richard Levitte <levitte@openssl.foundation>
Date: Thu Aug 20 12:10:57 2026 +0200
Add a test of the exported CMake config
The exported CMake config (OpenSSLConfig.cmake and friends, both the
build-tree and the installed variants) has no test coverage at all,
so breakage in what it provides to CMake consumers, such as
OPENSSL_LIBRARIES missing the crypto libraries, goes unnoticed.
This adds a test that configures, builds and runs a small CMake
consumer project against the build tree's exported config, linking
the way CMake's FindOpenSSL.cmake has traditionally promoted: through
OPENSSL_LIBRARIES, and through the OpenSSL::SSL and OpenSSL::Crypto
targets. The legacy provider is loaded as well, to check that the
module search path is correctly available.
The test is skipped when no suitable cmake is available, and degrades
gracefully when the legacy provider isn't part of the configuration.
Assisted-by: Pi:moonshotai/kimi-k3
Signed-off-by: Richard Levitte <levitte@openssl.foundation>
Reviewed-by: Andrew Dinh <andrewd@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.foundation>
Merge-date: Sat Nov 14 17:36:41 2026
Merged-from: https://github.com/openssl/openssl/pull/32442
diff --git a/test/recipes/94-test_cmake_config.t b/test/recipes/94-test_cmake_config.t
new file mode 100644
index 0000000000..f81e530971
--- /dev/null
+++ b/test/recipes/94-test_cmake_config.t
@@ -0,0 +1,54 @@
+#! /usr/bin/env perl
+# Copyright 2026 The OpenSSL Project Authors. All Rights Reserved.
+#
+# Licensed under the Apache License 2.0 (the "License"). You may not use
+# this file except in compliance with the License. You can obtain a copy
+# in the file LICENSE in the source distribution or at
+# https://www.openssl.org/source/license.html
+
+use strict;
+use warnings;
+
+use Cwd qw(abs_path);
+use IPC::Cmd;
+use OpenSSL::Test;
+use OpenSSL::Test::Utils;
+use OpenSSL::Test qw/:DEFAULT bldtop_dir bldtop_file data_dir result_dir/;
+
+setup("test_cmake_config");
+
+plan skip_all => "cmake is not available"
+ unless IPC::Cmd::can_run("cmake");
+
+# We require cmake 3.22 or later
+my $cmake_version_output = `cmake --version`;
+my ($cmake_major, $cmake_minor) =
+ $cmake_version_output =~ /version (\d+)\.(\d+)/;
+plan skip_all => "cmake version could not be determined"
+ unless defined $cmake_major;
+plan skip_all => "cmake 3.22 or later is required (found $cmake_major.$cmake_minor)"
+ unless $cmake_major > 3 || ($cmake_major == 3 && $cmake_minor >= 22);
+
+plan tests => 3;
+
+my $cmake_build_dir = result_dir("cmake-build");
+
+my @cmake_configure =
+ ("cmake",
+ "-S", abs_path(data_dir()),
+ "-B", $cmake_build_dir,
+ # Point find_package() at the build tree's exported config
+ "-DCMAKE_PREFIX_PATH=" . abs_path(bldtop_dir()),
+ # The dummy programs are run through the same wrapper that the rest
+ # of the test suite uses, so the loader path is set up for them
+ "-DOPENSSL_WRAP_PL=" . abs_path(bldtop_file("util", "wrap.pl")));
+push @cmake_configure, "-DTEST_LEGACY_PROVIDER=OFF"
+ if disabled("legacy") || disabled("module");
+
+ok(run(cmd([@cmake_configure])),
+ "configure the cmake test project");
+ok(run(cmd(["cmake", "--build", $cmake_build_dir, "--config", "Release"])),
+ "build the cmake test project");
+ok(run(cmd(["ctest", "--test-dir", $cmake_build_dir,
+ "-C", "Release", "--output-on-failure"])),
+ "run the cmake test project");
diff --git a/test/recipes/94-test_cmake_config_data/CMakeLists.txt b/test/recipes/94-test_cmake_config_data/CMakeLists.txt
new file mode 100644
index 0000000000..643f216a14
--- /dev/null
+++ b/test/recipes/94-test_cmake_config_data/CMakeLists.txt
@@ -0,0 +1,90 @@
+# Copyright 2026 The OpenSSL Project Authors. All Rights Reserved.
+#
+# Licensed under the Apache License 2.0 (the "License"). You may not use
+# this file except in compliance with the License. You can obtain a copy
+# in the file LICENSE in the source distribution or at
+# https://www.openssl.org/source/license.html
+
+cmake_minimum_required(VERSION 3.22)
+project(OpenSSLConfigTest C)
+
+option(TEST_LEGACY_PROVIDER "Test loading the legacy provider" ON)
+
+# CONFIG mode is essential here; without it, CMake's own FindOpenSSL.cmake
+# module may be used instead of OpenSSL's exported config, which is what
+# this test is meant to exercise. Special circumstances: this test must
+# exercise this build tree's config specifically, so OpenSSL_ROOT /
+# OPENSSL_ROOT from the environment must not redirect the search.
+find_package(OpenSSL CONFIG REQUIRED
+ PATHS "${CMAKE_PREFIX_PATH}"
+ NO_DEFAULT_PATH)
+
+# We build the same dummy program in three variants, covering the ways
+# CMake's FindOpenSSL.cmake has traditionally promoted for linking against
+# OpenSSL:
+#
+# ossl_config_dummy_vars links with ${OPENSSL_LIBRARIES}, and calls
+# libssl and libcrypto functions directly
+# ossl_config_dummy_tgt links with the OpenSSL::SSL and OpenSSL::Crypto
+# targets, and calls libssl and libcrypto
+# functions directly
+# ossl_config_dummy_sslonly links with the OpenSSL::SSL target alone, and
+# only calls libssl functions directly, relying
+# on the implied libcrypto dependency
+
+add_executable(ossl_config_dummy_vars dummy.c)
+target_compile_definitions(ossl_config_dummy_vars PRIVATE DIRECT_CRYPTO_CALLS)
+target_link_libraries(ossl_config_dummy_vars PRIVATE ${OPENSSL_LIBRARIES})
+
+add_executable(ossl_config_dummy_tgt dummy.c)
+target_compile_definitions(ossl_config_dummy_tgt PRIVATE DIRECT_CRYPTO_CALLS)
+target_link_libraries(ossl_config_dummy_tgt PRIVATE OpenSSL::SSL OpenSSL::Crypto)
+
+add_executable(ossl_config_dummy_sslonly dummy.c)
+target_link_libraries(ossl_config_dummy_sslonly PRIVATE OpenSSL::SSL)
+
+set(all_dummies
+ ossl_config_dummy_vars ossl_config_dummy_tgt ossl_config_dummy_sslonly)
+set(crypto_dummies
+ ossl_config_dummy_vars ossl_config_dummy_tgt)
+
+if(WIN32)
+ # Console applications linking against the OpenSSL DLLs need applink,
+ # when that target exists (it's absent in no-uplink configurations)
+ if(TARGET OpenSSL::applink)
+ foreach(dummy IN LISTS all_dummies)
+ target_link_libraries(${dummy} PRIVATE OpenSSL::applink)
+ endforeach()
+ endif()
+
+ # Copy the OpenSSL DLLs next to the binaries, so the tests can run
+ if(DEFINED OPENSSL_LIBCRYPTO_SHARED)
+ foreach(dummy IN LISTS all_dummies)
+ add_custom_command(TARGET ${dummy} POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy_if_different
+ "${OPENSSL_LIBCRYPTO_SHARED}" "${OPENSSL_LIBSSL_SHARED}"
+ $<TARGET_FILE_DIR:${dummy}>)
+ endforeach()
+ endif()
+endif()
+
+if(TEST_LEGACY_PROVIDER)
+ foreach(dummy IN LISTS crypto_dummies)
+ target_compile_definitions(${dummy} PRIVATE TEST_LEGACY_PROVIDER)
+ endforeach()
+endif()
+
+enable_testing()
+
+# The dummy programs are run through OpenSSL's util/wrap.pl (path passed in
+# as OPENSSL_WRAP_PL), which sets up the loader path for the platform at
+# hand. OPENSSL_MODULES is set here to ensure the CMake configuration is
+# correctly exercised.
+find_program(PERL_PROGRAM perl REQUIRED)
+
+foreach(dummy IN LISTS all_dummies)
+ add_test(NAME ${dummy}
+ COMMAND ${PERL_PROGRAM} ${OPENSSL_WRAP_PL} $<TARGET_FILE:${dummy}>)
+ set_tests_properties(${dummy} PROPERTIES
+ ENVIRONMENT "OPENSSL_MODULES=${OPENSSL_MODULES_DIR}")
+endforeach()
diff --git a/test/recipes/94-test_cmake_config_data/dummy.c b/test/recipes/94-test_cmake_config_data/dummy.c
new file mode 100644
index 0000000000..2e6835485a
--- /dev/null
+++ b/test/recipes/94-test_cmake_config_data/dummy.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2026 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <openssl/ssl.h>
+#ifdef DIRECT_CRYPTO_CALLS
+#include <openssl/crypto.h>
+#include <openssl/provider.h>
+#endif
+
+int main(void)
+{
+ SSL_CTX *ctx = NULL;
+#ifdef DIRECT_CRYPTO_CALLS
+ /* Exercise libcrypto directly */
+ printf("Linked against %s\n", OpenSSL_version(OPENSSL_VERSION));
+#endif
+
+ /* Exercise libssl */
+ ctx = SSL_CTX_new(TLS_method());
+ if (ctx == NULL) {
+ fprintf(stderr, "SSL_CTX_new() failed\n");
+ return EXIT_FAILURE;
+ }
+ SSL_CTX_free(ctx);
+
+#if defined(DIRECT_CRYPTO_CALLS) && defined(TEST_LEGACY_PROVIDER)
+ /*
+ * Exercise the provider module search path. This relies on
+ * OPENSSL_MODULES being set appropriately in the environment.
+ */
+ {
+ OSSL_PROVIDER *legacy = NULL;
+ OSSL_PROVIDER *def = NULL;
+
+ legacy = OSSL_PROVIDER_load(NULL, "legacy");
+ if (legacy == NULL) {
+ fprintf(stderr, "OSSL_PROVIDER_load(\"legacy\") failed\n");
+ return EXIT_FAILURE;
+ }
+ def = OSSL_PROVIDER_load(NULL, "default");
+ if (def == NULL) {
+ fprintf(stderr, "OSSL_PROVIDER_load(\"default\") failed\n");
+ OSSL_PROVIDER_unload(legacy);
+ return EXIT_FAILURE;
+ }
+ OSSL_PROVIDER_unload(def);
+ OSSL_PROVIDER_unload(legacy);
+ }
+#endif
+
+ return EXIT_SUCCESS;
+}