Merge topic 'instrumentation-interrupt' b5c03bdef4 Source: Restore compilation on FreeBSD Acked-by: Kitware Robot <kwrobot@kitware.com> Merge-request: !12196
diff --git a/.pvsconfig b/.pvsconfig index 4d7413f..2cb7888 100644 --- a/.pvsconfig +++ b/.pvsconfig
@@ -6,17 +6,13 @@ //-V::508 # The 'x' variable is assigned values twice successively. Perhaps this is a mistake. //-V::519 -# Possible null pointer dereference. -//-V::522 # Constant value is represented by an octal form. //-V::536 # Iterators are passed as arguments to 'Foo' function. Consider inspecting the expression. //-V::539 # Expression is always true/false. //-V::547 -# Expression of the 'A - B > 0' kind will work as 'A != B'. -//-V::555 -# Possible array overrun. +# Array underrun/overrun is possible. //-V::557 # Part of conditional expression is always true/false. //-V::560 @@ -90,8 +86,6 @@ //-V::1071 # Conditional initialization inside the constructor may leave some members uninitialized. //-V::1077 -# Call of the 'Foo' function will lead to buffer underflow. -//-V::1086 # Waiting on condition variable without predicate. A thread can wait indefinitely or experience a spurious wake-up. //-V::1089 # The 'emplace' / 'insert' function call contains potentially dangerous move operation. Moved object can be destroyed even if there is no insertion.
diff --git a/Help/command/export.rst b/Help/command/export.rst index 775282f..5b98ecf 100644 --- a/Help/command/export.rst +++ b/Help/command/export.rst
@@ -178,7 +178,8 @@ [FORMAT <string>] [PROJECT <project-name>|NO_PROJECT_METADATA] [VERSION <major>[.<minor>[.<patch>[.<tweak>]]]] - [LICENSE <license-string>] + [DATA_LICENSE <license-string>] + [DEFAULT_LICENSE <license-string>] [DESCRIPTION <description-string>] [HOMEPAGE_URL <url-string>] [PACKAGE_URL <url-string>])
diff --git a/Help/command/file.rst b/Help/command/file.rst index 094262e..0b9fe56 100644 --- a/Help/command/file.rst +++ b/Help/command/file.rst
@@ -937,6 +937,7 @@ [MTIME <mtime>] [THREADS <number>] [WORKING_DIRECTORY <dir>] + [PATTERNS_EXCLUDE <pattern>...] [VERBOSE]) :target: ARCHIVE_CREATE :break: verbatim @@ -1077,6 +1078,17 @@ this directory. If this option is not provided, the current working directory will be used by default. + ``PATTERNS_EXCLUDE <pattern>...`` + .. versionadded:: 4.5 + + Do not add files or directories that match one of the given patterns. + Wildcards are supported. When a directory matches a pattern, it is + excluded together with everything beneath it. + + Exclusion patterns are not anchored to the start of an entry's path: a + pattern matches if it matches any portion of the path. This is consistent + with the ``--exclude`` option of command-line ``tar``. + ``VERBOSE`` Enable verbose output from the archive operation.
diff --git a/Help/command/function.rst b/Help/command/function.rst index 069f9fa..6722ca4 100644 --- a/Help/command/function.rst +++ b/Help/command/function.rst
@@ -59,20 +59,29 @@ When the function is invoked, the recorded ``<commands>`` are first modified by replacing formal parameters (``${arg1}``, ...) with the -arguments passed, and then invoked as normal commands. +arguments passed, and then invoked as normal commands. The following +variables are set in the scope of the function: -In addition to referencing the formal parameters you can reference the -``ARGC`` variable which will be set to the number of arguments passed -into the function as well as ``ARGV0``, ``ARGV1``, ``ARGV2``, ... which -will have the actual values of the arguments passed in. This facilitates -creating functions with optional arguments. +``ARGC`` + The number of arguments passed into the function. -Furthermore, ``ARGV`` holds the list of all arguments given to the -function and ``ARGN`` holds the list of arguments past the last expected -argument. Referencing to ``ARGV#`` arguments beyond ``ARGC`` have -undefined behavior. Checking that ``ARGC`` is greater than ``#`` is -the only way to ensure that ``ARGV#`` was passed to the function as an -extra argument. +``ARGV`` + The list of all arguments given to the function. + +``ARGV#`` + The variables ``ARGV0``, ``ARGV1``, ``ARGV2``, ... which will have the + actual values of the arguments passed in. References to ``ARGV#`` + arguments beyond ``ARGC`` have undefined behavior. Checking that + ``ARGC`` is greater than ``#`` is the only way to ensure that ``ARGV#`` + was passed to the function as an extra argument. + +``ARGN`` + The list of arguments past the last expected argument. + +``ARGNC`` + .. versionadded:: 4.5 + + The number of arguments past the last expected argument. See Also ^^^^^^^^
diff --git a/Help/command/install.rst b/Help/command/install.rst index 75016b0..cb8db41 100644 --- a/Help/command/install.rst +++ b/Help/command/install.rst
@@ -1217,7 +1217,8 @@ [PROJECT <project-name>|NO_PROJECT_METADATA] [DESTINATION <dir>] [VERSION <major>[.<minor>[.<patch>[.<tweak>]]]] - [LICENSE <license-string>] + [DATA_LICENSE <license-string>] + [DEFAULT_LICENSE <license-string>] [DESCRIPTION <description-string>] [HOMEPAGE_URL <url-string>] [PACKAGE_URL <url-string>] @@ -1260,16 +1261,21 @@ An informational canonical package URL for the project. - ``LICENSE <license-string>`` + ``DATA_LICENSE <license-string>`` 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. + SBOM data itself in the generated document. See the SPDX `License List`_ + for a list of commonly used licenses and their identifiers. In the SPDX + format, it corresponds to the `dataLicense`_ property. The license of individual components is taken from the - :prop_tgt:`SPDX_LICENSE` property of their respective targets. + :prop_tgt:`SPDX_LICENSE` property of their respective targets if set and + the ``DEFAULT_LICENSE`` otherwise. + + ``DEFAULT_LICENSE <license-string>`` + + A |SPDX|_ (SPDX) `License Expression`_ that describes the license(s) of any + components which do not otherwise specify their license(s). ``DESCRIPTION <description-string>`` @@ -1420,5 +1426,6 @@ .. _License Expression: https://spdx.github.io/spdx-spec/v3.0.1/annexes/spdx-license-expressions/ .. _License List: https://spdx.org/licenses/ +.. _dataLicense: https://spdx.github.io/spdx-spec/v3.0.1/model/Core/Properties/dataLicense/ .. |SBOM| replace:: Software Bill of Material
diff --git a/Help/dev/experimental.rst b/Help/dev/experimental.rst index 60955f1..6a3b7f7 100644 --- a/Help/dev/experimental.rst +++ b/Help/dev/experimental.rst
@@ -109,7 +109,7 @@ set * variable ``CMAKE_EXPERIMENTAL_GENERATE_SBOM`` to -* value ``2d856d6d-53e8-488b-a17f-d486d2cac317``. +* value ``248471c2-d905-4c9e-81b5-b89cd27965e1``. This UUID may change in future versions of CMake. Be sure to use the value documented here by the source tree of the version of CMake with which you are
diff --git a/Help/manual/cmake-instrumentation.7.rst b/Help/manual/cmake-instrumentation.7.rst index 33f81cb..3ff3090 100644 --- a/Help/manual/cmake-instrumentation.7.rst +++ b/Help/manual/cmake-instrumentation.7.rst
@@ -260,8 +260,9 @@ for the most recent minor version, even if an earlier minor version is requested. - Currently, the only supported version is ``1.0``. Query files with an unknown - data version will be ignored. + Currently, the only supported major version is ``1``. Query files + requesting a minor version up to the maximum described in `Data Version`_ + are accepted; those with an unknown data version will be ignored. ``callbacks`` A list of command-line strings for `Callbacks`_ to handle collected @@ -437,8 +438,8 @@ ``<role>-<hash>-<timestamp>.json`` and contain the following data: ``version`` - The `Data Version`_ of the snippet file. Currently the version is - always ``{ "major": 1, "minor": 0 }``. + The `Data Version`_ of the snippet file, written as + ``{ "major": 1, "minor": N }`` where ``N`` is the most recent minor version. ``command`` The full command executed. Excluded when ``role`` is ``build``. @@ -624,8 +625,8 @@ `Callbacks`_ are executed. ``version`` - The `Data Version`_ of the index file. Currently this is always written as: - ``{ "major": 1, "minor": 0 }``. + The `Data Version`_ of the index file, written as + ``{ "major": 1, "minor": N }`` where ``N`` is the most recent minor version. ``buildDir`` The build directory of the CMake project. @@ -727,8 +728,8 @@ Each CMake content file contains the following: ``version`` - The `Data Version`_ of the content file. Currently the version is - always ``{ "major": 1, "minor": 0 }``. + The `Data Version`_ of the content file, written as + ``{ "major": 1, "minor": N }`` where ``N`` is the most recent minor version. ``project`` The value of :variable:`CMAKE_PROJECT_NAME`.
diff --git a/Help/prop_tgt/Fortran_BUILDING_INTRINSIC_MODULES.rst b/Help/prop_tgt/Fortran_BUILDING_INTRINSIC_MODULES.rst index 8e0f71b..f7152ab 100644 --- a/Help/prop_tgt/Fortran_BUILDING_INTRINSIC_MODULES.rst +++ b/Help/prop_tgt/Fortran_BUILDING_INTRINSIC_MODULES.rst
@@ -14,3 +14,7 @@ Fortran intrinsic modules whereas turning the property off will ignore Fortran intrinsic modules in the dependency graph as they are supplied by the compiler itself. + +.. versionadded:: 4.5 + This property is now honored by the :ref:`Ninja Generators`. + Previously it was only honored by the :ref:`Makefile Generators`.
diff --git a/Help/release/dev/file-ARCHIVE_CREATE-patterns-exclude.rst b/Help/release/dev/file-ARCHIVE_CREATE-patterns-exclude.rst new file mode 100644 index 0000000..40cc6f0 --- /dev/null +++ b/Help/release/dev/file-ARCHIVE_CREATE-patterns-exclude.rst
@@ -0,0 +1,6 @@ +file-ARCHIVE_CREATE-patterns-exclude +------------------------------------ + +* The :command:`file(ARCHIVE_CREATE)` command gained a ``PATTERNS_EXCLUDE`` + option to omit files and directories matching the given patterns from the + created archive.
diff --git a/Help/release/dev/fortran-intrinsic-modules-ninja.rst b/Help/release/dev/fortran-intrinsic-modules-ninja.rst new file mode 100644 index 0000000..b4209fa --- /dev/null +++ b/Help/release/dev/fortran-intrinsic-modules-ninja.rst
@@ -0,0 +1,6 @@ +fortran-intrinsic-modules-ninja +------------------------------- + +* The :prop_tgt:`Fortran_BUILDING_INTRINSIC_MODULES` target property is now + honored by the :ref:`Ninja Generators`. Previously it was only honored + by the :ref:`Makefile Generators`.
diff --git a/Help/release/dev/function-argnc.rst b/Help/release/dev/function-argnc.rst new file mode 100644 index 0000000..94210e0 --- /dev/null +++ b/Help/release/dev/function-argnc.rst
@@ -0,0 +1,5 @@ +function-argnc +-------------- + +* The :command:`function` command now sets the ``ARGNC`` variable, which + holds the number of arguments past the last expected argument.
diff --git a/Modules/FindRuby.cmake b/Modules/FindRuby.cmake index 863f70a..6f865da 100644 --- a/Modules/FindRuby.cmake +++ b/Modules/FindRuby.cmake
@@ -407,7 +407,7 @@ _RUBY_CONFIG_VAR("sitelibdir" Ruby_SITELIB_DIR) # vendor_ruby - TODO - Not relevant and should be removed. - execute_process(COMMAND "${Ruby_EXECUTABLE}" -r vendor-specific -e "print 'true'" + execute_process(COMMAND ${Ruby_EXECUTABLE} -r rbconfig -e "print 'true' unless RbConfig::CONFIG['vendorarchdir'].nil?" OUTPUT_VARIABLE Ruby_HAS_VENDOR_RUBY ERROR_QUIET) if (Ruby_HAS_VENDOR_RUBY)
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index bf160c5..6973989 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake
@@ -1,7 +1,7 @@ # CMake version number components. set(CMake_VERSION_MAJOR 4) set(CMake_VERSION_MINOR 4) -set(CMake_VERSION_PATCH 20260617) +set(CMake_VERSION_PATCH 20260622) #set(CMake_VERSION_RC 0) set(CMake_VERSION_IS_DIRTY 0)
diff --git a/Source/CursesDialog/cmCursesMainForm.cxx b/Source/CursesDialog/cmCursesMainForm.cxx index 6b465c1..74089e5 100644 --- a/Source/CursesDialog/cmCursesMainForm.cxx +++ b/Source/CursesDialog/cmCursesMainForm.cxx
@@ -314,9 +314,12 @@ char secondLine[512] = ""; char thirdLine[512] = ""; if (process) { - memset(firstLine, ' ', 68); - memset(secondLine, ' ', 68); - memset(thirdLine, ' ', 68); + std::fill_n(firstLine, 68, ' '); + firstLine[68] = '\0'; + std::fill_n(secondLine, 68, ' '); + secondLine[68] = '\0'; + std::fill_n(thirdLine, 68, ' '); + thirdLine[68] = '\0'; } else { if (this->OkToGenerate) { snprintf(firstLine, sizeof(firstLine), @@ -340,7 +343,8 @@ move(y - 4, 0); char fmt[512] = "Keys: [enter] Edit an entry [d] Delete an entry"; if (process) { - memset(fmt, ' ', 57); + std::fill_n(fmt, 57, ' '); + fmt[57] = '\0'; } printw(fmt_s, fmt); move(y - 3, 0);
diff --git a/Source/bindexplib.cxx b/Source/bindexplib.cxx index 59680aa..b43ac0f 100644 --- a/Source/bindexplib.cxx +++ b/Source/bindexplib.cxx
@@ -391,7 +391,7 @@ line.c_str()); return false; } - if (line.size() < sym_end + 1) { + if (line.size() < sym_end) { fprintf(stderr, "Couldn't parse llvm-nm output line: %s\n", line.c_str()); return false;
diff --git a/Source/cmArchiveWrite.cxx b/Source/cmArchiveWrite.cxx index 374e476..af92ca3 100644 --- a/Source/cmArchiveWrite.cxx +++ b/Source/cmArchiveWrite.cxx
@@ -406,8 +406,44 @@ return true; } +bool cmArchiveWrite::SetExcludePatterns( + std::vector<std::string> const& patterns) +{ + if (patterns.empty()) { + return true; + } + if (!this->MatchObject) { + this->MatchObject = archive_match_new(); + if (!this->MatchObject) { + this->Error = "archive_match_new: out of memory"; + return false; + } + } + // NOLINTNEXTLINE(readability-use-anyofallof) + for (std::string const& pattern : patterns) { + // Reject empty patterns ourselves. libarchive would reject them too, but + // only after allocating an error message on the match object that + // archive_match_free() does not release. + if (pattern.empty()) { + this->Error = "exclusion pattern must not be empty"; + return false; + } + if (archive_match_exclude_pattern(this->MatchObject, pattern.c_str()) != + ARCHIVE_OK) { + this->Error = + cmStrCat("Failed to add to exclusion list: ", pattern, " (", + cm_archive_error_string(this->MatchObject), ')'); + return false; + } + } + return true; +} + cmArchiveWrite::~cmArchiveWrite() { + if (this->MatchObject) { + archive_match_free(this->MatchObject); + } archive_read_free(this->Disk); archive_write_free(this->Archive); } @@ -425,6 +461,23 @@ bool cmArchiveWrite::AddPath(std::string const& path, size_t skip, char const* prefix, bool recursive) { + // Skip paths whose archive entry name matches an exclusion pattern. For a + // directory this also prevents descending into it, pruning the subtree. + if (this->MatchObject && skip < path.length()) { + cm::string_view out = cm::string_view(path).substr(skip); + std::string dest = cmStrCat(prefix ? prefix : "", out); + Entry e; + cm_archive_entry_copy_pathname(e, dest.c_str()); + int matched = archive_match_path_excluded(this->MatchObject, e); + if (matched < 0) { + this->Error = cmStrCat("archive_match_path_excluded: ", + cm_archive_error_string(this->MatchObject)); + return false; + } + if (matched > 0) { + return true; + } + } if (path != "." || (this->Format != "zip" && this->Format != "7zip")) { if (!this->AddFile(path, skip, prefix)) { return false;
diff --git a/Source/cmArchiveWrite.h b/Source/cmArchiveWrite.h index dfefc72..00c8ebc 100644 --- a/Source/cmArchiveWrite.h +++ b/Source/cmArchiveWrite.h
@@ -7,6 +7,7 @@ #include <cstddef> #include <iosfwd> #include <string> +#include <vector> #if defined(CMAKE_BOOTSTRAP) # error "cmArchiveWrite not allowed during bootstrap build!" @@ -143,6 +144,11 @@ this->Gname = ""; } + //! Sets exclusion patterns. Any path whose archive entry name matches one + //! of the patterns is skipped, and excluded directories are not descended + //! into. Returns false and sets the error if a pattern cannot be added. + bool SetExcludePatterns(std::vector<std::string> const& patterns); + private: bool Okay() const { return this->Error.empty(); } bool AddPath(std::string const& path, size_t skip, char const* prefix, @@ -158,6 +164,7 @@ std::ostream& Stream; struct archive* Archive; struct archive* Disk; + struct archive* MatchObject = nullptr; bool Verbose = false; std::string Format; std::string Error;
diff --git a/Source/cmCTest.cxx b/Source/cmCTest.cxx index e3508b5..7b15c97 100644 --- a/Source/cmCTest.cxx +++ b/Source/cmCTest.cxx
@@ -1341,8 +1341,9 @@ std::vector<std::string> files; files.push_back(file); - if (!cmSystemTools::CreateTar( - tarFile, files, {}, cmSystemTools::TarCompressGZip, "UTF-8", false)) { + if (!cmSystemTools::CreateTar(tarFile, files, {}, {}, + cmSystemTools::TarCompressGZip, "UTF-8", + false)) { cmCTestLog(this, ERROR_MESSAGE, "Error creating tar while " "encoding file: "
diff --git a/Source/cmExperimental.cxx b/Source/cmExperimental.cxx index 2d9232c..3d50bf1 100644 --- a/Source/cmExperimental.cxx +++ b/Source/cmExperimental.cxx
@@ -55,7 +55,7 @@ {}, cmExperimental::TryCompileCondition::Never }, { "GenerateSbom", - "2d856d6d-53e8-488b-a17f-d486d2cac317", + "248471c2-d905-4c9e-81b5-b89cd27965e1", "CMAKE_EXPERIMENTAL_GENERATE_SBOM", "CMake's support for generating software bill of materials (Sbom) " "information in SPDX format is experimental. It is meant only for "
diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx index 222acd7..fb82c3c 100644 --- a/Source/cmFileCommand.cxx +++ b/Source/cmFileCommand.cxx
@@ -3720,6 +3720,7 @@ bool Verbose = false; // "PATHS" requires at least one value, but use a custom check below. ArgumentParser::MaybeEmpty<std::vector<std::string>> Paths; + ArgumentParser::MaybeEmpty<std::vector<std::string>> PatternsExclude; }; static auto const parser = @@ -3733,7 +3734,8 @@ .Bind("THREADS"_s, &Arguments::Threads) .Bind("WORKING_DIRECTORY"_s, &Arguments::WorkingDirectory) .Bind("VERBOSE"_s, &Arguments::Verbose) - .Bind("PATHS"_s, &Arguments::Paths); + .Bind("PATHS"_s, &Arguments::Paths) + .Bind("PATTERNS_EXCLUDE"_s, &Arguments::PatternsExclude); std::vector<std::string> unrecognizedArguments; auto parsedArgs = @@ -3866,9 +3868,10 @@ } if (!cmSystemTools::CreateTar( - parsedArgs.Output, parsedArgs.Paths, parsedArgs.WorkingDirectory, - compress, parsedArgs.Encoding, parsedArgs.Verbose, parsedArgs.MTime, - parsedArgs.Format, compressionLevel, threads)) { + parsedArgs.Output, parsedArgs.Paths, parsedArgs.PatternsExclude, + parsedArgs.WorkingDirectory, compress, parsedArgs.Encoding, + parsedArgs.Verbose, parsedArgs.MTime, parsedArgs.Format, + compressionLevel, threads)) { status.SetError(cmStrCat("failed to compress: ", parsedArgs.Output)); cmSystemTools::SetFatalErrorOccurred(); return false;
diff --git a/Source/cmFunctionCommand.cxx b/Source/cmFunctionCommand.cxx index 3e62649..0d02993 100644 --- a/Source/cmFunctionCommand.cxx +++ b/Source/cmFunctionCommand.cxx
@@ -25,7 +25,7 @@ namespace { std::string const ARGC = "ARGC"; -std::string const kFUNCTION_ARGNC = "_FUNCTION_ARGNC"; +std::string const ARGNC = "ARGNC"; std::string const ARGN = "ARGN"; std::string const ARGV = "ARGV"; std::string const CMAKE_CURRENT_FUNCTION = "CMAKE_CURRENT_FUNCTION"; @@ -94,7 +94,7 @@ makefile.AddDefinition(this->Args[j], expandedArgs[j - 1]); } - // define ARGV, ARGN, and _FUNCTION_ARGNC + // define ARGV, ARGN, and ARGNC auto const argvDef = cmList::to_string(expandedArgs); auto const expIt = expandedArgs.begin() + (this->Args.size() - 1); auto const argnDef = @@ -105,8 +105,8 @@ makefile.MarkVariableAsUsed(ARGV); makefile.AddDefinition(ARGN, argnDef); makefile.MarkVariableAsUsed(ARGN); - makefile.AddDefinition(kFUNCTION_ARGNC, functionArgncDef); - makefile.MarkVariableAsUsed(kFUNCTION_ARGNC); + makefile.AddDefinition(ARGNC, functionArgncDef); + makefile.MarkVariableAsUsed(ARGNC); makefile.AddDefinition(CMAKE_CURRENT_FUNCTION, this->Args.front()); makefile.MarkVariableAsUsed(CMAKE_CURRENT_FUNCTION);
diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx index 8d29ec4..bed1634 100644 --- a/Source/cmGlobalNinjaGenerator.cxx +++ b/Source/cmGlobalNinjaGenerator.cxx
@@ -7,6 +7,7 @@ #include <cstdio> #include <functional> #include <iterator> +#include <set> #include <sstream> #include <utility> @@ -2565,6 +2566,7 @@ std::vector<std::string> includes; std::string dir_top_bld; std::string module_dir; + bool building_intrinsics = false; if (!arg_src_orig.empty()) { // Prepend the original source file's directory as an include directory @@ -2615,6 +2617,10 @@ Json::Value const& tdi_submodule_ext = tdi["submodule-ext"]; fc.SModExt = tdi_submodule_ext.asString(); + + Json::Value const& tdi_building_intrinsics = + tdi["building-intrinsic-modules"]; + building_intrinsics = tdi_building_intrinsics.asBool(); } cmFortranSourceInfo finfo; @@ -2643,7 +2649,11 @@ } info->ScanDep.Provides.emplace_back(src_info); } - for (std::string const& require : finfo.Requires) { + std::set<std::string> requiredModules = finfo.Requires; + if (building_intrinsics) { + requiredModules.insert(finfo.Intrinsics.begin(), finfo.Intrinsics.end()); + } + for (std::string const& require : requiredModules) { // Require modules not provided in the same source. if (finfo.Provides.count(require)) { continue;
diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index 0215e34..4da4569 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx
@@ -3583,7 +3583,10 @@ target->AddAttribute("name", this->CreateString(gtgt->GetName())); target->AddAttribute("productName", this->CreateString(gtgt->GetName())); - cmXCodeObject* fileRef = this->CreateObject(cmXCodeObject::PBXFileReference); + cmXCodeObject* fileRef = + this->CreateObject(cmXCodeObject::PBXFileReference, + cmStrCat("PBXFileReference:product:", gtgt->GetName(), + ':', targetBinaryPath)); if (char const* fileType = this->GetTargetFileType(gtgt)) { fileRef->AddAttribute("explicitFileType", this->CreateString(fileType)); }
diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index f2505de..ec5c369 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx
@@ -2376,6 +2376,8 @@ this->Makefile->GetSafeDefinition("CMAKE_Fortran_SUBMODULE_SEP"); tdi["submodule-ext"] = this->Makefile->GetSafeDefinition("CMAKE_Fortran_SUBMODULE_EXT"); + tdi["building-intrinsic-modules"] = + this->GeneratorTarget->IsFortranBuildingIntrinsicModules(); } else if (lang == "CXX") { // No extra information necessary. }
diff --git a/Source/cmParseArgumentsCommand.cxx b/Source/cmParseArgumentsCommand.cxx index 88b6295..19f23ee 100644 --- a/Source/cmParseArgumentsCommand.cxx +++ b/Source/cmParseArgumentsCommand.cxx
@@ -182,12 +182,11 @@ } parseFromArg = true; argIter++; // move past PARSE_ARGN - std::string argncStr = - status.GetMakefile().GetSafeDefinition("_FUNCTION_ARGNC"); + std::string argncStr = status.GetMakefile().GetSafeDefinition("ARGNC"); if (!cmStrToULong(argncStr, &argnc)) { status.GetMakefile().IssueMessage( MessageType::FATAL_ERROR, - cmStrCat("PARSE_ARGN called with _FUNCTION_ARGNC='", argncStr, + cmStrCat("PARSE_ARGN called with ARGNC='", argncStr, "' that is not an unsigned integer")); cmSystemTools::SetFatalErrorOccurred(); return true;
diff --git a/Source/cmSbomArguments.cxx b/Source/cmSbomArguments.cxx index 155aefd..b5c48fa 100644 --- a/Source/cmSbomArguments.cxx +++ b/Source/cmSbomArguments.cxx
@@ -65,6 +65,14 @@ return false; } } + + if (!this->License.empty()) { + // Do not allow the license argument to be provided as SBOM only accepts a + // DEFAULT_LICENSE + status.SetError("SBOM given unknown argument: \"LICENSE\"."); + return false; + } + return true; }
diff --git a/Source/cmSbomArguments.h b/Source/cmSbomArguments.h index ab62226..a45d52e 100644 --- a/Source/cmSbomArguments.h +++ b/Source/cmSbomArguments.h
@@ -41,6 +41,8 @@ ArgumentParser::NonEmpty<std::string> Format; ArgumentParser::NonEmpty<std::string> PackageUrl; + ArgumentParser::NonEmpty<std::string> DefaultLicense; + ArgumentParser::NonEmpty<std::string> DataLicense; protected: cm::string_view CommandName() const override; @@ -55,6 +57,8 @@ Bind(base, parser, "SBOM"_s, &cmProjectInfoArguments::PackageName); Bind(self, parser, "FORMAT"_s, &cmSbomArguments::Format); Bind(self, parser, "PACKAGE_URL"_s, &cmSbomArguments::PackageUrl); + Bind(self, parser, "DEFAULT_LICENSE"_s, &cmSbomArguments::DefaultLicense); + Bind(self, parser, "DATA_LICENSE"_s, &cmSbomArguments::DataLicense); cmProjectInfoArguments::Bind(parser, self); } };
diff --git a/Source/cmSbomBuilder.cxx b/Source/cmSbomBuilder.cxx index 16397a2..aed9b15 100644 --- a/Source/cmSbomBuilder.cxx +++ b/Source/cmSbomBuilder.cxx
@@ -70,7 +70,8 @@ , PackageDescription(std::move(args.Description)) , PackageWebsite(std::move(args.Website)) , PackageUrl(std::move(args.PackageUrl)) - , PackageLicense(std::move(args.License)) + , DataLicense(std::move(args.DataLicense)) + , DefaultLicense(std::move(args.DefaultLicense)) , PackageFormat(args.GetFormat()) { } @@ -222,8 +223,12 @@ proj.Description = this->PackageDescription; } - if (!this->PackageLicense.empty()) { - proj.DataLicense = this->PackageLicense; + if (!this->DataLicense.empty()) { + cmSpdxLicenseExpression license; + license.SpdxId = cmStrCat("urn:", PackageName, "#LicenseExpression"); + license.CreationInfo = ci; + license.LicenseExpression = this->DataLicense; + proj.DataLicense = license; } return proj; @@ -319,7 +324,31 @@ this->AddPackageInformation(pkg, pkgIt->first, pkgIt->second); } } - return { true, insert_back(project->Elements, std::move(pkg)) }; + + cmSpdxPackage const* pkgPtr = + insert_back(project->Elements, std::move(pkg)); + if (!linkInfo.License.empty() && + !cm::contains(this->GeneratedLinkLicenses, name)) { + this->GeneratedLinkLicenses.emplace(name); + + cmSpdxLicenseExpression license; + license.SpdxId = cmStrCat("urn:", name, "#LicenseExpression"); + license.CreationInfo = ci; + license.LicenseExpression = linkInfo.License; + + cmSpdxRelationship relHasLicense; + relHasLicense.SpdxId = + cmStrCat("urn:", name, "#DeclaredLicenseRelationship"); + relHasLicense.CreationInfo = ci; + relHasLicense.RelationshipType = + cmSpdxRelationship::HAS_DECLARED_LICENSE; + relHasLicense.From = pkgPtr; + relHasLicense.To.emplace_back(std::move(license)); + + insert_back(doc.Graph, std::move(relHasLicense)); + } + + return { true, pkgPtr }; } cmSpdxPackage pkg; @@ -368,10 +397,40 @@ current, allTargets, config); status &= this->GenerateLinkProperties( doc, proj, ci, "INTERFACE_LINK_LIBRARIES", current, allTargets, config); - + status &= this->GenerateMetaProperties(doc, proj, ci, current); return status; } +bool cmSbomBuilder::GenerateMetaProperties( + cmSbomDocument& doc, cmSpdxDocument* /*project*/, + cmSpdxCreationInfo const* ci, TargetProperties const& current) const +{ + std::string licenseExpr = this->DefaultLicense; + cmValue licenseExprProp = current.Target->GetProperty("SPDX_LICENSE"); + if (licenseExprProp) { + licenseExpr = licenseExprProp; + } + if (!licenseExpr.empty()) { + auto const& tgtName = current.Target->GetName(); + + cmSpdxLicenseExpression license; + license.SpdxId = cmStrCat("urn:", tgtName, "#LicenseExpression"); + license.CreationInfo = ci; + license.LicenseExpression = std::move(licenseExpr); + + cmSpdxRelationship relHasLicense; + relHasLicense.SpdxId = + cmStrCat("urn:", tgtName, "#DeclaredLicenseRelationship"); + relHasLicense.CreationInfo = ci; + relHasLicense.RelationshipType = cmSpdxRelationship::HAS_DECLARED_LICENSE; + relHasLicense.From = current.Package; + relHasLicense.To.emplace_back(std::move(license)); + + insert_back(doc.Graph, std::move(relHasLicense)); + } + return true; +} + bool cmSbomBuilder::PopulateLinkLibrariesProperty( cmGeneratorTarget const* target, cmGeneratorExpression::PreprocessContext preprocessRule, @@ -428,9 +487,12 @@ std::string const& linkedName, cmGeneratorTarget const* linkedTarget) { + auto linkedLicense = linkedTarget->GetSafeProperty("SPDX_LICENSE"); + if (cm::contains(this->SbomTargets, linkedTarget)) { - this->LinkTargets.emplace(linkedName, - LinkInfo{ "", linkedTarget->GetExportName() }); + this->LinkTargets.emplace( + linkedName, + LinkInfo{ "", linkedTarget->GetExportName(), linkedLicense }); return true; } @@ -468,7 +530,8 @@ } else { component = linkedName.substr(prefix.length()); } - this->LinkTargets.emplace(linkedName, LinkInfo{ pkgName, component }); + this->LinkTargets.emplace(linkedName, + LinkInfo{ pkgName, component, linkedLicense }); cmPackageInformation& req = this->Requirements.insert(std::move(*pkgInfo)).first->second; req.Components.emplace(std::move(component)); @@ -494,9 +557,11 @@ std::string pkgName{ linkNamespace.data(), linkNamespace.size() - 2 }; std::string component = linkedTarget->GetExportName(); if (pkgName == this->GetPackageName()) { - this->LinkTargets.emplace(linkedName, LinkInfo{ "", component }); + this->LinkTargets.emplace(linkedName, + LinkInfo{ "", component, linkedLicense }); } else { - this->LinkTargets.emplace(linkedName, LinkInfo{ pkgName, component }); + this->LinkTargets.emplace(linkedName, + LinkInfo{ pkgName, component, linkedLicense }); this->Requirements[pkgName].Components.emplace(std::move(component)); } return true; @@ -535,7 +600,8 @@ "\" (first alphabetically).")); } std::string component = linkedTarget->GetExportName(); - this->LinkTargets.emplace(linkedName, LinkInfo{ pkgName, component }); + this->LinkTargets.emplace(linkedName, + LinkInfo{ pkgName, component, linkedLicense }); this->Requirements[pkgName].Components.emplace(std::move(component)); return true; }
diff --git a/Source/cmSbomBuilder.h b/Source/cmSbomBuilder.h index 961e9db..f092e3f 100644 --- a/Source/cmSbomBuilder.h +++ b/Source/cmSbomBuilder.h
@@ -129,6 +129,9 @@ TargetProperties const& current, std::vector<TargetProperties> const& allTargets, std::string const& config) const; + bool GenerateMetaProperties(cmSbomDocument& doc, cmSpdxDocument* project, + cmSpdxCreationInfo const* ci, + TargetProperties const& current) const; bool NoteLinkedTarget(cmGeneratorTarget const* target, std::string const& linkedName, @@ -163,6 +166,7 @@ { std::string Package; std::string Component; + std::string License; }; // Metadata @@ -172,7 +176,8 @@ std::string const PackageDescription; std::string const PackageWebsite; std::string const PackageUrl; - std::string const PackageLicense; + std::string const DataLicense; + std::string const DefaultLicense; cmSbomArguments::SbomFormat const PackageFormat; // Derived from inputs at generate time @@ -182,4 +187,7 @@ std::map<std::string, LinkInfo> LinkTargets; std::map<std::string, cmPackageInformation> Requirements; std::vector<std::string> Configurations; + + // Targets for which license data has been generated + mutable std::set<std::string> GeneratedLinkLicenses; };
diff --git a/Source/cmSpdx.cxx b/Source/cmSpdx.cxx index 870eec4..492c9a3 100644 --- a/Source/cmSpdx.cxx +++ b/Source/cmSpdx.cxx
@@ -128,6 +128,8 @@ return "contains"; case cmSpdxRelationship::RelationshipTypeId::DEPENDS_ON: return "dependsOn"; + case cmSpdxRelationship::RelationshipTypeId::HAS_DECLARED_LICENSE: + return "hasDeclaredLicense"; case cmSpdxRelationship::RelationshipTypeId::OTHER: return "other"; } @@ -497,6 +499,20 @@ } } +void cmSpdxAnyLicenseInfo::Serialize(cmSbomSerializer& serializer) const +{ + cmSpdxElement::Serialize(serializer); + serializer.AddString("type", "simplelicensing_AnyLicenseInfo"); +} + +void cmSpdxLicenseExpression::Serialize(cmSbomSerializer& serializer) const +{ + cmSpdxAnyLicenseInfo::Serialize(serializer); + serializer.AddString("type", "simplelicensing_LicenseExpression"); + SerializeIfPresent(serializer, "simplelicensing_licenseExpression", + LicenseExpression); +} + void cmSpdxDocument::Serialize(cmSbomSerializer& serializer) const { cmSpdxElementCollection::Serialize(serializer); @@ -508,7 +524,9 @@ if (NamespaceMap) { serializer.AddVisitable("namespaceMap", *NamespaceMap); } - SerializeIfPresent(serializer, "dataLicense", DataLicense); + if (DataLicense) { + serializer.AddVisitable("dataLicense", *DataLicense); + } } void cmSbomDocument::Serialize(cmSbomSerializer& serializer) const
diff --git a/Source/cmSpdx.h b/Source/cmSpdx.h index adaa26a..f792e7a 100644 --- a/Source/cmSpdx.h +++ b/Source/cmSpdx.h
@@ -159,6 +159,7 @@ DESCRIBES, CONTAINS, DEPENDS_ON, + HAS_DECLARED_LICENSE, OTHER }; @@ -343,11 +344,23 @@ void Serialize(cmSbomSerializer&) const override; }; +struct cmSpdxAnyLicenseInfo : cmSpdxElement +{ + void Serialize(cmSbomSerializer&) const override; +}; + +struct cmSpdxLicenseExpression final : cmSpdxAnyLicenseInfo +{ + cm::optional<std::string> LicenseExpression; + + void Serialize(cmSbomSerializer&) const override; +}; + struct cmSpdxDocument final : cmSpdxElementCollection { cm::optional<cmSbomObject> ExternalMap; cm::optional<cmSbomObject> NamespaceMap; - std::string DataLicense; + cm::optional<cmSbomObject> DataLicense; void Serialize(cmSbomSerializer& serializer) const override; };
diff --git a/Source/cmStringReplaceHelper.cxx b/Source/cmStringReplaceHelper.cxx index 0e18457..aa00907 100644 --- a/Source/cmStringReplaceHelper.cxx +++ b/Source/cmStringReplaceHelper.cxx
@@ -93,7 +93,7 @@ this->Replacements.emplace_back( this->ReplaceExpression.substr(l, r - l)); } else { - if (r - l > 0) { + if (r > l) { this->Replacements.emplace_back( this->ReplaceExpression.substr(l, r - l)); }
diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index 7976757..ea87266 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx
@@ -2238,6 +2238,7 @@ bool cmSystemTools::CreateTar( std::string const& arFileName, std::vector<std::string> const& files, + std::vector<std::string> const& excludeFiles, std::string const& workingDirectory, cmTarCompression compressType, std::string const& encoding, bool verbose, std::string const& mtime, std::string const& format, int compressionLevel, int numThreads) @@ -2300,6 +2301,10 @@ } a.SetMTime(mtime); a.SetVerbose(verbose); + if (!a.SetExcludePatterns(excludeFiles)) { + cmSystemTools::Error(a.GetError()); + return false; + } bool tarCreatedSuccessfully = true; for (auto path : files) { if (cmSystemTools::FileIsFullPath(path)) { @@ -2315,6 +2320,7 @@ #else (void)arFileName; (void)files; + (void)excludeFiles; (void)encoding; (void)verbose; return false; @@ -3889,7 +3895,8 @@ // There is no RPATH or RUNPATH anyway. return true; } - if (se_count == 2 && se[1]->IndexInSection < se[0]->IndexInSection) { + if (se_count == 2 && se[0] && se[1] && + se[1]->IndexInSection < se[0]->IndexInSection) { std::swap(se[0], se[1]); }
diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h index e72e5ea..c09ce30 100644 --- a/Source/cmSystemTools.h +++ b/Source/cmSystemTools.h
@@ -527,6 +527,7 @@ std::string const& encoding, bool verbose); static bool CreateTar(std::string const& arFileName, std::vector<std::string> const& files, + std::vector<std::string> const& excludeFiles, std::string const& workingDirectory, cmTarCompression compressType, std::string const& encoding, bool verbose,
diff --git a/Source/cmTargetPropCommandBase.cxx b/Source/cmTargetPropCommandBase.cxx index 960e36c..aa3975f 100644 --- a/Source/cmTargetPropCommandBase.cxx +++ b/Source/cmTargetPropCommandBase.cxx
@@ -81,14 +81,16 @@ } bool prepend = false; - if ((flags & PROCESS_BEFORE) && args[argIndex] == "BEFORE") { + if ((flags & PROCESS_BEFORE) && argIndex < args.size() && + args[argIndex] == "BEFORE") { if (args.size() < 3) { this->SetError("called with incorrect number of arguments"); return false; } prepend = true; ++argIndex; - } else if ((flags & PROCESS_AFTER) && args[argIndex] == "AFTER") { + } else if ((flags & PROCESS_AFTER) && argIndex < args.size() && + args[argIndex] == "AFTER") { if (args.size() < 3) { this->SetError("called with incorrect number of arguments"); return false; @@ -97,7 +99,8 @@ ++argIndex; } - if ((flags & PROCESS_REUSE_FROM) && args[argIndex] == "REUSE_FROM") { + if ((flags & PROCESS_REUSE_FROM) && argIndex < args.size() && + args[argIndex] == "REUSE_FROM") { if (args.size() != 3) { this->SetError("called with incorrect number of arguments"); return false;
diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx index e942370..01be8a1 100644 --- a/Source/cmcmd.cxx +++ b/Source/cmcmd.cxx
@@ -2129,9 +2129,9 @@ if (files.empty()) { std::cerr << "tar: No files or directories specified\n"; } - if (!cmSystemTools::CreateTar(outFile, files, {}, compress, encoding, - verbose, mtime, format, compressionLevel, - numThreads)) { + if (!cmSystemTools::CreateTar(outFile, files, {}, {}, compress, + encoding, verbose, mtime, format, + compressionLevel, numThreads)) { cmSystemTools::Error(cmStrCat("Problem creating tar:\n ", outFile)); return 1; }
diff --git a/Tests/CMakeLib/testSpdxSerializer.cxx b/Tests/CMakeLib/testSpdxSerializer.cxx index 7a5f6be..95e6caa 100644 --- a/Tests/CMakeLib/testSpdxSerializer.cxx +++ b/Tests/CMakeLib/testSpdxSerializer.cxx
@@ -28,7 +28,6 @@ cmSpdxDocument spdxValue; spdxValue.SpdxId = "_:SPDXRef-Document"; - spdxValue.DataLicense = "CC0-1.0"; auto spdx = insert_back(doc.Graph, std::move(spdxValue)); {
diff --git a/Tests/CMakeLib/testUVStreambuf.cxx b/Tests/CMakeLib/testUVStreambuf.cxx index a901ab2..54a65c8 100644 --- a/Tests/CMakeLib/testUVStreambuf.cxx +++ b/Tests/CMakeLib/testUVStreambuf.cxx
@@ -246,7 +246,8 @@ << std::endl; goto end; } - if (std::memcmp(inputData.data(), outputData, 64)) { + if (std::memcmp(inputData.data(), outputData, //-V1086 Ignore underflow + 64)) { std::cout << "Read data does not match write data" << std::endl; goto end; }
diff --git a/Tests/RunCMake/EnvSbom/RunCMakeTest.cmake b/Tests/RunCMake/EnvSbom/RunCMakeTest.cmake index 78debd2..39bd58c 100644 --- a/Tests/RunCMake/EnvSbom/RunCMakeTest.cmake +++ b/Tests/RunCMake/EnvSbom/RunCMakeTest.cmake
@@ -2,7 +2,7 @@ set(common_test_options -Wno-author - "-DCMAKE_EXPERIMENTAL_GENERATE_SBOM:STRING=2d856d6d-53e8-488b-a17f-d486d2cac317" + "-DCMAKE_EXPERIMENTAL_GENERATE_SBOM:STRING=248471c2-d905-4c9e-81b5-b89cd27965e1" "-DCMAKE_INSTALL_SBOM_FORMATS:STRING=JSON" "-DCMAKE_INSTALL_LIBDIR=lib" )
diff --git a/Tests/RunCMake/ExportSbom/ProjectMetadata.cmake b/Tests/RunCMake/ExportSbom/ProjectMetadata.cmake index 02b5ce3..43678f2 100644 --- a/Tests/RunCMake/ExportSbom/ProjectMetadata.cmake +++ b/Tests/RunCMake/ExportSbom/ProjectMetadata.cmake
@@ -4,7 +4,7 @@ SBOM test_targets EXPORTS test_targets DESCRIPTION "An eloquent description" - LICENSE "BSD-3" + DATA_LICENSE "BSD-3" HOMEPAGE_URL "www.example.com" PACKAGE_URL "https://example.com/test_targets.tar.gz" VERSION "1.3.4"
diff --git a/Tests/RunCMake/ExportSbom/RunCMakeTest.cmake b/Tests/RunCMake/ExportSbom/RunCMakeTest.cmake index 4f1f0ef..41b8a45 100644 --- a/Tests/RunCMake/ExportSbom/RunCMakeTest.cmake +++ b/Tests/RunCMake/ExportSbom/RunCMakeTest.cmake
@@ -2,7 +2,7 @@ set(common_test_options -Wno-author - "-DCMAKE_EXPERIMENTAL_GENERATE_SBOM:STRING=2d856d6d-53e8-488b-a17f-d486d2cac317" + "-DCMAKE_EXPERIMENTAL_GENERATE_SBOM:STRING=248471c2-d905-4c9e-81b5-b89cd27965e1" ) function(run_cmake_error test)
diff --git a/Tests/RunCMake/File_Archive/RunCMakeTest.cmake b/Tests/RunCMake/File_Archive/RunCMakeTest.cmake index 4685247..17f7e61 100644 --- a/Tests/RunCMake/File_Archive/RunCMakeTest.cmake +++ b/Tests/RunCMake/File_Archive/RunCMakeTest.cmake
@@ -72,6 +72,10 @@ run_cmake(zip-filtered-exclude) run_cmake(zip-filtered-exclude-precedence) +# Excluding selected files or directories from creation +run_cmake(create-filtered-exclude) +run_cmake(create-empty-pattern-exclude) + run_cmake(create-missing-args) run_cmake(extract-missing-args) run_cmake(extract-missing-pattern)
diff --git a/Tests/RunCMake/File_Archive/create-empty-pattern-exclude-result.txt b/Tests/RunCMake/File_Archive/create-empty-pattern-exclude-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/File_Archive/create-empty-pattern-exclude-result.txt
@@ -0,0 +1 @@ +1
diff --git a/Tests/RunCMake/File_Archive/create-empty-pattern-exclude-stderr.txt b/Tests/RunCMake/File_Archive/create-empty-pattern-exclude-stderr.txt new file mode 100644 index 0000000..9b07333 --- /dev/null +++ b/Tests/RunCMake/File_Archive/create-empty-pattern-exclude-stderr.txt
@@ -0,0 +1,3 @@ +^CMake Error: exclusion pattern must not be empty +CMake Error at create-empty-pattern-exclude\.cmake:[0-9]+ \(file\): + file failed to compress:
diff --git a/Tests/RunCMake/File_Archive/create-empty-pattern-exclude.cmake b/Tests/RunCMake/File_Archive/create-empty-pattern-exclude.cmake new file mode 100644 index 0000000..7027705 --- /dev/null +++ b/Tests/RunCMake/File_Archive/create-empty-pattern-exclude.cmake
@@ -0,0 +1,8 @@ +set(COMPRESS_DIR ${CMAKE_CURRENT_BINARY_DIR}/compress_dir) +file(WRITE ${COMPRESS_DIR}/f1.txt "f1") + +file(ARCHIVE_CREATE + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/out.tar + FORMAT gnutar + PATHS ${COMPRESS_DIR} + PATTERNS_EXCLUDE "*.o" "") # empty pattern is rejected
diff --git a/Tests/RunCMake/File_Archive/create-filtered-exclude.cmake b/Tests/RunCMake/File_Archive/create-filtered-exclude.cmake new file mode 100644 index 0000000..e75107f --- /dev/null +++ b/Tests/RunCMake/File_Archive/create-filtered-exclude.cmake
@@ -0,0 +1,30 @@ +set(OUTPUT_NAME "test.zip") + +set(ARCHIVE_FORMAT zip) + +# Exclude entries matching PATTERNS_EXCLUDE while *creating* the archive. +set(COMPRESSION_OPTIONS + PATTERNS_EXCLUDE + "compress_dir/d 2/*" # exclude everything under a directory + "d-4" # exclude by unanchored name (dir + contents) + "no_such_entry" # matches nothing: must not be an error +) + +# Everything that was not excluded must still be packed and extracted. +set(CUSTOM_CHECK_FILES + "f1.txt" + "d1/f1.txt" + "d + 3/f1.txt" + "d_4/f1.txt" # underscore, not the excluded "d-4" + "My Special Directory/f1.txt" +) + +# The excluded entries must not be present in the created archive. +set(NOT_EXISTING_FILES_CHECK + "d 2/f1.txt" + "d-4/f1.txt" +) + +include(${CMAKE_CURRENT_LIST_DIR}/roundtrip.cmake) + +check_magic("504b0304" LIMIT 4 HEX)
diff --git a/Tests/RunCMake/File_Archive/roundtrip.cmake b/Tests/RunCMake/File_Archive/roundtrip.cmake index bdbc600..a0611c9 100644 --- a/Tests/RunCMake/File_Archive/roundtrip.cmake +++ b/Tests/RunCMake/File_Archive/roundtrip.cmake
@@ -65,6 +65,7 @@ COMPRESSION "${COMPRESSION_TYPE}" WORKING_DIRECTORY "${WORKING_DIRECTORY}" ${ENCODING_OPTIONS} + ${COMPRESSION_OPTIONS} VERBOSE PATHS ${FULL_COMPRESS_DIR})
diff --git a/Tests/RunCMake/InstallSbom/ProjectMetadata.cmake b/Tests/RunCMake/InstallSbom/ProjectMetadata.cmake index daaf3b4..d1f99b7 100644 --- a/Tests/RunCMake/InstallSbom/ProjectMetadata.cmake +++ b/Tests/RunCMake/InstallSbom/ProjectMetadata.cmake
@@ -3,7 +3,7 @@ install( SBOM test_targets DESCRIPTION "An eloquent description" - LICENSE "BSD-3" + DATA_LICENSE "BSD-3" HOMEPAGE_URL "www.example.com" PACKAGE_URL "https://example.com/test_targets.tar.gz" VERSION "1.3.4"
diff --git a/Tests/RunCMake/InstallSbom/RunCMakeTest.cmake b/Tests/RunCMake/InstallSbom/RunCMakeTest.cmake index fd567a8..bc1bddc 100644 --- a/Tests/RunCMake/InstallSbom/RunCMakeTest.cmake +++ b/Tests/RunCMake/InstallSbom/RunCMakeTest.cmake
@@ -2,7 +2,7 @@ set(common_test_options -Wno-author - "-DCMAKE_EXPERIMENTAL_GENERATE_SBOM:STRING=2d856d6d-53e8-488b-a17f-d486d2cac317" + "-DCMAKE_EXPERIMENTAL_GENERATE_SBOM:STRING=248471c2-d905-4c9e-81b5-b89cd27965e1" ) function(run_cmake_error test)
diff --git a/Tests/RunCMake/Sbom/ProjectMetadata-install-check.cmake b/Tests/RunCMake/Sbom/ProjectMetadata-install-check.cmake index 697eb70..83ffda6 100644 --- a/Tests/RunCMake/Sbom/ProjectMetadata-install-check.cmake +++ b/Tests/RunCMake/Sbom/ProjectMetadata-install-check.cmake
@@ -36,6 +36,25 @@ } ]=]) +set(LICENSE_EXPECTED [=[ +{ + "creationInfo" : "_:Build#CreationInfo", + "from" : "urn:test#Package", + "relationshipType" : "hasDeclaredLicense", + "spdxId" : "urn:test#DeclaredLicenseRelationship", + "to" : + [ + { + "creationInfo" : "_:Build#CreationInfo", + "simplelicensing_licenseExpression" : "license-for-test-target", + "spdxId" : "urn:test#LicenseExpression", + "type" : "simplelicensing_LicenseExpression" + } + ], + "type" : "Relationship" +} +]=]) + expect_value("${content}" "https://spdx.org/rdf/3.0.1/spdx-context.jsonld" "@context") string(JSON CREATION_INFO GET "${content}" "@graph" "0") @@ -44,3 +63,6 @@ string(JSON SPDX_DOCUMENT GET "${content}" "@graph" "1") expect_object("${SPDX_DOCUMENT}" SPDX_DOCUMENT_EXPECTED) expect_object("${SPDX_DOCUMENT}" APPLICATION_EXPECTED "rootElement") + +string(JSON LICENSE_RELATIONSHIP GET "${content}" "@graph" "2") +expect_object("${LICENSE_RELATIONSHIP}" LICENSE_EXPECTED)
diff --git a/Tests/RunCMake/Sbom/ProjectMetadata.cmake b/Tests/RunCMake/Sbom/ProjectMetadata.cmake index 02604fc..c56c0e2 100644 --- a/Tests/RunCMake/Sbom/ProjectMetadata.cmake +++ b/Tests/RunCMake/Sbom/ProjectMetadata.cmake
@@ -10,6 +10,7 @@ VERSION 1.2.0) add_library(test INTERFACE) +set_target_properties(test PROPERTIES SPDX_LICENSE license-for-test-target) install( TARGETS test
diff --git a/Tests/RunCMake/Sbom/ProjectMetadataExplicitAssertions.cmake b/Tests/RunCMake/Sbom/ProjectMetadataExplicitAssertions.cmake index 33fca83..6d3247c 100644 --- a/Tests/RunCMake/Sbom/ProjectMetadataExplicitAssertions.cmake +++ b/Tests/RunCMake/Sbom/ProjectMetadataExplicitAssertions.cmake
@@ -3,7 +3,13 @@ set(DOCUMENT_METADATA_EXPECTED [=[ { "description" : "An eloquent description", - "dataLicense" : "BSD-3" + "dataLicense" : + { + "creationInfo" : "_:Build#CreationInfo", + "simplelicensing_licenseExpression" : "BSD-3", + "spdxId" : "urn:test_targets#LicenseExpression", + "type" : "simplelicensing_LicenseExpression" + } } ]=])
diff --git a/Tests/RunCMake/Sbom/Requirements-install-check.cmake b/Tests/RunCMake/Sbom/Requirements-install-check.cmake index 92f2010..5e5aa14 100644 --- a/Tests/RunCMake/Sbom/Requirements-install-check.cmake +++ b/Tests/RunCMake/Sbom/Requirements-install-check.cmake
@@ -119,6 +119,24 @@ } ]=]) +set(TEST_LIBA_LINKED_LICENSE_EXPECTED [=[ +{ + "creationInfo" : "_:Build#CreationInfo", + "from" : "urn:test:liba#Package", + "relationshipType" : "hasDeclaredLicense", + "spdxId" : "urn:test::liba#DeclaredLicenseRelationship", + "to" : + [ + { + "creationInfo" : "_:Build#CreationInfo", + "simplelicensing_licenseExpression" : "license-for-test-liba", + "spdxId" : "urn:test::liba#LicenseExpression", + "type" : "simplelicensing_LicenseExpression" + } + ], + "type" : "Relationship" +} +]=]) set(CREATION_INFO_EXPECTED [=[ { @@ -147,3 +165,7 @@ expect_object("${BAR_SPDX_DOCUMENT}" BAR_LIBD "rootElement") expect_object("${BAR_SPDX_DOCUMENT}" BAR_DEPENDENCY_TEST "element") expect_object("${BAR_SPDX_DOCUMENT}" BAR_DEPENDENCY_FOO "element") + +# Check that the license target property imported from cmake config is reported +string(JSON LICENSE_RELATIONSHIP GET "${BAR_CONTENT}" "@graph" "2") +expect_object("${LICENSE_RELATIONSHIP}" TEST_LIBA_LINKED_LICENSE_EXPECTED)
diff --git a/Tests/RunCMake/Sbom/SharedTarget-install-check.cmake b/Tests/RunCMake/Sbom/SharedTarget-install-check.cmake index 7114364..1c698e8 100644 --- a/Tests/RunCMake/Sbom/SharedTarget-install-check.cmake +++ b/Tests/RunCMake/Sbom/SharedTarget-install-check.cmake
@@ -67,6 +67,25 @@ } ]=]) +set(LICENSE_EXPECTED [=[ +{ + "creationInfo" : "_:Build#CreationInfo", + "from" : "urn:foo:foo#Package", + "relationshipType" : "hasDeclaredLicense", + "spdxId" : "urn:foo::foo#DeclaredLicenseRelationship", + "to" : + [ + { + "creationInfo" : "_:Build#CreationInfo", + "simplelicensing_licenseExpression" : "BSD-3-Clause", + "spdxId" : "urn:foo::foo#LicenseExpression", + "type" : "simplelicensing_LicenseExpression" + } + ], + "type" : "Relationship" +} +]=]) + expect_value("${content}" "https://spdx.org/rdf/3.0.1/spdx-context.jsonld" "@context") string(JSON CREATION_INFO GET "${content}" "@graph" "0") @@ -76,5 +95,9 @@ expect_object("${SPDX_DOCUMENT}" SPDX_DOCUMENT_EXPECTED) expect_object("${SPDX_DOCUMENT}" APPLICATION_EXPECTED "rootElement") expect_object("${SPDX_DOCUMENT}" DEPENDENCY_EXPECTED "element") -string(JSON LINKED_LIBRARIES GET "${content}" "@graph" "2") +string(JSON LINKED_LIBRARIES GET "${content}" "@graph" "3") expect_object("${LINKED_LIBRARIES}" BUILD_LINKED_LIBRARIES_EXPECTED) + +# Check that default_license from the imported CPS package is reported +string(JSON LICENSE_RELATIONSHIP GET "${content}" "@graph" "2") +expect_object("${LICENSE_RELATIONSHIP}" LICENSE_EXPECTED)
diff --git a/Tests/RunCMake/Sbom/cmake/test-config.cmake b/Tests/RunCMake/Sbom/cmake/test-config.cmake index 3c46ea6..12cea73 100644 --- a/Tests/RunCMake/Sbom/cmake/test-config.cmake +++ b/Tests/RunCMake/Sbom/cmake/test-config.cmake
@@ -1 +1,2 @@ add_library(test::liba INTERFACE IMPORTED) +set_target_properties(test::liba PROPERTIES SPDX_LICENSE license-for-test-liba)
diff --git a/Tests/RunCMake/XcodeProject/DeterministicProductIds-check.cmake b/Tests/RunCMake/XcodeProject/DeterministicProductIds-check.cmake new file mode 100644 index 0000000..3c86e6f --- /dev/null +++ b/Tests/RunCMake/XcodeProject/DeterministicProductIds-check.cmake
@@ -0,0 +1,49 @@ +# Collect "path -> object id" for every product PBXFileReference (those under +# BUILT_PRODUCTS_DIR) in a generated project.pbxproj. +function(read_product_ids pbxproj out_var) + if(NOT EXISTS "${pbxproj}") + set(RunCMake_TEST_FAILED "Project file does not exist:\n ${pbxproj}" PARENT_SCOPE) + return() + endif() + set(ids "") + file(STRINGS "${pbxproj}" lines) + foreach(line IN LISTS lines) + if(line MATCHES "isa = PBXFileReference;" AND line MATCHES "sourceTree = BUILT_PRODUCTS_DIR;") + string(REGEX MATCH "^[ \t]*([0-9A-F]+) " _ "${line}") + set(id "${CMAKE_MATCH_1}") + string(REGEX MATCH "path = ([^;]+);" _ "${line}") + set(path "${CMAKE_MATCH_1}") + list(APPEND ids "${path}=${id}") + endif() + endforeach() + list(SORT ids) + set(${out_var} "${ids}" PARENT_SCOPE) +endfunction() + +set(pbxproj "${RunCMake_TEST_BINARY_DIR}/DeterministicProductIds.xcodeproj/project.pbxproj") +read_product_ids("${pbxproj}" this_ids) +if(RunCMake_TEST_FAILED) + return() +endif() + +if(NOT this_ids) + set(RunCMake_TEST_FAILED "No product PBXFileReference entries found in\n ${pbxproj}") + return() +endif() + +# On the second generation, compare against the first build tree. The ids must +# be byte-identical even though the build tree path differs. +if(DEFINED DeterministicProductIds_FirstBinaryDir) + read_product_ids( + "${DeterministicProductIds_FirstBinaryDir}/DeterministicProductIds.xcodeproj/project.pbxproj" + first_ids) + if(RunCMake_TEST_FAILED) + return() + endif() + if(NOT this_ids STREQUAL first_ids) + string(REPLACE ";" "\n " a "${first_ids}") + string(REPLACE ";" "\n " b "${this_ids}") + set(RunCMake_TEST_FAILED + "Product PBXFileReference ids are not deterministic across build trees.\nFirst:\n ${a}\nSecond:\n ${b}") + endif() +endif()
diff --git a/Tests/RunCMake/XcodeProject/DeterministicProductIds.cmake b/Tests/RunCMake/XcodeProject/DeterministicProductIds.cmake new file mode 100644 index 0000000..53350f2 --- /dev/null +++ b/Tests/RunCMake/XcodeProject/DeterministicProductIds.cmake
@@ -0,0 +1,10 @@ +enable_language(C) + +# Each target's product PBXFileReference must get a deterministic object id so +# that a parent project embedding this one can keep a stable remoteGlobalIDString. +add_library(productStatic STATIC empty.c) +add_library(productShared SHARED empty.c) +add_executable(productExe empty.c) + +# A target in a subdirectory exercises the relative-path component of the key. +add_subdirectory(DeterministicProductIdsSub)
diff --git a/Tests/RunCMake/XcodeProject/DeterministicProductIdsSub/CMakeLists.txt b/Tests/RunCMake/XcodeProject/DeterministicProductIdsSub/CMakeLists.txt new file mode 100644 index 0000000..bfbf6a8 --- /dev/null +++ b/Tests/RunCMake/XcodeProject/DeterministicProductIdsSub/CMakeLists.txt
@@ -0,0 +1 @@ +add_library(productSubStatic STATIC ../empty.c)
diff --git a/Tests/RunCMake/XcodeProject/RunCMakeTest.cmake b/Tests/RunCMake/XcodeProject/RunCMakeTest.cmake index eb8993e..d5162b5 100644 --- a/Tests/RunCMake/XcodeProject/RunCMakeTest.cmake +++ b/Tests/RunCMake/XcodeProject/RunCMakeTest.cmake
@@ -14,6 +14,19 @@ run_cmake(ExplicitCMakeLists) run_cmake(ImplicitCMakeLists) run_cmake(InterfaceLibSources) + +function(DeterministicProductIds) + # Generate the same project into two separate build trees and verify that the + # product PBXFileReference object ids are byte-identical: deterministic and + # independent of the build tree location. + set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/DeterministicProductIds-build1) + run_cmake(DeterministicProductIds) + set(DeterministicProductIds_FirstBinaryDir ${RunCMake_TEST_BINARY_DIR}) + set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/DeterministicProductIds-build2) + run_cmake(DeterministicProductIds) +endfunction() +DeterministicProductIds() + run_cmake_with_options(SearchPaths -DCMAKE_CONFIGURATION_TYPES=Debug) run_cmake_with_options(InheritedParameters -DCMake_TEST_Swift=${CMake_TEST_Swift})
diff --git a/Tests/RunCMake/XcodeProject/empty.c b/Tests/RunCMake/XcodeProject/empty.c new file mode 100644 index 0000000..af917d0 --- /dev/null +++ b/Tests/RunCMake/XcodeProject/empty.c
@@ -0,0 +1,4 @@ +int productSymbol(void) +{ + return 0; +}
diff --git a/Tests/RunCMake/cmake_parse_arguments/BadArgN2-stderr.txt b/Tests/RunCMake/cmake_parse_arguments/BadArgN2-stderr.txt index 806756a..dcb6341 100644 --- a/Tests/RunCMake/cmake_parse_arguments/BadArgN2-stderr.txt +++ b/Tests/RunCMake/cmake_parse_arguments/BadArgN2-stderr.txt
@@ -1,5 +1,5 @@ ^CMake Error at BadArgN2\.cmake:[0-9]+ \(cmake_parse_arguments\): - PARSE_ARGN called with _FUNCTION_ARGNC='' that is not an unsigned integer + PARSE_ARGN called with ARGNC='' that is not an unsigned integer Call Stack \(most recent call first\): BadArgN2\.cmake:[0-9]+ \(test2\) CMakeLists\.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/cmake_parse_arguments/BadArgN2.cmake b/Tests/RunCMake/cmake_parse_arguments/BadArgN2.cmake index 0e91679..476d0bc 100644 --- a/Tests/RunCMake/cmake_parse_arguments/BadArgN2.cmake +++ b/Tests/RunCMake/cmake_parse_arguments/BadArgN2.cmake
@@ -1,5 +1,5 @@ function(test2) - unset(_FUNCTION_ARGNC) + unset(ARGNC) cmake_parse_arguments(PARSE_ARGN pref "" "" "") endfunction() test2()
diff --git a/Tests/RunCMake/install/RunCMakeTest.cmake b/Tests/RunCMake/install/RunCMakeTest.cmake index 9408443..b628597 100644 --- a/Tests/RunCMake/install/RunCMakeTest.cmake +++ b/Tests/RunCMake/install/RunCMakeTest.cmake
@@ -95,7 +95,7 @@ run_cmake_with_options(PACKAGE_INFO-AbsoluteDest-error -Werror=install-absolute-destination) run_cmake_with_options(SBOM-AbsoluteDest-warn -Winstall-absolute-destination - -DCMAKE_EXPERIMENTAL_GENERATE_SBOM=2d856d6d-53e8-488b-a17f-d486d2cac317) + -DCMAKE_EXPERIMENTAL_GENERATE_SBOM=248471c2-d905-4c9e-81b5-b89cd27965e1) run_cmake_with_options(IMPORTED_RUNTIME_ARTIFACTS-AbsoluteDest-warn -Winstall-absolute-destination) if(CMAKE_SYSTEM_NAME MATCHES "^(Linux|Darwin|Windows)$") run_cmake_with_options(RUNTIME_DEPENDENCY_SET-AbsoluteDest-warn -Winstall-absolute-destination)