diff options
36 files changed, 312 insertions, 91 deletions
@@ -1,27 +1,30 @@ +/CMakeUserPresets.json + # Common build directories -build*/ +/build*/ -# Exclude MacOS Finder files. +# MacOS Finder files. .DS_Store -*.user* - +# Python compile output. *.pyc -Help/_generated -Testing -CMakeUserPresets.json +# See Utilities/Sphinx/tutorial_archive.cmake +/Help/_generated -# Visual Studio work directory -.vs/ -# Visual Studio build directory -out/ +# CLion work directory +/.idea/ +# CLion build directories +/cmake-build-*/ + +# QtCreator files. +/CMakeLists.txt.user* # Visual Studio Code -.vscode/ -.cache/ +/.vscode/ +/.cache/ -# CLion work directory -.idea/ -# CLion build directories -cmake-build-*/ +# Visual Studio work directory +/.vs/ +# Visual Studio build directory +/out/ diff --git a/Help/command/UNSET_NOTE.txt b/Help/command/UNSET_NOTE.txt new file mode 100644 index 0000000..8dc9125 --- /dev/null +++ b/Help/command/UNSET_NOTE.txt @@ -0,0 +1,9 @@ +.. note:: + + When evaluating :ref:`Variable References` of the form ``${VAR}``, CMake + first searches for a normal variable with that name. If no such normal + variable exists, CMake will then search for a cache entry with that name. + Because of this, **unsetting a normal variable can expose a cache variable + that was previously hidden**. To force a variable reference of the form + ``${VAR}`` to return an empty string, use ``set(<variable> "")``, which + clears the normal variable but leaves it defined. diff --git a/Help/command/file.rst b/Help/command/file.rst index 25b762c..30a7f4d 100644 --- a/Help/command/file.rst +++ b/Help/command/file.rst @@ -341,12 +341,13 @@ Reading On Windows platforms, library resolution works as follows: - 1. The dependent DLL name is converted to lowercase. Windows DLL names are - case-insensitive, and some linkers mangle the case of the DLL dependency - names. However, this makes it more difficult for ``PRE_INCLUDE_REGEXES``, - ``PRE_EXCLUDE_REGEXES``, ``POST_INCLUDE_REGEXES``, and - ``POST_EXCLUDE_REGEXES`` to properly filter DLL names - every regex would - have to check for both uppercase and lowercase letters. For example: + 1. DLL dependency names are converted to lowercase for matching filters. + Windows DLL names are case-insensitive, and some linkers mangle the + case of the DLL dependency names. However, this makes it more difficult + for ``PRE_INCLUDE_REGEXES``, ``PRE_EXCLUDE_REGEXES``, + ``POST_INCLUDE_REGEXES``, and ``POST_EXCLUDE_REGEXES`` to properly + filter DLL names - every regex would have to check for both uppercase + and lowercase letters. For example: .. code-block:: cmake @@ -369,9 +370,15 @@ Reading either on disk or in the depending file. (For example, it will match ``mylibrary.dll``, ``MyLibrary.dll``, and ``MYLIBRARY.DLL``.) - Please note that the directory portion of any resolved DLLs retains its - casing and is not converted to lowercase. Only the filename portion is - converted. + .. versionchanged:: 3.27 + + The conversion to lowercase only applies while matching filters. + Results reported after filtering case-preserve each DLL name as it is + found on disk, if resolved, and otherwise as it is referenced by the + dependent binary. + + Prior to CMake 3.27, the results were reported with lowercase DLL + file names, but the directory portion retained its casing. 2. (**Not yet implemented**) If the depending file is a Windows Store app, and the dependency is listed as a dependency in the application's package diff --git a/Help/command/set.rst b/Help/command/set.rst index ee677c9..aeb88b3 100644 --- a/Help/command/set.rst +++ b/Help/command/set.rst @@ -8,9 +8,8 @@ and cache entries. Signatures of this command that specify a ``<value>...`` placeholder expect zero or more arguments. Multiple arguments will be joined as -a :ref:`semicolon-separated list <CMake Language Lists>` to form the actual variable -value to be set. Zero arguments will cause normal variables to be -unset. See the :command:`unset` command to unset variables explicitly. +a :ref:`semicolon-separated list <CMake Language Lists>` to form the +actual variable value to be set. Set Normal Variable ^^^^^^^^^^^^^^^^^^^ @@ -19,7 +18,11 @@ Set Normal Variable set(<variable> <value>... [PARENT_SCOPE]) :target: normal - Sets the given ``<variable>`` in the current function or directory scope. + Set or unset ``<variable>`` in the current function or directory scope: + + * If at least one ``<value>...`` is given, set the variable to that value. + * If no value is given, unset the variable. This is equivalent to + :command:`unset(<variable>) <unset>`. If the ``PARENT_SCOPE`` option is given the variable will be set in the scope above the current scope. Each new directory or :command:`function` @@ -34,6 +37,8 @@ Set Normal Variable can be used as an alternate method to the :command:`set(PARENT_SCOPE)` and :command:`unset(PARENT_SCOPE)` commands to update the parent scope. +.. include:: UNSET_NOTE.txt + Set Cache Entry ^^^^^^^^^^^^^^^ diff --git a/Help/command/unset.rst b/Help/command/unset.rst index 1cd1398..522be89 100644 --- a/Help/command/unset.rst +++ b/Help/command/unset.rst @@ -12,19 +12,14 @@ Unset Normal Variable or Cache Entry Removes a normal variable from the current scope, causing it to become undefined. If ``CACHE`` is present, then a cache variable -is removed instead of a normal variable. Note that when evaluating -:ref:`Variable References` of the form ``${VAR}``, CMake first searches -for a normal variable with that name. If no such normal variable exists, -CMake will then search for a cache entry with that name. Because of this -unsetting a normal variable can expose a cache variable that was previously -hidden. To force a variable reference of the form ``${VAR}`` to return an -empty string, use ``set(<variable> "")``, which clears the normal variable -but leaves it defined. +is removed instead of a normal variable. If ``PARENT_SCOPE`` is present then the variable is removed from the scope above the current scope. See the same option in the :command:`set` command for further details. +.. include:: UNSET_NOTE.txt + Unset Environment Variable ^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/Help/release/dev/FindPython-Windows-ARM.rst b/Help/release/dev/FindPython-Windows-ARM.rst new file mode 100644 index 0000000..d88a65a --- /dev/null +++ b/Help/release/dev/FindPython-Windows-ARM.rst @@ -0,0 +1,5 @@ +FindPython-Windows-ARM +---------------------- + +* :module:`FindPython`, :module:`FindPython2` and :module:`FindPython3` modules + learn to manage ``Windows/ARM`` platform. diff --git a/Help/release/dev/file-GET_RUNTIME_DEPENDENCIES-windows-casing.rst b/Help/release/dev/file-GET_RUNTIME_DEPENDENCIES-windows-casing.rst new file mode 100644 index 0000000..858f8b3 --- /dev/null +++ b/Help/release/dev/file-GET_RUNTIME_DEPENDENCIES-windows-casing.rst @@ -0,0 +1,7 @@ +file-GET_RUNTIME_DEPENDENCIES-windows-casing +-------------------------------------------- + + +* The :command:`file(GET_RUNTIME_DEPENDENCIES)` command now case-preserves + DLL names reported on Windows. They are still converted to lowercase + for filter matching. diff --git a/Help/variable/CMAKE_CROSSCOMPILING.rst b/Help/variable/CMAKE_CROSSCOMPILING.rst index 7e6ec33..16dbfa5 100644 --- a/Help/variable/CMAKE_CROSSCOMPILING.rst +++ b/Help/variable/CMAKE_CROSSCOMPILING.rst @@ -1,15 +1,15 @@ CMAKE_CROSSCOMPILING -------------------- -Intended to indicate whether CMake is cross compiling, but note limitations -discussed below. +This variable is set by CMake to indicate whether it is cross compiling, +but note limitations discussed below. This variable will be set to true by CMake if the :variable:`CMAKE_SYSTEM_NAME` variable has been set manually (i.e. in a toolchain file or as a cache entry from the :manual:`cmake <cmake(1)>` command line). In most cases, manually -setting :variable:`CMAKE_SYSTEM_NAME` will only be done when cross compiling, -since it will otherwise be given the same value as -:variable:`CMAKE_HOST_SYSTEM_NAME` if not manually set, which is correct for +setting :variable:`CMAKE_SYSTEM_NAME` will only be done when cross compiling +since, if not manually set, it will be given the same value as +:variable:`CMAKE_HOST_SYSTEM_NAME`, which is correct for the non-cross-compiling case. In the event that :variable:`CMAKE_SYSTEM_NAME` is manually set to the same value as :variable:`CMAKE_HOST_SYSTEM_NAME`, then ``CMAKE_CROSSCOMPILING`` will still be set to true. diff --git a/Modules/CMakeDetermineSystem.cmake b/Modules/CMakeDetermineSystem.cmake index d4dcc62..386be73 100644 --- a/Modules/CMakeDetermineSystem.cmake +++ b/Modules/CMakeDetermineSystem.cmake @@ -176,6 +176,13 @@ else() set(CMAKE_SYSTEM_VERSION "${CMAKE_HOST_SYSTEM_VERSION}") endif() set(CMAKE_SYSTEM_PROCESSOR "${CMAKE_HOST_SYSTEM_PROCESSOR}") + if(CMAKE_CROSSCOMPILING) + message(AUTHOR_WARNING + "CMAKE_CROSSCOMPILING has been set by the project, toolchain file, or user. " + "CMake is resetting it to false because CMAKE_SYSTEM_NAME was not set. " + "To indicate cross compilation, only CMAKE_SYSTEM_NAME needs to be set." + ) + endif() set(CMAKE_CROSSCOMPILING FALSE) set(PRESET_CMAKE_SYSTEM_NAME FALSE) endif() diff --git a/Modules/Compiler/IBMClang.cmake b/Modules/Compiler/IBMClang.cmake index a9d760f..169a0f0 100644 --- a/Modules/Compiler/IBMClang.cmake +++ b/Modules/Compiler/IBMClang.cmake @@ -43,7 +43,10 @@ macro(__compiler_ibmclang lang) set(_CMAKE_${lang}_IPO_SUPPORTED_BY_CMAKE YES) set(_CMAKE_${lang}_IPO_MAY_BE_SUPPORTED_BY_COMPILER YES) - set(_CMAKE_LTO_THIN TRUE) + # Thin LTO is not yet supported on AIX. + if(NOT (CMAKE_SYSTEM_NAME STREQUAL "AIX")) + set(_CMAKE_LTO_THIN TRUE) + endif() if(_CMAKE_LTO_THIN) set(CMAKE_${lang}_COMPILE_OPTIONS_IPO "-flto=thin") diff --git a/Modules/FindPython/Support.cmake b/Modules/FindPython/Support.cmake index 517ac21..60d2296 100644 --- a/Modules/FindPython/Support.cmake +++ b/Modules/FindPython/Support.cmake @@ -192,28 +192,25 @@ function (_PYTHON_GET_REGISTRIES _PYTHON_PGR_REGISTRY_PATHS) if (implementation STREQUAL "CPython") foreach (version IN LISTS _PGR_VERSION) string (REPLACE "." "" version_no_dots ${version}) - list (APPEND registries - [HKEY_CURRENT_USER/SOFTWARE/Python/PythonCore/${version}-${_${_PYTHON_PREFIX}_ARCH}/InstallPath] - [HKEY_CURRENT_USER/SOFTWARE/Python/PythonCore/${version}-${_${_PYTHON_PREFIX}_ARCH2}/InstallPath]) + list (TRANSFORM _${_PYTHON_PREFIX}_ARCH REPLACE "^(.+)$" "[HKEY_CURRENT_USER/SOFTWARE/Python/PythonCore/${version}-\\1/InstallPath]" OUTPUT_VARIABLE reg_paths) + list (APPEND registries ${reg_paths}) if (version VERSION_GREATER_EQUAL "3.5") # cmake_host_system_information is not usable in bootstrap get_filename_component (arch "[HKEY_CURRENT_USER\\Software\\Python\\PythonCore\\${version};SysArchitecture]" NAME) - if (arch MATCHES "(${_${_PYTHON_PREFIX}_ARCH}|${_${_PYTHON_PREFIX}_ARCH2})bit") - list (APPEND registries - [HKEY_CURRENT_USER/SOFTWARE/Python/PythonCore/${version}/InstallPath]) + string (REPLACE "bit" "" arch "${arch}") + if (arch IN_LIST _${_PYTHON_PREFIX}_ARCH) + list (APPEND registries [HKEY_CURRENT_USER/SOFTWARE/Python/PythonCore/${version}/InstallPath]) endif() else() - list (APPEND registries - [HKEY_CURRENT_USER/SOFTWARE/Python/PythonCore/${version}/InstallPath]) - endif() - list (APPEND registries - [HKEY_CURRENT_USER/SOFTWARE/Python/ContinuumAnalytics/Anaconda${version_no_dots}-${_${_PYTHON_PREFIX}_ARCH}/InstallPath] - [HKEY_CURRENT_USER/SOFTWARE/Python/ContinuumAnalytics/Anaconda${version_no_dots}-${_${_PYTHON_PREFIX}_ARCH2}/InstallPath] - [HKEY_LOCAL_MACHINE/SOFTWARE/Python/PythonCore/${version}-${_${_PYTHON_PREFIX}_ARCH}/InstallPath] - [HKEY_LOCAL_MACHINE/SOFTWARE/Python/PythonCore/${version}-${_${_PYTHON_PREFIX}_ARCH2}/InstallPath] - [HKEY_LOCAL_MACHINE/SOFTWARE/Python/PythonCore/${version}/InstallPath] - [HKEY_LOCAL_MACHINE/SOFTWARE/Python/ContinuumAnalytics/Anaconda${version_no_dots}-${_${_PYTHON_PREFIX}_ARCH}/InstallPath] - [HKEY_LOCAL_MACHINE/SOFTWARE/Python/ContinuumAnalytics/Anaconda${version_no_dots}-${_${_PYTHON_PREFIX}_ARCH2}/InstallPath]) + list (APPEND registries [HKEY_CURRENT_USER/SOFTWARE/Python/PythonCore/${version}/InstallPath]) + endif() + list (TRANSFORM _${_PYTHON_PREFIX}_ARCH REPLACE "^(.+)$" "[HKEY_CURRENT_USER/SOFTWARE/Python/ContinuumAnalytics/Anaconda${version_no_dots}-\\1/InstallPath]" OUTPUT_VARIABLE reg_paths) + list (APPEND registries ${reg_paths}) + list (TRANSFORM _${_PYTHON_PREFIX}_ARCH REPLACE "^(.+)$" "[HKEY_CURRENT_USER/SOFTWARE/Python/PythonCore/${version}-\\1/InstallPath]" OUTPUT_VARIABLE reg_paths) + list (APPEND registries ${reg_paths}) + list (APPEND registries [HKEY_LOCAL_MACHINE/SOFTWARE/Python/PythonCore/${version}/InstallPath]) + list (TRANSFORM _${_PYTHON_PREFIX}_ARCH REPLACE "^(.+)$" "[HKEY_LOCAL_MACHINE/SOFTWARE/Python/ContinuumAnalytics/Anaconda${version_no_dots}-\\1/InstallPath]" OUTPUT_VARIABLE reg_paths) + list (APPEND registries ${reg_paths}) endforeach() elseif (implementation STREQUAL "IronPython") foreach (version IN LISTS _PGR_VERSION) @@ -927,6 +924,33 @@ function (_PYTHON_VALIDATE_INTERPRETER) set_property (CACHE _${_PYTHON_PREFIX}_EXECUTABLE PROPERTY VALUE "${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND") return() endif() + + if (WIN32) + # In this case, check if the interpreter is compatible with the target processor architecture + if (NOT CMAKE_GENERATOR_PLATFORM AND CMAKE_SYSTEM_PROCESSOR MATCHES "ARM" OR CMAKE_GENERATOR_PLATFORM MATCHES "ARM") + set(target_arm TRUE) + else() + set(target_arm FALSE) + endif() + execute_process (COMMAND ${launcher} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c + "import sys, sysconfig; sys.stdout.write(sysconfig.get_platform())" + RESULT_VARIABLE result + OUTPUT_VARIABLE platform + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) + string(TOUPPER "${platform}" platform) + if (result OR ((target_arm AND NOT platform MATCHES "ARM") OR + (NOT target_arm AND platform MATCHES "ARM"))) + # interpreter not usable or has wrong architecture + if (result) + set_property (CACHE _${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE PROPERTY VALUE "Cannot use the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"") + else() + set_property (CACHE _${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE PROPERTY VALUE "Wrong architecture for the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"") + endif() + set_property (CACHE _${_PYTHON_PREFIX}_EXECUTABLE PROPERTY VALUE "${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND") + return() + endif() + endif() endif() endfunction() @@ -1419,19 +1443,37 @@ if (CMAKE_SIZEOF_VOID_P) OR "Development.SABIModule" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS OR "Development.Embed" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS) # In this case, search only for 64bit or 32bit - set (_${_PYTHON_PREFIX}_ARCH2 ${_${_PYTHON_PREFIX}_ARCH}) set (_${_PYTHON_PREFIX}_REGISTRY_VIEW REGISTRY_VIEW ${_${_PYTHON_PREFIX}_ARCH}) + if (WIN32 AND (NOT CMAKE_GENERATOR_PLATFORM AND CMAKE_SYSTEM_PROCESSOR MATCHES "ARM" + OR CMAKE_GENERATOR_PLATFORM MATCHES "ARM")) + # search exclusively ARM architecture: 64bit or 32bit + if (_${_PYTHON_PREFIX}_ARCH EQUAL 64) + set (_${_PYTHON_PREFIX}_ARCH ARM64) + else() + set (_${_PYTHON_PREFIX}_ARCH ARM) + endif() + endif() else() if (_${_PYTHON_PREFIX}_ARCH EQUAL "32") - set (_${_PYTHON_PREFIX}_ARCH2 64) + if (CMAKE_SYSTEM_PROCESSOR MATCHES "ARM") + # search first ARM architectures: 32bit and then 64bit + list (PREPEND _${_PYTHON_PREFIX}_ARCH ARM ARM64) + endif() + list (APPEND _${_PYTHON_PREFIX}_ARCH 64) else() - set (_${_PYTHON_PREFIX}_ARCH2 32) + if (CMAKE_SYSTEM_PROCESSOR MATCHES "ARM") + # search first ARM architectures: 64bit and then 32bit + list (PREPEND _${_PYTHON_PREFIX}_ARCH ARM64 ARM) + endif() + list (APPEND _${_PYTHON_PREFIX}_ARCH 32) endif() endif() else() # architecture unknown, search for both 64bit and 32bit - set (_${_PYTHON_PREFIX}_ARCH 64) - set (_${_PYTHON_PREFIX}_ARCH2 32) + set (_${_PYTHON_PREFIX}_ARCH 64 32) + if (CMAKE_SYSTEM_PROCESSOR MATCHES "ARM") + list (PREPEND _${_PYTHON_PREFIX}_ARCH ARM64 ARM) + endif() endif() # IronPython support @@ -1439,7 +1481,7 @@ unset (_${_PYTHON_PREFIX}_IRON_PYTHON_INTERPRETER_NAMES) unset (_${_PYTHON_PREFIX}_IRON_PYTHON_COMPILER_NAMES) unset (_${_PYTHON_PREFIX}_IRON_PYTHON_COMPILER_ARCH_FLAGS) if (CMAKE_SIZEOF_VOID_P) - if (_${_PYTHON_PREFIX}_ARCH EQUAL "32") + if (CMAKE_SIZEOF_VOID_P EQUAL "4") set (_${_PYTHON_PREFIX}_IRON_PYTHON_COMPILER_ARCH_FLAGS "/platform:x86") else() set (_${_PYTHON_PREFIX}_IRON_PYTHON_COMPILER_ARCH_FLAGS "/platform:x64") @@ -2048,7 +2090,6 @@ if ("Interpreter" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS) list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 3 ${_PYTHON_PREFIX}_VERSION_PATCH) list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 4 _${_PYTHON_PREFIX}_ARCH) - set (_${_PYTHON_PREFIX}_ARCH2 ${_${_PYTHON_PREFIX}_ARCH}) list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 5 _${_PYTHON_PREFIX}_ABIFLAGS) list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 6 ${_PYTHON_PREFIX}_SOABI) @@ -2098,10 +2139,27 @@ if ("Interpreter" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS) if (NOT _${_PYTHON_PREFIX}_RESULT) if (${_PYTHON_PREFIX}_IS64BIT) set (_${_PYTHON_PREFIX}_ARCH 64) - set (_${_PYTHON_PREFIX}_ARCH2 64) else() set (_${_PYTHON_PREFIX}_ARCH 32) - set (_${_PYTHON_PREFIX}_ARCH2 32) + endif() + endif() + + if (WIN32) + # check if architecture is Intel or ARM + execute_process (COMMAND ${_${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c + "import sys; import sysconfig; sys.stdout.write(sysconfig.get_platform())" + RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT + OUTPUT_VARIABLE _${_PYTHON_PREFIX}_PLATFORM + ERROR_VARIABLE ${_PYTHON_PREFIX}_PLATFORM) + if (NOT _${_PYTHON_PREFIX}_RESULT) + string(TOUPPER "${_${_PYTHON_PREFIX}_PLATFORM}" _${_PYTHON_PREFIX}_PLATFORM) + if (_${_PYTHON_PREFIX}_PLATFORM MATCHES "ARM") + if (${_PYTHON_PREFIX}_IS64BIT) + set (_${_PYTHON_PREFIX}_ARCH ARM64) + else() + set (_${_PYTHON_PREFIX}_ARCH ARM) + endif() + endif() endif() endif() endif() diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index e29df7f..6521b7b 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 26) -set(CMake_VERSION_PATCH 20230324) +set(CMake_VERSION_PATCH 20230328) #set(CMake_VERSION_RC 0) set(CMake_VERSION_IS_DIRTY 0) diff --git a/Source/cmBinUtilsWindowsPELinker.cxx b/Source/cmBinUtilsWindowsPELinker.cxx index 79e39e9..918f563 100644 --- a/Source/cmBinUtilsWindowsPELinker.cxx +++ b/Source/cmBinUtilsWindowsPELinker.cxx @@ -3,7 +3,10 @@ #include "cmBinUtilsWindowsPELinker.h" +#include <algorithm> +#include <iterator> #include <sstream> +#include <utility> #include <vector> #include <cm/memory> @@ -16,6 +19,27 @@ #ifdef _WIN32 # include <windows.h> + +# include "cmsys/Encoding.hxx" +#endif + +#ifdef _WIN32 +namespace { + +void ReplaceWithActualNameCasing(std::string& path) +{ + WIN32_FIND_DATAW findData; + HANDLE hFind = ::FindFirstFileW( + cmsys::Encoding::ToWindowsExtendedPath(path).c_str(), &findData); + + if (hFind != INVALID_HANDLE_VALUE) { + auto onDiskName = cmsys::Encoding::ToNarrow(findData.cFileName); + ::FindClose(hFind); + path.replace(path.end() - onDiskName.size(), path.end(), onDiskName); + } +} + +} #endif cmBinUtilsWindowsPELinker::cmBinUtilsWindowsPELinker( @@ -60,29 +84,47 @@ bool cmBinUtilsWindowsPELinker::ScanDependencies( if (!this->Tool->GetFileInfo(file, needed)) { return false; } - for (auto& n : needed) { - n = cmSystemTools::LowerCase(n); - } + + struct WinPEDependency + { + WinPEDependency(std::string o) + : Original(std::move(o)) + , LowerCase(cmSystemTools::LowerCase(Original)) + { + } + std::string const Original; + std::string const LowerCase; + }; + + std::vector<WinPEDependency> depends; + depends.reserve(needed.size()); + std::move(needed.begin(), needed.end(), std::back_inserter(depends)); std::string origin = cmSystemTools::GetFilenamePath(file); - for (auto const& lib : needed) { - if (!this->Archive->IsPreExcluded(lib)) { + for (auto const& lib : depends) { + if (!this->Archive->IsPreExcluded(lib.LowerCase)) { std::string path; bool resolved = false; - if (!this->ResolveDependency(lib, origin, path, resolved)) { + if (!this->ResolveDependency(lib.LowerCase, origin, path, resolved)) { return false; } if (resolved) { if (!this->Archive->IsPostExcluded(path)) { +#ifdef _WIN32 + ReplaceWithActualNameCasing(path); +#else + path.replace(path.end() - lib.Original.size(), path.end(), + lib.Original); +#endif bool unique; - this->Archive->AddResolvedPath(lib, path, unique); + this->Archive->AddResolvedPath(lib.Original, path, unique); if (unique && !this->ScanDependencies(path, cmStateEnums::SHARED_LIBRARY)) { return false; } } } else { - this->Archive->AddUnresolvedPath(lib); + this->Archive->AddUnresolvedPath(lib.Original); } } } diff --git a/Source/cmCommonTargetGenerator.cxx b/Source/cmCommonTargetGenerator.cxx index 5601bf2..f6fdd48 100644 --- a/Source/cmCommonTargetGenerator.cxx +++ b/Source/cmCommonTargetGenerator.cxx @@ -165,6 +165,7 @@ std::vector<std::string> cmCommonTargetGenerator::GetLinkedTargetDirectories( { std::vector<std::string> dirs; std::set<cmGeneratorTarget const*> emitted; + cmGlobalCommonGenerator* const gg = this->GlobalCommonGenerator; if (cmComputeLinkInformation* cli = this->GeneratorTarget->GetLinkInformation(config)) { cmComputeLinkInformation::ItemVector const& items = cli->GetItems(); @@ -172,6 +173,8 @@ std::vector<std::string> cmCommonTargetGenerator::GetLinkedTargetDirectories( cmGeneratorTarget const* linkee = item.Target; if (linkee && !linkee->IsImported() + // Skip targets that build after this one in a static lib cycle. + && gg->TargetOrderIndexLess(linkee, this->GeneratorTarget) // We can ignore the INTERFACE_LIBRARY items because // Target->GetLinkInformation already processed their // link interface and they don't have any output themselves. diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index 7ed68d6..0e9f78e 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -1727,8 +1727,7 @@ cmGlobalGenerator::GetLocalGeneratorTargetsInOrder(cmLocalGenerator* lg) const cm::append(gts, lg->GetGeneratorTargets()); std::sort(gts.begin(), gts.end(), [this](cmGeneratorTarget const* l, cmGeneratorTarget const* r) { - return this->TargetOrderIndex.at(l) < - this->TargetOrderIndex.at(r); + return this->TargetOrderIndexLess(l, r); }); return gts; } @@ -3068,6 +3067,12 @@ cmGlobalGenerator::GetTargetDirectDepends(cmGeneratorTarget const* target) return this->TargetDependencies[target]; } +bool cmGlobalGenerator::TargetOrderIndexLess(cmGeneratorTarget const* l, + cmGeneratorTarget const* r) const +{ + return this->TargetOrderIndex.at(l) < this->TargetOrderIndex.at(r); +} + bool cmGlobalGenerator::IsReservedTarget(std::string const& name) { // The following is a list of targets reserved diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h index 7de8215..4d321b5 100644 --- a/Source/cmGlobalGenerator.h +++ b/Source/cmGlobalGenerator.h @@ -479,6 +479,11 @@ public: TargetDependSet const& GetTargetDirectDepends( const cmGeneratorTarget* target); + // Return true if target 'l' occurs before 'r' in a global ordering + // of targets that respects inter-target dependencies. + bool TargetOrderIndexLess(cmGeneratorTarget const* l, + cmGeneratorTarget const* r) const; + const std::map<std::string, std::vector<cmLocalGenerator*>>& GetProjectMap() const { diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx index 37856d9..052f2e9 100644 --- a/Source/cmGlobalNinjaGenerator.cxx +++ b/Source/cmGlobalNinjaGenerator.cxx @@ -949,8 +949,9 @@ void cmGlobalNinjaGenerator::EnableLanguage( mf->GetSafeDefinition(cmStrCat("CMAKE_", l, "_SIMULATE_ID")); std::string const& compilerFrontendVariant = mf->GetSafeDefinition( cmStrCat("CMAKE_", l, "_COMPILER_FRONTEND_VARIANT")); - this->SetUsingGCCOnWindows( - DetectGCCOnWindows(compilerId, simulateId, compilerFrontendVariant)); + if (DetectGCCOnWindows(compilerId, simulateId, compilerFrontendVariant)) { + this->MarkAsGCCOnWindows(); + } #endif } } @@ -2843,8 +2844,9 @@ int cmcmd_cmake_ninja_dyndep(std::vector<std::string>::const_iterator argBeg, cmGlobalNinjaGenerator& gg = cm::static_reference_cast<cmGlobalNinjaGenerator>(ggd); # ifdef _WIN32 - gg.SetUsingGCCOnWindows( - DetectGCCOnWindows(compilerId, simulateId, compilerFrontendVariant)); + if (DetectGCCOnWindows(compilerId, simulateId, compilerFrontendVariant)) { + gg.MarkAsGCCOnWindows(); + } # endif return gg.WriteDyndepFile(dir_top_src, dir_top_bld, dir_cur_src, dir_cur_bld, arg_dd, arg_ddis, module_dir, linked_target_dirs, diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h index 12c6698..55fdbf0 100644 --- a/Source/cmGlobalNinjaGenerator.h +++ b/Source/cmGlobalNinjaGenerator.h @@ -169,7 +169,7 @@ public: const std::string& comment = ""); bool IsGCCOnWindows() const { return this->UsingGCCOnWindows; } - void SetUsingGCCOnWindows(bool b) { this->UsingGCCOnWindows = b; } + void MarkAsGCCOnWindows() { this->UsingGCCOnWindows = true; } cmGlobalNinjaGenerator(cmake* cm); diff --git a/Tests/CudaOnly/RuntimeControls/verify_runtime.cmake b/Tests/CudaOnly/RuntimeControls/verify_runtime.cmake index b313dac..27fbe45 100644 --- a/Tests/CudaOnly/RuntimeControls/verify_runtime.cmake +++ b/Tests/CudaOnly/RuntimeControls/verify_runtime.cmake @@ -7,7 +7,7 @@ file(GET_RUNTIME_DEPENDENCIES EXECUTABLES ${EXEC_PATH} ) -list(FILTER resolved_libs INCLUDE REGEX ".*cudart.*") +list(FILTER resolved_libs INCLUDE REGEX ".*[Cc][Uu][Dd][Aa][Rr][Tt].*") list(LENGTH resolved_libs has_cudart) if(has_cudart EQUAL 0) diff --git a/Tests/FortranModules/Executable/CMakeLists.txt b/Tests/FortranModules/Executable/CMakeLists.txt index f31a3e6..182e23a 100644 --- a/Tests/FortranModules/Executable/CMakeLists.txt +++ b/Tests/FortranModules/Executable/CMakeLists.txt @@ -6,3 +6,4 @@ add_executable(subdir_exe2 main.f90) target_link_libraries(subdir_exe2 subdir_mods subdir_mods2) add_dependencies(subdir_exe2 ExternalTarget) target_link_libraries(subdir_exe2 myext) +target_link_libraries(subdir_exe2 cycleA) diff --git a/Tests/FortranModules/Executable/main.f90 b/Tests/FortranModules/Executable/main.f90 index 640259c..218eee6 100644 --- a/Tests/FortranModules/Executable/main.f90 +++ b/Tests/FortranModules/Executable/main.f90 @@ -3,5 +3,9 @@ PROGRAM MAINF90 USE libraryModuleB USE subdirModuleA USE externalMod + USE libraryCycleA + USE libraryCycleB CALL printExtModGreeting + CALL libraryCycleA2 + CALL libraryCycleB2 END PROGRAM MAINF90 diff --git a/Tests/FortranModules/Library/CMakeLists.txt b/Tests/FortranModules/Library/CMakeLists.txt index 17438ca..e525208 100644 --- a/Tests/FortranModules/Library/CMakeLists.txt +++ b/Tests/FortranModules/Library/CMakeLists.txt @@ -3,9 +3,14 @@ add_library(subdir_mods a.f90 b.f90) add_executable(subdir_exe main.f90) target_link_libraries(subdir_exe subdir_mods) +add_library(cycleA STATIC cycleA1.f90 cycleA2.f90) +add_library(cycleB STATIC cycleB1.f90 cycleB2.f90) +target_link_libraries(cycleA PRIVATE cycleB) +target_link_libraries(cycleB PRIVATE cycleA) + # Test module output directory if available. if(CMAKE_Fortran_MODDIR_FLAG) - set_target_properties(subdir_mods PROPERTIES + set_target_properties(subdir_mods cycleA cycleB PROPERTIES Fortran_MODULE_DIRECTORY modules ) endif() diff --git a/Tests/FortranModules/Library/cycleA1.f90 b/Tests/FortranModules/Library/cycleA1.f90 new file mode 100644 index 0000000..cceebe2 --- /dev/null +++ b/Tests/FortranModules/Library/cycleA1.f90 @@ -0,0 +1,3 @@ +subroutine cycleA1 +use libraryCycleA +end subroutine diff --git a/Tests/FortranModules/Library/cycleA2.f90 b/Tests/FortranModules/Library/cycleA2.f90 new file mode 100644 index 0000000..a2e432e --- /dev/null +++ b/Tests/FortranModules/Library/cycleA2.f90 @@ -0,0 +1,5 @@ +module libraryCycleA +contains + subroutine libraryCycleA2 + end subroutine +end module diff --git a/Tests/FortranModules/Library/cycleB1.f90 b/Tests/FortranModules/Library/cycleB1.f90 new file mode 100644 index 0000000..d6680fa --- /dev/null +++ b/Tests/FortranModules/Library/cycleB1.f90 @@ -0,0 +1,3 @@ +subroutine cycleB1 +use libraryCycleB +end subroutine diff --git a/Tests/FortranModules/Library/cycleB2.f90 b/Tests/FortranModules/Library/cycleB2.f90 new file mode 100644 index 0000000..07c774e --- /dev/null +++ b/Tests/FortranModules/Library/cycleB2.f90 @@ -0,0 +1,5 @@ +module libraryCycleB +contains + subroutine libraryCycleB2 + end subroutine +end module diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt index 0ebb720..080740c 100644 --- a/Tests/RunCMake/CMakeLists.txt +++ b/Tests/RunCMake/CMakeLists.txt @@ -784,6 +784,7 @@ if(DEFINED CMake_COMPILER_FORCES_NEW_DTAGS) endif() add_RunCMake_test(file-GET_RUNTIME_DEPENDENCIES -DCMake_INSTALL_NAME_TOOL_BUG=${CMake_INSTALL_NAME_TOOL_BUG} + -DCMAKE_C_COMPILER_ID=${CMAKE_C_COMPILER_ID} ) add_RunCMake_test(CPackCommandLine) diff --git a/Tests/RunCMake/ToolchainFile/RunCMakeTest.cmake b/Tests/RunCMake/ToolchainFile/RunCMakeTest.cmake index 7744ee8..b588ce0 100644 --- a/Tests/RunCMake/ToolchainFile/RunCMakeTest.cmake +++ b/Tests/RunCMake/ToolchainFile/RunCMakeTest.cmake @@ -14,6 +14,7 @@ run_cmake_toolchain(LinkFlagsInit) run_cmake_toolchain(CMP0126-NEW) run_cmake_toolchain(CMP0126-OLD) run_cmake_toolchain(CMP0126-WARN) +run_cmake_toolchain(SetCrossCompiling) function(run_IncludeDirectories) run_cmake_toolchain(IncludeDirectories) diff --git a/Tests/RunCMake/ToolchainFile/SetCrossCompiling-stderr.txt b/Tests/RunCMake/ToolchainFile/SetCrossCompiling-stderr.txt new file mode 100644 index 0000000..6642cf6 --- /dev/null +++ b/Tests/RunCMake/ToolchainFile/SetCrossCompiling-stderr.txt @@ -0,0 +1,8 @@ +^CMake Warning \(dev\) at [^ +]*/Modules/CMakeDetermineSystem.cmake:[0-9]+ \(message\): + CMAKE_CROSSCOMPILING has been set by the project, toolchain file, or user\. + CMake is resetting it to false because CMAKE_SYSTEM_NAME was not set\. To + indicate cross compilation, only CMAKE_SYSTEM_NAME needs to be set\. +Call Stack \(most recent call first\): + CMakeLists\.txt:[0-9]+ \(project\) +This warning is for project developers\. Use -Wno-dev to suppress it\.$ diff --git a/Tests/RunCMake/ToolchainFile/SetCrossCompiling-toolchain.cmake b/Tests/RunCMake/ToolchainFile/SetCrossCompiling-toolchain.cmake new file mode 100644 index 0000000..170e26c --- /dev/null +++ b/Tests/RunCMake/ToolchainFile/SetCrossCompiling-toolchain.cmake @@ -0,0 +1 @@ +set(CMAKE_CROSSCOMPILING TRUE) diff --git a/Tests/RunCMake/ToolchainFile/SetCrossCompiling.cmake b/Tests/RunCMake/ToolchainFile/SetCrossCompiling.cmake new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/Tests/RunCMake/ToolchainFile/SetCrossCompiling.cmake diff --git a/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/RunCMakeTest.cmake b/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/RunCMakeTest.cmake index 43b406b..a68607e 100644 --- a/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/RunCMakeTest.cmake +++ b/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/RunCMakeTest.cmake @@ -9,6 +9,10 @@ function(run_install_test case) run_cmake_command(${case}-build ${CMAKE_COMMAND} --build . --config Debug) # Check "all" components. set(CMAKE_INSTALL_PREFIX ${RunCMake_TEST_BINARY_DIR}/root-all) + set(maybe_stderr "${case}-all-stderr-${CMAKE_C_COMPILER_ID}.txt") + if(EXISTS "${RunCMake_SOURCE_DIR}/${maybe_stderr}") + set(RunCMake-stderr-file "${maybe_stderr}") + endif() run_cmake_command(${case}-all ${CMAKE_COMMAND} --install . --prefix ${CMAKE_INSTALL_PREFIX} --config Debug) endfunction() diff --git a/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/windows-all-check.cmake b/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/windows-all-check.cmake index cb0e534..10b7b82 100644 --- a/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/windows-all-check.cmake +++ b/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/windows-all-check.cmake @@ -1,19 +1,29 @@ +if(CMAKE_C_COMPILER_ID STREQUAL "Borland") + # Borland upper-cases dll names referenced in import libraries. + set(conflict_dll [[CONFLICT\.DLL]]) + set(unresolved_dll [[UNRESOLVED\.DLL]]) +else() + set(conflict_dll [[conflict\.dll]]) + set(unresolved_dll [[unresolved\.dll]]) +endif() + set(_check [=[[^;]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/windows-build/root-all/bin/\.conflict/\.\./(lib)?libdir\.dll]=] [=[[^;]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/windows-build/root-all/bin/\.search/(lib)?search\.dll]=] + [=[[^;]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/windows-build/root-all/bin/(lib)?MixedCase\.dll]=] [=[[^;]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/windows-build/root-all/bin/(lib)?testlib\.dll]=] ) check_contents(deps/deps1.txt "^${_check}$") check_contents(deps/deps2.txt "^${_check}$") check_contents(deps/deps3.txt "^${_check}$") set(_check - [=[(lib)?unresolved\.dll]=] + "(lib)?${unresolved_dll}" ) check_contents(deps/udeps1.txt "^${_check}$") check_contents(deps/udeps2.txt "^${_check}$") check_contents(deps/udeps3.txt "^${_check}$") set(_check - "^(lib)?conflict\\.dll:[^;]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/windows-build/root-all/bin/\\.conflict/(lib)?conflict\\.dll;[^;]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/windows-build/root-all/bin/(lib)?conflict\\.dll\n$" + "^(lib)?${conflict_dll}:[^;]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/windows-build/root-all/bin/\\.conflict/(lib)?conflict\\.dll;[^;]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/windows-build/root-all/bin/(lib)?conflict\\.dll\n$" ) check_contents(deps/cdeps1.txt "${_check}") check_contents(deps/cdeps2.txt "${_check}") diff --git a/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/windows-conflict-all-stderr-Borland.txt b/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/windows-conflict-all-stderr-Borland.txt new file mode 100644 index 0000000..607e4b8 --- /dev/null +++ b/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/windows-conflict-all-stderr-Borland.txt @@ -0,0 +1,7 @@ +^CMake Error at cmake_install\.cmake:[0-9]+ \(file\): + file Multiple conflicting paths found for PATH\.DLL: + + [^ +]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/windows-conflict-build/root-all/lib/test1/path\.dll + [^ +]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/windows-conflict-build/root-all/lib/test2/path\.dll$ diff --git a/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/windows-unresolved-all-stderr-Borland.txt b/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/windows-unresolved-all-stderr-Borland.txt new file mode 100644 index 0000000..fea1083 --- /dev/null +++ b/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/windows-unresolved-all-stderr-Borland.txt @@ -0,0 +1,4 @@ +^CMake Error at cmake_install\.cmake:[0-9]+ \(file\): + file Could not resolve runtime dependencies: + + UNRESOLVED\.DLL$ diff --git a/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/windows.cmake b/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/windows.cmake index 9160ce5..aad9077 100644 --- a/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/windows.cmake +++ b/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/windows.cmake @@ -8,6 +8,7 @@ set(testlib_names search unresolved conflict + MixedCase ) file(REMOVE "${CMAKE_BINARY_DIR}/testlib.c") @@ -34,7 +35,7 @@ file(WRITE "${CMAKE_BINARY_DIR}/testlib_noconflict.c" "__declspec(dllimport) ext add_library(testlib_noconflict SHARED "${CMAKE_BINARY_DIR}/testlib_noconflict.c") target_link_libraries(testlib_noconflict PRIVATE libdir) -install(TARGETS testlib libdir_postexcluded libdir conflict testlib_noconflict DESTINATION bin) +install(TARGETS testlib libdir_postexcluded libdir conflict MixedCase testlib_noconflict DESTINATION bin) install(TARGETS libdir search_postexcluded search DESTINATION bin/.search) # Prefixing with "." ensures it is the first item after list(SORT) install(TARGETS testlib_conflict conflict DESTINATION bin/.conflict) @@ -61,6 +62,7 @@ install(CODE [[ "^(lib)?search\\.dll$" "^(lib)?unresolved\\.dll$" "^(lib)?conflict\\.dll$" + "^(lib)?mixedcase\\.dll$" "^kernel32\\.dll$" PRE_EXCLUDE_REGEXES ".*" POST_INCLUDE_REGEXES @@ -68,6 +70,7 @@ install(CODE [[ "^.*/(lib)?libdir\\.dll$" "^.*/(lib)?search\\.dll$" "^.*/(lib)?conflict\\.dll$" + "^.*/(lib)?mixedcase\\.dll$" POST_EXCLUDE_REGEXES ".*" DIRECTORIES "${CMAKE_INSTALL_PREFIX}/bin/.search" |