summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarc Chevrier <marc.chevrier@gmail.com>2020-10-18 14:11:27 (GMT)
committerMarc Chevrier <marc.chevrier@gmail.com>2020-11-29 14:25:42 (GMT)
commit2c71d051facad13b0a42a57066be2489d5fff6ea (patch)
treed07f850f8abc74d9df34ad885681c08d36c14472
parentafd0f6785dc1220a07743d31699fcd9097cca46a (diff)
downloadCMake-2c71d051facad13b0a42a57066be2489d5fff6ea.zip
CMake-2c71d051facad13b0a42a57066be2489d5fff6ea.tar.gz
CMake-2c71d051facad13b0a42a57066be2489d5fff6ea.tar.bz2
Makefiles Generators: use compiler for dependencies generation
Each source compilation generates a dependencies file. These dependencies files are consolidated in one file per target. This consolidation is done as part of command 'cmake -E cmake_depends` launched before evaluation of makefile dependency graph. The consolidation uses the same approach as `CMake` dependencies management. Fixes: #21321
-rw-r--r--Help/manual/cmake-variables.7.rst1
-rw-r--r--Help/release/dev/makefiles-dependencies-use-compiler.rst5
-rw-r--r--Help/variable/CMAKE_DEPENDS_USE_COMPILER.rst9
-rw-r--r--Modules/CMakeDetermineCompilerId.cmake5
-rw-r--r--Modules/Compiler/AppleClang-C.cmake12
-rw-r--r--Modules/Compiler/AppleClang-CXX.cmake8
-rw-r--r--Modules/Compiler/AppleClang-OBJC.cmake9
-rw-r--r--Modules/Compiler/AppleClang-OBJCXX.cmake10
-rw-r--r--Modules/Compiler/Clang-C.cmake13
-rw-r--r--Modules/Compiler/Clang-CUDA.cmake6
-rw-r--r--Modules/Compiler/Clang-CXX.cmake13
-rw-r--r--Modules/Compiler/Clang-OBJC.cmake9
-rw-r--r--Modules/Compiler/Clang-OBJCXX.cmake8
-rw-r--r--Modules/Compiler/GNU-C.cmake10
-rw-r--r--Modules/Compiler/GNU-CXX.cmake10
-rw-r--r--Modules/Compiler/GNU-OBJC.cmake9
-rw-r--r--Modules/Compiler/GNU-OBJCXX.cmake9
-rw-r--r--Modules/Compiler/Intel-C.cmake6
-rw-r--r--Modules/Compiler/Intel-CXX.cmake6
-rw-r--r--Modules/Compiler/Intel-ISPC.cmake6
-rw-r--r--Modules/Compiler/NVIDIA-CUDA.cmake8
-rw-r--r--Modules/Platform/Windows-Clang-C.cmake16
-rw-r--r--Modules/Platform/Windows-Clang-CXX.cmake16
-rw-r--r--Modules/Platform/Windows-Intel-C.cmake7
-rw-r--r--Modules/Platform/Windows-Intel-CXX.cmake7
-rw-r--r--Modules/Platform/Windows-MSVC-C.cmake7
-rw-r--r--Modules/Platform/Windows-MSVC-CXX.cmake7
-rw-r--r--Modules/Platform/Windows-MSVC.cmake7
-rw-r--r--Source/CMakeLists.txt2
-rw-r--r--Source/cmDependsCompiler.cxx267
-rw-r--r--Source/cmDependsCompiler.h60
-rw-r--r--Source/cmGlobalUnixMakefileGenerator3.h10
-rw-r--r--Source/cmLocalUnixMakefileGenerator3.cxx529
-rw-r--r--Source/cmMakefileTargetGenerator.cxx155
-rw-r--r--Source/cmcmd.cxx183
-rw-r--r--Tests/BuildDepends/Project/CMakeLists.txt6
-rw-r--r--Tests/IncludeDirectories/CMakeLists.txt6
-rw-r--r--Tests/RunCMake/BuildDepends/CompilerDependencies.cmake46
-rw-r--r--Tests/RunCMake/BuildDepends/CompilerDependencies.step1.cmake9
-rw-r--r--Tests/RunCMake/BuildDepends/CompilerDependencies.step2.cmake3
-rw-r--r--Tests/RunCMake/BuildDepends/RunCMakeTest.cmake10
-rw-r--r--Tests/RunCMake/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/Make/TargetMessages-OFF-build-check.cmake3
-rw-r--r--Tests/RunCMake/Make/TargetMessages-OFF-build-stdout.txt6
-rw-r--r--Tests/RunCMake/Make/TargetMessages-ON-build-check.cmake3
-rw-r--r--Tests/RunCMake/Make/TargetMessages-ON-build-stdout.txt9
-rw-r--r--Tests/RunCMake/Make/TargetMessages-VAR-OFF-build-check.cmake3
-rw-r--r--Tests/RunCMake/Make/TargetMessages-VAR-OFF-build-stdout.txt6
-rw-r--r--Tests/RunCMake/Make/TargetMessages-VAR-ON-build-check.cmake3
-rw-r--r--Tests/RunCMake/Make/TargetMessages-VAR-ON-build-stdout.txt9
-rw-r--r--Tests/RunCMake/Make/TargetMessages-validation.cmake10
-rwxr-xr-xbootstrap2
52 files changed, 1312 insertions, 270 deletions
diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst
index f0c9d99..28cd101 100644
--- a/Help/manual/cmake-variables.7.rst
+++ b/Help/manual/cmake-variables.7.rst
@@ -387,6 +387,7 @@ Variables that Control the Build
/variable/CMAKE_DEFAULT_BUILD_TYPE
/variable/CMAKE_DEFAULT_CONFIGS
/variable/CMAKE_DISABLE_PRECOMPILE_HEADERS
+ /variable/CMAKE_DEPENDS_USE_COMPILER
/variable/CMAKE_ENABLE_EXPORTS
/variable/CMAKE_EXE_LINKER_FLAGS
/variable/CMAKE_EXE_LINKER_FLAGS_CONFIG
diff --git a/Help/release/dev/makefiles-dependencies-use-compiler.rst b/Help/release/dev/makefiles-dependencies-use-compiler.rst
new file mode 100644
index 0000000..8170cda
--- /dev/null
+++ b/Help/release/dev/makefiles-dependencies-use-compiler.rst
@@ -0,0 +1,5 @@
+makefiles-dependencies-use-compiler
+-----------------------------------
+
+* The :ref:`Makefile Generators` gained the capability, for a selection of
+ compilers, to use the compiler itself to generate implicit dependencies.
diff --git a/Help/variable/CMAKE_DEPENDS_USE_COMPILER.rst b/Help/variable/CMAKE_DEPENDS_USE_COMPILER.rst
new file mode 100644
index 0000000..bdad59e
--- /dev/null
+++ b/Help/variable/CMAKE_DEPENDS_USE_COMPILER.rst
@@ -0,0 +1,9 @@
+CMAKE_DEPENDS_USE_COMPILER
+--------------------------
+
+.. versionadded:: 3.20
+
+For the :ref:`Makefile Generators`, source dependencies are now, for a
+selection of compilers, generated by the compiler itself. By defining this
+variable with value ``FALSE``, you can restore the legacy behavior (i.e. using
+``CMake`` for dependencies discovery).
diff --git a/Modules/CMakeDetermineCompilerId.cmake b/Modules/CMakeDetermineCompilerId.cmake
index a982d2c..33ac07e 100644
--- a/Modules/CMakeDetermineCompilerId.cmake
+++ b/Modules/CMakeDetermineCompilerId.cmake
@@ -152,7 +152,10 @@ function(CMAKE_DETERMINE_COMPILER_ID lang flagvar src)
set(CMAKE_EXECUTABLE_FORMAT "Unknown" CACHE INTERNAL "Executable file format")
endif()
- if(CMAKE_GENERATOR MATCHES "^Ninja" AND MSVC_${lang}_ARCHITECTURE_ID)
+ if((CMAKE_GENERATOR MATCHES "^Ninja"
+ OR ((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+ AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"))
+ AND MSVC_${lang}_ARCHITECTURE_ID)
foreach(userflags "${CMAKE_${lang}_COMPILER_ID_FLAGS_LIST}" "")
CMAKE_DETERMINE_MSVC_SHOWINCLUDES_PREFIX(${lang} "${userflags}")
endforeach()
diff --git a/Modules/Compiler/AppleClang-C.cmake b/Modules/Compiler/AppleClang-C.cmake
index 2794f52..02d10d3 100644
--- a/Modules/Compiler/AppleClang-C.cmake
+++ b/Modules/Compiler/AppleClang-C.cmake
@@ -1,6 +1,18 @@
include(Compiler/Clang)
__compiler_clang(C)
+
+if(NOT "x${CMAKE_C_SIMULATE_ID}" STREQUAL "xMSVC")
+ if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+ AND CMAKE_GENERATOR MATCHES "Makefiles"
+ AND CMAKE_DEPFILE_FLAGS_C)
+ # dependencies are computed by the compiler itself
+ set(CMAKE_C_DEPFILE_FORMAT gcc)
+ set(CMAKE_C_DEPENDS_USE_COMPILER TRUE)
+ endif()
+endif()
+
+
if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.0)
set(CMAKE_C90_STANDARD_COMPILE_OPTION "-std=c90")
set(CMAKE_C90_EXTENSION_COMPILE_OPTION "-std=gnu90")
diff --git a/Modules/Compiler/AppleClang-CXX.cmake b/Modules/Compiler/AppleClang-CXX.cmake
index 15edc21..5282077 100644
--- a/Modules/Compiler/AppleClang-CXX.cmake
+++ b/Modules/Compiler/AppleClang-CXX.cmake
@@ -2,6 +2,14 @@ include(Compiler/Clang)
__compiler_clang(CXX)
if(NOT "x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC")
+ if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+ AND CMAKE_GENERATOR MATCHES "Makefiles"
+ AND CMAKE_DEPFILE_FLAGS_CXX)
+ # dependencies are computed by the compiler itself
+ set(CMAKE_CXX_DEPFILE_FORMAT gcc)
+ set(CMAKE_CXX_DEPENDS_USE_COMPILER TRUE)
+ endif()
+
set(CMAKE_CXX_COMPILE_OPTIONS_VISIBILITY_INLINES_HIDDEN "-fvisibility-inlines-hidden")
endif()
diff --git a/Modules/Compiler/AppleClang-OBJC.cmake b/Modules/Compiler/AppleClang-OBJC.cmake
index d1f3706..d4eab4f 100644
--- a/Modules/Compiler/AppleClang-OBJC.cmake
+++ b/Modules/Compiler/AppleClang-OBJC.cmake
@@ -1,5 +1,14 @@
include(Compiler/Clang-OBJC)
+if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+ AND CMAKE_GENERATOR MATCHES "Makefiles"
+ AND CMAKE_DEPFILE_FLAGS_OBJC)
+ # dependencies are computed by the compiler itself
+ set(CMAKE_OBJC_DEPFILE_FORMAT gcc)
+ set(CMAKE_OBJC_DEPENDS_USE_COMPILER TRUE)
+endif()
+
+
if(NOT CMAKE_OBJC_COMPILER_VERSION VERSION_LESS 4.0)
set(CMAKE_OBJC90_STANDARD_COMPILE_OPTION "-std=c90")
set(CMAKE_OBJC90_EXTENSION_COMPILE_OPTION "-std=gnu90")
diff --git a/Modules/Compiler/AppleClang-OBJCXX.cmake b/Modules/Compiler/AppleClang-OBJCXX.cmake
index 409bd4a..172a343 100644
--- a/Modules/Compiler/AppleClang-OBJCXX.cmake
+++ b/Modules/Compiler/AppleClang-OBJCXX.cmake
@@ -1,5 +1,15 @@
include(Compiler/Clang-OBJCXX)
+
+if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+ AND CMAKE_GENERATOR MATCHES "Makefiles"
+ AND CMAKE_DEPFILE_FLAGS_OBJCXX)
+ # dependencies are computed by the compiler itself
+ set(CMAKE_OBJCXX_DEPFILE_FORMAT gcc)
+ set(CMAKE_OBJCXX_DEPENDS_USE_COMPILER TRUE)
+endif()
+
+
set(CMAKE_OBJCXX_COMPILE_OPTIONS_VISIBILITY_INLINES_HIDDEN "-fvisibility-inlines-hidden")
if(NOT CMAKE_OBJCXX_COMPILER_VERSION VERSION_LESS 4.0)
diff --git a/Modules/Compiler/Clang-C.cmake b/Modules/Compiler/Clang-C.cmake
index 7c4a263..a631ac0 100644
--- a/Modules/Compiler/Clang-C.cmake
+++ b/Modules/Compiler/Clang-C.cmake
@@ -8,6 +8,19 @@ endif()
if("x${CMAKE_C_COMPILER_FRONTEND_VARIANT}" STREQUAL "xMSVC")
set(CMAKE_C_CLANG_TIDY_DRIVER_MODE "cl")
+ if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+ AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
+ AND CMAKE_DEPFILE_FLAGS_C)
+ set(CMAKE_C_DEPENDS_USE_COMPILER TRUE)
+ endif()
+elseif("x${CMAKE_C_COMPILER_FRONTEND_VARIANT}" STREQUAL "xGNU")
+ if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+ AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
+ AND CMAKE_DEPFILE_FLAGS_C)
+ # dependencies are computed by the compiler itself
+ set(CMAKE_C_DEPFILE_FORMAT gcc)
+ set(CMAKE_C_DEPENDS_USE_COMPILER TRUE)
+ endif()
endif()
if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 3.4)
diff --git a/Modules/Compiler/Clang-CUDA.cmake b/Modules/Compiler/Clang-CUDA.cmake
index b6155bd..cafc7dd 100644
--- a/Modules/Compiler/Clang-CUDA.cmake
+++ b/Modules/Compiler/Clang-CUDA.cmake
@@ -3,6 +3,12 @@ __compiler_clang(CUDA)
# Set explicitly, because __compiler_clang() doesn't set this if we're simulating MSVC.
set(CMAKE_DEPFILE_FLAGS_CUDA "-MD -MT <DEP_TARGET> -MF <DEP_FILE>")
+if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+ AND CMAKE_GENERATOR MATCHES "Makefiles|WMake")
+ # dependencies are computed by the compiler itself
+ set(CMAKE_CUDA_DEPFILE_FORMAT gcc)
+ set(CMAKE_CUDA_DEPENDS_USE_COMPILER TRUE)
+endif()
# C++03 isn't supported for CXX, but is for CUDA, so we need to set these manually.
# Do this before __compiler_clang_cxx_standards() since that adds the feature.
diff --git a/Modules/Compiler/Clang-CXX.cmake b/Modules/Compiler/Clang-CXX.cmake
index 789e991..430a91c 100644
--- a/Modules/Compiler/Clang-CXX.cmake
+++ b/Modules/Compiler/Clang-CXX.cmake
@@ -3,6 +3,14 @@ __compiler_clang(CXX)
__compiler_clang_cxx_standards(CXX)
if("x${CMAKE_CXX_COMPILER_FRONTEND_VARIANT}" STREQUAL "xGNU")
+ if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+ AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
+ AND CMAKE_DEPFILE_FLAGS_CXX)
+ # dependencies are computed by the compiler itself
+ set(CMAKE_CXX_DEPFILE_FORMAT gcc)
+ set(CMAKE_CXX_DEPENDS_USE_COMPILER TRUE)
+ endif()
+
set(CMAKE_CXX_COMPILE_OPTIONS_VISIBILITY_INLINES_HIDDEN "-fvisibility-inlines-hidden")
endif()
@@ -13,4 +21,9 @@ endif()
if("x${CMAKE_CXX_COMPILER_FRONTEND_VARIANT}" STREQUAL "xMSVC")
set(CMAKE_CXX_CLANG_TIDY_DRIVER_MODE "cl")
+ if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+ AND CMAKE_GENERATOR MATCHES "Makefiles"
+ AND CMAKE_DEPFILE_FLAGS_CXX)
+ set(CMAKE_CXX_DEPENDS_USE_COMPILER TRUE)
+ endif()
endif()
diff --git a/Modules/Compiler/Clang-OBJC.cmake b/Modules/Compiler/Clang-OBJC.cmake
index c61c497..19179e3 100644
--- a/Modules/Compiler/Clang-OBJC.cmake
+++ b/Modules/Compiler/Clang-OBJC.cmake
@@ -1,6 +1,15 @@
include(Compiler/Clang)
__compiler_clang(OBJC)
+if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+ AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
+ AND CMAKE_DEPFILE_FLAGS_OBJC)
+ # dependencies are computed by the compiler itself
+ set(CMAKE_OBJC_DEPFILE_FORMAT gcc)
+ set(CMAKE_OBJC_DEPENDS_USE_COMPILER TRUE)
+endif()
+
+
if(NOT CMAKE_OBJC_COMPILER_VERSION VERSION_LESS 3.4)
set(CMAKE_OBJC90_STANDARD_COMPILE_OPTION "-std=c90")
set(CMAKE_OBJC90_EXTENSION_COMPILE_OPTION "-std=gnu90")
diff --git a/Modules/Compiler/Clang-OBJCXX.cmake b/Modules/Compiler/Clang-OBJCXX.cmake
index 453b5fd..9bdff66 100644
--- a/Modules/Compiler/Clang-OBJCXX.cmake
+++ b/Modules/Compiler/Clang-OBJCXX.cmake
@@ -1,3 +1,11 @@
include(Compiler/Clang)
__compiler_clang(OBJCXX)
__compiler_clang_cxx_standards(OBJCXX)
+
+if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+ AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
+ AND CMAKE_DEPFILE_FLAGS_OBJCXX)
+ # dependencies are computed by the compiler itself
+ set(CMAKE_OBJCXX_DEPFILE_FORMAT gcc)
+ set(CMAKE_OBJCXX_DEPENDS_USE_COMPILER TRUE)
+endif()
diff --git a/Modules/Compiler/GNU-C.cmake b/Modules/Compiler/GNU-C.cmake
index ca286b3..1e6b61d 100644
--- a/Modules/Compiler/GNU-C.cmake
+++ b/Modules/Compiler/GNU-C.cmake
@@ -1,6 +1,16 @@
include(Compiler/GNU)
__compiler_gnu(C)
+
+if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+ AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
+ AND CMAKE_DEPFILE_FLAGS_C)
+ # dependencies are computed by the compiler itself
+ set(CMAKE_C_DEPFILE_FORMAT gcc)
+ set(CMAKE_C_DEPENDS_USE_COMPILER TRUE)
+endif()
+
+
if (NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.5)
set(CMAKE_C90_STANDARD_COMPILE_OPTION "-std=c90")
set(CMAKE_C90_EXTENSION_COMPILE_OPTION "-std=gnu90")
diff --git a/Modules/Compiler/GNU-CXX.cmake b/Modules/Compiler/GNU-CXX.cmake
index fcaaeab..24be2d7 100644
--- a/Modules/Compiler/GNU-CXX.cmake
+++ b/Modules/Compiler/GNU-CXX.cmake
@@ -1,6 +1,16 @@
include(Compiler/GNU)
__compiler_gnu(CXX)
+
+if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+ AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
+ AND CMAKE_DEPFILE_FLAGS_CXX)
+ # dependencies are computed by the compiler itself
+ set(CMAKE_CXX_DEPFILE_FORMAT gcc)
+ set(CMAKE_CXX_DEPENDS_USE_COMPILER TRUE)
+endif()
+
+
if (WIN32)
if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.6)
set(CMAKE_CXX_COMPILE_OPTIONS_VISIBILITY_INLINES_HIDDEN "-fno-keep-inline-dllexport")
diff --git a/Modules/Compiler/GNU-OBJC.cmake b/Modules/Compiler/GNU-OBJC.cmake
index fb9b0b2..7eeed83 100644
--- a/Modules/Compiler/GNU-OBJC.cmake
+++ b/Modules/Compiler/GNU-OBJC.cmake
@@ -1,2 +1,11 @@
include(Compiler/GNU)
__compiler_gnu(OBJC)
+
+
+if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+ AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
+ AND CMAKE_DEPFILE_FLAGS_OBJC)
+ # dependencies are computed by the compiler itself
+ set(CMAKE_OBJC_DEPFILE_FORMAT gcc)
+ set(CMAKE_OBJC_DEPENDS_USE_COMPILER TRUE)
+endif()
diff --git a/Modules/Compiler/GNU-OBJCXX.cmake b/Modules/Compiler/GNU-OBJCXX.cmake
index 06f0244..1047b5d 100644
--- a/Modules/Compiler/GNU-OBJCXX.cmake
+++ b/Modules/Compiler/GNU-OBJCXX.cmake
@@ -1,6 +1,15 @@
include(Compiler/GNU)
__compiler_gnu(OBJCXX)
+if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+ AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
+ AND CMAKE_DEPFILE_FLAGS_OBJCXX)
+ # dependencies are computed by the compiler itself
+ set(CMAKE_OBJCXX_DEPFILE_FORMAT gcc)
+ set(CMAKE_OBJCXX_DEPENDS_USE_COMPILER TRUE)
+endif()
+
+
if(NOT CMAKE_OBJCXX_COMPILER_VERSION VERSION_LESS 4.2)
set(CMAKE_OBJCXX_COMPILE_OPTIONS_VISIBILITY_INLINES_HIDDEN "-fvisibility-inlines-hidden")
endif()
diff --git a/Modules/Compiler/Intel-C.cmake b/Modules/Compiler/Intel-C.cmake
index 0a3ab54..a7c71bd 100644
--- a/Modules/Compiler/Intel-C.cmake
+++ b/Modules/Compiler/Intel-C.cmake
@@ -6,6 +6,12 @@ string(APPEND CMAKE_C_FLAGS_RELEASE_INIT " -DNDEBUG")
string(APPEND CMAKE_C_FLAGS_RELWITHDEBINFO_INIT " -DNDEBUG")
set(CMAKE_DEPFILE_FLAGS_C "-MD -MT <DEP_TARGET> -MF <DEP_FILE>")
+if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+ AND CMAKE_GENERATOR MATCHES "Makefiles|WMake")
+ # dependencies are computed by the compiler itself
+ set(CMAKE_C_DEPFILE_FORMAT gcc)
+ set(CMAKE_C_DEPENDS_USE_COMPILER TRUE)
+endif()
if("x${CMAKE_C_SIMULATE_ID}" STREQUAL "xMSVC")
diff --git a/Modules/Compiler/Intel-CXX.cmake b/Modules/Compiler/Intel-CXX.cmake
index 76d0aec..dd9681e 100644
--- a/Modules/Compiler/Intel-CXX.cmake
+++ b/Modules/Compiler/Intel-CXX.cmake
@@ -6,6 +6,12 @@ string(APPEND CMAKE_CXX_FLAGS_RELEASE_INIT " -DNDEBUG")
string(APPEND CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT " -DNDEBUG")
set(CMAKE_DEPFILE_FLAGS_CXX "-MD -MT <DEP_TARGET> -MF <DEP_FILE>")
+if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+ AND CMAKE_GENERATOR MATCHES "Makefiles|WMake")
+ # dependencies are computed by the compiler itself
+ set(CMAKE_CXX_DEPFILE_FORMAT gcc)
+ set(CMAKE_CXX_DEPENDS_USE_COMPILER TRUE)
+endif()
if("x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC")
diff --git a/Modules/Compiler/Intel-ISPC.cmake b/Modules/Compiler/Intel-ISPC.cmake
index 66b26d7..e4d5c97 100644
--- a/Modules/Compiler/Intel-ISPC.cmake
+++ b/Modules/Compiler/Intel-ISPC.cmake
@@ -4,6 +4,12 @@ include(Compiler/CMakeCommonCompilerMacros)
#set(CMAKE_ISPC_VERBOSE_FLAG )
set(CMAKE_DEPFILE_FLAGS_ISPC "-M -MT <DEP_TARGET> -MF <DEP_FILE>")
+if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+ AND CMAKE_GENERATOR MATCHES "Makefiles|WMake")
+ # dependencies are computed by the compiler itself
+ set(CMAKE_ISPC_DEPFILE_FORMAT gcc)
+ set(CMAKE_ISPC_DEPENDS_USE_COMPILER TRUE)
+endif()
string(APPEND CMAKE_ISPC_FLAGS_INIT " ")
string(APPEND CMAKE_ISPC_FLAGS_DEBUG_INIT "-O0 -g")
diff --git a/Modules/Compiler/NVIDIA-CUDA.cmake b/Modules/Compiler/NVIDIA-CUDA.cmake
index 464c208..3e8d4eb 100644
--- a/Modules/Compiler/NVIDIA-CUDA.cmake
+++ b/Modules/Compiler/NVIDIA-CUDA.cmake
@@ -30,6 +30,14 @@ if (CMAKE_CUDA_COMPILER_VERSION VERSION_GREATER_EQUAL 10.2.89)
# to get header dependency information
set(CMAKE_DEPFILE_FLAGS_CUDA "-MD -MT <DEP_TARGET> -MF <DEP_FILE>")
endif()
+if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+ AND CMAKE_GENERATOR MATCHES "Makefiles|WMake")
+ if (NOT CMAKE_DEPFILE_FLAGS_CUDA)
+ set(CMAKE_CUDA_DEPENDS_EXTRA_COMMANDS "<CMAKE_CUDA_COMPILER> ${_CMAKE_CUDA_EXTRA_FLAGS} <DEFINES> <INCLUDES> <FLAGS> ${_CMAKE_COMPILE_AS_CUDA_FLAG} -M <SOURCE> -MT <OBJECT> -o <DEP_FILE>")
+ endif()
+ set(CMAKE_CUDA_DEPFILE_FORMAT gcc)
+ set(CMAKE_CUDA_DEPENDS_USE_COMPILER TRUE)
+endif()
if(NOT "x${CMAKE_CUDA_SIMULATE_ID}" STREQUAL "xMSVC")
set(CMAKE_CUDA_COMPILE_OPTIONS_PIE -Xcompiler=-fPIE)
diff --git a/Modules/Platform/Windows-Clang-C.cmake b/Modules/Platform/Windows-Clang-C.cmake
index d007105..322e3fb 100644
--- a/Modules/Platform/Windows-Clang-C.cmake
+++ b/Modules/Platform/Windows-Clang-C.cmake
@@ -1,2 +1,18 @@
include(Platform/Windows-Clang)
__windows_compiler_clang(C)
+
+if("x${MAKE_C_COMPILER_FRONTEND_VARIANT}" STREQUAL "xMSVC")
+ if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+ AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
+ AND CMAKE_DEPFILE_FLAGS_C)
+ set(CMAKE_C_DEPENDS_USE_COMPILER TRUE)
+ endif()
+elseif("x${CMAKE_C_COMPILER_FRONTEND_VARIANT}" STREQUAL "xGNU")
+ if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+ AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
+ AND CMAKE_DEPFILE_FLAGS_C)
+ # dependencies are computed by the compiler itself
+ set(CMAKE_C_DEPFILE_FORMAT gcc)
+ set(CMAKE_C_DEPENDS_USE_COMPILER TRUE)
+ endif()
+endif()
diff --git a/Modules/Platform/Windows-Clang-CXX.cmake b/Modules/Platform/Windows-Clang-CXX.cmake
index f1d40f2..b4aaf1e 100644
--- a/Modules/Platform/Windows-Clang-CXX.cmake
+++ b/Modules/Platform/Windows-Clang-CXX.cmake
@@ -1,3 +1,19 @@
include(Platform/Windows-Clang)
set(_COMPILE_CXX_MSVC " -TP")
__windows_compiler_clang(CXX)
+
+if("x${MAKE_CXX_COMPILER_FRONTEND_VARIANT}" STREQUAL "xMSVC")
+ if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+ AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
+ AND CMAKE_DEPFILE_FLAGS_CXX)
+ set(CMAKE_CXX_DEPENDS_USE_COMPILER TRUE)
+ endif()
+elseif("x${CMAKE_CXX_COMPILER_FRONTEND_VARIANT}" STREQUAL "xGNU")
+ if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+ AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
+ AND CMAKE_DEPFILE_FLAGS_CXX)
+ # dependencies are computed by the compiler itself
+ set(CMAKE_CXX_DEPFILE_FORMAT gcc)
+ set(CMAKE_CXX_DEPENDS_USE_COMPILER TRUE)
+ endif()
+endif()
diff --git a/Modules/Platform/Windows-Intel-C.cmake b/Modules/Platform/Windows-Intel-C.cmake
index f3aa851..3cbc7a5 100644
--- a/Modules/Platform/Windows-Intel-C.cmake
+++ b/Modules/Platform/Windows-Intel-C.cmake
@@ -2,3 +2,10 @@ include(Platform/Windows-Intel)
__windows_compiler_intel(C)
set(CMAKE_NINJA_DEPTYPE_C intel) # special value handled by CMake
set(CMAKE_DEPFILE_FLAGS_C "-QMMD -QMT <DEP_TARGET> -QMF <DEP_FILE>")
+
+if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+ AND CMAKE_GENERATOR MATCHES "Makefiles|WMake")
+ # dependencies are computed by the compiler itself
+ set(CMAKE_C_DEPFILE_FORMAT gcc)
+ set(CMAKE_C_DEPENDS_USE_COMPILER TRUE)
+endif()
diff --git a/Modules/Platform/Windows-Intel-CXX.cmake b/Modules/Platform/Windows-Intel-CXX.cmake
index f0b15b1..6539f64 100644
--- a/Modules/Platform/Windows-Intel-CXX.cmake
+++ b/Modules/Platform/Windows-Intel-CXX.cmake
@@ -3,3 +3,10 @@ set(_COMPILE_CXX " /TP")
__windows_compiler_intel(CXX)
set(CMAKE_NINJA_DEPTYPE_CXX intel) # special value handled by CMake
set(CMAKE_DEPFILE_FLAGS_CXX "-QMMD -QMT <DEP_TARGET> -QMF <DEP_FILE>")
+
+if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+ AND CMAKE_GENERATOR MATCHES "Makefiles|WMake")
+ # dependencies are computed by the compiler itself
+ set(CMAKE_CXX_DEPFILE_FORMAT gcc)
+ set(CMAKE_CXX_DEPENDS_USE_COMPILER TRUE)
+endif()
diff --git a/Modules/Platform/Windows-MSVC-C.cmake b/Modules/Platform/Windows-MSVC-C.cmake
index cbe1586..67b6827 100644
--- a/Modules/Platform/Windows-MSVC-C.cmake
+++ b/Modules/Platform/Windows-MSVC-C.cmake
@@ -3,3 +3,10 @@ if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 18.0)
set(_FS_C " /FS")
endif()
__windows_compiler_msvc(C)
+
+if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+ AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
+ AND CMAKE_DEPFILE_FLAGS_C)
+ # dependencies are computed by the compiler itself
+ set(CMAKE_C_DEPENDS_USE_COMPILER TRUE)
+endif()
diff --git a/Modules/Platform/Windows-MSVC-CXX.cmake b/Modules/Platform/Windows-MSVC-CXX.cmake
index 0e85005..6fea617 100644
--- a/Modules/Platform/Windows-MSVC-CXX.cmake
+++ b/Modules/Platform/Windows-MSVC-CXX.cmake
@@ -4,3 +4,10 @@ if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 18.0)
set(_FS_CXX " /FS")
endif()
__windows_compiler_msvc(CXX)
+
+if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+ AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
+ AND CMAKE_DEPFILE_FLAGS_CXX)
+ # dependencies are computed by the compiler itself
+ set(CMAKE_CXX_DEPENDS_USE_COMPILER TRUE)
+endif()
diff --git a/Modules/Platform/Windows-MSVC.cmake b/Modules/Platform/Windows-MSVC.cmake
index 3f65475..ec5758c 100644
--- a/Modules/Platform/Windows-MSVC.cmake
+++ b/Modules/Platform/Windows-MSVC.cmake
@@ -437,6 +437,13 @@ macro(__windows_compiler_msvc lang)
set(CMAKE_${lang}_LINKER_SUPPORTS_PDB ON)
set(CMAKE_NINJA_DEPTYPE_${lang} msvc)
__windows_compiler_msvc_enable_rc("${_PLATFORM_DEFINES} ${_PLATFORM_DEFINES_${lang}}")
+
+ # define generic information about compiler dependencies
+ # activation is done on per language platform configuration basis
+ if (MSVC_VERSION GREATER 1300)
+ set(CMAKE_DEPFILE_FLAGS_${lang} "/showIncludes")
+ set(CMAKE_${lang}_DEPFILE_FORMAT msvc)
+ endif()
endmacro()
macro(__windows_compiler_msvc_enable_rc flags)
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index d1616ad..8d022eb 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -224,6 +224,8 @@ set(SRCS
cmDependsJava.h
cmDependsJavaParserHelper.cxx
cmDependsJavaParserHelper.h
+ cmDependsCompiler.cxx
+ cmDependsCompiler.h
cmDocumentation.cxx
cmDocumentationFormatter.cxx
cmDocumentationSection.cxx
diff --git a/Source/cmDependsCompiler.cxx b/Source/cmDependsCompiler.cxx
new file mode 100644
index 0000000..eb0f1d5
--- /dev/null
+++ b/Source/cmDependsCompiler.cxx
@@ -0,0 +1,267 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include "cmDependsCompiler.h"
+
+#include <algorithm>
+#include <map>
+#include <string>
+#include <unordered_set>
+#include <utility>
+
+#include <cm/string_view>
+#include <cm/vector>
+#include <cmext/string_view>
+
+#include "cmsys/FStream.hxx"
+
+#include "cmFileTime.h"
+#include "cmGlobalUnixMakefileGenerator3.h"
+#include "cmLocalUnixMakefileGenerator3.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+namespace {
+std::string& ReplaceAll(std::string& data, const std::string& toSearch,
+ const std::string& replaceStr)
+{
+ // Get the first occurrence
+ auto pos = data.find(toSearch);
+ // Repeat until the end is reached
+ while (pos != std::string::npos) {
+ // Replace this occurrence of Sub String
+ data.replace(pos, toSearch.size(), replaceStr);
+ // Get the next occurrence from the current position
+ pos = data.find(toSearch, pos + replaceStr.size());
+ }
+
+ return data;
+}
+
+std::string& NormalizePath(std::string& item)
+{
+ ReplaceAll(item, "$$", "$");
+ ReplaceAll(item, "\\ ", " ");
+ ReplaceAll(item, "\\#", "#");
+ ReplaceAll(item, "\\", "/");
+
+ return item;
+}
+
+void ParseLine(const std::string& line, std::vector<std::string>& depends)
+{
+ auto start = line.find_first_not_of(' ');
+ if (start == std::string::npos || line[start] == '#') {
+ return;
+ }
+
+ auto index = start;
+ while ((index = line.find(' ', index)) != std::string::npos) {
+ if (line[index - 1] == '\\') {
+ index += 1;
+ continue;
+ }
+
+ auto item = line.substr(start, index - start);
+ if (item.back() != ':') {
+ // check that ':' is not present after some spaces
+ auto index2 = line.find_first_not_of(' ', index + 1);
+ if (index2 == std::string::npos || line[index2] != ':') {
+ // this is a dependency, add it
+ depends.emplace_back(std::move(NormalizePath(item)));
+ } else {
+ index = index2;
+ }
+ }
+
+ start = line.find_first_not_of(' ', index + 1);
+ index = start;
+ }
+ if (start != std::string::npos) {
+ auto item = line.substr(start);
+ if (line.back() != ':') {
+ // this is a dependency, add it
+ depends.emplace_back(std::move(NormalizePath(item)));
+ }
+ }
+}
+}
+
+bool cmDependsCompiler::CheckDependencies(
+ const std::string& internalDepFile, const std::vector<std::string>& depFiles,
+ cmDepends::DependencyMap& dependencies,
+ const std::function<bool(const std::string&)>& isValidPath)
+{
+ bool status = true;
+ bool forceReadDeps = true;
+
+ cmFileTime internalDepFileTime;
+ // read cached dependencies stored in internal file
+ if (cmSystemTools::FileExists(internalDepFile)) {
+ internalDepFileTime.Load(internalDepFile);
+ forceReadDeps = false;
+
+ // read current dependencies
+ cmsys::ifstream fin(internalDepFile.c_str());
+ if (fin) {
+ std::string line;
+ std::string depender;
+ std::vector<std::string>* currentDependencies = nullptr;
+ while (std::getline(fin, line)) {
+ if (line.empty() || line.front() == '#') {
+ continue;
+ }
+ // Drop carriage return character at the end
+ if (line.back() == '\r') {
+ line.pop_back();
+ if (line.empty()) {
+ continue;
+ }
+ }
+ // Check if this a depender line
+ if (line.front() != ' ') {
+ depender = std::move(line);
+ currentDependencies = &dependencies[depender];
+ continue;
+ }
+ // This is a dependee line
+ if (currentDependencies != nullptr) {
+ currentDependencies->emplace_back(line.substr(1));
+ }
+ }
+ fin.close();
+ }
+ }
+
+ // Now, update dependencies map with all new compiler generated
+ // dependencies files
+ cmFileTime depFileTime;
+ for (auto dep = depFiles.begin(); dep != depFiles.end(); dep++) {
+ const auto& source = *dep++;
+ const auto& target = *dep++;
+ const auto& format = *dep++;
+ const auto& depFile = *dep;
+
+ if (!cmSystemTools::FileExists(depFile)) {
+ continue;
+ }
+
+ if (!forceReadDeps) {
+ depFileTime.Load(depFile);
+ }
+ if (forceReadDeps || depFileTime.Newer(internalDepFileTime)) {
+ status = false;
+ if (this->Verbose) {
+ cmSystemTools::Stdout(cmStrCat("Dependencies file \"", depFile,
+ "\" is newer than depends file \"",
+ internalDepFile, "\".\n"));
+ }
+ cmsys::ifstream fin(depFile.c_str());
+ if (!fin) {
+ continue;
+ }
+
+ std::vector<std::string> depends;
+ std::string line;
+ if (format == "msvc"_s) {
+ if (!isValidPath) {
+ // insert source as first dependency
+ depends.push_back(source);
+ }
+ while (cmSystemTools::GetLineFromStream(fin, line)) {
+ depends.emplace_back(std::move(line));
+ }
+ } else {
+ while (cmSystemTools::GetLineFromStream(fin, line)) {
+ if (line.empty()) {
+ continue;
+ }
+ if (line.back() == '\\') {
+ line.pop_back();
+ }
+ ParseLine(line, depends);
+ }
+
+ // depending of the effective format of the dependencies file generated
+ // by the compiler, the target can be wrongly identified as a
+ // dependency so remove it from the list
+ if (depends.front() == target) {
+ depends.erase(depends.begin());
+ }
+
+ if (isValidPath) {
+ // remove first dependency because it must not be filtered out
+ depends.erase(depends.begin());
+ }
+ }
+
+ if (isValidPath) {
+ cm::erase_if(depends, isValidPath);
+ // insert source as first dependency
+ depends.insert(depends.begin(), source);
+ }
+
+ dependencies[target] = std::move(depends);
+ }
+ }
+
+ return status;
+}
+
+void cmDependsCompiler::WriteDependencies(
+ const cmDepends::DependencyMap& dependencies, std::ostream& makeDepends,
+ std::ostream& internalDepends)
+{
+ // dependencies file consumed by make tool
+ const auto& lineContinue = static_cast<cmGlobalUnixMakefileGenerator3*>(
+ this->LocalGenerator->GetGlobalGenerator())
+ ->LineContinueDirective;
+ const auto& binDir = this->LocalGenerator->GetBinaryDirectory();
+ cmDepends::DependencyMap makeDependencies(dependencies);
+ std::unordered_set<cm::string_view> phonyTargets;
+
+ // external dependencies file
+ for (auto& node : makeDependencies) {
+ auto& deps = node.second;
+ std::transform(
+ deps.cbegin(), deps.cend(), deps.begin(),
+ [this, &binDir](const std::string& dep) {
+ return LocalGenerator->ConvertToMakefilePath(
+ this->LocalGenerator->MaybeConvertToRelativePath(binDir, dep));
+ });
+
+ makeDepends << this->LocalGenerator->ConvertToMakefilePath(node.first)
+ << ": " << deps.front();
+ // first dependency is the source, remove it because should not be declared
+ // as phony target
+ deps.erase(deps.begin());
+ for (const auto& dep : deps) {
+ makeDepends << ' ' << lineContinue << " " << dep;
+ phonyTargets.emplace(dep.data(), dep.length());
+ }
+ makeDepends << std::endl << std::endl;
+ }
+
+ // add phony targets
+ for (const auto& target : phonyTargets) {
+ makeDepends << std::endl << target << ':' << std::endl;
+ }
+
+ // internal dependencies file
+ for (const auto& node : dependencies) {
+ internalDepends << node.first << std::endl;
+ for (const auto& dep : node.second) {
+ internalDepends << ' ' << dep << std::endl;
+ }
+ internalDepends << std::endl;
+ }
+}
+
+void cmDependsCompiler::ClearDependencies(
+ const std::vector<std::string>& depFiles)
+{
+ for (auto dep = depFiles.begin(); dep != depFiles.end(); dep++) {
+ dep += 3;
+ cmSystemTools::RemoveFile(*dep);
+ }
+}
diff --git a/Source/cmDependsCompiler.h b/Source/cmDependsCompiler.h
new file mode 100644
index 0000000..838156d
--- /dev/null
+++ b/Source/cmDependsCompiler.h
@@ -0,0 +1,60 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <functional>
+#include <iosfwd>
+#include <string>
+#include <vector>
+
+#include "cmDepends.h"
+
+class cmLocalUnixMakefileGenerator3;
+
+/** \class cmDepends
+ * \brief Dependencies files manager.
+ *
+ * This class is responsible for maintaining a compiler_depends.make file in
+ * the build tree corresponding to an object file.
+ */
+class cmDependsCompiler
+{
+public:
+ cmDependsCompiler() = default;
+ ~cmDependsCompiler() = default;
+
+ /** should this be verbose in its output */
+ void SetVerbose(bool verb) { this->Verbose = verb; }
+
+ /** Set the local generator for the directory in which we are
+ scanning dependencies. This is not a full local generator; it
+ has been setup to do relative path conversions for the current
+ directory. */
+ void SetLocalGenerator(cmLocalUnixMakefileGenerator3* lg)
+ {
+ this->LocalGenerator = lg;
+ }
+
+ /** Read dependencies for the target file. Return true if
+ dependencies didn't changed and false if not.
+ Up-to-date Dependencies will be stored in deps. */
+ bool CheckDependencies(
+ const std::string& internalDepFile,
+ const std::vector<std::string>& depFiles,
+ cmDepends::DependencyMap& dependencies,
+ const std::function<bool(const std::string&)>& isValidPath);
+
+ /** Write dependencies for the target file. */
+ void WriteDependencies(const cmDepends::DependencyMap& dependencies,
+ std::ostream& makeDepends,
+ std::ostream& internalDepends);
+
+ /** Clear dependencies for the target so they will be regenerated. */
+ void ClearDependencies(const std::vector<std::string>& depFiles);
+
+private:
+ bool Verbose = false;
+ cmLocalUnixMakefileGenerator3* LocalGenerator = nullptr;
+};
diff --git a/Source/cmGlobalUnixMakefileGenerator3.h b/Source/cmGlobalUnixMakefileGenerator3.h
index 5d12831..6459771 100644
--- a/Source/cmGlobalUnixMakefileGenerator3.h
+++ b/Source/cmGlobalUnixMakefileGenerator3.h
@@ -127,6 +127,12 @@ public:
void WriteConvenienceRules(std::ostream& ruleFileStream,
std::set<std::string>& emitted);
+ // Make tool supports dependency files generated by compiler
+ bool SupportsCompilerDependencies()
+ {
+ return this->ToolSupportsCompilerDependencies;
+ }
+
/** Get the command to use for a target that has no rule. This is
used for multiple output dependencies and for cmake_force. */
std::string GetEmptyRuleHackCommand() { return this->EmptyRuleHackCommand; }
@@ -219,6 +225,10 @@ protected:
bool CheckALLOW_DUPLICATE_CUSTOM_TARGETS() const override { return true; }
+ // Specify if the make tool is able to consume dependency files
+ // generated by the compiler
+ bool ToolSupportsCompilerDependencies = true;
+
// Some make programs (Borland) do not keep a rule if there are no
// dependencies or commands. This is a problem for creating rules
// that might not do anything but might have other dependencies
diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx
index 3654e8f..08cefb7 100644
--- a/Source/cmLocalUnixMakefileGenerator3.cxx
+++ b/Source/cmLocalUnixMakefileGenerator3.cxx
@@ -5,6 +5,7 @@
#include <algorithm>
#include <cassert>
#include <cstdio>
+#include <functional>
#include <sstream>
#include <utility>
@@ -19,6 +20,7 @@
#include "cmCMakePath.h"
#include "cmCustomCommand.h" // IWYU pragma: keep
#include "cmCustomCommandGenerator.h"
+#include "cmDependsCompiler.h"
#include "cmFileTimeCache.h"
#include "cmGeneratedFileStream.h"
#include "cmGeneratorExpression.h"
@@ -52,8 +54,9 @@
# include "cmDependsJava.h"
#endif
+namespace {
// Helper function used below.
-static std::string cmSplitExtension(std::string const& in, std::string& base)
+std::string cmSplitExtension(std::string const& in, std::string& base)
{
std::string ext;
std::string::size_type dot_pos = in.rfind('.');
@@ -67,6 +70,43 @@ static std::string cmSplitExtension(std::string const& in, std::string& base)
return ext;
}
+// Helper predicate for removing absolute paths that don't point to the
+// source or binary directory. It is used when CMAKE_DEPENDS_IN_PROJECT_ONLY
+// is set ON, to only consider in-project dependencies during the build.
+class NotInProjectDir
+{
+public:
+ // Constructor with the source and binary directory's path
+ NotInProjectDir(cm::string_view sourceDir, cm::string_view binaryDir)
+ : SourceDir(sourceDir)
+ , BinaryDir(binaryDir)
+ {
+ }
+
+ // Operator evaluating the predicate
+ bool operator()(const std::string& p) const
+ {
+ auto path = cmCMakePath(p).Normal();
+
+ // Keep all relative paths:
+ if (path.IsRelative()) {
+ return false;
+ }
+
+ // If it's an absolute path, check if it starts with the source
+ // directory:
+ return !(cmCMakePath(SourceDir).IsPrefix(path) ||
+ cmCMakePath(BinaryDir).IsPrefix(path));
+ }
+
+private:
+ // The path to the source directory
+ cm::string_view SourceDir;
+ // The path to the binary directory
+ cm::string_view BinaryDir;
+};
+}
+
cmLocalUnixMakefileGenerator3::cmLocalUnixMakefileGenerator3(
cmGlobalGenerator* gg, cmMakefile* mf)
: cmLocalCommonGenerator(gg, mf, mf->GetCurrentBinaryDirectory())
@@ -554,8 +594,10 @@ void cmLocalUnixMakefileGenerator3::WriteMakeRule(
}
}
- // Write the list of commands.
- os << cmWrap("\t", commands, "", "\n") << "\n";
+ if (!commands.empty()) {
+ // Write the list of commands.
+ os << cmWrap("\t", commands, "", "\n") << "\n";
+ }
if (symbolic && !this->IsWatcomWMake()) {
os << ".PHONY : " << tgt << "\n";
}
@@ -1300,91 +1342,153 @@ bool cmLocalUnixMakefileGenerator3::UpdateDependencies(
cmSystemTools::Error("Target DependInfo.cmake file not found");
}
+ bool status = true;
+
// Check if any multiple output pairs have a missing file.
this->CheckMultipleOutputs(verbose);
std::string const targetDir = cmSystemTools::GetFilenamePath(tgtInfo);
- std::string const internalDependFile = targetDir + "/depend.internal";
- std::string const dependFile = targetDir + "/depend.make";
-
- // If the target DependInfo.cmake file has changed since the last
- // time dependencies were scanned then force rescanning. This may
- // happen when a new source file is added and CMake regenerates the
- // project but no other sources were touched.
- bool needRescanDependInfo = false;
- cmFileTimeCache* ftc =
- this->GlobalGenerator->GetCMakeInstance()->GetFileTimeCache();
- {
- int result;
- if (!ftc->Compare(internalDependFile, tgtInfo, &result) || result < 0) {
- if (verbose) {
- cmSystemTools::Stdout(cmStrCat("Dependee \"", tgtInfo,
- "\" is newer than depender \"",
- internalDependFile, "\".\n"));
+ if (!this->Makefile->GetSafeDefinition("CMAKE_DEPENDS_LANGUAGES").empty()) {
+ // dependencies are managed by CMake itself
+
+ std::string const internalDependFile = targetDir + "/depend.internal";
+ std::string const dependFile = targetDir + "/depend.make";
+
+ // If the target DependInfo.cmake file has changed since the last
+ // time dependencies were scanned then force rescanning. This may
+ // happen when a new source file is added and CMake regenerates the
+ // project but no other sources were touched.
+ bool needRescanDependInfo = false;
+ cmFileTimeCache* ftc =
+ this->GlobalGenerator->GetCMakeInstance()->GetFileTimeCache();
+ {
+ int result;
+ if (!ftc->Compare(internalDependFile, tgtInfo, &result) || result < 0) {
+ if (verbose) {
+ cmSystemTools::Stdout(cmStrCat("Dependee \"", tgtInfo,
+ "\" is newer than depender \"",
+ internalDependFile, "\".\n"));
+ }
+ needRescanDependInfo = true;
}
- needRescanDependInfo = true;
}
- }
- // If the directory information is newer than depend.internal, include dirs
- // may have changed. In this case discard all old dependencies.
- bool needRescanDirInfo = false;
- {
- std::string dirInfoFile =
- cmStrCat(this->GetCurrentBinaryDirectory(),
- "/CMakeFiles/CMakeDirectoryInformation.cmake");
- int result;
- if (!ftc->Compare(internalDependFile, dirInfoFile, &result) ||
- result < 0) {
- if (verbose) {
- cmSystemTools::Stdout(cmStrCat("Dependee \"", dirInfoFile,
- "\" is newer than depender \"",
- internalDependFile, "\".\n"));
+ // If the directory information is newer than depend.internal, include
+ // dirs may have changed. In this case discard all old dependencies.
+ bool needRescanDirInfo = false;
+ {
+ std::string dirInfoFile =
+ cmStrCat(this->GetCurrentBinaryDirectory(),
+ "/CMakeFiles/CMakeDirectoryInformation.cmake");
+ int result;
+ if (!ftc->Compare(internalDependFile, dirInfoFile, &result) ||
+ result < 0) {
+ if (verbose) {
+ cmSystemTools::Stdout(cmStrCat("Dependee \"", dirInfoFile,
+ "\" is newer than depender \"",
+ internalDependFile, "\".\n"));
+ }
+ needRescanDirInfo = true;
}
- needRescanDirInfo = true;
+ }
+
+ // Check the implicit dependencies to see if they are up to date.
+ // The build.make file may have explicit dependencies for the object
+ // files but these will not affect the scanning process so they need
+ // not be considered.
+ cmDepends::DependencyMap validDependencies;
+ bool needRescanDependencies = false;
+ if (!needRescanDirInfo) {
+ cmDependsC checker;
+ checker.SetVerbose(verbose);
+ checker.SetFileTimeCache(ftc);
+ // cmDependsC::Check() fills the vector validDependencies() with the
+ // dependencies for those files where they are still valid, i.e.
+ // neither the files themselves nor any files they depend on have
+ // changed. We don't do that if the CMakeDirectoryInformation.cmake
+ // file has changed, because then potentially all dependencies have
+ // changed. This information is given later on to cmDependsC, which
+ // then only rescans the files where it did not get valid dependencies
+ // via this dependency vector. This means that in the normal case, when
+ // only few or one file have been edited, then also only this one file
+ // is actually scanned again, instead of all files for this target.
+ needRescanDependencies =
+ !checker.Check(dependFile, internalDependFile, validDependencies);
+ }
+
+ if (needRescanDependInfo || needRescanDirInfo || needRescanDependencies) {
+ // The dependencies must be regenerated.
+ std::string targetName = cmSystemTools::GetFilenameName(targetDir);
+ targetName = targetName.substr(0, targetName.length() - 4);
+ std::string message =
+ cmStrCat("Scanning dependencies of target ", targetName);
+ cmSystemTools::MakefileColorEcho(cmsysTerminal_Color_ForegroundMagenta |
+ cmsysTerminal_Color_ForegroundBold,
+ message.c_str(), true, color);
+
+ status = this->ScanDependencies(targetDir, dependFile,
+ internalDependFile, validDependencies);
}
}
- // Check the implicit dependencies to see if they are up to date.
- // The build.make file may have explicit dependencies for the object
- // files but these will not affect the scanning process so they need
- // not be considered.
- cmDepends::DependencyMap validDependencies;
- bool needRescanDependencies = false;
- if (!needRescanDirInfo) {
- cmDependsC checker;
- checker.SetVerbose(verbose);
- checker.SetFileTimeCache(ftc);
- // cmDependsC::Check() fills the vector validDependencies() with the
- // dependencies for those files where they are still valid, i.e. neither
- // the files themselves nor any files they depend on have changed.
- // We don't do that if the CMakeDirectoryInformation.cmake file has
- // changed, because then potentially all dependencies have changed.
- // This information is given later on to cmDependsC, which then only
- // rescans the files where it did not get valid dependencies via this
- // dependency vector. This means that in the normal case, when only
- // few or one file have been edited, then also only this one file is
- // actually scanned again, instead of all files for this target.
- needRescanDependencies =
- !checker.Check(dependFile, internalDependFile, validDependencies);
- }
-
- if (needRescanDependInfo || needRescanDirInfo || needRescanDependencies) {
- // The dependencies must be regenerated.
- std::string targetName = cmSystemTools::GetFilenameName(targetDir);
- targetName = targetName.substr(0, targetName.length() - 4);
- std::string message =
- cmStrCat("Scanning dependencies of target ", targetName);
- cmSystemTools::MakefileColorEcho(cmsysTerminal_Color_ForegroundMagenta |
- cmsysTerminal_Color_ForegroundBold,
- message.c_str(), true, color);
-
- return this->ScanDependencies(targetDir, dependFile, internalDependFile,
- validDependencies);
+ auto depends =
+ this->Makefile->GetSafeDefinition("CMAKE_DEPENDS_DEPENDENCY_FILES");
+ if (!depends.empty()) {
+ // dependencies are managed by compiler
+ auto depFiles = cmExpandedList(depends);
+ std::string const internalDepFile =
+ targetDir + "/compiler_depend.internal";
+ std::string const depFile = targetDir + "/compiler_depend.make";
+ cmDepends::DependencyMap dependencies;
+ cmDependsCompiler depsManager;
+ bool projectOnly = cmIsOn(
+ this->Makefile->GetSafeDefinition("CMAKE_DEPENDS_IN_PROJECT_ONLY"));
+
+ depsManager.SetVerbose(verbose);
+ depsManager.SetLocalGenerator(this);
+
+ if (!depsManager.CheckDependencies(
+ internalDepFile, depFiles, dependencies,
+ projectOnly ? NotInProjectDir(this->GetSourceDirectory(),
+ this->GetBinaryDirectory())
+ : std::function<bool(const std::string&)>())) {
+ // regenerate dependencies files
+ std::string targetName =
+ cmCMakePath(targetDir).GetFileName().RemoveExtension().GenericString();
+ auto message = cmStrCat(
+ "Consolidate compiler generated dependencies of target ", targetName);
+ cmSystemTools::MakefileColorEcho(cmsysTerminal_Color_ForegroundMagenta |
+ cmsysTerminal_Color_ForegroundBold,
+ message.c_str(), true, color);
+
+ // Open the make depends file. This should be copy-if-different
+ // because the make tool may try to reload it needlessly otherwise.
+ cmGeneratedFileStream ruleFileStream(
+ depFile, false, this->GlobalGenerator->GetMakefileEncoding());
+ ruleFileStream.SetCopyIfDifferent(true);
+ if (!ruleFileStream) {
+ return false;
+ }
+
+ // Open the cmake dependency tracking file. This should not be
+ // copy-if-different because dependencies are re-scanned when it is
+ // older than the DependInfo.cmake.
+ cmGeneratedFileStream internalRuleFileStream(
+ internalDepFile, false, this->GlobalGenerator->GetMakefileEncoding());
+ if (!internalRuleFileStream) {
+ return false;
+ }
+
+ this->WriteDisclaimer(ruleFileStream);
+ this->WriteDisclaimer(internalRuleFileStream);
+
+ depsManager.WriteDependencies(dependencies, ruleFileStream,
+ internalRuleFileStream);
+ }
}
// The dependencies are already up-to-date.
- return true;
+ return status;
}
bool cmLocalUnixMakefileGenerator3::ScanDependencies(
@@ -1723,166 +1827,193 @@ void cmLocalUnixMakefileGenerator3::ClearDependencies(cmMakefile* mf,
cmDepends clearer;
clearer.SetVerbose(verbose);
for (std::string const& file : files) {
- std::string dir = cmSystemTools::GetFilenamePath(file);
-
- // Clear the implicit dependency makefile.
- std::string dependFile = dir + "/depend.make";
- clearer.Clear(dependFile);
+ auto snapshot = mf->GetState()->CreateBaseSnapshot();
+ cmMakefile lmf(mf->GetGlobalGenerator(), snapshot);
+ lmf.ReadListFile(file);
- // Remove the internal dependency check file to force
- // regeneration.
- std::string internalDependFile = dir + "/depend.internal";
- cmSystemTools::RemoveFile(internalDependFile);
- }
-}
+ if (!lmf.GetSafeDefinition("CMAKE_DEPENDS_LANGUAGES").empty()) {
+ std::string dir = cmSystemTools::GetFilenamePath(file);
-namespace {
-// Helper predicate for removing absolute paths that don't point to the
-// source or binary directory. It is used when CMAKE_DEPENDS_IN_PROJECT_ONLY
-// is set ON, to only consider in-project dependencies during the build.
-class NotInProjectDir
-{
-public:
- // Constructor with the source and binary directory's path
- NotInProjectDir(cm::string_view sourceDir, cm::string_view binaryDir)
- : SourceDir(sourceDir)
- , BinaryDir(binaryDir)
- {
- }
+ // Clear the implicit dependency makefile.
+ std::string dependFile = dir + "/depend.make";
+ clearer.Clear(dependFile);
- // Operator evaluating the predicate
- bool operator()(const std::string& p) const
- {
- auto path = cmCMakePath(p).Normal();
+ // Remove the internal dependency check file to force
+ // regeneration.
+ std::string internalDependFile = dir + "/depend.internal";
+ cmSystemTools::RemoveFile(internalDependFile);
+ }
- // Keep all relative paths:
- if (path.IsRelative()) {
- return false;
+ auto depsFiles = lmf.GetSafeDefinition("CMAKE_DEPENDS_DEPENDENCY_FILES");
+ if (!depsFiles.empty()) {
+ auto dir = cmCMakePath(file).GetParentPath();
+ // Clear the implicit dependency makefile.
+ auto depFile = cmCMakePath(dir).Append("compiler_depend.make");
+ clearer.Clear(depFile.GenericString());
+
+ // Remove the internal dependency check file
+ auto internalDepFile =
+ cmCMakePath(dir).Append("compiler_depend.internal");
+ cmSystemTools::RemoveFile(internalDepFile.GenericString());
+
+ // Touch timestamp file to force dependencies regeneration
+ auto DepTimestamp = cmCMakePath(dir).Append("compiler_depend.ts");
+ cmSystemTools::Touch(DepTimestamp.GenericString(), true);
+
+ // clear the dependencies files generated by the compiler
+ std::vector<std::string> dependencies = cmExpandedList(depsFiles);
+ cmDependsCompiler depsManager;
+ depsManager.SetVerbose(verbose);
+ depsManager.ClearDependencies(dependencies);
}
- // If it's an absolute path, check if it starts with the source
- // directory:
- return !(cmCMakePath(SourceDir).IsPrefix(path) ||
- cmCMakePath(BinaryDir).IsPrefix(path));
}
-
-private:
- // The path to the source directory
- cm::string_view SourceDir;
- // The path to the binary directory
- cm::string_view BinaryDir;
-};
}
void cmLocalUnixMakefileGenerator3::WriteDependLanguageInfo(
std::ostream& cmakefileStream, cmGeneratorTarget* target)
{
- ImplicitDependLanguageMap const& implicitLangs =
- this->GetImplicitDepends(target);
+ // To enable dependencies filtering
+ cmakefileStream << "\n"
+ << "# Consider dependencies only in project.\n"
+ << "set(CMAKE_DEPENDS_IN_PROJECT_ONLY "
+ << (cmIsOn(this->Makefile->GetSafeDefinition(
+ "CMAKE_DEPENDS_IN_PROJECT_ONLY"))
+ ? "ON"
+ : "OFF")
+ << ")\n\n";
+
+ auto const& implicitLangs =
+ this->GetImplicitDepends(target, cmDependencyScannerKind::CMake);
// list the languages
- cmakefileStream
- << "# The set of languages for which implicit dependencies are needed:\n";
+ cmakefileStream << "# The set of languages for which implicit "
+ "dependencies are needed:\n";
cmakefileStream << "set(CMAKE_DEPENDS_LANGUAGES\n";
for (auto const& implicitLang : implicitLangs) {
cmakefileStream << " \"" << implicitLang.first << "\"\n";
}
cmakefileStream << " )\n";
- // now list the files for each language
- cmakefileStream
- << "# The set of files for implicit dependencies of each language:\n";
- for (auto const& implicitLang : implicitLangs) {
- cmakefileStream << "set(CMAKE_DEPENDS_CHECK_" << implicitLang.first
- << "\n";
- ImplicitDependFileMap const& implicitPairs = implicitLang.second;
-
- // for each file pair
- for (auto const& implicitPair : implicitPairs) {
- for (auto const& di : implicitPair.second) {
- cmakefileStream << " \"" << di << "\" ";
- cmakefileStream << "\"" << implicitPair.first << "\"\n";
+ if (!implicitLangs.empty()) {
+ // now list the files for each language
+ cmakefileStream
+ << "# The set of files for implicit dependencies of each language:\n";
+ for (auto const& implicitLang : implicitLangs) {
+ const auto& lang = implicitLang.first;
+
+ cmakefileStream << "set(CMAKE_DEPENDS_CHECK_" << lang << "\n";
+ auto const& implicitPairs = implicitLang.second;
+
+ // for each file pair
+ for (auto const& implicitPair : implicitPairs) {
+ for (auto const& di : implicitPair.second) {
+ cmakefileStream << " \"" << di << "\" ";
+ cmakefileStream << "\"" << implicitPair.first << "\"\n";
+ }
}
- }
- cmakefileStream << " )\n";
-
- // Tell the dependency scanner what compiler is used.
- std::string cidVar =
- cmStrCat("CMAKE_", implicitLang.first, "_COMPILER_ID");
- cmProp cid = this->Makefile->GetDefinition(cidVar);
- if (cmNonempty(cid)) {
- cmakefileStream << "set(CMAKE_" << implicitLang.first
- << "_COMPILER_ID \"" << *cid << "\")\n";
- }
+ cmakefileStream << " )\n";
- if (implicitLang.first == "Fortran") {
- std::string smodSep =
- this->Makefile->GetSafeDefinition("CMAKE_Fortran_SUBMODULE_SEP");
- std::string smodExt =
- this->Makefile->GetSafeDefinition("CMAKE_Fortran_SUBMODULE_EXT");
- cmakefileStream << "set(CMAKE_Fortran_SUBMODULE_SEP \"" << smodSep
- << "\")\n";
- cmakefileStream << "set(CMAKE_Fortran_SUBMODULE_EXT \"" << smodExt
- << "\")\n";
- }
+ // Tell the dependency scanner what compiler is used.
+ std::string cidVar = cmStrCat("CMAKE_", lang, "_COMPILER_ID");
+ cmProp cid = this->Makefile->GetDefinition(cidVar);
+ if (cmNonempty(cid)) {
+ cmakefileStream << "set(CMAKE_" << lang << "_COMPILER_ID \"" << *cid
+ << "\")\n";
+ }
- // Build a list of preprocessor definitions for the target.
- std::set<std::string> defines;
- this->GetTargetDefines(target, this->GetConfigName(), implicitLang.first,
- defines);
- if (!defines.empty()) {
- /* clang-format off */
+ if (lang == "Fortran") {
+ std::string smodSep =
+ this->Makefile->GetSafeDefinition("CMAKE_Fortran_SUBMODULE_SEP");
+ std::string smodExt =
+ this->Makefile->GetSafeDefinition("CMAKE_Fortran_SUBMODULE_EXT");
+ cmakefileStream << "set(CMAKE_Fortran_SUBMODULE_SEP \"" << smodSep
+ << "\")\n";
+ cmakefileStream << "set(CMAKE_Fortran_SUBMODULE_EXT \"" << smodExt
+ << "\")\n";
+ }
+
+ // Build a list of preprocessor definitions for the target.
+ std::set<std::string> defines;
+ this->GetTargetDefines(target, this->GetConfigName(), lang, defines);
+ if (!defines.empty()) {
+ /* clang-format off */
cmakefileStream
<< "\n"
<< "# Preprocessor definitions for this target.\n"
- << "set(CMAKE_TARGET_DEFINITIONS_" << implicitLang.first << "\n";
- /* clang-format on */
- for (std::string const& define : defines) {
- cmakefileStream << " " << cmOutputConverter::EscapeForCMake(define)
- << "\n";
+ << "set(CMAKE_TARGET_DEFINITIONS_" << lang << "\n";
+ /* clang-format on */
+ for (std::string const& define : defines) {
+ cmakefileStream << " " << cmOutputConverter::EscapeForCMake(define)
+ << "\n";
+ }
+ cmakefileStream << " )\n";
+ }
+
+ // Target-specific include directories:
+ cmakefileStream << "\n"
+ << "# The include file search paths:\n";
+ cmakefileStream << "set(CMAKE_" << lang << "_TARGET_INCLUDE_PATH\n";
+ std::vector<std::string> includes;
+
+ this->GetIncludeDirectories(includes, target, lang,
+ this->GetConfigName());
+ std::string const& binaryDir = this->GetState()->GetBinaryDirectory();
+ if (this->Makefile->IsOn("CMAKE_DEPENDS_IN_PROJECT_ONLY")) {
+ std::string const& sourceDir = this->GetState()->GetSourceDirectory();
+ cm::erase_if(includes, ::NotInProjectDir(sourceDir, binaryDir));
+ }
+ for (std::string const& include : includes) {
+ cmakefileStream << " \""
+ << this->MaybeConvertToRelativePath(binaryDir, include)
+ << "\"\n";
}
cmakefileStream << " )\n";
}
- // Target-specific include directories:
- cmakefileStream << "\n"
- << "# The include file search paths:\n";
- cmakefileStream << "set(CMAKE_" << implicitLang.first
- << "_TARGET_INCLUDE_PATH\n";
- std::vector<std::string> includes;
-
- this->GetIncludeDirectories(includes, target, implicitLang.first,
- this->GetConfigName());
- std::string const& binaryDir = this->GetState()->GetBinaryDirectory();
- if (this->Makefile->IsOn("CMAKE_DEPENDS_IN_PROJECT_ONLY")) {
- std::string const& sourceDir = this->GetState()->GetSourceDirectory();
- cm::erase_if(includes, ::NotInProjectDir(sourceDir, binaryDir));
+ // Store include transform rule properties. Write the directory
+ // rules first because they may be overridden by later target rules.
+ std::vector<std::string> transformRules;
+ if (cmProp xform =
+ this->Makefile->GetProperty("IMPLICIT_DEPENDS_INCLUDE_TRANSFORM")) {
+ cmExpandList(*xform, transformRules);
}
- for (std::string const& include : includes) {
- cmakefileStream << " \""
- << this->MaybeConvertToRelativePath(binaryDir, include)
- << "\"\n";
+ if (cmProp xform =
+ target->GetProperty("IMPLICIT_DEPENDS_INCLUDE_TRANSFORM")) {
+ cmExpandList(*xform, transformRules);
+ }
+ if (!transformRules.empty()) {
+ cmakefileStream << "\nset(CMAKE_INCLUDE_TRANSFORMS\n";
+ for (std::string const& tr : transformRules) {
+ cmakefileStream << " " << cmOutputConverter::EscapeForCMake(tr)
+ << "\n";
+ }
+ cmakefileStream << " )\n";
}
- cmakefileStream << " )\n";
}
- // Store include transform rule properties. Write the directory
- // rules first because they may be overridden by later target rules.
- std::vector<std::string> transformRules;
- if (cmProp xform =
- this->Makefile->GetProperty("IMPLICIT_DEPENDS_INCLUDE_TRANSFORM")) {
- cmExpandList(*xform, transformRules);
- }
- if (cmProp xform =
- target->GetProperty("IMPLICIT_DEPENDS_INCLUDE_TRANSFORM")) {
- cmExpandList(*xform, transformRules);
- }
- if (!transformRules.empty()) {
- cmakefileStream << "set(CMAKE_INCLUDE_TRANSFORMS\n";
- for (std::string const& tr : transformRules) {
- cmakefileStream << " " << cmOutputConverter::EscapeForCMake(tr) << "\n";
+ auto const& compilerLangs =
+ this->GetImplicitDepends(target, cmDependencyScannerKind::Compiler);
+
+ // list the dependency files managed by the compiler
+ cmakefileStream << "\n# The set of dependency files which are needed:\n";
+ cmakefileStream << "set(CMAKE_DEPENDS_DEPENDENCY_FILES\n";
+ for (auto const& compilerLang : compilerLangs) {
+ auto depFormat = this->Makefile->GetSafeDefinition(
+ cmStrCat("CMAKE_", compilerLang.first, "_DEPFILE_FORMAT"));
+ auto const& compilerPairs = compilerLang.second;
+ for (auto const& compilerPair : compilerPairs) {
+ for (auto const& src : compilerPair.second) {
+ cmakefileStream << " \"" << src << "\" \""
+ << this->MaybeConvertToRelativePath(
+ this->GetBinaryDirectory(), compilerPair.first)
+ << "\" \"" << depFormat << "\" \""
+ << this->MaybeConvertToRelativePath(
+ this->GetBinaryDirectory(), compilerPair.first)
+ << ".d\"\n";
+ }
}
- cmakefileStream << " )\n";
}
+ cmakefileStream << " )\n";
}
void cmLocalUnixMakefileGenerator3::WriteDisclaimer(std::ostream& os)
diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx
index 6bc915d..155a097 100644
--- a/Source/cmMakefileTargetGenerator.cxx
+++ b/Source/cmMakefileTargetGenerator.cxx
@@ -12,7 +12,9 @@
#include <utility>
#include <cm/memory>
+#include <cm/string_view>
#include <cmext/algorithm>
+#include <cmext/string_view>
#include "cmComputeLinkInformation.h"
#include "cmCustomCommand.h"
@@ -326,7 +328,45 @@ void cmMakefileTargetGenerator::WriteCommonCodeRules()
<< cmSystemTools::ConvertToOutputPath(
this->LocalGenerator->MaybeConvertToRelativePath(
this->LocalGenerator->GetBinaryDirectory(), dependFileNameFull))
- << "\n\n";
+ << "\n";
+
+ std::string depsUseCompiler = "CMAKE_DEPENDS_USE_COMPILER";
+ if (!this->Makefile->IsDefinitionSet(depsUseCompiler) ||
+ this->Makefile->IsOn(depsUseCompiler)) {
+ std::string compilerDependFile =
+ cmStrCat(this->TargetBuildDirectoryFull, "/compiler_depend.make");
+ *this->BuildFileStream
+ << "# Include any dependencies generated by the "
+ "compiler for this target.\n"
+ << this->GlobalGenerator->IncludeDirective << " " << root
+ << cmSystemTools::ConvertToOutputPath(
+ this->LocalGenerator->MaybeConvertToRelativePath(
+ 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";
+ }
+
+ std::string compilerDependTimestamp =
+ cmStrCat(this->TargetBuildDirectoryFull, "/compiler_depend.ts");
+ if (!cmSystemTools::FileExists(compilerDependTimestamp)) {
+ // Write a dependency timestamp file.
+ cmGeneratedFileStream depFileStream(
+ 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";
+ }
+ }
if (!this->NoRuleMessages) {
// Include the progress variables for the target.
@@ -473,6 +513,14 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles(
return;
}
+ // Use compiler to generate dependencies, if supported.
+ bool compilerGenerateDeps =
+ this->GlobalGenerator->SupportsCompilerDependencies() &&
+ cmIsOn(this->Makefile->GetDefinition(
+ cmStrCat("CMAKE_", lang, "_DEPENDS_USE_COMPILER")));
+ auto scanner = compilerGenerateDeps ? cmDependencyScannerKind::Compiler
+ : cmDependencyScannerKind::CMake;
+
// Get the full path name of the object file.
std::string const& objectName =
this->GeneratorTarget->GetObjectName(&source);
@@ -512,7 +560,7 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles(
std::string srcFullPath =
cmSystemTools::CollapseFullPath(source.GetFullPath());
this->LocalGenerator->AddImplicitDepends(this->GeneratorTarget, lang,
- objFullPath, srcFullPath);
+ objFullPath, srcFullPath, scanner);
this->LocalGenerator->AppendRuleDepend(depends,
this->FlagFileNameFull.c_str());
@@ -554,8 +602,8 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles(
depends.push_back(
this->GeneratorTarget->GetPchFile(config, lang, arch));
}
- this->LocalGenerator->AddImplicitDepends(this->GeneratorTarget, lang,
- objFullPath, pchHeader);
+ this->LocalGenerator->AddImplicitDepends(
+ this->GeneratorTarget, lang, objFullPath, pchHeader, scanner);
}
}
@@ -689,7 +737,7 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles(
source.GetFullPath(), cmOutputConverter::SHELL);
// Construct the build message.
- std::vector<std::string> no_commands;
+ std::vector<std::string> no_depends;
std::vector<std::string> commands;
// add in a progress call if needed
@@ -783,6 +831,26 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles(
"$(" + lang + "_INCLUDES)");
vars.Includes = includesString.c_str();
+ std::string dependencyTarget;
+ std::string shellDependencyFile;
+ std::string dependencyTimestamp;
+ if (compilerGenerateDeps) {
+ dependencyTarget = this->LocalGenerator->EscapeForShell(
+ this->LocalGenerator->ConvertToMakefilePath(
+ this->LocalGenerator->MaybeConvertToRelativePath(
+ this->LocalGenerator->GetBinaryDirectory(), relativeObj)));
+ vars.DependencyTarget = dependencyTarget.c_str();
+
+ auto depFile = cmStrCat(obj, ".d");
+ shellDependencyFile = this->LocalGenerator->ConvertToOutputFormat(
+ depFile, cmOutputConverter::SHELL);
+ vars.DependencyFile = shellDependencyFile.c_str();
+
+ dependencyTimestamp = this->LocalGenerator->MaybeConvertToRelativePath(
+ this->LocalGenerator->GetBinaryDirectory(),
+ cmStrCat(this->TargetBuildDirectoryFull, "/compiler_depend.ts"));
+ }
+
// At the moment, it is assumed that C, C++, Fortran, and CUDA have both
// assembly and preprocessor capabilities. The same is true for the
// ability to export compile commands
@@ -954,6 +1022,53 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles(
}
}
+ std::string flagsWithDeps(flags);
+
+ if (compilerGenerateDeps) {
+ // Injects dependency computation
+ auto depFlags = this->Makefile->GetSafeDefinition(
+ cmStrCat("CMAKE_DEPFILE_FLAGS_", lang));
+
+ if (!depFlags.empty()) {
+ // Add dependency flags
+ rulePlaceholderExpander->ExpandRuleVariables(this->LocalGenerator,
+ depFlags, vars);
+ flagsWithDeps.append(1, ' ');
+ flagsWithDeps.append(depFlags);
+ }
+ vars.Flags = flagsWithDeps.c_str();
+
+ const auto& extraCommands = this->Makefile->GetSafeDefinition(
+ cmStrCat("CMAKE_", lang, "_DEPENDS_EXTRA_COMMANDS"));
+ if (!extraCommands.empty()) {
+ auto commandList = cmExpandedList(extraCommands);
+ compileCommands.insert(compileCommands.end(), commandList.cbegin(),
+ commandList.cend());
+ }
+
+ const auto& depFormat = this->Makefile->GetRequiredDefinition(
+ cmStrCat("CMAKE_", lang, "_DEPFILE_FORMAT"));
+
+ if (depFormat == "msvc"_s) {
+ // compiler must be launched through a wrapper to pick-up dependencies
+ std::string depFilter =
+ "$(CMAKE_COMMAND) -E cmake_cl_compile_depends ";
+ depFilter += cmStrCat("--dep-file=", shellDependencyFile);
+ depFilter +=
+ cmStrCat(" --working-dir=",
+ this->LocalGenerator->ConvertToOutputFormat(
+ this->LocalGenerator->GetCurrentBinaryDirectory(),
+ cmOutputConverter::SHELL));
+ const auto& prefix = this->Makefile->GetSafeDefinition(
+ cmStrCat("CMAKE_", lang, "_CL_SHOWINCLUDES_PREFIX"));
+ depFilter += cmStrCat(" --filter-prefix=",
+ this->LocalGenerator->ConvertToOutputFormat(
+ prefix, cmOutputConverter::SHELL));
+ depFilter += " -- ";
+ compileCommands.front().insert(0, depFilter);
+ }
+ }
+
// Expand placeholders in the commands.
for (std::string& compileCommand : compileCommands) {
compileCommand = cmStrCat(launcher, compileCommand);
@@ -979,8 +1094,8 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles(
cmExpandList(evaluated_outputs, outputs);
}
}
- if (!ispcHeaderRelative
- .empty()) { // can't move ispcHeader as vars is using it
+ if (!ispcHeaderRelative.empty()) {
+ // can't move ispcHeader as vars is using it
outputs.emplace_back(ispcHeaderRelative);
}
@@ -988,10 +1103,19 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles(
this->CleanFiles.insert(outputs.begin() + 1, outputs.end());
}
+ if (compilerGenerateDeps) {
+ depends.push_back(dependencyTimestamp);
+ }
+
// Write the rule.
this->WriteMakeRule(*this->BuildFileStream, nullptr, outputs, depends,
commands);
+ if (compilerGenerateDeps) {
+ // set back flags without dependency generation
+ vars.Flags = flags.c_str();
+ }
+
bool do_preprocess_rules = lang_has_preprocessor &&
this->LocalGenerator->GetCreatePreprocessedSourceRules();
bool do_assembly_rules =
@@ -1388,10 +1512,10 @@ void cmMakefileTargetGenerator::WriteDeviceLinkRule(
std::string registerFileCmd;
- // The generated register file contains macros that when expanded register
- // the device routines. Because the routines are the same for all
- // architectures the register file will be the same too. Thus generate it
- // only on the first invocation to reduce overhead.
+ // The generated register file contains macros that when expanded
+ // register the device routines. Because the routines are the same for
+ // all architectures the register file will be the same too. Thus
+ // generate it only on the first invocation to reduce overhead.
if (fatbinaryDepends.size() == 1) {
std::string registerFileRel =
this->LocalGenerator->MaybeConvertToRelativePath(
@@ -1426,7 +1550,8 @@ void cmMakefileTargetGenerator::WriteDeviceLinkRule(
fatbinaryOutputRel, fatbinaryDepends,
{ fatbinaryCommand }, false);
- // Compile the stub that registers the kernels and contains the fatbinaries.
+ // Compile the stub that registers the kernels and contains the
+ // fatbinaries.
cmRulePlaceholderExpander::RuleVariables vars;
vars.CMTargetName = this->GetGeneratorTarget()->GetName().c_str();
vars.CMTargetType =
@@ -1839,9 +1964,9 @@ bool cmMakefileTargetGenerator::CheckUseResponseFileForObjects(
if (size_t const limit = cmSystemTools::CalculateCommandLineLengthLimit()) {
// Compute the total length of our list of object files with room
// for argument separation and quoting. This does not convert paths
- // relative to CMAKE_CURRENT_BINARY_DIR like the final list will be, so the
- // actual list will likely be much shorter than this. However, in the
- // worst case all objects will remain as absolute paths.
+ // relative to CMAKE_CURRENT_BINARY_DIR like the final list will be, so
+ // the actual list will likely be much shorter than this. However, in
+ // the worst case all objects will remain as absolute paths.
size_t length = 0;
for (std::string const& obj : this->Objects) {
length += obj.size() + 3;
diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx
index 81374a1..b8464f2 100644
--- a/Source/cmcmd.cxx
+++ b/Source/cmcmd.cxx
@@ -33,6 +33,13 @@
# include "bindexplib.h"
#endif
+#if !defined(CMAKE_BOOTSTRAP) || defined(CMAKE_BOOTSTRAP_MAKEFILES)
+# include <algorithm>
+
+# include "cmCMakePath.h"
+# include "cmProcessTools.h"
+#endif
+
#if !defined(CMAKE_BOOTSTRAP) && defined(_WIN32) && !defined(__CYGWIN__)
# include "cmVisualStudioWCEPlatformParser.h"
#endif
@@ -66,6 +73,7 @@ int cmcmd_cmake_ninja_depends(std::vector<std::string>::const_iterator argBeg,
int cmcmd_cmake_ninja_dyndep(std::vector<std::string>::const_iterator argBeg,
std::vector<std::string>::const_iterator argEnd);
+namespace {
void CMakeCommandUsage(const char* program)
{
std::ostringstream errorStream;
@@ -144,8 +152,7 @@ void CMakeCommandUsage(const char* program)
cmSystemTools::Error(errorStream.str());
}
-static bool cmTarFilesFrom(std::string const& file,
- std::vector<std::string>& files)
+bool cmTarFilesFrom(std::string const& file, std::vector<std::string>& files)
{
if (cmSystemTools::FileIsDirectory(file)) {
std::ostringstream e;
@@ -180,7 +187,7 @@ static bool cmTarFilesFrom(std::string const& file,
return true;
}
-static void cmCatFile(const std::string& fileToAppend)
+void cmCatFile(const std::string& fileToAppend)
{
#ifdef _WIN32
_setmode(fileno(stdout), _O_BINARY);
@@ -190,7 +197,7 @@ static void cmCatFile(const std::string& fileToAppend)
std::cout << source.rdbuf();
}
-static bool cmRemoveDirectory(const std::string& dir, bool recursive = true)
+bool cmRemoveDirectory(const std::string& dir, bool recursive = true)
{
if (cmSystemTools::FileIsSymlink(dir)) {
if (!cmSystemTools::RemoveFile(dir)) {
@@ -208,9 +215,123 @@ static bool cmRemoveDirectory(const std::string& dir, bool recursive = true)
return true;
}
-static int HandleIWYU(const std::string& runCmd,
- const std::string& /* sourceFile */,
- const std::vector<std::string>& orig_cmd)
+#if !defined(CMAKE_BOOTSTRAP) || defined(CMAKE_BOOTSTRAP_MAKEFILES)
+class CLIncludeParser : public cmProcessTools::LineParser
+{
+public:
+ CLIncludeParser(cm::string_view includePrefix, cmsys::ofstream& depFile,
+ std::ostream& output)
+ : IncludePrefix(includePrefix)
+ , DepFile(depFile)
+ , Output(output)
+ {
+ }
+
+private:
+ bool ProcessLine() override
+ {
+ if (cmHasPrefix(this->Line, this->IncludePrefix)) {
+ this->DepFile << cmCMakePath(
+ cmTrimWhitespace(this->Line.c_str() +
+ this->IncludePrefix.size()))
+ .GenericString()
+ << std::endl;
+ } else {
+ this->Output << this->Line << std::endl << std::flush;
+ }
+
+ return true;
+ }
+
+ cm::string_view IncludePrefix;
+ cmsys::ofstream& DepFile;
+ std::ostream& Output;
+};
+
+class CLOutputLogger : public cmProcessTools::OutputLogger
+{
+public:
+ CLOutputLogger(std::ostream& log)
+ : cmProcessTools::OutputLogger(log)
+ {
+ }
+
+ bool ProcessLine() override
+ {
+ *this->Log << std::flush;
+ return true;
+ }
+};
+
+int CLCompileAndDependencies(const std::vector<std::string>& args)
+{
+ std::string depFile;
+ std::string currentBinaryDir;
+ std::string filterPrefix;
+ std::vector<std::string> command;
+ for (auto it = args.cbegin() + 2; it != args.cend(); it++) {
+ if (cmHasLiteralPrefix(*it, "--dep-file=")) {
+ depFile = it->substr(11);
+ } else if (cmHasLiteralPrefix(*it, "--working-dir=")) {
+ currentBinaryDir = it->substr(14);
+ } else if (cmHasLiteralPrefix(*it, "--filter-prefix=")) {
+ filterPrefix = it->substr(16);
+ } else if (*it == "--") {
+ command.insert(command.begin(), ++it, args.cend());
+ break;
+ } else {
+ return 1;
+ }
+ }
+
+ std::unique_ptr<cmsysProcess, void (*)(cmsysProcess*)> cp(
+ cmsysProcess_New(), cmsysProcess_Delete);
+ std::vector<const char*> argv(command.size() + 1);
+ std::transform(command.begin(), command.end(), argv.begin(),
+ [](std::string const& s) { return s.c_str(); });
+ argv.back() = nullptr;
+ cmsysProcess_SetCommand(cp.get(), argv.data());
+ cmsysProcess_SetWorkingDirectory(cp.get(), currentBinaryDir.c_str());
+
+ cmsys::ofstream fout(depFile.c_str());
+ if (!fout) {
+ return 3;
+ }
+
+ CLIncludeParser includeParser(filterPrefix, fout, std::cout);
+ CLOutputLogger errLogger(std::cerr);
+
+ // Start the process.
+ cmProcessTools::RunProcess(cp.get(), &includeParser, &errLogger);
+
+ int status = 0;
+ // handle status of process
+ switch (cmsysProcess_GetState(cp.get())) {
+ case cmsysProcess_State_Exited:
+ status = cmsysProcess_GetExitValue(cp.get());
+ break;
+ case cmsysProcess_State_Exception:
+ status = 1;
+ break;
+ case cmsysProcess_State_Error:
+ status = 2;
+ break;
+ default:
+ break;
+ }
+
+ if (status != 0) {
+ // remove the dependencies file because potentially invalid
+ fout.close();
+ cmSystemTools::RemoveFile(depFile);
+ }
+
+ return status;
+}
+#endif
+
+int HandleIWYU(const std::string& runCmd, const std::string& /* sourceFile */,
+ const std::vector<std::string>& orig_cmd)
{
// Construct the iwyu command line by taking what was given
// and adding all the arguments we give to the compiler.
@@ -235,8 +356,8 @@ static int HandleIWYU(const std::string& runCmd,
return 0;
}
-static int HandleTidy(const std::string& runCmd, const std::string& sourceFile,
- const std::vector<std::string>& orig_cmd)
+int HandleTidy(const std::string& runCmd, const std::string& sourceFile,
+ const std::vector<std::string>& orig_cmd)
{
// Construct the clang-tidy command line by taking what was given
// and adding our compiler command line. The clang-tidy tool will
@@ -265,9 +386,8 @@ static int HandleTidy(const std::string& runCmd, const std::string& sourceFile,
return ret;
}
-static int HandleLWYU(const std::string& runCmd,
- const std::string& /* sourceFile */,
- const std::vector<std::string>&)
+int HandleLWYU(const std::string& runCmd, const std::string& /* sourceFile */,
+ const std::vector<std::string>&)
{
// Construct the ldd -r -u (link what you use lwyu) command line
// ldd -u -r lwuy target
@@ -298,9 +418,8 @@ static int HandleLWYU(const std::string& runCmd,
return 0;
}
-static int HandleCppLint(const std::string& runCmd,
- const std::string& sourceFile,
- const std::vector<std::string>&)
+int HandleCppLint(const std::string& runCmd, const std::string& sourceFile,
+ const std::vector<std::string>&)
{
// Construct the cpplint command line.
std::vector<std::string> cpplint_cmd = cmExpandedList(runCmd, true);
@@ -326,9 +445,8 @@ static int HandleCppLint(const std::string& runCmd,
return 0;
}
-static int HandleCppCheck(const std::string& runCmd,
- const std::string& sourceFile,
- const std::vector<std::string>& orig_cmd)
+int HandleCppCheck(const std::string& runCmd, const std::string& sourceFile,
+ const std::vector<std::string>& orig_cmd)
{
// Construct the cpplint command line.
std::vector<std::string> cppcheck_cmd = cmExpandedList(runCmd, true);
@@ -391,7 +509,7 @@ struct CoCompiler
bool NoOriginalCommand;
};
-static const std::array<CoCompiler, 5> CoCompilers = {
+const std::array<CoCompiler, 5> CoCompilers = {
{ // Table of options and handlers.
{ "--cppcheck=", HandleCppCheck, false },
{ "--cpplint=", HandleCppLint, false },
@@ -405,6 +523,7 @@ struct CoCompileJob
std::string Command;
CoCompileHandler Handler;
};
+}
// called when args[0] == "__run_co_compile"
int cmcmd::HandleCoCompileCommands(std::vector<std::string> const& args)
@@ -586,7 +705,7 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args,
} else if (args[2] == "--ignore-eol") {
filesDiffer = cmsys::SystemTools::TextFilesDiffer(args[3], args[4]);
} else {
- ::CMakeCommandUsage(args[0].c_str());
+ CMakeCommandUsage(args[0].c_str());
return 2;
}
@@ -621,8 +740,8 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args,
}
}
if (outValid) {
- // The def file already exists and all input files are older than the
- // existing def file.
+ // The def file already exists and all input files are older than
+ // the existing def file.
return 0;
}
}
@@ -1162,6 +1281,13 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args,
return 1;
}
+#if !defined(CMAKE_BOOTSTRAP) || defined(CMAKE_BOOTSTRAP_MAKEFILES)
+ // Internal CMake compiler dependencies filtering
+ if (args[1] == "cmake_cl_compile_depends") {
+ return CLCompileAndDependencies(args);
+ }
+#endif
+
// Internal CMake link script support.
if (args[1] == "cmake_link_script" && args.size() >= 3) {
return cmcmd::ExecuteLinkScript(args);
@@ -1412,7 +1538,7 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args,
}
}
- ::CMakeCommandUsage(args[0].c_str());
+ CMakeCommandUsage(args[0].c_str());
return 1;
}
@@ -1779,8 +1905,8 @@ int cmcmd::RunLLVMRC(std::vector<std::string> const& args)
skipNextArg = false;
continue;
}
- // We use ++ as seperator between the preprocessing step definition and the
- // rc compilation step becase we need to prepend a -- to seperate the
+ // We use ++ as seperator between the preprocessing step definition and
+ // the rc compilation step becase we need to prepend a -- to seperate the
// source file properly from other options when using clang-cl for
// preprocessing.
if (arg == "++") {
@@ -1830,7 +1956,8 @@ int cmcmd::RunLLVMRC(std::vector<std::string> const& args)
return 1;
}
// Since we might have skipped the last argument to llvm-rc
- // we need to make sure the llvm-rc source file is present in the commandline
+ // we need to make sure the llvm-rc source file is present in the
+ // commandline
if (resource_compile.back() != intermediate_file) {
resource_compile.push_back(intermediate_file);
}
@@ -2123,8 +2250,8 @@ int cmVSLink::LinkIncremental()
// http://blogs.msdn.com/zakramer/archive/2006/05/22/603558.aspx
// 1. Compiler compiles the application and generates the *.obj files.
- // 2. An empty manifest file is generated if this is a clean build and if
- // not the previous one is reused.
+ // 2. An empty manifest file is generated if this is a clean build and
+ // if not the previous one is reused.
// 3. The resource compiler (rc.exe) compiles the *.manifest file to a
// *.res file.
// 4. Linker generates the binary (EXE or DLL) with the /incremental
diff --git a/Tests/BuildDepends/Project/CMakeLists.txt b/Tests/BuildDepends/Project/CMakeLists.txt
index c438e1d..c2576f3 100644
--- a/Tests/BuildDepends/Project/CMakeLists.txt
+++ b/Tests/BuildDepends/Project/CMakeLists.txt
@@ -102,6 +102,12 @@ target_link_libraries(zot zot_pch)
if(NOT CMAKE_OSX_ARCHITECTURES MATCHES "[;$]")
target_precompile_headers(zot_pch PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/zot_pch.hxx)
endif()
+if (CMAKE_CXX_DEPENDS_USE_COMPILER AND
+ CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS "4.4")
+ # Mixing pre-compile headers and flags to generate dependencies (-M options family)
+ # causes the compiler to crash
+ set_property(TARGET zot_pch PROPERTY DISABLE_PRECOMPILE_HEADERS ON)
+endif()
# Test the #include line macro transformation rule support.
set_property(
diff --git a/Tests/IncludeDirectories/CMakeLists.txt b/Tests/IncludeDirectories/CMakeLists.txt
index 1f5b664..d4c19c7 100644
--- a/Tests/IncludeDirectories/CMakeLists.txt
+++ b/Tests/IncludeDirectories/CMakeLists.txt
@@ -67,7 +67,11 @@ else()
endif()
# Test escaping of special characters in include directory paths.
-set(special_chars "~@%&{}()!'")
+set(special_chars "~@&{}()!'")
+if(NOT CMAKE_GENERATOR MATCHES "(Unix|MinGW|MSYS) Makefiles")
+ # when compiler is used for dependencies, special characters for make are not escaped
+ string(APPEND special_chars "%")
+endif()
if(NOT CMAKE_GENERATOR STREQUAL "Watcom WMake")
# Watcom seems to have no way to encode these characters.
string(APPEND special_chars "#=[]")
diff --git a/Tests/RunCMake/BuildDepends/CompilerDependencies.cmake b/Tests/RunCMake/BuildDepends/CompilerDependencies.cmake
new file mode 100644
index 0000000..8a9e600
--- /dev/null
+++ b/Tests/RunCMake/BuildDepends/CompilerDependencies.cmake
@@ -0,0 +1,46 @@
+enable_language(C)
+
+add_executable(main ${CMAKE_CURRENT_BINARY_DIR}/main.c)
+
+file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/check-$<LOWER_CASE:$<CONFIG>>.cmake CONTENT "
+set(check_pairs
+ \"$<TARGET_FILE:main>|${CMAKE_CURRENT_BINARY_DIR}/main.c\"
+ \"$<TARGET_FILE:main>|${CMAKE_CURRENT_BINARY_DIR}/main.h\"
+ )
+set(check_exes
+ \"$<TARGET_FILE:main>\"
+ )
+
+if (check_step EQUAL 2)
+ include(\"${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/Makefile.cmake\")
+ if (NOT CMAKE_DEPEND_INFO_FILES)
+ set(RunCMake_TEST_FAILED \"Variable CMAKE_DEPEND_INFO_FILES not found.\")
+ else()
+ include(\"${CMAKE_CURRENT_BINARY_DIR}/\${CMAKE_DEPEND_INFO_FILES}\")
+ if (NOT CMAKE_DEPENDS_DEPENDENCY_FILES)
+ set(RunCMake_TEST_FAILED \"Variable CMAKE_DEPENDS_DEPENDENCY_FILES not found.\")
+ else()
+ list(GET CMAKE_DEPENDS_DEPENDENCY_FILES 1 OBJECT_FILE)
+ list(GET CMAKE_DEPENDS_DEPENDENCY_FILES 3 DEP_FILE)
+ if (NOT EXISTS \"${CMAKE_CURRENT_BINARY_DIR}/\${DEP_FILE}\")
+ set(RunCMake_TEST_FAILED \"File \${DEP_FILE} not found.\")
+ else()
+ set (TARGET_DEP_FILE \"${CMAKE_CURRENT_BINARY_DIR}/\${DEP_FILE}\")
+ cmake_path(REPLACE_FILENAME TARGET_DEP_FILE \"compiler_depend.make\")
+ file(READ \"\${TARGET_DEP_FILE}\" DEPENDS_CONTENT)
+ if (WIN32)
+ string (REPLACE \"\\\\\" \"/\" DEPENDS_CONTENT \"\${DEPENDS_CONTENT}\")
+ string (TOLOWER \"\${DEPENDS_CONTENT}\" DEPENDS_CONTENT)
+ string (TOLOWER \"\${OBJECT_FILE}\" OBJECT_FILE)
+ else()
+ string(REPLACE \"\\\\ \" \" \" DEPENDS_CONTENT \"\${DEPENDS_CONTENT}\")
+ endif()
+ if(NOT DEPENDS_CONTENT MATCHES \"\${OBJECT_FILE} *:.+main.c\"
+ OR NOT DEPENDS_CONTENT MATCHES \"main.h\")
+ set(RunCMake_TEST_FAILED \"Dependency file '\${TARGET_DEP_FILE}' badly generated.\")
+ endif()
+ endif()
+ endif()
+ endif()
+endif()
+")
diff --git a/Tests/RunCMake/BuildDepends/CompilerDependencies.step1.cmake b/Tests/RunCMake/BuildDepends/CompilerDependencies.step1.cmake
new file mode 100644
index 0000000..1da2593
--- /dev/null
+++ b/Tests/RunCMake/BuildDepends/CompilerDependencies.step1.cmake
@@ -0,0 +1,9 @@
+file(WRITE "${RunCMake_TEST_BINARY_DIR}/main.h" [[
+#define COUNT 1
+]])
+
+file(WRITE "${RunCMake_TEST_BINARY_DIR}/main.c" [[
+#include "main.h"
+
+int main(void) { return COUNT; }
+]])
diff --git a/Tests/RunCMake/BuildDepends/CompilerDependencies.step2.cmake b/Tests/RunCMake/BuildDepends/CompilerDependencies.step2.cmake
new file mode 100644
index 0000000..e983665
--- /dev/null
+++ b/Tests/RunCMake/BuildDepends/CompilerDependencies.step2.cmake
@@ -0,0 +1,3 @@
+file(WRITE "${RunCMake_TEST_BINARY_DIR}/main.h" [[
+#define COUNT 2
+]])
diff --git a/Tests/RunCMake/BuildDepends/RunCMakeTest.cmake b/Tests/RunCMake/BuildDepends/RunCMakeTest.cmake
index 7a68c4b..23e222a 100644
--- a/Tests/RunCMake/BuildDepends/RunCMakeTest.cmake
+++ b/Tests/RunCMake/BuildDepends/RunCMakeTest.cmake
@@ -113,3 +113,13 @@ if(CMake_TEST_BuildDepends_GNU_AS)
set(ENV{ASM} "${CMake_TEST_BuildDepends_GNU_AS}")
run_BuildDepends(GNU-AS)
endif()
+
+if ((RunCMake_GENERATOR STREQUAL "Unix Makefiles"
+ AND (CMAKE_C_COMPILER_ID STREQUAL "GNU"
+ OR CMAKE_C_COMPILER_ID STREQUAL "Clang"
+ OR CMAKE_C_COMPILER_ID STREQUAL "AppleClang"))
+ OR (RunCMake_GENERATOR STREQUAL "NMake Makefiles"
+ AND MSVC_VERSION GREATER 1300
+ AND CMAKE_C_COMPILER_ID STREQUAL "MSVC"))
+ run_BuildDepends(CompilerDependencies)
+endif()
diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt
index 5b0b055..f094b42 100644
--- a/Tests/RunCMake/CMakeLists.txt
+++ b/Tests/RunCMake/CMakeLists.txt
@@ -203,7 +203,10 @@ if(NOT DEFINED CMake_TEST_BuildDepends_GNU_AS
set(CMake_TEST_BuildDepends_GNU_AS "${_gnu_as}")
endif()
endif()
+
add_RunCMake_test(BuildDepends
+ -DMSVC_VERSION=${MSVC_VERSION}
+ -DCMAKE_C_COMPILER_ID=${CMAKE_C_COMPILER_ID}
-DCMake_TEST_BuildDepends_GNU_AS=${CMake_TEST_BuildDepends_GNU_AS}
)
if(UNIX AND "${CMAKE_GENERATOR}" MATCHES "Unix Makefiles|Ninja")
diff --git a/Tests/RunCMake/Make/TargetMessages-OFF-build-check.cmake b/Tests/RunCMake/Make/TargetMessages-OFF-build-check.cmake
new file mode 100644
index 0000000..74a0564
--- /dev/null
+++ b/Tests/RunCMake/Make/TargetMessages-OFF-build-check.cmake
@@ -0,0 +1,3 @@
+
+set (CHECK_TARGET_MESSAGES OFF)
+include ("${CMAKE_CURRENT_LIST_DIR}/TargetMessages-validation.cmake")
diff --git a/Tests/RunCMake/Make/TargetMessages-OFF-build-stdout.txt b/Tests/RunCMake/Make/TargetMessages-OFF-build-stdout.txt
index 77a582a..8d98f9d 100644
--- a/Tests/RunCMake/Make/TargetMessages-OFF-build-stdout.txt
+++ b/Tests/RunCMake/Make/TargetMessages-OFF-build-stdout.txt
@@ -1,5 +1 @@
-^(([^B]|B[^u]|Bu[^i]|Bui[^l]|Buil[^t]|Built[^ ])[^
-]*
-)*Scanning dependencies of target CustomTarget(
-([^B]|B[^u]|Bu[^i]|Bui[^l]|Buil[^t]|Built[^ ])[^
-]*)*$
+.*
diff --git a/Tests/RunCMake/Make/TargetMessages-ON-build-check.cmake b/Tests/RunCMake/Make/TargetMessages-ON-build-check.cmake
new file mode 100644
index 0000000..afd8efb
--- /dev/null
+++ b/Tests/RunCMake/Make/TargetMessages-ON-build-check.cmake
@@ -0,0 +1,3 @@
+
+set (CHECK_TARGET_MESSAGES ON)
+include ("${CMAKE_CURRENT_LIST_DIR}/TargetMessages-validation.cmake")
diff --git a/Tests/RunCMake/Make/TargetMessages-ON-build-stdout.txt b/Tests/RunCMake/Make/TargetMessages-ON-build-stdout.txt
index a827624..8d98f9d 100644
--- a/Tests/RunCMake/Make/TargetMessages-ON-build-stdout.txt
+++ b/Tests/RunCMake/Make/TargetMessages-ON-build-stdout.txt
@@ -1,8 +1 @@
-^(([^B]|B[^u]|Bu[^i]|Bui[^l]|Buil[^t]|Built[^ ])[^
-]*
-)*Scanning dependencies of target CustomTarget(
-([^B]|B[^u]|Bu[^i]|Bui[^l]|Buil[^t]|Built[^ ])[^
-]*)*
-Built target CustomTarget(
-([^B]|B[^u]|Bu[^i]|Bui[^l]|Buil[^t]|Built[^ ])[^
-]*)*$
+.*
diff --git a/Tests/RunCMake/Make/TargetMessages-VAR-OFF-build-check.cmake b/Tests/RunCMake/Make/TargetMessages-VAR-OFF-build-check.cmake
new file mode 100644
index 0000000..74a0564
--- /dev/null
+++ b/Tests/RunCMake/Make/TargetMessages-VAR-OFF-build-check.cmake
@@ -0,0 +1,3 @@
+
+set (CHECK_TARGET_MESSAGES OFF)
+include ("${CMAKE_CURRENT_LIST_DIR}/TargetMessages-validation.cmake")
diff --git a/Tests/RunCMake/Make/TargetMessages-VAR-OFF-build-stdout.txt b/Tests/RunCMake/Make/TargetMessages-VAR-OFF-build-stdout.txt
index 77a582a..8d98f9d 100644
--- a/Tests/RunCMake/Make/TargetMessages-VAR-OFF-build-stdout.txt
+++ b/Tests/RunCMake/Make/TargetMessages-VAR-OFF-build-stdout.txt
@@ -1,5 +1 @@
-^(([^B]|B[^u]|Bu[^i]|Bui[^l]|Buil[^t]|Built[^ ])[^
-]*
-)*Scanning dependencies of target CustomTarget(
-([^B]|B[^u]|Bu[^i]|Bui[^l]|Buil[^t]|Built[^ ])[^
-]*)*$
+.*
diff --git a/Tests/RunCMake/Make/TargetMessages-VAR-ON-build-check.cmake b/Tests/RunCMake/Make/TargetMessages-VAR-ON-build-check.cmake
new file mode 100644
index 0000000..afd8efb
--- /dev/null
+++ b/Tests/RunCMake/Make/TargetMessages-VAR-ON-build-check.cmake
@@ -0,0 +1,3 @@
+
+set (CHECK_TARGET_MESSAGES ON)
+include ("${CMAKE_CURRENT_LIST_DIR}/TargetMessages-validation.cmake")
diff --git a/Tests/RunCMake/Make/TargetMessages-VAR-ON-build-stdout.txt b/Tests/RunCMake/Make/TargetMessages-VAR-ON-build-stdout.txt
index a827624..8d98f9d 100644
--- a/Tests/RunCMake/Make/TargetMessages-VAR-ON-build-stdout.txt
+++ b/Tests/RunCMake/Make/TargetMessages-VAR-ON-build-stdout.txt
@@ -1,8 +1 @@
-^(([^B]|B[^u]|Bu[^i]|Bui[^l]|Buil[^t]|Built[^ ])[^
-]*
-)*Scanning dependencies of target CustomTarget(
-([^B]|B[^u]|Bu[^i]|Bui[^l]|Buil[^t]|Built[^ ])[^
-]*)*
-Built target CustomTarget(
-([^B]|B[^u]|Bu[^i]|Bui[^l]|Buil[^t]|Built[^ ])[^
-]*)*$
+.*
diff --git a/Tests/RunCMake/Make/TargetMessages-validation.cmake b/Tests/RunCMake/Make/TargetMessages-validation.cmake
new file mode 100644
index 0000000..f3d7af1
--- /dev/null
+++ b/Tests/RunCMake/Make/TargetMessages-validation.cmake
@@ -0,0 +1,10 @@
+
+if (CHECK_TARGET_MESSAGES)
+ if (NOT actual_stdout MATCHES "Built target CustomTarget")
+ set (RunCMake_TEST_FAILED "Not found expected 'Built target' message.")
+ endif()
+else()
+ if (actual_stdout MATCHES "Built target CustomTarget")
+ set (RunCMake_TEST_FAILED "Found unexpected 'Built target' message.")
+ endif()
+endif()
diff --git a/bootstrap b/bootstrap
index b7fcd7e..c342f10 100755
--- a/bootstrap
+++ b/bootstrap
@@ -1054,12 +1054,14 @@ else
CMAKE_CXX_SOURCES="${CMAKE_CXX_SOURCES} \
cmDepends \
cmDependsC \
+ cmDependsCompiler \
cmGlobalUnixMakefileGenerator3 \
cmLocalUnixMakefileGenerator3 \
cmMakefileExecutableTargetGenerator \
cmMakefileLibraryTargetGenerator \
cmMakefileTargetGenerator \
cmMakefileUtilityTargetGenerator \
+ cmProcessTools \
"
JSONCPP_CXX_SOURCES=