diff options
24 files changed, 250 insertions, 93 deletions
diff --git a/Help/command/if.rst b/Help/command/if.rst index 72d328d..c51d2bc 100644 --- a/Help/command/if.rst +++ b/Help/command/if.rst @@ -47,7 +47,8 @@ as ``EXISTS``, ``COMMAND``, and ``DEFINED``. Then binary tests such as and ``MATCHES``. Then the boolean operators in the order ``NOT``, ``AND``, and finally ``OR``. -Possible conditions are: +Basic Expressions +""""""""""""""""" ``if(<constant>)`` True if the constant is ``1``, ``ON``, ``YES``, ``TRUE``, ``Y``, @@ -62,6 +63,9 @@ Possible conditions are: True if given a variable that is defined to a value that is not a false constant. False otherwise. (Note macro arguments are not variables.) +Logic Operators +""""""""""""""" + ``if(NOT <condition>)`` True if the condition is not true. @@ -71,6 +75,15 @@ Possible conditions are: ``if(<cond1> OR <cond2>)`` True if either condition would be considered true individually. +``if((condition) AND (condition OR (condition)))`` + The conditions inside the parenthesis are evaluated first and then + the remaining condition is evaluated as in the other examples. + Where there are nested parenthesis the innermost are evaluated as part + of evaluating the condition that contains them. + +Existence Checks +"""""""""""""""" + ``if(COMMAND command-name)`` True if the given name is a command, macro or function that can be invoked. @@ -89,6 +102,21 @@ Possible conditions are: True if the given name is an existing test name created by the :command:`add_test` command. +``if(DEFINED <name>|CACHE{<name>}|ENV{<name>})`` + True if a variable, cache variable or environment variable + with given ``<name>`` is defined. The value of the variable + does not matter. Note that macro arguments are not variables. + + .. versionadded:: 3.14 + Added support for ``CACHE{<name>}`` variables. + +``if(<variable|string> IN_LIST <variable>)`` + .. versionadded:: 3.3 + True if the given element is contained in the named list variable. + +File Operations +""""""""""""""" + ``if(EXISTS path-to-file-or-directory)`` True if the named file or directory exists. Behavior is well-defined only for full paths. Resolves symbolic links, i.e. if the named file or @@ -114,6 +142,9 @@ Possible conditions are: ``if(IS_ABSOLUTE path)`` True if the given path is an absolute path. +Comparisons +""""""""""" + ``if(<variable|string> MATCHES regex)`` True if the given string or variable's value matches the given regular condition. See :ref:`Regex Specification` for regex format. @@ -165,6 +196,9 @@ Possible conditions are: True if the given string or variable's value is lexicographically greater than or equal to the string or variable on the right. +Version Comparisons +""""""""""""""""""" + ``if(<variable|string> VERSION_LESS <variable|string>)`` Component-wise integer version number comparison (version format is ``major[.minor[.patch[.tweak]]]``, omitted components are treated as zero). @@ -197,24 +231,6 @@ Possible conditions are: Any non-integer version component or non-integer trailing part of a version component effectively truncates the string at that point. -``if(<variable|string> IN_LIST <variable>)`` - .. versionadded:: 3.3 - True if the given element is contained in the named list variable. - -``if(DEFINED <name>|CACHE{<name>}|ENV{<name>})`` - True if a variable, cache variable or environment variable - with given ``<name>`` is defined. The value of the variable - does not matter. Note that macro arguments are not variables. - - .. versionadded:: 3.14 - Added support for ``CACHE{<name>}`` variables. - -``if((condition) AND (condition OR (condition)))`` - The conditions inside the parenthesis are evaluated first and then - the remaining condition is evaluated as in the previous examples. - Where there are nested parenthesis the innermost are evaluated as part - of evaluating the condition that contains them. - Variable Expansion ^^^^^^^^^^^^^^^^^^ diff --git a/Help/generator/Ninja Multi-Config.rst b/Help/generator/Ninja Multi-Config.rst index d1df42b..8901192 100644 --- a/Help/generator/Ninja Multi-Config.rst +++ b/Help/generator/Ninja Multi-Config.rst @@ -130,3 +130,34 @@ output config using the ``Release`` command config. The ``Release`` build of the ``generator`` target is called with ``Debug.txt Debug Release`` as arguments. The command depends on the ``Release`` builds of ``tgt1`` and ``tgt4``, and the ``Debug`` builds of ``tgt2`` and ``tgt3``. + +``PRE_BUILD``, ``PRE_LINK``, and ``POST_BUILD`` custom commands for targets +only get run in their "native" configuration (the ``Release`` configuration in +the ``build-Release.ninja`` file) unless they have no ``BYPRODUCTS`` or their +``BYPRODUCTS`` are unique per config. Consider the following example: + +.. code-block:: cmake + + add_executable(exe main.c) + add_custom_command( + TARGET exe + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E echo "Running no-byproduct command" + ) + add_custom_command( + TARGET exe + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E echo "Running separate-byproduct command for $<CONFIG>" + BYPRODUCTS $<CONFIG>.txt + ) + add_custom_command( + TARGET exe + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E echo "Running common-byproduct command for $<CONFIG>" + BYPRODUCTS exe.txt + ) + +In this example, if you build ``exe:Debug`` in ``build-Release.ninja``, the +first and second custom commands get run, since their byproducts are unique +per-config, but the last custom command does not. However, if you build +``exe:Release`` in ``build-Release.ninja``, all three custom commands get run. diff --git a/Help/release/dev/cuda-nvcc-ccache-symlink.rst b/Help/release/dev/cuda-nvcc-ccache-symlink.rst new file mode 100644 index 0000000..4d38047 --- /dev/null +++ b/Help/release/dev/cuda-nvcc-ccache-symlink.rst @@ -0,0 +1,9 @@ +cuda-nvcc-ccache-symlink +------------------------ + +* ``CUDA`` language support now works when ``nvcc`` is a symbolic link, + for example due to a ``ccache`` or ``colornvcc`` wrapper script. + +* The :module:`FindCUDAToolkit` module gained support for finding CUDA + toolkits when ``nvcc`` is a symbolic link, + for example due to a ``ccache`` or ``colornvcc`` wrapper script. diff --git a/Modules/CMakeDetermineCUDACompiler.cmake b/Modules/CMakeDetermineCUDACompiler.cmake index 578729c..c77fc3a 100644 --- a/Modules/CMakeDetermineCUDACompiler.cmake +++ b/Modules/CMakeDetermineCUDACompiler.cmake @@ -172,7 +172,20 @@ if(NOT CMAKE_CUDA_COMPILER_ID_RUN) endif() endif() - get_filename_component(CMAKE_CUDA_COMPILER_TOOLKIT_ROOT "${_CUDA_NVCC_EXECUTABLE}" DIRECTORY) + # If NVCC is a symlink due to a wrapper script (e.g. ccache or colornvcc), then invoke it to find the + # real non-scattered toolkit. + if(IS_SYMLINK ${_CUDA_NVCC_EXECUTABLE}) + execute_process(COMMAND ${_CUDA_NVCC_EXECUTABLE} "-v" "__cmake_determine_cuda" ERROR_VARIABLE NVCC_ERR) + if(NVCC_ERR MATCHES " _HERE_=([^\r\n]*)") + set(CMAKE_CUDA_COMPILER_TOOLKIT_ROOT "${CMAKE_MATCH_1}") + else() + message(FATAL_ERROR "Could not execute nvcc with -v.") + endif() + unset(NVCC_ERR) + else() + get_filename_component(CMAKE_CUDA_COMPILER_TOOLKIT_ROOT "${_CUDA_NVCC_EXECUTABLE}" DIRECTORY) + endif() + set(CMAKE_CUDA_DEVICE_LINKER "${CMAKE_CUDA_COMPILER_TOOLKIT_ROOT}/nvlink${CMAKE_EXECUTABLE_SUFFIX}") set(CMAKE_CUDA_FATBINARY "${CMAKE_CUDA_COMPILER_TOOLKIT_ROOT}/fatbinary${CMAKE_EXECUTABLE_SUFFIX}") get_filename_component(CMAKE_CUDA_COMPILER_TOOLKIT_ROOT "${CMAKE_CUDA_COMPILER_TOOLKIT_ROOT}" DIRECTORY) diff --git a/Modules/FindCUDA.cmake b/Modules/FindCUDA.cmake index 6daf81d..240f0a5 100644 --- a/Modules/FindCUDA.cmake +++ b/Modules/FindCUDA.cmake @@ -834,7 +834,20 @@ if(NOT CUDA_TOOLKIT_ROOT_DIR AND NOT CMAKE_CROSSCOMPILING) ) if (CUDA_TOOLKIT_ROOT_DIR_NVCC) - get_filename_component(CUDA_TOOLKIT_ROOT_DIR_NVCC_PAR "${CUDA_TOOLKIT_ROOT_DIR_NVCC}" DIRECTORY) + # If NVCC is a symlink due to a wrapper script (e.g. ccache or colornvcc), then invoke it to find the + # real non-scattered toolkit. + if(IS_SYMLINK ${CUDA_TOOLKIT_ROOT_DIR_NVCC}) + execute_process(COMMAND ${CUDA_TOOLKIT_ROOT_DIR_NVCC} "-v" "__cmake_determine_cuda" ERROR_VARIABLE NVCC_ERR) + if(NVCC_ERR MATCHES " _HERE_=([^\r\n]*)") + set(CUDA_TOOLKIT_ROOT_DIR_NVCC_PAR "${CMAKE_MATCH_1}") + else() + message(FATAL_ERROR "Could not execute nvcc with -v.") + endif() + unset(NVCC_ERR) + else() + get_filename_component(CUDA_TOOLKIT_ROOT_DIR_NVCC_PAR "${CUDA_TOOLKIT_ROOT_DIR_NVCC}" DIRECTORY) + endif() + get_filename_component(CUDA_TOOLKIT_ROOT_DIR "${CUDA_TOOLKIT_ROOT_DIR_NVCC_PAR}" DIRECTORY CACHE) string(REGEX REPLACE "[/\\\\]?bin[64]*[/\\\\]?$" "" CUDA_TOOLKIT_ROOT_DIR ${CUDA_TOOLKIT_ROOT_DIR}) # We need to force this back into the cache. diff --git a/Modules/FindCUDAToolkit.cmake b/Modules/FindCUDAToolkit.cmake index 61e264b..0d80c80 100644 --- a/Modules/FindCUDAToolkit.cmake +++ b/Modules/FindCUDAToolkit.cmake @@ -519,7 +519,19 @@ else() endif() if(CUDAToolkit_NVCC_EXECUTABLE) - get_filename_component(CUDAToolkit_BIN_DIR "${CUDAToolkit_NVCC_EXECUTABLE}" DIRECTORY) + # If NVCC is a symlink due to a wrapper script (e.g. ccache or colornvcc), then invoke it to find the + # real non-scattered toolkit. + if(IS_SYMLINK ${CUDAToolkit_NVCC_EXECUTABLE}) + execute_process(COMMAND ${CUDAToolkit_NVCC_EXECUTABLE} "-v" "__cmake_determine_cuda" ERROR_VARIABLE NVCC_ERR) + if(NVCC_ERR MATCHES " _HERE_=([^\r\n]*)") + set(CUDAToolkit_BIN_DIR "${CMAKE_MATCH_1}") + else() + message(FATAL_ERROR "Could not execute nvcc with -v.") + endif() + unset(NVCC_ERR) + else() + get_filename_component(CUDAToolkit_BIN_DIR "${CUDAToolkit_NVCC_EXECUTABLE}" DIRECTORY) + endif() set(CUDAToolkit_BIN_DIR "${CUDAToolkit_BIN_DIR}" CACHE PATH "" FORCE) mark_as_advanced(CUDAToolkit_BIN_DIR) diff --git a/Modules/FindPostgreSQL.cmake b/Modules/FindPostgreSQL.cmake index cd50d8c..911210f 100644 --- a/Modules/FindPostgreSQL.cmake +++ b/Modules/FindPostgreSQL.cmake @@ -247,7 +247,7 @@ endif() # Did we find anything? include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake) find_package_handle_standard_args(PostgreSQL - REQUIRED_VARS PostgreSQL_LIBRARY PostgreSQL_INCLUDE_DIR PostgreSQL_TYPE_INCLUDE_DIR + REQUIRED_VARS PostgreSQL_LIBRARY PostgreSQL_INCLUDE_DIR VERSION_VAR PostgreSQL_VERSION_STRING) set(PostgreSQL_FOUND ${POSTGRESQL_FOUND}) @@ -271,16 +271,19 @@ endfunction() # Now try to get the include and library path. if(PostgreSQL_FOUND) + set(PostgreSQL_INCLUDE_DIRS ${PostgreSQL_INCLUDE_DIR}) + if(PostgreSQL_TYPE_INCLUDE_DIR) + list(APPEND PostgreSQL_INCLUDE_DIRS ${PostgreSQL_TYPE_INCLUDE_DIR}) + endif() + set(PostgreSQL_LIBRARY_DIRS ${PostgreSQL_LIBRARY_DIR} ) if (NOT TARGET PostgreSQL::PostgreSQL) add_library(PostgreSQL::PostgreSQL UNKNOWN IMPORTED) set_target_properties(PostgreSQL::PostgreSQL PROPERTIES - INTERFACE_INCLUDE_DIRECTORIES "${PostgreSQL_INCLUDE_DIR};${PostgreSQL_TYPE_INCLUDE_DIR}") + INTERFACE_INCLUDE_DIRECTORIES "${PostgreSQL_INCLUDE_DIRS}") __postgresql_import_library(PostgreSQL::PostgreSQL PostgreSQL_LIBRARY "") __postgresql_import_library(PostgreSQL::PostgreSQL PostgreSQL_LIBRARY "RELEASE") __postgresql_import_library(PostgreSQL::PostgreSQL PostgreSQL_LIBRARY "DEBUG") endif () - set(PostgreSQL_INCLUDE_DIRS ${PostgreSQL_INCLUDE_DIR} ${PostgreSQL_TYPE_INCLUDE_DIR} ) - set(PostgreSQL_LIBRARY_DIRS ${PostgreSQL_LIBRARY_DIR} ) endif() mark_as_advanced(PostgreSQL_INCLUDE_DIR PostgreSQL_TYPE_INCLUDE_DIR) diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 9f0ac8b..a5cf411 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 19) -set(CMake_VERSION_PATCH 20210110) +set(CMake_VERSION_PATCH 20210112) #set(CMake_VERSION_RC 0) set(CMake_VERSION_IS_DIRTY 0) diff --git a/Source/QtDialog/CMakeLists.txt b/Source/QtDialog/CMakeLists.txt index d8f89d6..0c263bb 100644 --- a/Source/QtDialog/CMakeLists.txt +++ b/Source/QtDialog/CMakeLists.txt @@ -213,6 +213,7 @@ else() qt_wrap_cpp(MOC_BUILT_SRCS ${MOC_SRCS}) qt_add_resources(QRC_BUILT_SRCS ${QRC_SRCS}) endif() +add_library(CMakeGUIQRCLib OBJECT ${QRC_BUILT_SRCS}) if (FALSE) # CMake's bootstrap binary does not support automoc set(CMAKE_AUTOMOC 1) @@ -221,8 +222,7 @@ if (FALSE) # CMake's bootstrap binary does not support automoc else () list(APPEND SRCS ${UI_BUILT_SRCS} - ${MOC_BUILT_SRCS} - ${QRC_BUILT_SRCS}) + ${MOC_BUILT_SRCS}) endif () if(USE_LGPL) @@ -246,6 +246,7 @@ target_link_libraries(CMakeGUIMainLib PUBLIC CMakeGUILib) add_executable(cmake-gui WIN32 MACOSX_BUNDLE CMakeGUIExec.cxx ${MANIFEST_FILE}) target_link_libraries(cmake-gui CMakeGUIMainLib Qt${INSTALLED_QT_VERSION}::Core) +target_sources(CMakeGUIMainLib INTERFACE $<TARGET_OBJECTS:CMakeGUIQRCLib>) if(WIN32) target_sources(CMakeGUIMainLib INTERFACE $<TARGET_OBJECTS:CMakeVersion> CMakeSetup.rc) endif() diff --git a/Source/cmGccDepfileReader.cxx b/Source/cmGccDepfileReader.cxx index 96a562e..8253375 100644 --- a/Source/cmGccDepfileReader.cxx +++ b/Source/cmGccDepfileReader.cxx @@ -12,40 +12,33 @@ #include "cmStringAlgorithms.h" #include "cmSystemTools.h" -cm::optional<cmGccDepfileContent> cmReadGccDepfile(const char* filePath) -{ - cmGccDepfileLexerHelper helper; - if (helper.readFile(filePath)) { - return cm::make_optional(std::move(helper).extractContent()); - } - return cm::nullopt; -} - cm::optional<cmGccDepfileContent> cmReadGccDepfile(const char* filePath, const std::string& prefix) { - auto deps = cmReadGccDepfile(filePath); - - if (prefix.empty() || !deps) { - return deps; + cmGccDepfileLexerHelper helper; + if (!helper.readFile(filePath)) { + return cm::nullopt; } + auto deps = cm::make_optional(std::move(helper).extractContent()); for (auto& dep : *deps) { for (auto& rule : dep.rules) { - if (!cmSystemTools::FileIsFullPath(rule)) { + if (!prefix.empty() && !cmSystemTools::FileIsFullPath(rule)) { rule = cmStrCat(prefix, rule); } if (cmSystemTools::FileIsFullPath(rule)) { rule = cmSystemTools::CollapseFullPath(rule); } + cmSystemTools::ConvertToLongPath(rule); } for (auto& path : dep.paths) { - if (!cmSystemTools::FileIsFullPath(path)) { + if (!prefix.empty() && !cmSystemTools::FileIsFullPath(path)) { path = cmStrCat(prefix, path); } if (cmSystemTools::FileIsFullPath(path)) { path = cmSystemTools::CollapseFullPath(path); } + cmSystemTools::ConvertToLongPath(path); } } diff --git a/Source/cmGccDepfileReader.h b/Source/cmGccDepfileReader.h index 66ff75d..c8a3748 100644 --- a/Source/cmGccDepfileReader.h +++ b/Source/cmGccDepfileReader.h @@ -8,10 +8,8 @@ #include "cmGccDepfileReaderTypes.h" -cm::optional<cmGccDepfileContent> cmReadGccDepfile(const char* filePath); - /* * Read dependencies file and append prefix to all relative paths */ -cm::optional<cmGccDepfileContent> cmReadGccDepfile(const char* filePath, - const std::string& prefix); +cm::optional<cmGccDepfileContent> cmReadGccDepfile( + const char* filePath, const std::string& prefix = {}); diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx index 5a747e5..7229101 100644 --- a/Source/cmLocalNinjaGenerator.cxx +++ b/Source/cmLocalNinjaGenerator.cxx @@ -693,13 +693,11 @@ void cmLocalNinjaGenerator::WriteCustomCommandBuildStatement( } } -namespace { -bool HasUniqueByproducts(cmLocalGenerator& lg, - std::vector<std::string> const& byproducts, - cmListFileBacktrace const& bt) +bool cmLocalNinjaGenerator::HasUniqueByproducts( + std::vector<std::string> const& byproducts, cmListFileBacktrace const& bt) { std::vector<std::string> configs = - lg.GetMakefile()->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig); + this->GetMakefile()->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig); cmGeneratorExpression ge(bt); for (std::string const& p : byproducts) { if (cmGeneratorExpression::Find(p) == std::string::npos) { @@ -709,7 +707,7 @@ bool HasUniqueByproducts(cmLocalGenerator& lg, std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(p); for (std::string const& config : configs) { for (std::string const& b : - lg.ExpandCustomCommandOutputPaths(*cge, config)) { + this->ExpandCustomCommandOutputPaths(*cge, config)) { if (!seen.insert(b).second) { return false; } @@ -719,6 +717,7 @@ bool HasUniqueByproducts(cmLocalGenerator& lg, return true; } +namespace { bool HasUniqueOutputs(std::vector<cmCustomCommandGenerator> const& ccgs) { std::set<std::string> allOutputs; @@ -746,7 +745,7 @@ std::string cmLocalNinjaGenerator::CreateUtilityOutput( // In Ninja Multi-Config, we can only produce cross-config utility // commands if all byproducts are per-config. if (!this->GetGlobalGenerator()->IsMultiConfig() || - !HasUniqueByproducts(*this, byproducts, bt)) { + !this->HasUniqueByproducts(byproducts, bt)) { return this->cmLocalGenerator::CreateUtilityOutput(targetName, byproducts, bt); } diff --git a/Source/cmLocalNinjaGenerator.h b/Source/cmLocalNinjaGenerator.h index 87d5e53..5b850f3 100644 --- a/Source/cmLocalNinjaGenerator.h +++ b/Source/cmLocalNinjaGenerator.h @@ -86,6 +86,9 @@ public: cmNinjaDeps& ninjaDeps, const std::string& config); + bool HasUniqueByproducts(std::vector<std::string> const& byproducts, + cmListFileBacktrace const& bt); + protected: std::string ConvertToIncludeReference( std::string const& path, diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index e4c8e4b..cea20ad 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -303,7 +303,7 @@ void cmMakefile::PrintCommandTrace( args.reserve(lff.Arguments().size()); for (cmListFileArgument const& arg : lff.Arguments()) { - if (expand) { + if (expand && arg.Delim != cmListFileArgument::Bracket) { temp = arg.Value; this->ExpandVariablesInString(temp); args.push_back(temp); diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index c33fabd..adf40b0 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -345,27 +345,51 @@ void cmMakefileTargetGenerator::WriteCommonCodeRules() this->LocalGenerator->GetBinaryDirectory(), compilerDependFile)) << "\n\n"; - if (!cmSystemTools::FileExists(compilerDependFile)) { - // Write an empty dependency file. - cmGeneratedFileStream depFileStream( - compilerDependFile, false, - this->GlobalGenerator->GetMakefileEncoding()); - depFileStream << "# Empty compiler generated dependencies file for " - << this->GeneratorTarget->GetName() << ".\n" - << "# This may be replaced when dependencies are built.\n"; - } + // Write an empty dependency file. + cmGeneratedFileStream depFileStream( + compilerDependFile, false, this->GlobalGenerator->GetMakefileEncoding()); + depFileStream << "# Empty compiler generated dependencies file for " + << this->GeneratorTarget->GetName() << ".\n" + << "# This may be replaced when dependencies are built.\n"; + // remove internal dependency file + cmSystemTools::RemoveFile( + cmStrCat(this->TargetBuildDirectoryFull, "/compiler_depend.internal")); std::string compilerDependTimestamp = cmStrCat(this->TargetBuildDirectoryFull, "/compiler_depend.ts"); if (!cmSystemTools::FileExists(compilerDependTimestamp)) { // Write a dependency timestamp file. - cmGeneratedFileStream depFileStream( + cmGeneratedFileStream timestampFileStream( compilerDependTimestamp, false, this->GlobalGenerator->GetMakefileEncoding()); - depFileStream << "# CMAKE generated file: DO NOT EDIT!\n" - << "# Timestamp file for compiler generated dependencies " - "management for " - << this->GeneratorTarget->GetName() << ".\n"; + timestampFileStream + << "# CMAKE generated file: DO NOT EDIT!\n" + << "# Timestamp file for compiler generated dependencies " + "management for " + << this->GeneratorTarget->GetName() << ".\n"; + } + + // deactivate no longer needed legacy dependency files + // Write an empty dependency file. + cmGeneratedFileStream legacyDepFileStream( + dependFileNameFull, false, this->GlobalGenerator->GetMakefileEncoding()); + legacyDepFileStream + << "# Empty dependencies file for " << this->GeneratorTarget->GetName() + << ".\n" + << "# This may be replaced when dependencies are built.\n"; + // remove internal dependency file + cmSystemTools::RemoveFile( + cmStrCat(this->TargetBuildDirectoryFull, "/depend.internal")); + } else { + // make sure the depend file exists + if (!cmSystemTools::FileExists(dependFileNameFull)) { + // Write an empty dependency file. + cmGeneratedFileStream depFileStream( + dependFileNameFull, false, + this->GlobalGenerator->GetMakefileEncoding()); + depFileStream << "# Empty dependencies file for " + << this->GeneratorTarget->GetName() << ".\n" + << "# This may be replaced when dependencies are built.\n"; } } @@ -381,16 +405,6 @@ void cmMakefileTargetGenerator::WriteCommonCodeRules() << "\n\n"; } - // make sure the depend file exists - if (!cmSystemTools::FileExists(dependFileNameFull)) { - // Write an empty dependency file. - cmGeneratedFileStream depFileStream( - dependFileNameFull, false, this->GlobalGenerator->GetMakefileEncoding()); - depFileStream << "# Empty dependencies file for " - << this->GeneratorTarget->GetName() << ".\n" - << "# This may be replaced when dependencies are built.\n"; - } - // Open the flags file. This should be copy-if-different because the // rules may depend on this file itself. this->FlagFileNameFull = @@ -855,6 +869,7 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles( shellDependencyFile = this->LocalGenerator->ConvertToOutputFormat( depFile, cmOutputConverter::SHELL); vars.DependencyFile = shellDependencyFile.c_str(); + this->CleanFiles.insert(depFile); dependencyTimestamp = this->LocalGenerator->MaybeConvertToRelativePath( this->LocalGenerator->GetBinaryDirectory(), diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx index 620b8ff..49e5e4c 100644 --- a/Source/cmNinjaNormalTargetGenerator.cxx +++ b/Source/cmNinjaNormalTargetGenerator.cxx @@ -12,6 +12,7 @@ #include <utility> #include <cm/memory> +#include <cm/optional> #include <cm/vector> #include "cmComputeLinkInformation.h" @@ -1238,14 +1239,17 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement( std::vector<std::string> preLinkCmdLines; std::vector<std::string> postBuildCmdLines; - if (config == fileConfig) { - std::vector<std::string>* cmdLineLists[3] = { &preLinkCmdLines, - &preLinkCmdLines, - &postBuildCmdLines }; - - for (unsigned i = 0; i != 3; ++i) { - for (cmCustomCommand const& cc : *cmdLists[i]) { - cmCustomCommandGenerator ccg(cc, config, this->GetLocalGenerator()); + std::vector<std::string>* cmdLineLists[3] = { &preLinkCmdLines, + &preLinkCmdLines, + &postBuildCmdLines }; + + for (unsigned i = 0; i != 3; ++i) { + for (cmCustomCommand const& cc : *cmdLists[i]) { + if (config == fileConfig || + this->GetLocalGenerator()->HasUniqueByproducts(cc.GetByproducts(), + cc.GetBacktrace())) { + cmCustomCommandGenerator ccg(cc, fileConfig, this->GetLocalGenerator(), + true, config); localGen.AppendCustomCommandLines(ccg, *cmdLineLists[i]); std::vector<std::string> const& ccByproducts = ccg.GetByproducts(); std::transform(ccByproducts.begin(), ccByproducts.end(), diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index 6a705f4..024356f 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -1255,6 +1255,30 @@ void cmSystemTools::ConvertToOutputSlashes(std::string& path) #endif } +void cmSystemTools::ConvertToLongPath(std::string& path) +{ +#if defined(_WIN32) && !defined(__CYGWIN__) + // Try to convert path to a long path only if the path contains character '~' + if (path.find('~') == std::string::npos) { + return; + } + + std::wstring wPath = cmsys::Encoding::ToWide(path); + DWORD ret = GetLongPathNameW(wPath.c_str(), nullptr, 0); + std::vector<wchar_t> buffer(ret); + if (ret != 0) { + ret = GetLongPathNameW(wPath.c_str(), buffer.data(), + static_cast<DWORD>(buffer.size())); + } + + if (ret != 0) { + path = cmsys::Encoding::ToNarrow(buffer.data()); + } +#else + static_cast<void>(path); +#endif +} + std::string cmSystemTools::ConvertToRunCommandPath(const std::string& path) { #if defined(_WIN32) && !defined(__CYGWIN__) diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h index 1100f05..5bbbb0c 100644 --- a/Source/cmSystemTools.h +++ b/Source/cmSystemTools.h @@ -287,6 +287,12 @@ public: // running cmake needs paths to be in its format static std::string ConvertToRunCommandPath(const std::string& path); + /** + * For windows computes the long path for the given path, + * For Unix, it is a noop + */ + static void ConvertToLongPath(std::string& path); + /** compute the relative path from local to remote. local must be a directory. remote can be a file or a directory. Both remote and local must be full paths. Basically, if diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx index 4c0fbeb..851205e 100644 --- a/Source/cmcmd.cxx +++ b/Source/cmcmd.cxx @@ -231,11 +231,10 @@ private: bool ProcessLine() override { if (cmHasPrefix(this->Line, this->IncludePrefix)) { - this->DepFile << cmCMakePath( - cmTrimWhitespace(this->Line.c_str() + - this->IncludePrefix.size())) - .GenericString() - << std::endl; + auto path = + cmTrimWhitespace(this->Line.c_str() + this->IncludePrefix.size()); + cmSystemTools::ConvertToLongPath(path); + this->DepFile << cmCMakePath(path).GenericString() << std::endl; } else { this->Output << this->Line << std::endl << std::flush; } diff --git a/Tests/RunCMake/CommandLine/trace-expand.cmake b/Tests/RunCMake/CommandLine/trace-expand.cmake index e69de29..24da02a 100644 --- a/Tests/RunCMake/CommandLine/trace-expand.cmake +++ b/Tests/RunCMake/CommandLine/trace-expand.cmake @@ -0,0 +1 @@ +set(a [[\B]]) diff --git a/Tests/RunCMake/NinjaMultiConfig/PostBuild-debug-in-release-graph-build-stdout.txt b/Tests/RunCMake/NinjaMultiConfig/PostBuild-debug-in-release-graph-build-stdout.txt new file mode 100644 index 0000000..fad923a --- /dev/null +++ b/Tests/RunCMake/NinjaMultiConfig/PostBuild-debug-in-release-graph-build-stdout.txt @@ -0,0 +1,2 @@ +Running post-build command with Debug +Generating Debug\.txt diff --git a/Tests/RunCMake/NinjaMultiConfig/PostBuild-release-build-stdout.txt b/Tests/RunCMake/NinjaMultiConfig/PostBuild-release-build-stdout.txt new file mode 100644 index 0000000..485a52c --- /dev/null +++ b/Tests/RunCMake/NinjaMultiConfig/PostBuild-release-build-stdout.txt @@ -0,0 +1,3 @@ +Running post-build command with Release +Generating out\.txt with Release +Generating Release\.txt diff --git a/Tests/RunCMake/NinjaMultiConfig/PostBuild.cmake b/Tests/RunCMake/NinjaMultiConfig/PostBuild.cmake new file mode 100644 index 0000000..5fcff74 --- /dev/null +++ b/Tests/RunCMake/NinjaMultiConfig/PostBuild.cmake @@ -0,0 +1,6 @@ +enable_language(C) + +add_executable(Exe main.c) +add_custom_command(TARGET Exe POST_BUILD COMMAND ${CMAKE_COMMAND} -E echo "Running post-build command with $<CONFIG>") +add_custom_command(TARGET Exe POST_BUILD COMMAND ${CMAKE_COMMAND} -E echo "Generating out.txt with $<CONFIG>" BYPRODUCTS out.txt) +add_custom_command(TARGET Exe POST_BUILD COMMAND ${CMAKE_COMMAND} -E echo "Generating $<CONFIG>.txt" BYPRODUCTS $<CONFIG>.txt) diff --git a/Tests/RunCMake/NinjaMultiConfig/RunCMakeTest.cmake b/Tests/RunCMake/NinjaMultiConfig/RunCMakeTest.cmake index dc2db57..480d628 100644 --- a/Tests/RunCMake/NinjaMultiConfig/RunCMakeTest.cmake +++ b/Tests/RunCMake/NinjaMultiConfig/RunCMakeTest.cmake @@ -187,6 +187,12 @@ run_ninja(SimpleCrossConfigs clean-all-in-release-graph build-Release.ninja clea run_cmake_build(SimpleCrossConfigs all-all-in-release-graph Release all:all) run_cmake_build(SimpleCrossConfigs all-relwithdebinfo-in-release-graph Release all:RelWithDebInfo) +set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/PostBuild-build) +set(RunCMake_TEST_OPTIONS "-DCMAKE_CROSS_CONFIGS=all") +run_cmake_configure(PostBuild) +run_cmake_build(PostBuild release Release Exe) +run_cmake_build(PostBuild debug-in-release-graph Release Exe:Debug) + set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/Framework-build) set(RunCMake_TEST_OPTIONS "-DCMAKE_CROSS_CONFIGS=all") run_cmake_configure(Framework) |