Merge topic 'xcode-framework-system-includes'
7d99cff236 Xcode: Properly identify frameworks with system includes
Acked-by: Kitware Robot <kwrobot@kitware.com>
Tested-by: buildbot <buildbot@kitware.com>
Merge-request: !6815
diff --git a/.gitlab/ci/configure_windows_vs_common.cmake b/.gitlab/ci/configure_windows_vs_common.cmake
index a0a4742..703f534 100644
--- a/.gitlab/ci/configure_windows_vs_common.cmake
+++ b/.gitlab/ci/configure_windows_vs_common.cmake
@@ -4,5 +4,6 @@
set(CMake_TEST_FindOpenMP_C "ON" CACHE BOOL "")
set(CMake_TEST_FindOpenMP_CXX "ON" CACHE BOOL "")
set(CMake_TEST_FindOpenMP_Fortran "OFF" CACHE BOOL "")
+set(CMake_TEST_Java OFF CACHE BOOL "")
include("${CMAKE_CURRENT_LIST_DIR}/configure_external_test.cmake")
diff --git a/Auxiliary/vim/syntax/cmake.vim b/Auxiliary/vim/syntax/cmake.vim
index 52330f7..c6c5d23 100644
--- a/Auxiliary/vim/syntax/cmake.vim
+++ b/Auxiliary/vim/syntax/cmake.vim
@@ -152,6 +152,7 @@
\ DISABLED
\ DISABLED_FEATURES
\ DISABLE_PRECOMPILE_HEADERS
+ \ DOTNET_SDK
\ DOTNET_TARGET_FRAMEWORK
\ DOTNET_TARGET_FRAMEWORK_VERSION
\ ECLIPSE_EXTRA_CPROJECT_CONTENTS
@@ -1001,6 +1002,7 @@
\ CMAKE_DIRECTORY_LABELS
\ CMAKE_DISABLE_PRECOMPILE_HEADERS
\ CMAKE_DL_LIBS
+ \ CMAKE_DOTNET_SDK
\ CMAKE_DOTNET_TARGET_FRAMEWORK
\ CMAKE_DOTNET_TARGET_FRAMEWORK_VERSION
\ CMAKE_ECLIPSE_GENERATE_LINKED_RESOURCES
diff --git a/Copyright.txt b/Copyright.txt
index b703193..ed25419 100644
--- a/Copyright.txt
+++ b/Copyright.txt
@@ -1,5 +1,5 @@
CMake - Cross Platform Makefile Generator
-Copyright 2000-2021 Kitware, Inc. and Contributors
+Copyright 2000-2022 Kitware, Inc. and Contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/Help/command/if.rst b/Help/command/if.rst
index 6957142..a729b1e 100644
--- a/Help/command/if.rst
+++ b/Help/command/if.rst
@@ -52,7 +52,8 @@
``if(<constant>)``
True if the constant is ``1``, ``ON``, ``YES``, ``TRUE``, ``Y``,
- or a non-zero number. False if the constant is ``0``, ``OFF``,
+ or a non-zero number (including floating point numbers).
+ False if the constant is ``0``, ``OFF``,
``NO``, ``FALSE``, ``N``, ``IGNORE``, ``NOTFOUND``, the empty string,
or ends in the suffix ``-NOTFOUND``. Named boolean constants are
case-insensitive. If the argument is not one of these specific
diff --git a/Help/command/list.rst b/Help/command/list.rst
index 9b49cb4..33c4f80 100644
--- a/Help/command/list.rst
+++ b/Help/command/list.rst
@@ -128,7 +128,9 @@
list(APPEND <list> [<element> ...])
-Appends elements to the list.
+Appends elements to the list. If no variable named ``<list>`` exists in the
+current scope its value is treated as empty and the elements are appended to
+that empty list.
.. _FILTER:
@@ -150,7 +152,12 @@
list(INSERT <list> <element_index> <element> [<element> ...])
-Inserts elements to the list to the specified location.
+Inserts elements to the list to the specified index. It is an
+error to specify an out-of-range index. Valid indexes are 0 to `N`
+where `N` is the length of the list, inclusive. An empty list
+has length 0. If no variable named ``<list>`` exists in the
+current scope its value is treated as empty and the elements are
+inserted in that empty list.
.. _POP_BACK:
@@ -186,7 +193,9 @@
.. versionadded:: 3.15
-Insert elements to the 0th position in the list.
+Insert elements to the 0th position in the list. If no variable named
+``<list>`` exists in the current scope its value is treated as empty and
+the elements are prepended to that empty list.
.. _REMOVE_ITEM:
diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst
index 5e18e10..ddb917a 100644
--- a/Help/manual/cmake-properties.7.rst
+++ b/Help/manual/cmake-properties.7.rst
@@ -191,6 +191,7 @@
/prop_tgt/DEPLOYMENT_REMOTE_DIRECTORY
/prop_tgt/DEPRECATION
/prop_tgt/DISABLE_PRECOMPILE_HEADERS
+ /prop_tgt/DOTNET_SDK
/prop_tgt/DOTNET_TARGET_FRAMEWORK
/prop_tgt/DOTNET_TARGET_FRAMEWORK_VERSION
/prop_tgt/EchoString
@@ -304,6 +305,7 @@
/prop_tgt/LINK_INTERFACE_MULTIPLICITY
/prop_tgt/LINK_INTERFACE_MULTIPLICITY_CONFIG
/prop_tgt/LINK_LIBRARIES
+ /prop_tgt/LINK_LIBRARIES_ONLY_TARGETS
/prop_tgt/LINK_OPTIONS
/prop_tgt/LINK_SEARCH_END_STATIC
/prop_tgt/LINK_SEARCH_START_STATIC
diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst
index 3c50117..51b092f 100644
--- a/Help/manual/cmake-variables.7.rst
+++ b/Help/manual/cmake-variables.7.rst
@@ -49,6 +49,7 @@
/variable/CMAKE_DEBUG_TARGET_PROPERTIES
/variable/CMAKE_DIRECTORY_LABELS
/variable/CMAKE_DL_LIBS
+ /variable/CMAKE_DOTNET_SDK
/variable/CMAKE_DOTNET_TARGET_FRAMEWORK
/variable/CMAKE_DOTNET_TARGET_FRAMEWORK_VERSION
/variable/CMAKE_EDIT_COMMAND
@@ -220,6 +221,7 @@
/variable/CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT
/variable/CMAKE_LIBRARY_PATH
/variable/CMAKE_LINK_DIRECTORIES_BEFORE
+ /variable/CMAKE_LINK_LIBRARIES_ONLY_TARGETS
/variable/CMAKE_MFC_FLAG
/variable/CMAKE_MAXIMUM_RECURSION_DEPTH
/variable/CMAKE_MESSAGE_CONTEXT
diff --git a/Help/policy/CMP0028.rst b/Help/policy/CMP0028.rst
index ab38229..dcd39d8 100644
--- a/Help/policy/CMP0028.rst
+++ b/Help/policy/CMP0028.rst
@@ -13,6 +13,8 @@
was considered to refer to a file on disk. This can lead to confusing error
messages if there is a typo in what should be a target name.
+See also the :prop_tgt:`LINK_LIBRARIES_ONLY_TARGETS` target property.
+
The ``OLD`` behavior for this policy is to search for targets, then files on
disk, even if the search term contains double-colons. The ``NEW`` behavior
for this policy is to issue a ``FATAL_ERROR`` if a link dependency contains
diff --git a/Help/prop_tgt/DOTNET_SDK.rst b/Help/prop_tgt/DOTNET_SDK.rst
new file mode 100644
index 0000000..ca1dcac
--- /dev/null
+++ b/Help/prop_tgt/DOTNET_SDK.rst
@@ -0,0 +1,25 @@
+DOTNET_SDK
+----------
+
+.. versionadded:: 3.23
+
+Specify the .NET SDK for C# projects. For example: ``Microsoft.NET.Sdk``.
+
+This property tells :ref:`Visual Studio Generators` for VS 2019 and
+above to generate a .NET SDK-style project using the specified SDK.
+The property is meaningful only to these generators, and only in C#
+targets. It is ignored for C++ projects, even if they are managed
+(e.g. using :prop_tgt:`COMMON_LANGUAGE_RUNTIME`).
+
+This property must be a non-empty string to generate .NET SDK-style projects.
+CMake does not perform any validations for the value of the property.
+
+This property may be initialized for all targets using the
+:variable:`CMAKE_DOTNET_SDK` variable.
+
+.. note::
+
+ The :ref:`Visual Studio Generators` in this version of CMake have not
+ yet learned to support :command:`add_custom_command` in .NET SDK-style
+ projects. It is currently an error to attach a custom command to a
+ target with the ``DOTNET_SDK`` property set.
diff --git a/Help/prop_tgt/LINK_LIBRARIES_ONLY_TARGETS.rst b/Help/prop_tgt/LINK_LIBRARIES_ONLY_TARGETS.rst
new file mode 100644
index 0000000..78fbb02
--- /dev/null
+++ b/Help/prop_tgt/LINK_LIBRARIES_ONLY_TARGETS.rst
@@ -0,0 +1,55 @@
+LINK_LIBRARIES_ONLY_TARGETS
+---------------------------
+
+.. versionadded:: 3.23
+
+Enforce that link items that can be target names are actually existing targets.
+
+Set this property to a true value to enable additional checks on the contents
+of the :prop_tgt:`LINK_LIBRARIES` and :prop_tgt:`INTERFACE_LINK_LIBRARIES`
+target properties, typically populated by :command:`target_link_libraries`.
+CMake will verify that link items that might be target names actually name
+existing targets. An item is considered a possible target name if:
+
+* it does not contain a ``/`` or ``\``, and
+* it does not start in ``-``, and
+* (for historical reasons) it does not start in ``$`` or `````.
+
+This property is initialized by the value of the
+:variable:`CMAKE_LINK_LIBRARIES_ONLY_TARGETS` variable when a non-imported
+target is created. The property may be explicitly enabled on an imported
+target to check its link interface.
+
+For example, the following code:
+
+.. code-block:: cmake
+
+ set(CMAKE_LINK_LIBRARIES_ONLY_TARGETS ON)
+ add_executable(myLib STATIC myLib.c)
+ add_executable(myExe myExe.c)
+ target_link_libraries(myExe PRIVATE miLib) # typo for myLib
+
+will produce a CMake-time error that ``miLib`` is not a target.
+
+In order to link toolchain-provided libraries by name while still
+enforcing ``LINK_LIBRARIES_ONLY_TARGETS``, use an
+:ref:`imported <Imported Targets>`
+:ref:`Interface Library <Interface Libraries>` with the
+:prop_tgt:`IMPORTED_LIBNAME` target property:
+
+.. code-block:: cmake
+
+ add_library(toolchain::m INTERFACE IMPORTED)
+ set_property(TARGET toolchain::m PROPERTY IMPORTED_LIBNAME "m")
+ target_link_libraries(myExe PRIVATE toolchain::m)
+
+See also policy :policy:`CMP0028`.
+
+.. note::
+
+ If :prop_tgt:`INTERFACE_LINK_LIBRARIES` contains generator expressions,
+ its actual list of link items may depend on the type and properties of
+ the consuming target. In such cases CMake may not always detect names
+ of missing targets that only appear for specific consumers.
+ A future version of CMake with improved heuristics may start triggering
+ errors on projects accepted by previous versions of CMake.
diff --git a/Help/release/dev/link-only-targets.rst b/Help/release/dev/link-only-targets.rst
new file mode 100644
index 0000000..7901a25
--- /dev/null
+++ b/Help/release/dev/link-only-targets.rst
@@ -0,0 +1,7 @@
+link-only-targets
+-----------------
+
+* The :variable:`CMAKE_LINK_LIBRARIES_ONLY_TARGETS` variable and
+ corresponding :prop_tgt:`LINK_LIBRARIES_ONLY_TARGETS` target
+ property were added to optionally require that all link items
+ that can be target names are actually names of existing targets.
diff --git a/Help/release/dev/vs-csharp-dotnet-sdk.rst b/Help/release/dev/vs-csharp-dotnet-sdk.rst
new file mode 100644
index 0000000..cc0ebe4
--- /dev/null
+++ b/Help/release/dev/vs-csharp-dotnet-sdk.rst
@@ -0,0 +1,9 @@
+vs-csharp-dotnet-sdk
+--------------------
+
+* The :ref:`Visual Studio Generators` for VS 2019 and above learned to
+ support .NET SDK-style project files (``.csproj``) for C# projects.
+ See the :prop_tgt:`DOTNET_SDK` target property and corresponding
+ :variable:`CMAKE_DOTNET_SDK` variable.
+ However, this version of CMake does not yet support using
+ :command:`add_custom_command` in .NET SDK-style projects.
diff --git a/Help/variable/CMAKE_DOTNET_SDK.rst b/Help/variable/CMAKE_DOTNET_SDK.rst
new file mode 100644
index 0000000..dc8806a
--- /dev/null
+++ b/Help/variable/CMAKE_DOTNET_SDK.rst
@@ -0,0 +1,9 @@
+CMAKE_DOTNET_SDK
+----------------
+
+.. versionadded:: 3.23
+
+Default value for :prop_tgt:`DOTNET_SDK` property of targets.
+
+This variable is used to initialize the :prop_tgt:`DOTNET_SDK`
+property on all targets. See that target property for additional information.
diff --git a/Help/variable/CMAKE_LINK_LIBRARIES_ONLY_TARGETS.rst b/Help/variable/CMAKE_LINK_LIBRARIES_ONLY_TARGETS.rst
new file mode 100644
index 0000000..513c3d0
--- /dev/null
+++ b/Help/variable/CMAKE_LINK_LIBRARIES_ONLY_TARGETS.rst
@@ -0,0 +1,10 @@
+CMAKE_LINK_LIBRARIES_ONLY_TARGETS
+---------------------------------
+
+.. versionadded:: 3.23
+
+Set this variable to initialize the :prop_tgt:`LINK_LIBRARIES_ONLY_TARGETS`
+property of non-imported targets when they are created. Setting it to true
+enables an additional check that all items named by
+:command:`target_link_libraries` that can be target names are actually names
+of existing targets. See the target property documentation for details.
diff --git a/Modules/Internal/CPack/CPackFreeBSD.cmake b/Modules/Internal/CPack/CPackFreeBSD.cmake
index ae40532..c35089c 100644
--- a/Modules/Internal/CPack/CPackFreeBSD.cmake
+++ b/Modules/Internal/CPack/CPackFreeBSD.cmake
@@ -34,7 +34,7 @@
endif()
endforeach()
if(NOT VALUE)
- message(WARNING "Variable ${OUTPUT_VAR_NAME} could not be given a fallback value from any variable ${FALLBACK_VAR_NAMES}.")
+ message(WARNING "Variable ${OUTPUT_VAR_NAME} could not be given a fallback value from (any of) ${FALLBACK_VAR_NAMES}.")
endif()
endfunction()
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake
index 86535b6..4b51017 100644
--- a/Source/CMakeVersion.cmake
+++ b/Source/CMakeVersion.cmake
@@ -1,7 +1,7 @@
# CMake version number components.
set(CMake_VERSION_MAJOR 3)
set(CMake_VERSION_MINOR 22)
-set(CMake_VERSION_PATCH 20211222)
+set(CMake_VERSION_PATCH 20220106)
#set(CMake_VERSION_RC 0)
set(CMake_VERSION_IS_DIRTY 0)
diff --git a/Source/CPack/cmCPackFreeBSDGenerator.cxx b/Source/CPack/cmCPackFreeBSDGenerator.cxx
index fcd5753..b5d41fc 100644
--- a/Source/CPack/cmCPackFreeBSDGenerator.cxx
+++ b/Source/CPack/cmCPackFreeBSDGenerator.cxx
@@ -21,8 +21,15 @@
#include <sys/stat.h>
+// Suffix used to tell libpkg what compression to use
+static const char FreeBSDPackageCompression[] = "txz";
+// Resulting package file-suffix, for < 1.17 and >= 1.17 versions of libpkg
+static const char FreeBSDPackageSuffix_10[] = ".txz";
+static const char FreeBSDPackageSuffix_17[] = ".pkg";
+
cmCPackFreeBSDGenerator::cmCPackFreeBSDGenerator()
- : cmCPackArchiveGenerator(cmArchiveWrite::CompressXZ, "paxr", ".txz")
+ : cmCPackArchiveGenerator(cmArchiveWrite::CompressXZ, "paxr",
+ FreeBSDPackageSuffix_17)
{
}
@@ -35,6 +42,56 @@
cmCPackFreeBSDGenerator::~cmCPackFreeBSDGenerator() = default;
+// This is a wrapper for struct pkg_create and pkg_create()
+//
+// Instantiate this class with suitable parameters, then
+// check isValid() to check if it's ok. Afterwards, call
+// Create() to do the actual work. This will leave a package
+// in the given `output_dir`.
+//
+// This wrapper cleans up the struct pkg_create.
+class PkgCreate
+{
+public:
+ PkgCreate()
+ : d(nullptr)
+ {
+ }
+ PkgCreate(const std::string& output_dir, const std::string& toplevel_dir,
+ const std::string& manifest_name)
+ : d(pkg_create_new())
+ , manifest(manifest_name)
+
+ {
+ if (d) {
+ pkg_create_set_format(d, FreeBSDPackageCompression);
+ pkg_create_set_compression_level(d, 0); // Explicitly set default
+ pkg_create_set_overwrite(d, false);
+ pkg_create_set_rootdir(d, toplevel_dir.c_str());
+ pkg_create_set_output_dir(d, output_dir.c_str());
+ }
+ }
+ ~PkgCreate()
+ {
+ if (d)
+ pkg_create_free(d);
+ }
+
+ bool isValid() const { return d; }
+
+ bool Create()
+ {
+ if (!isValid())
+ return false;
+ int r = pkg_create(d, manifest.c_str(), nullptr, false);
+ return r == 0;
+ }
+
+private:
+ struct pkg_create* d;
+ std::string manifest;
+};
+
// This is a wrapper, for use only in stream-based output,
// that will output a string in UCL escaped fashion (in particular,
// quotes and backslashes are escaped). The list of characters
@@ -271,7 +328,7 @@
s << "\"files\": {\n";
for (std::string const& file : files) {
s << " \"/" << cmSystemTools::RelativePath(toplevel, file) << "\": \""
- << "<sha256>"
+ << "<sha256>" // this gets replaced by libpkg by the actual SHA256
<< "\",\n";
}
s << " },\n";
@@ -281,11 +338,10 @@
{
if (!this->ReadListFile("Internal/CPack/CPackFreeBSD.cmake")) {
cmCPackLogger(cmCPackLog::LOG_ERROR,
- "Error while execution CPackFreeBSD.cmake" << std::endl);
+ "Error while executing CPackFreeBSD.cmake" << std::endl);
return 0;
}
- std::vector<std::string>::const_iterator fileIt;
cmWorkingDirectory wd(toplevel);
files.erase(std::remove_if(files.begin(), files.end(), ignore_file),
@@ -317,19 +373,84 @@
ONE_PACKAGE_PER_COMPONENT);
}
- std::string output_dir = cmSystemTools::CollapseFullPath("../", toplevel);
- pkg_create_from_manifest(output_dir.c_str(), ::TXZ, toplevel.c_str(),
- manifestname.c_str(), nullptr);
+ // There should be one name in the packageFileNames (already, see comment
+ // in cmCPackGenerator::DoPackage(), which holds what CPack guesses
+ // will be the package filename. libpkg does something else, though,
+ // so update the single filename to what we know will be right.
+ if (this->packageFileNames.size() == 1) {
+ std::string currentPackage = this->packageFileNames[0];
+ auto lastSlash = currentPackage.rfind('/');
- std::string broken_suffix =
- cmStrCat('-', var_lookup("CPACK_TOPLEVEL_TAG"), ".txz");
+ // If there is a pathname, preserve that; libpkg will write out
+ // a file with the package name and version as specified in the
+ // manifest, so we look those up (again). lastSlash is the slash
+ // itself, we need that as path separator to the calculated package name.
+ std::string actualPackage =
+ ((lastSlash != std::string::npos)
+ ? std::string(currentPackage, 0, lastSlash + 1)
+ : std::string()) +
+ var_lookup("CPACK_FREEBSD_PACKAGE_NAME") + '-' +
+ var_lookup("CPACK_FREEBSD_PACKAGE_VERSION") + FreeBSDPackageSuffix_17;
+
+ this->packageFileNames.clear();
+ this->packageFileNames.emplace_back(actualPackage);
+ }
+
+ if (!pkg_initialized() && pkg_init(NULL, NULL) != EPKG_OK) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Can not initialize FreeBSD libpkg." << std::endl);
+ return 0;
+ }
+
+ std::string output_dir = cmSystemTools::CollapseFullPath("../", toplevel);
+ PkgCreate package(output_dir, toplevel, manifestname);
+ if (package.isValid()) {
+ if (!package.Create()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error during pkg_create()" << std::endl);
+ return 0;
+ }
+ } else {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error before pkg_create()" << std::endl);
+ return 0;
+ }
+
+ // Specifically looking for packages suffixed with the TAG, either extension
+ std::string broken_suffix_10 =
+ cmStrCat('-', var_lookup("CPACK_TOPLEVEL_TAG"), FreeBSDPackageSuffix_10);
+ std::string broken_suffix_17 =
+ cmStrCat('-', var_lookup("CPACK_TOPLEVEL_TAG"), FreeBSDPackageSuffix_17);
for (std::string& name : packageFileNames) {
cmCPackLogger(cmCPackLog::LOG_DEBUG, "Packagefile " << name << std::endl);
- if (cmHasSuffix(name, broken_suffix)) {
- name.replace(name.size() - broken_suffix.size(), std::string::npos,
- ".txz");
+ if (cmHasSuffix(name, broken_suffix_10)) {
+ name.replace(name.size() - broken_suffix_10.size(), std::string::npos,
+ FreeBSDPackageSuffix_10);
break;
}
+ if (cmHasSuffix(name, broken_suffix_17)) {
+ name.replace(name.size() - broken_suffix_17.size(), std::string::npos,
+ FreeBSDPackageSuffix_17);
+ break;
+ }
+ }
+ // If the name uses a *new* style name, which doesn't exist, but there
+ // is an *old* style name, then use that instead. This indicates we used
+ // an older libpkg, which still creates .txz instead of .pkg files.
+ for (std::string& name : packageFileNames) {
+ if (cmHasSuffix(name, FreeBSDPackageSuffix_17) &&
+ !cmSystemTools::FileExists(name)) {
+ const std::string badSuffix(FreeBSDPackageSuffix_17);
+ const std::string goodSuffix(FreeBSDPackageSuffix_10);
+ std::string repairedName(name);
+ repairedName.replace(repairedName.size() - badSuffix.size(),
+ std::string::npos, goodSuffix);
+ if (cmSystemTools::FileExists(repairedName)) {
+ name = repairedName;
+ cmCPackLogger(cmCPackLog::LOG_DEBUG,
+ "Repaired packagefile " << name << std::endl);
+ }
+ }
}
return 1;
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
index e370472..421e136 100644
--- a/Source/cmGeneratorTarget.cxx
+++ b/Source/cmGeneratorTarget.cxx
@@ -6247,6 +6247,18 @@
void cmGeneratorTarget::CheckLinkLibraries() const
{
+ bool linkLibrariesOnlyTargets =
+ this->GetPropertyAsBool("LINK_LIBRARIES_ONLY_TARGETS");
+
+ // Evaluate the link interface of this target if needed for extra checks.
+ if (linkLibrariesOnlyTargets) {
+ std::vector<std::string> const& configs =
+ this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
+ for (std::string const& config : configs) {
+ this->GetLinkInterfaceLibraries(config, this, LinkInterfaceFor::Link);
+ }
+ }
+
// Check link the implementation for each generated configuration.
for (auto const& hmp : this->LinkImplMap) {
HeadToLinkImplementationMap const& hm = hmp.second;
@@ -6260,6 +6272,10 @@
if (!this->VerifyLinkItemColons(LinkItemRole::Implementation, item)) {
return;
}
+ if (linkLibrariesOnlyTargets &&
+ !this->VerifyLinkItemIsTarget(LinkItemRole::Implementation, item)) {
+ return;
+ }
}
}
@@ -6276,11 +6292,23 @@
if (!this->VerifyLinkItemColons(LinkItemRole::Interface, item)) {
return;
}
+ if (linkLibrariesOnlyTargets &&
+ !this->VerifyLinkItemIsTarget(LinkItemRole::Interface, item)) {
+ return;
+ }
}
}
}
}
+namespace {
+cm::string_view missingTargetPossibleReasons =
+ "Possible reasons include:\n"
+ " * There is a typo in the target name.\n"
+ " * A find_package call is missing for an IMPORTED target.\n"
+ " * An ALIAS target is missing.\n"_s;
+}
+
bool cmGeneratorTarget::VerifyLinkItemColons(LinkItemRole role,
cmLinkItem const& item) const
{
@@ -6309,11 +6337,9 @@
e = cmStrCat(e, "The link interface of target \"", this->GetName(),
"\" contains");
}
- e = cmStrCat(e, ":\n ", item.AsStr(), "\n",
- "but the target was not found. Possible reasons include:\n"
- " * There is a typo in the target name.\n"
- " * A find_package call is missing for an IMPORTED target.\n"
- " * An ALIAS target is missing.\n");
+ e =
+ cmStrCat(e, ":\n ", item.AsStr(), "\n", "but the target was not found. ",
+ missingTargetPossibleReasons);
cmListFileBacktrace backtrace = item.Backtrace;
if (backtrace.Empty()) {
backtrace = this->GetBacktrace();
@@ -6323,6 +6349,35 @@
return false;
}
+bool cmGeneratorTarget::VerifyLinkItemIsTarget(LinkItemRole role,
+ cmLinkItem const& item) const
+{
+ if (item.Target) {
+ return true;
+ }
+ std::string const& str = item.AsStr();
+ if (!str.empty() &&
+ (str[0] == '-' || str[0] == '$' || str[0] == '`' ||
+ str.find_first_of("/\\") != std::string::npos)) {
+ return true;
+ }
+
+ std::string e = cmStrCat("Target \"", this->GetName(),
+ "\" has LINK_LIBRARIES_ONLY_TARGETS enabled, but ",
+ role == LinkItemRole::Implementation
+ ? "it links to"
+ : "its link interface contains",
+ ":\n ", item.AsStr(), "\nwhich is not a target. ",
+ missingTargetPossibleReasons);
+ cmListFileBacktrace backtrace = item.Backtrace;
+ if (backtrace.Empty()) {
+ backtrace = this->GetBacktrace();
+ }
+ this->LocalGenerator->GetCMakeInstance()->IssueMessage(
+ MessageType::FATAL_ERROR, e, backtrace);
+ return false;
+}
+
void cmGeneratorTarget::GetTargetVersion(int& major, int& minor) const
{
int patch;
@@ -7787,6 +7842,11 @@
return languages.size() == 1 && languages.count("CSharp") > 0;
}
+bool cmGeneratorTarget::IsDotNetSdkTarget() const
+{
+ return !this->GetProperty("DOTNET_SDK").IsEmpty();
+}
+
void cmGeneratorTarget::ComputeLinkImplementationLanguages(
const std::string& config, cmOptionalLinkImplementation& impl) const
{
diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h
index 096e2ea..71212c4 100644
--- a/Source/cmGeneratorTarget.h
+++ b/Source/cmGeneratorTarget.h
@@ -436,6 +436,8 @@
bool IsCSharpOnly() const;
+ bool IsDotNetSdkTarget() const;
+
void GetObjectLibrariesCMP0026(
std::vector<cmGeneratorTarget*>& objlibs) const;
@@ -982,6 +984,7 @@
Implementation,
Interface,
};
+ bool VerifyLinkItemIsTarget(LinkItemRole role, cmLinkItem const& item) const;
bool VerifyLinkItemColons(LinkItemRole role, cmLinkItem const& item) const;
// Cache import information from properties for each configuration.
diff --git a/Source/cmGlobalVisualStudio7Generator.cxx b/Source/cmGlobalVisualStudio7Generator.cxx
index b3f8d90..c72b109 100644
--- a/Source/cmGlobalVisualStudio7Generator.cxx
+++ b/Source/cmGlobalVisualStudio7Generator.cxx
@@ -373,8 +373,16 @@
this->IsPartOfDefaultBuild(configs, projectTargets, target);
cmValue vcprojName = target->GetProperty("GENERATOR_FILE_NAME");
if (vcprojName) {
+ std::string mapping;
+
+ // On VS 19 and above, always map .NET SDK projects to "Any CPU".
+ if (target->IsDotNetSdkTarget() &&
+ this->GetVersion() >= VSVersion::VS16 &&
+ !this->IsReservedTarget(target->GetName())) {
+ mapping = "Any CPU";
+ }
this->WriteProjectConfigurations(fout, *vcprojName, *target, configs,
- configsPartOfDefaultBuild);
+ configsPartOfDefaultBuild, mapping);
}
}
}
diff --git a/Source/cmMachO.h b/Source/cmMachO.h
index faa024b..ec7d54c 100644
--- a/Source/cmMachO.h
+++ b/Source/cmMachO.h
@@ -5,6 +5,7 @@
#include "cmConfigure.h" // IWYU pragma: keep
#include <iosfwd>
+#include <memory>
#include <string>
#if !defined(CMake_USE_MACH_PARSER)
diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx
index 38361cc..c5703a1 100644
--- a/Source/cmTarget.cxx
+++ b/Source/cmTarget.cxx
@@ -471,6 +471,9 @@
initProp(property);
}
}
+ if (!this->IsImported()) {
+ initProp("LINK_LIBRARIES_ONLY_TARGETS");
+ }
}
// Save the backtrace of target construction.
@@ -526,6 +529,10 @@
this->impl->PolicyMap.Set(cmPolicies::CMP0022, cmPolicies::NEW);
}
+ if (!this->IsImported()) {
+ initProp("DOTNET_SDK");
+ }
+
if (this->impl->TargetType <= cmStateEnums::GLOBAL_TARGET) {
initProp("DOTNET_TARGET_FRAMEWORK");
initProp("DOTNET_TARGET_FRAMEWORK_VERSION");
diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx
index 9523038..84044e4 100644
--- a/Source/cmVisualStudio10TargetGenerator.cxx
+++ b/Source/cmVisualStudio10TargetGenerator.cxx
@@ -405,6 +405,27 @@
// Write the encoding header into the file
char magic[] = { char(0xEF), char(0xBB), char(0xBF) };
BuildFileStream.write(magic, 3);
+
+ if (this->Managed && this->ProjectType == VsProjectType::csproj &&
+ this->GeneratorTarget->IsDotNetSdkTarget() &&
+ this->GlobalGenerator->GetVersion() >=
+ cmGlobalVisualStudioGenerator::VS16) {
+ this->WriteSdkStyleProjectFile(BuildFileStream);
+ } else {
+ this->WriteClassicMsBuildProjectFile(BuildFileStream);
+ }
+
+ if (BuildFileStream.Close()) {
+ this->GlobalGenerator->FileReplacedDuringGenerate(PathToProjectFile);
+ }
+
+ // The groups are stored in a separate file for VS 10
+ this->WriteGroups();
+}
+
+void cmVisualStudio10TargetGenerator::WriteClassicMsBuildProjectFile(
+ cmGeneratedFileStream& BuildFileStream)
+{
BuildFileStream << "<?xml version=\"1.0\" encoding=\""
<< this->GlobalGenerator->Encoding() << "\"?>";
{
@@ -447,14 +468,27 @@
e1.Element("PreferredToolArchitecture", hostArch);
}
+ // ALL_BUILD and ZERO_CHECK projects transitively include
+ // Microsoft.Common.CurrentVersion.targets which triggers Target
+ // ResolveNugetPackageAssets when SDK-style targets are in the project.
+ // However, these projects have no nuget packages to reference and the
+ // build fails.
+ // Setting ResolveNugetPackages to false skips this target and the build
+ // succeeds.
+ cm::string_view targetName{ this->GeneratorTarget->GetName() };
+ if (targetName == "ALL_BUILD" ||
+ targetName == CMAKE_CHECK_BUILD_SYSTEM_TARGET) {
+ Elem e1(e0, "PropertyGroup");
+ e1.Element("ResolveNugetPackages", "false");
+ }
+
if (this->ProjectType != VsProjectType::csproj) {
this->WriteProjectConfigurations(e0);
}
{
Elem e1(e0, "PropertyGroup");
- e1.Attribute("Label", "Globals");
- e1.Element("ProjectGuid", "{" + this->GUID + "}");
+ this->WriteCommonPropertyGroupGlobals(e1);
if ((this->MSTools || this->Android) &&
this->GeneratorTarget->IsInBuildSystem()) {
@@ -462,16 +496,6 @@
this->VerifyNecessaryFiles();
}
- cmValue vsProjectTypes =
- this->GeneratorTarget->GetProperty("VS_GLOBAL_PROJECT_TYPES");
- if (vsProjectTypes) {
- const char* tagName = "ProjectTypes";
- if (this->ProjectType == VsProjectType::csproj) {
- tagName = "ProjectTypeGuids";
- }
- e1.Element(tagName, *vsProjectTypes);
- }
-
cmValue vsProjectName =
this->GeneratorTarget->GetProperty("VS_SCC_PROJECTNAME");
cmValue vsLocalPath =
@@ -495,24 +519,6 @@
e1.Element("WinMDAssembly", "true");
}
- cmValue vsGlobalKeyword =
- this->GeneratorTarget->GetProperty("VS_GLOBAL_KEYWORD");
- if (!vsGlobalKeyword) {
- if (this->GlobalGenerator->TargetsAndroid()) {
- e1.Element("Keyword", "Android");
- } else {
- e1.Element("Keyword", "Win32Proj");
- }
- } else {
- e1.Element("Keyword", *vsGlobalKeyword);
- }
-
- cmValue vsGlobalRootNamespace =
- this->GeneratorTarget->GetProperty("VS_GLOBAL_ROOTNAMESPACE");
- if (vsGlobalRootNamespace) {
- e1.Element("RootNamespace", *vsGlobalRootNamespace);
- }
-
e1.Element("Platform", this->Platform);
cmValue projLabel = this->GeneratorTarget->GetProperty("PROJECT_LABEL");
e1.Element("ProjectName", projLabel ? projLabel : this->Name);
@@ -602,24 +608,6 @@
e1.Element("VCTargetsPath", vcTargetsPath);
}
- std::vector<std::string> keys = this->GeneratorTarget->GetPropertyKeys();
- for (std::string const& keyIt : keys) {
- static const cm::string_view prefix = "VS_GLOBAL_";
- if (!cmHasPrefix(keyIt, prefix))
- continue;
- cm::string_view globalKey =
- cm::string_view(keyIt).substr(prefix.length());
- // Skip invalid or separately-handled properties.
- if (globalKey.empty() || globalKey == "PROJECT_TYPES" ||
- globalKey == "ROOTNAMESPACE" || globalKey == "KEYWORD") {
- continue;
- }
- cmValue value = this->GeneratorTarget->GetProperty(keyIt);
- if (!value)
- continue;
- e1.Element(globalKey, *value);
- }
-
if (this->Managed) {
if (this->LocalGenerator->GetVersion() >=
cmGlobalVisualStudioGenerator::VS17) {
@@ -839,13 +827,165 @@
}
}
}
+}
- if (BuildFileStream.Close()) {
- this->GlobalGenerator->FileReplacedDuringGenerate(PathToProjectFile);
+void cmVisualStudio10TargetGenerator::WriteSdkStyleProjectFile(
+ cmGeneratedFileStream& BuildFileStream)
+{
+ if (!this->Managed || this->ProjectType != VsProjectType::csproj ||
+ !this->GeneratorTarget->IsDotNetSdkTarget()) {
+ std::string message = "The target \"" + this->GeneratorTarget->GetName() +
+ "\" is not eligible for .Net SDK style project.";
+ this->Makefile->IssueMessage(MessageType::INTERNAL_ERROR, message);
+ return;
}
- // The groups are stored in a separate file for VS 10
- this->WriteGroups();
+ if (this->HasCustomCommands()) {
+ std::string message = "The target \"" + this->GeneratorTarget->GetName() +
+ "\" does not currently support add_custom_command as the Visual Studio "
+ "generators have not yet learned how to generate custom commands in "
+ ".Net SDK-style projects.";
+ this->Makefile->IssueMessage(MessageType::FATAL_ERROR, message);
+ return;
+ }
+
+ Elem e0(BuildFileStream, "Project");
+ e0.Attribute("Sdk", *this->GeneratorTarget->GetProperty("DOTNET_SDK"));
+
+ {
+ Elem e1(e0, "PropertyGroup");
+ this->WriteCommonPropertyGroupGlobals(e1);
+
+ e1.Element("EnableDefaultItems", "false");
+ // Disable the project upgrade prompt that is displayed the first time a
+ // project using an older toolset version is opened in a newer version
+ // of the IDE.
+ e1.Element("VCProjectUpgraderObjectName", "NoUpgrade");
+ e1.Element("ManagedAssembly", "true");
+
+ cmValue targetFramework =
+ this->GeneratorTarget->GetProperty("DOTNET_TARGET_FRAMEWORK");
+ if (targetFramework) {
+ if (targetFramework->find(';') != std::string::npos) {
+ e1.Element("TargetFrameworks", *targetFramework);
+ } else {
+ e1.Element("TargetFramework", *targetFramework);
+ }
+ } else {
+ e1.Element("TargetFramework", "net5.0");
+ }
+
+ std::string outputType;
+ switch (this->GeneratorTarget->GetType()) {
+ case cmStateEnums::OBJECT_LIBRARY:
+ case cmStateEnums::STATIC_LIBRARY:
+ case cmStateEnums::MODULE_LIBRARY:
+ this->Makefile->IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmStrCat("Target \"", this->GeneratorTarget->GetName(),
+ "\" is of a type not supported for managed binaries."));
+ return;
+ case cmStateEnums::SHARED_LIBRARY:
+ outputType = "Library";
+ break;
+ case cmStateEnums::EXECUTABLE: {
+ auto const win32 =
+ this->GeneratorTarget->GetSafeProperty("WIN32_EXECUTABLE");
+ if (win32.find("$<") != std::string::npos) {
+ this->Makefile->IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmStrCat("Target \"", this->GeneratorTarget->GetName(),
+ "\" has a generator expression in its WIN32_EXECUTABLE "
+ "property. This is not supported on managed "
+ "executables."));
+ return;
+ }
+ outputType = "Exe";
+ } break;
+ case cmStateEnums::UTILITY:
+ case cmStateEnums::INTERFACE_LIBRARY:
+ case cmStateEnums::GLOBAL_TARGET:
+ outputType = "Utility";
+ break;
+ case cmStateEnums::UNKNOWN_LIBRARY:
+ break;
+ }
+ e1.Element("OutputType", outputType);
+ }
+
+ this->WriteDotNetDocumentationFile(e0);
+ this->WriteAllSources(e0);
+ this->WritePackageReferences(e0);
+ this->WriteProjectReferences(e0);
+}
+
+void cmVisualStudio10TargetGenerator::WriteCommonPropertyGroupGlobals(Elem& e1)
+{
+ e1.Attribute("Label", "Globals");
+ e1.Element("ProjectGuid", "{" + this->GUID + "}");
+
+ cmValue vsProjectTypes =
+ this->GeneratorTarget->GetProperty("VS_GLOBAL_PROJECT_TYPES");
+ if (vsProjectTypes) {
+ const char* tagName = "ProjectTypes";
+ if (this->ProjectType == VsProjectType::csproj) {
+ tagName = "ProjectTypeGuids";
+ }
+ e1.Element(tagName, *vsProjectTypes);
+ }
+
+ cmValue vsGlobalKeyword =
+ this->GeneratorTarget->GetProperty("VS_GLOBAL_KEYWORD");
+ if (!vsGlobalKeyword) {
+ if (this->GlobalGenerator->TargetsAndroid()) {
+ e1.Element("Keyword", "Android");
+ } else {
+ e1.Element("Keyword", "Win32Proj");
+ }
+ } else {
+ e1.Element("Keyword", *vsGlobalKeyword);
+ }
+
+ cmValue vsGlobalRootNamespace =
+ this->GeneratorTarget->GetProperty("VS_GLOBAL_ROOTNAMESPACE");
+ if (vsGlobalRootNamespace) {
+ e1.Element("RootNamespace", *vsGlobalRootNamespace);
+ }
+
+ std::vector<std::string> keys = this->GeneratorTarget->GetPropertyKeys();
+ for (std::string const& keyIt : keys) {
+ static const cm::string_view prefix = "VS_GLOBAL_";
+ if (!cmHasPrefix(keyIt, prefix))
+ continue;
+ cm::string_view globalKey = cm::string_view(keyIt).substr(prefix.length());
+ // Skip invalid or separately-handled properties.
+ if (globalKey.empty() || globalKey == "PROJECT_TYPES" ||
+ globalKey == "ROOTNAMESPACE" || globalKey == "KEYWORD") {
+ continue;
+ }
+ cmValue value = this->GeneratorTarget->GetProperty(keyIt);
+ if (!value)
+ continue;
+ e1.Element(globalKey, *value);
+ }
+}
+
+bool cmVisualStudio10TargetGenerator::HasCustomCommands() const
+{
+ if (!this->GeneratorTarget->GetPreBuildCommands().empty() ||
+ !this->GeneratorTarget->GetPreLinkCommands().empty() ||
+ !this->GeneratorTarget->GetPostBuildCommands().empty()) {
+ return true;
+ }
+
+ for (cmGeneratorTarget::AllConfigSource const& si :
+ this->GeneratorTarget->GetAllConfigSources()) {
+ if (si.Source->GetCustomCommand()) {
+ return true;
+ }
+ }
+
+ return false;
}
void cmVisualStudio10TargetGenerator::WritePackageReferences(Elem& e0)
diff --git a/Source/cmVisualStudio10TargetGenerator.h b/Source/cmVisualStudio10TargetGenerator.h
index ec6362f..37b8dfd 100644
--- a/Source/cmVisualStudio10TargetGenerator.h
+++ b/Source/cmVisualStudio10TargetGenerator.h
@@ -18,6 +18,7 @@
class cmComputeLinkInformation;
class cmCustomCommand;
class cmCustomCommandGenerator;
+class cmGeneratedFileStream;
class cmGlobalVisualStudio10Generator;
class cmLocalVisualStudio10Generator;
class cmMakefile;
@@ -260,6 +261,15 @@
void ClassifyAllConfigSources();
void ClassifyAllConfigSource(cmGeneratorTarget::AllConfigSource const& acs);
+ // .Net SDK-stype project variable and helper functions
+ void WriteClassicMsBuildProjectFile(cmGeneratedFileStream& BuildFileStream);
+ void WriteSdkStyleProjectFile(cmGeneratedFileStream& BuildFileStream);
+
+ void WriteCommonPropertyGroupGlobals(
+ cmVisualStudio10TargetGenerator::Elem& e1);
+
+ bool HasCustomCommands() const;
+
std::unordered_map<std::string, ConfigToSettings> ParsedToolTargetSettings;
bool PropertyIsSameInAllConfigs(const ConfigToSettings& toolSettings,
const std::string& propName);
diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt
index 5dc7031..f0457a8 100644
--- a/Tests/RunCMake/CMakeLists.txt
+++ b/Tests/RunCMake/CMakeLists.txt
@@ -94,7 +94,6 @@
add_RunCMake_test(CMP0022)
add_RunCMake_test(CMP0026)
add_RunCMake_test(CMP0027)
-add_RunCMake_test(CMP0028)
add_RunCMake_test(CMP0037)
add_RunCMake_test(CMP0038)
add_RunCMake_test(CMP0039)
@@ -329,6 +328,7 @@
add_RunCMake_test(Graphviz)
add_RunCMake_test(TargetPropertyGeneratorExpressions)
add_RunCMake_test(Languages)
+add_RunCMake_test(LinkItemValidation)
add_RunCMake_test(LinkStatic)
if(CMAKE_CXX_COMPILER_ID MATCHES "^(Cray|PGI|NVHPC|XL|XLClang|Fujitsu|FujitsuClang)$")
add_RunCMake_test(MetaCompileFeatures)
@@ -616,6 +616,10 @@
endif()
endif()
+if(CMAKE_GENERATOR MATCHES "^Visual Studio (1[6-9]|[2-9][0-9])")
+ add_RunCMake_test(VsDotnetSdk)
+endif()
+
if(XCODE_VERSION)
add_RunCMake_test(XcodeProject -DXCODE_VERSION=${XCODE_VERSION})
add_RunCMake_test(XcodeProject-Embed -DXCODE_VERSION=${XCODE_VERSION})
diff --git a/Tests/RunCMake/CMP0028/CMP0028-NEW-iface-result.txt b/Tests/RunCMake/LinkItemValidation/CMP0028-NEW-iface-result.txt
similarity index 100%
rename from Tests/RunCMake/CMP0028/CMP0028-NEW-iface-result.txt
rename to Tests/RunCMake/LinkItemValidation/CMP0028-NEW-iface-result.txt
diff --git a/Tests/RunCMake/CMP0028/CMP0028-NEW-iface-stderr.txt b/Tests/RunCMake/LinkItemValidation/CMP0028-NEW-iface-stderr.txt
similarity index 100%
rename from Tests/RunCMake/CMP0028/CMP0028-NEW-iface-stderr.txt
rename to Tests/RunCMake/LinkItemValidation/CMP0028-NEW-iface-stderr.txt
diff --git a/Tests/RunCMake/CMP0028/CMP0028-NEW-iface.cmake b/Tests/RunCMake/LinkItemValidation/CMP0028-NEW-iface.cmake
similarity index 100%
rename from Tests/RunCMake/CMP0028/CMP0028-NEW-iface.cmake
rename to Tests/RunCMake/LinkItemValidation/CMP0028-NEW-iface.cmake
diff --git a/Tests/RunCMake/CMP0028/CMP0028-NEW-result.txt b/Tests/RunCMake/LinkItemValidation/CMP0028-NEW-result.txt
similarity index 100%
rename from Tests/RunCMake/CMP0028/CMP0028-NEW-result.txt
rename to Tests/RunCMake/LinkItemValidation/CMP0028-NEW-result.txt
diff --git a/Tests/RunCMake/CMP0028/CMP0028-NEW-stderr.txt b/Tests/RunCMake/LinkItemValidation/CMP0028-NEW-stderr.txt
similarity index 100%
rename from Tests/RunCMake/CMP0028/CMP0028-NEW-stderr.txt
rename to Tests/RunCMake/LinkItemValidation/CMP0028-NEW-stderr.txt
diff --git a/Tests/RunCMake/CMP0028/CMP0028-NEW.cmake b/Tests/RunCMake/LinkItemValidation/CMP0028-NEW.cmake
similarity index 100%
rename from Tests/RunCMake/CMP0028/CMP0028-NEW.cmake
rename to Tests/RunCMake/LinkItemValidation/CMP0028-NEW.cmake
diff --git a/Tests/RunCMake/CMP0028/CMP0028-OLD-iface-result.txt b/Tests/RunCMake/LinkItemValidation/CMP0028-OLD-iface-result.txt
similarity index 100%
rename from Tests/RunCMake/CMP0028/CMP0028-OLD-iface-result.txt
rename to Tests/RunCMake/LinkItemValidation/CMP0028-OLD-iface-result.txt
diff --git a/Tests/RunCMake/CMP0028/CMP0028-OLD-iface-stderr.txt b/Tests/RunCMake/LinkItemValidation/CMP0028-OLD-iface-stderr.txt
similarity index 100%
rename from Tests/RunCMake/CMP0028/CMP0028-OLD-iface-stderr.txt
rename to Tests/RunCMake/LinkItemValidation/CMP0028-OLD-iface-stderr.txt
diff --git a/Tests/RunCMake/CMP0028/CMP0028-OLD-iface.cmake b/Tests/RunCMake/LinkItemValidation/CMP0028-OLD-iface.cmake
similarity index 100%
rename from Tests/RunCMake/CMP0028/CMP0028-OLD-iface.cmake
rename to Tests/RunCMake/LinkItemValidation/CMP0028-OLD-iface.cmake
diff --git a/Tests/RunCMake/CMP0028/CMP0028-OLD-result.txt b/Tests/RunCMake/LinkItemValidation/CMP0028-OLD-result.txt
similarity index 100%
rename from Tests/RunCMake/CMP0028/CMP0028-OLD-result.txt
rename to Tests/RunCMake/LinkItemValidation/CMP0028-OLD-result.txt
diff --git a/Tests/RunCMake/CMP0028/CMP0028-OLD-stderr.txt b/Tests/RunCMake/LinkItemValidation/CMP0028-OLD-stderr.txt
similarity index 100%
rename from Tests/RunCMake/CMP0028/CMP0028-OLD-stderr.txt
rename to Tests/RunCMake/LinkItemValidation/CMP0028-OLD-stderr.txt
diff --git a/Tests/RunCMake/CMP0028/CMP0028-OLD.cmake b/Tests/RunCMake/LinkItemValidation/CMP0028-OLD.cmake
similarity index 100%
rename from Tests/RunCMake/CMP0028/CMP0028-OLD.cmake
rename to Tests/RunCMake/LinkItemValidation/CMP0028-OLD.cmake
diff --git a/Tests/RunCMake/CMP0028/CMP0028-WARN-iface-result.txt b/Tests/RunCMake/LinkItemValidation/CMP0028-WARN-iface-result.txt
similarity index 100%
rename from Tests/RunCMake/CMP0028/CMP0028-WARN-iface-result.txt
rename to Tests/RunCMake/LinkItemValidation/CMP0028-WARN-iface-result.txt
diff --git a/Tests/RunCMake/CMP0028/CMP0028-WARN-iface-stderr.txt b/Tests/RunCMake/LinkItemValidation/CMP0028-WARN-iface-stderr.txt
similarity index 100%
rename from Tests/RunCMake/CMP0028/CMP0028-WARN-iface-stderr.txt
rename to Tests/RunCMake/LinkItemValidation/CMP0028-WARN-iface-stderr.txt
diff --git a/Tests/RunCMake/CMP0028/CMP0028-WARN-iface.cmake b/Tests/RunCMake/LinkItemValidation/CMP0028-WARN-iface.cmake
similarity index 100%
rename from Tests/RunCMake/CMP0028/CMP0028-WARN-iface.cmake
rename to Tests/RunCMake/LinkItemValidation/CMP0028-WARN-iface.cmake
diff --git a/Tests/RunCMake/CMP0028/CMP0028-WARN-result.txt b/Tests/RunCMake/LinkItemValidation/CMP0028-WARN-result.txt
similarity index 100%
rename from Tests/RunCMake/CMP0028/CMP0028-WARN-result.txt
rename to Tests/RunCMake/LinkItemValidation/CMP0028-WARN-result.txt
diff --git a/Tests/RunCMake/CMP0028/CMP0028-WARN-stderr.txt b/Tests/RunCMake/LinkItemValidation/CMP0028-WARN-stderr.txt
similarity index 100%
rename from Tests/RunCMake/CMP0028/CMP0028-WARN-stderr.txt
rename to Tests/RunCMake/LinkItemValidation/CMP0028-WARN-stderr.txt
diff --git a/Tests/RunCMake/CMP0028/CMP0028-WARN.cmake b/Tests/RunCMake/LinkItemValidation/CMP0028-WARN.cmake
similarity index 100%
rename from Tests/RunCMake/CMP0028/CMP0028-WARN.cmake
rename to Tests/RunCMake/LinkItemValidation/CMP0028-WARN.cmake
diff --git a/Tests/RunCMake/CMP0028/CMakeLists.txt b/Tests/RunCMake/LinkItemValidation/CMakeLists.txt
similarity index 62%
rename from Tests/RunCMake/CMP0028/CMakeLists.txt
rename to Tests/RunCMake/LinkItemValidation/CMakeLists.txt
index 4f867df..185cd91 100644
--- a/Tests/RunCMake/CMP0028/CMakeLists.txt
+++ b/Tests/RunCMake/LinkItemValidation/CMakeLists.txt
@@ -1,3 +1,6 @@
cmake_minimum_required(VERSION 2.8.12)
+if(NOT RunCMake_TEST MATCHES "^CMP0028")
+ cmake_minimum_required(VERSION 3.22)
+endif()
project(${RunCMake_TEST} CXX)
include(${RunCMake_TEST}.cmake NO_POLICY_SCOPE) # policy used at end of dir
diff --git a/Tests/RunCMake/CMP0028/CMP0028-NEW-result.txt b/Tests/RunCMake/LinkItemValidation/OnlyTargets-result.txt
similarity index 100%
copy from Tests/RunCMake/CMP0028/CMP0028-NEW-result.txt
copy to Tests/RunCMake/LinkItemValidation/OnlyTargets-result.txt
diff --git a/Tests/RunCMake/LinkItemValidation/OnlyTargets-stderr.txt b/Tests/RunCMake/LinkItemValidation/OnlyTargets-stderr.txt
new file mode 100644
index 0000000..bbb0170
--- /dev/null
+++ b/Tests/RunCMake/LinkItemValidation/OnlyTargets-stderr.txt
@@ -0,0 +1,40 @@
+^CMake Error at OnlyTargets\.cmake:11 \(target_link_libraries\):
+ Target "exe" has LINK_LIBRARIES_ONLY_TARGETS enabled, but it links to:
+
+ non_target_in_exe
+
+ which is not a target\. Possible reasons include:
+(
+ \*[^
+]+)*
+
+Call Stack \(most recent call first\):
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at OnlyTargets\.cmake:21 \(target_link_libraries\):
+ Target "iface" has LINK_LIBRARIES_ONLY_TARGETS enabled, but its link
+ interface contains:
+
+ non_target_in_iface
+
+ which is not a target\. Possible reasons include:
+(
+ \*[^
+]+)*
+
+Call Stack \(most recent call first\):
+ CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at OnlyTargets\.cmake:30 \(target_link_libraries\):
+ Target "iface_imported_checked" has LINK_LIBRARIES_ONLY_TARGETS enabled,
+ but its link interface contains:
+
+ non_target_in_iface_imported_checked
+
+ which is not a target\. Possible reasons include:
+(
+ \*[^
+]+)*
+
+Call Stack \(most recent call first\):
+ CMakeLists\.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/LinkItemValidation/OnlyTargets.cmake b/Tests/RunCMake/LinkItemValidation/OnlyTargets.cmake
new file mode 100644
index 0000000..9417318
--- /dev/null
+++ b/Tests/RunCMake/LinkItemValidation/OnlyTargets.cmake
@@ -0,0 +1,56 @@
+enable_language(C)
+
+set(CMAKE_LINK_LIBRARIES_ONLY_TARGETS 1)
+
+# Use imported interface library to name toolchain-provided libraries.
+add_library(toolchain::m INTERFACE IMPORTED)
+set_property(TARGET toolchain::m PROPERTY IMPORTED_LIBNAME "m")
+
+# Linking directly warns.
+add_executable(exe main.c)
+target_link_libraries(exe PRIVATE
+ -lflag_in_exe # accepted
+ /abs/path/in_exe # accepted
+ rel/path/in_exe # accepted
+ toolchain::m # accepted
+ non_target_in_exe # rejected
+ )
+
+# Link interfaces warn.
+add_library(iface INTERFACE)
+target_link_libraries(iface INTERFACE
+ -lflag_in_iface # accepted
+ /abs/path/in_iface # accepted
+ rel/path/in_iface # accepted
+ non_target_in_iface # rejected
+ )
+
+# Imported target link interfaces warn if explicitly enabled.
+add_library(iface_imported_checked INTERFACE IMPORTED)
+target_link_libraries(iface_imported_checked INTERFACE
+ -lflag_iface_imported_checked # accepted
+ /abs/path/in_iface_imported_checked # accepted
+ rel/path/in_iface_imported_checked # accepted
+ non_target_in_iface_imported_checked # rejected
+ )
+set_property(TARGET iface_imported_checked PROPERTY LINK_LIBRARIES_ONLY_TARGETS 1)
+
+# Linking directly does not warn if explicitly disabled.
+add_executable(exe_not_checked main.c)
+target_link_libraries(exe_not_checked PRIVATE
+ non_target_in_exe_not_checked
+ )
+set_property(TARGET exe_not_checked PROPERTY LINK_LIBRARIES_ONLY_TARGETS 0)
+
+# Link interfaces do not warn if explicitly disabled.
+add_library(iface_not_checked INTERFACE)
+target_link_libraries(iface_not_checked INTERFACE
+ non_target_in_iface_not_checked
+ )
+set_property(TARGET iface_not_checked PROPERTY LINK_LIBRARIES_ONLY_TARGETS 0)
+
+# Imported target link interfaces do not warn if not explicitly enabled.
+add_library(iface_imported_default INTERFACE IMPORTED)
+target_link_libraries(iface_imported_default INTERFACE
+ non_target_in_iface_imported_default
+ )
diff --git a/Tests/RunCMake/CMP0028/RunCMakeTest.cmake b/Tests/RunCMake/LinkItemValidation/RunCMakeTest.cmake
similarity index 87%
rename from Tests/RunCMake/CMP0028/RunCMakeTest.cmake
rename to Tests/RunCMake/LinkItemValidation/RunCMakeTest.cmake
index 0c72ca2..c423f6a 100644
--- a/Tests/RunCMake/CMP0028/RunCMakeTest.cmake
+++ b/Tests/RunCMake/LinkItemValidation/RunCMakeTest.cmake
@@ -6,3 +6,5 @@
run_cmake(CMP0028-NEW-iface)
run_cmake(CMP0028-OLD-iface)
run_cmake(CMP0028-WARN-iface)
+
+run_cmake(OnlyTargets)
diff --git a/Tests/RunCMake/CMP0028/empty.cpp b/Tests/RunCMake/LinkItemValidation/empty.cpp
similarity index 100%
rename from Tests/RunCMake/CMP0028/empty.cpp
rename to Tests/RunCMake/LinkItemValidation/empty.cpp
diff --git a/Tests/RunCMake/LinkItemValidation/main.c b/Tests/RunCMake/LinkItemValidation/main.c
new file mode 100644
index 0000000..8488f4e
--- /dev/null
+++ b/Tests/RunCMake/LinkItemValidation/main.c
@@ -0,0 +1,4 @@
+int main(void)
+{
+ return 0;
+}
diff --git a/Tests/RunCMake/VsDotnetSdk/CMakeLists.txt b/Tests/RunCMake/VsDotnetSdk/CMakeLists.txt
new file mode 100644
index 0000000..e597708
--- /dev/null
+++ b/Tests/RunCMake/VsDotnetSdk/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.22.0)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/VsDotnetSdk/DotnetSdkVariables-check.cmake b/Tests/RunCMake/VsDotnetSdk/DotnetSdkVariables-check.cmake
new file mode 100644
index 0000000..7a5cd1d
--- /dev/null
+++ b/Tests/RunCMake/VsDotnetSdk/DotnetSdkVariables-check.cmake
@@ -0,0 +1,52 @@
+set(files foo.csproj bar.csproj baz.csproj)
+
+set(inLib1 FALSE)
+set(dotnetSdkInLib1 FALSE)
+
+set(inLib2 FALSE)
+set(dotnetSdkWebInLib2 FALSE)
+
+set(inLib3 FALSE)
+set(classicProjInLib3 FALSE)
+
+foreach(file ${files})
+ set(csProjectFile ${RunCMake_TEST_BINARY_DIR}/${file})
+
+ if(NOT EXISTS "${csProjectFile}")
+ set(RunCMake_TEST_FAILED "Project file ${csProjectFile} does not exist.")
+ return()
+ endif()
+
+ file(STRINGS "${csProjectFile}" lines)
+
+ foreach(line IN LISTS lines)
+ if(NOT inLib1)
+ if(line MATCHES "<Project Sdk=\"Microsoft\.NET\.Sdk\">")
+ set(dotnetSdkInLib1 TRUE)
+ set(inLib1 TRUE)
+ endif()
+ elseif(NOT inLib2)
+ if(line MATCHES "<Project Sdk=\"Microsoft\.NET\.Sdk\.Web\">")
+ set(dotnetSdkWebInLib2 TRUE)
+ set(inLib2 TRUE)
+ endif()
+ elseif(NOT inLib3)
+ if(line MATCHES "<Project DefaultTargets=\"Build\" ToolsVersion=\"")
+ set(classicProjInLib3 TRUE)
+ set(inLib3 TRUE)
+ endif()
+ endif()
+ endforeach()
+endforeach()
+
+if(NOT dotnetSdkInLib1)
+ set(RunCMake_TEST_FAILED ".Net SDK not set correctly.")
+endif()
+
+if(NOT dotnetSdkWebInLib2)
+ set(RunCMake_TEST_FAILED ".Net Web SDK not set correctly.")
+endif()
+
+if(NOT classicProjInLib3)
+ set(RunCMake_TEST_FAILED "Empty DOTNET_SDK doesn't build Classic project.")
+endif()
diff --git a/Tests/RunCMake/VsDotnetSdk/DotnetSdkVariables.cmake b/Tests/RunCMake/VsDotnetSdk/DotnetSdkVariables.cmake
new file mode 100644
index 0000000..f080edd
--- /dev/null
+++ b/Tests/RunCMake/VsDotnetSdk/DotnetSdkVariables.cmake
@@ -0,0 +1,14 @@
+enable_language(CSharp)
+
+if(NOT CMAKE_CSharp_COMPILER)
+ return()
+endif()
+
+set(CMAKE_DOTNET_SDK "Microsoft.NET.Sdk")
+add_library(foo SHARED lib1.cs)
+
+set(CMAKE_DOTNET_SDK "Microsoft.NET.Sdk.Web")
+add_library(bar SHARED lib1.cs)
+
+set(CMAKE_DOTNET_SDK "")
+add_library(baz SHARED lib1.cs)
diff --git a/Tests/RunCMake/VsDotnetSdk/RunCMakeTest.cmake b/Tests/RunCMake/VsDotnetSdk/RunCMakeTest.cmake
new file mode 100644
index 0000000..b174c25
--- /dev/null
+++ b/Tests/RunCMake/VsDotnetSdk/RunCMakeTest.cmake
@@ -0,0 +1,17 @@
+cmake_policy(SET CMP0053 NEW)
+include(RunCMake)
+
+run_cmake(VsDotnetSdkCustomCommandsTarget)
+run_cmake(VsDotnetSdkCustomCommandsSource)
+run_cmake(DotnetSdkVariables)
+
+function(run_VsDotnetSdk)
+ set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/VsDotnetSdk-build)
+ set(RunCMake_TEST_NO_CLEAN 1)
+ file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
+ file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
+ run_cmake(VsDotnetSdk)
+ set(build_flags /restore)
+ run_cmake_command(VsDotnetSdk-build ${CMAKE_COMMAND} --build . -- ${build_flags})
+endfunction()
+run_VsDotnetSdk()
diff --git a/Tests/RunCMake/VsDotnetSdk/VsDotnetSdk.cmake b/Tests/RunCMake/VsDotnetSdk/VsDotnetSdk.cmake
new file mode 100644
index 0000000..60066ab
--- /dev/null
+++ b/Tests/RunCMake/VsDotnetSdk/VsDotnetSdk.cmake
@@ -0,0 +1,18 @@
+cmake_minimum_required(VERSION 3.22)
+
+# a simple CSharp only test case
+project (DotNetSdk CSharp)
+
+set(CMAKE_DOTNET_TARGET_FRAMEWORK net472)
+set(CMAKE_DOTNET_SDK "Microsoft.NET.Sdk")
+
+add_library(dotNetSdkLib1 SHARED lib1.cs)
+set_target_properties(dotNetSdkLib1
+ PROPERTIES
+ VS_GLOBAL_RuntimeIdentifier win10-x64)
+
+add_executable(DotNetSdk csharponly.cs)
+target_link_libraries(DotNetSdk dotNetSdkLib1)
+set_target_properties(DotNetSdk
+ PROPERTIES
+ VS_GLOBAL_RuntimeIdentifier win10-x64)
diff --git a/Tests/RunCMake/CMP0028/empty.cpp b/Tests/RunCMake/VsDotnetSdk/VsDotnetSdkCustomCommandsSource-result.txt
similarity index 100%
copy from Tests/RunCMake/CMP0028/empty.cpp
copy to Tests/RunCMake/VsDotnetSdk/VsDotnetSdkCustomCommandsSource-result.txt
diff --git a/Tests/RunCMake/VsDotnetSdk/VsDotnetSdkCustomCommandsSource-stderr.txt b/Tests/RunCMake/VsDotnetSdk/VsDotnetSdkCustomCommandsSource-stderr.txt
new file mode 100644
index 0000000..90af627
--- /dev/null
+++ b/Tests/RunCMake/VsDotnetSdk/VsDotnetSdkCustomCommandsSource-stderr.txt
@@ -0,0 +1,7 @@
+CMake Error in CMakeLists.txt:
+ The target "foo" does not currently support add_custom_command as the
+ Visual Studio generators have not yet learned how to generate custom
+ commands in .Net SDK-style projects.
+
+
+CMake Generate step failed. Build files cannot be regenerated correctly.
diff --git a/Tests/RunCMake/VsDotnetSdk/VsDotnetSdkCustomCommandsSource.cmake b/Tests/RunCMake/VsDotnetSdk/VsDotnetSdkCustomCommandsSource.cmake
new file mode 100644
index 0000000..af18946
--- /dev/null
+++ b/Tests/RunCMake/VsDotnetSdk/VsDotnetSdkCustomCommandsSource.cmake
@@ -0,0 +1,15 @@
+enable_language(CSharp)
+
+if(NOT CMAKE_CSharp_COMPILER)
+ return()
+endif()
+
+set(CMAKE_DOTNET_SDK "Microsoft.NET.Sdk")
+add_custom_command(
+ OUTPUT bar.cs
+ COMMAND copy /A ${CMAKE_CURRENT_SOURCE_DIR}/lib1.cs
+ bar.cs
+ DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/lib1.cs
+ VERBATIM)
+
+add_library(foo SHARED bar.cs)
diff --git a/Tests/RunCMake/CMP0028/empty.cpp b/Tests/RunCMake/VsDotnetSdk/VsDotnetSdkCustomCommandsTarget-result.txt
similarity index 100%
copy from Tests/RunCMake/CMP0028/empty.cpp
copy to Tests/RunCMake/VsDotnetSdk/VsDotnetSdkCustomCommandsTarget-result.txt
diff --git a/Tests/RunCMake/VsDotnetSdk/VsDotnetSdkCustomCommandsTarget-stderr.txt b/Tests/RunCMake/VsDotnetSdk/VsDotnetSdkCustomCommandsTarget-stderr.txt
new file mode 100644
index 0000000..90af627
--- /dev/null
+++ b/Tests/RunCMake/VsDotnetSdk/VsDotnetSdkCustomCommandsTarget-stderr.txt
@@ -0,0 +1,7 @@
+CMake Error in CMakeLists.txt:
+ The target "foo" does not currently support add_custom_command as the
+ Visual Studio generators have not yet learned how to generate custom
+ commands in .Net SDK-style projects.
+
+
+CMake Generate step failed. Build files cannot be regenerated correctly.
diff --git a/Tests/RunCMake/VsDotnetSdk/VsDotnetSdkCustomCommandsTarget.cmake b/Tests/RunCMake/VsDotnetSdk/VsDotnetSdkCustomCommandsTarget.cmake
new file mode 100644
index 0000000..f5cd317
--- /dev/null
+++ b/Tests/RunCMake/VsDotnetSdk/VsDotnetSdkCustomCommandsTarget.cmake
@@ -0,0 +1,12 @@
+enable_language(CSharp)
+
+if(NOT CMAKE_CSharp_COMPILER)
+ return()
+endif()
+
+set(CMAKE_DOTNET_SDK "Microsoft.NET.Sdk")
+add_library(foo SHARED lib1.cs)
+add_custom_command(TARGET foo
+ PRE_BUILD
+ COMMAND echo "This shouldn't happen!"
+ VERBATIM)
diff --git a/Tests/RunCMake/VsDotnetSdk/csharponly.cs b/Tests/RunCMake/VsDotnetSdk/csharponly.cs
new file mode 100644
index 0000000..f02e8a3
--- /dev/null
+++ b/Tests/RunCMake/VsDotnetSdk/csharponly.cs
@@ -0,0 +1,11 @@
+namespace CSharpOnly
+{
+ class CSharpOnly
+ {
+ public static void Main(string[] args)
+ {
+ int val = Lib1.getResult();
+ return;
+ }
+ }
+}
diff --git a/Tests/RunCMake/VsDotnetSdk/lib1.cs b/Tests/RunCMake/VsDotnetSdk/lib1.cs
new file mode 100644
index 0000000..7a7ae10
--- /dev/null
+++ b/Tests/RunCMake/VsDotnetSdk/lib1.cs
@@ -0,0 +1,10 @@
+namespace CSharpOnly
+{
+ public class Lib1
+ {
+ public static int getResult()
+ {
+ return 23;
+ }
+ }
+}
diff --git a/Tests/RunCMake/list/LIST-nonexistent.cmake b/Tests/RunCMake/list/LIST-nonexistent.cmake
new file mode 100644
index 0000000..ee88548
--- /dev/null
+++ b/Tests/RunCMake/list/LIST-nonexistent.cmake
@@ -0,0 +1,45 @@
+# Various list operations should treat non-existent variables as empty
+# - APPEND
+# - PREPEND
+# - INSERT (only valid index is 0)
+set(nex_l0 "")
+list(APPEND nex_l0 a)
+list(APPEND nex_l0 b)
+if(NOT nex_l0 STREQUAL "a;b")
+ message(FATAL_ERROR "a;b expected, got ${nex_l0}")
+endif()
+
+unset(nex_l1)
+list(APPEND nex_l1 c)
+list(APPEND nex_l1 d)
+if(NOT nex_l1 STREQUAL "c;d")
+ message(FATAL_ERROR "c;d expected, got ${nex_l1}")
+endif()
+
+set(nex_l2 "")
+list(PREPEND nex_l2 E)
+list(PREPEND nex_l2 f)
+if(NOT nex_l2 STREQUAL "f;E")
+ message(FATAL_ERROR "f;E expected, got ${nex_l2}")
+endif()
+
+unset(nex_l3)
+list(PREPEND nex_l3 hi)
+list(PREPEND nex_l3 G)
+if(NOT nex_l3 STREQUAL "G;hi")
+ message(FATAL_ERROR "G;hi expected, got ${nex_l3}")
+endif()
+
+set(nex_l4 "")
+list(INSERT nex_l4 0 j)
+list(INSERT nex_l4 0 kl)
+if(NOT nex_l4 STREQUAL "kl;j")
+ message(FATAL_ERROR "kl;j expected, got ${nex_l4}")
+endif()
+
+unset(nex_l5)
+list(INSERT nex_l5 0 M)
+list(INSERT nex_l5 0 noP)
+if(NOT nex_l5 STREQUAL "noP;M")
+ message(FATAL_ERROR "noP;M expected, got ${nex_l5}")
+endif()
diff --git a/Tests/RunCMake/list/RunCMakeTest.cmake b/Tests/RunCMake/list/RunCMakeTest.cmake
index eb43ee0..adfe255 100644
--- a/Tests/RunCMake/list/RunCMakeTest.cmake
+++ b/Tests/RunCMake/list/RunCMakeTest.cmake
@@ -116,3 +116,6 @@
# Successful tests
run_cmake(POP_BACK)
run_cmake(POP_FRONT)
+
+# Nonexistent variables treated as empty
+run_cmake(LIST-nonexistent)