summaryrefslogtreecommitdiffstats
path: root/cmake
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--cmake/CTestCostData.txt159
-rw-r--r--cmake/Modules/AdocMan.cmake135
-rw-r--r--cmake/Modules/FindBotan2.cmake131
-rw-r--r--cmake/Modules/FindGnuPG.cmake137
-rw-r--r--cmake/Modules/FindJSON-C.cmake123
-rw-r--r--cmake/Modules/FindOpenSSLFeatures.cmake171
-rw-r--r--cmake/Modules/FindWindowsSDK.cmake662
-rw-r--r--cmake/Modules/findopensslfeatures.c101
-rw-r--r--cmake/info.cmake41
-rw-r--r--cmake/librnp.pc.in13
-rw-r--r--cmake/packaging.cmake79
-rw-r--r--cmake/rnp-config.cmake.in31
-rw-r--r--cmake/rnp_tests_discover.cmake40
-rw-r--r--cmake/version.cmake163
14 files changed, 1986 insertions, 0 deletions
diff --git a/cmake/CTestCostData.txt b/cmake/CTestCostData.txt
new file mode 100644
index 0000000..1a00177
--- /dev/null
+++ b/cmake/CTestCostData.txt
@@ -0,0 +1,159 @@
+rnp_tests.hash_test_success 1 0.0138223
+rnp_tests.cipher_test_success 1 0.0120679
+rnp_tests.pkcs1_rsa_test_success 1 0.0714414
+rnp_tests.rnp_test_eddsa 1 0.014394
+rnp_tests.rnp_test_x25519 1 0.0197451
+rnp_tests.raw_elgamal_random_key_test_success 1 0.725944
+rnp_tests.ecdsa_signverify_success 1 0.0561304
+rnp_tests.ecdh_roundtrip 1 0.0383161
+rnp_tests.ecdh_decryptionNegativeCases 1 0.0201392
+rnp_tests.sm2_roundtrip 1 0.0214206
+rnp_tests.sm2_sm3_signature_test 1 0.027973
+rnp_tests.sm2_sha256_signature_test 1 0.0269801
+rnp_tests.test_dsa_roundtrip 1 24.2023
+rnp_tests.test_dsa_verify_negative 1 0.800061
+rnp_tests.s2k_iteration_tuning 1 0.515675
+rnp_tests.s2k_iteration_encode_decode 1 0.0134686
+rnp_tests.test_validate_key_material 1 1.68337
+rnp_tests.test_cli_rnp_keyfile 1 0.859851
+rnp_tests.test_cli_g10_operations 1 2.50301
+rnp_tests.test_cli_rnp 1 0.0972449
+rnp_tests.test_cli_examples 1 1.3149
+rnp_tests.test_cli_rnpkeys 1 0.115061
+rnp_tests.test_cli_dump 1 0.0361111
+rnp_tests.test_cli_logname 1 0.0116097
+rnp_tests.rnpkeys_exportkey_verifyUserId 1 0.118051
+rnp_tests.test_ffi_homedir 1 0.0241839
+rnp_tests.test_ffi_detect_key_format 1 0.0129409
+rnp_tests.test_ffi_load_keys 1 0.0493167
+rnp_tests.test_ffi_clear_keys 1 0.0259738
+rnp_tests.test_ffi_save_keys 1 0.0316757
+rnp_tests.test_ffi_keygen_json_pair 1 0.0736696
+rnp_tests.test_ffi_keygen_json_pair_dsa_elg 1 12.7012
+rnp_tests.test_ffi_keygen_json_primary 1 0.0194215
+rnp_tests.test_ffi_keygen_json_sub 1 0.0573184
+rnp_tests.test_ffi_key_generate_misc 1 0.985612
+rnp_tests.test_ffi_key_generate_rsa 1 0.342821
+rnp_tests.test_ffi_key_generate_dsa 1 2.13331
+rnp_tests.test_ffi_key_generate_ecdsa 1 0.0177323
+rnp_tests.test_ffi_key_generate_eddsa 1 0.0143182
+rnp_tests.test_ffi_key_generate_sm2 1 0.0175289
+rnp_tests.test_ffi_key_generate_ex 1 5.74498
+rnp_tests.test_ffi_key_generate_algnamecase 1 2.62221
+rnp_tests.test_ffi_key_generate_protection 1 1.40079
+rnp_tests.test_ffi_add_userid 1 0.0404918
+rnp_tests.test_ffi_keygen_json_sub_pass_required 1 0.382914
+rnp_tests.test_ffi_encrypt_pass 1 0.429726
+rnp_tests.test_ffi_encrypt_pass_provider 1 0.342456
+rnp_tests.test_ffi_encrypt_pk 1 0.0482677
+rnp_tests.test_ffi_encrypt_pk_key_provider 1 0.0339246
+rnp_tests.test_ffi_encrypt_and_sign 1 0.0917957
+rnp_tests.test_ffi_signatures_memory 1 0.0518454
+rnp_tests.test_ffi_signatures 1 0.0488163
+rnp_tests.test_ffi_signatures_detached_memory 1 0.0492941
+rnp_tests.test_ffi_signatures_detached 1 0.04846
+rnp_tests.test_ffi_signatures_dump 1 0.0168647
+rnp_tests.test_ffi_key_to_json 1 0.0164411
+rnp_tests.test_ffi_key_iter 1 0.0261607
+rnp_tests.test_ffi_locate_key 1 0.0161026
+rnp_tests.test_ffi_signatures_detached_memory_g10 1 0.0427063
+rnp_tests.test_ffi_enarmor_dearmor 1 0.0373763
+rnp_tests.test_ffi_version 1 0.0140884
+rnp_tests.test_ffi_key_export 1 0.0250205
+rnp_tests.test_ffi_key_dump 1 0.0256317
+rnp_tests.test_ffi_pkt_dump 1 0.0167862
+rnp_tests.test_ffi_rsa_v3_dump 1 0.0158175
+rnp_tests.test_ffi_load_userattr 1 0.0177854
+rnp_tests.test_ffi_revocations 1 0.0191412
+rnp_tests.test_ffi_file_output 1 0.0292883
+rnp_tests.test_ffi_key_signatures 1 0.0211163
+rnp_tests.test_ffi_keys_import 1 0.577245
+rnp_tests.test_ffi_import_keys_check_pktlen 1 0.0151679
+rnp_tests.test_ffi_calculate_iterations 1 0.0279029
+rnp_tests.test_ffi_supported_features 1 0.0149266
+rnp_tests.test_ffi_enable_debug 1 0.010948
+rnp_tests.test_ffi_rnp_key_get_primary_grip 1 0.0178161
+rnp_tests.test_ffi_output_to_armor 1 0.01893
+rnp_tests.test_ffi_rnp_guess_contents 1 0.0121287
+rnp_tests.test_ffi_literal_filename 1 0.0552985
+rnp_tests.test_ffi_op_set_hash 1 0.0528855
+rnp_tests.test_ffi_op_set_compression 1 0.0730627
+rnp_tests.test_ffi_aead_params 1 0.241513
+rnp_tests.test_ffi_detached_verify_input 1 0.0228228
+rnp_tests.test_ffi_op_verify_sig_count 1 0.0491328
+rnp_tests.rnpkeys_generatekey_testSignature 1 1.18378
+rnp_tests.rnpkeys_generatekey_testEncryption 1 0.275621
+rnp_tests.rnpkeys_generatekey_verifySupportedHashAlg 1 1.41153
+rnp_tests.rnpkeys_generatekey_verifyUserIdOption 1 0.616167
+rnp_tests.rnpkeys_generatekey_verifykeyHomeDirOption 1 0.188337
+rnp_tests.rnpkeys_generatekey_verifykeyKBXHomeDirOption 1 0.205113
+rnp_tests.rnpkeys_generatekey_verifykeyHomeDirNoPermission 1 0.149937
+rnp_tests.rnpkeys_generatekey_testExpertMode 1 2.63892
+rnp_tests.generatekeyECDSA_explicitlySetSmallOutputDigest_DigestAlgAdjusted 1 0.0200285
+rnp_tests.generatekey_multipleUserIds_ShouldFail 1 0.0110169
+rnp_tests.generatekeyECDSA_explicitlySetBiggerThanNeededDigest_ShouldSuceed 1 0.0187109
+rnp_tests.generatekeyECDSA_explicitlySetUnknownDigest_ShouldFail 1 0.0133541
+rnp_tests.test_generated_key_sigs 1 0.128008
+rnp_tests.test_kbx_nsigs 1 4.07201
+rnp_tests.test_key_add_userid 1 0.0324633
+rnp_tests.key_grip 1 0.0621873
+rnp_tests.test_key_prefs 1 0.0115654
+rnp_tests.test_key_protect_load_pgp 1 0.330786
+rnp_tests.test_key_store_search 1 0.0108802
+rnp_tests.test_key_store_search_by_name 1 0.0138023
+rnp_tests.test_key_unlock_pgp 1 0.0629279
+rnp_tests.test_key_validate 1 0.0313496
+rnp_tests.test_forged_key_validate 1 0.0350325
+rnp_tests.test_key_validity 1 0.0179677
+rnp_tests.test_large_packet 1 12.6562
+rnp_tests.test_load_g10 1 0.493759
+rnp_tests.test_load_v3_keyring_pgp 1 0.012287
+rnp_tests.test_load_v4_keyring_pgp 1 0.015202
+rnp_tests.test_load_keyring_and_count_pgp 1 0.0166739
+rnp_tests.test_load_check_bitfields_and_times 1 0.0145676
+rnp_tests.test_load_check_bitfields_and_times_v3 1 0.0141121
+rnp_tests.test_load_armored_pub_sec 1 0.0233942
+rnp_tests.test_load_merge 1 0.148499
+rnp_tests.test_load_public_from_secret 1 0.0321099
+rnp_tests.test_key_import 1 0.256372
+rnp_tests.test_load_subkey 1 0.0191733
+rnp_tests.test_partial_length_public_key 1 0.0120663
+rnp_tests.test_partial_length_signature 1 0.0141925
+rnp_tests.test_partial_length_first_packet_256 1 0.017635
+rnp_tests.test_partial_length_zero_last_chunk 1 0.0177394
+rnp_tests.test_partial_length_largest 1 3.20183
+rnp_tests.test_partial_length_first_packet_length 1 0.0300068
+rnp_tests.test_s2k_iterations 1 7.229982
+rnp_tests.test_stream_memory 1 0.0125394
+rnp_tests.test_stream_memory_discard 1 0.0111196
+rnp_tests.test_stream_file 1 0.0168583
+rnp_tests.test_stream_signatures 1 0.0373302
+rnp_tests.test_stream_signatures_revoked_key 1 0.012537
+rnp_tests.test_stream_key_load 1 0.0130797
+rnp_tests.test_stream_key_load_errors 1 0.727713
+rnp_tests.test_stream_key_decrypt 1 0.511516
+rnp_tests.test_stream_key_encrypt 1 0.487256
+rnp_tests.test_stream_key_signatures 1 0.0199383
+rnp_tests.test_stream_key_signature_validate 1 0.108001
+rnp_tests.test_stream_verify_no_key 1 0.0301321
+rnp_tests.test_stream_dumper 1 0.0180775
+rnp_tests.test_stream_z 1 21.1022
+rnp_tests.test_stream_814_dearmor_double_free 1 0.0119918
+rnp_tests.test_stream_825_dearmor_blank_line 1 0.0155773
+rnp_tests.test_stream_dearmor_edge_cases 1 0.0119838
+rnp_tests.test_load_user_prefs 1 0.0142821
+rnp_tests.test_utils_list 1 0.0107737
+rnp_tests.test_rnpcfg 1 0.0108745
+rnp_tests.issue_1030_rnpkeys_secret_keys_unprotected 1 0.31969
+setupTestData 1 0.0175373
+cli_tests-Keystore 1 5.56182
+cli_tests-SignECDSA 1 3.92326
+cli_tests-Compression 1 137.827
+cli_tests-Encryption 1 329.997
+cli_tests-Misc 1 35.6212
+cli_tests-SignDefault 1 16.0034
+cli_tests-EncryptEcdh 1 4.19268
+cli_tests-SignDSA 1 6.13993
+cli_tests-EncryptSignRSA 1 2.47967
+cli_tests-EncryptElgamal 1 11.2535
+---
diff --git a/cmake/Modules/AdocMan.cmake b/cmake/Modules/AdocMan.cmake
new file mode 100644
index 0000000..96c5c93
--- /dev/null
+++ b/cmake/Modules/AdocMan.cmake
@@ -0,0 +1,135 @@
+# Copyright (c) 2021 Ribose Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+#.adoc:
+# add_adoc_man
+# -----------
+#
+# Convert adoc manual page to troff and install it via the custom target.
+#
+# Parameters
+# ^^^^^^^^^^
+# Required parameter is source with markdown file. Must have md extension with man category prepended, i.e. something like ${CMAKE_SOURCE_DIR}/src/utility.1.adoc
+# DST - optional parameter, which overrides where generated man will be stored.
+# If not specified then will be automatically set to ${CMAKE_BINARY_DIR}/src/utility.1
+#
+# Generated man page will be installed via the target, named man_utility
+#
+
+set(ADOCCOMMAND_FOUND 0)
+find_program(ADOCCOMMAND_PATH
+ NAMES asciidoctor
+ DOC "Path to AsciiDoc processor. Used to generate man pages from AsciiDoc."
+)
+
+if(NOT EXISTS ${ADOCCOMMAND_PATH})
+ set(ADOC_MISSING_MSG "AsciiDoc processor not found, man pages will not be generated. Install asciidoctor or use the CMAKE_PROGRAM_PATH variable.")
+
+ string(TOLOWER "${ENABLE_DOC}" ENABLE_DOC)
+ if (ENABLE_DOC STREQUAL "auto")
+ message(WARNING ${ADOC_MISSING_MSG})
+ elseif(ENABLE_DOC)
+ message(FATAL_ERROR ${ADOC_MISSING_MSG})
+ endif()
+else()
+ set(ADOCCOMMAND_FOUND 1)
+endif()
+
+function(add_adoc_man SRC COMPONENT_VERSION)
+ if (NOT ${ADOCCOMMAND_FOUND})
+ return()
+ endif()
+
+ cmake_parse_arguments(
+ ARGS
+ ""
+ "DST"
+ ""
+ ${ARGN}
+ )
+
+ set(ADOC_EXT ".adoc")
+ get_filename_component(FILE_NAME ${SRC} NAME)
+
+ # The following procedures check against the expected file name
+ # pattern: "{name}.{man-number}.adoc", and builds to a
+ # destination file "{name}.{man-number}".
+
+ # Check SRC extension
+ get_filename_component(END_EXT ${SRC} LAST_EXT)
+ string(COMPARE EQUAL ${END_EXT} ${ADOC_EXT} _equal)
+ if (NOT _equal)
+ message(FATAL_ERROR "SRC must have ${ADOC_EXT} extension.")
+ endif()
+
+ # Check man number
+ get_filename_component(EXTS ${SRC} EXT)
+ string(REGEX MATCH "^\.([1-9])\.+$" _matches ${EXTS})
+ set(MAN_NUM ${CMAKE_MATCH_1})
+ if (NOT _matches)
+ message(FATAL_ERROR "Man file with wrong name pattern: ${FILE_NAME} must be in format {name}.[0-9]${ADOC_EXT}.")
+ endif()
+
+ # Set target name
+ get_filename_component(TARGET_NAME ${SRC} NAME_WE)
+ string(PREPEND TARGET_NAME "man_")
+
+ # Build output path if not specified.
+ if(NOT DST)
+ get_filename_component(SRC_PREFIX ${SRC} DIRECTORY)
+
+ # Ensure that SRC_PREFIX is within CMAKE_SOURCE_DIR
+ if(NOT(SRC_PREFIX MATCHES "^${CMAKE_SOURCE_DIR}"))
+ message(FATAL_ERROR "Cannot build DST path as SRC is outside of the CMake sources dir.")
+ endif()
+ STRING(REGEX REPLACE "^${CMAKE_SOURCE_DIR}/" "" SUBDIR_PATH ${SRC})
+
+ # Strip '.adoc' from the output subpath
+ get_filename_component(SUBDIR_PATH_NAME_WLE ${SUBDIR_PATH} NAME_WLE)
+ get_filename_component(SUBDIR_PATH_DIRECTORY ${SUBDIR_PATH} DIRECTORY)
+ set(DST "${CMAKE_BINARY_DIR}/${SUBDIR_PATH_DIRECTORY}/${SUBDIR_PATH_NAME_WLE}")
+ endif()
+
+ # Check conformance of destination file name to pattern
+ get_filename_component(FILE_NAME_WE ${SRC} NAME_WE)
+ get_filename_component(MAN_FILE_NAME ${DST} NAME)
+ if(NOT(MAN_FILE_NAME MATCHES "^${FILE_NAME_WE}.${MAN_NUM}$"))
+ message(FATAL_ERROR "File name of a man page must be in the format {name}.{man-number}${ADOC_EXT}.")
+ endif()
+
+ add_custom_command(
+ OUTPUT ${DST}
+ COMMAND ${ADOCCOMMAND_PATH} -b manpage ${SRC} -o ${DST} -a component-version=${COMPONENT_VERSION}
+ DEPENDS ${SRC}
+ WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
+ COMMENT "Generating man page ${SUBDIR_PATH_DIRECTORY}/${SUBDIR_PATH_NAME_WLE}"
+ VERBATIM
+ )
+
+ add_custom_target("${TARGET_NAME}" ALL DEPENDS ${DST})
+ install(FILES ${DST}
+ DESTINATION "${CMAKE_INSTALL_FULL_MANDIR}/man${MAN_NUM}"
+ COMPONENT doc
+ )
+endfunction(add_adoc_man)
diff --git a/cmake/Modules/FindBotan2.cmake b/cmake/Modules/FindBotan2.cmake
new file mode 100644
index 0000000..2708491
--- /dev/null
+++ b/cmake/Modules/FindBotan2.cmake
@@ -0,0 +1,131 @@
+# Copyright (c) 2018-2020 Ribose Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+#.rst:
+# FindBotan2
+# -----------
+#
+# Find the botan-2 library.
+#
+# IMPORTED Targets
+# ^^^^^^^^^^^^^^^^
+#
+# This module defines :prop_tgt:`IMPORTED` targets:
+#
+# ``Botan2::Botan2``
+# The botan-2 library, if found.
+#
+# Result variables
+# ^^^^^^^^^^^^^^^^
+#
+# This module defines the following variables:
+#
+# ::
+#
+# BOTAN2_FOUND - true if the headers and library were found
+# BOTAN2_INCLUDE_DIRS - where to find headers
+# BOTAN2_LIBRARIES - list of libraries to link
+# BOTAN2_VERSION - library version that was found, if any
+
+# use pkg-config to get the directories and then use these values
+# in the find_path() and find_library() calls
+find_package(PkgConfig QUIET)
+pkg_check_modules(PC_BOTAN2 QUIET botan-2)
+
+# find the headers
+find_path(BOTAN2_INCLUDE_DIR
+ NAMES botan/version.h
+ HINTS
+ ${PC_BOTAN2_INCLUDEDIR}
+ ${PC_BOTAN2_INCLUDE_DIRS}
+ PATH_SUFFIXES botan-2
+)
+
+# find the library
+if(MSVC)
+ find_library(BOTAN2_LIBRARY
+ NAMES botan
+ HINTS
+ ${PC_BOTAN2_LIBDIR}
+ ${PC_BOTAN2_LIBRARY_DIRS}
+ )
+else()
+ find_library(BOTAN2_LIBRARY
+ NAMES botan-2 libbotan-2
+ HINTS
+ ${PC_BOTAN2_LIBDIR}
+ ${PC_BOTAN2_LIBRARY_DIRS}
+ )
+endif()
+
+# determine the version
+if(PC_BOTAN2_VERSION)
+ set(BOTAN2_VERSION ${PC_BOTAN2_VERSION})
+elseif(BOTAN2_INCLUDE_DIR AND EXISTS "${BOTAN2_INCLUDE_DIR}/botan/build.h")
+ file(STRINGS "${BOTAN2_INCLUDE_DIR}/botan/build.h" botan2_version_str
+ REGEX "^#define[\t ]+(BOTAN_VERSION_[A-Z]+)[\t ]+[0-9]+")
+
+ string(REGEX REPLACE ".*#define[\t ]+BOTAN_VERSION_MAJOR[\t ]+([0-9]+).*"
+ "\\1" _botan2_version_major "${botan2_version_str}")
+ string(REGEX REPLACE ".*#define[\t ]+BOTAN_VERSION_MINOR[\t ]+([0-9]+).*"
+ "\\1" _botan2_version_minor "${botan2_version_str}")
+ string(REGEX REPLACE ".*#define[\t ]+BOTAN_VERSION_PATCH[\t ]+([0-9]+).*"
+ "\\1" _botan2_version_patch "${botan2_version_str}")
+ set(BOTAN2_VERSION "${_botan2_version_major}.${_botan2_version_minor}.${_botan2_version_patch}"
+ CACHE INTERNAL "The version of Botan which was detected")
+endif()
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(Botan2
+ REQUIRED_VARS BOTAN2_LIBRARY BOTAN2_INCLUDE_DIR
+ VERSION_VAR BOTAN2_VERSION
+)
+
+if (BOTAN2_FOUND)
+ set(BOTAN2_INCLUDE_DIRS ${BOTAN2_INCLUDE_DIR} ${PC_BOTAN2_INCLUDE_DIRS})
+ set(BOTAN2_LIBRARIES ${BOTAN2_LIBRARY})
+endif()
+
+if (BOTAN2_FOUND AND NOT TARGET Botan2::Botan2)
+ # create the new library target
+ add_library(Botan2::Botan2 UNKNOWN IMPORTED)
+ # set the required include dirs for the target
+ if (BOTAN2_INCLUDE_DIRS)
+ set_target_properties(Botan2::Botan2
+ PROPERTIES
+ INTERFACE_INCLUDE_DIRECTORIES "${BOTAN2_INCLUDE_DIRS}"
+ )
+ endif()
+ # set the required libraries for the target
+ if (EXISTS "${BOTAN2_LIBRARY}")
+ set_target_properties(Botan2::Botan2
+ PROPERTIES
+ IMPORTED_LINK_INTERFACE_LANGUAGES "C"
+ IMPORTED_LOCATION "${BOTAN2_LIBRARY}"
+ )
+ endif()
+endif()
+
+mark_as_advanced(BOTAN2_INCLUDE_DIR BOTAN2_LIBRARY)
+
diff --git a/cmake/Modules/FindGnuPG.cmake b/cmake/Modules/FindGnuPG.cmake
new file mode 100644
index 0000000..ed92027
--- /dev/null
+++ b/cmake/Modules/FindGnuPG.cmake
@@ -0,0 +1,137 @@
+# Copyright (c) 2018 Ribose Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+#.rst:
+# FindGnuPG
+# -----------
+#
+# Find GnuPG executables.
+#
+# Imported targets
+# ^^^^^^^^^^^^^^^^
+#
+# This module defines the following :prop_tgt:`IMPORTED` targets:
+#
+# ::
+#
+# GnuPG::<COMPONENT> - the component executable that was requested (default is just 'gpg')
+#
+## Result variables
+# ^^^^^^^^^^^^^^^^
+#
+# This module always defines the following variables:
+#
+# ::
+#
+# GNUPG_VERSION - version that was found
+#
+# Depending on components requested, this module will also define variables like:
+#
+# ::
+#
+# GPG_EXECUTABLE - path to the gpg executable
+# <COMPONENT>_EXECUTABLE - path to the component executable
+#
+
+# helper that will call <utility_name> --version and extract the version string
+function(_get_gpg_version utility_name exe_path var_prefix)
+ execute_process(
+ COMMAND "${exe_path}" --version
+ OUTPUT_VARIABLE version
+ RESULT_VARIABLE exit_code
+ ERROR_QUIET
+ )
+ if (NOT exit_code)
+ string(REGEX MATCH "${utility_name} \\(GnuPG\\) (([0-9]+)\\.([0-9]+)\\.([0-9]+))" version "${version}")
+ if (CMAKE_MATCH_1)
+ set(${var_prefix}_VERSION "${CMAKE_MATCH_1}" PARENT_SCOPE)
+ endif()
+ endif()
+endfunction()
+
+# default to finding gpg
+if (NOT GnuPG_FIND_COMPONENTS)
+ set(GnuPG_FIND_COMPONENTS gpg)
+endif()
+
+foreach(_comp IN LISTS GnuPG_FIND_COMPONENTS)
+ # we also check for an executable with the 2 suffix when appropriate
+ set(_names "${_comp}")
+ if (_comp STREQUAL "gpg" OR _comp STREQUAL "gpgv")
+ if (NOT ${GnuPG_FIND_VERSION})
+ set(_names "${_comp}2" ${_comp})
+ elseif (${GnuPG_FIND_VERSION} VERSION_GREATER_EQUAL 2.2)
+ # 2.2+ defaults to gpg/gpgv, but supports gpg2/gpgv2
+ set(_names ${_comp} "${_comp}2")
+ elseif(${GnuPG_FIND_VERSION} VERSION_GREATER_EQUAL 2.0)
+ # 2.0-2.2 or so used a temporary naming of gpg2/gpgv2
+ set(_names "${_comp}2" ${_comp})
+ endif()
+ endif()
+ string(TOUPPER "${_comp}" _comp_upper)
+ find_program(${_comp_upper}_EXECUTABLE NAMES ${_names})
+ unset(_names)
+ mark_as_advanced(${_comp_upper}_EXECUTABLE)
+
+ # if we found an executable, check the version
+ if (${_comp_upper}_EXECUTABLE)
+ _get_gpg_version(${_comp} ${${_comp_upper}_EXECUTABLE} _${_comp})
+ if (_${_comp}_VERSION)
+ if (NOT GNUPG_VERSION)
+ # this is the first component found, so set the version to match
+ set(GNUPG_VERSION ${_${_comp}_VERSION})
+ endif()
+ # see if the version matches the previous components found
+ if(_${_comp}_VERSION VERSION_EQUAL ${GNUPG_VERSION} AND NOT TARGET GnuPG::${_comp})
+ add_executable(GnuPG::${_comp} IMPORTED GLOBAL)
+ set_target_properties(GnuPG::${_comp} PROPERTIES
+ IMPORTED_LOCATION "${${_comp_upper}_EXECUTABLE}"
+ )
+ endif()
+ endif()
+ unset(_${_comp}_VERSION)
+ endif()
+
+ # mark our components as found or not found
+ if (TARGET GnuPG::${_comp})
+ set(GnuPG_${_comp}_FOUND TRUE)
+ else()
+ set(GnuPG_${_comp}_FOUND FALSE)
+ unset(${_comp_upper}_EXECUTABLE)
+ endif()
+
+ if (GnuPG_FIND_REQUIRED_${_comp})
+ list(APPEND _GnuPG_REQUIRED_VARS ${_comp_upper}_EXECUTABLE)
+ endif()
+endforeach()
+unset(_comp)
+unset(_comp_upper)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(GnuPG
+ REQUIRED_VARS ${_GnuPG_REQUIRED_VARS}
+ VERSION_VAR GNUPG_VERSION
+ HANDLE_COMPONENTS
+)
+
diff --git a/cmake/Modules/FindJSON-C.cmake b/cmake/Modules/FindJSON-C.cmake
new file mode 100644
index 0000000..e66a011
--- /dev/null
+++ b/cmake/Modules/FindJSON-C.cmake
@@ -0,0 +1,123 @@
+# Copyright (c) 2018 Ribose Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+#.rst:
+# FindJSON-C
+# -----------
+#
+# Find the json-c library.
+#
+# IMPORTED Targets
+# ^^^^^^^^^^^^^^^^
+#
+# This module defines :prop_tgt:`IMPORTED` targets:
+#
+# ``JSON-C::JSON-C``
+# The json-c library, if found.
+#
+# Result variables
+# ^^^^^^^^^^^^^^^^
+#
+# This module defines the following variables:
+#
+# ::
+#
+# JSON-C_FOUND - true if the headers and library were found
+# JSON-C_INCLUDE_DIRS - where to find headers
+# JSON-C_LIBRARIES - list of libraries to link
+# JSON-C_VERSION - library version that was found, if any
+
+# use pkg-config to get the directories and then use these values
+# in the find_path() and find_library() calls
+find_package(PkgConfig QUIET)
+pkg_check_modules(PC_JSON-C QUIET json-c)
+
+# RHEL-based systems may have json-c12
+if (NOT PC_JSON-C_FOUND)
+ pkg_check_modules(PC_JSON-C QUIET json-c12)
+endif()
+
+# find the headers
+find_path(JSON-C_INCLUDE_DIR
+ NAMES json_c_version.h
+ HINTS
+ ${PC_JSON-C_INCLUDEDIR}
+ ${PC_JSON-C_INCLUDE_DIRS}
+ PATH_SUFFIXES json-c
+)
+
+# find the library
+find_library(JSON-C_LIBRARY
+ NAMES json-c libjson-c json-c12 libjson-c12
+ HINTS
+ ${PC_JSON-C_LIBDIR}
+ ${PC_JSON-C_LIBRARY_DIRS}
+)
+
+# determine the version
+if(PC_JSON-C_VERSION)
+ set(JSON-C_VERSION ${PC_JSON-C_VERSION})
+elseif(JSON-C_INCLUDE_DIR AND EXISTS "${JSON-C_INCLUDE_DIR}/json_c_version.h")
+ file(STRINGS "${JSON-C_INCLUDE_DIR}/json_c_version.h" _json-c_version_h
+ REGEX "^#define[\t ]+JSON_C_VERSION[\t ]+\"[^\"]*\"$")
+
+ string(REGEX REPLACE ".*#define[\t ]+JSON_C_VERSION[\t ]+\"([^\"]*)\".*"
+ "\\1" _json-c_version_str "${_json-c_version_h}")
+ set(JSON-C_VERSION "${_json-c_version_str}"
+ CACHE INTERNAL "The version of json-c which was detected")
+endif()
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(JSON-C
+ REQUIRED_VARS JSON-C_LIBRARY JSON-C_INCLUDE_DIR JSON-C_VERSION
+ VERSION_VAR JSON-C_VERSION
+)
+
+if (JSON-C_FOUND)
+ set(JSON-C_INCLUDE_DIRS ${JSON-C_INCLUDE_DIR} ${PC_JSON-C_INCLUDE_DIRS})
+ set(JSON-C_LIBRARIES ${JSON-C_LIBRARY})
+endif()
+
+if (JSON-C_FOUND AND NOT TARGET JSON-C::JSON-C)
+ # create the new library target
+ add_library(JSON-C::JSON-C UNKNOWN IMPORTED)
+ # set the required include dirs for the target
+ if (JSON-C_INCLUDE_DIRS)
+ set_target_properties(JSON-C::JSON-C
+ PROPERTIES
+ INTERFACE_INCLUDE_DIRECTORIES "${JSON-C_INCLUDE_DIRS}"
+ )
+ endif()
+ # set the required libraries for the target
+ if (EXISTS "${JSON-C_LIBRARY}")
+ set_target_properties(JSON-C::JSON-C
+ PROPERTIES
+ IMPORTED_LINK_INTERFACE_LANGUAGES "C"
+ IMPORTED_LOCATION "${JSON-C_LIBRARY}"
+ )
+ endif()
+endif()
+
+mark_as_advanced(JSON-C_INCLUDE_DIR JSON-C_LIBRARY)
+
diff --git a/cmake/Modules/FindOpenSSLFeatures.cmake b/cmake/Modules/FindOpenSSLFeatures.cmake
new file mode 100644
index 0000000..6967764
--- /dev/null
+++ b/cmake/Modules/FindOpenSSLFeatures.cmake
@@ -0,0 +1,171 @@
+# Copyright (c) 2021 Ribose Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+#.rst:
+# FindOpenSSLFeatures
+# -----------
+#
+# Find OpenSSL features: supported hashes, ciphers, curves and public-key algorithms.
+# Requires FindOpenSSL to be included first, and C compiler to be set as module
+# compiles and executes program which do checks against installed OpenSSL library.
+#
+# Result variables
+# ^^^^^^^^^^^^^^^^
+#
+# This module defines the following variables:
+#
+# ::
+#
+# OPENSSL_SUPPORTED_HASHES - list of the supported hash algorithms
+# OPENSSL_SUPPORTED_CIPHERS - list of the supported ciphers
+# OPENSSL_SUPPORTED_CURVES - list of the supported elliptic curves
+# OPENSSL_SUPPORTED_PUBLICKEY - list of the supported public-key algorithms
+# OPENSSL_SUPPORTED_FEATURES - all previous lists, glued together
+#
+# Functions
+# ^^^^^^^^^
+# OpenSSLHasFeature(FEATURE <VARIABLE>)
+# Check whether OpenSSL has corresponding feature (hash/curve/public-key algorithm name, elliptic curve).
+# Result is stored in VARIABLE as boolean value, i.e. TRUE or FALSE
+#
+if (NOT OPENSSL_FOUND)
+ message(FATAL_ERROR "OpenSSL is not found. Please make sure that you call find_package(OpenSSL) first.")
+endif()
+
+message(STATUS "Querying OpenSSL features")
+
+# Copy and build findopensslfeatures.c in fossl-build subfolder.
+set(_fossl_work_dir "${CMAKE_BINARY_DIR}/fossl")
+file(MAKE_DIRECTORY "${_fossl_work_dir}")
+file(COPY "${CMAKE_CURRENT_LIST_DIR}/findopensslfeatures.c"
+ DESTINATION "${_fossl_work_dir}"
+)
+# As it's short enough let's keep it here.
+# Reuse OPENSSL parameters from the upstream project
+# otherwise there is a good chance to find another instance of openssl
+# We assume that OpenSSL root is one level up openssl include directory
+# This does not look as a good solution, however it is the only one that
+# works with all Windows configuration options
+
+message(STATUS "Using OpenSSL root directory at ${OPENSSL_INCLUDE_DIR}/..")
+
+file(WRITE "${_fossl_work_dir}/CMakeLists.txt"
+"cmake_minimum_required(VERSION 3.18)\n\
+project(findopensslfeatures LANGUAGES C)\n\
+set(CMAKE_C_STANDARD 99)\n\
+include(FindOpenSSL)\n\
+find_package(OpenSSL REQUIRED)\n\
+add_executable(findopensslfeatures findopensslfeatures.c)\n\
+target_include_directories(findopensslfeatures PRIVATE ${OPENSSL_INCLUDE_DIR})\n\
+target_link_libraries(findopensslfeatures PRIVATE OpenSSL::Crypto)\n\
+if (OpenSSL::applink)\n\
+ target_link_libraries(findopensslfeatures PRIVATE OpenSSL::applink)\n\
+endif(OpenSSL::applink)\n"
+)
+
+set(MKF ${MKF} "-DCMAKE_BUILD_TYPE=Release" "-DOPENSSL_ROOT_DIR=${OPENSSL_INCLUDE_DIR}/..")
+
+if(CMAKE_PREFIX_PATH)
+ set(MKF ${MKF} "-DCMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH}")
+endif(CMAKE_PREFIX_PATH)
+
+if(CMAKE_TOOLCHAIN_FILE)
+ set(MKF ${MKF} "-DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}")
+endif(CMAKE_TOOLCHAIN_FILE)
+
+if(CMAKE_GENERATOR_PLATFORM)
+ set(MKF ${MKF} "-A" "${CMAKE_GENERATOR_PLATFORM}")
+endif(CMAKE_GENERATOR_PLATFORM)
+
+if(CMAKE_GENERATOR_TOOLSET)
+ set(MKF ${MKF} "-T" "${CMAKE_GENERATOR_TOOLSET}")
+endif(CMAKE_GENERATOR_TOOLSET)
+
+execute_process(
+ COMMAND "${CMAKE_COMMAND}" "-Bbuild" ${MKF} "."
+ WORKING_DIRECTORY "${_fossl_work_dir}"
+ OUTPUT_VARIABLE output
+ ERROR_VARIABLE error
+ RESULT_VARIABLE result
+ COMMAND_ECHO STDOUT
+ ECHO_OUTPUT_VARIABLE
+ ECHO_ERROR_VARIABLE
+)
+
+if (NOT ${result} EQUAL 0)
+ message(FATAL_ERROR "Error configuring findopensslfeatures")
+endif()
+
+execute_process(
+ COMMAND "${CMAKE_COMMAND}" "--build" "build" --config "Release"
+ WORKING_DIRECTORY "${_fossl_work_dir}"
+ OUTPUT_VARIABLE output
+ ERROR_VARIABLE error
+ RESULT_VARIABLE result
+ COMMAND_ECHO STDOUT
+ ECHO_OUTPUT_VARIABLE
+ ECHO_ERROR_VARIABLE
+)
+
+if (NOT ${result} EQUAL 0)
+ message(FATAL_ERROR "Error building findopensslfeatures")
+endif()
+
+set(OPENSSL_SUPPORTED_FEATURES "")
+if(WIN32 AND NOT MINGW)
+ set(FOF "build/Release/findopensslfeatures")
+else(WIN32 AND NOT MINGW)
+ set(FOF "build/findopensslfeatures")
+endif(WIN32 AND NOT MINGW)
+
+foreach(feature "hashes" "ciphers" "curves" "publickey")
+ execute_process(
+ COMMAND "${FOF}" "${feature}"
+ WORKING_DIRECTORY "${_fossl_work_dir}"
+ OUTPUT_VARIABLE feature_val
+ ERROR_VARIABLE error
+ RESULT_VARIABLE result
+ )
+
+ if(NOT ${result} EQUAL 0)
+ message(FATAL_ERROR "Error getting supported OpenSSL ${feature}: ${result}\n${error}")
+ endif()
+
+ string(TOUPPER ${feature} feature_up)
+ string(TOUPPER ${feature_val} feature_val)
+ string(REPLACE "\n" ";" feature_val ${feature_val})
+ set(OPENSSL_SUPPORTED_${feature_up} ${feature_val})
+ list(LENGTH OPENSSL_SUPPORTED_${feature_up} ${feature}_len)
+ list(APPEND OPENSSL_SUPPORTED_FEATURES ${OPENSSL_SUPPORTED_${feature_up}})
+endforeach()
+
+message(STATUS "Fetched OpenSSL features: ${hashes_len} hashes, ${ciphers_len} ciphers, ${curves_len} curves, ${publickey_len} publickey.")
+
+function(OpenSSLHasFeature FEATURE VARIABLE)
+ string(TOUPPER ${FEATURE} _feature_up)
+ set(${VARIABLE} FALSE PARENT_SCOPE)
+ if (${_feature_up} IN_LIST OPENSSL_SUPPORTED_FEATURES)
+ set(${VARIABLE} TRUE PARENT_SCOPE)
+ endif()
+endfunction(OpenSSLHasFeature)
diff --git a/cmake/Modules/FindWindowsSDK.cmake b/cmake/Modules/FindWindowsSDK.cmake
new file mode 100644
index 0000000..d18e979
--- /dev/null
+++ b/cmake/Modules/FindWindowsSDK.cmake
@@ -0,0 +1,662 @@
+# - Find the Windows SDK aka Platform SDK
+# taken from https://github.com/ampl/mp/blob/master/support/cmake/FindWindowsSDK.cmake
+#
+# Relevant Wikipedia article: http://en.wikipedia.org/wiki/Microsoft_Windows_SDK
+#
+# Pass "COMPONENTS tools" to ignore Visual Studio version checks: in case
+# you just want the tool binaries to run, rather than the libraries and headers
+# for compiling.
+#
+# Variables:
+# WINDOWSSDK_FOUND - if any version of the windows or platform SDK was found that is usable with the current version of visual studio
+# WINDOWSSDK_LATEST_DIR
+# WINDOWSSDK_LATEST_NAME
+# WINDOWSSDK_FOUND_PREFERENCE - if we found an entry indicating a "preferred" SDK listed for this visual studio version
+# WINDOWSSDK_PREFERRED_DIR
+# WINDOWSSDK_PREFERRED_NAME
+#
+# WINDOWSSDK_DIRS - contains no duplicates, ordered most recent first.
+# WINDOWSSDK_PREFERRED_FIRST_DIRS - contains no duplicates, ordered with preferred first, followed by the rest in descending recency
+#
+# Functions:
+# GetUMWindowsSDKLibraryDir(<output variable>) - Find the latest SDK user mode (um) library directory,
+# architecture dependent
+# GetUMWindowsSDKIncludeDir(<output variable>) - Find the latest SDK user mode (um) include directory
+#
+# windowssdk_name_lookup(<directory> <output variable>) - Find the name corresponding with the SDK directory you pass in, or
+# NOTFOUND if not recognized. Your directory must be one of WINDOWSSDK_DIRS for this to work.
+#
+# windowssdk_build_lookup(<directory> <output variable>) - Find the build version number corresponding with the SDK directory you pass in, or
+# NOTFOUND if not recognized. Your directory must be one of WINDOWSSDK_DIRS for this to work.
+#
+# get_windowssdk_from_component(<file or dir> <output variable>) - Given a library or include dir,
+# find the Windows SDK root dir corresponding to it, or NOTFOUND if unrecognized.
+#
+# get_windowssdk_library_dirs(<directory> <output variable>) - Find the architecture-appropriate
+# library directories corresponding to the SDK directory you pass in (or NOTFOUND if none)
+#
+# get_windowssdk_library_dirs_multiple(<output variable> <directory> ...) - Find the architecture-appropriate
+# library directories corresponding to the SDK directories you pass in, in order, skipping those not found. NOTFOUND if none at all.
+# Good for passing WINDOWSSDK_DIRS or WINDOWSSDK_DIRS to if you really just want a file and don't care where from.
+#
+# get_windowssdk_include_dirs(<directory> <output variable>) - Find the
+# include directories corresponding to the SDK directory you pass in (or NOTFOUND if none)
+#
+# get_windowssdk_include_dirs_multiple(<output variable> <directory> ...) - Find the
+# include directories corresponding to the SDK directories you pass in, in order, skipping those not found. NOTFOUND if none at all.
+# Good for passing WINDOWSSDK_DIRS or WINDOWSSDK_DIRS to if you really just want a file and don't care where from.
+#
+# Requires these CMake modules:
+# FindPackageHandleStandardArgs (known included with CMake >=2.6.2)
+#
+# Original Author:
+# 2012 Ryan Pavlik <rpavlik@iastate.edu> <abiryan@ryand.net>
+# http://academic.cleardefinition.com
+# Iowa State University HCI Graduate Program/VRAC
+#
+# Copyright Iowa State University 2012.
+# Distributed under the Boost Software License, Version 1.0.
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
+
+set(_preferred_sdk_dirs) # pre-output
+set(_win_sdk_dirs) # pre-output
+set(_win_sdk_versanddirs) # pre-output
+set(_win_sdk_buildsanddirs) # pre-output
+set(_winsdk_vistaonly) # search parameters
+set(_winsdk_kits) # search parameters
+
+
+set(_WINDOWSSDK_ANNOUNCE OFF)
+if(NOT WINDOWSSDK_FOUND AND (NOT WindowsSDK_FIND_QUIETLY))
+ set(_WINDOWSSDK_ANNOUNCE ON)
+endif()
+macro(_winsdk_announce)
+ if(_WINSDK_ANNOUNCE)
+ message(STATUS ${ARGN})
+ endif()
+endmacro()
+
+
+set(_winsdk_win10vers
+ 10.0.18362.0 # Windows 10 SDK for 2019 Update
+ 10.0.17763.0 # Windows 10 SDK for October 2018 Update
+ 10.0.17133.0 # Redstone 4 aka Win10 1803 "April 1018 Update"
+ 10.0.16299.0 # Redstone 3 aka Win10 1709 "Fall Creators Update"
+ 10.0.15063.0 # Redstone 2 aka Win10 1703 "Creators Update"
+ 10.0.14393.0 # Redstone aka Win10 1607 "Anniversary Update"
+ 10.0.10586.0 # TH2 aka Win10 1511
+ 10.0.10240.0 # Win10 RTM
+ 10.0.10150.0 # just ucrt
+ 10.0.10056.0
+)
+
+if(WindowsSDK_FIND_COMPONENTS MATCHES "tools")
+ set(_WINDOWSSDK_IGNOREMSVC ON)
+ _winsdk_announce("Checking for tools from Windows/Platform SDKs...")
+else()
+ set(_WINDOWSSDK_IGNOREMSVC OFF)
+ _winsdk_announce("Checking for Windows/Platform SDKs...")
+endif()
+
+# Appends to the three main pre-output lists used only if the path exists
+# and is not already in the list.
+function(_winsdk_conditional_append _vername _build _path)
+ if(("${_path}" MATCHES "registry") OR (NOT EXISTS "${_path}"))
+ # Path invalid - do not add
+ return()
+ endif()
+ list(FIND _win_sdk_dirs "${_path}" _win_sdk_idx)
+ if(_win_sdk_idx GREATER -1)
+ # Path already in list - do not add
+ return()
+ endif()
+ _winsdk_announce( " - ${_vername}, Build ${_build} @ ${_path}")
+ # Not yet in the list, so we'll add it
+ list(APPEND _win_sdk_dirs "${_path}")
+ set(_win_sdk_dirs "${_win_sdk_dirs}" CACHE INTERNAL "" FORCE)
+ list(APPEND
+ _win_sdk_versanddirs
+ "${_vername}"
+ "${_path}")
+ set(_win_sdk_versanddirs "${_win_sdk_versanddirs}" CACHE INTERNAL "" FORCE)
+ list(APPEND
+ _win_sdk_buildsanddirs
+ "${_build}"
+ "${_path}")
+ set(_win_sdk_buildsanddirs "${_win_sdk_buildsanddirs}" CACHE INTERNAL "" FORCE)
+endfunction()
+
+# Appends to the "preferred SDK" lists only if the path exists
+function(_winsdk_conditional_append_preferred _info _path)
+ if(("${_path}" MATCHES "registry") OR (NOT EXISTS "${_path}"))
+ # Path invalid - do not add
+ return()
+ endif()
+
+ get_filename_component(_path "${_path}" ABSOLUTE)
+
+ list(FIND _win_sdk_preferred_sdk_dirs "${_path}" _win_sdk_idx)
+ if(_win_sdk_idx GREATER -1)
+ # Path already in list - do not add
+ return()
+ endif()
+ _winsdk_announce( " - Found \"preferred\" SDK ${_info} @ ${_path}")
+ # Not yet in the list, so we'll add it
+ list(APPEND _win_sdk_preferred_sdk_dirs "${_path}")
+ set(_win_sdk_preferred_sdk_dirs "${_win_sdk_dirs}" CACHE INTERNAL "" FORCE)
+
+ # Just in case we somehow missed it:
+ _winsdk_conditional_append("${_info}" "" "${_path}")
+endfunction()
+
+# Given a version like v7.0A, looks for an SDK in the registry under "Microsoft SDKs".
+# If the given version might be in both HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows
+# and HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots aka "Windows Kits",
+# use this macro first, since these registry keys usually have more information.
+#
+# Pass a "default" build number as an extra argument in case we can't find it.
+function(_winsdk_check_microsoft_sdks_registry _winsdkver)
+ set(SDKKEY "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\${_winsdkver}")
+ get_filename_component(_sdkdir
+ "[${SDKKEY};InstallationFolder]"
+ ABSOLUTE)
+
+ set(_sdkname "Windows SDK ${_winsdkver}")
+
+ # Default build number passed as extra argument
+ set(_build ${ARGN})
+ # See if the registry holds a Microsoft-mutilated, err, designated, product name
+ # (just using get_filename_component to execute the registry lookup)
+ get_filename_component(_sdkproductname
+ "[${SDKKEY};ProductName]"
+ NAME)
+ if(NOT "${_sdkproductname}" MATCHES "registry")
+ # Got a product name
+ set(_sdkname "${_sdkname} (${_sdkproductname})")
+ endif()
+
+ # try for a version to augment our name
+ # (just using get_filename_component to execute the registry lookup)
+ get_filename_component(_sdkver
+ "[${SDKKEY};ProductVersion]"
+ NAME)
+ if(NOT "${_sdkver}" MATCHES "registry" AND NOT MATCHES)
+ # Got a version
+ if(NOT "${_sdkver}" MATCHES "\\.\\.")
+ # and it's not an invalid one with two dots in it:
+ # use to override the default build
+ set(_build ${_sdkver})
+ if(NOT "${_sdkname}" MATCHES "${_sdkver}")
+ # Got a version that's not already in the name, let's use it to improve our name.
+ set(_sdkname "${_sdkname} (${_sdkver})")
+ endif()
+ endif()
+ endif()
+ _winsdk_conditional_append("${_sdkname}" "${_build}" "${_sdkdir}")
+endfunction()
+
+# Given a name for identification purposes, the build number, and a key (technically a "value name")
+# corresponding to a Windows SDK packaged as a "Windows Kit", look for it
+# in HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots
+# Note that the key or "value name" tends to be something weird like KitsRoot81 -
+# no easy way to predict, just have to observe them in the wild.
+# Doesn't hurt to also try _winsdk_check_microsoft_sdks_registry for these:
+# sometimes you get keys in both parts of the registry (in the wow64 portion especially),
+# and the non-"Windows Kits" location is often more descriptive.
+function(_winsdk_check_windows_kits_registry _winkit_name _winkit_build _winkit_key)
+ get_filename_component(_sdkdir
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots;${_winkit_key}]"
+ ABSOLUTE)
+ _winsdk_conditional_append("${_winkit_name}" "${_winkit_build}" "${_sdkdir}")
+endfunction()
+
+# Given a name for identification purposes and the build number
+# corresponding to a Windows 10 SDK packaged as a "Windows Kit", look for it
+# in HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots
+# Doesn't hurt to also try _winsdk_check_microsoft_sdks_registry for these:
+# sometimes you get keys in both parts of the registry (in the wow64 portion especially),
+# and the non-"Windows Kits" location is often more descriptive.
+function(_winsdk_check_win10_kits _winkit_build)
+ get_filename_component(_sdkdir
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots;KitsRoot10]"
+ ABSOLUTE)
+ if(("${_sdkdir}" MATCHES "registry") OR (NOT EXISTS "${_sdkdir}"))
+ return() # not found
+ endif()
+ if(EXISTS "${_sdkdir}/Include/${_winkit_build}/um")
+ _winsdk_conditional_append("Windows Kits 10 (Build ${_winkit_build})" "${_winkit_build}" "${_sdkdir}")
+ endif()
+endfunction()
+
+# Given a name for identification purposes, the build number, and the associated package GUID,
+# look in the registry under both HKLM and HKCU in \\SOFTWARE\\Microsoft\\MicrosoftSDK\\InstalledSDKs\\
+# for that guid and the SDK it points to.
+function(_winsdk_check_platformsdk_registry _platformsdkname _build _platformsdkguid)
+ foreach(_winsdk_hive HKEY_LOCAL_MACHINE HKEY_CURRENT_USER)
+ get_filename_component(_sdkdir
+ "[${_winsdk_hive}\\SOFTWARE\\Microsoft\\MicrosoftSDK\\InstalledSDKs\\${_platformsdkguid};Install Dir]"
+ ABSOLUTE)
+ _winsdk_conditional_append("${_platformsdkname} (${_build})" "${_build}" "${_sdkdir}")
+ endforeach()
+endfunction()
+
+###
+# Detect toolchain information: to know whether it's OK to use Vista+ only SDKs
+###
+set(_winsdk_vistaonly_ok OFF)
+if(MSVC AND NOT _WINDOWSSDK_IGNOREMSVC)
+ # VC 10 and older has broad target support
+ if(MSVC_VERSION LESS 1700)
+ # VC 11 by default targets Vista and later only, so we can add a few more SDKs that (might?) only work on vista+
+ elseif("${CMAKE_VS_PLATFORM_TOOLSET}" MATCHES "_xp")
+ # This is the XP-compatible v110+ toolset
+ elseif("${CMAKE_VS_PLATFORM_TOOLSET}" STREQUAL "v100" OR "${CMAKE_VS_PLATFORM_TOOLSET}" STREQUAL "v90")
+ # This is the VS2010/VS2008 toolset
+ else()
+ # OK, we're VC11 or newer and not using a backlevel or XP-compatible toolset.
+ # These versions have no XP (and possibly Vista pre-SP1) support
+ set(_winsdk_vistaonly_ok ON)
+ if(_WINDOWSSDK_ANNOUNCE AND NOT _WINDOWSSDK_VISTAONLY_PESTERED)
+ set(_WINDOWSSDK_VISTAONLY_PESTERED ON CACHE INTERNAL "" FORCE)
+ message(STATUS "FindWindowsSDK: Detected Visual Studio 2012 or newer, not using the _xp toolset variant: including SDK versions that drop XP support in search!")
+ endif()
+ endif()
+endif()
+if(_WINDOWSSDK_IGNOREMSVC)
+ set(_winsdk_vistaonly_ok ON)
+endif()
+
+###
+# MSVC version checks - keeps messy conditionals in one place
+# (messy because of _WINDOWSSDK_IGNOREMSVC)
+###
+set(_winsdk_msvc_greater_1200 OFF)
+if(_WINDOWSSDK_IGNOREMSVC OR (MSVC AND (MSVC_VERSION GREATER 1200)))
+ set(_winsdk_msvc_greater_1200 ON)
+endif()
+# Newer than VS .NET/VS Toolkit 2003
+set(_winsdk_msvc_greater_1310 OFF)
+if(_WINDOWSSDK_IGNOREMSVC OR (MSVC AND (MSVC_VERSION GREATER 1310)))
+ set(_winsdk_msvc_greater_1310 ON)
+endif()
+
+# VS2005/2008
+set(_winsdk_msvc_less_1600 OFF)
+if(_WINDOWSSDK_IGNOREMSVC OR (MSVC AND (MSVC_VERSION LESS 1600)))
+ set(_winsdk_msvc_less_1600 ON)
+endif()
+
+# VS2013+
+set(_winsdk_msvc_not_less_1800 OFF)
+if(_WINDOWSSDK_IGNOREMSVC OR (MSVC AND (NOT MSVC_VERSION LESS 1800)))
+ set(_winsdk_msvc_not_less_1800 ON)
+endif()
+
+###
+# START body of find module
+###
+if(_winsdk_msvc_greater_1310) # Newer than VS .NET/VS Toolkit 2003
+ ###
+ # Look for "preferred" SDKs
+ ###
+
+ # Environment variable for SDK dir
+ if(EXISTS "$ENV{WindowsSDKDir}" AND (NOT "$ENV{WindowsSDKDir}" STREQUAL ""))
+ _winsdk_conditional_append_preferred("WindowsSDKDir environment variable" "$ENV{WindowsSDKDir}")
+ endif()
+
+ if(_winsdk_msvc_less_1600)
+ # Per-user current Windows SDK for VS2005/2008
+ get_filename_component(_sdkdir
+ "[HKEY_CURRENT_USER\\Software\\Microsoft\\Microsoft SDKs\\Windows;CurrentInstallFolder]"
+ ABSOLUTE)
+ _winsdk_conditional_append_preferred("Per-user current Windows SDK" "${_sdkdir}")
+
+ # System-wide current Windows SDK for VS2005/2008
+ get_filename_component(_sdkdir
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows;CurrentInstallFolder]"
+ ABSOLUTE)
+ _winsdk_conditional_append_preferred("System-wide current Windows SDK" "${_sdkdir}")
+ endif()
+
+ ###
+ # Begin the massive list of SDK searching!
+ ###
+ if(_winsdk_vistaonly_ok AND _winsdk_msvc_not_less_1800)
+ # These require at least Visual Studio 2013 (VC12)
+
+ _winsdk_check_microsoft_sdks_registry(v10.0A)
+
+ # Windows Software Development Kit (SDK) for Windows 10
+ # Several different versions living in the same directory - if nothing else we can assume RTM (10240)
+ _winsdk_check_microsoft_sdks_registry(v10.0 10.0.10240.0)
+ foreach(_win10build ${_winsdk_win10vers})
+ _winsdk_check_win10_kits(${_win10build})
+ endforeach()
+ endif() # vista-only and 2013+
+
+ # Included in Visual Studio 2013
+ # Includes the v120_xp toolset
+ _winsdk_check_microsoft_sdks_registry(v8.1A 8.1.51636)
+
+ if(_winsdk_vistaonly_ok AND _winsdk_msvc_not_less_1800)
+ # Windows Software Development Kit (SDK) for Windows 8.1
+ # http://msdn.microsoft.com/en-gb/windows/desktop/bg162891
+ _winsdk_check_microsoft_sdks_registry(v8.1 8.1.25984.0)
+ _winsdk_check_windows_kits_registry("Windows Kits 8.1" 8.1.25984.0 KitsRoot81)
+ endif() # vista-only and 2013+
+
+ if(_winsdk_vistaonly_ok)
+ # Included in Visual Studio 2012
+ _winsdk_check_microsoft_sdks_registry(v8.0A 8.0.50727)
+
+ # Microsoft Windows SDK for Windows 8 and .NET Framework 4.5
+ # This is the first version to also include the DirectX SDK
+ # http://msdn.microsoft.com/en-US/windows/desktop/hh852363.aspx
+ _winsdk_check_microsoft_sdks_registry(v8.0 6.2.9200.16384)
+ _winsdk_check_windows_kits_registry("Windows Kits 8.0" 6.2.9200.16384 KitsRoot)
+ endif() # vista-only
+
+ # Included with VS 2012 Update 1 or later
+ # Introduces v110_xp toolset
+ _winsdk_check_microsoft_sdks_registry(v7.1A 7.1.51106)
+ if(_winsdk_vistaonly_ok)
+ # Microsoft Windows SDK for Windows 7 and .NET Framework 4
+ # http://www.microsoft.com/downloads/en/details.aspx?FamilyID=6b6c21d2-2006-4afa-9702-529fa782d63b
+ _winsdk_check_microsoft_sdks_registry(v7.1 7.1.7600.0.30514)
+ endif() # vista-only
+
+ # Included with VS 2010
+ _winsdk_check_microsoft_sdks_registry(v7.0A 6.1.7600.16385)
+
+ # Windows SDK for Windows 7 and .NET Framework 3.5 SP1
+ # Works with VC9
+ # http://www.microsoft.com/en-us/download/details.aspx?id=18950
+ _winsdk_check_microsoft_sdks_registry(v7.0 6.1.7600.16385)
+
+ # Two versions call themselves "v6.1":
+ # Older:
+ # Windows Vista Update & .NET 3.0 SDK
+ # http://www.microsoft.com/en-us/download/details.aspx?id=14477
+
+ # Newer:
+ # Windows Server 2008 & .NET 3.5 SDK
+ # may have broken VS9SP1? they recommend v7.0 instead, or a KB...
+ # http://www.microsoft.com/en-us/download/details.aspx?id=24826
+ _winsdk_check_microsoft_sdks_registry(v6.1 6.1.6000.16384.10)
+
+ # Included in VS 2008
+ _winsdk_check_microsoft_sdks_registry(v6.0A 6.1.6723.1)
+
+ # Microsoft Windows Software Development Kit for Windows Vista and .NET Framework 3.0 Runtime Components
+ # http://blogs.msdn.com/b/stanley/archive/2006/11/08/microsoft-windows-software-development-kit-for-windows-vista-and-net-framework-3-0-runtime-components.aspx
+ _winsdk_check_microsoft_sdks_registry(v6.0 6.0.6000.16384)
+endif()
+
+# Let's not forget the Platform SDKs, which sometimes are useful!
+if(_winsdk_msvc_greater_1200)
+ _winsdk_check_platformsdk_registry("Microsoft Platform SDK for Windows Server 2003 R2" "5.2.3790.2075.51" "D2FF9F89-8AA2-4373-8A31-C838BF4DBBE1")
+ _winsdk_check_platformsdk_registry("Microsoft Platform SDK for Windows Server 2003 SP1" "5.2.3790.1830.15" "8F9E5EF3-A9A5-491B-A889-C58EFFECE8B3")
+endif()
+###
+# Finally, look for "preferred" SDKs
+###
+if(_winsdk_msvc_greater_1310) # Newer than VS .NET/VS Toolkit 2003
+
+
+ # Environment variable for SDK dir
+ if(EXISTS "$ENV{WindowsSDKDir}" AND (NOT "$ENV{WindowsSDKDir}" STREQUAL ""))
+ _winsdk_conditional_append_preferred("WindowsSDKDir environment variable" "$ENV{WindowsSDKDir}")
+ endif()
+
+ if(_winsdk_msvc_less_1600)
+ # Per-user current Windows SDK for VS2005/2008
+ get_filename_component(_sdkdir
+ "[HKEY_CURRENT_USER\\Software\\Microsoft\\Microsoft SDKs\\Windows;CurrentInstallFolder]"
+ ABSOLUTE)
+ _winsdk_conditional_append_preferred("Per-user current Windows SDK" "${_sdkdir}")
+
+ # System-wide current Windows SDK for VS2005/2008
+ get_filename_component(_sdkdir
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows;CurrentInstallFolder]"
+ ABSOLUTE)
+ _winsdk_conditional_append_preferred("System-wide current Windows SDK" "${_sdkdir}")
+ endif()
+endif()
+
+
+function(windowssdk_name_lookup _dir _outvar)
+ list(FIND _win_sdk_versanddirs "${_dir}" _diridx)
+ math(EXPR _idx "${_diridx} - 1")
+ if(${_idx} GREATER -1)
+ list(GET _win_sdk_versanddirs ${_idx} _ret)
+ else()
+ set(_ret "NOTFOUND")
+ endif()
+ set(${_outvar} "${_ret}" PARENT_SCOPE)
+endfunction()
+
+function(windowssdk_build_lookup _dir _outvar)
+ list(FIND _win_sdk_buildsanddirs "${_dir}" _diridx)
+ math(EXPR _idx "${_diridx} - 1")
+ if(${_idx} GREATER -1)
+ list(GET _win_sdk_buildsanddirs ${_idx} _ret)
+ else()
+ set(_ret "NOTFOUND")
+ endif()
+ set(${_outvar} "${_ret}" PARENT_SCOPE)
+endfunction()
+
+# If we found something...
+if(_win_sdk_dirs)
+ list(GET _win_sdk_dirs 0 WINDOWSSDK_LATEST_DIR)
+ windowssdk_name_lookup("${WINDOWSSDK_LATEST_DIR}"
+ WINDOWSSDK_LATEST_NAME)
+ set(WINDOWSSDK_DIRS ${_win_sdk_dirs})
+
+ # Fallback, in case no preference found.
+ set(WINDOWSSDK_PREFERRED_DIR "${WINDOWSSDK_LATEST_DIR}")
+ set(WINDOWSSDK_PREFERRED_NAME "${WINDOWSSDK_LATEST_NAME}")
+ set(WINDOWSSDK_PREFERRED_FIRST_DIRS ${WINDOWSSDK_DIRS})
+ set(WINDOWSSDK_FOUND_PREFERENCE OFF)
+endif()
+
+# If we found indications of a user preference...
+if(_win_sdk_preferred_sdk_dirs)
+ list(GET _win_sdk_preferred_sdk_dirs 0 WINDOWSSDK_PREFERRED_DIR)
+ windowssdk_name_lookup("${WINDOWSSDK_PREFERRED_DIR}"
+ WINDOWSSDK_PREFERRED_NAME)
+ set(WINDOWSSDK_PREFERRED_FIRST_DIRS
+ ${_win_sdk_preferred_sdk_dirs}
+ ${_win_sdk_dirs})
+ list(REMOVE_DUPLICATES WINDOWSSDK_PREFERRED_FIRST_DIRS)
+ set(WINDOWSSDK_FOUND_PREFERENCE ON)
+endif()
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(WindowsSDK
+ "No compatible version of the Windows SDK or Platform SDK found."
+ WINDOWSSDK_DIRS)
+
+if(WINDOWSSDK_FOUND)
+ # Internal: Architecture-appropriate library directory names.
+ if("${CMAKE_VS_PLATFORM_NAME}" STREQUAL "ARM")
+ if(CMAKE_SIZEOF_VOID_P MATCHES "8")
+ # Only supported in Win10 SDK and up.
+ set(_winsdk_arch8 arm64) # what the WDK for Win8+ calls this architecture
+ else()
+ set(_winsdk_archbare /arm) # what the architecture used to be called in oldest SDKs
+ set(_winsdk_arch arm) # what the architecture used to be called
+ set(_winsdk_arch8 arm) # what the WDK for Win8+ calls this architecture
+ endif()
+ else()
+ if(CMAKE_SIZEOF_VOID_P MATCHES "8")
+ set(_winsdk_archbare /x64) # what the architecture used to be called in oldest SDKs
+ set(_winsdk_arch amd64) # what the architecture used to be called
+ set(_winsdk_arch8 x64) # what the WDK for Win8+ calls this architecture
+ else()
+ set(_winsdk_archbare ) # what the architecture used to be called in oldest SDKs
+ set(_winsdk_arch i386) # what the architecture used to be called
+ set(_winsdk_arch8 x86) # what the WDK for Win8+ calls this architecture
+ endif()
+ endif()
+
+ function(get_windowssdk_from_component _component _var)
+ get_filename_component(_component "${_component}" ABSOLUTE)
+ file(TO_CMAKE_PATH "${_component}" _component)
+ foreach(_sdkdir ${WINDOWSSDK_DIRS})
+ get_filename_component(_sdkdir "${_sdkdir}" ABSOLUTE)
+ string(LENGTH "${_sdkdir}" _sdklen)
+ file(RELATIVE_PATH _rel "${_sdkdir}" "${_component}")
+ # If we don't have any "parent directory" items...
+ if(NOT "${_rel}" MATCHES "[.][.]")
+ set(${_var} "${_sdkdir}" PARENT_SCOPE)
+ return()
+ endif()
+ endforeach()
+ # Fail.
+ set(${_var} "NOTFOUND" PARENT_SCOPE)
+ endfunction()
+ function(get_windowssdk_library_dirs _winsdk_dir _var)
+ set(_dirs)
+ set(_suffixes
+ "lib${_winsdk_archbare}" # SDKs like 7.1A
+ "lib/${_winsdk_arch}" # just because some SDKs have x86 dir and root dir
+ "lib/w2k/${_winsdk_arch}" # Win2k min requirement
+ "lib/wxp/${_winsdk_arch}" # WinXP min requirement
+ "lib/wnet/${_winsdk_arch}" # Win Server 2003 min requirement
+ "lib/wlh/${_winsdk_arch}"
+ "lib/wlh/um/${_winsdk_arch8}" # Win Vista ("Long Horn") min requirement
+ "lib/win7/${_winsdk_arch}"
+ "lib/win7/um/${_winsdk_arch8}" # Win 7 min requirement
+ )
+ foreach(_ver
+ wlh # Win Vista ("Long Horn") min requirement
+ win7 # Win 7 min requirement
+ win8 # Win 8 min requirement
+ winv6.3 # Win 8.1 min requirement
+ )
+
+ list(APPEND _suffixes
+ "lib/${_ver}/${_winsdk_arch}"
+ "lib/${_ver}/um/${_winsdk_arch8}"
+ "lib/${_ver}/km/${_winsdk_arch8}"
+ )
+ endforeach()
+
+ # Look for WDF libraries in Win10+ SDK
+ foreach(_mode umdf kmdf)
+ file(GLOB _wdfdirs RELATIVE "${_winsdk_dir}" "${_winsdk_dir}/lib/wdf/${_mode}/${_winsdk_arch8}/*")
+ if(_wdfdirs)
+ list(APPEND _suffixes ${_wdfdirs})
+ endif()
+ endforeach()
+
+ # Look in each Win10+ SDK version for the components
+ foreach(_win10ver ${_winsdk_win10vers})
+ foreach(_component um km ucrt mmos)
+ list(APPEND _suffixes "lib/${_win10ver}/${_component}/${_winsdk_arch8}")
+ endforeach()
+ endforeach()
+
+ foreach(_suffix ${_suffixes})
+ # Check to see if a library actually exists here.
+ file(GLOB _libs "${_winsdk_dir}/${_suffix}/*.lib")
+ if(_libs)
+ list(APPEND _dirs "${_winsdk_dir}/${_suffix}")
+ endif()
+ endforeach()
+ if("${_dirs}" STREQUAL "")
+ set(_dirs NOTFOUND)
+ else()
+ list(REMOVE_DUPLICATES _dirs)
+ endif()
+ set(${_var} ${_dirs} PARENT_SCOPE)
+ endfunction()
+ function(get_windowssdk_include_dirs _winsdk_dir _var)
+ set(_dirs)
+
+ set(_subdirs shared um winrt km wdf mmos ucrt)
+ set(_suffixes Include)
+
+ foreach(_dir ${_subdirs})
+ list(APPEND _suffixes "Include/${_dir}")
+ endforeach()
+
+ foreach(_ver ${_winsdk_win10vers})
+ foreach(_dir ${_subdirs})
+ list(APPEND _suffixes "Include/${_ver}/${_dir}")
+ endforeach()
+ endforeach()
+
+ foreach(_suffix ${_suffixes})
+ # Check to see if a header file actually exists here.
+ file(GLOB _headers "${_winsdk_dir}/${_suffix}/*.h")
+ if(_headers)
+ list(APPEND _dirs "${_winsdk_dir}/${_suffix}")
+ endif()
+ endforeach()
+ if("${_dirs}" STREQUAL "")
+ set(_dirs NOTFOUND)
+ else()
+ list(REMOVE_DUPLICATES _dirs)
+ endif()
+ set(${_var} ${_dirs} PARENT_SCOPE)
+ endfunction()
+
+
+
+ function(get_windowssdk_library_dirs_multiple _var)
+ set(_dirs)
+ foreach(_sdkdir ${ARGN})
+ get_windowssdk_library_dirs("${_sdkdir}" _current_sdk_libdirs)
+ if(_current_sdk_libdirs)
+ list(APPEND _dirs ${_current_sdk_libdirs})
+ endif()
+ endforeach()
+ if("${_dirs}" STREQUAL "")
+ set(_dirs NOTFOUND)
+ else()
+ list(REMOVE_DUPLICATES _dirs)
+ endif()
+ set(${_var} ${_dirs} PARENT_SCOPE)
+ endfunction()
+ function(get_windowssdk_include_dirs_multiple _var)
+ set(_dirs)
+ foreach(_sdkdir ${ARGN})
+ get_windowssdk_include_dirs("${_sdkdir}" _current_sdk_incdirs)
+ if(_current_sdk_libdirs)
+ list(APPEND _dirs ${_current_sdk_incdirs})
+ endif()
+ endforeach()
+ if("${_dirs}" STREQUAL "")
+ set(_dirs NOTFOUND)
+ else()
+ list(REMOVE_DUPLICATES _dirs)
+ endif()
+ set(${_var} ${_dirs} PARENT_SCOPE)
+ endfunction()
+endif()
+
+
+function(FindFirstStringMatching list reg matching)
+ foreach(l ${${list}})
+ if(${l} MATCHES ${reg})
+ set(${matching} ${l} PARENT_SCOPE)
+ break()
+ endif()
+ endforeach()
+endfunction()
+
+function(GetUMWindowsSDKLibraryDir library_dir)
+ get_windowssdk_library_dirs(${WINDOWSSDK_LATEST_DIR} WIN_LIBRARY_DIRS)
+ FindFirstStringMatching(WIN_LIBRARY_DIRS "[\\/]um[\\/]" WINDOWSKIT_LIBRARY_DIR)
+ set(${library_dir} ${WINDOWSKIT_LIBRARY_DIR} PARENT_SCOPE)
+endfunction()
+
+function(GetUMWindowsSDKIncludeDir include_dir)
+ get_windowssdk_include_dirs(${WINDOWSSDK_LATEST_DIR} WIN_INCLUDE_DIRS)
+ FindFirstStringMatching(WIN_INCLUDE_DIRS "[\\/]um[\\/]" WIN_INCLUDE_DIR)
+ set(${include_dir} ${WIN_INCLUDE_DIR} PARENT_SCOPE)
+endfunction()
diff --git a/cmake/Modules/findopensslfeatures.c b/cmake/Modules/findopensslfeatures.c
new file mode 100644
index 0000000..390f1d2
--- /dev/null
+++ b/cmake/Modules/findopensslfeatures.c
@@ -0,0 +1,101 @@
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <openssl/ec.h>
+#include <openssl/objects.h>
+#include <openssl/evp.h>
+
+int
+list_curves()
+{
+ size_t len = EC_get_builtin_curves(NULL, 0);
+ EC_builtin_curve *curves = OPENSSL_malloc(sizeof(EC_builtin_curve) * len);
+ if (!curves) {
+ fprintf(stderr, "Allocation failed.\n");
+ return 1;
+ }
+ if (!EC_get_builtin_curves(curves, len)) {
+ OPENSSL_free(curves);
+ fprintf(stderr, "Failed to get curves.\n");
+ return 1;
+ }
+ for (size_t i = 0; i < len; i++) {
+ const char *sname = OBJ_nid2sn(curves[i].nid);
+ if (!sname) {
+ continue;
+ }
+ printf("%s\n", sname);
+ }
+ OPENSSL_free(curves);
+ return 0;
+}
+
+static void
+print_hash(const EVP_MD *md, const char *from, const char *to, void *arg)
+{
+ if (!md) {
+ return;
+ }
+ if (strstr(from, "rsa") || strstr(from, "RSA")) {
+ return;
+ }
+ printf("%s\n", from);
+}
+
+int
+list_hashes()
+{
+ EVP_MD_do_all_sorted(print_hash, NULL);
+ return 0;
+}
+
+static void
+print_cipher(const EVP_CIPHER *cipher, const char *from, const char *to, void *x)
+{
+ if (!cipher) {
+ return;
+ }
+ printf("%s\n", from);
+}
+
+int
+list_ciphers()
+{
+ EVP_CIPHER_do_all_sorted(print_cipher, NULL);
+ return 0;
+}
+
+int
+list_publickey()
+{
+ for (size_t i = 0; i < EVP_PKEY_meth_get_count(); i++) {
+ const EVP_PKEY_METHOD *pmeth = EVP_PKEY_meth_get0(i);
+ int id = 0;
+ EVP_PKEY_meth_get0_info(&id, NULL, pmeth);
+ printf("%s\n", OBJ_nid2ln(id));
+ }
+ return 0;
+}
+
+int
+main(int argc, char *argv[])
+{
+ if (argc != 2) {
+ fprintf(stderr, "Usage: opensslfeatures [curves|hashes|ciphers|publickey]\n");
+ return 1;
+ }
+ if (!strcmp(argv[1], "hashes")) {
+ return list_hashes();
+ }
+ if (!strcmp(argv[1], "ciphers")) {
+ return list_ciphers();
+ }
+ if (!strcmp(argv[1], "curves")) {
+ return list_curves();
+ }
+ if (!strcmp(argv[1], "publickey")) {
+ return list_publickey();
+ }
+ fprintf(stderr, "Unknown command: %s\n", argv[1]);
+ return 1;
+}
diff --git a/cmake/info.cmake b/cmake/info.cmake
new file mode 100644
index 0000000..21ea680
--- /dev/null
+++ b/cmake/info.cmake
@@ -0,0 +1,41 @@
+# Copyright (c) 2018 Ribose Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+# this file contains things that are likely to change occasionally
+set(PACKAGE_VENDOR "Ribose Inc.")
+set(PACKAGE_URL "https://github.com/rnpgp/rnp")
+
+set(PACKAGING_EMAIL "Ribose Inc. <rnpgp@ribose.com>")
+set(BUGREPORT_EMAIL "${PACKAGING_EMAIL}")
+
+set(PACKAGE_DESCRIPTION [=[
+A set of OpenPGP tools for encrypting, decrypting, signing, and \
+verifying files.
+]=]
+)
+set(PACKAGE_DESCRIPTION_SHORT "Freely-licensed OpenPGP library and command-line tools")
+set(PACKAGE_LICENSE "BSD")
+
+set(RPM_RELEASE_NUM 1)
+set(DEB_RELEASE_NUM 1)
diff --git a/cmake/librnp.pc.in b/cmake/librnp.pc.in
new file mode 100644
index 0000000..2eb84bf
--- /dev/null
+++ b/cmake/librnp.pc.in
@@ -0,0 +1,13 @@
+prefix=@CMAKE_INSTALL_PREFIX@
+exec_prefix=${prefix}
+libdir=@PKGCONFIG_LIBDIR@
+includedir=@PKGCONFIG_INCLUDEDIR@
+
+Name: rnp
+Description: @PACKAGE_DESCRIPTION_SHORT@
+Version: @PROJECT_VERSION@
+
+Libs: -L${libdir} -l@LIBRNP_OUTPUT_NAME@
+Libs.private: @LIBRNP_PRIVATE_LIBS@
+Cflags: -I${includedir}
+
diff --git a/cmake/packaging.cmake b/cmake/packaging.cmake
new file mode 100644
index 0000000..2180845
--- /dev/null
+++ b/cmake/packaging.cmake
@@ -0,0 +1,79 @@
+# Copyright (c) 2018, 2023 Ribose Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+# this file contains packaging items that aren't likely to change much
+
+# general
+set(CPACK_PACKAGE_VENDOR "${PACKAGE_VENDOR}")
+set(CPACK_PACKAGE_CONTACT "${PACKAGING_EMAIL}")
+set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "${PACKAGE_DESCRIPTION_SHORT}")
+set(CPACK_PACKAGE_VERSION "${PROJECT_VERSION}")
+set(CPACK_PACKAGE_FILE_NAME "rnp-${CPACK_PACKAGE_VERSION}")
+set(CPACK_PACKAGE_NAME "rnp${PROJECT_VERSION_MAJOR}")
+
+set(CPACK_SOURCE_IGNORE_FILES "/installs/;/build/;/\\\\.git/;\\\\.#;/#")
+
+# deb-specific
+set(CPACK_DEBIAN_PACKAGE_HOMEPAGE "${PACKAGE_URL}")
+set(CPACK_DEBIAN_PACKAGE_RELEASE "${DEB_RELEASE_NUM}")
+set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
+
+# rpm-specific
+set(CPACK_RPM_PACKAGE_LICENSE "${PACKAGE_LICENSE}")
+set(CPACK_RPM_PACKAGE_URL "${PACKAGE_URL}")
+set(CPACK_RPM_PACKAGE_RELEASE "${RPM_RELEASE_NUM}${RNP_VERSION_SUFFIX}")
+set(CPACK_RPM_PACKAGE_RELEASE_DIST ON)
+set(CPACK_RPM_PACKAGE_GROUP "Applications/System")
+set(CPACK_RPM_PACKAGE_DESCRIPTION "${PACKAGE_DESCRIPTION}")
+set(CPACK_RPM_PACKAGE_AUTOREQPROV ON)
+file(WRITE "${PROJECT_BINARY_DIR}/rpm-ldconfig" "/sbin/ldconfig")
+set(CPACK_RPM_POST_INSTALL_SCRIPT_FILE "${PROJECT_BINARY_DIR}/rpm-ldconfig")
+set(CPACK_RPM_POST_UNINSTALL_SCRIPT_FILE "${PROJECT_BINARY_DIR}/rpm-ldconfig")
+# rnp - obsolete the original package name, now preferring to append the major ver
+# rnp0 < [...] - obsolete the monolithic RPM generated by previous versions
+set(CPACK_RPM_PACKAGE_OBSOLETES "rnp, rnp0 < %{version}-%{release}")
+# rpm component packages
+set(CPACK_RPM_COMPONENT_INSTALL ON)
+set(CPACK_RPM_MAIN_COMPONENT "cli")
+# runtime library
+set(CPACK_RPM_RUNTIME_PACKAGE_NAME "librnp${PROJECT_VERSION_MAJOR}")
+set(CPACK_RPM_RUNTIME_FILE_NAME "${CPACK_RPM_RUNTIME_PACKAGE_NAME}-%{version}-%{release}.rpm")
+set(CPACK_RPM_RUNTIME_PACKAGE_SUMMARY "${CPACK_PACKAGE_DESCRIPTION_SUMMARY} (runtime)")
+# development files
+set(CPACK_RPM_DEVELOPMENT_PACKAGE_NAME "${CPACK_RPM_RUNTIME_PACKAGE_NAME}-devel")
+set(CPACK_RPM_DEVELOPMENT_FILE_NAME "${CPACK_RPM_DEVELOPMENT_PACKAGE_NAME}-%{version}-%{release}.rpm")
+set(CPACK_RPM_DEVELOPMENT_PACKAGE_SUMMARY "${CPACK_PACKAGE_DESCRIPTION_SUMMARY} (development files)")
+set(CPACK_RPM_DEVELOPMENT_PACKAGE_DESCRIPTION "Development files for the rnp library")
+set(CPACK_RPM_DEVELOPMENT_PACKAGE_REQUIRES "${CPACK_RPM_RUNTIME_PACKAGE_NAME}")
+# cli utils
+set(CPACK_RPM_CLI_FILE_NAME RPM-DEFAULT)
+set(CPACK_RPM_CLI_PACKAGE_SUMMARY "${CPACK_PACKAGE_DESCRIPTION_SUMMARY} (command-line utilities)")
+
+# bsd-specific
+set(CPACK_FREEBSD_PACKAGE_MAINTAINER "${PACKAGING_EMAIL}")
+set(CPACK_FREEBSD_PACKAGE_ORIGIN "security/rnp")
+set(CPACK_FREEBSD_PACKAGE_CATEGORIES security)
+set(CPACK_FREEBSD_PACKAGE_DEPS bzip2 json-c botan2)
+
+include(CPack)
diff --git a/cmake/rnp-config.cmake.in b/cmake/rnp-config.cmake.in
new file mode 100644
index 0000000..04f4f26
--- /dev/null
+++ b/cmake/rnp-config.cmake.in
@@ -0,0 +1,31 @@
+# Copyright (c) 2018 Ribose Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+@PACKAGE_INIT@
+
+include(CMakeFindDependencyMacro)
+
+if(NOT TARGET rnp::librnp)
+ include("${CMAKE_CURRENT_LIST_DIR}/rnp-targets.cmake")
+endif()
diff --git a/cmake/rnp_tests_discover.cmake b/cmake/rnp_tests_discover.cmake
new file mode 100644
index 0000000..9f05293
--- /dev/null
+++ b/cmake/rnp_tests_discover.cmake
@@ -0,0 +1,40 @@
+set(script)
+
+function(add_command NAME)
+ set(_args "")
+ foreach(_arg ${ARGN})
+ set(_args "${_args} [==[${_arg}]==]")
+ endforeach()
+ set(script "${script}${NAME}(${_args})\n" PARENT_SCOPE)
+endfunction()
+
+if(NOT EXISTS "${TEST_EXECUTABLE}")
+ message(FATAL_ERROR "Executable does not exist: ${TEST_EXECUTABE}")
+endif()
+execute_process(
+ COMMAND "${TEST_EXECUTABLE}" list-tests
+ WORKING_DIRECTORY "${TEST_WORKING_DIR}"
+ OUTPUT_VARIABLE output
+ RESULT_VARIABLE result
+)
+if(NOT ${result} EQUAL 0)
+ message(FATAL_ERROR "Error running executable: ${TEST_EXECUTABE}")
+endif()
+
+string(REPLACE "\n" ";" output "${output}")
+
+foreach(line ${output})
+ set(test "${line}")
+ add_command(add_test
+ "rnp_tests-${test}"
+ "${TEST_EXECUTABLE}"
+ "${test}"
+ )
+ add_command(set_tests_properties
+ "rnp_tests-${test}"
+ PROPERTIES ${TEST_PROPERTIES}
+ )
+endforeach()
+
+file(WRITE "${CTEST_FILE}" "${script}")
+
diff --git a/cmake/version.cmake b/cmake/version.cmake
new file mode 100644
index 0000000..f74126e
--- /dev/null
+++ b/cmake/version.cmake
@@ -0,0 +1,163 @@
+# Copyright (c) 2018-2021 Ribose Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+# desired length of commit hash
+set(GIT_REV_LEN 7)
+
+# call git, store output in var (can fail)
+macro(_git var)
+ execute_process(
+ COMMAND "${GIT_EXECUTABLE}" ${ARGN}
+ WORKING_DIRECTORY "${source_dir}"
+ RESULT_VARIABLE _git_ec
+ OUTPUT_VARIABLE ${var}
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ ERROR_QUIET
+ )
+endmacro()
+
+function(extract_version_info version var_prefix)
+ # extract the main components
+ # v1.9.0-3-g5b92266+1546836556
+ # v1.9.0-3-g5b92266-dirty+1546836556
+ string(REGEX MATCH "^v?([0-9]+\\.[0-9]+\\.[0-9]+)(-([0-9]+)-g([0-9a-f]+)(-dirty)?)?(\\+([0-9]+))?$" matches "${version}")
+ if (NOT matches)
+ message(FATAL_ERROR "Failed to extract version components from ${version}.")
+ endif()
+ set(${var_prefix}_VERSION "${CMAKE_MATCH_1}" PARENT_SCOPE) # 1.9.0
+ if (NOT CMAKE_MATCH_3)
+ set(CMAKE_MATCH_3 "0")
+ endif()
+ set(${var_prefix}_VERSION_NCOMMITS "${CMAKE_MATCH_3}" PARENT_SCOPE) # 3
+ if (NOT CMAKE_MATCH_4)
+ set(CMAKE_MATCH_4 "0")
+ endif()
+ set(${var_prefix}_VERSION_GIT_REV "${CMAKE_MATCH_4}" PARENT_SCOPE) # 5b92266
+ if (CMAKE_MATCH_5 STREQUAL "-dirty")
+ set(${var_prefix}_VERSION_IS_DIRTY TRUE PARENT_SCOPE)
+ else()
+ set(${var_prefix}_VERSION_IS_DIRTY FALSE PARENT_SCOPE)
+ endif()
+ # timestamp is optional, default to 0
+ if (NOT CMAKE_MATCH_7)
+ set(CMAKE_MATCH_7 "0")
+ endif()
+ set(${var_prefix}_VERSION_COMMIT_TIMESTAMP "${CMAKE_MATCH_7}" PARENT_SCOPE) # 1546836556
+endfunction()
+
+function(determine_version source_dir var_prefix)
+ set(has_release_tag NO)
+ set(has_version_txt NO)
+ set(local_prefix "_determine_ver")
+ # find out base version via version.txt
+ set(base_version "0.0.0")
+ if (EXISTS "${source_dir}/version.txt")
+ set(has_version_txt YES)
+ file(STRINGS "${source_dir}/version.txt" version_file)
+ extract_version_info("${version_file}" "${local_prefix}")
+ set(base_version "${${local_prefix}_VERSION}")
+ message(STATUS "Found version.txt with ${version_file}")
+ else()
+ message(STATUS "Found no version.txt.")
+ endif()
+ # for GIT_EXECUTABLE
+ find_package(Git)
+ # get a description of the version, something like:
+ # v1.9.1-0-g38ffe82 (a tagged release)
+ # v1.9.1-0-g38ffe82-dirty (a tagged release with local modifications)
+ # v1.9.0-3-g5b92266 (post-release snapshot)
+ # v1.9.0-3-g5b92266-dirty (post-release snapshot with local modifications)
+ _git(version describe --abbrev=${GIT_REV_LEN} --match "v[0-9]*" --long --dirty)
+ if (NOT _git_ec EQUAL 0)
+ # no annotated tags, fake one
+ message(STATUS "Found no annotated tags.")
+ _git(revision rev-parse --short=${GIT_REV_LEN} --verify HEAD)
+ if (_git_ec EQUAL 0)
+ set(version "v${base_version}-0-g${revision}")
+ # check if dirty (this won't detect untracked files, but should be ok)
+ _git(changes diff-index --quiet HEAD --)
+ if (NOT _git_ec EQUAL 0)
+ string(APPEND version "-dirty")
+ endif()
+ # append the commit timestamp of the most recent commit (only
+ # in non-release branches -- typically master)
+ _git(commit_timestamp show -s --format=%ct)
+ if (_git_ec EQUAL 0)
+ string(APPEND version "+${commit_timestamp}")
+ endif()
+ elseif(has_version_txt)
+ # Nothing to get from git - so use version.txt completely
+ set(version "${version_file}")
+ else()
+ # Sad case - no git, no version.txt
+ set(version "v${base_version}")
+ endif()
+ else()
+ set(has_release_tag YES)
+ message(STATUS "Found annotated tag ${version}")
+ endif()
+ extract_version_info("${version}" "${local_prefix}")
+ if ("${has_version_txt}" AND NOT ${base_version} STREQUAL ${local_prefix}_VERSION)
+ message(WARNING "Tagged version ${${local_prefix}_VERSION} doesn't match one from the version.txt: ${base_version}")
+ if (${base_version} VERSION_GREATER ${local_prefix}_VERSION)
+ set(${local_prefix}_VERSION ${base_version})
+ endif()
+ endif()
+ foreach(suffix VERSION VERSION_NCOMMITS VERSION_GIT_REV VERSION_IS_DIRTY VERSION_COMMIT_TIMESTAMP)
+ if (NOT DEFINED ${local_prefix}_${suffix})
+ message(FATAL_ERROR "Unable to determine version.")
+ endif()
+ set(${var_prefix}_${suffix} "${${local_prefix}_${suffix}}" PARENT_SCOPE)
+ message(STATUS "${var_prefix}_${suffix}: ${${local_prefix}_${suffix}}")
+ endforeach()
+ # Set VERSION_SUFFIX and VERSION_FULL. When making changes, be aware that
+ # this is used in packaging as well and will affect ordering.
+ # | state | version_full |
+ # |-----------------------------------------------------|
+ # | exact tag | 0.9.0 |
+ # | exact tag, dirty | 0.9.0+git20180604 |
+ # | after tag | 0.9.0+git20180604.1.085039f |
+ # | no tag, version.txt | 0.9.0+git20180604.2ee02af |
+ # | no tag, no version.txt| 0.0.0+git20180604.2ee02af |
+ string(TIMESTAMP date "%Y%m%d" UTC)
+ set(version_suffix "")
+ if (NOT ${local_prefix}_VERSION_NCOMMITS EQUAL 0)
+ # 0.9.0+git20150604.4.289818b
+ string(APPEND version_suffix "+git${date}.${${local_prefix}_VERSION_NCOMMITS}.${${local_prefix}_VERSION_GIT_REV}")
+ elseif ((NOT has_release_tag) AND ((NOT has_version_txt) OR ("${base_version}" STREQUAL "0.0.0") OR (NOT "${revision}" STREQUAL "")))
+ # 0.9.0+git20150604.289818b
+ string(APPEND version_suffix "+git${date}.${${local_prefix}_VERSION_GIT_REV}")
+ elseif(${local_prefix}_VERSION_IS_DIRTY)
+ # 0.9.0+git20150604
+ string(APPEND version_suffix "+git${date}")
+ endif()
+ set(version_full "${${local_prefix}_VERSION}${version_suffix}")
+ # set the results
+ set(${var_prefix}_VERSION_SUFFIX "${version_suffix}" PARENT_SCOPE)
+ set(${var_prefix}_VERSION_FULL "${version_full}" PARENT_SCOPE)
+ # for informational purposes
+ message(STATUS "${var_prefix}_VERSION_SUFFIX: ${version_suffix}")
+ message(STATUS "${var_prefix}_VERSION_FULL: ${version_full}")
+endfunction()
+