Merge branch 'release-4.1'
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index cccd68c..4474ab9 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -806,6 +806,13 @@
CMAKE_CI_BUILD_NAME: oneapi2025.1.0_makefiles
CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2025.1.0-rocky9
+t:oneapi2025.2.0-makefiles:
+ extends:
+ - .cmake_test_linux_inteloneapi_makefiles
+ variables:
+ CMAKE_CI_BUILD_NAME: oneapi2025.2.0_makefiles
+ CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2025.2.0-rocky9
+
b:linux-x86_64-package:
extends:
- .linux_package
diff --git a/.gitlab/.gitignore b/.gitlab/.gitignore
index ef38d5f..848d72f 100644
--- a/.gitlab/.gitignore
+++ b/.gitlab/.gitignore
@@ -2,6 +2,7 @@
/5.15.1-0-202009071110*
/bcc*
/cmake*
+/emsdk
/iar
/intel
/ispc*
diff --git a/.gitlab/ci/configure_debian12_makefiles_clang.cmake b/.gitlab/ci/configure_debian12_makefiles_clang.cmake
index 9bd6275..fa92973 100644
--- a/.gitlab/ci/configure_debian12_makefiles_clang.cmake
+++ b/.gitlab/ci/configure_debian12_makefiles_clang.cmake
@@ -4,6 +4,7 @@
if (NOT "$ENV{CMAKE_CI_NIGHTLY}" STREQUAL "")
set(CMake_TEST_IAR_TOOLCHAINS "/opt/iarsystems" CACHE PATH "")
set(CMake_TEST_TICLANG_TOOLCHAINS "$ENV{CI_PROJECT_DIR}/.gitlab/ticlang" CACHE PATH "")
+ set(CMake_TEST_Emscripten_TOOLCHAINS "$ENV{CI_PROJECT_DIR}/.gitlab/emsdk/upstream/emscripten" CACHE PATH "")
endif()
include("${CMAKE_CURRENT_LIST_DIR}/configure_external_test.cmake")
diff --git a/.gitlab/ci/configure_debian12_ninja_clang.cmake b/.gitlab/ci/configure_debian12_ninja_clang.cmake
index 1a8e192..7f45fa9 100644
--- a/.gitlab/ci/configure_debian12_ninja_clang.cmake
+++ b/.gitlab/ci/configure_debian12_ninja_clang.cmake
@@ -1,6 +1,7 @@
if (NOT "$ENV{CMAKE_CI_NIGHTLY}" STREQUAL "")
set(CMake_TEST_IAR_TOOLCHAINS "/opt/iarsystems" CACHE PATH "")
set(CMake_TEST_TICLANG_TOOLCHAINS "$ENV{CI_PROJECT_DIR}/.gitlab/ticlang" CACHE PATH "")
+ set(CMake_TEST_Emscripten_TOOLCHAINS "$ENV{CI_PROJECT_DIR}/.gitlab/emsdk/upstream/emscripten" CACHE PATH "")
endif()
include("${CMAKE_CURRENT_LIST_DIR}/configure_external_test.cmake")
diff --git a/.gitlab/ci/emsdk-env.sh b/.gitlab/ci/emsdk-env.sh
new file mode 100644
index 0000000..c62e0e7
--- /dev/null
+++ b/.gitlab/ci/emsdk-env.sh
@@ -0,0 +1,3 @@
+.gitlab/ci/emsdk.sh
+. .gitlab/emsdk/emsdk_env.sh
+em++ --version
diff --git a/.gitlab/ci/emsdk.sh b/.gitlab/ci/emsdk.sh
new file mode 100755
index 0000000..0a798a2
--- /dev/null
+++ b/.gitlab/ci/emsdk.sh
@@ -0,0 +1,25 @@
+#!/bin/sh
+
+set -e
+
+case "$(uname -s)-$(uname -m)" in
+ Linux-x86_64)
+ ;;
+ *)
+ echo "Unrecognized platform $(uname -s)-$(uname -m)"
+ exit 1
+ ;;
+esac
+
+cd .gitlab
+
+version=4.0.9
+dirname="emsdk-$version"
+filename="$dirname.tar.gz"
+curl -OJL "https://github.com/emscripten-core/emsdk/archive/refs/tags/$version.tar.gz"
+tar xzf "$filename"
+mv "$dirname" emsdk
+emsdk/emsdk install "$version"
+emsdk/emsdk activate "$version"
+
+rm -f "$filename"
diff --git a/.gitlab/ci/env_debian12_makefiles_clang.sh b/.gitlab/ci/env_debian12_makefiles_clang.sh
index e4ee249..11f0745 100644
--- a/.gitlab/ci/env_debian12_makefiles_clang.sh
+++ b/.gitlab/ci/env_debian12_makefiles_clang.sh
@@ -1,6 +1,7 @@
if test "$CMAKE_CI_NIGHTLY" = "true"; then
source .gitlab/ci/iar-env.sh
source .gitlab/ci/ticlang-env.sh
+ source .gitlab/ci/emsdk-env.sh
fi
export CC=/usr/bin/clang-15
diff --git a/.gitlab/ci/env_debian12_ninja_clang.sh b/.gitlab/ci/env_debian12_ninja_clang.sh
index e4ee249..11f0745 100644
--- a/.gitlab/ci/env_debian12_ninja_clang.sh
+++ b/.gitlab/ci/env_debian12_ninja_clang.sh
@@ -1,6 +1,7 @@
if test "$CMAKE_CI_NIGHTLY" = "true"; then
source .gitlab/ci/iar-env.sh
source .gitlab/ci/ticlang-env.sh
+ source .gitlab/ci/emsdk-env.sh
fi
export CC=/usr/bin/clang-15
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 8b6d940..a9cb573 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -39,6 +39,7 @@
CMakeLib/testCTestResourceSpec_data/spec13
| RunCMake/CTestResourceAllocation/invalid
)\.json
+ - id: check-toml
- id: check-yaml
- id: end-of-file-fixer
# NOTE Exclude tests directory: some test files have no
@@ -102,13 +103,14 @@
- id: rst-inline-touching-normal
- repo: https://github.com/codespell-project/codespell
- rev: v2.4.0
+ rev: v2.4.1
hooks:
- id: codespell
stages: [commit-msg, pre-commit]
- - repo: https://github.com/crate-ci/typos
- rev: v1.30.0
+ # NOTE See BUG https://github.com/crate-ci/typos/issues/390
+ - repo: https://github.com/adhtruong/mirrors-typos
+ rev: v1.33.1
hooks:
- id: typos
# NOTE Override hook's default args to prevent automatic
diff --git a/.typos.toml b/.typos.toml
index 5ad2245..6838bb7 100644
--- a/.typos.toml
+++ b/.typos.toml
@@ -5,10 +5,10 @@
check-file = true
check-filename = true
extend-ignore-re = [
- # NOTE Allow to mark a block of text to exclude from spellchecking
- "(?s)(#|/(/|\\*)|\\.\\.)\\s*(NOQA|noqa):? spellcheck(: *|=| +)off.*?\\n\\s*(#|/(/|\\*)|\\.\\.)\\s*(NOQA|noqa):? spellcheck(: *|=| +)on"
+ # NOTE Allow to mark block of text to exclude from spellchecking inside C++ or hash-style comments (CMake,Python,&etc.)
+ "(?s)(#|//)\\s*(NOQA|noqa):? spellcheck(: *|=| +)off.*?\\n\\s*(#|//)\\s*(NOQA|noqa):? spellcheck(: *|=| +)on"
# NOTE Allow to mark a line to exclude from spellchecking
- , "(?Rm)^.*(#|/(/|\\*)|\\.\\.)\\s*(NOQA|noqa):? spellcheck(: *|=| +)disable-line$"
+ , "(?Rm)^.*(#|//)\\s*(NOQA|noqa):? spellcheck(: *|=| +)disable-line$"
# NOTE Stop checking from this line to the end of file
# This line is a marker added by Git to the `COMMIT_EDITMSG`.
, "(?sm)^# ------------------------ >8 ------------------------$.*"
@@ -34,7 +34,28 @@
restat = "restat"
# SpectreMitigation
Spectre = "Spectre"
+# Identifier used in source code (`GlobalTargetInfo`)
+gti = "gti"
+[files]
+ignore-hidden = false
+ignore-dot = false
+extend-exclude = [
+ "CONTRIBUTORS.rst"
+ # Exclude third-party sources.
+ , "Source/CursesDialog/form/"
+ , "Source/kwsys/"
+ , "Source/bindexplib.cxx"
+ , "Source/cmcldeps.cxx"
+ , "Source/QtDialog/*.ui"
+ , "Utilities/cm*"
+ , "Utilities/ClangTidyModule"
+ , "Utilities/KWIML"
+ # FIXME: Fix spelling typos in tests. Exclude for now.
+ , "Tests"
+ ]
+
+# BEGIN Type-specific settings
[type.cmake.extend-identifiers]
COMMANDs = "COMMANDs"
xCOMMANDx = "xCOMMANDx"
@@ -60,20 +81,9 @@
[type.py.extend-identifiers]
typ = "typ"
-[files]
-ignore-hidden = false
-ignore-dot = false
-extend-exclude = [
- "CONTRIBUTORS.rst"
- # Exclude third-party sources.
- , "Source/CursesDialog/form/"
- , "Source/kwsys/"
- , "Source/bindexplib.cxx"
- , "Source/cmcldeps.cxx"
- , "Source/QtDialog/*.ui"
- , "Utilities/cm*"
- , "Utilities/ClangTidyModule"
- , "Utilities/KWIML"
- # FIXME: Fix spelling typos in tests. Exclude for now.
- , "Tests"
+[type.rst]
+extend-ignore-re = [
+ # NOTE Allow to mark block of text to exclude from spellchecking as RST comments
+ "(?s)\\.\\.\\s+(NOQA|noqa):? spellcheck(: *|=| +)off.*?\\n\\.\\.\\s+(NOQA|noqa):? spellcheck(: *|=| +)on"
]
+# END Type-specific settings
diff --git a/Help/command/export.rst b/Help/command/export.rst
index 6668e97..9673869 100644
--- a/Help/command/export.rst
+++ b/Help/command/export.rst
@@ -141,7 +141,9 @@
[VERSION_SCHEMA <string>]]
[DEFAULT_TARGETS <target>...]
[DEFAULT_CONFIGURATIONS <config>...]
- [DESCRIPTION <project-description-string>]
+ [LICENSE <license-string>]
+ [DEFAULT_LICENSE <license-string>]
+ [DESCRIPTION <description-string>]
[HOMEPAGE_URL <url-string>])
.. versionadded:: 4.1
diff --git a/Help/command/find_package.rst b/Help/command/find_package.rst
index 4dc9696..4073345 100644
--- a/Help/command/find_package.rst
+++ b/Help/command/find_package.rst
@@ -581,12 +581,12 @@
configuration file found is used, even if a newer version of the package
resides later in the list of search paths.
-For search paths which contain glob expressions (``*``), the order in which
-directories matching the glob are searched is unspecified unless the
-:variable:`CMAKE_FIND_PACKAGE_SORT_ORDER` variable is set. This variable,
-along with the :variable:`CMAKE_FIND_PACKAGE_SORT_DIRECTION` variable,
-determines the order in which CMake considers glob matches. For example, if
-the file system contains the package configuration files
+For search paths which contain glob expressions (``*``), directories matching
+the glob are searched in natural, descending order by default. This behavior
+can be overridden by setting variables :variable:`CMAKE_FIND_PACKAGE_SORT_ORDER`
+and :variable:`CMAKE_FIND_PACKAGE_SORT_DIRECTION` accordingly. Those variables
+determine the order in which CMake considers glob matches. For example, if the
+file system contains the package configuration files
::
@@ -594,21 +594,21 @@
<prefix>/example-1.10/example-config.cmake
<prefix>/share/example-2.0/example-config.cmake
-it is unspecified (when the aforementioned variables are unset) whether
-``find_package(example)`` will find ``example-1.2`` or ``example-1.10``
-(assuming that both are viable), but ``find_package`` will *not* find
-``example-2.0``, because one of the other two will be found first.
+then ``find_package(example)`` will (when the aforementioned variables are
+unset) pick ``example-1.10`` (assuming both ``example-1.2`` and ``example-1.10``
+are viable). Note however that ``find_package`` will *not* find ``example-2.0``,
+because one of the other two will be found first.
To control the order in which ``find_package`` searches directories that match
a glob expression, use :variable:`CMAKE_FIND_PACKAGE_SORT_ORDER` and
:variable:`CMAKE_FIND_PACKAGE_SORT_DIRECTION`.
-For instance, to cause the above example to select ``example-1.10``,
+For instance, to cause the above example to select ``example-1.2``,
one can set
.. code-block:: cmake
set(CMAKE_FIND_PACKAGE_SORT_ORDER NATURAL)
- set(CMAKE_FIND_PACKAGE_SORT_DIRECTION DEC)
+ set(CMAKE_FIND_PACKAGE_SORT_DIRECTION ASC)
before calling ``find_package``.
@@ -624,6 +624,15 @@
and ``<prefix>/<name>.framework/Versions/*/Resources/CMake``. In previous
versions of CMake, this order was unspecified.
+.. versionchanged:: 4.2
+ When encountering multiple viable matches, ``find_package`` now picks the
+ one with the most recent version by default. In previous versions of CMake,
+ the result was unspecified. Accordingly, the default of
+ :variable:`CMAKE_FIND_PACKAGE_SORT_ORDER` has changed from ``NONE`` to
+ ``NATURAL`` and :variable:`CMAKE_FIND_PACKAGE_SORT_DIRECTION`
+ now defaults to ``DEC`` (descending) instead of ``ASC`` (ascending).
+
+
.. include:: include/FIND_XXX_ROOT.rst
.. include:: include/FIND_XXX_ORDER.rst
diff --git a/Help/command/install.rst b/Help/command/install.rst
index 001bee0..2ab9780 100644
--- a/Help/command/install.rst
+++ b/Help/command/install.rst
@@ -1001,7 +1001,9 @@
[VERSION_SCHEMA <string>]]
[DEFAULT_TARGETS <target>...]
[DEFAULT_CONFIGURATIONS <config>...]
- [DESCRIPTION <project-description-string>]
+ [LICENSE <license-string>]
+ [DEFAULT_LICENSE <license-string>]
+ [DESCRIPTION <description-string>]
[HOMEPAGE_URL <url-string>]
[PERMISSIONS <permission>...]
[CONFIGURATIONS <config>...]
@@ -1059,7 +1061,25 @@
configurations exists. If not specified, CMake will fall back to the
package's available configurations in an unspecified order.
- ``DESCRIPTION <project-description-string>``
+ ``LICENSE <license-string>``
+ .. versionadded:: 4.2
+
+ A |SPDX|_ (SPDX) `License Expression`_ that describes the license(s) of the
+ project as a whole, including documentation, resources, or other materials
+ distributed with the project, in addition to software artifacts. See the
+ SPDX `License List`_ for a list of commonly used licenses and their
+ identifiers.
+
+ The license of individual components is taken from the
+ :prop_tgt:`SPDX_LICENSE` property of their respective targets.
+
+ ``DEFAULT_LICENSE <license-string>``
+ .. versionadded:: 4.2
+
+ A |SPDX|_ (SPDX) `License Expression`_ that describes the license(s) of any
+ components which do not otherwise specify their license(s).
+
+ ``DESCRIPTION <description-string>``
.. versionadded:: 4.1
An informational description of the project. It is recommended that this
@@ -1291,3 +1311,9 @@
.. _cps-version_schema: https://cps-org.github.io/cps/schema.html#version-schema
.. |cps-version_schema| replace:: ``version_schema``
+
+.. _SPDX: https://spdx.dev/
+.. |SPDX| replace:: System Package Data Exchange
+
+.. _License Expression: https://spdx.github.io/spdx-spec/v3.0.1/annexes/spdx-license-expressions/
+.. _License List: https://spdx.org/licenses/
diff --git a/Help/command/project.rst b/Help/command/project.rst
index bf0f171..a079bab 100644
--- a/Help/command/project.rst
+++ b/Help/command/project.rst
@@ -12,7 +12,8 @@
project(<PROJECT-NAME>
[VERSION <major>[.<minor>[.<patch>[.<tweak>]]]]
[COMPAT_VERSION <major>[.<minor>[.<patch>[.<tweak>]]]]
- [DESCRIPTION <project-description-string>]
+ [SPDX_LICENSE <license-string>]
+ [DESCRIPTION <description-string>]
[HOMEPAGE_URL <url-string>]
[LANGUAGES <language-name>...])
@@ -106,7 +107,30 @@
``CMakeLists.txt``, then the compatibility version is also stored in the
variable :variable:`CMAKE_PROJECT_COMPAT_VERSION`.
-``DESCRIPTION <project-description-string>``
+``SPDX_LICENSE <license-string>``
+ .. versionadded:: 4.2
+
+ Optional.
+ Sets the variables
+
+ * :variable:`PROJECT_SPDX_LICENSE`,
+ :variable:`<PROJECT-NAME>_SPDX_LICENSE`
+
+ to ``<license-string>``, which shall be a |SPDX|_ (SPDX)
+ `License Expression`_ that describes the license(s) of the project as a
+ whole, including documentation, resources, or other materials distributed
+ with the project, in addition to software artifacts. See the SPDX
+ `License List`_ for a list of commonly used licenses and their identifiers.
+ See the :prop_tgt:`SPDX_LICENSE` property for specifying the license(s) on
+ individual software artifacts.
+
+.. _SPDX: https://spdx.dev/
+.. |SPDX| replace:: System Package Data Exchange
+
+.. _License Expression: https://spdx.github.io/spdx-spec/v3.0.1/annexes/spdx-license-expressions/
+.. _License List: https://spdx.org/licenses/
+
+``DESCRIPTION <description-string>``
.. versionadded:: 3.9
Optional.
@@ -114,7 +138,7 @@
* :variable:`PROJECT_DESCRIPTION`, :variable:`<PROJECT-NAME>_DESCRIPTION`
- to ``<project-description-string>``.
+ to ``<description-string>``.
It is recommended that this description is a relatively short string,
usually no more than a few words.
@@ -149,10 +173,11 @@
Specify language ``NONE``, or use the ``LANGUAGES`` keyword and list no languages,
to skip enabling any languages.
-The variables set through the ``VERSION``, ``COMPAT_VERSION``, ``DESCRIPTION``
-and ``HOMEPAGE_URL`` options are intended for use as default values in package
-metadata and documentation. The :command:`export` and :command:`install`
-commands use these accordingly when generating |CPS| package descriptions.
+The variables set through the ``VERSION``, ``COMPAT_VERSION``,
+``SPDX_LICENSE``, ``DESCRIPTION`` and ``HOMEPAGE_URL`` options are
+intended for use as default values in package metadata and documentation.
+The :command:`export` and :command:`install` commands use these accordingly
+when generating |CPS| package descriptions.
.. |CPS| replace:: Common Package Specification
diff --git a/Help/generator/Visual Studio 10 2010.rst b/Help/generator/Visual Studio 10 2010.rst
index 8b7e31d..08940d2 100644
--- a/Help/generator/Visual Studio 10 2010.rst
+++ b/Help/generator/Visual Studio 10 2010.rst
@@ -3,7 +3,7 @@
Removed. This once generated Visual Studio 10 2010 project files, but
the generator has been removed since CMake 3.25. It is still possible
-to build with the VS 10 2010 toolset by also installing VS 2015 (or above)
-and using the :generator:`Visual Studio 14 2015` (or above) generator with
+to build with the VS 10 2010 toolset by also installing VS 2017 (or above)
+and using the :generator:`Visual Studio 15 2017` (or above) generator with
:variable:`CMAKE_GENERATOR_TOOLSET` set to ``v100``,
or by using the :generator:`NMake Makefiles` generator.
diff --git a/Help/generator/Visual Studio 11 2012.rst b/Help/generator/Visual Studio 11 2012.rst
index 99048bd..8c0f37c 100644
--- a/Help/generator/Visual Studio 11 2012.rst
+++ b/Help/generator/Visual Studio 11 2012.rst
@@ -3,7 +3,7 @@
Removed. This once generated Visual Studio 11 2012 project files, but
the generator has been removed since CMake 3.28. It is still possible
-to build with the VS 11 2012 toolset by also installing VS 2015 (or above)
-and using the :generator:`Visual Studio 14 2015` (or above) generator with
+to build with the VS 11 2012 toolset by also installing VS 2017 (or above)
+and using the :generator:`Visual Studio 15 2017` (or above) generator with
:variable:`CMAKE_GENERATOR_TOOLSET` set to ``v110``,
or by using the :generator:`NMake Makefiles` generator.
diff --git a/Help/generator/Visual Studio 12 2013.rst b/Help/generator/Visual Studio 12 2013.rst
index 6589072..1724c0c 100644
--- a/Help/generator/Visual Studio 12 2013.rst
+++ b/Help/generator/Visual Studio 12 2013.rst
@@ -3,7 +3,7 @@
Removed. This once generated Visual Studio 12 2013 project files, but
the generator has been removed since CMake 3.31. It is still possible
-to build with the VS 12 2013 toolset by also installing VS 2015 (or above)
-and using the :generator:`Visual Studio 14 2015` (or above) generator with
+to build with the VS 12 2013 toolset by also installing VS 2017 (or above)
+and using the :generator:`Visual Studio 15 2017` (or above) generator with
:variable:`CMAKE_GENERATOR_TOOLSET` set to ``v120``,
or by using the :generator:`NMake Makefiles` generator.
diff --git a/Help/generator/Visual Studio 14 2015.rst b/Help/generator/Visual Studio 14 2015.rst
index a491193..7e9035d 100644
--- a/Help/generator/Visual Studio 14 2015.rst
+++ b/Help/generator/Visual Studio 14 2015.rst
@@ -1,6 +1,14 @@
Visual Studio 14 2015
---------------------
+.. deprecated:: 4.2
+
+ This generator is deprecated and will be removed in a future version
+ of CMake. It will still be possible to build with VS 14 2015 tools
+ using the :generator:`Visual Studio 15 2017` (or above) generator
+ with :variable:`CMAKE_GENERATOR_TOOLSET` set to ``v140``, or by
+ using the :generator:`NMake Makefiles` generator.
+
.. versionadded:: 3.1
Generates Visual Studio 14 (VS 2015) project files.
diff --git a/Help/generator/Visual Studio 9 2008.rst b/Help/generator/Visual Studio 9 2008.rst
index a5d953a..1e2730c 100644
--- a/Help/generator/Visual Studio 9 2008.rst
+++ b/Help/generator/Visual Studio 9 2008.rst
@@ -4,6 +4,6 @@
Removed. This once generated Visual Studio 9 2008 project files, but
the generator has been removed since CMake 3.30. It is still possible
to build with the VS 9 2008 toolset by also installing VS 10 2010 and
-VS 2015 (or above) and using the :generator:`Visual Studio 14 2015`
+VS 2017 (or above) and using the :generator:`Visual Studio 15 2017`
generator (or above) with :variable:`CMAKE_GENERATOR_TOOLSET` set to ``v90``,
or by using the :generator:`NMake Makefiles` generator.
diff --git a/Help/manual/cmake-generator-expressions.7.rst b/Help/manual/cmake-generator-expressions.7.rst
index 4bc0435..b031246 100644
--- a/Help/manual/cmake-generator-expressions.7.rst
+++ b/Help/manual/cmake-generator-expressions.7.rst
@@ -1420,8 +1420,8 @@
Note that for proper evaluation of this expression requires policy :policy:`CMP0099`
to be set to ``NEW``.
-Linker Language And ID
-^^^^^^^^^^^^^^^^^^^^^^
+Link Language and ID
+^^^^^^^^^^^^^^^^^^^^
.. genex:: $<LINK_LANGUAGE>
@@ -1827,6 +1827,209 @@
(see :genex:`$<DEVICE_LINK:list>` generator expression). This expression can
only be used to specify link options.
+Linker ID and Frontend-Variant
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+See also the :variable:`CMAKE_<LANG>_COMPILER_LINKER_ID` and
+:variable:`CMAKE_<LANG>_COMPILER_LINKER_FRONTEND_VARIANT` variables, which are
+closely related to most of the expressions in this sub-section.
+
+.. genex:: $<C_COMPILER_LINKER_ID>
+
+ .. versionadded:: 4.2
+
+ CMake's linker id of the C linker used.
+
+.. genex:: $<C_COMPILER_LINKER_ID:linker_ids>
+
+ .. versionadded:: 4.2
+
+ where ``linker_ids`` is a comma-separated list.
+ ``1`` if CMake's linker id of the C linker matches any one
+ of the entries in ``linker_ids``, otherwise ``0``.
+
+.. genex:: $<CXX_COMPILER_LINKER_ID>
+
+ .. versionadded:: 4.2
+
+ CMake's linker id of the C++ linker used.
+
+.. genex:: $<CXX_COMPILER_LINKER_ID:linker_ids>
+
+ .. versionadded:: 4.2
+
+ where ``linker_ids`` is a comma-separated list.
+ ``1`` if CMake's linker id of the C++ linker matches any one
+ of the entries in ``linker_ids``, otherwise ``0``.
+
+.. genex:: $<CUDA_COMPILER_LINKER_ID>
+
+ .. versionadded:: 4.2
+
+ CMake's linker id of the CUDA linker used.
+
+.. genex:: $<CUDA_COMPILER_LINKER_ID:linker_ids>
+
+ .. versionadded:: 4.2
+
+ where ``linker_ids`` is a comma-separated list.
+ ``1`` if CMake's linker id of the CUDA linker matches any one
+ of the entries in ``linker_ids``, otherwise ``0``.
+
+.. genex:: $<OBJC_COMPILER_LINKER_ID>
+
+ .. versionadded:: 4.2
+
+ CMake's linker id of the Objective-C linker used.
+
+.. genex:: $<OBJC_COMPILER_LINKER_ID:linker_ids>
+
+ .. versionadded:: 4.2
+
+ where ``linker_ids`` is a comma-separated list.
+ ``1`` if CMake's linker id of the Objective-C linker matches any one
+ of the entries in ``linker_ids``, otherwise ``0``.
+
+.. genex:: $<OBJCXX_COMPILER_LINKER_ID>
+
+ .. versionadded:: 4.2
+
+ CMake's linker id of the Objective-C++ linker used.
+
+.. genex:: $<OBJCXX_COMPILER_LINKER_ID:linker_ids>
+
+ .. versionadded:: 4.2
+
+ where ``linker_ids`` is a comma-separated list.
+ ``1`` if CMake's linker id of the Objective-C++ linker matches any one
+ of the entries in ``linker_ids``, otherwise ``0``.
+
+.. genex:: $<Fortran_COMPILER_LINKER_ID>
+
+ .. versionadded:: 4.2
+
+ CMake's linker id of the Fortran linker used.
+
+.. genex:: $<Fortran_COMPILER_LINKER_ID:linker_ids>
+
+ .. versionadded:: 4.2
+
+ where ``linker_ids`` is a comma-separated list.
+ ``1`` if CMake's linker id of the Fortran linker matches any one
+ of the entries in ``linker_ids``, otherwise ``0``.
+
+.. genex:: $<HIP_COMPILER_LINKER_ID>
+
+ .. versionadded:: 4.2
+
+ CMake's linker id of the HIP linker used.
+
+.. genex:: $<HIP_COMPILER_LINKER_ID:linker_ids>
+
+ .. versionadded:: 4.2
+
+ where ``linker_ids`` is a comma-separated list.
+ ``1`` if CMake's linker id of the HIP linker matches any one
+ of the entries in ``linker_ids``, otherwise ``0``.
+
+.. genex:: $<C_COMPILER_LINKER_FRONTEND_VARIANT>
+
+ .. versionadded:: 4.2
+
+ CMake's linker frontend variant of the C linker used.
+
+.. genex:: $<C_COMPILER_LINKER_FRONTEND_VARIANT:variant_ids>
+
+ .. versionadded:: 4.2
+
+ where ``variant_ids`` is a comma-separated list.
+ ``1`` if CMake's linker frontend variant of the C linker matches any one
+ of the entries in ``variant_ids``, otherwise ``0``.
+
+.. genex:: $<CXX_COMPILER_LINKER_FRONTEND_VARIANT>
+
+ .. versionadded:: 4.2
+
+ CMake's linker frontend variant of the C++ linker used.
+
+.. genex:: $<CXX_COMPILER_LINKER_FRONTEND_VARIANT:variant_ids>
+
+ .. versionadded:: 4.2
+
+ where ``variant_ids`` is a comma-separated list.
+ ``1`` if CMake's linker frontend variant of the C++ linker matches any one
+ of the entries in ``variant_ids``, otherwise ``0``.
+
+.. genex:: $<CUDA_COMPILER_LINKER_FRONTEND_VARIANT>
+
+ .. versionadded:: 4.2
+
+ CMake's linker frontend variant of the CUDA linker used.
+
+.. genex:: $<CUDA_COMPILER_LINKER_FRONTEND_VARIANT:variant_ids>
+
+ .. versionadded:: 4.2
+
+ where ``variant_ids`` is a comma-separated list.
+ ``1`` if CMake's linker frontend variant of the CUDA linker matches any one
+ of the entries in ``variant_ids``, otherwise ``0``.
+
+.. genex:: $<OBJC_COMPILER_LINKER_FRONTEND_VARIANT>
+
+ .. versionadded:: 4.2
+
+ CMake's linker frontend variant of the Objective-C linker used.
+
+.. genex:: $<OBJC_COMPILER_LINKER_FRONTEND_VARIANT:variant_ids>
+
+ .. versionadded:: 4.2
+
+ where ``variant_ids`` is a comma-separated list.
+ ``1`` if CMake's linker frontend variant of the Objective-C linker matches
+ any one of the entries in ``variant_ids``, otherwise ``0``.
+
+.. genex:: $<OBJCXX_COMPILER_LINKER_FRONTEND_VARIANT>
+
+ .. versionadded:: 4.2
+
+ CMake's linker frontend variant of the Objective-C++ linker used.
+
+.. genex:: $<OBJCXX_COMPILER_LINKER_FRONTEND_VARIANT:variant_ids>
+
+ .. versionadded:: 4.2
+
+ where ``variant_ids`` is a comma-separated list.
+ ``1`` if CMake's linker frontend variant of the Objective-C++ linker matches
+ any one of the entries in ``variant_ids``, otherwise ``0``.
+
+.. genex:: $<Fortran_COMPILER_LINKER_FRONTEND_VARIANT>
+
+ .. versionadded:: 4.2
+
+ CMake's linker frontend variant of the Fortran linker used.
+
+.. genex:: $<Fortran_COMPILER_LINKER_FRONTEND_VARIANT:variant_ids>
+
+ .. versionadded:: 4.2
+
+ where ``variant_ids`` is a comma-separated list.
+ ``1`` if CMake's linker frontend variant of the Fortran linker matches
+ any one of the entries in ``variant_ids``, otherwise ``0``.
+
+.. genex:: $<HIP_COMPILER_LINKER_FRONTEND_VARIANT>
+
+ .. versionadded:: 4.2
+
+ CMake's linker frontend variant of the HIP linker used.
+
+.. genex:: $<HIP_COMPILER_LINKER_FRONTEND_VARIANT:variant_ids>
+
+ .. versionadded:: 4.2
+
+ where ``variant_ids`` is a comma-separated list.
+ ``1`` if CMake's linker frontend variant of the HIP linker matches
+ any one of the entries in ``variant_ids``, otherwise ``0``.
+
.. _`Target-Dependent Expressions`:
diff --git a/Help/manual/cmake-policies.7.rst b/Help/manual/cmake-policies.7.rst
index 45e0ca0..21cc92a 100644
--- a/Help/manual/cmake-policies.7.rst
+++ b/Help/manual/cmake-policies.7.rst
@@ -34,10 +34,10 @@
.. code-block:: cmake
- cmake_minimum_required(VERSION 3.10...4.0)
+ cmake_minimum_required(VERSION 3.10...4.1)
This uses the ``<min>...<max>`` syntax to enable the ``NEW`` behaviors
-of policies introduced in CMake 4.0 and earlier while only requiring a
+of policies introduced in CMake 4.1 and earlier while only requiring a
minimum version of CMake 3.10. The project is expected to work with
both the ``OLD`` and ``NEW`` behaviors of policies introduced between
those versions.
diff --git a/Help/manual/cmake-toolchains.7.rst b/Help/manual/cmake-toolchains.7.rst
index 9eee219..cbd1f74 100644
--- a/Help/manual/cmake-toolchains.7.rst
+++ b/Help/manual/cmake-toolchains.7.rst
@@ -704,3 +704,22 @@
- Use :command:`find_package` only for libraries installed with
:variable:`CMAKE_IOS_INSTALL_COMBINED` feature
+
+.. _`Cross Compiling for Emscripten`:
+
+Cross Compiling for Emscripten
+------------------------------
+
+.. versionadded:: 4.2
+
+A toolchain file may configure cross-compiling for `Emscripten`_ by
+setting the :variable:`CMAKE_SYSTEM_NAME` variable to ``Emscripten``.
+For example, a toolchain file might contain:
+
+.. code-block:: cmake
+
+ set(CMAKE_SYSTEM_NAME Emscripten)
+ set(CMAKE_C_COMPILER /path/to/emcc)
+ set(CMAKE_CXX_COMPILER /path/to/em++)
+
+.. _`Emscripten`: https://emscripten.org/
diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst
index d3ff681..1b8d0a7 100644
--- a/Help/manual/cmake-variables.7.rst
+++ b/Help/manual/cmake-variables.7.rst
@@ -98,15 +98,16 @@
/variable/CMAKE_OBJDUMP
/variable/CMAKE_PARENT_LIST_FILE
/variable/CMAKE_PATCH_VERSION
+ /variable/CMAKE_PROJECT_COMPAT_VERSION
/variable/CMAKE_PROJECT_DESCRIPTION
/variable/CMAKE_PROJECT_HOMEPAGE_URL
/variable/CMAKE_PROJECT_NAME
+ /variable/CMAKE_PROJECT_SPDX_LICENSE
/variable/CMAKE_PROJECT_VERSION
/variable/CMAKE_PROJECT_VERSION_MAJOR
/variable/CMAKE_PROJECT_VERSION_MINOR
/variable/CMAKE_PROJECT_VERSION_PATCH
/variable/CMAKE_PROJECT_VERSION_TWEAK
- /variable/CMAKE_PROJECT_COMPAT_VERSION
/variable/CMAKE_RANLIB
/variable/CMAKE_ROOT
/variable/CMAKE_RULE_MESSAGES
@@ -154,28 +155,30 @@
/variable/CMAKE_XCODE_BUILD_SYSTEM
/variable/CMAKE_XCODE_PLATFORM_TOOLSET
/variable/PROJECT-NAME_BINARY_DIR
+ /variable/PROJECT-NAME_COMPAT_VERSION
/variable/PROJECT-NAME_DESCRIPTION
/variable/PROJECT-NAME_HOMEPAGE_URL
/variable/PROJECT-NAME_IS_TOP_LEVEL
/variable/PROJECT-NAME_SOURCE_DIR
+ /variable/PROJECT-NAME_SPDX_LICENSE
/variable/PROJECT-NAME_VERSION
/variable/PROJECT-NAME_VERSION_MAJOR
/variable/PROJECT-NAME_VERSION_MINOR
/variable/PROJECT-NAME_VERSION_PATCH
/variable/PROJECT-NAME_VERSION_TWEAK
- /variable/PROJECT-NAME_COMPAT_VERSION
/variable/PROJECT_BINARY_DIR
+ /variable/PROJECT_COMPAT_VERSION
/variable/PROJECT_DESCRIPTION
/variable/PROJECT_HOMEPAGE_URL
/variable/PROJECT_IS_TOP_LEVEL
/variable/PROJECT_NAME
/variable/PROJECT_SOURCE_DIR
+ /variable/PROJECT_SPDX_LICENSE
/variable/PROJECT_VERSION
/variable/PROJECT_VERSION_MAJOR
/variable/PROJECT_VERSION_MINOR
/variable/PROJECT_VERSION_PATCH
/variable/PROJECT_VERSION_TWEAK
- /variable/PROJECT_COMPAT_VERSION
Variables that Change Behavior
==============================
diff --git a/Help/prop_tgt/SPDX_LICENSE.rst b/Help/prop_tgt/SPDX_LICENSE.rst
index 056c860..a030e6c 100644
--- a/Help/prop_tgt/SPDX_LICENSE.rst
+++ b/Help/prop_tgt/SPDX_LICENSE.rst
@@ -3,9 +3,9 @@
.. versionadded:: 4.1
-Specify the license of a target using a |SPDX|_ (SPDX) `License Expression`_.
-See the SPDX `License List`_ for a list of commonly used licenses and their
-identifiers.
+Specify the license(s) of a target using a |SPDX|_ (SPDX)
+`License Expression`_. See the SPDX `License List`_ for a list of commonly used
+licenses and their identifiers.
.. _SPDX: https://spdx.dev/
.. |SPDX| replace:: System Package Data Exchange
diff --git a/Help/release/dev/0-sample-topic.rst b/Help/release/dev/0-sample-topic.rst
new file mode 100644
index 0000000..e4cc01e
--- /dev/null
+++ b/Help/release/dev/0-sample-topic.rst
@@ -0,0 +1,7 @@
+0-sample-topic
+--------------
+
+* This is a sample release note for the change in a topic.
+ Developers should add similar notes for each topic branch
+ making a noteworthy change. Each document should be named
+ and titled to match the topic name to avoid merge conflicts.
diff --git a/Help/release/dev/GenEx-COMPILER_LINKER.rst b/Help/release/dev/GenEx-COMPILER_LINKER.rst
new file mode 100644
index 0000000..d0a1896
--- /dev/null
+++ b/Help/release/dev/GenEx-COMPILER_LINKER.rst
@@ -0,0 +1,8 @@
+GenEx-COMPILER_LINKER
+---------------------
+
+* The :genex:`<LANG>_COMPILER_LINKER_ID <C_COMPILER_LINKER_ID>` and
+ :genex:`<LANG>_COMPILER_LINKER_FRONTEND_VARIANT <C_COMPILER_LINKER_FRONTEND_VARIANT>`
+ families of generator expressions were added to access the value of the
+ associated :variable:`CMAKE_<LANG>_COMPILER_LINKER_ID` and
+ :variable:`CMAKE_<LANG>_COMPILER_LINKER_FRONTEND_VARIANT` variables.
diff --git a/Help/release/dev/emscripten-platform.rst b/Help/release/dev/emscripten-platform.rst
new file mode 100644
index 0000000..4757227
--- /dev/null
+++ b/Help/release/dev/emscripten-platform.rst
@@ -0,0 +1,5 @@
+emscripten-platform
+-------------------
+
+* CMake now supports :ref:`Cross Compiling for Emscripten` with simple
+ toolchain files.
diff --git a/Help/release/dev/vs14-deprecate.rst b/Help/release/dev/vs14-deprecate.rst
new file mode 100644
index 0000000..f3aab73
--- /dev/null
+++ b/Help/release/dev/vs14-deprecate.rst
@@ -0,0 +1,5 @@
+vs14-deprecate
+--------------
+
+* The :generator:`Visual Studio 14 2015` generator is now deprecated
+ and will be removed in a future version of CMake.
diff --git a/Help/release/index.rst b/Help/release/index.rst
index 400e1f2..64b933a 100644
--- a/Help/release/index.rst
+++ b/Help/release/index.rst
@@ -7,6 +7,8 @@
This file should include the adjacent "dev.txt" file
in development versions but not in release versions.
+.. include:: dev.txt
+
Releases
========
diff --git a/Help/variable/CMAKE_BINARY_DIR.rst b/Help/variable/CMAKE_BINARY_DIR.rst
index 96c6319..b046037 100644
--- a/Help/variable/CMAKE_BINARY_DIR.rst
+++ b/Help/variable/CMAKE_BINARY_DIR.rst
@@ -11,3 +11,5 @@
``CMAKE_BINARY_DIR``, :variable:`CMAKE_SOURCE_DIR`,
:variable:`CMAKE_CURRENT_BINARY_DIR` and
:variable:`CMAKE_CURRENT_SOURCE_DIR` to the current working directory.
+
+Modifying ``CMAKE_BINARY_DIR`` has undefined behavior.
diff --git a/Help/variable/CMAKE_CURRENT_BINARY_DIR.rst b/Help/variable/CMAKE_CURRENT_BINARY_DIR.rst
index 1d7a111..1eabaef 100644
--- a/Help/variable/CMAKE_CURRENT_BINARY_DIR.rst
+++ b/Help/variable/CMAKE_CURRENT_BINARY_DIR.rst
@@ -13,3 +13,5 @@
:variable:`CMAKE_BINARY_DIR`, :variable:`CMAKE_SOURCE_DIR`,
``CMAKE_CURRENT_BINARY_DIR`` and
:variable:`CMAKE_CURRENT_SOURCE_DIR` to the current working directory.
+
+Modifying ``CMAKE_CURRENT_BINARY_DIR`` has undefined behavior.
diff --git a/Help/variable/CMAKE_CURRENT_SOURCE_DIR.rst b/Help/variable/CMAKE_CURRENT_SOURCE_DIR.rst
index 4205efb..7a08892 100644
--- a/Help/variable/CMAKE_CURRENT_SOURCE_DIR.rst
+++ b/Help/variable/CMAKE_CURRENT_SOURCE_DIR.rst
@@ -10,3 +10,5 @@
:variable:`CMAKE_BINARY_DIR`, :variable:`CMAKE_SOURCE_DIR`,
:variable:`CMAKE_CURRENT_BINARY_DIR` and
``CMAKE_CURRENT_SOURCE_DIR`` to the current working directory.
+
+Modifying ``CMAKE_CURRENT_SOURCE_DIR`` has undefined behavior.
diff --git a/Help/variable/CMAKE_FIND_PACKAGE_SORT_DIRECTION.rst b/Help/variable/CMAKE_FIND_PACKAGE_SORT_DIRECTION.rst
index 92758fd..033748a 100644
--- a/Help/variable/CMAKE_FIND_PACKAGE_SORT_DIRECTION.rst
+++ b/Help/variable/CMAKE_FIND_PACKAGE_SORT_DIRECTION.rst
@@ -3,16 +3,21 @@
.. versionadded:: 3.7
+.. versionchanged:: 4.2
+
+ The default sort direction has changed from ``DEC`` to ``ASC``.
+
+
The sorting direction used by :variable:`CMAKE_FIND_PACKAGE_SORT_ORDER`.
It can assume one of the following values:
``ASC``
- Default. Ordering is done in ascending mode.
+ Ordering is done in ascending mode.
The lowest folder found will be tested first.
``DEC``
- Ordering is done in descending mode.
+ Default. Ordering is done in descending mode.
The highest folder found will be tested first.
-If :variable:`CMAKE_FIND_PACKAGE_SORT_ORDER` is not set or is set to ``NONE``
-this variable has no effect.
+If :variable:`CMAKE_FIND_PACKAGE_SORT_ORDER` is set to ``NONE`` this variable
+has no effect.
diff --git a/Help/variable/CMAKE_FIND_PACKAGE_SORT_ORDER.rst b/Help/variable/CMAKE_FIND_PACKAGE_SORT_ORDER.rst
index f1016d9..524b2ef 100644
--- a/Help/variable/CMAKE_FIND_PACKAGE_SORT_ORDER.rst
+++ b/Help/variable/CMAKE_FIND_PACKAGE_SORT_ORDER.rst
@@ -3,39 +3,40 @@
.. versionadded:: 3.7
+.. versionchanged:: 4.2
+
+ The default sort order has changed from ``NONE`` to ``NATURAL``.
+
+
The default order for sorting directories which match a search path containing
a glob expression found using :command:`find_package`. It can assume one of
the following values:
``NONE``
- Default. No attempt is done to sort directories.
+ No attempt is done to sort directories.
The first valid package found will be selected.
``NAME``
Sort directories lexicographically before searching.
``NATURAL``
- Sort directories using natural order (see ``strverscmp(3)`` manual),
+ Default. Sort directories using natural order (see ``strverscmp(3)`` manual),
i.e. such that contiguous digits are compared as whole numbers.
-Natural sorting can be employed to return the highest version when multiple
-versions of the same library are available to be found by
-:command:`find_package`. For example suppose that the following libraries
-have package configuration files on disk, in a directory of the same name,
-with all such directories residing in the same parent directory:
+Natural sorting is employed by default to return the highest version when
+multiple versions of the same library are available to be found by
+:command:`find_package`. For example suppose that the following libraries have
+package configuration files on disk, in a directory of the same name, with all
+such directories residing in the same parent directory:
-* libX-1.1.0
-* libX-1.2.9
-* libX-1.2.10
+* ``libX-1.1.0``
+* ``libX-1.2.9``
+* ``libX-1.2.10``
-By setting ``NATURAL`` order we can select the one with the highest
-version number ``libX-1.2.10``.
-
-.. code-block:: cmake
-
- set(CMAKE_FIND_PACKAGE_SORT_ORDER NATURAL)
- find_package(libX CONFIG)
+The default order of ``NATURAL`` will select the one with the highest version
+number, i.e. ``libX-1.2.10``.
The sort direction can be controlled using the
-:variable:`CMAKE_FIND_PACKAGE_SORT_DIRECTION` variable
-(by default descending, e.g. lib-B will be tested before lib-A).
+:variable:`CMAKE_FIND_PACKAGE_SORT_DIRECTION` variable (by default descending,
+i.e. ``libX-1.2`` will be tested before ``libX-1.0`` and ``lib-B`` will be
+tested before ``lib-A``).
diff --git a/Help/variable/CMAKE_PROJECT_SPDX_LICENSE.rst b/Help/variable/CMAKE_PROJECT_SPDX_LICENSE.rst
new file mode 100644
index 0000000..0cbde7c
--- /dev/null
+++ b/Help/variable/CMAKE_PROJECT_SPDX_LICENSE.rst
@@ -0,0 +1,41 @@
+CMAKE_PROJECT_SPDX_LICENSE
+--------------------------
+
+.. versionadded:: 4.2
+
+.. note::
+
+ Experimental. Gated by ``CMAKE_EXPERIMENTAL_EXPORT_PACKAGE_INFO``.
+
+The license(s) of the top level project.
+
+This variable holds the license expression of the project as specified in the
+top level CMakeLists.txt file by a :command:`project` command. In the event
+that the top level CMakeLists.txt contains multiple :command:`project` calls,
+the most recently called one from that top level CMakeLists.txt will determine
+the value that ``CMAKE_PROJECT_SPDX_LICENSE`` contains. For example, consider
+the following top level CMakeLists.txt:
+
+.. code-block:: cmake
+
+ cmake_minimum_required(VERSION 4.2)
+ project(First SPDX_LICENSE "BSD-3-Clause")
+ project(Second SPDX_LICENSE "BSD-3-Clause AND CC-BY-SA-4.0")
+ add_subdirectory(sub)
+ project(Third SPDX_LICENSE "BSD-3-Clause AND CC0-1.0")
+
+And ``sub/CMakeLists.txt`` with the following contents:
+
+.. code-block:: cmake
+
+ project(SubProj SPDX_LICENSE Apache-2.0)
+ message("CMAKE_PROJECT_SPDX_LICENSE = ${CMAKE_PROJECT_SPDX_LICENSE}")
+
+The most recently seen :command:`project` command from the top level
+CMakeLists.txt would be ``project(Second ...)``, so this will print::
+
+ CMAKE_PROJECT_SPDX_LICENSE = BSD-3-Clause AND CC-BY-SA-4.0
+
+To obtain the version from the most recent call to :command:`project` in
+the current directory scope or above, see the :variable:`PROJECT_SPDX_LICENSE`
+variable.
diff --git a/Help/variable/CMAKE_SOURCE_DIR.rst b/Help/variable/CMAKE_SOURCE_DIR.rst
index f1d1bee..be28f4d 100644
--- a/Help/variable/CMAKE_SOURCE_DIR.rst
+++ b/Help/variable/CMAKE_SOURCE_DIR.rst
@@ -11,3 +11,5 @@
:variable:`CMAKE_BINARY_DIR`, ``CMAKE_SOURCE_DIR``,
:variable:`CMAKE_CURRENT_BINARY_DIR` and
:variable:`CMAKE_CURRENT_SOURCE_DIR` to the current working directory.
+
+Modifying ``CMAKE_SOURCE_DIR`` has undefined behavior.
diff --git a/Help/variable/PROJECT-NAME_SPDX_LICENSE.rst b/Help/variable/PROJECT-NAME_SPDX_LICENSE.rst
new file mode 100644
index 0000000..06c395d
--- /dev/null
+++ b/Help/variable/PROJECT-NAME_SPDX_LICENSE.rst
@@ -0,0 +1,11 @@
+<PROJECT-NAME>_SPDX_LICENSE
+---------------------------
+
+.. versionadded:: 4.2
+
+.. note::
+
+ Experimental. Gated by ``CMAKE_EXPERIMENTAL_EXPORT_PACKAGE_INFO``.
+
+Value given to the ``SPDX_LICENSE`` option of the most recent call to the
+:command:`project` command with project name ``<PROJECT-NAME>``, if any.
diff --git a/Help/variable/PROJECT_SPDX_LICENSE.rst b/Help/variable/PROJECT_SPDX_LICENSE.rst
new file mode 100644
index 0000000..4f62e94
--- /dev/null
+++ b/Help/variable/PROJECT_SPDX_LICENSE.rst
@@ -0,0 +1,12 @@
+PROJECT_SPDX_LICENSE
+--------------------
+
+.. versionadded:: 4.2
+
+.. note::
+
+ Experimental. Gated by ``CMAKE_EXPERIMENTAL_EXPORT_PACKAGE_INFO``.
+
+Value given to the ``SPDX_LICENSE`` option of the most recent call to the
+:command:`project` command, if any. To obtain the compatibility version of the
+top level project, see the :variable:`CMAKE_PROJECT_SPDX_LICENSE` variable.
diff --git a/Modules/CMakeFindBinUtils.cmake b/Modules/CMakeFindBinUtils.cmake
index 1948c63..fb63d8d 100644
--- a/Modules/CMakeFindBinUtils.cmake
+++ b/Modules/CMakeFindBinUtils.cmake
@@ -219,6 +219,11 @@
list(PREPEND _CMAKE_LINKER_NAMES "armlink")
endif()
+ if(EMSCRIPTEN)
+ list(PREPEND _CMAKE_AR_NAMES "emar")
+ list(PREPEND _CMAKE_RANLIB_NAMES "emranlib")
+ endif()
+
list(APPEND _CMAKE_TOOL_VARS AR RANLIB STRIP LINKER NM OBJDUMP OBJCOPY READELF DLLTOOL ADDR2LINE TAPI)
endif()
diff --git a/Modules/Platform/Emscripten-Clang-C.cmake b/Modules/Platform/Emscripten-Clang-C.cmake
new file mode 100644
index 0000000..1b6b2ab
--- /dev/null
+++ b/Modules/Platform/Emscripten-Clang-C.cmake
@@ -0,0 +1,3 @@
+include(Platform/Emscripten-Clang)
+
+__emscripten_clang(C)
diff --git a/Modules/Platform/Emscripten-Clang-CXX.cmake b/Modules/Platform/Emscripten-Clang-CXX.cmake
new file mode 100644
index 0000000..32b913e
--- /dev/null
+++ b/Modules/Platform/Emscripten-Clang-CXX.cmake
@@ -0,0 +1,3 @@
+include(Platform/Emscripten-Clang)
+
+__emscripten_clang(CXX)
diff --git a/Modules/Platform/Emscripten-Clang.cmake b/Modules/Platform/Emscripten-Clang.cmake
new file mode 100644
index 0000000..88cb197
--- /dev/null
+++ b/Modules/Platform/Emscripten-Clang.cmake
@@ -0,0 +1,17 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file LICENSE.rst or https://cmake.org/licensing for details.
+
+include_guard()
+
+macro(__emscripten_clang lang)
+ set(CMAKE_SHARED_LIBRARY_SONAME_${lang}_FLAG "-Wl,-soname,")
+ set(CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS "-sSIDE_MODULE")
+
+ set(CMAKE_${lang}_USE_RESPONSE_FILE_FOR_LIBRARIES 1)
+ set(CMAKE_${lang}_USE_RESPONSE_FILE_FOR_OBJECTS 1)
+ set(CMAKE_${lang}_USE_RESPONSE_FILE_FOR_INCLUDES 1)
+ set(CMAKE_${lang}_COMPILE_OBJECT
+ "<CMAKE_${lang}_COMPILER> -c <SOURCE> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT> -fPIC")
+ set(CMAKE_${lang}_LINK_EXECUTABLE
+ "<CMAKE_${lang}_COMPILER> <FLAGS> <CMAKE_${lang}_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES> -sMAIN_MODULE")
+endmacro()
diff --git a/Modules/Platform/Emscripten-Initialize.cmake b/Modules/Platform/Emscripten-Initialize.cmake
new file mode 100644
index 0000000..3117e05
--- /dev/null
+++ b/Modules/Platform/Emscripten-Initialize.cmake
@@ -0,0 +1,2 @@
+set(EMSCRIPTEN 1)
+set(UNIX 1)
diff --git a/Modules/Platform/Emscripten.cmake b/Modules/Platform/Emscripten.cmake
new file mode 100644
index 0000000..8157d47
--- /dev/null
+++ b/Modules/Platform/Emscripten.cmake
@@ -0,0 +1,6 @@
+set(CMAKE_SHARED_LIBRARY_LINK_C_WITH_RUNTIME_PATH ON)
+
+set(CMAKE_SHARED_LIBRARY_SUFFIX ".wasm")
+set(CMAKE_EXECUTABLE_SUFFIX ".js")
+
+set(CMAKE_DL_LIBS "")
diff --git a/Modules/Platform/Linker/Emscripten-C.cmake b/Modules/Platform/Linker/Emscripten-C.cmake
new file mode 100644
index 0000000..dfef6a3
--- /dev/null
+++ b/Modules/Platform/Linker/Emscripten-C.cmake
@@ -0,0 +1,4 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file LICENSE.rst or https://cmake.org/licensing for details.
+
+include(Platform/Linker/Emscripten-LLD-C)
diff --git a/Modules/Platform/Linker/Emscripten-CXX.cmake b/Modules/Platform/Linker/Emscripten-CXX.cmake
new file mode 100644
index 0000000..90bb820
--- /dev/null
+++ b/Modules/Platform/Linker/Emscripten-CXX.cmake
@@ -0,0 +1,4 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file LICENSE.rst or https://cmake.org/licensing for details.
+
+include(Platform/Linker/Emscripten-LLD-CXX)
diff --git a/Modules/Platform/Linker/Emscripten-LLD-C.cmake b/Modules/Platform/Linker/Emscripten-LLD-C.cmake
new file mode 100644
index 0000000..448d7cc
--- /dev/null
+++ b/Modules/Platform/Linker/Emscripten-LLD-C.cmake
@@ -0,0 +1,6 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file LICENSE.rst or https://cmake.org/licensing for details.
+
+include(Platform/Linker/Emscripten-LLD)
+
+__emscripten_linker_lld(C)
diff --git a/Modules/Platform/Linker/Emscripten-LLD-CXX.cmake b/Modules/Platform/Linker/Emscripten-LLD-CXX.cmake
new file mode 100644
index 0000000..63d71b4
--- /dev/null
+++ b/Modules/Platform/Linker/Emscripten-LLD-CXX.cmake
@@ -0,0 +1,6 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file LICENSE.rst or https://cmake.org/licensing for details.
+
+include(Platform/Linker/Emscripten-LLD)
+
+__emscripten_linker_lld(CXX)
diff --git a/Modules/Platform/Linker/Emscripten-LLD.cmake b/Modules/Platform/Linker/Emscripten-LLD.cmake
new file mode 100644
index 0000000..4c02cf7
--- /dev/null
+++ b/Modules/Platform/Linker/Emscripten-LLD.cmake
@@ -0,0 +1,11 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file LICENSE.rst or https://cmake.org/licensing for details.
+
+# This module is shared by multiple languages; use include blocker.
+include_guard()
+
+macro(__emscripten_linker_lld lang)
+ set(CMAKE_${lang}_LINK_LIBRARY_USING_WHOLE_ARCHIVE "-Wl,--whole-archive" "<LINK_ITEM>" "-Wl,--no-whole-archive")
+ set(CMAKE_${lang}_LINK_LIBRARY_USING_WHOLE_ARCHIVE_SUPPORTED TRUE)
+ set(CMAKE_${lang}_LINK_LIBRARY_WHOLE_ARCHIVE_ATTRIBUTES LIBRARY_TYPE=STATIC DEDUPLICATION=YES OVERRIDE=DEFAULT)
+endmacro()
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index b1c8290..7885af0 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -717,6 +717,9 @@
cmSiteNameCommand.h
cmSourceGroupCommand.cxx
cmSourceGroupCommand.h
+ cmSPDXSerializer.cxx
+ cmSPDXSerializer.h
+ cmSPDXTypes.def
cmString.cxx
cmString.hxx
cmStringReplaceHelper.cxx
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake
index 2103501..363e6a6 100644
--- a/Source/CMakeVersion.cmake
+++ b/Source/CMakeVersion.cmake
@@ -1,8 +1,8 @@
# CMake version number components.
set(CMake_VERSION_MAJOR 4)
set(CMake_VERSION_MINOR 1)
-set(CMake_VERSION_PATCH 0)
-set(CMake_VERSION_RC 1)
+set(CMake_VERSION_PATCH 20250701)
+#set(CMake_VERSION_RC 0)
set(CMake_VERSION_IS_DIRTY 0)
# Start with the full version number used in tags. It has no dev info.
diff --git a/Source/cmCoreTryCompile.cxx b/Source/cmCoreTryCompile.cxx
index eb8f616..4a2f163 100644
--- a/Source/cmCoreTryCompile.cxx
+++ b/Source/cmCoreTryCompile.cxx
@@ -1386,6 +1386,14 @@
return;
}
+ if (cmHasLiteralSuffix(outputFileLocation, ".js")) {
+ std::string wasmOutputLocation = cmStrCat(
+ outputFileLocation.substr(0, outputFileLocation.length() - 3), ".wasm");
+ if (cmSystemTools::FileExists(wasmOutputLocation)) {
+ outputFileLocation = wasmOutputLocation;
+ }
+ }
+
this->OutputFile = cmSystemTools::CollapseFullPath(outputFileLocation);
}
diff --git a/Source/cmExportPackageInfoGenerator.cxx b/Source/cmExportPackageInfoGenerator.cxx
index f2fbc28..d38c640 100644
--- a/Source/cmExportPackageInfoGenerator.cxx
+++ b/Source/cmExportPackageInfoGenerator.cxx
@@ -39,6 +39,8 @@
, PackageVersionSchema(std::move(arguments.VersionSchema))
, PackageDescription(std::move(arguments.Description))
, PackageWebsite(std::move(arguments.Website))
+ , PackageLicense(std::move(arguments.License))
+ , DefaultLicense(std::move(arguments.DefaultLicense))
, DefaultTargets(std::move(arguments.DefaultTargets))
, DefaultConfigurations(std::move(arguments.DefaultConfigs))
{
@@ -127,7 +129,8 @@
SetProperty(package, "description", this->PackageDescription);
SetProperty(package, "website", this->PackageWebsite);
- // TODO: license
+ SetProperty(package, "license", this->PackageLicense);
+ SetProperty(package, "default_license", this->DefaultLicense);
return package;
}
diff --git a/Source/cmExportPackageInfoGenerator.h b/Source/cmExportPackageInfoGenerator.h
index fb7d79f..83cb6ad 100644
--- a/Source/cmExportPackageInfoGenerator.h
+++ b/Source/cmExportPackageInfoGenerator.h
@@ -110,6 +110,8 @@
std::string const PackageVersionSchema;
std::string const PackageDescription;
std::string const PackageWebsite;
+ std::string const PackageLicense;
+ std::string const DefaultLicense;
std::vector<std::string> DefaultTargets;
std::vector<std::string> DefaultConfigurations;
diff --git a/Source/cmFindPackageCommand.h b/Source/cmFindPackageCommand.h
index 10448a8..4d5da75 100644
--- a/Source/cmFindPackageCommand.h
+++ b/Source/cmFindPackageCommand.h
@@ -334,10 +334,10 @@
class FlushDebugBufferOnExit;
- /*! the selected sortOrder (None by default)*/
- SortOrderType SortOrder = None;
- /*! the selected sortDirection (Asc by default)*/
- SortDirectionType SortDirection = Asc;
+ /*! the selected sortOrder (Natural by default)*/
+ SortOrderType SortOrder = Natural;
+ /*! the selected sortDirection (Dec by default)*/
+ SortDirectionType SortDirection = Dec;
struct ConfigFileInfo
{
diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx
index 90bb06b..3c2e7ec 100644
--- a/Source/cmGeneratorExpressionNode.cxx
+++ b/Source/cmGeneratorExpressionNode.cxx
@@ -2561,6 +2561,146 @@
}
} linkLanguageAndIdNode;
+struct CompilerLinkerIdNode : public cmGeneratorExpressionNode
+{
+ CompilerLinkerIdNode(char const* lang)
+ : Language(lang)
+ {
+ }
+
+ int NumExpectedParameters() const override { return ZeroOrMoreParameters; }
+
+ std::string Evaluate(
+ std::vector<std::string> const& parameters,
+ cmGeneratorExpressionContext* context,
+ GeneratorExpressionContent const* content,
+ cmGeneratorExpressionDAGChecker* dagChecker) const override
+ {
+ if (!context->HeadTarget) {
+ reportError(
+ context, content->GetOriginalExpression(),
+ cmStrCat(
+ "$<", this->Language,
+ "_COMPILER_LINKER_ID> may only be used with binary targets. It may "
+ "not be used with add_custom_command or add_custom_target."));
+ return {};
+ }
+ return this->EvaluateWithLanguage(parameters, context, content, dagChecker,
+ this->Language);
+ }
+
+ std::string EvaluateWithLanguage(std::vector<std::string> const& parameters,
+ cmGeneratorExpressionContext* context,
+ GeneratorExpressionContent const* content,
+ cmGeneratorExpressionDAGChecker* /*unused*/,
+ std::string const& lang) const
+ {
+ std::string const& compilerLinkerId =
+ context->LG->GetMakefile()->GetSafeDefinition(
+ cmStrCat("CMAKE_", lang, "_COMPILER_LINKER_ID"));
+ if (parameters.empty()) {
+ return compilerLinkerId;
+ }
+ if (compilerLinkerId.empty()) {
+ return parameters.front().empty() ? "1" : "0";
+ }
+ static cmsys::RegularExpression compilerLinkerIdValidator(
+ "^[A-Za-z0-9_]*$");
+
+ for (auto const& param : parameters) {
+ if (!compilerLinkerIdValidator.find(param)) {
+ reportError(context, content->GetOriginalExpression(),
+ "Expression syntax not recognized.");
+ return std::string();
+ }
+
+ if (param == compilerLinkerId) {
+ return "1";
+ }
+ }
+ return "0";
+ }
+
+ char const* const Language;
+};
+
+static CompilerLinkerIdNode const cCompilerLinkerIdNode("C"),
+ cxxCompilerLinkerIdNode("CXX"), cudaCompilerLinkerIdNode("CUDA"),
+ objcCompilerLinkerIdNode("OBJC"), objcxxCompilerLinkerIdNode("OBJCXX"),
+ fortranCompilerLinkerIdNode("Fortran"), hipCompilerLinkerIdNode("HIP");
+
+struct CompilerLinkerFrontendVariantNode : public cmGeneratorExpressionNode
+{
+ CompilerLinkerFrontendVariantNode(char const* lang)
+ : Language(lang)
+ {
+ }
+
+ int NumExpectedParameters() const override { return ZeroOrMoreParameters; }
+
+ std::string Evaluate(
+ std::vector<std::string> const& parameters,
+ cmGeneratorExpressionContext* context,
+ GeneratorExpressionContent const* content,
+ cmGeneratorExpressionDAGChecker* dagChecker) const override
+ {
+ if (!context->HeadTarget) {
+ reportError(
+ context, content->GetOriginalExpression(),
+ cmStrCat(
+ "$<", this->Language,
+ "_COMPILER_LINKER_FRONTEND_VARIANT> may only be used with binary "
+ "targets. It may not be used with add_custom_command or "
+ "add_custom_target."));
+ return {};
+ }
+ return this->EvaluateWithLanguage(parameters, context, content, dagChecker,
+ this->Language);
+ }
+
+ std::string EvaluateWithLanguage(std::vector<std::string> const& parameters,
+ cmGeneratorExpressionContext* context,
+ GeneratorExpressionContent const* content,
+ cmGeneratorExpressionDAGChecker* /*unused*/,
+ std::string const& lang) const
+ {
+ std::string const& compilerLinkerFrontendVariant =
+ context->LG->GetMakefile()->GetSafeDefinition(
+ cmStrCat("CMAKE_", lang, "_COMPILER_LINKER_FRONTEND_VARIANT"));
+ if (parameters.empty()) {
+ return compilerLinkerFrontendVariant;
+ }
+ if (compilerLinkerFrontendVariant.empty()) {
+ return parameters.front().empty() ? "1" : "0";
+ }
+ static cmsys::RegularExpression compilerLinkerFrontendVariantValidator(
+ "^[A-Za-z0-9_]*$");
+
+ for (auto const& param : parameters) {
+ if (!compilerLinkerFrontendVariantValidator.find(param)) {
+ reportError(context, content->GetOriginalExpression(),
+ "Expression syntax not recognized.");
+ return {};
+ }
+ if (param == compilerLinkerFrontendVariant) {
+ return "1";
+ }
+ }
+ return "0";
+ }
+
+ char const* const Language;
+};
+
+static CompilerLinkerFrontendVariantNode const
+ cCompilerLinkerFrontendVariantNode("C"),
+ cxxCompilerLinkerFrontendVariantNode("CXX"),
+ cudaCompilerLinkerFrontendVariantNode("CUDA"),
+ objcCompilerLinkerFrontendVariantNode("OBJC"),
+ objcxxCompilerLinkerFrontendVariantNode("OBJCXX"),
+ fortranCompilerLinkerFrontendVariantNode("Fortran"),
+ hipCompilerLinkerFrontendVariantNode("HIP");
+
static const struct LinkLibraryNode : public cmGeneratorExpressionNode
{
LinkLibraryNode() {} // NOLINT(modernize-use-equals-default)
@@ -4641,6 +4781,27 @@
{ "COMPILE_LANGUAGE", &languageNode },
{ "LINK_LANG_AND_ID", &linkLanguageAndIdNode },
{ "LINK_LANGUAGE", &linkLanguageNode },
+ { "C_COMPILER_LINKER_ID", &cCompilerLinkerIdNode },
+ { "CXX_COMPILER_LINKER_ID", &cxxCompilerLinkerIdNode },
+ { "OBJC_COMPILER_LINKER_ID", &objcCompilerLinkerIdNode },
+ { "OBJCXX_COMPILER_LINKER_ID", &objcxxCompilerLinkerIdNode },
+ { "CUDA_COMPILER_LINKER_ID", &cudaCompilerLinkerIdNode },
+ { "Fortran_COMPILER_LINKER_ID", &fortranCompilerLinkerIdNode },
+ { "HIP_COMPILER_LINKER_ID", &hipCompilerLinkerIdNode },
+ { "C_COMPILER_LINKER_FRONTEND_VARIANT",
+ &cCompilerLinkerFrontendVariantNode },
+ { "CXX_COMPILER_LINKER_FRONTEND_VARIANT",
+ &cxxCompilerLinkerFrontendVariantNode },
+ { "CUDA_COMPILER_LINKER_FRONTEND_VARIANT",
+ &cudaCompilerLinkerFrontendVariantNode },
+ { "OBJC_COMPILER_LINKER_FRONTEND_VARIANT",
+ &objcCompilerLinkerFrontendVariantNode },
+ { "OBJCXX_COMPILER_LINKER_FRONTEND_VARIANT",
+ &objcxxCompilerLinkerFrontendVariantNode },
+ { "Fortran_COMPILER_LINKER_FRONTEND_VARIANT",
+ &fortranCompilerLinkerFrontendVariantNode },
+ { "HIP_COMPILER_LINKER_FRONTEND_VARIANT",
+ &hipCompilerLinkerFrontendVariantNode },
{ "LINK_LIBRARY", &linkLibraryNode },
{ "LINK_GROUP", &linkGroupNode },
{ "HOST_LINK", &hostLinkNode },
diff --git a/Source/cmGeneratorTarget_Sources.cxx b/Source/cmGeneratorTarget_Sources.cxx
index fa27998..ed002e4 100644
--- a/Source/cmGeneratorTarget_Sources.cxx
+++ b/Source/cmGeneratorTarget_Sources.cxx
@@ -96,10 +96,11 @@
}
cmake* cm = headTarget->GetLocalGenerator()->GetCMakeInstance();
for (auto& entryCge : fileSet->CompileFileEntries()) {
- auto tpe = cmGeneratorTarget::TargetPropertyEntry::CreateFileSet(
- dirs, contextSensitiveDirs, std::move(entryCge), fileSet);
- entries.Entries.emplace_back(
- EvaluateTargetPropertyEntry(headTarget, config, "", dagChecker, *tpe));
+ auto targetPropEntry =
+ cmGeneratorTarget::TargetPropertyEntry::CreateFileSet(
+ dirs, contextSensitiveDirs, std::move(entryCge), fileSet);
+ entries.Entries.emplace_back(EvaluateTargetPropertyEntry(
+ headTarget, config, "", dagChecker, *targetPropEntry));
EvaluatedTargetPropertyEntry const& entry = entries.Entries.back();
for (auto const& file : entry.Values) {
auto* sf = headTarget->Makefile->GetOrCreateSource(file);
diff --git a/Source/cmGlobalVisualStudio14Generator.cxx b/Source/cmGlobalVisualStudio14Generator.cxx
index 5d4ebbd..55dcf05 100644
--- a/Source/cmGlobalVisualStudio14Generator.cxx
+++ b/Source/cmGlobalVisualStudio14Generator.cxx
@@ -57,7 +57,7 @@
cmDocumentationEntry GetDocumentation() const override
{
return { std::string(vs14generatorName),
- "Generates Visual Studio 2015 project files. "
+ "Deprecated. Generates Visual Studio 2015 project files. "
"Use -A option to specify architecture." };
}
diff --git a/Source/cmGlobalVisualStudio7Generator.cxx b/Source/cmGlobalVisualStudio7Generator.cxx
index c875be0..83eff0d 100644
--- a/Source/cmGlobalVisualStudio7Generator.cxx
+++ b/Source/cmGlobalVisualStudio7Generator.cxx
@@ -308,6 +308,26 @@
this->CallVisualStudioMacro(MacroReload,
GetSLNFile(this->LocalGenerators[0].get()));
}
+
+ if (this->Version == VSVersion::VS14 &&
+ !this->CMakeInstance->GetIsInTryCompile()) {
+ std::string cmakeWarnVS14;
+ if (cmValue cached = this->CMakeInstance->GetState()->GetCacheEntryValue(
+ "CMAKE_WARN_VS14")) {
+ this->CMakeInstance->MarkCliAsUsed("CMAKE_WARN_VS14");
+ cmakeWarnVS14 = *cached;
+ } else {
+ cmSystemTools::GetEnv("CMAKE_WARN_VS14", cmakeWarnVS14);
+ }
+ if (cmakeWarnVS14.empty() || !cmIsOff(cmakeWarnVS14)) {
+ this->CMakeInstance->IssueMessage(
+ MessageType::WARNING,
+ "The \"Visual Studio 14 2015\" generator is deprecated "
+ "and will be removed in a future version of CMake."
+ "\n"
+ "Add CMAKE_WARN_VS14=OFF to the cache to disable this warning.");
+ }
+ }
}
void cmGlobalVisualStudio7Generator::OutputSLNFile(
diff --git a/Source/cmPackageInfoArguments.cxx b/Source/cmPackageInfoArguments.cxx
index 078f63d..d60e08c 100644
--- a/Source/cmPackageInfoArguments.cxx
+++ b/Source/cmPackageInfoArguments.cxx
@@ -60,6 +60,8 @@
ENFORCE_REQUIRES("PACKAGE_INFO", this->LowerCase, "LOWER_CASE_FILE");
ENFORCE_REQUIRES("PACKAGE_INFO", this->Appendix, "APPENDIX");
ENFORCE_REQUIRES("PACKAGE_INFO", this->Version, "VERSION");
+ ENFORCE_REQUIRES("PACKAGE_INFO", this->License, "LICENSE");
+ ENFORCE_REQUIRES("PACKAGE_INFO", this->DefaultLicense, "DEFAULT_LICENSE");
ENFORCE_REQUIRES("PACKAGE_INFO", this->Description, "DESCRIPTION");
ENFORCE_REQUIRES("PACKAGE_INFO", this->Website, "HOMEPAGE_URL");
ENFORCE_REQUIRES("PACKAGE_INFO", this->DefaultTargets, "DEFAULT_TARGETS");
@@ -73,6 +75,7 @@
// Check for incompatible options.
if (!this->Appendix.empty()) {
ENFORCE_EXCLUSIVE("APPENDIX", this->Version, "VERSION");
+ ENFORCE_EXCLUSIVE("APPENDIX", this->License, "LICENSE");
ENFORCE_EXCLUSIVE("APPENDIX", this->Description, "DESCRIPTION");
ENFORCE_EXCLUSIVE("APPENDIX", this->Website, "HOMEPAGE_URL");
ENFORCE_EXCLUSIVE("APPENDIX", this->DefaultTargets, "DEFAULT_TARGETS");
@@ -136,6 +139,10 @@
}
}
+ if (this->License.empty()) {
+ mapProjectValue(this->License, "SPDX_LICENSE"_s);
+ }
+
if (this->Description.empty()) {
mapProjectValue(this->Description, "DESCRIPTION"_s);
}
diff --git a/Source/cmPackageInfoArguments.h b/Source/cmPackageInfoArguments.h
index a002197..9134bc1 100644
--- a/Source/cmPackageInfoArguments.h
+++ b/Source/cmPackageInfoArguments.h
@@ -56,6 +56,8 @@
ArgumentParser::NonEmpty<std::string> Version;
ArgumentParser::NonEmpty<std::string> VersionCompat;
ArgumentParser::NonEmpty<std::string> VersionSchema;
+ ArgumentParser::NonEmpty<std::string> License;
+ ArgumentParser::NonEmpty<std::string> DefaultLicense;
ArgumentParser::NonEmpty<std::string> Description;
ArgumentParser::NonEmpty<std::string> Website;
ArgumentParser::NonEmpty<std::vector<std::string>> DefaultTargets;
@@ -84,6 +86,9 @@
&cmPackageInfoArguments::DefaultTargets);
Bind(self, parser, "DEFAULT_CONFIGURATIONS"_s,
&cmPackageInfoArguments::DefaultConfigs);
+ Bind(self, parser, "LICENSE"_s, &cmPackageInfoArguments::License);
+ Bind(self, parser, "DEFAULT_LICENSE"_s,
+ &cmPackageInfoArguments::DefaultLicense);
Bind(self, parser, "DESCRIPTION"_s, &cmPackageInfoArguments::Description);
Bind(self, parser, "HOMEPAGE_URL"_s, &cmPackageInfoArguments::Website);
diff --git a/Source/cmPackageInfoReader.cxx b/Source/cmPackageInfoReader.cxx
index dd6a13c..cffd9be 100644
--- a/Source/cmPackageInfoReader.cxx
+++ b/Source/cmPackageInfoReader.cxx
@@ -479,6 +479,14 @@
}
}
+ // Check for a default license.
+ Json::Value const& defaultLicense = reader->Data["default_license"];
+ if (!defaultLicense.isNull()) {
+ reader->DefaultLicense = defaultLicense.asString();
+ } else if (parent) {
+ reader->DefaultLicense = parent->DefaultLicense;
+ }
+
return reader;
}
@@ -582,12 +590,14 @@
}
}
-void cmPackageInfoReader::SetMetaProperty(cmTarget* target,
- cm::string_view property,
- Json::Value const& value) const
+void cmPackageInfoReader::SetMetaProperty(
+ cmTarget* target, cm::string_view property, Json::Value const& value,
+ std::string const& defaultValue) const
{
if (!value.isNull()) {
target->SetProperty(property.data(), value.asString());
+ } else if (!defaultValue.empty()) {
+ target->SetProperty(property.data(), defaultValue);
}
}
@@ -671,7 +681,8 @@
// Add other information.
if (configuration.empty()) {
- this->SetMetaProperty(target, "SPDX_LICENSE"_s, data["license"]);
+ this->SetMetaProperty(target, "SPDX_LICENSE"_s, data["license"],
+ this->DefaultLicense);
}
}
diff --git a/Source/cmPackageInfoReader.h b/Source/cmPackageInfoReader.h
index 3173f66..4597e83 100644
--- a/Source/cmPackageInfoReader.h
+++ b/Source/cmPackageInfoReader.h
@@ -98,7 +98,8 @@
cm::string_view configuration,
Json::Value const& value) const;
void SetMetaProperty(cmTarget* target, cm::string_view property,
- Json::Value const& value) const;
+ Json::Value const& value,
+ std::string const& defaultValue = {}) const;
std::string ResolvePath(std::string path) const;
@@ -108,4 +109,5 @@
std::map<std::string, cmTarget*> ComponentTargets;
std::vector<std::string> DefaultConfigurations;
+ std::string DefaultLicense;
};
diff --git a/Source/cmProjectCommand.cxx b/Source/cmProjectCommand.cxx
index 45efaa5..0835b12 100644
--- a/Source/cmProjectCommand.cxx
+++ b/Source/cmProjectCommand.cxx
@@ -38,6 +38,7 @@
cm::optional<std::string> ProjectName;
cm::optional<std::string> Version;
cm::optional<std::string> CompatVersion;
+ cm::optional<std::string> License;
cm::optional<std::string> Description;
cm::optional<std::string> HomepageURL;
cm::optional<ArgumentParser::MaybeEmpty<std::vector<std::string>>> Languages;
@@ -73,11 +74,12 @@
.Bind("LANGUAGES"_s, prArgs.Languages);
cmMakefile& mf = status.GetMakefile();
- bool enableCompatVersion = cmExperimental::HasSupportEnabled(
+ bool enablePackageInfo = cmExperimental::HasSupportEnabled(
mf, cmExperimental::Feature::ExportPackageInfo);
- if (enableCompatVersion) {
+ if (enablePackageInfo) {
parser.Bind("COMPAT_VERSION"_s, prArgs.CompatVersion);
+ parser.Bind("SPDX_LICENSE"_s, prArgs.License);
}
parser.Parse(args, &unparsedArgs, 0);
@@ -263,6 +265,7 @@
createVariables("VERSION_PATCH"_s, version_components[2]);
createVariables("VERSION_TWEAK"_s, version_components[3]);
createVariables("COMPAT_VERSION"_s, prArgs.CompatVersion.value_or(""));
+ createVariables("SPDX_LICENSE"_s, prArgs.License.value_or(""));
createVariables("DESCRIPTION"_s, prArgs.Description.value_or(""));
createVariables("HOMEPAGE_URL"_s, prArgs.HomepageURL.value_or(""));
diff --git a/Source/cmSPDXSerializer.cxx b/Source/cmSPDXSerializer.cxx
new file mode 100644
index 0000000..7d22103
--- /dev/null
+++ b/Source/cmSPDXSerializer.cxx
@@ -0,0 +1,1375 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file LICENSE.rst or https://cmake.org/licensing for details. */
+#include "cmSPDXSerializer.h"
+
+#include <new>
+#include <string>
+
+#include <cm/optional>
+
+#include <cm3p/json/value.h>
+
+// Serialization Utilities
+
+template <typename T>
+void addVectorSPDXValue(Json::Value& obj, std::string const& key,
+ std::vector<T> const& vec)
+{
+ auto& list = obj[key];
+ list = Json::Value(Json::arrayValue);
+ for (auto const& val : vec) {
+ list.append(val.toJsonLD());
+ }
+}
+
+template <>
+void addVectorSPDXValue(Json::Value& obj, std::string const& key,
+ std::vector<std::string> const& vec)
+{
+ auto& list = obj[key];
+ list = Json::Value(Json::arrayValue);
+ for (auto const& val : vec) {
+ list.append(val);
+ }
+}
+
+template <typename T>
+void addOptionalSPDXValue(Json::Value& obj, std::string const& key,
+ cm::optional<std::vector<T>> const& opt)
+{
+ if (opt) {
+ addVectorSPDXValue(obj, key, *opt);
+ }
+}
+
+template <typename T>
+void addOptionalSPDXValue(Json::Value& obj, std::string const& key,
+ cm::optional<T> const& opt)
+{
+ if (opt) {
+ obj[key] = opt->toJsonLD();
+ }
+}
+
+template <>
+void addOptionalSPDXValue(Json::Value& obj, std::string const& key,
+ cm::optional<std::string> const& opt)
+{
+ if (opt) {
+ obj[key] = *opt;
+ }
+}
+
+// Base Class
+
+cmSPDXSerializationBase::SPDXTypeId cmSPDXSerializationBase::getTypeId() const
+{
+ return TypeId;
+}
+
+cmSPDXSerializationBase::cmSPDXSerializationBase(SPDXTypeId id)
+ : TypeId(id)
+{
+}
+
+cmSPDXSerializationBase::cmSPDXSerializationBase(SPDXTypeId id,
+ std::string nodeId)
+ : NodeId(std::move(nodeId))
+ , TypeId(id)
+{
+}
+
+// Convenience Classes
+
+cmSPDXIdentifierReference::cmSPDXIdentifierReference()
+ : cmSPDXSerializationBase(CM_IDENTIFIER_REFERENCE)
+{
+}
+cmSPDXIdentifierReference::cmSPDXIdentifierReference(
+ cmSPDXSerializationBase const& ref)
+ : cmSPDXSerializationBase(CM_IDENTIFIER_REFERENCE, ref.NodeId)
+{
+}
+cmSPDXIdentifierReference::cmSPDXIdentifierReference(std::string const& ref)
+ : cmSPDXSerializationBase(CM_IDENTIFIER_REFERENCE, ref)
+{
+}
+
+Json::Value cmSPDXIdentifierReference::toJsonLD() const
+{
+ return NodeId;
+}
+
+cmSPDXNonElementBase::cmSPDXNonElementBase(SPDXTypeId id)
+ : cmSPDXSerializationBase(id)
+{
+}
+
+Json::Value cmSPDXNonElementBase::toJsonLD() const
+{
+ Json::Value obj(Json::objectValue);
+ obj["@id"] = NodeId;
+ return obj;
+}
+
+// SPDX Core Enums
+
+cmSPDXAnnotationType::cmSPDXAnnotationType(cmSPDXAnnotationTypeId typeId)
+ : TypeId(typeId)
+{
+}
+
+Json::Value cmSPDXAnnotationType::toJsonLD() const
+{
+ switch (TypeId) {
+ case OTHER:
+ return "other";
+ case REVIEW:
+ return "review";
+ default:
+ return "INVALID_ANNOTATION_TYPE_ID";
+ }
+}
+
+cmSPDXExternalIdentifierType::cmSPDXExternalIdentifierType(
+ cmSPDXExternalIdentifierTypeId typeId)
+ : TypeId(typeId)
+{
+}
+
+Json::Value cmSPDXExternalIdentifierType::toJsonLD() const
+{
+ switch (TypeId) {
+ case CPE22:
+ return "cpe22";
+ case CPE23:
+ return "cpe23";
+ case CVE:
+ return "cve";
+ case EMAIL:
+ return "email";
+ case GITOID:
+ return "gitoid";
+ case OTHER:
+ return "other";
+ case PACKAGE_URL:
+ return "packageUrl";
+ case SECURITY_OTHER:
+ return "securityOther";
+ case SWHID:
+ return "swhid";
+ case SWID:
+ return "swid";
+ case URL_SCHEME:
+ return "urlScheme";
+ default:
+ return "INVALID_EXTERNAL_IDENTIFIER_TYPE_ID";
+ }
+}
+
+cmSPDXExternalRefType::cmSPDXExternalRefType(cmSPDXExternalRefTypeId typeId)
+ : TypeId(typeId)
+{
+}
+
+Json::Value cmSPDXExternalRefType::toJsonLD() const
+{
+ switch (TypeId) {
+ case ALT_DOWNLOAD_LOCATION:
+ return "altDownloadLocation:";
+ case ALT_WEB_PAGE:
+ return "altWebPage";
+ case BINARY_ARTIFACT:
+ return "binaryArtifact";
+ case BOWER:
+ return "bower";
+ case BUILD_META:
+ return "buildMeta";
+ case BUILD_SYSTEM:
+ return "buildSystem";
+ case CERTIFICATION_REPORT:
+ return "certificationReport";
+ case CHAT:
+ return "chat";
+ case COMPONENT_ANALYSIS_REPORT:
+ return "componentAnalysisReport";
+ case CWE:
+ return "cwe";
+ case DOCUMENTATION:
+ return "documentation";
+ case DYNAMIC_ANALYSIS_REPORT:
+ return "dynamicAnalysisReport";
+ case EOL_NOTICE:
+ return "eolNotice";
+ case EXPORT_CONTROL_ASSESSMENT:
+ return "exportControlAssessment";
+ case FUNDING:
+ return "funding";
+ case ISSUE_TRACKER:
+ return "issueTracker";
+ case LICENSE:
+ return "license";
+ case MAILING_LIST:
+ return "mailingList";
+ case MAVEN_CENTRAL:
+ return "mavenCentral";
+ case METRICS:
+ return "metrics";
+ case NPM:
+ return "npm";
+ case NUGET:
+ return "nuget";
+ case OTHER:
+ return "other";
+ case PRIVACY_ASSESSMENT:
+ return "privacyAssessment";
+ case PRODUCT_METADATA:
+ return "productMetadata";
+ case PURCHASE_ORDER:
+ return "purchaseOrder";
+ case QUALITY_ASSESSMENT_REPORT:
+ return "qualityAssessmentReport";
+ case RELEASE_HISTORY:
+ return "releaseHistory";
+ case RELEASE_NOTES:
+ return "releaseNotes";
+ case RISK_ASSESSMENT:
+ return "riskAssessment";
+ case RUNTIME_ANALYSIS_REPORT:
+ return "runtimeAnalysisReport";
+ case SECURE_SOFTWARE_ATTESTATION:
+ return "secureSoftwareAttestation";
+ case SECURITY_ADVERSARY_MODEL:
+ return "securityAdversaryModel";
+ case SECURITY_ADVISORY:
+ return "securityAdvisory";
+ case SECURITY_FIX:
+ return "securityFix";
+ case SECURITY_OTHER:
+ return "securityOther";
+ case SECURITY_PEN_TEST_REPORT:
+ return "securityPenTestReport";
+ case SECURITY_POLICY:
+ return "securityPolicy";
+ case SECURITY_THREAT_MODEL:
+ return "securityThreatModel";
+ case SOCIAL_MEDIA:
+ return "socialMedia";
+ case SOURCE_ARTIFACT:
+ return "sourceArtifact";
+ case STATIC_ANALYSIS_REPORT:
+ return "staticAnalysisReport";
+ case SUPPORT:
+ return "support";
+ case VCS:
+ return "vcs";
+ case VULNERABILITY_DISCLOSURE_REPORT:
+ return "vulnerabilityDisclosureReport";
+ case VULNERABILITY_EXPLOITABILITY_ASSESSMENT:
+ return "vulnerabilityExploitabilityAssessment";
+ default:
+ return "INVALID_EXTERNAL_REF_TYPE_ID";
+ }
+}
+
+cmSPDXHashAlgorithm::cmSPDXHashAlgorithm(cmSPDXHashAlgorithmId typeId)
+ : TypeId(typeId)
+{
+}
+
+Json::Value cmSPDXHashAlgorithm::toJsonLD() const
+{
+ switch (TypeId) {
+ case ADLER32:
+ return "adler32";
+ case BLAKE2B256:
+ return "blake2b256";
+ case BLAKE2B384:
+ return "blake2b384";
+ case BLAKE2B512:
+ return "blake2b512";
+ case BLAKE3:
+ return "blake3";
+ case CRYSTALS_DILITHIUM:
+ return "crystalsDilithium";
+ case CRYSTALS_KYBER:
+ return "crystalsLyber";
+ case FALCON:
+ return "falcon";
+ case MD2:
+ return "md2";
+ case MD4:
+ return "md4";
+ case MD5:
+ return "md5";
+ case MD6:
+ return "md6";
+ case OTHER:
+ return "other";
+ case SHA1:
+ return "sha1";
+ case SHA224:
+ return "sha224";
+ case SHA256:
+ return "sha256";
+ case SHA384:
+ return "sha384";
+ case SHA3_224:
+ return "sha3_224";
+ case SHA3_256:
+ return "sha3_256";
+ case SHA3_384:
+ return "sha3_384";
+ case SHA3_512:
+ return "sha3_512";
+ case SHA512:
+ return "sha512";
+ default:
+ return "INVALID_HASH_TYPE_ID";
+ }
+}
+
+cmSPDXLifecycleScopeType::cmSPDXLifecycleScopeType(
+ cmSPDXLifecycleScopeTypeId typeId)
+ : TypeId(typeId)
+{
+}
+
+Json::Value cmSPDXLifecycleScopeType::toJsonLD() const
+{
+ switch (TypeId) {
+ case BUILD:
+ return "build";
+ case DESIGN:
+ return "design";
+ case DEVELOPMENT:
+ return "development";
+ case OTHER:
+ return "other";
+ case RUNTIME:
+ return "runtime";
+ case TEST:
+ return "test";
+ default:
+ return "INVALID_LIFECYCLE_SCOPE_TYPE_ID";
+ }
+}
+
+cmSPDXProfileIdentifierType::cmSPDXProfileIdentifierType(
+ cmSPDXProfileIdentifierTypeId typeId)
+ : TypeId(typeId)
+{
+}
+
+Json::Value cmSPDXProfileIdentifierType::toJsonLD() const
+{
+ switch (TypeId) {
+ case AI:
+ return "ai";
+ case BUILD:
+ return "build";
+ case CORE:
+ return "code";
+ case DATASET:
+ return "dataset";
+ case EXPANDED_LICENSING:
+ return "expandedLicensing";
+ case EXTENSION:
+ return "extension";
+ case LITE:
+ return "lite";
+ case SECURITY:
+ return "security";
+ case SIMPLE_LICENSING:
+ return "simpleLicensing";
+ case SOFTWARE:
+ return "software";
+ default:
+ return "INVALID_PROFILE_IDENTIFIER_TYPE_ID";
+ }
+}
+
+cmSPDXRelationshipCompletenessType::cmSPDXRelationshipCompletenessType(
+ cmSPDXRelationshipCompletenessTypeId typeId)
+ : TypeId(typeId)
+{
+}
+
+Json::Value cmSPDXRelationshipCompletenessType::toJsonLD() const
+{
+ switch (TypeId) {
+ case COMPLETE:
+ return "complete";
+ case INCOMPLETE:
+ return "incomplete";
+ case NO_ASSERTION:
+ return "noAssertion";
+ default:
+ return "INVALID_RELATIONSHIP_COMPLETENESS_TYPE_ID";
+ }
+}
+
+cmSPDXRelationshipType::cmSPDXRelationshipType(cmSPDXRelationshipTypeId typeId)
+ : TypeId(typeId)
+{
+}
+
+Json::Value cmSPDXRelationshipType::toJsonLD() const
+{
+ switch (TypeId) {
+ case AFFECTS:
+ return "affects";
+ case AMENDED_BY:
+ return "amendedBy";
+ case ANCESTOR_OF:
+ return "ancestorOf";
+ case AVAILABLE_FROM:
+ return "availableFrom";
+ case CONFIGURES:
+ return "configures";
+ case CONTAINS:
+ return "contains";
+ case COORDINATED_BY:
+ return "coordinatedBy";
+ case COPIED_TO:
+ return "copiedTo";
+ case DELEGATED_TO:
+ return "delegatedTo";
+ case DEPENDS_ON:
+ return "dependsOn";
+ case DESCENDANT_OF:
+ return "descendantOf";
+ case DESCRIBES:
+ return "describes";
+ case DOES_NOT_AFFECT:
+ return "doesNotAffect";
+ case EXPANDS_TO:
+ return "expandsTo";
+ case EXPLOIT_CREATED_BY:
+ return "exploitCreatedBy";
+ case FIXED_BY:
+ return "fixedBy";
+ case FIXED_IN:
+ return "fixedIn";
+ case FOUND_BY:
+ return "foundBy";
+ case GENERATES:
+ return "generates";
+ case HAS_ADDED_FILE:
+ return "hasAddedFile";
+ case HAS_ASSESSMENT_FOR:
+ return "hasAssessmentFor";
+ case HAS_ASSOCIATED_VULNERABILITY:
+ return "hasAssociatedVulnerability";
+ case HAS_CONCLUDED_LICENSE:
+ return "hasConcludedLicense";
+ case HAS_DATA_FILE:
+ return "hasDataFile";
+ case HAS_DECLARED_LICENSE:
+ return "hasDeclaredLicense";
+ case HAS_DELETED_FILE:
+ return "hasDeletedFile";
+ case HAS_DEPENDENCY_MANIFEST:
+ return "hasDependencyManifest";
+ case HAS_DISTRIBUTION_ARTIFACT:
+ return "hasDistributionArtifact";
+ case HAS_DOCUMENTATION:
+ return "hasDocumentation";
+ case HAS_DYNAMIC_LINK:
+ return "hasDynamicLink";
+ case HAS_EVIDENCE:
+ return "hasEvidence";
+ case HAS_EXAMPLE:
+ return "hasExample";
+ case HAS_HOST:
+ return "hasHost";
+ case HAS_INPUT:
+ return "hasInput";
+ case HAS_METADATA:
+ return "hasMetadata";
+ case HAS_OPTIONAL_COMPONENT:
+ return "hasOptionalComponent";
+ case HAS_OPTIONAL_DEPENDENCY:
+ return "hasOptionalDependency";
+ case HAS_OUTPUT:
+ return "hasOutput";
+ case HAS_PREREQUISITE:
+ return "hasPrerequisite";
+ case HAS_PROVIDED_DEPENDENCY:
+ return "hasProvidedDependency";
+ case HAS_REQUIREMENT:
+ return "hasRequirement";
+ case HAS_SPECIFICATION:
+ return "hasSpecification";
+ case HAS_STATIC_LINK:
+ return "hasStaticLink";
+ case HAS_TEST:
+ return "hasTest";
+ case HAS_TEST_CASE:
+ return "hasTestCase";
+ case HAS_VARIANT:
+ return "hasVariant";
+ case INVOKED_BY:
+ return "invokedBy";
+ case MODIFIED_BY:
+ return "modifiedBy";
+ case OTHER:
+ return "other";
+ case PACKAGED_BY:
+ return "packagedBy";
+ case PATCHED_BY:
+ return "patchedBy";
+ case PUBLISHED_BY:
+ return "publishedBy";
+ case REPORTED_BY:
+ return "reportedBy";
+ case REPUBLISHED_BY:
+ return "republishedBy";
+ case SERIALIZED_IN_ARTIFACT:
+ return "serializedInArtifact";
+ case TESTED_ON:
+ return "testedOn";
+ case TRAINED_ON:
+ return "trainedOn";
+ case UNDER_INVESTIGATION_FOR:
+ return "underInvestigationFor";
+ case USES_TOOL:
+ return "usesTool";
+ default:
+ return "INVALID_RELATIONSHIP_TYPE_ID";
+ }
+}
+
+cmSPDXSupportType::cmSPDXSupportType(cmSPDXSupportTypeId typeId)
+ : TypeId(typeId)
+{
+}
+
+Json::Value cmSPDXSupportType::toJsonLD() const
+{
+ switch (TypeId) {
+ case DEPLOYED:
+ return "deployed";
+ case DEVELOPMENT:
+ return "development";
+ case END_OF_SUPPORT:
+ return "endOfSupport";
+ case LIMITED_SUPPORT:
+ return "limitedSupport";
+ case NO_ASSERTION:
+ return "noAssertion";
+ case NO_SUPPORT:
+ return "noSupport";
+ case SUPPORT:
+ return "support";
+ default:
+ return "INVALID_SUPPORT_TYPE_ID";
+ }
+}
+
+// SPDX Core NonElement Classes, Abstract
+
+cmSPDXIntegrityMethod::cmSPDXIntegrityMethod(SPDXTypeId id)
+ : cmSPDXNonElementBase(id)
+{
+}
+
+Json::Value cmSPDXIntegrityMethod::toJsonLD() const
+{
+ auto obj = cmSPDXNonElementBase::toJsonLD();
+ addOptionalSPDXValue(obj, "comment", Comment);
+ return obj;
+}
+
+// SPDX Core NonElement Classes, Concrete
+
+cmSPDXCreationInfo::cmSPDXCreationInfo()
+ : cmSPDXNonElementBase(CORE_CREATION_INFO)
+{
+}
+
+Json::Value cmSPDXCreationInfo::toJsonLD() const
+{
+ auto obj = cmSPDXNonElementBase::toJsonLD();
+ obj["type"] = "CreationInfo";
+ addOptionalSPDXValue(obj, "Comment", Comment);
+ obj["created"] = Created;
+ addVectorSPDXValue(obj, "createdBy", CreatedBy);
+ addOptionalSPDXValue(obj, "createdUsing", CreatedUsing);
+ return obj;
+}
+
+cmSPDXDictionaryEntry::cmSPDXDictionaryEntry()
+ : cmSPDXNonElementBase(CORE_DICTIONARY_ENTRY)
+{
+}
+cmSPDXDictionaryEntry::cmSPDXDictionaryEntry(std::string key)
+ : cmSPDXNonElementBase(CORE_DICTIONARY_ENTRY)
+ , Key(std::move(key))
+{
+}
+cmSPDXDictionaryEntry::cmSPDXDictionaryEntry(std::string key, std::string val)
+ : cmSPDXNonElementBase(CORE_DICTIONARY_ENTRY)
+ , Key(std::move(key))
+ , Value(std::move(val))
+{
+}
+
+Json::Value cmSPDXDictionaryEntry::toJsonLD() const
+{
+ auto obj = cmSPDXNonElementBase::toJsonLD();
+ obj["type"] = "DictionaryEntry";
+ obj["key"] = Key;
+ addOptionalSPDXValue(obj, "value", Value);
+ return obj;
+}
+
+cmSPDXExternalIdentifier::cmSPDXExternalIdentifier()
+ : cmSPDXNonElementBase(CORE_EXTERNAL_IDENTIFIER)
+{
+}
+
+Json::Value cmSPDXExternalIdentifier::toJsonLD() const
+{
+ auto obj = cmSPDXNonElementBase::toJsonLD();
+ obj["type"] = "ExternalIdentifier";
+ addOptionalSPDXValue(obj, "comment", Comment);
+ obj["externalIdentifierType"] = ExternalIdentifierType.toJsonLD();
+ obj["identifier"] = Identifier;
+ addOptionalSPDXValue(obj, "identifierLocator", IdentifierLocator);
+ addOptionalSPDXValue(obj, "issuingAuthority", IssuingAuthority);
+ return obj;
+}
+
+cmSPDXExternalMap::cmSPDXExternalMap()
+ : cmSPDXNonElementBase(CORE_EXTERNAL_MAP)
+{
+}
+
+Json::Value cmSPDXExternalMap::toJsonLD() const
+{
+ auto obj = cmSPDXNonElementBase::toJsonLD();
+ obj["type"] = "ExternalMap";
+ addOptionalSPDXValue(obj, "definingArtifact", DefiningArtifact);
+ obj["externalSpdxId"] = ExternalSpdxId;
+ addOptionalSPDXValue(obj, "locationHint", LocationHint);
+ addOptionalSPDXValue(obj, "integrityMethod", IntegrityMethod);
+ return obj;
+}
+
+cmSPDXExternalRef::cmSPDXExternalRef()
+ : cmSPDXNonElementBase(CORE_EXTERNAL_REF)
+{
+}
+
+Json::Value cmSPDXExternalRef::toJsonLD() const
+{
+ auto obj = cmSPDXNonElementBase::toJsonLD();
+ obj["type"] = "ExternalRef";
+ addOptionalSPDXValue(obj, "comment", Comment);
+ addOptionalSPDXValue(obj, "contentType", ContentType);
+ addOptionalSPDXValue(obj, "externalRefType", ExternalRefType);
+ addOptionalSPDXValue(obj, "locator", Locator);
+ return obj;
+}
+
+cmSPDXHash::cmSPDXHash()
+ : cmSPDXIntegrityMethod(CORE_HASH)
+{
+}
+
+Json::Value cmSPDXHash::toJsonLD() const
+{
+ auto obj = cmSPDXIntegrityMethod::toJsonLD();
+ obj["type"] = "Hash";
+ obj["algorithm"] = Algorithm.toJsonLD();
+ obj["hashValue"] = HashValue;
+ return obj;
+}
+
+cmSPDXNamespaceMap::cmSPDXNamespaceMap()
+ : cmSPDXNonElementBase(CORE_NAMESPACE_MAP)
+{
+}
+
+Json::Value cmSPDXNamespaceMap::toJsonLD() const
+{
+ auto obj = cmSPDXNonElementBase::toJsonLD();
+ obj["type"] = "NamespaceMap";
+ obj["namespace"] = Namespace;
+ obj["prefix"] = Namespace;
+ return obj;
+}
+
+cmSPDXPackageVerificationCode::cmSPDXPackageVerificationCode()
+ : cmSPDXIntegrityMethod(CORE_PACKAGE_VERIFICATION_CODE)
+{
+}
+
+Json::Value cmSPDXPackageVerificationCode::toJsonLD() const
+{
+ auto obj = cmSPDXIntegrityMethod::toJsonLD();
+ obj["type"] = "PackageVerificationCode";
+ obj["algorithm"] = Algorithm.toJsonLD();
+ obj["hashValue"] = HashValue;
+ return obj;
+}
+
+cmSPDXPositiveIntegerRange::cmSPDXPositiveIntegerRange(
+ unsigned int beingIntegerRange, unsigned int endIntegerRange)
+ : cmSPDXNonElementBase(CORE_POSITIVE_INTEGER_RANGE)
+ , BeginIntegerRange(beingIntegerRange)
+ , EndIntegerRange(endIntegerRange)
+{
+}
+
+Json::Value cmSPDXPositiveIntegerRange::toJsonLD() const
+{
+ auto obj = cmSPDXNonElementBase::toJsonLD();
+ obj["type"] = "PositiveIntegerRange";
+ obj["beginIntegerRange"] = BeginIntegerRange;
+ obj["endIntegerRange"] = EndIntegerRange;
+ return obj;
+}
+
+// SPDX Core Element Classes, Abstract
+
+cmSPDXElement::cmSPDXElement(SPDXTypeId id,
+ cmSPDXCreationInfo const& creationInfo)
+ : cmSPDXSerializationBase(id)
+ , CreationInfo(creationInfo)
+{
+}
+
+Json::Value cmSPDXElement::toJsonLD() const
+{
+ Json::Value obj(Json::objectValue);
+ addOptionalSPDXValue(obj, "comment", Comment);
+ obj["creationInfo"] = CreationInfo.toJsonLD();
+ addOptionalSPDXValue(obj, "description", Description);
+ addOptionalSPDXValue(obj, "extension", Extension);
+ addOptionalSPDXValue(obj, "externalIdentifier", ExternalIdentifier);
+ addOptionalSPDXValue(obj, "externalRef", ExternalRef);
+ addOptionalSPDXValue(obj, "name", Name);
+ obj["spdxId"] = NodeId;
+ addOptionalSPDXValue(obj, "summary", Summary);
+ addOptionalSPDXValue(obj, "verifiedUsing", VerifiedUsing);
+ return obj;
+}
+
+cmSPDXArtifact::cmSPDXArtifact(SPDXTypeId id,
+ cmSPDXCreationInfo const& creationInfo)
+ : cmSPDXElement(id, creationInfo)
+{
+}
+
+Json::Value cmSPDXArtifact::toJsonLD() const
+{
+ auto obj = cmSPDXElement::toJsonLD();
+ addOptionalSPDXValue(obj, "builtTime", BuiltTime);
+ addOptionalSPDXValue(obj, "originateBy", OriginatedBy);
+ addOptionalSPDXValue(obj, "releaseTime", ReleaseTime);
+ addOptionalSPDXValue(obj, "standardName", StandardName);
+ addOptionalSPDXValue(obj, "suppliedBy", SuppliedBy);
+ addOptionalSPDXValue(obj, "supportType", SupportType);
+ addOptionalSPDXValue(obj, "validUntilTime", ValidUntilTime);
+ return obj;
+}
+
+cmSPDXElementCollection::cmSPDXElementCollection(
+ SPDXTypeId id, cmSPDXCreationInfo const& creationInfo)
+ : cmSPDXElement(id, creationInfo)
+{
+}
+
+Json::Value cmSPDXElementCollection::toJsonLD() const
+{
+ auto obj = cmSPDXElement::toJsonLD();
+ addOptionalSPDXValue(obj, "element", Element);
+ addOptionalSPDXValue(obj, "profileConformance", ProfileConformance);
+ addOptionalSPDXValue(obj, "rootElement", RootElement);
+ return obj;
+}
+
+// SPDX Implicit Core Element Classes, Abstract
+
+// Nominally an inheritable class, but adds nothing to Element
+using cmSPDXAgentAbstract = cmSPDXElement;
+
+cmSPDXBundleAbstract::cmSPDXBundleAbstract(
+ SPDXTypeId id, cmSPDXCreationInfo const& creationInfo)
+ : cmSPDXElementCollection(id, creationInfo)
+{
+}
+
+Json::Value cmSPDXBundleAbstract::toJsonLD() const
+{
+ auto obj = cmSPDXElementCollection::toJsonLD();
+ obj["context"] = Context;
+ return obj;
+}
+
+// Nominally an inheritable class, but adds nothing to Bundle
+using cmSPDXBomAbstract = cmSPDXBundleAbstract;
+
+cmSPDXRelationshipAbstract::cmSPDXRelationshipAbstract(
+ SPDXTypeId id, cmSPDXCreationInfo const& creationInfo)
+ : cmSPDXElement(id, creationInfo)
+{
+}
+
+Json::Value cmSPDXRelationshipAbstract::toJsonLD() const
+{
+ auto obj = cmSPDXElement::toJsonLD();
+ addOptionalSPDXValue(obj, "completeness", Completeness);
+ addOptionalSPDXValue(obj, "endTime", EndTime);
+ obj["from"] = From.toJsonLD();
+ obj["relationshipType"] = RelationshipType.toJsonLD();
+ addOptionalSPDXValue(obj, "startTime", StartTime);
+ addVectorSPDXValue(obj, "to", To);
+ return obj;
+}
+
+// SPDX Core Element Classes, Concrete
+
+cmSPDXAgent::cmSPDXAgent(cmSPDXCreationInfo const& creationInfo)
+ : cmSPDXAgentAbstract(CORE_AGENT, creationInfo)
+{
+}
+
+Json::Value cmSPDXAgent::toJsonLD() const
+{
+ auto obj = cmSPDXAgentAbstract::toJsonLD();
+ obj["type"] = "Agent";
+ return obj;
+}
+
+cmSPDXAnnotation::cmSPDXAnnotation(cmSPDXCreationInfo const& creationInfo,
+ cmSPDXIdentifierReference subject)
+ : cmSPDXElement(CORE_ANNOTATION, creationInfo)
+ , Subject(std::move(subject))
+{
+}
+
+Json::Value cmSPDXAnnotation::toJsonLD() const
+{
+ auto obj = cmSPDXElement::toJsonLD();
+ obj["type"] = "Annotation";
+ obj["annotationType"] = AnnotationType.toJsonLD();
+ addOptionalSPDXValue(obj, "contentType", ContentType);
+ addOptionalSPDXValue(obj, "statement", Statement);
+ obj["subject"] = Subject.toJsonLD();
+ return obj;
+}
+
+cmSPDXBom::cmSPDXBom(cmSPDXCreationInfo const& creationInfo)
+ : cmSPDXBomAbstract(CORE_BOM, creationInfo)
+{
+}
+
+Json::Value cmSPDXBom::toJsonLD() const
+{
+ auto obj = cmSPDXBomAbstract::toJsonLD();
+ obj["type"] = "Bom";
+ return obj;
+}
+
+cmSPDXBundle::cmSPDXBundle(cmSPDXCreationInfo const& creationInfo)
+ : cmSPDXBundleAbstract(CORE_BUNDLE, creationInfo)
+{
+}
+
+Json::Value cmSPDXBundle::toJsonLD() const
+{
+ auto obj = cmSPDXBundleAbstract::toJsonLD();
+ obj["type"] = "Bundle";
+ return obj;
+}
+
+cmSPDXIndividualElement::cmSPDXIndividualElement(
+ cmSPDXCreationInfo const& creationInfo)
+ : cmSPDXElement(CORE_INDIVIDUAL_ELEMENT, creationInfo)
+{
+}
+
+Json::Value cmSPDXIndividualElement::toJsonLD() const
+{
+ auto obj = cmSPDXElement::toJsonLD();
+ obj["type"] = "IndividualElement";
+ return obj;
+}
+
+cmSPDXLifecycleScopedRelationship::cmSPDXLifecycleScopedRelationship(
+ cmSPDXCreationInfo const& creationInfo)
+ : cmSPDXRelationshipAbstract(CORE_LIFECYCLE_SCOPED_RELATIONSHIP,
+ creationInfo)
+{
+}
+
+Json::Value cmSPDXLifecycleScopedRelationship::toJsonLD() const
+{
+ auto obj = cmSPDXRelationshipAbstract::toJsonLD();
+ obj["type"] = "LifecycleScopedRelationship";
+ addOptionalSPDXValue(obj, "scope", Scope);
+ return obj;
+}
+
+cmSPDXOrganization::cmSPDXOrganization(cmSPDXCreationInfo const& creationInfo)
+ : cmSPDXAgentAbstract(CORE_ORGANIZATION, creationInfo)
+{
+}
+
+Json::Value cmSPDXOrganization::toJsonLD() const
+{
+ auto obj = cmSPDXAgentAbstract::toJsonLD();
+ obj["type"] = "Organization";
+ return obj;
+}
+
+cmSPDXPerson::cmSPDXPerson(cmSPDXCreationInfo const& creationInfo)
+ : cmSPDXAgentAbstract(CORE_PERSON, creationInfo)
+{
+}
+
+Json::Value cmSPDXPerson::toJsonLD() const
+{
+ auto obj = cmSPDXAgentAbstract::toJsonLD();
+ obj["type"] = "Person";
+ return obj;
+}
+
+cmSPDXRelationship::cmSPDXRelationship(cmSPDXCreationInfo const& creationInfo)
+ : cmSPDXRelationshipAbstract(CORE_RELATIONSHIP, creationInfo)
+{
+}
+
+Json::Value cmSPDXRelationship::toJsonLD() const
+{
+ auto obj = cmSPDXRelationshipAbstract::toJsonLD();
+ obj["type"] = "Relationship";
+ return obj;
+}
+
+cmSPDXSoftwareAgent::cmSPDXSoftwareAgent(
+ cmSPDXCreationInfo const& creationInfo)
+ : cmSPDXAgentAbstract(CORE_SOFTWARE_AGENT, creationInfo)
+{
+}
+
+Json::Value cmSPDXSoftwareAgent::toJsonLD() const
+{
+ auto obj = cmSPDXAgentAbstract::toJsonLD();
+ obj["type"] = "SoftwareAgent";
+ return obj;
+}
+
+cmSPDXSpdxDocument::cmSPDXSpdxDocument(cmSPDXCreationInfo const& creationInfo)
+ : cmSPDXElementCollection(CORE_SPDX_DOCUMENT, creationInfo)
+{
+}
+
+Json::Value cmSPDXSpdxDocument::toJsonLD() const
+{
+ auto obj = cmSPDXElementCollection::toJsonLD();
+ obj["type"] = "SpdxDocument";
+ addOptionalSPDXValue(obj, "dataLicense", DataLicense);
+ addOptionalSPDXValue(obj, "externalMap", ExternalMap);
+ addOptionalSPDXValue(obj, "namespaceMap", NamespaceMap);
+ return obj;
+}
+
+cmSPDXTool::cmSPDXTool(cmSPDXCreationInfo const& creationInfo)
+ : cmSPDXElement(CORE_TOOL, creationInfo)
+{
+}
+
+Json::Value cmSPDXTool::toJsonLD() const
+{
+ auto obj = cmSPDXElement::toJsonLD();
+ obj["type"] = "Tool";
+ return obj;
+}
+
+// SPDX Software Enums
+
+cmSPDXContentIdentifierType::cmSPDXContentIdentifierType(
+ cmSPDXContentIdentifierTypeId typeId)
+ : TypeId(typeId)
+{
+}
+
+Json::Value cmSPDXContentIdentifierType::toJsonLD() const
+{
+ switch (TypeId) {
+ case GITOID:
+ return "gitoid";
+ case SWHID:
+ return "swhid";
+ default:
+ return "INVALID_CONTENT_IDENTIFIER_TYPE_ID";
+ }
+}
+
+cmSPDXFileKindType::cmSPDXFileKindType(cmSPDXFileKindTypeId typeId)
+ : TypeId(typeId)
+{
+}
+
+Json::Value cmSPDXFileKindType::toJsonLD() const
+{
+ switch (TypeId) {
+ case DIRECTORY:
+ return "directory";
+ case FILE:
+ return "file";
+ default:
+ return "INVALID_FILE_KIND_TYPE_ID";
+ }
+}
+
+cmSPDXSbomType::cmSPDXSbomType(cmSPDXSbomTypeId typeId)
+ : TypeId(typeId)
+{
+}
+
+Json::Value cmSPDXSbomType::toJsonLD() const
+{
+ switch (TypeId) {
+ case ANALYZED:
+ return "analyzed";
+ case BUILD:
+ return "build";
+ case DEPLOYED:
+ return "deployed";
+ case DESIGN:
+ return "design";
+ case RUNTIME:
+ return "runtime";
+ case SOURCE:
+ return "source";
+ default:
+ return "INVALID_SBOM_TYPE_ID";
+ }
+}
+
+cmSPDXSoftwarePurpose::cmSPDXSoftwarePurpose(cmSPDXSoftwarePurposeId typeId)
+ : TypeId(typeId)
+{
+}
+
+Json::Value cmSPDXSoftwarePurpose::toJsonLD() const
+{
+ switch (TypeId) {
+ case APPLICATION:
+ return "application";
+ case ARCHIVE:
+ return "archive";
+ case BOM:
+ return "bom";
+ case CONFIGURATION:
+ return "configuration";
+ case CONTAINER:
+ return "container";
+ case DATA:
+ return "data";
+ case DEVICE:
+ return "device";
+ case DEVICE_DRIVER:
+ return "deviceDriver";
+ case DISK_IMAGE:
+ return "diskImage";
+ case DOCUMENTATION:
+ return "documentation";
+ case EVIDENCE:
+ return "evidence";
+ case EXECUTABLE:
+ return "executable";
+ case FILE:
+ return "file";
+ case FILESYSTEM_IMAGE:
+ return "filesystemImage";
+ case FIRMWARE:
+ return "firmware";
+ case FRAMEWORK:
+ return "framework";
+ case INSTALL:
+ return "install";
+ case LIBRARY:
+ return "library";
+ case MANIFEST:
+ return "manifest";
+ case MODEL:
+ return "model";
+ case MODULE:
+ return "module";
+ case OPERATING_SYSTEM:
+ return "operatingSystem";
+ case OTHER:
+ return "other";
+ case PATCH:
+ return "patch";
+ case PLATFORM:
+ return "platform";
+ case REQUIREMENT:
+ return "requirement";
+ case SOURCE:
+ return "source";
+ case SPECIFICATION:
+ return "specification";
+ case TEST:
+ return "test";
+ default:
+ return "INVALID_SOFTWARE_PURPOSE_ID";
+ }
+}
+
+// SPDX Software NonElement Classes, Concrete
+
+cmSPDXContentIdentifier::cmSPDXContentIdentifier()
+ : cmSPDXIntegrityMethod(SOFTWARE_CONTENT_IDENTIFIER)
+{
+}
+
+Json::Value cmSPDXContentIdentifier::toJsonLD() const
+{
+ auto obj = cmSPDXIntegrityMethod::toJsonLD();
+ obj["type"] = "ContentIdentifier";
+ obj["contentIdentifierType"] = ContentIdentifierType.toJsonLD();
+ obj["contentIdentifierValue"] = ContentIdentifierValue;
+ return obj;
+}
+
+// SPDX Software Element Classes, Abstract
+
+cmSPDXSoftwareArtifact::cmSPDXSoftwareArtifact(
+ SPDXTypeId id, cmSPDXCreationInfo const& creationInfo)
+ : cmSPDXArtifact(id, creationInfo)
+{
+}
+
+Json::Value cmSPDXSoftwareArtifact::toJsonLD() const
+{
+ auto obj = cmSPDXArtifact::toJsonLD();
+ addOptionalSPDXValue(obj, "additionalPurpose", AdditionalPurpose);
+ addOptionalSPDXValue(obj, "attributionText", AttributionText);
+ addOptionalSPDXValue(obj, "contentIdentifier", ContentIdentifier);
+ addOptionalSPDXValue(obj, "copyrightText", CopyrightText);
+ addOptionalSPDXValue(obj, "primaryPurpose", PrimaryPurpose);
+ return obj;
+}
+
+// SPDX Software Element Classes, Concrete
+
+cmSPDXFile::cmSPDXFile(cmSPDXCreationInfo const& creationInfo)
+ : cmSPDXSoftwareArtifact(SOFTWARE_FILE, creationInfo)
+{
+}
+
+Json::Value cmSPDXFile::toJsonLD() const
+{
+ auto obj = cmSPDXSoftwareArtifact::toJsonLD();
+ obj["type"] = "File";
+ addOptionalSPDXValue(obj, "contentType", ContentType);
+ addOptionalSPDXValue(obj, "fileKind", FileKind);
+ return obj;
+}
+
+cmSPDXPackage::cmSPDXPackage(cmSPDXCreationInfo const& creationInfo)
+ : cmSPDXSoftwareArtifact(SOFTWARE_PACKAGE, creationInfo)
+{
+}
+
+Json::Value cmSPDXPackage::toJsonLD() const
+{
+ auto obj = cmSPDXSoftwareArtifact::toJsonLD();
+ obj["type"] = "Package";
+ addOptionalSPDXValue(obj, "downloadLocation", DownloadLocation);
+ addOptionalSPDXValue(obj, "homePage", HomePage);
+ addOptionalSPDXValue(obj, "packageUrl", PackageUrl);
+ addOptionalSPDXValue(obj, "packageVersion", PackageVersion);
+ addOptionalSPDXValue(obj, "sourceInfo", SourceInfo);
+ return obj;
+}
+
+cmSPDXSbom::cmSPDXSbom(cmSPDXCreationInfo const& creationInfo)
+ : cmSPDXBomAbstract(SOFTWARE_SBOM, creationInfo)
+{
+}
+
+Json::Value cmSPDXSbom::toJsonLD() const
+{
+ auto obj = cmSPDXBomAbstract::toJsonLD();
+ obj["type"] = "Sbom";
+ addOptionalSPDXValue(obj, "sbomType", SbomType);
+ return obj;
+}
+
+cmSPDXSnippet::cmSPDXSnippet(cmSPDXCreationInfo const& creationInfo)
+ : cmSPDXSoftwareArtifact(SOFTWARE_SNIPPET, creationInfo)
+{
+}
+
+Json::Value cmSPDXSnippet::toJsonLD() const
+{
+ auto obj = cmSPDXSoftwareArtifact::toJsonLD();
+ obj["type"] = "Snippet";
+ addOptionalSPDXValue(obj, "byteRange", ByteRange);
+ addOptionalSPDXValue(obj, "lineRange", LineRange);
+ obj["snippetFromFile"] = SnippetFromFile.toJsonLD();
+ return obj;
+}
+
+// SPDX SimpleLicensing Element Classes, Concrete
+
+cmSPDXLicenseExpression::cmSPDXLicenseExpression(
+ cmSPDXCreationInfo const& creationInfo)
+ : cmSPDXAnyLicenseInfo(SIMPLE_LICENSING_LICENSE_EXPRESSION, creationInfo)
+{
+}
+
+Json::Value cmSPDXLicenseExpression::toJsonLD() const
+{
+ auto obj = cmSPDXAnyLicenseInfo::toJsonLD();
+ obj["type"] = "LicenseExpression";
+ addOptionalSPDXValue(obj, "customIdToUri", CustomIdToUri);
+ obj["licenseExpression"] = LicenseExpression;
+ addOptionalSPDXValue(obj, "licenseListVersion", LicenseListVersion);
+ return obj;
+}
+
+cmSPDXSimpleLicensingText::cmSPDXSimpleLicensingText(
+ cmSPDXCreationInfo const& creationInfo)
+ : cmSPDXElement(SIMPLE_LICENSING_SIMPLE_LICENSING_TEXT, creationInfo)
+{
+}
+
+Json::Value cmSPDXSimpleLicensingText::toJsonLD() const
+{
+ auto obj = cmSPDXElement::toJsonLD();
+ obj["type"] = "SimpleLicensingText";
+ obj["licenseText"] = LicenseText;
+ return obj;
+}
+
+// Graph Manipulation
+
+#define X_SPDX(classtype, enumid, member, camel) \
+ template <> \
+ cmSPDXSerializationBase::SPDXTypeId cmSPDXGetTypeId<classtype>() \
+ { \
+ return cmSPDXSerializationBase::enumid; \
+ } \
+ \
+ template <> \
+ std::string cmSPDXGetTypeName<classtype>() \
+ { \
+ return #camel; \
+ } \
+ \
+ cmSPDXObject::cmSPDXObject(classtype val) \
+ : member(std::move(val)) {}; \
+ \
+ void cmSPDXObject::get(classtype** ptr) \
+ { \
+ *ptr = SerializationBase.getTypeId() == cmSPDXSerializationBase::enumid \
+ ? &member \
+ : nullptr; \
+ }
+#include "cmSPDXTypes.def"
+
+cmSPDXObject::cmSPDXObject()
+ : IdentifierReference("UNINITIALIZED_SPDX_OBJECT")
+{
+}
+
+cmSPDXObject::cmSPDXObject(cmSPDXObject const& other)
+{
+ switch (other.SerializationBase.getTypeId()) {
+#define X_SPDX(classtype, enumid, member, camel) \
+ case cmSPDXSerializationBase::enumid: \
+ new (&member) classtype(other.member); \
+ break;
+#include "cmSPDXTypes.def"
+ default:
+ new (&IdentifierReference)
+ cmSPDXIdentifierReference("UNINITIALIZED_SPDX_OBJECT");
+ }
+}
+
+cmSPDXObject::cmSPDXObject(cmSPDXObject&& other) noexcept
+{
+ switch (other.SerializationBase.getTypeId()) {
+#define X_SPDX(classtype, enumid, member, camel) \
+ case cmSPDXSerializationBase::enumid: \
+ new (&member) classtype(std::move(other.member)); \
+ break;
+#include "cmSPDXTypes.def"
+ default:
+ new (&IdentifierReference)
+ cmSPDXIdentifierReference("UNINITIALIZED_SPDX_OBJECT");
+ }
+}
+
+cmSPDXObject& cmSPDXObject::operator=(cmSPDXObject const& other)
+{
+ this->~cmSPDXObject();
+ new (this) cmSPDXObject(other);
+ return *this;
+}
+
+cmSPDXObject& cmSPDXObject::operator=(cmSPDXObject&& other) noexcept
+{
+ this->~cmSPDXObject();
+ new (this) cmSPDXObject(std::move(other));
+ return *this;
+}
+
+cmSPDXObject::~cmSPDXObject()
+{
+ switch (SerializationBase.getTypeId()) {
+#define X_SPDX(classtype, enumid, member, camel) \
+ case cmSPDXSerializationBase::enumid: \
+ member.~classtype(); \
+ break;
+#include "cmSPDXTypes.def"
+ default:
+ break;
+ }
+}
+
+Json::Value cmSPDXObject::toJsonLD() const
+{
+ switch (SerializationBase.getTypeId()) {
+#define X_SPDX(classtype, enumid, member, camel) \
+ case cmSPDXSerializationBase::enumid: \
+ return member.toJsonLD();
+#include "cmSPDXTypes.def"
+ default:
+ return "INVALID_SPDX_OBJECT_TYPE_ID";
+ }
+}
+
+cmSPDXSimpleGraph::cmSPDXSimpleGraph(std::string iriBase,
+ cmSPDXCreationInfo creationInfo)
+ : IRIBase(std::move(iriBase))
+ , CreationInfo(&insert<cmSPDXCreationInfo>(std::move(creationInfo)))
+{
+}
+
+cmSPDXCreationInfo& cmSPDXSimpleGraph::getCreationInfo()
+{
+ return *CreationInfo;
+}
+
+Json::Value cmSPDXSimpleGraph::toJsonLD()
+{
+ Json::Value obj(Json::objectValue);
+ obj["@context"] = "https://spdx.org/rdf/3.0.1/spdx-context.jsonld";
+
+ auto& graph = obj["@graph"];
+ for (auto const& it : Graph) {
+ graph.append(it.second.toJsonLD());
+ }
+
+ return obj;
+}
diff --git a/Source/cmSPDXSerializer.h b/Source/cmSPDXSerializer.h
new file mode 100644
index 0000000..65bf214
--- /dev/null
+++ b/Source/cmSPDXSerializer.h
@@ -0,0 +1,1008 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file LICENSE.rst or https://cmake.org/licensing for details. */
+#pragma once
+
+#include <array>
+#include <cstddef>
+#include <map>
+#include <new>
+#include <string>
+#include <tuple>
+#include <utility>
+#include <vector>
+
+#include <cm/optional>
+#include <cm/type_traits>
+
+#include <cm3p/json/value.h>
+
+#include "cmStringAlgorithms.h"
+
+// Base Class
+
+struct cmSPDXSerializationBase
+{
+ enum SPDXTypeId
+ {
+ INVALID = -1,
+ NULL_ID = 0,
+
+#define X_SPDX(classtype, enumid, title, camel) enumid,
+#include "cmSPDXTypes.def"
+
+ SPDX_TYPE_ID_MAX,
+ };
+
+ SPDXTypeId getTypeId() const;
+
+ std::string NodeId;
+
+protected:
+ cmSPDXSerializationBase(SPDXTypeId id);
+ cmSPDXSerializationBase(SPDXTypeId id, std::string nodeId);
+
+private:
+ SPDXTypeId TypeId;
+};
+
+// Convenience Classes
+
+struct cmSPDXIdentifierReference : cmSPDXSerializationBase
+{
+ cmSPDXIdentifierReference();
+ cmSPDXIdentifierReference(cmSPDXSerializationBase const& ref);
+ cmSPDXIdentifierReference(std::string const& ref);
+
+ Json::Value toJsonLD() const;
+};
+
+struct cmSPDXNonElementBase : cmSPDXSerializationBase
+{
+protected:
+ cmSPDXNonElementBase(SPDXTypeId id);
+
+ Json::Value toJsonLD() const;
+};
+
+// SPDX Core Data Types
+
+// Nominally these are supposed to be validated strings
+using cmSPDXDateTime = std::string;
+using cmSPDXMediaType = std::string;
+using cmSPDXSemVer = std::string;
+
+// SPDX Core Enums
+
+struct cmSPDXAnnotationType
+{
+ enum cmSPDXAnnotationTypeId
+ {
+ INVALID = -1,
+ NULL_ID = 0,
+ OTHER,
+ REVIEW,
+ };
+
+ cmSPDXAnnotationTypeId TypeId;
+
+ cmSPDXAnnotationType(cmSPDXAnnotationTypeId typeId = NULL_ID);
+
+ Json::Value toJsonLD() const;
+};
+
+struct cmSPDXExternalIdentifierType
+{
+ enum cmSPDXExternalIdentifierTypeId
+ {
+ INVALID = -1,
+ NULL_ID = 0,
+ CPE22,
+ CPE23,
+ CVE,
+ EMAIL,
+ GITOID,
+ OTHER,
+ PACKAGE_URL,
+ SECURITY_OTHER,
+ SWHID,
+ SWID,
+ URL_SCHEME,
+ };
+
+ cmSPDXExternalIdentifierTypeId TypeId;
+
+ cmSPDXExternalIdentifierType(
+ cmSPDXExternalIdentifierTypeId typeId = NULL_ID);
+
+ Json::Value toJsonLD() const;
+};
+
+struct cmSPDXExternalRefType
+{
+ enum cmSPDXExternalRefTypeId
+ {
+ INVALID = -1,
+ NULL_ID = 0,
+ ALT_DOWNLOAD_LOCATION,
+ ALT_WEB_PAGE,
+ BINARY_ARTIFACT,
+ BOWER,
+ BUILD_META,
+ BUILD_SYSTEM,
+ CERTIFICATION_REPORT,
+ CHAT,
+ COMPONENT_ANALYSIS_REPORT,
+ CWE,
+ DOCUMENTATION,
+ DYNAMIC_ANALYSIS_REPORT,
+ EOL_NOTICE,
+ EXPORT_CONTROL_ASSESSMENT,
+ FUNDING,
+ ISSUE_TRACKER,
+ LICENSE,
+ MAILING_LIST,
+ MAVEN_CENTRAL,
+ METRICS,
+ NPM,
+ NUGET,
+ OTHER,
+ PRIVACY_ASSESSMENT,
+ PRODUCT_METADATA,
+ PURCHASE_ORDER,
+ QUALITY_ASSESSMENT_REPORT,
+ RELEASE_HISTORY,
+ RELEASE_NOTES,
+ RISK_ASSESSMENT,
+ RUNTIME_ANALYSIS_REPORT,
+ SECURE_SOFTWARE_ATTESTATION,
+ SECURITY_ADVERSARY_MODEL,
+ SECURITY_ADVISORY,
+ SECURITY_FIX,
+ SECURITY_OTHER,
+ SECURITY_PEN_TEST_REPORT,
+ SECURITY_POLICY,
+ SECURITY_THREAT_MODEL,
+ SOCIAL_MEDIA,
+ SOURCE_ARTIFACT,
+ STATIC_ANALYSIS_REPORT,
+ SUPPORT,
+ VCS,
+ VULNERABILITY_DISCLOSURE_REPORT,
+ VULNERABILITY_EXPLOITABILITY_ASSESSMENT,
+ };
+
+ cmSPDXExternalRefTypeId TypeId;
+
+ cmSPDXExternalRefType(cmSPDXExternalRefTypeId typeId = NULL_ID);
+
+ Json::Value toJsonLD() const;
+};
+
+struct cmSPDXHashAlgorithm
+{
+ enum cmSPDXHashAlgorithmId
+ {
+ INVALID = -1,
+ NULL_ID = 0,
+ ADLER32,
+ BLAKE2B256,
+ BLAKE2B384,
+ BLAKE2B512,
+ BLAKE3,
+ CRYSTALS_DILITHIUM,
+ CRYSTALS_KYBER,
+ FALCON,
+ MD2,
+ MD4,
+ MD5,
+ MD6,
+ OTHER,
+ SHA1,
+ SHA224,
+ SHA256,
+ SHA384,
+ SHA3_224,
+ SHA3_256,
+ SHA3_384,
+ SHA3_512,
+ SHA512,
+ };
+
+ cmSPDXHashAlgorithmId TypeId;
+
+ cmSPDXHashAlgorithm(cmSPDXHashAlgorithmId typeId = NULL_ID);
+
+ Json::Value toJsonLD() const;
+};
+
+struct cmSPDXLifecycleScopeType
+{
+ enum cmSPDXLifecycleScopeTypeId
+ {
+ INVALID = -1,
+ NULL_ID = 0,
+ BUILD,
+ DESIGN,
+ DEVELOPMENT,
+ OTHER,
+ RUNTIME,
+ TEST,
+ };
+
+ cmSPDXLifecycleScopeTypeId TypeId;
+
+ cmSPDXLifecycleScopeType(cmSPDXLifecycleScopeTypeId typeId = NULL_ID);
+
+ Json::Value toJsonLD() const;
+};
+
+struct cmSPDXProfileIdentifierType
+{
+ enum cmSPDXProfileIdentifierTypeId
+ {
+ INVALID = -1,
+ NULL_ID = 0,
+ AI,
+ BUILD,
+ CORE,
+ DATASET,
+ EXPANDED_LICENSING,
+ EXTENSION,
+ LITE,
+ SECURITY,
+ SIMPLE_LICENSING,
+ SOFTWARE,
+ };
+
+ cmSPDXProfileIdentifierTypeId TypeId;
+
+ cmSPDXProfileIdentifierType(cmSPDXProfileIdentifierTypeId typeId = NULL_ID);
+
+ Json::Value toJsonLD() const;
+};
+
+struct cmSPDXRelationshipCompletenessType
+{
+ enum cmSPDXRelationshipCompletenessTypeId
+ {
+ INVALID = -1,
+ NULL_ID = 0,
+ COMPLETE,
+ INCOMPLETE,
+ NO_ASSERTION,
+ };
+
+ cmSPDXRelationshipCompletenessTypeId TypeId;
+
+ cmSPDXRelationshipCompletenessType(
+ cmSPDXRelationshipCompletenessTypeId typeId = NULL_ID);
+
+ Json::Value toJsonLD() const;
+};
+
+struct cmSPDXRelationshipType
+{
+ enum cmSPDXRelationshipTypeId
+ {
+ INVALID = -1,
+ NULL_ID = 0,
+ AFFECTS,
+ AMENDED_BY,
+ ANCESTOR_OF,
+ AVAILABLE_FROM,
+ CONFIGURES,
+ CONTAINS,
+ COORDINATED_BY,
+ COPIED_TO,
+ DELEGATED_TO,
+ DEPENDS_ON,
+ DESCENDANT_OF,
+ DESCRIBES,
+ DOES_NOT_AFFECT,
+ EXPANDS_TO,
+ EXPLOIT_CREATED_BY,
+ FIXED_BY,
+ FIXED_IN,
+ FOUND_BY,
+ GENERATES,
+ HAS_ADDED_FILE,
+ HAS_ASSESSMENT_FOR,
+ HAS_ASSOCIATED_VULNERABILITY,
+ HAS_CONCLUDED_LICENSE,
+ HAS_DATA_FILE,
+ HAS_DECLARED_LICENSE,
+ HAS_DELETED_FILE,
+ HAS_DEPENDENCY_MANIFEST,
+ HAS_DISTRIBUTION_ARTIFACT,
+ HAS_DOCUMENTATION,
+ HAS_DYNAMIC_LINK,
+ HAS_EVIDENCE,
+ HAS_EXAMPLE,
+ HAS_HOST,
+ HAS_INPUT,
+ HAS_METADATA,
+ HAS_OPTIONAL_COMPONENT,
+ HAS_OPTIONAL_DEPENDENCY,
+ HAS_OUTPUT,
+ HAS_PREREQUISITE,
+ HAS_PROVIDED_DEPENDENCY,
+ HAS_REQUIREMENT,
+ HAS_SPECIFICATION,
+ HAS_STATIC_LINK,
+ HAS_TEST,
+ HAS_TEST_CASE,
+ HAS_VARIANT,
+ INVOKED_BY,
+ MODIFIED_BY,
+ OTHER,
+ PACKAGED_BY,
+ PATCHED_BY,
+ PUBLISHED_BY,
+ REPORTED_BY,
+ REPUBLISHED_BY,
+ SERIALIZED_IN_ARTIFACT,
+ TESTED_ON,
+ TRAINED_ON,
+ UNDER_INVESTIGATION_FOR,
+ USES_TOOL,
+ };
+
+ cmSPDXRelationshipTypeId TypeId;
+
+ cmSPDXRelationshipType(cmSPDXRelationshipTypeId typeId = NULL_ID);
+
+ Json::Value toJsonLD() const;
+};
+
+struct cmSPDXSupportType
+{
+ enum cmSPDXSupportTypeId
+ {
+ INVALID = -1,
+ NULL_ID = 0,
+ DEPLOYED,
+ DEVELOPMENT,
+ END_OF_SUPPORT,
+ LIMITED_SUPPORT,
+ NO_ASSERTION,
+ NO_SUPPORT,
+ SUPPORT,
+ };
+
+ cmSPDXSupportTypeId TypeId;
+
+ cmSPDXSupportType(cmSPDXSupportTypeId typeId = NULL_ID);
+
+ Json::Value toJsonLD() const;
+};
+
+// SPDX Core NonElement Classes, Abstract
+
+struct cmSPDXIntegrityMethod : cmSPDXNonElementBase
+{
+
+ cm::optional<std::string> Comment;
+
+protected:
+ cmSPDXIntegrityMethod(SPDXTypeId id);
+
+ Json::Value toJsonLD() const;
+};
+
+// SPDX Core NonElement Classes, Concrete
+
+struct cmSPDXCreationInfo : cmSPDXNonElementBase
+{
+ cm::optional<std::string> Comment;
+ cmSPDXDateTime Created;
+ std::vector<cmSPDXIdentifierReference> CreatedBy;
+ cm::optional<std::vector<cmSPDXIdentifierReference>> CreatedUsing;
+
+ cmSPDXCreationInfo();
+
+ Json::Value toJsonLD() const;
+};
+
+struct cmSPDXDictionaryEntry : cmSPDXNonElementBase
+{
+ std::string Key;
+ cm::optional<std::string> Value;
+
+ cmSPDXDictionaryEntry();
+ cmSPDXDictionaryEntry(std::string key);
+ cmSPDXDictionaryEntry(std::string key, std::string val);
+
+ Json::Value toJsonLD() const;
+};
+
+struct cmSPDXExternalIdentifier : cmSPDXNonElementBase
+{
+ cm::optional<std::string> Comment;
+ cmSPDXExternalIdentifierType ExternalIdentifierType;
+ std::string Identifier;
+ cm::optional<std::vector<std::string>> IdentifierLocator;
+ cm::optional<std::string> IssuingAuthority;
+
+ cmSPDXExternalIdentifier();
+
+ Json::Value toJsonLD() const;
+};
+
+struct cmSPDXExternalMap : cmSPDXNonElementBase
+{
+ cm::optional<cmSPDXIdentifierReference> DefiningArtifact;
+ std::string ExternalSpdxId;
+ cm::optional<std::string> LocationHint;
+ cm::optional<std::vector<cmSPDXIdentifierReference>> IntegrityMethod;
+
+ cmSPDXExternalMap();
+
+ Json::Value toJsonLD() const;
+};
+
+struct cmSPDXExternalRef : cmSPDXNonElementBase
+{
+ cm::optional<std::string> Comment;
+ cm::optional<cmSPDXMediaType> ContentType;
+ cm::optional<cmSPDXExternalRefType> ExternalRefType;
+ cm::optional<std::vector<std::string>> Locator;
+
+ cmSPDXExternalRef();
+
+ Json::Value toJsonLD() const;
+};
+
+struct cmSPDXHash : cmSPDXIntegrityMethod
+{
+ cmSPDXHashAlgorithm Algorithm;
+ std::string HashValue;
+
+ cmSPDXHash();
+
+ Json::Value toJsonLD() const;
+};
+
+struct cmSPDXNamespaceMap : cmSPDXNonElementBase
+{
+ std::string Namespace;
+ std::string Prefix;
+
+ cmSPDXNamespaceMap();
+
+ Json::Value toJsonLD() const;
+};
+
+struct cmSPDXPackageVerificationCode : cmSPDXIntegrityMethod
+{
+ cmSPDXHashAlgorithm Algorithm;
+ std::string HashValue;
+ cm::optional<std::vector<std::string>> PackageVerificationCodeExcludedFile;
+
+ cmSPDXPackageVerificationCode();
+
+ Json::Value toJsonLD() const;
+};
+
+struct cmSPDXPositiveIntegerRange : cmSPDXNonElementBase
+{
+ unsigned int BeginIntegerRange;
+ unsigned int EndIntegerRange;
+
+ cmSPDXPositiveIntegerRange(unsigned int beingIntegerRange = 0,
+ unsigned int endIntegerRange = 0);
+
+ Json::Value toJsonLD() const;
+};
+
+// SPDX Core Element Classes, Abstract
+
+struct cmSPDXElement : cmSPDXSerializationBase
+{
+ cm::optional<std::string> Comment;
+ cmSPDXIdentifierReference CreationInfo;
+ cm::optional<std::string> Description;
+ cm::optional<std::vector<cmSPDXIdentifierReference>> Extension;
+ cm::optional<std::vector<cmSPDXIdentifierReference>> ExternalIdentifier;
+ cm::optional<std::vector<cmSPDXIdentifierReference>> ExternalRef;
+ cm::optional<std::string> Name;
+ // SpdxId is the NodeId
+ cm::optional<std::string> Summary;
+ cm::optional<std::vector<cmSPDXIdentifierReference>> VerifiedUsing;
+
+protected:
+ cmSPDXElement(SPDXTypeId id, cmSPDXCreationInfo const& creationInfo);
+
+ Json::Value toJsonLD() const;
+};
+
+struct cmSPDXArtifact : cmSPDXElement
+{
+ cm::optional<cmSPDXDateTime> BuiltTime;
+ cm::optional<std::vector<cmSPDXIdentifierReference>> OriginatedBy;
+ cm::optional<cmSPDXDateTime> ReleaseTime;
+ cm::optional<std::vector<std::string>> StandardName;
+ cm::optional<cmSPDXIdentifierReference> SuppliedBy;
+ cm::optional<std::vector<cmSPDXSupportType>> SupportType;
+ cm::optional<cmSPDXDateTime> ValidUntilTime;
+
+protected:
+ cmSPDXArtifact(SPDXTypeId id, cmSPDXCreationInfo const& creationInfo);
+
+ Json::Value toJsonLD() const;
+};
+
+struct cmSPDXElementCollection : cmSPDXElement
+{
+ cm::optional<std::vector<cmSPDXIdentifierReference>> Element;
+ cm::optional<std::vector<cmSPDXProfileIdentifierType>> ProfileConformance;
+ cm::optional<std::vector<cmSPDXIdentifierReference>> RootElement;
+
+protected:
+ cmSPDXElementCollection(SPDXTypeId id,
+ cmSPDXCreationInfo const& creationInfo);
+
+ Json::Value toJsonLD() const;
+};
+
+// SPDX Implicit Core Element Classes, Abstract
+
+// Nominally an inheritable class, but adds nothing to Element
+using cmSPDXAgentAbstract = cmSPDXElement;
+
+struct cmSPDXBundleAbstract : cmSPDXElementCollection
+{
+ std::string Context;
+
+protected:
+ cmSPDXBundleAbstract(SPDXTypeId id, cmSPDXCreationInfo const& creationInfo);
+
+ Json::Value toJsonLD() const;
+};
+
+// Nominally an inheritable class, but adds nothing to Bundle
+using cmSPDXBomAbstract = cmSPDXBundleAbstract;
+
+struct cmSPDXRelationshipAbstract : cmSPDXElement
+{
+ cm::optional<cmSPDXRelationshipCompletenessType> Completeness;
+ cm::optional<cmSPDXDateTime> EndTime;
+ cmSPDXIdentifierReference From;
+ cmSPDXRelationshipType RelationshipType;
+ cm::optional<cmSPDXDateTime> StartTime;
+ std::vector<cmSPDXIdentifierReference> To;
+
+protected:
+ cmSPDXRelationshipAbstract(SPDXTypeId id,
+ cmSPDXCreationInfo const& creationInfo);
+
+ Json::Value toJsonLD() const;
+};
+
+// SPDX Core Element Classes, Concrete
+
+struct cmSPDXAgent : cmSPDXAgentAbstract
+{
+ cmSPDXAgent(cmSPDXCreationInfo const& creationInfo);
+
+ Json::Value toJsonLD() const;
+};
+
+struct cmSPDXAnnotation : cmSPDXElement
+{
+ cmSPDXAnnotationType AnnotationType;
+ cm::optional<cmSPDXMediaType> ContentType;
+ cm::optional<std::string> Statement;
+ cmSPDXIdentifierReference Subject;
+
+ cmSPDXAnnotation(cmSPDXCreationInfo const& creationInfo,
+ cmSPDXIdentifierReference subject = {});
+
+ Json::Value toJsonLD() const;
+};
+
+struct cmSPDXBom : cmSPDXBomAbstract
+{
+ cmSPDXBom(cmSPDXCreationInfo const& creationInfo);
+
+ Json::Value toJsonLD() const;
+};
+
+struct cmSPDXBundle : cmSPDXBundleAbstract
+{
+ cmSPDXBundle(cmSPDXCreationInfo const& creationInfo);
+
+ Json::Value toJsonLD() const;
+};
+
+struct cmSPDXIndividualElement : cmSPDXElement
+{
+ cmSPDXIndividualElement(cmSPDXCreationInfo const& creationInfo);
+
+ Json::Value toJsonLD() const;
+};
+
+struct cmSPDXLifecycleScopedRelationship : cmSPDXRelationshipAbstract
+{
+ cm::optional<cmSPDXLifecycleScopeType> Scope;
+
+ cmSPDXLifecycleScopedRelationship(cmSPDXCreationInfo const& creationInfo);
+
+ Json::Value toJsonLD() const;
+};
+
+struct cmSPDXOrganization : cmSPDXAgentAbstract
+{
+ cmSPDXOrganization(cmSPDXCreationInfo const& creationInfo);
+
+ Json::Value toJsonLD() const;
+};
+
+struct cmSPDXPerson : cmSPDXAgentAbstract
+{
+ cmSPDXPerson(cmSPDXCreationInfo const& creationInfo);
+
+ Json::Value toJsonLD() const;
+};
+
+struct cmSPDXRelationship : cmSPDXRelationshipAbstract
+{
+ cmSPDXRelationship(cmSPDXCreationInfo const& creationInfo);
+
+ Json::Value toJsonLD() const;
+};
+
+struct cmSPDXSoftwareAgent : cmSPDXAgentAbstract
+{
+ cmSPDXSoftwareAgent(cmSPDXCreationInfo const& creationInfo);
+
+ Json::Value toJsonLD() const;
+};
+
+struct cmSPDXSpdxDocument : cmSPDXElementCollection
+{
+ cm::optional<cmSPDXIdentifierReference> DataLicense;
+ cm::optional<cmSPDXIdentifierReference> ExternalMap;
+ cm::optional<cmSPDXIdentifierReference> NamespaceMap;
+
+ cmSPDXSpdxDocument(cmSPDXCreationInfo const& creationInfo);
+
+ Json::Value toJsonLD() const;
+};
+
+struct cmSPDXTool : cmSPDXElement
+{
+ cmSPDXTool(cmSPDXCreationInfo const& creationInfo);
+
+ Json::Value toJsonLD() const;
+};
+
+// SPDX Software Enums
+
+struct cmSPDXContentIdentifierType
+{
+ enum cmSPDXContentIdentifierTypeId
+ {
+ INVALID = -1,
+ NULL_ID = 0,
+ GITOID,
+ SWHID,
+ };
+
+ cmSPDXContentIdentifierTypeId TypeId;
+
+ cmSPDXContentIdentifierType(cmSPDXContentIdentifierTypeId typeId = NULL_ID);
+
+ Json::Value toJsonLD() const;
+};
+
+struct cmSPDXFileKindType
+{
+ enum cmSPDXFileKindTypeId
+ {
+ INVALID = -1,
+ NULL_ID = 0,
+ DIRECTORY,
+ FILE,
+ };
+
+ cmSPDXFileKindTypeId TypeId;
+
+ cmSPDXFileKindType(cmSPDXFileKindTypeId typeId = NULL_ID);
+
+ Json::Value toJsonLD() const;
+};
+
+struct cmSPDXSbomType
+{
+ enum cmSPDXSbomTypeId
+ {
+ INVALID = -1,
+ NULL_ID = 0,
+ ANALYZED,
+ BUILD,
+ DEPLOYED,
+ DESIGN,
+ RUNTIME,
+ SOURCE,
+ };
+
+ cmSPDXSbomTypeId TypeId;
+
+ cmSPDXSbomType(cmSPDXSbomTypeId typeId = NULL_ID);
+
+ Json::Value toJsonLD() const;
+};
+
+struct cmSPDXSoftwarePurpose
+{
+ enum cmSPDXSoftwarePurposeId
+ {
+ INVALID = -1,
+ NULL_ID = 0,
+ APPLICATION,
+ ARCHIVE,
+ BOM,
+ CONFIGURATION,
+ CONTAINER,
+ DATA,
+ DEVICE,
+ DEVICE_DRIVER,
+ DISK_IMAGE,
+ DOCUMENTATION,
+ EVIDENCE,
+ EXECUTABLE,
+ FILE,
+ FILESYSTEM_IMAGE,
+ FIRMWARE,
+ FRAMEWORK,
+ INSTALL,
+ LIBRARY,
+ MANIFEST,
+ MODEL,
+ MODULE,
+ OPERATING_SYSTEM,
+ OTHER,
+ PATCH,
+ PLATFORM,
+ REQUIREMENT,
+ SOURCE,
+ SPECIFICATION,
+ TEST,
+ };
+
+ cmSPDXSoftwarePurposeId TypeId;
+
+ cmSPDXSoftwarePurpose(cmSPDXSoftwarePurposeId typeId = NULL_ID);
+
+ Json::Value toJsonLD() const;
+};
+
+// SPDX Software NonElement Classes, Concrete
+
+struct cmSPDXContentIdentifier : cmSPDXIntegrityMethod
+{
+ cmSPDXContentIdentifierType ContentIdentifierType;
+ std::string ContentIdentifierValue;
+
+ cmSPDXContentIdentifier();
+
+ Json::Value toJsonLD() const;
+};
+
+// SPDX Software Element Classes, Abstract
+
+struct cmSPDXSoftwareArtifact : cmSPDXArtifact
+{
+ cm::optional<std::vector<cmSPDXSoftwarePurpose>> AdditionalPurpose;
+ cm::optional<std::string> AttributionText;
+ cm::optional<cmSPDXIdentifierReference> ContentIdentifier;
+ cm::optional<std::string> CopyrightText;
+ cm::optional<cmSPDXSoftwarePurpose> PrimaryPurpose;
+
+protected:
+ cmSPDXSoftwareArtifact(SPDXTypeId id,
+ cmSPDXCreationInfo const& creationInfo);
+
+ Json::Value toJsonLD() const;
+};
+
+// SPDX Software Element Classes, Concrete
+
+struct cmSPDXFile : cmSPDXSoftwareArtifact
+{
+ cm::optional<cmSPDXMediaType> ContentType;
+ cm::optional<cmSPDXFileKindType> FileKind;
+
+ cmSPDXFile(cmSPDXCreationInfo const& creationInfo);
+
+ Json::Value toJsonLD() const;
+};
+
+struct cmSPDXPackage : cmSPDXSoftwareArtifact
+{
+ cm::optional<std::string> DownloadLocation;
+ cm::optional<std::string> HomePage;
+ cm::optional<std::string> PackageUrl;
+ cm::optional<std::string> PackageVersion;
+ cm::optional<std::string> SourceInfo;
+
+ cmSPDXPackage(cmSPDXCreationInfo const& creationInfo);
+
+ Json::Value toJsonLD() const;
+};
+
+struct cmSPDXSbom : cmSPDXBomAbstract
+{
+ cm::optional<std::vector<cmSPDXSbomType>> SbomType;
+
+ cmSPDXSbom(cmSPDXCreationInfo const& creationInfo);
+
+ Json::Value toJsonLD() const;
+};
+
+struct cmSPDXSnippet : cmSPDXSoftwareArtifact
+{
+ cm::optional<cmSPDXIdentifierReference> ByteRange;
+ cm::optional<cmSPDXIdentifierReference> LineRange;
+ cmSPDXIdentifierReference SnippetFromFile;
+
+ cmSPDXSnippet(cmSPDXCreationInfo const& creationInfo);
+
+ Json::Value toJsonLD() const;
+};
+
+// SPDX SimpleLicensing Element Classes, Abstract
+
+// Nominally an inheritable class, but adds nothing to Element
+using cmSPDXAnyLicenseInfo = cmSPDXElement;
+
+// SPDX SimpleLicensing Element Classes, Concrete
+
+struct cmSPDXLicenseExpression : cmSPDXAnyLicenseInfo
+{
+ cm::optional<std::vector<cmSPDXIdentifierReference>> CustomIdToUri;
+ std::string LicenseExpression;
+ cm::optional<cmSPDXSemVer> LicenseListVersion;
+
+ cmSPDXLicenseExpression(cmSPDXCreationInfo const& CreationInfo);
+
+ Json::Value toJsonLD() const;
+};
+
+struct cmSPDXSimpleLicensingText : cmSPDXElement
+{
+ std::string LicenseText;
+
+ cmSPDXSimpleLicensingText(cmSPDXCreationInfo const& CreationInfo);
+
+ Json::Value toJsonLD() const;
+};
+
+// Graph Manipulation
+
+template <typename T>
+cmSPDXSerializationBase::SPDXTypeId cmSPDXGetTypeId();
+
+template <typename T>
+std::string cmSPDXGetTypeName();
+
+#define X_SPDX(classtype, enumid, member, camel) \
+ template <> \
+ cmSPDXSerializationBase::SPDXTypeId cmSPDXGetTypeId<classtype>(); \
+ \
+ template <> \
+ std::string cmSPDXGetTypeName<classtype>();
+#include "cmSPDXTypes.def"
+
+template <class T>
+struct cmSPDXTag
+{
+ using type = T;
+};
+
+union cmSPDXObject
+{
+
+ cmSPDXSerializationBase SerializationBase;
+
+ cmSPDXObject();
+ cmSPDXObject(cmSPDXObject const& other);
+ cmSPDXObject(cmSPDXObject&& other) noexcept;
+
+#define X_SPDX(classtype, enumid, member, camel) \
+ classtype member; \
+ cmSPDXObject(classtype val); \
+ \
+ template <typename... Args> \
+ cmSPDXObject(cmSPDXTag<classtype>, Args&&... args) \
+ { \
+ new (&member) classtype(std::forward<Args>(args)...); \
+ }
+#include "cmSPDXTypes.def"
+
+ cmSPDXObject& operator=(cmSPDXObject const& other);
+ cmSPDXObject& operator=(cmSPDXObject&& other) noexcept;
+
+ ~cmSPDXObject();
+
+ template <typename T>
+ T* get()
+ {
+ T* ptr;
+ get(&ptr);
+ return ptr;
+ }
+
+ Json::Value toJsonLD() const;
+
+private:
+#define X_SPDX(classtype, enumid, member, camel) void get(classtype** ptr);
+#include "cmSPDXTypes.def"
+};
+
+struct cmSPDXSimpleGraph
+{
+ cmSPDXSimpleGraph(std::string iriBase, cmSPDXCreationInfo creationInfo = {});
+
+ template <typename T, typename... Args>
+ cm::enable_if_t<std::is_base_of<cmSPDXElement, T>::value, T>& insert(
+ Args&&... args)
+ {
+ std::string nodeId = cmStrCat(IRIBase, IRICount++);
+ auto const& it =
+ Graph.emplace(std::piecewise_construct, std::forward_as_tuple(nodeId),
+ std::forward_as_tuple(cmSPDXTag<T>{}, *CreationInfo,
+ std::forward<Args>(args)...));
+ auto& node = *it.first->second.template get<T>();
+ node.NodeId = std::move(nodeId);
+ return node;
+ }
+
+ cmSPDXCreationInfo& getCreationInfo();
+
+ template <typename T, typename... Args>
+ cm::enable_if_t<std::is_base_of<cmSPDXNonElementBase, T>::value, T>& insert(
+ Args&&... args)
+ {
+ std::size_t nodeCount = BlankCounts[cmSPDXGetTypeId<T>()]++;
+ std::string nodeId =
+ cmStrCat("_:", cmSPDXGetTypeName<T>(), "_", nodeCount);
+ auto const& it = Graph.emplace(
+ std::piecewise_construct, std::forward_as_tuple(nodeId),
+ std::forward_as_tuple(cmSPDXTag<T>{}, std::forward<Args>(args)...));
+ auto& node = *it.first->second.template get<T>();
+ node.NodeId = std::move(nodeId);
+ return node;
+ }
+
+ template <typename T>
+ T* get(std::string const& key)
+ {
+ auto it = Graph.find(key);
+ if (it == Graph.end()) {
+ return nullptr;
+ }
+ return it->second.get<T>();
+ }
+
+ template <typename T>
+ T* get(cmSPDXIdentifierReference const& key)
+ {
+ auto it = Graph.find(key.NodeId);
+ if (it == Graph.end()) {
+ return nullptr;
+ }
+ return it->second.get<T>();
+ }
+
+ Json::Value toJsonLD();
+
+private:
+ std::string IRIBase;
+ std::size_t IRICount{ 0 };
+ std::array<std::size_t, cmSPDXSerializationBase::SPDX_TYPE_ID_MAX>
+ BlankCounts{};
+
+ std::map<std::string, cmSPDXObject> Graph;
+ cmSPDXCreationInfo* CreationInfo;
+};
diff --git a/Source/cmSPDXTypes.def b/Source/cmSPDXTypes.def
new file mode 100644
index 0000000..88d8043
--- /dev/null
+++ b/Source/cmSPDXTypes.def
@@ -0,0 +1,54 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file LICENSE.rst or https://cmake.org/licensing for details. */
+#ifndef X_SPDX
+# define X_SPDX(classtype, enumid, member, camel)
+#endif
+
+// Convenience
+X_SPDX(cmSPDXIdentifierReference, CM_IDENTIFIER_REFERENCE, IdentifierReference,
+ identifierReference)
+
+// Core
+X_SPDX(cmSPDXAgent, CORE_AGENT, Agent, agent)
+X_SPDX(cmSPDXAnnotation, CORE_ANNOTATION, Annotation, annotation)
+X_SPDX(cmSPDXBom, CORE_BOM, Bom, bom)
+X_SPDX(cmSPDXBundle, CORE_BUNDLE, Bundle, bundle)
+X_SPDX(cmSPDXCreationInfo, CORE_CREATION_INFO, CreationInfo, creationInfo)
+X_SPDX(cmSPDXDictionaryEntry, CORE_DICTIONARY_ENTRY, DictionaryEntry,
+ dictionaryEntry)
+X_SPDX(cmSPDXExternalIdentifier, CORE_EXTERNAL_IDENTIFIER, ExternalIdentifier,
+ externalIdentifier)
+X_SPDX(cmSPDXExternalMap, CORE_EXTERNAL_MAP, ExternalMap, externalMap)
+X_SPDX(cmSPDXExternalRef, CORE_EXTERNAL_REF, ExternalRef, externalRef)
+X_SPDX(cmSPDXHash, CORE_HASH, Hash, hash)
+X_SPDX(cmSPDXIndividualElement, CORE_INDIVIDUAL_ELEMENT, IndividualElement,
+ individualElement)
+X_SPDX(cmSPDXLifecycleScopedRelationship, CORE_LIFECYCLE_SCOPED_RELATIONSHIP,
+ LifecycleScopedRelationship, lifecycleScopedRelationship)
+X_SPDX(cmSPDXNamespaceMap, CORE_NAMESPACE_MAP, NamespaceMap, namespaceMap)
+X_SPDX(cmSPDXOrganization, CORE_ORGANIZATION, Organization, organization)
+X_SPDX(cmSPDXPackageVerificationCode, CORE_PACKAGE_VERIFICATION_CODE,
+ PackageVerificationCode, packageVerificationCode)
+X_SPDX(cmSPDXPerson, CORE_PERSON, Person, person)
+X_SPDX(cmSPDXPositiveIntegerRange, CORE_POSITIVE_INTEGER_RANGE,
+ PositiveIntegerRange, positiveIntegerRange)
+X_SPDX(cmSPDXRelationship, CORE_RELATIONSHIP, Relationship, relationship)
+X_SPDX(cmSPDXSoftwareAgent, CORE_SOFTWARE_AGENT, SoftwareAgent, softwareAgent)
+X_SPDX(cmSPDXSpdxDocument, CORE_SPDX_DOCUMENT, SpdxDocument, spdxDocument)
+X_SPDX(cmSPDXTool, CORE_TOOL, Tool, tool)
+
+// Software
+X_SPDX(cmSPDXContentIdentifier, SOFTWARE_CONTENT_IDENTIFIER, ContentIdentifier,
+ contentIdentifier)
+X_SPDX(cmSPDXFile, SOFTWARE_FILE, File, file)
+X_SPDX(cmSPDXPackage, SOFTWARE_PACKAGE, Package, package)
+X_SPDX(cmSPDXSbom, SOFTWARE_SBOM, Sbom, sbom)
+X_SPDX(cmSPDXSnippet, SOFTWARE_SNIPPET, Snippet, snippet)
+
+// SimpleLicensing
+X_SPDX(cmSPDXLicenseExpression, SIMPLE_LICENSING_LICENSE_EXPRESSION,
+ LicenseExpression, licenseExpression)
+X_SPDX(cmSPDXSimpleLicensingText, SIMPLE_LICENSING_SIMPLE_LICENSING_TEXT,
+ SimpleLicensingText, simpleLicensingText)
+
+#undef X_SPDX
diff --git a/Tests/CMakeLib/CMakeLists.txt b/Tests/CMakeLib/CMakeLists.txt
index 3f6ae04..7f35f04 100644
--- a/Tests/CMakeLib/CMakeLists.txt
+++ b/Tests/CMakeLib/CMakeLists.txt
@@ -24,6 +24,7 @@
testRange.cxx
testOptional.cxx
testPathResolver.cxx
+ testSPDXSerializer.cxx
testStdIo.cxx
testString.cxx
testStringAlgorithms.cxx
diff --git a/Tests/CMakeLib/testSPDXSerializer.cxx b/Tests/CMakeLib/testSPDXSerializer.cxx
new file mode 100644
index 0000000..b8ab923
--- /dev/null
+++ b/Tests/CMakeLib/testSPDXSerializer.cxx
@@ -0,0 +1,649 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file LICENSE.rst or https://cmake.org/licensing for details. */
+#include <iostream>
+#include <string>
+#include <vector>
+
+#include <cm/optional>
+#include <cm/type_traits>
+
+#include <cm3p/json/reader.h>
+#include <cm3p/json/value.h>
+
+#include "cmSPDXSerializer.h"
+
+namespace {
+
+std::string const nonOptional(R"================({
+ "@context": "https://spdx.org/rdf/3.0.1/spdx-context.jsonld",
+ "@graph": [
+ {
+ "@id": "_:contentIdentifier_0",
+ "contentIdentifierType": "INVALID_CONTENT_IDENTIFIER_TYPE_ID",
+ "contentIdentifierValue": "",
+ "type": "ContentIdentifier"
+ },
+ {
+ "@id": "_:creationInfo_0",
+ "created": "",
+ "createdBy": [],
+ "type": "CreationInfo"
+ },
+ {
+ "@id": "_:creationInfo_1",
+ "created": "",
+ "createdBy": [],
+ "type": "CreationInfo"
+ },
+ {
+ "@id": "_:dictionaryEntry_0",
+ "key": "",
+ "type": "DictionaryEntry"
+ },
+ {
+ "@id": "_:externalIdentifier_0",
+ "externalIdentifierType": "INVALID_EXTERNAL_IDENTIFIER_TYPE_ID",
+ "identifier": "",
+ "type": "ExternalIdentifier"
+ },
+ {
+ "@id": "_:externalMap_0",
+ "externalSpdxId": "",
+ "type": "ExternalMap"
+ },
+ {
+ "@id": "_:externalRef_0",
+ "type": "ExternalRef"
+ },
+ {
+ "@id": "_:hash_0",
+ "algorithm": "INVALID_HASH_TYPE_ID",
+ "hashValue": "",
+ "type": "Hash"
+ },
+ {
+ "@id": "_:namespaceMap_0",
+ "namespace": "",
+ "prefix": "",
+ "type": "NamespaceMap"
+ },
+ {
+ "@id": "_:packageVerificationCode_0",
+ "algorithm": "INVALID_HASH_TYPE_ID",
+ "hashValue": "",
+ "type": "PackageVerificationCode"
+ },
+ {
+ "@id": "_:positiveIntegerRange_0",
+ "beginIntegerRange": 0,
+ "endIntegerRange": 0,
+ "type": "PositiveIntegerRange"
+ },
+ {
+ "creationInfo": "_:creationInfo_0",
+ "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd0",
+ "type": "Agent"
+ },
+ {
+ "annotationType": "INVALID_ANNOTATION_TYPE_ID",
+ "creationInfo": "_:creationInfo_0",
+ "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd1",
+ "subject": "",
+ "type": "Annotation"
+ },
+ {
+ "creationInfo": "_:creationInfo_0",
+ "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd10",
+ "type": "SpdxDocument"
+ },
+ {
+ "creationInfo": "_:creationInfo_0",
+ "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd11",
+ "type": "Tool"
+ },
+ {
+ "creationInfo": "_:creationInfo_0",
+ "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd12",
+ "type": "File"
+ },
+ {
+ "creationInfo": "_:creationInfo_0",
+ "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd13",
+ "type": "Package"
+ },
+ {
+ "context": "",
+ "creationInfo": "_:creationInfo_0",
+ "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd14",
+ "type": "Sbom"
+ },
+ {
+ "creationInfo": "_:creationInfo_0",
+ "snippetFromFile": "",
+ "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd15",
+ "type": "Snippet"
+ },
+ {
+ "creationInfo": "_:creationInfo_0",
+ "licenseExpression": "",
+ "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd16",
+ "type": "LicenseExpression"
+ },
+ {
+ "creationInfo": "_:creationInfo_0",
+ "licenseText": "",
+ "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd17",
+ "type": "SimpleLicensingText"
+ },
+ {
+ "context": "",
+ "creationInfo": "_:creationInfo_0",
+ "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd2",
+ "type": "Bom"
+ },
+ {
+ "context": "",
+ "creationInfo": "_:creationInfo_0",
+ "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd3",
+ "type": "Bundle"
+ },
+ {
+ "creationInfo": "_:creationInfo_0",
+ "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd4",
+ "type": "IndividualElement"
+ },
+ {
+ "creationInfo": "_:creationInfo_0",
+ "from": "",
+ "relationshipType": "INVALID_RELATIONSHIP_TYPE_ID",
+ "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd5",
+ "to": [],
+ "type": "LifecycleScopedRelationship"
+ },
+ {
+ "creationInfo": "_:creationInfo_0",
+ "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd6",
+ "type": "Organization"
+ },
+ {
+ "creationInfo": "_:creationInfo_0",
+ "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd7",
+ "type": "Person"
+ },
+ {
+ "creationInfo": "_:creationInfo_0",
+ "from": "",
+ "relationshipType": "INVALID_RELATIONSHIP_TYPE_ID",
+ "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd8",
+ "to": [],
+ "type": "Relationship"
+ },
+ {
+ "creationInfo": "_:creationInfo_0",
+ "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd9",
+ "type": "SoftwareAgent"
+ }
+ ]
+})================");
+
+std::string const Optional(R"================({
+ "@context": "https://spdx.org/rdf/3.0.1/spdx-context.jsonld",
+ "@graph": [
+ {
+ "@id": "_:contentIdentifier_0",
+ "contentIdentifierType": "gitoid",
+ "contentIdentifierValue": "ContentIdentifierValue",
+ "type": "ContentIdentifier"
+ },
+ {
+ "@id": "_:creationInfo_0",
+ "created": "",
+ "createdBy": [],
+ "type": "CreationInfo"
+ },
+ {
+ "@id": "_:creationInfo_1",
+ "Comment": "Comment",
+ "created": "Created",
+ "createdBy": [
+ "testRef"
+ ],
+ "createdUsing": [
+ "testRef"
+ ],
+ "type": "CreationInfo"
+ },
+ {
+ "@id": "_:dictionaryEntry_0",
+ "key": "Key",
+ "type": "DictionaryEntry",
+ "value": "Value"
+ },
+ {
+ "@id": "_:externalIdentifier_0",
+ "comment": "Comment",
+ "externalIdentifierType": "other",
+ "identifier": "Identifier",
+ "identifierLocator": [
+ "IdentifierLocator"
+ ],
+ "issuingAuthority": "IssuingAuthority",
+ "type": "ExternalIdentifier"
+ },
+ {
+ "@id": "_:externalMap_0",
+ "definingArtifact": "testRef",
+ "externalSpdxId": "ExternalSpdxId",
+ "integrityMethod": [
+ "testRef"
+ ],
+ "locationHint": "LocationHint",
+ "type": "ExternalMap"
+ },
+ {
+ "@id": "_:externalRef_0",
+ "comment": "Comment",
+ "contentType": "ContentType",
+ "externalRefType": "other",
+ "locator": [
+ "Locator"
+ ],
+ "type": "ExternalRef"
+ },
+ {
+ "@id": "_:hash_0",
+ "algorithm": "other",
+ "hashValue": "HashValue",
+ "type": "Hash"
+ },
+ {
+ "@id": "_:namespaceMap_0",
+ "namespace": "Namespace",
+ "prefix": "Namespace",
+ "type": "NamespaceMap"
+ },
+ {
+ "@id": "_:packageVerificationCode_0",
+ "algorithm": "other",
+ "hashValue": "HashValue",
+ "type": "PackageVerificationCode"
+ },
+ {
+ "@id": "_:positiveIntegerRange_0",
+ "beginIntegerRange": 1,
+ "endIntegerRange": 2,
+ "type": "PositiveIntegerRange"
+ },
+ {
+ "comment": "Comment",
+ "creationInfo": "_:creationInfo_0",
+ "description": "Description",
+ "extension": [
+ "testRef"
+ ],
+ "externalIdentifier": [
+ "testRef"
+ ],
+ "externalRef": [
+ "testRef"
+ ],
+ "name": "Name",
+ "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd0",
+ "summary": "Summary",
+ "type": "Agent",
+ "verifiedUsing": [
+ "testRef"
+ ]
+ },
+ {
+ "annotationType": "other",
+ "contentType": "ContentType",
+ "creationInfo": "_:creationInfo_0",
+ "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd1",
+ "statement": "Statement",
+ "subject": "testRef",
+ "type": "Annotation"
+ },
+ {
+ "creationInfo": "_:creationInfo_0",
+ "dataLicense": "testRef",
+ "externalMap": "testRef",
+ "namespaceMap": "testRef",
+ "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd10",
+ "type": "SpdxDocument"
+ },
+ {
+ "creationInfo": "_:creationInfo_0",
+ "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd11",
+ "type": "Tool"
+ },
+ {
+ "additionalPurpose": [
+ "other"
+ ],
+ "attributionText": "AttributionText",
+ "contentIdentifier": "testRef",
+ "contentType": "ContentType",
+ "copyrightText": "CopyrightText",
+ "creationInfo": "_:creationInfo_0",
+ "fileKind": "file",
+ "primaryPurpose": "file",
+ "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd12",
+ "type": "File"
+ },
+ {
+ "creationInfo": "_:creationInfo_0",
+ "downloadLocation": "DownloadLocation",
+ "homePage": "HomePage",
+ "packageUrl": "PackageUrl",
+ "packageVersion": "PackageVersion",
+ "sourceInfo": "SourceInfo",
+ "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd13",
+ "type": "Package"
+ },
+ {
+ "context": "",
+ "creationInfo": "_:creationInfo_0",
+ "sbomType": [
+ "build"
+ ],
+ "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd14",
+ "type": "Sbom"
+ },
+ {
+ "byteRange": "testRef",
+ "creationInfo": "_:creationInfo_0",
+ "lineRange": "testRef",
+ "snippetFromFile": "testRef",
+ "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd15",
+ "type": "Snippet"
+ },
+ {
+ "creationInfo": "_:creationInfo_0",
+ "customIdToUri": [
+ "testRef"
+ ],
+ "licenseExpression": "LicenseExpression",
+ "licenseListVersion": "LicenseListVersion",
+ "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd16",
+ "type": "LicenseExpression"
+ },
+ {
+ "creationInfo": "_:creationInfo_0",
+ "licenseText": "LicenseText",
+ "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd17",
+ "type": "SimpleLicensingText"
+ },
+ {
+ "context": "Context",
+ "creationInfo": "_:creationInfo_0",
+ "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd2",
+ "type": "Bom"
+ },
+ {
+ "context": "",
+ "creationInfo": "_:creationInfo_0",
+ "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd3",
+ "type": "Bundle"
+ },
+ {
+ "creationInfo": "_:creationInfo_0",
+ "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd4",
+ "type": "IndividualElement"
+ },
+ {
+ "completeness": "noAssertion",
+ "creationInfo": "_:creationInfo_0",
+ "endTime": "EndTime",
+ "from": "testRef",
+ "relationshipType": "other",
+ "scope": "other",
+ "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd5",
+ "startTime": "StartTime",
+ "to": [
+ "testRef"
+ ],
+ "type": "LifecycleScopedRelationship"
+ },
+ {
+ "creationInfo": "_:creationInfo_0",
+ "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd6",
+ "type": "Organization"
+ },
+ {
+ "creationInfo": "_:creationInfo_0",
+ "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd7",
+ "type": "Person"
+ },
+ {
+ "creationInfo": "_:creationInfo_0",
+ "from": "",
+ "relationshipType": "INVALID_RELATIONSHIP_TYPE_ID",
+ "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd8",
+ "to": [],
+ "type": "Relationship"
+ },
+ {
+ "creationInfo": "_:creationInfo_0",
+ "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd9",
+ "type": "SoftwareAgent"
+ }
+ ]
+})================");
+}
+
+int testNonOptional()
+{
+ cmSPDXSimpleGraph graph("https://cmake.org/testSPDXSerialization-gnrtd");
+
+ // Core
+ graph.insert<cmSPDXAgent>();
+ graph.insert<cmSPDXAnnotation>();
+ graph.insert<cmSPDXBom>();
+ graph.insert<cmSPDXBundle>();
+ graph.insert<cmSPDXCreationInfo>();
+ graph.insert<cmSPDXDictionaryEntry>();
+ graph.insert<cmSPDXExternalIdentifier>();
+ graph.insert<cmSPDXExternalMap>();
+ graph.insert<cmSPDXExternalRef>();
+ graph.insert<cmSPDXHash>();
+ graph.insert<cmSPDXIndividualElement>();
+ graph.insert<cmSPDXLifecycleScopedRelationship>();
+ graph.insert<cmSPDXNamespaceMap>();
+ graph.insert<cmSPDXOrganization>();
+ graph.insert<cmSPDXPackageVerificationCode>();
+ graph.insert<cmSPDXPerson>();
+ graph.insert<cmSPDXPositiveIntegerRange>();
+ graph.insert<cmSPDXRelationship>();
+ graph.insert<cmSPDXSoftwareAgent>();
+ graph.insert<cmSPDXSpdxDocument>();
+ graph.insert<cmSPDXTool>();
+
+ // Software
+ graph.insert<cmSPDXContentIdentifier>();
+ graph.insert<cmSPDXFile>();
+ graph.insert<cmSPDXPackage>();
+ graph.insert<cmSPDXSbom>();
+ graph.insert<cmSPDXSnippet>();
+
+ // SimpleLicensing
+ graph.insert<cmSPDXLicenseExpression>();
+ graph.insert<cmSPDXSimpleLicensingText>();
+
+ Json::Value root;
+ Json::Reader().parse(nonOptional.c_str(), root);
+
+ std::cout << "NonOptional SPDX:";
+ std::cout << "\nConstructed Graph: " << graph.toJsonLD().toStyledString();
+ std::cout << "\nComparison Graph:" << root.toStyledString() << "\n";
+
+ // Convert to string to disregard differences in number signedness
+ return root.toStyledString() == graph.toJsonLD().toStyledString();
+};
+
+int testOptional()
+{
+ cmSPDXSimpleGraph graph("https://cmake.org/testSPDXSerialization-gnrtd");
+
+ cmSPDXIdentifierReference ident("testRef");
+
+ // Core
+ auto& agent = graph.insert<cmSPDXAgent>();
+ agent.Comment = "Comment";
+ agent.Description = "Description";
+ agent.Extension.emplace().push_back(ident);
+ agent.ExternalIdentifier.emplace().push_back(ident);
+ agent.ExternalRef.emplace().push_back(ident);
+ agent.Name = "Name";
+ agent.Summary = "Summary";
+ agent.VerifiedUsing.emplace().push_back(ident);
+
+ auto& annotation = graph.insert<cmSPDXAnnotation>();
+ annotation.AnnotationType = cmSPDXAnnotationType::OTHER;
+ annotation.ContentType = "ContentType";
+ annotation.Statement = "Statement";
+ annotation.Subject = ident;
+
+ auto& bom = graph.insert<cmSPDXBom>();
+ bom.Context = "Context";
+
+ graph.insert<cmSPDXBundle>();
+
+ auto& creationInfo = graph.insert<cmSPDXCreationInfo>();
+ creationInfo.Comment = "Comment";
+ creationInfo.Created = "Created";
+ creationInfo.CreatedBy.push_back(ident);
+ creationInfo.CreatedUsing.emplace().push_back(ident);
+
+ auto& dictionaryEntry = graph.insert<cmSPDXDictionaryEntry>();
+ dictionaryEntry.Key = "Key";
+ dictionaryEntry.Value = "Value";
+
+ auto& externalIdentifier = graph.insert<cmSPDXExternalIdentifier>();
+ externalIdentifier.Comment = "Comment";
+ externalIdentifier.ExternalIdentifierType =
+ cmSPDXExternalIdentifierType::OTHER;
+ externalIdentifier.Identifier = "Identifier";
+ externalIdentifier.IdentifierLocator.emplace().push_back(
+ "IdentifierLocator");
+ externalIdentifier.IssuingAuthority = "IssuingAuthority";
+
+ auto& externalMap = graph.insert<cmSPDXExternalMap>();
+ externalMap.DefiningArtifact = ident;
+ externalMap.ExternalSpdxId = "ExternalSpdxId";
+ externalMap.LocationHint = "LocationHint";
+ externalMap.IntegrityMethod.emplace().push_back(ident);
+
+ auto& externalRef = graph.insert<cmSPDXExternalRef>();
+ externalRef.Comment = "Comment";
+ externalRef.ContentType = "ContentType";
+ externalRef.ExternalRefType = cmSPDXExternalRefType::OTHER;
+ externalRef.Locator.emplace().push_back("Locator");
+
+ auto& hash = graph.insert<cmSPDXHash>();
+ hash.Algorithm = cmSPDXHashAlgorithm::OTHER;
+ hash.HashValue = "HashValue";
+
+ graph.insert<cmSPDXIndividualElement>();
+
+ auto& lifecycleScopedRelationship =
+ graph.insert<cmSPDXLifecycleScopedRelationship>();
+ lifecycleScopedRelationship.Completeness =
+ cmSPDXRelationshipCompletenessType::NO_ASSERTION;
+ lifecycleScopedRelationship.EndTime = "EndTime";
+ lifecycleScopedRelationship.From = ident;
+ lifecycleScopedRelationship.RelationshipType = cmSPDXRelationshipType::OTHER;
+ lifecycleScopedRelationship.StartTime = "StartTime";
+ lifecycleScopedRelationship.To.push_back(ident);
+ lifecycleScopedRelationship.Scope = cmSPDXLifecycleScopeType::OTHER;
+
+ auto& namespaceMap = graph.insert<cmSPDXNamespaceMap>();
+ namespaceMap.Namespace = "Namespace";
+ namespaceMap.Prefix = "Prefix";
+
+ graph.insert<cmSPDXOrganization>();
+
+ auto& packageVerificationCode =
+ graph.insert<cmSPDXPackageVerificationCode>();
+ packageVerificationCode.Algorithm = cmSPDXHashAlgorithm::OTHER;
+ packageVerificationCode.HashValue = "HashValue";
+ packageVerificationCode.PackageVerificationCodeExcludedFile.emplace()
+ .push_back("PacakgeVerificationCodeExcludeFile");
+
+ graph.insert<cmSPDXPerson>();
+
+ auto& positiveIntegerRange = graph.insert<cmSPDXPositiveIntegerRange>();
+ positiveIntegerRange.BeginIntegerRange = 1;
+ positiveIntegerRange.EndIntegerRange = 2;
+
+ graph.insert<cmSPDXRelationship>();
+
+ graph.insert<cmSPDXSoftwareAgent>();
+
+ auto& spdxDocument = graph.insert<cmSPDXSpdxDocument>();
+ spdxDocument.DataLicense = ident;
+ spdxDocument.ExternalMap = ident;
+ spdxDocument.NamespaceMap = ident;
+
+ graph.insert<cmSPDXTool>();
+
+ // Software
+ auto& contentIdentifier = graph.insert<cmSPDXContentIdentifier>();
+ contentIdentifier.ContentIdentifierType =
+ cmSPDXContentIdentifierType::GITOID;
+ contentIdentifier.ContentIdentifierValue = "ContentIdentifierValue";
+
+ auto& file = graph.insert<cmSPDXFile>();
+ file.AdditionalPurpose.emplace().push_back(cmSPDXSoftwarePurpose::OTHER);
+ file.AttributionText = "AttributionText";
+ file.ContentIdentifier = ident;
+ file.CopyrightText = "CopyrightText";
+ file.PrimaryPurpose = cmSPDXSoftwarePurpose::FILE;
+ file.ContentType = "ContentType";
+ file.FileKind = cmSPDXFileKindType::FILE;
+
+ auto& package = graph.insert<cmSPDXPackage>();
+ package.DownloadLocation = "DownloadLocation";
+ package.HomePage = "HomePage";
+ package.PackageUrl = "PackageUrl";
+ package.PackageVersion = "PackageVersion";
+ package.SourceInfo = "SourceInfo";
+
+ auto& sbom = graph.insert<cmSPDXSbom>();
+ sbom.SbomType.emplace().push_back(cmSPDXSbomType::BUILD);
+
+ auto& snippet = graph.insert<cmSPDXSnippet>();
+ snippet.ByteRange = ident;
+ snippet.LineRange = ident;
+ snippet.SnippetFromFile = ident;
+
+ // SimpleLicensing
+ auto& licenseExpression = graph.insert<cmSPDXLicenseExpression>();
+ licenseExpression.CustomIdToUri.emplace().push_back(ident);
+ licenseExpression.LicenseExpression = "LicenseExpression";
+ licenseExpression.LicenseListVersion = "LicenseListVersion";
+
+ auto& simpleLicensingText = graph.insert<cmSPDXSimpleLicensingText>();
+ simpleLicensingText.LicenseText = "LicenseText";
+
+ Json::Value root;
+ Json::Reader().parse(Optional.c_str(), root);
+
+ std::cout << "Optional SPDX:";
+ std::cout << "\nConstructed Graph: " << graph.toJsonLD().toStyledString();
+ std::cout << "\nComparison Graph:" << root.toStyledString() << "\n";
+
+ // Convert to string to disregard differences in number signedness
+ return root.toStyledString() == graph.toJsonLD().toStyledString();
+};
+
+int testSPDXSerializer(int /* argc */, char* /* argv */[])
+{
+ if (!testNonOptional())
+ return -1;
+
+ if (!testOptional())
+ return -1;
+
+ return 0;
+}
diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt
index 15a1e2c..2d40fd0 100644
--- a/Tests/CMakeLists.txt
+++ b/Tests/CMakeLists.txt
@@ -50,6 +50,13 @@
")
endif()
+# Suppress generator deprecation warnings in test suite.
+if(CMAKE_GENERATOR MATCHES "^Visual Studio 14 2015")
+ set(TEST_WARN_VS_CODE "set(ENV{CMAKE_WARN_VS14} OFF)")
+else()
+ set(TEST_WARN_VS_CODE "")
+endif()
+
# 3.9 or later provides a definitive answer to whether we are multi-config
# through a global property. Prior to 3.9, CMAKE_CONFIGURATION_TYPES being set
# is assumed to mean multi-config, but developers might modify it so it is
diff --git a/Tests/CTestUpdateGIT.cmake.in b/Tests/CTestUpdateGIT.cmake.in
index 5e3448b..4921304 100644
--- a/Tests/CTestUpdateGIT.cmake.in
+++ b/Tests/CTestUpdateGIT.cmake.in
@@ -19,6 +19,8 @@
set(AUTHOR_CONFIG "[user]
\tname = Test Author
\temail = testauthor@cmake.org
+[commit]
+\tgpgsign = false
")
#-----------------------------------------------------------------------------
diff --git a/Tests/ExternalProjectUpdate/CMakeLists.txt b/Tests/ExternalProjectUpdate/CMakeLists.txt
index cbddd2f..2339d30 100644
--- a/Tests/ExternalProjectUpdate/CMakeLists.txt
+++ b/Tests/ExternalProjectUpdate/CMakeLists.txt
@@ -95,6 +95,7 @@
GIT_TAG ${TEST_GIT_TAG}
GIT_CONFIG "user.email=testauthor@cmake.org"
"user.name=testauthor"
+ "commit.gpgsign=false"
CMAKE_GENERATOR "${CMAKE_GENERATOR}"
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
INSTALL_COMMAND ""
diff --git a/Tests/FindPackageCMakeTest/CMakeLists.txt b/Tests/FindPackageCMakeTest/CMakeLists.txt
index bd1887a..37a63eb 100644
--- a/Tests/FindPackageCMakeTest/CMakeLists.txt
+++ b/Tests/FindPackageCMakeTest/CMakeLists.txt
@@ -117,7 +117,7 @@
endforeach()
# Enable framework and bundle searching. Make sure bundles are found
-# before unix-syle packages.
+# before unix-style packages.
set(CMAKE_FIND_FRAMEWORK LAST)
set(CMAKE_FIND_APPBUNDLE FIRST)
@@ -584,6 +584,17 @@
unset(SortLib_VERSION)
+set(SortLib_DIR "" CACHE FILEPATH "Wipe out find results for testing." FORCE)
+# Expected to default to 'NATURAL' and 'DEC'
+unset(CMAKE_FIND_PACKAGE_SORT_ORDER)
+unset(CMAKE_FIND_PACKAGE_SORT_DIRECTION)
+FIND_PACKAGE(SortLib CONFIG)
+IF (NOT "${SortLib_VERSION}" STREQUAL "3.10.1")
+ message(SEND_ERROR "FIND_PACKAGE_SORT_ORDER Default! ${SortLib_VERSION}")
+endif()
+unset(SortLib_VERSION)
+
+
set(SortFramework_DIR "" CACHE FILEPATH "Wipe out find results for testing." FORCE)
SET(CMAKE_FIND_PACKAGE_SORT_ORDER NAME)
SET(CMAKE_FIND_PACKAGE_SORT_DIRECTION ASC)
diff --git a/Tests/FindPackageCpsTest/CMakeLists.txt b/Tests/FindPackageCpsTest/CMakeLists.txt
index 574f5a7..43caab4 100644
--- a/Tests/FindPackageCpsTest/CMakeLists.txt
+++ b/Tests/FindPackageCpsTest/CMakeLists.txt
@@ -90,6 +90,7 @@
unset(SortLib_VERSION)
endforeach()
+
set(SortLib_DIR "" CACHE FILEPATH "Wipe out find results for testing." FORCE)
set(CMAKE_FIND_PACKAGE_SORT_ORDER NATURAL)
set(CMAKE_FIND_PACKAGE_SORT_DIRECTION DEC)
@@ -100,6 +101,7 @@
set(SortLib_DIR "" CACHE FILEPATH "Wipe out find results for testing." FORCE)
unset(SortLib_VERSION)
+
set(SortLib_DIR "" CACHE FILEPATH "Wipe out find results for testing." FORCE)
FIND_PACKAGE(SortLib 4.0 CONFIG)
IF (NOT "${SortLib_VERSION}" STREQUAL "4.0.0")
@@ -107,6 +109,18 @@
endif()
unset(SortLib_VERSION)
+
+set(SortLib_DIR "" CACHE FILEPATH "Wipe out find results for testing." FORCE)
+# Expected to default to 'NATURAL' and 'DEC'
+unset(CMAKE_FIND_PACKAGE_SORT_ORDER)
+unset(CMAKE_FIND_PACKAGE_SORT_DIRECTION)
+FIND_PACKAGE(SortLib CONFIG)
+IF (NOT "${SortLib_VERSION}" STREQUAL "3.10.1")
+ message(SEND_ERROR "FIND_PACKAGE_SORT_ORDER Default! ${SortLib_VERSION}")
+endif()
+unset(SortLib_VERSION)
+
+
set(SortFramework_DIR "" CACHE FILEPATH "Wipe out find results for testing." FORCE)
set(CMAKE_FIND_PACKAGE_SORT_ORDER NAME)
set(CMAKE_FIND_PACKAGE_SORT_DIRECTION ASC)
@@ -117,6 +131,7 @@
set(SortLib_DIR "" CACHE FILEPATH "Wipe out find results for testing." FORCE)
unset(SortFramework_VERSION)
+
set(SortFramework_DIR "" CACHE FILEPATH "Wipe out find results for testing." FORCE)
set(CMAKE_FIND_PACKAGE_SORT_ORDER NATURAL)
set(CMAKE_FIND_PACKAGE_SORT_DIRECTION DEC)
@@ -127,6 +142,7 @@
set(SortLib_DIR "" CACHE FILEPATH "Wipe out find results for testing." FORCE)
unset(SortFramework_VERSION)
+
unset(CMAKE_FIND_PACKAGE_SORT_ORDER)
unset(CMAKE_FIND_PACKAGE_SORT_DIRECTION)
diff --git a/Tests/RunCMake/CMP0150/CMakeLists.txt b/Tests/RunCMake/CMP0150/CMakeLists.txt
index 371dccc..29a2e04 100644
--- a/Tests/RunCMake/CMP0150/CMakeLists.txt
+++ b/Tests/RunCMake/CMP0150/CMakeLists.txt
@@ -20,6 +20,7 @@
execGitCommand("${workDir}" config user.email "testauthor@cmake.org")
execGitCommand("${workDir}" config user.name testauthor)
execGitCommand("${workDir}" config core.autocrlf false)
+ execGitCommand("${workDir}" config commit.gpgsign false)
execGitCommand("${workDir}" add CMakeLists.txt)
execGitCommand("${workDir}" commit -m "Initial commit")
endfunction()
diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt
index c92aac1..b2eb35c 100644
--- a/Tests/RunCMake/CMakeLists.txt
+++ b/Tests/RunCMake/CMakeLists.txt
@@ -521,7 +521,8 @@
add_RunCMake_test(GenEx-PATH)
add_RunCMake_test(GenEx-PATH_EQUAL)
add_RunCMake_test(GenEx-LIST)
-add_RunCMake_test(GeneratorExpression)
+add_RunCMake_test(GeneratorExpression -DCMake_TEST_OBJC=${CMake_TEST_OBJC} -DCMake_TEST_Fortran=${CMake_TEST_Fortran}
+ -DCMake_TEST_CUDA=${CMake_TEST_CUDA} -DCMake_TEST_HIP=${CMake_TEST_HIP})
add_RunCMake_test(GeneratorExpressionShortCircuit)
add_RunCMake_test(GeneratorInstance)
add_RunCMake_test(GeneratorPlatform)
@@ -1402,3 +1403,7 @@
add_RunCMake_test(Renesas -DCMake_TEST_Renesas_TOOLCHAINS=${CMake_TEST_Renesas_TOOLCHAINS})
set_property(TEST RunCMake.Renesas APPEND PROPERTY LABELS "Renesas")
endif()
+if(CMake_TEST_Emscripten_TOOLCHAINS)
+ add_RunCMake_test(Emscripten -DCMake_TEST_Emscripten_TOOLCHAINS=${CMake_TEST_Emscripten_TOOLCHAINS})
+ set_property(TEST RunCMake.Emscripten APPEND PROPERTY LABELS "Emscripten")
+endif()
diff --git a/Tests/RunCMake/CommandLine/DeprecateVS14-WARN-OFF.cmake b/Tests/RunCMake/CommandLine/DeprecateVS14-WARN-OFF.cmake
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/DeprecateVS14-WARN-OFF.cmake
diff --git a/Tests/RunCMake/CommandLine/DeprecateVS14-WARN-ON-stderr.txt b/Tests/RunCMake/CommandLine/DeprecateVS14-WARN-ON-stderr.txt
new file mode 100644
index 0000000..47caf4e
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/DeprecateVS14-WARN-ON-stderr.txt
@@ -0,0 +1,5 @@
+^CMake Warning:
+ The "Visual Studio 14 2015" generator is deprecated and will be removed in
+ a future version of CMake.
+
+ Add CMAKE_WARN_VS14=OFF to the cache to disable this warning.$
diff --git a/Tests/RunCMake/CommandLine/DeprecateVS14-WARN-ON.cmake b/Tests/RunCMake/CommandLine/DeprecateVS14-WARN-ON.cmake
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/DeprecateVS14-WARN-ON.cmake
diff --git a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake
index 9fda9eb..944f902 100644
--- a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake
@@ -1167,3 +1167,10 @@
endif()
set(ENV{CMAKE_CONFIG_DIR} cmake_config_dir)
run_cmake_command(print-config-dir-env ${CMAKE_COMMAND} "--print-config-dir")
+
+if(RunCMake_GENERATOR MATCHES "^Visual Studio 14 2015")
+ run_cmake_with_options(DeprecateVS14-WARN-ON -DCMAKE_WARN_VS14=ON)
+ unset(ENV{CMAKE_WARN_VS14})
+ run_cmake(DeprecateVS14-WARN-ON)
+ run_cmake_with_options(DeprecateVS14-WARN-OFF -DCMAKE_WARN_VS14=OFF)
+endif()
diff --git a/Tests/RunCMake/Emscripten/CMakeLists.txt b/Tests/RunCMake/Emscripten/CMakeLists.txt
new file mode 100644
index 0000000..955802c
--- /dev/null
+++ b/Tests/RunCMake/Emscripten/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 4.0)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/Emscripten/RunCMakeTest.cmake b/Tests/RunCMake/Emscripten/RunCMakeTest.cmake
new file mode 100644
index 0000000..efce630
--- /dev/null
+++ b/Tests/RunCMake/Emscripten/RunCMakeTest.cmake
@@ -0,0 +1,66 @@
+include(RunCMake)
+
+# Locate Emscripten toolchain
+if(RunCMake_GENERATOR MATCHES "Makefile|Ninja")
+ file(GLOB _emscripten_toolchains
+ "${CMake_TEST_Emscripten_TOOLCHAINS}/emcc" )
+ if(_emscripten_toolchains STREQUAL "")
+ message(FATAL_ERROR "Could not find any Emscripten toolchains at: ${CMake_TEST_Emscripten_TOOLCHAINS}.")
+ endif()
+endif()
+
+function(run_toolchain case)
+ set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${case}-build)
+ run_cmake_with_options(${case} ${ARGN})
+ set(RunCMake_TEST_NO_CLEAN 1)
+ run_cmake_command(${case}-build ${CMAKE_COMMAND} --build .)
+endfunction()
+
+macro(run_cmake_target test subtest target)
+ set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${test}-build)
+ set(RunCMake_TEST_NO_CLEAN 1)
+ run_cmake_command(${test}-${subtest}-build ${CMAKE_COMMAND} --build . --target ${target} --config Release --verbose ${ARGN})
+ unset(RunCMake_TEST_BINARY_DIR)
+ unset(RunCMake_TEST_NO_CLEAN)
+endmacro()
+
+foreach(_emscripten_toolchain IN LISTS _emscripten_toolchains)
+ message(STATUS "Found Emscripten toolchain: ${_emscripten_toolchain}")
+ cmake_path(GET _emscripten_toolchain PARENT_PATH BIN_DIR)
+
+ if (WIN32)
+ set(EMCC_SUFFIX ".bat")
+ else()
+ set(EMCC_SUFFIX "")
+ endif()
+
+ set(c_comp ${BIN_DIR}/emcc${EMCC_SUFFIX})
+ set(cxx_comp ${BIN_DIR}/em++${EMCC_SUFFIX})
+ set(comp_ar ${BIN_DIR}/emar${EMCC_SUFFIX})
+
+ # Create an executable from .c sources only.
+ run_toolchain(emscripten-c
+ -DCMAKE_SYSTEM_NAME=Emscripten
+ -DCMAKE_C_COMPILER=${c_comp}
+ )
+
+ # Create an executable from .c and .cxx sources.
+ run_toolchain(emscripten-cxx
+ -DCMAKE_SYSTEM_NAME=Emscripten
+ -DCMAKE_C_COMPILER=${c_comp}
+ -DCMAKE_CXX_COMPILER=${cxx_comp}
+ )
+
+ # Create a library and executable from .c sources.
+ run_toolchain(emscripten-lib
+ -DCMAKE_SYSTEM_NAME=Emscripten
+ -DCMAKE_C_COMPILER=${c_comp}
+ )
+
+ run_cmake_with_options(emscripten-WHOLE_ARCHIVE
+ -DCMAKE_SYSTEM_NAME=Emscripten
+ -DCMAKE_C_COMPILER=${c_comp}
+ )
+ run_cmake_target(emscripten-WHOLE_ARCHIVE link-exe main)
+ run_cmake_target(emscripten-WHOLE_ARCHIVE circular-exe main_circular)
+endforeach()
diff --git a/Tests/RunCMake/Emscripten/base.c b/Tests/RunCMake/Emscripten/base.c
new file mode 100644
index 0000000..ed769a0
--- /dev/null
+++ b/Tests/RunCMake/Emscripten/base.c
@@ -0,0 +1,9 @@
+
+#if !defined(STATIC_BASE)
+# if defined(_WIN32)
+__declspec(dllexport)
+# endif
+#endif
+ void base(void)
+{
+}
diff --git a/Tests/RunCMake/Emscripten/circular1.c b/Tests/RunCMake/Emscripten/circular1.c
new file mode 100644
index 0000000..80ee413
--- /dev/null
+++ b/Tests/RunCMake/Emscripten/circular1.c
@@ -0,0 +1,6 @@
+void circular2(void);
+
+void circular1(void)
+{
+ circular2();
+}
diff --git a/Tests/RunCMake/Emscripten/circular2.c b/Tests/RunCMake/Emscripten/circular2.c
new file mode 100644
index 0000000..751bab5
--- /dev/null
+++ b/Tests/RunCMake/Emscripten/circular2.c
@@ -0,0 +1,7 @@
+
+void circular1(void);
+
+void circular2(void)
+{
+ circular1();
+}
diff --git a/Tests/RunCMake/Emscripten/emscripten-WHOLE_ARCHIVE.cmake b/Tests/RunCMake/Emscripten/emscripten-WHOLE_ARCHIVE.cmake
new file mode 100644
index 0000000..e826eae
--- /dev/null
+++ b/Tests/RunCMake/Emscripten/emscripten-WHOLE_ARCHIVE.cmake
@@ -0,0 +1,20 @@
+
+enable_language(C)
+
+add_library(base STATIC base.c unref.c)
+target_compile_definitions(base PUBLIC STATIC_BASE)
+
+add_library(lib SHARED lib.c)
+target_link_libraries(lib PRIVATE "$<LINK_LIBRARY:WHOLE_ARCHIVE,base>")
+
+add_executable(main main.c)
+target_link_libraries(main PRIVATE lib)
+
+add_library(circular1 STATIC circular1.c)
+add_library(circular2 STATIC circular2.c)
+
+target_link_libraries(circular1 PRIVATE circular2)
+target_link_libraries(circular2 PRIVATE circular1)
+
+add_executable(main_circular main_circular.c)
+target_link_libraries(main_circular PRIVATE $<LINK_LIBRARY:WHOLE_ARCHIVE,circular1>)
diff --git a/Tests/RunCMake/Emscripten/emscripten-c.cmake b/Tests/RunCMake/Emscripten/emscripten-c.cmake
new file mode 100644
index 0000000..39325a7
--- /dev/null
+++ b/Tests/RunCMake/Emscripten/emscripten-c.cmake
@@ -0,0 +1,2 @@
+enable_language(C)
+add_executable(exec-c module.c)
diff --git a/Tests/RunCMake/Emscripten/emscripten-cxx.cmake b/Tests/RunCMake/Emscripten/emscripten-cxx.cmake
new file mode 100644
index 0000000..9e00aa3
--- /dev/null
+++ b/Tests/RunCMake/Emscripten/emscripten-cxx.cmake
@@ -0,0 +1,2 @@
+enable_language(CXX)
+add_executable(exec-cxx module.cxx)
diff --git a/Tests/RunCMake/Emscripten/emscripten-lib.cmake b/Tests/RunCMake/Emscripten/emscripten-lib.cmake
new file mode 100644
index 0000000..a215d02
--- /dev/null
+++ b/Tests/RunCMake/Emscripten/emscripten-lib.cmake
@@ -0,0 +1,6 @@
+enable_language(C)
+add_library(emscripten-test-lib libmod.c)
+
+add_executable(exec-lib-c module.c)
+target_compile_definitions(exec-lib-c PRIVATE __USE_LIBFUN)
+target_link_libraries(exec-lib-c PRIVATE emscripten-test-lib)
diff --git a/Tests/RunCMake/Emscripten/lib.c b/Tests/RunCMake/Emscripten/lib.c
new file mode 100644
index 0000000..21f559c
--- /dev/null
+++ b/Tests/RunCMake/Emscripten/lib.c
@@ -0,0 +1,15 @@
+
+#if !defined(STATIC_BASE)
+# if defined(_WIN32)
+__declspec(dllimport)
+# endif
+#endif
+ void base(void);
+
+#if defined(_WIN32)
+__declspec(dllexport)
+#endif
+ void lib(void)
+{
+ base();
+}
diff --git a/Tests/RunCMake/Emscripten/libmod.c b/Tests/RunCMake/Emscripten/libmod.c
new file mode 100644
index 0000000..b0d3952
--- /dev/null
+++ b/Tests/RunCMake/Emscripten/libmod.c
@@ -0,0 +1,4 @@
+int emscripten_libfun()
+{
+ return 42;
+}
diff --git a/Tests/RunCMake/Emscripten/main.c b/Tests/RunCMake/Emscripten/main.c
new file mode 100644
index 0000000..2e39bce
--- /dev/null
+++ b/Tests/RunCMake/Emscripten/main.c
@@ -0,0 +1,18 @@
+
+#if defined(_WIN32)
+__declspec(dllimport)
+#endif
+ void lib(void);
+
+#if defined(_WIN32)
+__declspec(dllimport)
+#endif
+ void unref(void);
+
+int main(void)
+{
+ lib();
+ unref();
+
+ return 0;
+}
diff --git a/Tests/RunCMake/Emscripten/main_circular.c b/Tests/RunCMake/Emscripten/main_circular.c
new file mode 100644
index 0000000..16ebee6
--- /dev/null
+++ b/Tests/RunCMake/Emscripten/main_circular.c
@@ -0,0 +1,9 @@
+
+void circular1(void);
+
+int main(void)
+{
+ circular1();
+
+ return 0;
+}
diff --git a/Tests/RunCMake/Emscripten/module.c b/Tests/RunCMake/Emscripten/module.c
new file mode 100644
index 0000000..62014fa
--- /dev/null
+++ b/Tests/RunCMake/Emscripten/module.c
@@ -0,0 +1,15 @@
+#include "module.h"
+#if defined(__USE_LIBFUN)
+extern int emscripten_libfun();
+#endif
+
+int i;
+int main()
+{
+#if defined(__USE_LIBFUN)
+ i = emscripten_libfun();
+#else
+ i = INTERNAL;
+#endif
+ return i;
+}
diff --git a/Tests/RunCMake/Emscripten/module.cxx b/Tests/RunCMake/Emscripten/module.cxx
new file mode 100644
index 0000000..b4d46b1
--- /dev/null
+++ b/Tests/RunCMake/Emscripten/module.cxx
@@ -0,0 +1,7 @@
+#include "module.h"
+int i;
+int main()
+{
+ i = INTERNAL;
+ return i;
+}
diff --git a/Tests/RunCMake/Emscripten/module.h b/Tests/RunCMake/Emscripten/module.h
new file mode 100644
index 0000000..a8a85a6
--- /dev/null
+++ b/Tests/RunCMake/Emscripten/module.h
@@ -0,0 +1,12 @@
+#ifndef __MODULE_H__
+#define __MODULE_H__
+
+#if defined(__cplusplus)
+# define INTERNAL 64
+#elif !defined(__cplusplus)
+# define INTERNAL 32
+#else
+# error "Unable to determine INTERNAL symbol."
+#endif
+
+#endif /* __MODULE_H__ */
diff --git a/Tests/RunCMake/Emscripten/unref.c b/Tests/RunCMake/Emscripten/unref.c
new file mode 100644
index 0000000..11922de
--- /dev/null
+++ b/Tests/RunCMake/Emscripten/unref.c
@@ -0,0 +1,8 @@
+
+
+#if defined(_WIN32)
+__declspec(dllexport)
+#endif
+ void unref(void)
+{
+}
diff --git a/Tests/RunCMake/ExportPackageInfo/Appendix-check.cmake b/Tests/RunCMake/ExportPackageInfo/Appendix-check.cmake
index c4f617f..8d55625 100644
--- a/Tests/RunCMake/ExportPackageInfo/Appendix-check.cmake
+++ b/Tests/RunCMake/ExportPackageInfo/Appendix-check.cmake
@@ -5,11 +5,13 @@
file(READ "${out_dir}/foo.cps" content)
expect_value("${content}" "foo" "name")
expect_value("${content}" "interface" "components" "mammal" "type")
+expect_value("${content}" "LGPL-3.0-or-later" "default_license")
expect_value("${content}" "1.0" "version")
file(READ "${out_dir}/foo-dog.cps" content)
expect_value("${content}" "foo" "name")
expect_value("${content}" "interface" "components" "canine" "type")
+expect_value("${content}" "GPL-3.0-or-later" "default_license")
expect_missing("${content}" "version")
expect_array("${content}" 1 "components" "canine" "requires")
diff --git a/Tests/RunCMake/ExportPackageInfo/Appendix.cmake b/Tests/RunCMake/ExportPackageInfo/Appendix.cmake
index 153231f..51a3c62 100644
--- a/Tests/RunCMake/ExportPackageInfo/Appendix.cmake
+++ b/Tests/RunCMake/ExportPackageInfo/Appendix.cmake
@@ -5,5 +5,14 @@
install(TARGETS mammal EXPORT mammal DESTINATION .)
install(TARGETS canine EXPORT canine DESTINATION .)
-export(EXPORT mammal PACKAGE_INFO foo VERSION 1.0)
-export(EXPORT canine PACKAGE_INFO foo APPENDIX dog)
+export(
+ EXPORT mammal
+ PACKAGE_INFO foo
+ VERSION 1.0
+ DEFAULT_LICENSE "LGPL-3.0-or-later")
+
+export(
+ EXPORT canine
+ PACKAGE_INFO foo
+ APPENDIX dog
+ DEFAULT_LICENSE "GPL-3.0-or-later")
diff --git a/Tests/RunCMake/ExportPackageInfo/BadArgs2-stderr.txt b/Tests/RunCMake/ExportPackageInfo/BadArgs2-stderr.txt
index cc81af4..a811229 100644
--- a/Tests/RunCMake/ExportPackageInfo/BadArgs2-stderr.txt
+++ b/Tests/RunCMake/ExportPackageInfo/BadArgs2-stderr.txt
@@ -5,6 +5,12 @@
CMake Error at BadArgs2\.cmake:[0-9]+ \(export\):
+ export APPENDIX and LICENSE are mutually exclusive\.
+Call Stack \(most recent call first\):
+ CMakeLists\.txt:3 \(include\)
+
+
+CMake Error at BadArgs2\.cmake:[0-9]+ \(export\):
export APPENDIX and DESCRIPTION are mutually exclusive\.
Call Stack \(most recent call first\):
CMakeLists\.txt:3 \(include\)
diff --git a/Tests/RunCMake/ExportPackageInfo/BadArgs2.cmake b/Tests/RunCMake/ExportPackageInfo/BadArgs2.cmake
index 5f4c949..6058c7f 100644
--- a/Tests/RunCMake/ExportPackageInfo/BadArgs2.cmake
+++ b/Tests/RunCMake/ExportPackageInfo/BadArgs2.cmake
@@ -1,8 +1,10 @@
add_library(foo INTERFACE)
install(TARGETS foo EXPORT foo DESTINATION .)
-export(EXPORT foo PACKAGE_INFO foo APPENDIX test VERSION 1.0)
-export(EXPORT foo PACKAGE_INFO foo APPENDIX test DESCRIPTION "Test")
-export(EXPORT foo PACKAGE_INFO foo APPENDIX test HOMEPAGE_URL "example.com")
-export(EXPORT foo PACKAGE_INFO foo APPENDIX test DEFAULT_TARGETS foo)
-export(EXPORT foo PACKAGE_INFO foo APPENDIX test DEFAULT_CONFIGURATIONS Release)
-export(EXPORT foo PACKAGE_INFO foo APPENDIX test PROJECT foo)
+set(args EXPORT foo PACKAGE_INFO foo APPENDIX test)
+export(${args} VERSION 1.0)
+export(${args} LICENSE "BSD-3-Clause AND CC-BY-SA-4.0")
+export(${args} DESCRIPTION "Test")
+export(${args} HOMEPAGE_URL "example.com")
+export(${args} DEFAULT_TARGETS foo)
+export(${args} DEFAULT_CONFIGURATIONS Release)
+export(${args} PROJECT foo)
diff --git a/Tests/RunCMake/ExportPackageInfo/BadArgs4-stderr.txt b/Tests/RunCMake/ExportPackageInfo/BadArgs4-stderr.txt
index e21b87e..2471497 100644
--- a/Tests/RunCMake/ExportPackageInfo/BadArgs4-stderr.txt
+++ b/Tests/RunCMake/ExportPackageInfo/BadArgs4-stderr.txt
@@ -17,6 +17,18 @@
CMake Error at BadArgs4\.cmake:[0-9]+ \(export\):
+ export LICENSE requires PACKAGE_INFO\.
+Call Stack \(most recent call first\):
+ CMakeLists\.txt:3 \(include\)
+
+
+CMake Error at BadArgs4\.cmake:[0-9]+ \(export\):
+ export DEFAULT_LICENSE requires PACKAGE_INFO\.
+Call Stack \(most recent call first\):
+ CMakeLists\.txt:3 \(include\)
+
+
+CMake Error at BadArgs4\.cmake:[0-9]+ \(export\):
export DESCRIPTION requires PACKAGE_INFO\.
Call Stack \(most recent call first\):
CMakeLists\.txt:3 \(include\)
diff --git a/Tests/RunCMake/ExportPackageInfo/BadArgs4.cmake b/Tests/RunCMake/ExportPackageInfo/BadArgs4.cmake
index d8cb163..2405a63 100644
--- a/Tests/RunCMake/ExportPackageInfo/BadArgs4.cmake
+++ b/Tests/RunCMake/ExportPackageInfo/BadArgs4.cmake
@@ -1,11 +1,14 @@
add_library(foo INTERFACE)
install(TARGETS foo EXPORT foo DESTINATION .)
-export(EXPORT foo LOWER_CASE_FILE)
-export(EXPORT foo APPENDIX test)
-export(EXPORT foo VERSION 1.0)
-export(EXPORT foo DESCRIPTION "Test")
-export(EXPORT foo HOMEPAGE_URL "example.com")
-export(EXPORT foo DEFAULT_TARGETS foo)
-export(EXPORT foo DEFAULT_CONFIGURATIONS Release)
-export(EXPORT foo PROJECT foo)
-export(EXPORT foo NO_PROJECT_METADATA)
+set(args EXPORT foo)
+export(${args} LOWER_CASE_FILE)
+export(${args} APPENDIX test)
+export(${args} VERSION 1.0)
+export(${args} LICENSE "BSD-3-Clause AND CC-BY-SA-4.0")
+export(${args} DEFAULT_LICENSE "BSD-3-Clause")
+export(${args} DESCRIPTION "Test")
+export(${args} HOMEPAGE_URL "example.com")
+export(${args} DEFAULT_TARGETS foo)
+export(${args} DEFAULT_CONFIGURATIONS Release)
+export(${args} PROJECT foo)
+export(${args} NO_PROJECT_METADATA)
diff --git a/Tests/RunCMake/ExportPackageInfo/Metadata-check.cmake b/Tests/RunCMake/ExportPackageInfo/Metadata-check.cmake
index f9b3cc7..438a76c 100644
--- a/Tests/RunCMake/ExportPackageInfo/Metadata-check.cmake
+++ b/Tests/RunCMake/ExportPackageInfo/Metadata-check.cmake
@@ -15,5 +15,7 @@
expect_value("${content}" "release" "configurations" 0)
expect_value("${content}" "debug" "configurations" 1)
+expect_value("${content}" "BSD-3-Clause" "default_license")
+expect_value("${content}" "BSD-3-Clause AND CC-BY-SA-4.0" "license")
expect_value("${content}" "Sample package" "description")
expect_value("${content}" "https://www.example.com/package/foo" "website")
diff --git a/Tests/RunCMake/ExportPackageInfo/Metadata.cmake b/Tests/RunCMake/ExportPackageInfo/Metadata.cmake
index 2311695..4f3bd16 100644
--- a/Tests/RunCMake/ExportPackageInfo/Metadata.cmake
+++ b/Tests/RunCMake/ExportPackageInfo/Metadata.cmake
@@ -8,6 +8,8 @@
COMPAT_VERSION 1.2.0
DEFAULT_TARGETS foo
DEFAULT_CONFIGURATIONS release debug
+ LICENSE "BSD-3-Clause AND CC-BY-SA-4.0"
+ DEFAULT_LICENSE "BSD-3-Clause"
DESCRIPTION "Sample package"
HOMEPAGE_URL "https://www.example.com/package/foo"
)
diff --git a/Tests/RunCMake/ExportPackageInfo/ProjectMetadata-check.cmake b/Tests/RunCMake/ExportPackageInfo/ProjectMetadata-check.cmake
index 1330099..c7201f8 100644
--- a/Tests/RunCMake/ExportPackageInfo/ProjectMetadata-check.cmake
+++ b/Tests/RunCMake/ExportPackageInfo/ProjectMetadata-check.cmake
@@ -6,6 +6,7 @@
expect_value("${content}" "foo" "name")
expect_value("${content}" "1.2.3" "version")
expect_value("${content}" "1.1.0" "compat_version")
+expect_value("${content}" "BSD-3-Clause" "license")
expect_value("${content}" "Sample package" "description")
expect_value("${content}" "https://www.example.com/package/foo" "website")
@@ -13,6 +14,7 @@
expect_value("${content}" "test1" "name")
expect_value("${content}" "1.2.3" "version")
expect_value("${content}" "1.1.0" "compat_version")
+expect_value("${content}" "BSD-3-Clause" "license")
expect_value("${content}" "Sample package" "description")
expect_value("${content}" "https://www.example.com/package/foo" "website")
@@ -20,5 +22,6 @@
expect_value("${content}" "test2" "name")
expect_value("${content}" "1.4.7" "version")
expect_missing("${content}" "compat_version")
+expect_value("${content}" "Apache-2.0" "license")
expect_value("${content}" "Don't inherit" "description")
expect_value("${content}" "https://www.example.com/package/bar" "website")
diff --git a/Tests/RunCMake/ExportPackageInfo/ProjectMetadata.cmake b/Tests/RunCMake/ExportPackageInfo/ProjectMetadata.cmake
index f53ba0e..e8f29af 100644
--- a/Tests/RunCMake/ExportPackageInfo/ProjectMetadata.cmake
+++ b/Tests/RunCMake/ExportPackageInfo/ProjectMetadata.cmake
@@ -1,6 +1,7 @@
project(foo
VERSION 1.2.3
COMPAT_VERSION 1.1.0
+ SPDX_LICENSE "BSD-3-Clause"
DESCRIPTION "Sample package"
HOMEPAGE_URL "https://www.example.com/package/foo"
)
@@ -27,6 +28,7 @@
PROJECT foo
PACKAGE_INFO test2
VERSION 1.4.7
+ LICENSE "Apache-2.0"
DESCRIPTION "Don't inherit"
HOMEPAGE_URL "https://www.example.com/package/bar"
)
diff --git a/Tests/RunCMake/ExternalProject/FetchGitRefs.cmake b/Tests/RunCMake/ExternalProject/FetchGitRefs.cmake
index a00908b..6f3db4d 100644
--- a/Tests/RunCMake/ExternalProject/FetchGitRefs.cmake
+++ b/Tests/RunCMake/ExternalProject/FetchGitRefs.cmake
@@ -47,6 +47,7 @@
execGitCommand(-c init.defaultBranch=master init)
execGitCommand(config --add user.email "testauthor@cmake.org")
execGitCommand(config --add user.name testauthor)
+execGitCommand(config commit.gpgsign "false")
# Create the initial repo structure
execGitCommand(add firstFile.txt)
diff --git a/Tests/RunCMake/GeneratorExpression/COMPILER_LINKER.cmake b/Tests/RunCMake/GeneratorExpression/COMPILER_LINKER.cmake
new file mode 100644
index 0000000..aedf6e4
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/COMPILER_LINKER.cmake
@@ -0,0 +1,19 @@
+
+set(languages C ${LANG})
+list(REMOVE_DUPLICATES languages)
+
+enable_language(${languages})
+
+include(CTest)
+
+set(VAR "${CMAKE_${LANG}_COMPILER_LINKER_${TYPE}}")
+if(NOT VAR)
+ set(VAR "UNDEF")
+endif()
+
+add_executable(COMPILER_LINKER compiler_linker.c)
+target_compile_definitions(COMPILER_LINKER PRIVATE "VAR=${VAR}"
+ "GENEX=$<IF:$<BOOL:$<${LANG}_COMPILER_LINKER_${TYPE}>>,$<${LANG}_COMPILER_LINKER_${TYPE}>,UNDEF>")
+
+add_test(NAME COMPILER_LINKER.${LANG}.${TYPE}
+ COMMAND COMPILER_LINKER)
diff --git a/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.C.FRONTEND_VARIANT-stderr.txt b/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.C.FRONTEND_VARIANT-stderr.txt
new file mode 100644
index 0000000..35285fc
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.C.FRONTEND_VARIANT-stderr.txt
@@ -0,0 +1,9 @@
+CMake Error at NonValidTarget-COMPILER_LINKER.cmake:[0-9]+ \(add_custom_command\):
+ Error evaluating generator expression:
+
+ \$<C_COMPILER_LINKER_FRONTEND_VARIANT>
+
+ \$<C_COMPILER_LINKER_FRONTEND_VARIANT> may only be used with binary targets.
+ It may not be used with add_custom_command or add_custom_target.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.C.ID-stderr.txt b/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.C.ID-stderr.txt
new file mode 100644
index 0000000..b68ff04
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.C.ID-stderr.txt
@@ -0,0 +1,9 @@
+CMake Error at NonValidTarget-COMPILER_LINKER.cmake:[0-9]+ \(add_custom_command\):
+ Error evaluating generator expression:
+
+ \$<C_COMPILER_LINKER_ID>
+
+ \$<C_COMPILER_LINKER_ID> may only be used with binary targets. It may not
+ be used with add_custom_command or add_custom_target.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.CUDA.FRONTEND_VARIANT-stderr.txt b/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.CUDA.FRONTEND_VARIANT-stderr.txt
new file mode 100644
index 0000000..796707f
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.CUDA.FRONTEND_VARIANT-stderr.txt
@@ -0,0 +1,9 @@
+CMake Error at NonValidTarget-COMPILER_LINKER.cmake:[0-9]+ \(add_custom_command\):
+ Error evaluating generator expression:
+
+ \$<CUDA_COMPILER_LINKER_FRONTEND_VARIANT>
+
+ \$<CUDA_COMPILER_LINKER_FRONTEND_VARIANT> may only be used with binary
+ targets. It may not be used with add_custom_command or add_custom_target.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.CUDA.ID-stderr.txt b/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.CUDA.ID-stderr.txt
new file mode 100644
index 0000000..d5a67a6
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.CUDA.ID-stderr.txt
@@ -0,0 +1,9 @@
+CMake Error at NonValidTarget-COMPILER_LINKER.cmake:[0-9]+ \(add_custom_command\):
+ Error evaluating generator expression:
+
+ \$<CUDA_COMPILER_LINKER_ID>
+
+ \$<CUDA_COMPILER_LINKER_ID> may only be used with binary targets. It may
+ not be used with add_custom_command or add_custom_target.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.CXX.FRONTEND_VARIANT-stderr.txt b/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.CXX.FRONTEND_VARIANT-stderr.txt
new file mode 100644
index 0000000..818c506
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.CXX.FRONTEND_VARIANT-stderr.txt
@@ -0,0 +1,9 @@
+CMake Error at NonValidTarget-COMPILER_LINKER.cmake:[0-9]+ \(add_custom_command\):
+ Error evaluating generator expression:
+
+ \$<CXX_COMPILER_LINKER_FRONTEND_VARIANT>
+
+ \$<CXX_COMPILER_LINKER_FRONTEND_VARIANT> may only be used with binary
+ targets. It may not be used with add_custom_command or add_custom_target.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.CXX.ID-stderr.txt b/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.CXX.ID-stderr.txt
new file mode 100644
index 0000000..b3e9636
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.CXX.ID-stderr.txt
@@ -0,0 +1,9 @@
+CMake Error at NonValidTarget-COMPILER_LINKER.cmake:[0-9]+ \(add_custom_command\):
+ Error evaluating generator expression:
+
+ \$<CXX_COMPILER_LINKER_ID>
+
+ \$<CXX_COMPILER_LINKER_ID> may only be used with binary targets. It may not
+ be used with add_custom_command or add_custom_target.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.Fortran.FRONTEND_VARIANT-stderr.txt b/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.Fortran.FRONTEND_VARIANT-stderr.txt
new file mode 100644
index 0000000..5271aa2
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.Fortran.FRONTEND_VARIANT-stderr.txt
@@ -0,0 +1,9 @@
+CMake Error at NonValidTarget-COMPILER_LINKER.cmake:[0-9]+ \(add_custom_command\):
+ Error evaluating generator expression:
+
+ \$<Fortran_COMPILER_LINKER_FRONTEND_VARIANT>
+
+ \$<Fortran_COMPILER_LINKER_FRONTEND_VARIANT> may only be used with binary
+ targets. It may not be used with add_custom_command or add_custom_target.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.Fortran.ID-stderr.txt b/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.Fortran.ID-stderr.txt
new file mode 100644
index 0000000..fba2c28
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.Fortran.ID-stderr.txt
@@ -0,0 +1,9 @@
+CMake Error at NonValidTarget-COMPILER_LINKER.cmake:[0-9]+ \(add_custom_command\):
+ Error evaluating generator expression:
+
+ \$<Fortran_COMPILER_LINKER_ID>
+
+ \$<Fortran_COMPILER_LINKER_ID> may only be used with binary targets. It may
+ not be used with add_custom_command or add_custom_target.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.HIP.FRONTEND_VARIANT-stderr.txt b/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.HIP.FRONTEND_VARIANT-stderr.txt
new file mode 100644
index 0000000..a260a01
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.HIP.FRONTEND_VARIANT-stderr.txt
@@ -0,0 +1,9 @@
+CMake Error at NonValidTarget-COMPILER_LINKER.cmake:[0-9]+ \(add_custom_command\):
+ Error evaluating generator expression:
+
+ \$<HIP_COMPILER_LINKER_FRONTEND_VARIANT>
+
+ \$<HIP_COMPILER_LINKER_FRONTEND_VARIANT> may only be used with binary
+ targets. It may not be used with add_custom_command or add_custom_target.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.HIP.ID-stderr.txt b/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.HIP.ID-stderr.txt
new file mode 100644
index 0000000..da64b4e
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.HIP.ID-stderr.txt
@@ -0,0 +1,9 @@
+CMake Error at NonValidTarget-COMPILER_LINKER.cmake:[0-9]+ \(add_custom_command\):
+ Error evaluating generator expression:
+
+ \$<HIP_COMPILER_LINKER_ID>
+
+ \$<HIP_COMPILER_LINKER_ID> may only be used with binary targets. It may not
+ be used with add_custom_command or add_custom_target.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.OBJC.FRONTEND_VARIANT-stderr.txt b/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.OBJC.FRONTEND_VARIANT-stderr.txt
new file mode 100644
index 0000000..80aee3e
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.OBJC.FRONTEND_VARIANT-stderr.txt
@@ -0,0 +1,9 @@
+CMake Error at NonValidTarget-COMPILER_LINKER.cmake:[0-9]+ \(add_custom_command\):
+ Error evaluating generator expression:
+
+ \$<OBJC_COMPILER_LINKER_FRONTEND_VARIANT>
+
+ \$<OBJC_COMPILER_LINKER_FRONTEND_VARIANT> may only be used with binary
+ targets. It may not be used with add_custom_command or add_custom_target.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.OBJC.ID-stderr.txt b/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.OBJC.ID-stderr.txt
new file mode 100644
index 0000000..c23c539
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.OBJC.ID-stderr.txt
@@ -0,0 +1,9 @@
+CMake Error at NonValidTarget-COMPILER_LINKER.cmake:[0-9]+ \(add_custom_command\):
+ Error evaluating generator expression:
+
+ \$<OBJC_COMPILER_LINKER_ID>
+
+ \$<OBJC_COMPILER_LINKER_ID> may only be used with binary targets. It may
+ not be used with add_custom_command or add_custom_target.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.OBJCXX.FRONTEND_VARIANT-stderr.txt b/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.OBJCXX.FRONTEND_VARIANT-stderr.txt
new file mode 100644
index 0000000..506a48b
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.OBJCXX.FRONTEND_VARIANT-stderr.txt
@@ -0,0 +1,9 @@
+CMake Error at NonValidTarget-COMPILER_LINKER.cmake:[0-9]+ \(add_custom_command\):
+ Error evaluating generator expression:
+
+ \$<OBJCXX_COMPILER_LINKER_FRONTEND_VARIANT>
+
+ \$<OBJCXX_COMPILER_LINKER_FRONTEND_VARIANT> may only be used with binary
+ targets. It may not be used with add_custom_command or add_custom_target.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.OBJCXX.ID-stderr.txt b/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.OBJCXX.ID-stderr.txt
new file mode 100644
index 0000000..7160ef7
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.OBJCXX.ID-stderr.txt
@@ -0,0 +1,9 @@
+CMake Error at NonValidTarget-COMPILER_LINKER.cmake:[0-9]+ \(add_custom_command\):
+ Error evaluating generator expression:
+
+ \$<OBJCXX_COMPILER_LINKER_ID>
+
+ \$<OBJCXX_COMPILER_LINKER_ID> may only be used with binary targets. It may
+ not be used with add_custom_command or add_custom_target.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.cmake b/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.cmake
new file mode 100644
index 0000000..0853e72
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.cmake
@@ -0,0 +1,4 @@
+add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/copied_file.c"
+ COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_CURRENT_SOURCE_DIR}/empty.c" "${CMAKE_CURRENT_BINARY_DIR}/copied_file$<${LANG}_COMPILER_LINKER_${TYPE}>.c"
+)
+add_custom_target(drive DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/copied_file.c")
diff --git a/Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake b/Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake
index 985d91b..fe7b64a 100644
--- a/Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake
+++ b/Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake
@@ -48,6 +48,49 @@
run_cmake(FILTER-Exclude)
run_cmake(FILTER-Include)
+function(run_linker_genex test lang type)
+ set(options_args CHECK_RESULT EXECUTE)
+ cmake_parse_arguments(PARSE_ARGV 3 RLG "${options_args}" "" "")
+
+ set(RunCMake_TEST_VARIANT_DESCRIPTION ".${lang}.${type}")
+ set(test_name ${test}${RunCMake_TEST_VARIANT_DESCRIPTION})
+ set(RunCMake_TEST_BINARY_DIR "${RunCMake_BINARY_DIR}/${test_name}-build")
+ if(NOT RunCMake_GENERATOR_IS_MULTI_CONFIG)
+ list(APPEND options -DCMAKE_BUILD_TYPE=Release)
+ endif()
+ if(RLG_CHECK_RESULT)
+ set(RunCMake_TEST_EXPECT_RESULT 1)
+ file(READ "${RunCMake_SOURCE_DIR}/${test_name}-stderr.txt" RunCMake_TEST_EXPECT_stderr)
+ endif()
+ run_cmake_with_options(${test} -DLANG=${lang} -DTYPE=${type})
+ set(RunCMake_TEST_NO_CLEAN 1)
+ unset(RunCMake_TEST_VARIANT_DESCRIPTION)
+ if(RLG_EXECUTE)
+ run_cmake_command(${test_name}-build "${CMAKE_COMMAND}" --build . --config Release)
+ run_cmake_command(${test_name}-run "${CMAKE_CTEST_COMMAND}" -C Release -V)
+ endif()
+endfunction()
+function(exec_linker_genex test lang type)
+ run_linker_genex(${ARGV} EXECUTE)
+endfunction()
+
+set(languages C CXX)
+foreach(lang IN ITEMS OBJC Fortran CUDA HIP)
+ if(CMake_TEST_${lang})
+ list(APPEND languages ${lang})
+ if(lang STREQUAL OBJC)
+ list(APPEND languages OBJCXX)
+ endif()
+ endif()
+endforeach()
+
+foreach(lang IN LISTS languages)
+ foreach(type IN ITEMS ID FRONTEND_VARIANT)
+ run_linker_genex(NonValidTarget-COMPILER_LINKER ${lang} ${type} CHECK_RESULT)
+ exec_linker_genex(COMPILER_LINKER ${lang} ${type})
+ endforeach()
+endforeach()
+
if(RunCMake_GENERATOR_IS_MULTI_CONFIG)
set(RunCMake_TEST_OPTIONS [==[-DCMAKE_CONFIGURATION_TYPES=CustomConfig]==])
else()
diff --git a/Tests/RunCMake/GeneratorExpression/compiler_linker.c b/Tests/RunCMake/GeneratorExpression/compiler_linker.c
new file mode 100644
index 0000000..db9a5f4
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/compiler_linker.c
@@ -0,0 +1,10 @@
+
+#include <string.h>
+
+#define xstr(s) str(s)
+#define str(s) #s
+
+int main(void)
+{
+ return strcmp(xstr(VAR), xstr(GENEX)) == 0 ? 0 : 1;
+}
diff --git a/Tests/RunCMake/InstallPackageInfo/Appendix-check.cmake b/Tests/RunCMake/InstallPackageInfo/Appendix-check.cmake
index 864e731..92925d8 100644
--- a/Tests/RunCMake/InstallPackageInfo/Appendix-check.cmake
+++ b/Tests/RunCMake/InstallPackageInfo/Appendix-check.cmake
@@ -5,11 +5,13 @@
file(READ "${out_dir}/foo.cps" content)
expect_value("${content}" "foo" "name")
expect_value("${content}" "interface" "components" "mammal" "type")
+expect_value("${content}" "LGPL-3.0-or-later" "default_license")
expect_value("${content}" "1.0" "version")
file(READ "${out_dir}/foo-dog.cps" content)
expect_value("${content}" "foo" "name")
expect_value("${content}" "interface" "components" "canine" "type")
+expect_value("${content}" "GPL-3.0-or-later" "default_license")
expect_missing("${content}" "version")
expect_array("${content}" 1 "components" "canine" "requires")
diff --git a/Tests/RunCMake/InstallPackageInfo/Appendix.cmake b/Tests/RunCMake/InstallPackageInfo/Appendix.cmake
index fe67778..5f4222c 100644
--- a/Tests/RunCMake/InstallPackageInfo/Appendix.cmake
+++ b/Tests/RunCMake/InstallPackageInfo/Appendix.cmake
@@ -5,5 +5,16 @@
install(TARGETS mammal EXPORT mammal DESTINATION .)
install(TARGETS canine EXPORT canine DESTINATION .)
-install(PACKAGE_INFO foo DESTINATION cps EXPORT mammal VERSION 1.0)
-install(PACKAGE_INFO foo DESTINATION cps EXPORT canine APPENDIX dog)
+install(
+ PACKAGE_INFO foo
+ DESTINATION cps
+ EXPORT mammal
+ VERSION 1.0
+ DEFAULT_LICENSE "LGPL-3.0-or-later")
+
+install(
+ PACKAGE_INFO foo
+ DESTINATION cps
+ EXPORT canine
+ APPENDIX dog
+ DEFAULT_LICENSE "GPL-3.0-or-later")
diff --git a/Tests/RunCMake/InstallPackageInfo/BadArgs2-stderr.txt b/Tests/RunCMake/InstallPackageInfo/BadArgs2-stderr.txt
index a50f759..1df7278 100644
--- a/Tests/RunCMake/InstallPackageInfo/BadArgs2-stderr.txt
+++ b/Tests/RunCMake/InstallPackageInfo/BadArgs2-stderr.txt
@@ -5,6 +5,12 @@
CMake Error at BadArgs2.cmake:[0-9]+ \(install\):
+ install APPENDIX and LICENSE are mutually exclusive.
+Call Stack \(most recent call first\):
+ CMakeLists\.txt:3 \(include\)
+
+
+CMake Error at BadArgs2.cmake:[0-9]+ \(install\):
install APPENDIX and DESCRIPTION are mutually exclusive.
Call Stack \(most recent call first\):
CMakeLists\.txt:3 \(include\)
diff --git a/Tests/RunCMake/InstallPackageInfo/BadArgs2.cmake b/Tests/RunCMake/InstallPackageInfo/BadArgs2.cmake
index b4d405f..4462907 100644
--- a/Tests/RunCMake/InstallPackageInfo/BadArgs2.cmake
+++ b/Tests/RunCMake/InstallPackageInfo/BadArgs2.cmake
@@ -1,8 +1,10 @@
add_library(foo INTERFACE)
install(TARGETS foo EXPORT foo DESTINATION .)
-install(PACKAGE_INFO test EXPORT foo APPENDIX test VERSION 1.0)
-install(PACKAGE_INFO test EXPORT foo APPENDIX test DESCRIPTION "Test")
-install(PACKAGE_INFO test EXPORT foo APPENDIX test HOMEPAGE_URL "example.com")
-install(PACKAGE_INFO test EXPORT foo APPENDIX test DEFAULT_TARGETS foo)
-install(PACKAGE_INFO test EXPORT foo APPENDIX test DEFAULT_CONFIGURATIONS test)
-install(PACKAGE_INFO test EXPORT foo APPENDIX test PROJECT foo)
+set(args PACKAGE_INFO test EXPORT foo APPENDIX test)
+install(${args} VERSION 1.0)
+install(${args} LICENSE "BSD-3-Clause AND CC-BY-SA-4.0")
+install(${args} DESCRIPTION "Test")
+install(${args} HOMEPAGE_URL "example.com")
+install(${args} DEFAULT_TARGETS foo)
+install(${args} DEFAULT_CONFIGURATIONS test)
+install(${args} PROJECT foo)
diff --git a/Tests/RunCMake/InstallPackageInfo/Metadata-check.cmake b/Tests/RunCMake/InstallPackageInfo/Metadata-check.cmake
index 7eca3b0..75516d5 100644
--- a/Tests/RunCMake/InstallPackageInfo/Metadata-check.cmake
+++ b/Tests/RunCMake/InstallPackageInfo/Metadata-check.cmake
@@ -15,5 +15,7 @@
expect_value("${content}" "release" "configurations" 0)
expect_value("${content}" "debug" "configurations" 1)
+expect_value("${content}" "BSD-3-Clause" "default_license")
+expect_value("${content}" "BSD-3-Clause AND CC-BY-SA-4.0" "license")
expect_value("${content}" "Sample package" "description")
expect_value("${content}" "https://www.example.com/package/foo" "website")
diff --git a/Tests/RunCMake/InstallPackageInfo/Metadata.cmake b/Tests/RunCMake/InstallPackageInfo/Metadata.cmake
index d551f3b..f14fe93 100644
--- a/Tests/RunCMake/InstallPackageInfo/Metadata.cmake
+++ b/Tests/RunCMake/InstallPackageInfo/Metadata.cmake
@@ -9,6 +9,8 @@
COMPAT_VERSION 1.2.0
DEFAULT_TARGETS foo
DEFAULT_CONFIGURATIONS release debug
+ LICENSE "BSD-3-Clause AND CC-BY-SA-4.0"
+ DEFAULT_LICENSE "BSD-3-Clause"
DESCRIPTION "Sample package"
HOMEPAGE_URL "https://www.example.com/package/foo"
)
diff --git a/Tests/RunCMake/InstallPackageInfo/ProjectMetadata-check.cmake b/Tests/RunCMake/InstallPackageInfo/ProjectMetadata-check.cmake
index 5c39b3f..b09b065 100644
--- a/Tests/RunCMake/InstallPackageInfo/ProjectMetadata-check.cmake
+++ b/Tests/RunCMake/InstallPackageInfo/ProjectMetadata-check.cmake
@@ -6,6 +6,7 @@
expect_value("${content}" "foo" "name")
expect_value("${content}" "1.2.3" "version")
expect_value("${content}" "1.1.0" "compat_version")
+expect_value("${content}" "BSD-3-Clause" "license")
expect_value("${content}" "Sample package" "description")
expect_value("${content}" "https://www.example.com/package/foo" "website")
@@ -13,6 +14,7 @@
expect_value("${content}" "test1" "name")
expect_value("${content}" "1.2.3" "version")
expect_value("${content}" "1.1.0" "compat_version")
+expect_value("${content}" "BSD-3-Clause" "license")
expect_value("${content}" "Sample package" "description")
expect_value("${content}" "https://www.example.com/package/foo" "website")
@@ -20,5 +22,6 @@
expect_value("${content}" "test2" "name")
expect_value("${content}" "1.4.7" "version")
expect_missing("${content}" "compat_version")
+expect_value("${content}" "Apache-2.0" "license")
expect_value("${content}" "Don't inherit" "description")
expect_value("${content}" "https://www.example.com/package/bar" "website")
diff --git a/Tests/RunCMake/InstallPackageInfo/ProjectMetadata.cmake b/Tests/RunCMake/InstallPackageInfo/ProjectMetadata.cmake
index e86372f..3111150 100644
--- a/Tests/RunCMake/InstallPackageInfo/ProjectMetadata.cmake
+++ b/Tests/RunCMake/InstallPackageInfo/ProjectMetadata.cmake
@@ -1,6 +1,7 @@
project(foo
VERSION 1.2.3
COMPAT_VERSION 1.1.0
+ SPDX_LICENSE "BSD-3-Clause"
DESCRIPTION "Sample package"
HOMEPAGE_URL "https://www.example.com/package/foo"
)
@@ -30,6 +31,7 @@
EXPORT foo
PROJECT foo
VERSION 1.4.7
+ LICENSE "Apache-2.0"
DESCRIPTION "Don't inherit"
HOMEPAGE_URL "https://www.example.com/package/bar"
)
diff --git a/Tests/RunCMake/find_package-CPS/License.cmake b/Tests/RunCMake/find_package-CPS/License.cmake
new file mode 100644
index 0000000..623dbc7
--- /dev/null
+++ b/Tests/RunCMake/find_package-CPS/License.cmake
@@ -0,0 +1,27 @@
+cmake_minimum_required(VERSION 4.0)
+
+include(Setup.cmake)
+
+set(CMAKE_FIND_PACKAGE_SORT_ORDER NAME)
+set(CMAKE_FIND_PACKAGE_SORT_DIRECTION DEC)
+
+find_package(LicenseTest REQUIRED)
+
+function(expect_license COMPONENT EXPECTED)
+ set(target LicenseTest::${COMPONENT})
+ if(TARGET ${target})
+ get_target_property(license ${target} "SPDX_LICENSE")
+ if (NOT "${license}" STREQUAL "${EXPECTED}")
+ message(SEND_ERROR
+ "Target ${target} has wrong license '${license}'"
+ " (expected '${EXPECTED}') !")
+ endif()
+ else()
+ message(SEND_ERROR "Expected target ${target} was not found !")
+ endif()
+endfunction()
+
+expect_license(SpecifiedOnTarget "Apache-2.0")
+expect_license(InheritFromRoot "BSD-3-Clause")
+expect_license(InheritFromAppendix "Apache-2.0")
+expect_license(DisableInheritance "license-NOTFOUND")
diff --git a/Tests/RunCMake/find_package-CPS/RunCMakeTest.cmake b/Tests/RunCMake/find_package-CPS/RunCMakeTest.cmake
index 1bcdc8a..cbc636a 100644
--- a/Tests/RunCMake/find_package-CPS/RunCMakeTest.cmake
+++ b/Tests/RunCMake/find_package-CPS/RunCMakeTest.cmake
@@ -18,7 +18,7 @@
run_cmake(CustomVersion)
# Metadata Tests
-run_cmake(SupplementalAttributes)
+run_cmake(License)
# Version-matching failure tests
run_cmake(MissingVersion1)
diff --git a/Tests/RunCMake/find_package-CPS/SupplementalAttributes.cmake b/Tests/RunCMake/find_package-CPS/SupplementalAttributes.cmake
deleted file mode 100644
index 3d6d567..0000000
--- a/Tests/RunCMake/find_package-CPS/SupplementalAttributes.cmake
+++ /dev/null
@@ -1,13 +0,0 @@
-cmake_minimum_required(VERSION 4.0)
-
-include(Setup.cmake)
-
-set(CMAKE_FIND_PACKAGE_SORT_ORDER NAME)
-set(CMAKE_FIND_PACKAGE_SORT_DIRECTION DEC)
-
-find_package(SupplementalAttributesTest REQUIRED COMPONENTS Sample)
-
-get_target_property(license SupplementalAttributesTest::Sample "SPDX_LICENSE")
-if (NOT "${license}" STREQUAL "BSD-3-Clause")
- message(SEND_ERROR "SupplementalAttributesTest wrong license ${license} !")
-endif()
diff --git a/Tests/RunCMake/find_package-CPS/cps/licensetest-notinherited.cps b/Tests/RunCMake/find_package-CPS/cps/licensetest-notinherited.cps
new file mode 100644
index 0000000..0ba7dd1
--- /dev/null
+++ b/Tests/RunCMake/find_package-CPS/cps/licensetest-notinherited.cps
@@ -0,0 +1,11 @@
+{
+ "cps_version": "0.13",
+ "name": "LicenseTest",
+ "default_license": "",
+ "cps_path": "@prefix@/cps",
+ "components": {
+ "DisableInheritance": {
+ "type": "interface"
+ }
+ }
+}
diff --git a/Tests/RunCMake/find_package-CPS/cps/licensetest-override.cps b/Tests/RunCMake/find_package-CPS/cps/licensetest-override.cps
new file mode 100644
index 0000000..01d8900
--- /dev/null
+++ b/Tests/RunCMake/find_package-CPS/cps/licensetest-override.cps
@@ -0,0 +1,11 @@
+{
+ "cps_version": "0.13",
+ "name": "LicenseTest",
+ "default_license": "Apache-2.0",
+ "cps_path": "@prefix@/cps",
+ "components": {
+ "InheritFromAppendix": {
+ "type": "interface"
+ }
+ }
+}
diff --git a/Tests/RunCMake/find_package-CPS/cps/licensetest.cps b/Tests/RunCMake/find_package-CPS/cps/licensetest.cps
new file mode 100644
index 0000000..f376933
--- /dev/null
+++ b/Tests/RunCMake/find_package-CPS/cps/licensetest.cps
@@ -0,0 +1,16 @@
+{
+ "cps_version": "0.13",
+ "name": "LicenseTest",
+ "version": "1.0",
+ "default_license": "BSD-3-Clause",
+ "cps_path": "@prefix@/cps",
+ "components": {
+ "SpecifiedOnTarget": {
+ "type": "interface",
+ "license": "Apache-2.0"
+ },
+ "InheritFromRoot": {
+ "type": "interface"
+ }
+ }
+}
diff --git a/Tests/RunCMake/find_package-CPS/cps/supplementalattributestest.cps b/Tests/RunCMake/find_package-CPS/cps/supplementalattributestest.cps
deleted file mode 100644
index c7f3ce4..0000000
--- a/Tests/RunCMake/find_package-CPS/cps/supplementalattributestest.cps
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "cps_version": "0.13",
- "name": "SupplementalAttributesTest",
- "version": "1.0",
- "cps_path": "@prefix@/cps",
- "components": {
- "Sample": {
- "type": "interface",
- "license": "BSD-3-Clause"
- }
- }
-}
diff --git a/Tests/RunCMake/find_package/ConfigureLog.cmake b/Tests/RunCMake/find_package/ConfigureLog.cmake
index 49e785c..3b304a9 100644
--- a/Tests/RunCMake/find_package/ConfigureLog.cmake
+++ b/Tests/RunCMake/find_package/ConfigureLog.cmake
@@ -6,6 +6,7 @@
set(CMAKE_FIND_DEBUG_MODE 1)
# Stable sorting for predictable behaviors.
set(CMAKE_FIND_PACKAGE_SORT_ORDER NAME)
+set(CMAKE_FIND_PACKAGE_SORT_DIRECTION ASCENDING)
# Unset search variables for more predictable output.
unset(CMAKE_FRAMEWORK_PATH)
diff --git a/Tests/RunCMake/project/Omissions.cmake b/Tests/RunCMake/project/Omissions.cmake
index 79f695f..88f8e82 100644
--- a/Tests/RunCMake/project/Omissions.cmake
+++ b/Tests/RunCMake/project/Omissions.cmake
@@ -20,5 +20,6 @@
expect_empty(VERSION_PATCH)
expect_empty(VERSION_TWEAK)
expect_empty(COMPAT_VERSION)
+expect_empty(SPDX_LICENSE)
expect_empty(DESCRIPTION)
expect_empty(HOMEPAGE_URL)
diff --git a/Tests/RunCMake/project/ProjectLicense-stdout.txt b/Tests/RunCMake/project/ProjectLicense-stdout.txt
new file mode 100644
index 0000000..ef08658
--- /dev/null
+++ b/Tests/RunCMake/project/ProjectLicense-stdout.txt
@@ -0,0 +1 @@
+PROJECT_SPDX_LICENSE=BSD-3-Clause
diff --git a/Tests/RunCMake/project/ProjectLicense.cmake b/Tests/RunCMake/project/ProjectLicense.cmake
new file mode 100644
index 0000000..847ee64
--- /dev/null
+++ b/Tests/RunCMake/project/ProjectLicense.cmake
@@ -0,0 +1,5 @@
+project(ProjectLicenseTest SPDX_LICENSE "BSD-3-Clause" LANGUAGES)
+if(NOT PROJECT_SPDX_LICENSE)
+ message(FATAL_ERROR "PROJECT_SPDX_LICENSE expected to be set")
+endif()
+message(STATUS "PROJECT_SPDX_LICENSE=${PROJECT_SPDX_LICENSE}")
diff --git a/Tests/RunCMake/project/ProjectLicense2-result.txt b/Tests/RunCMake/project/ProjectLicense2-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/project/ProjectLicense2-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/project/ProjectLicense2-stderr.txt b/Tests/RunCMake/project/ProjectLicense2-stderr.txt
new file mode 100644
index 0000000..b3be849
--- /dev/null
+++ b/Tests/RunCMake/project/ProjectLicense2-stderr.txt
@@ -0,0 +1 @@
+ SPDX_LICENSE may be specified at most once.
diff --git a/Tests/RunCMake/project/ProjectLicense2.cmake b/Tests/RunCMake/project/ProjectLicense2.cmake
new file mode 100644
index 0000000..c3ef751
--- /dev/null
+++ b/Tests/RunCMake/project/ProjectLicense2.cmake
@@ -0,0 +1 @@
+project(ProjectLicenseTest SPDX_LICENSE "BSD-3-Clause" SPDX_LICENSE "Apache-2.0" LANGUAGES)
diff --git a/Tests/RunCMake/project/ProjectLicenseNoArg-stderr.txt b/Tests/RunCMake/project/ProjectLicenseNoArg-stderr.txt
new file mode 100644
index 0000000..5cb13fa
--- /dev/null
+++ b/Tests/RunCMake/project/ProjectLicenseNoArg-stderr.txt
@@ -0,0 +1,2 @@
+ SPDX_LICENSE keyword not followed by a value or was followed by a value
+ that expanded to nothing.
diff --git a/Tests/RunCMake/project/ProjectLicenseNoArg.cmake b/Tests/RunCMake/project/ProjectLicenseNoArg.cmake
new file mode 100644
index 0000000..7404e4d
--- /dev/null
+++ b/Tests/RunCMake/project/ProjectLicenseNoArg.cmake
@@ -0,0 +1 @@
+project(ProjectLicenseTest LANGUAGES NONE SPDX_LICENSE)
diff --git a/Tests/RunCMake/project/ProjectLicenseNoArg2-stderr.txt b/Tests/RunCMake/project/ProjectLicenseNoArg2-stderr.txt
new file mode 100644
index 0000000..5cb13fa
--- /dev/null
+++ b/Tests/RunCMake/project/ProjectLicenseNoArg2-stderr.txt
@@ -0,0 +1,2 @@
+ SPDX_LICENSE keyword not followed by a value or was followed by a value
+ that expanded to nothing.
diff --git a/Tests/RunCMake/project/ProjectLicenseNoArg2.cmake b/Tests/RunCMake/project/ProjectLicenseNoArg2.cmake
new file mode 100644
index 0000000..4370d5b
--- /dev/null
+++ b/Tests/RunCMake/project/ProjectLicenseNoArg2.cmake
@@ -0,0 +1 @@
+project(ProjectLicenseTest SPDX_LICENSE LANGUAGES NONE)
diff --git a/Tests/RunCMake/project/RunCMakeTest.cmake b/Tests/RunCMake/project/RunCMakeTest.cmake
index 8ffc645..31579e9 100644
--- a/Tests/RunCMake/project/RunCMakeTest.cmake
+++ b/Tests/RunCMake/project/RunCMakeTest.cmake
@@ -66,6 +66,10 @@
run_cmake_with_options(ProjectCompatVersionMissingVersion ${opts})
run_cmake_with_options(ProjectCompatVersionNewer ${opts})
run_cmake_with_options(ProjectCompatVersionNoArg ${opts})
+run_cmake_with_options(ProjectLicense ${opts})
+run_cmake_with_options(ProjectLicense2 ${opts})
+run_cmake_with_options(ProjectLicenseNoArg ${opts})
+run_cmake_with_options(ProjectLicenseNoArg2 ${opts})
run_cmake(CMP0048-NEW)