diff options
author | Brad King <brad.king@kitware.com> | 2020-11-30 18:26:34 (GMT) |
---|---|---|
committer | Kitware Robot <kwrobot@kitware.com> | 2020-11-30 18:26:53 (GMT) |
commit | a24a4e18af1d40d6bf81045c5955aa08b5e51797 (patch) | |
tree | c47b8503b8bb1bee24bb481dcad4281b82208565 | |
parent | 0173cdcc012945901190e883283adfbbba61f491 (diff) | |
parent | 2c71d051facad13b0a42a57066be2489d5fff6ea (diff) | |
download | CMake-a24a4e18af1d40d6bf81045c5955aa08b5e51797.zip CMake-a24a4e18af1d40d6bf81045c5955aa08b5e51797.tar.gz CMake-a24a4e18af1d40d6bf81045c5955aa08b5e51797.tar.bz2 |
Merge topic 'makefiles-compiler-deps-optims'
2c71d051fa Makefiles Generators: use compiler for dependencies generation
afd0f6785d Refactoring: Abstract Makefile line continuation format
b6068ce407 Refactoring: enhance include file filtering
3401403f69 Refactoring: Introduce place-holder for dependency target.
a97c41bf8b Refactoring: Makefiles Generators: Add support for various depends scanners
Acked-by: Kitware Robot <kwrobot@kitware.com>
Acked-by: Brad King <brad.king@kitware.com>
Merge-request: !5528
69 files changed, 1413 insertions, 375 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/ARMCC.cmake b/Modules/Compiler/ARMCC.cmake index f949568..f4f1854 100644 --- a/Modules/Compiler/ARMCC.cmake +++ b/Modules/Compiler/ARMCC.cmake @@ -33,7 +33,7 @@ macro(__compiler_armcc lang) set(CMAKE_${lang}_LINK_EXECUTABLE "<CMAKE_LINKER> <CMAKE_${lang}_LINK_FLAGS> <LINK_FLAGS> <LINK_LIBRARIES> <OBJECTS> -o <TARGET> --list <TARGET_BASE>.map") set(CMAKE_${lang}_CREATE_STATIC_LIBRARY "<CMAKE_AR> --create -cr <TARGET> <LINK_FLAGS> <OBJECTS>") - set(CMAKE_DEPFILE_FLAGS_${lang} "--depend=<DEPFILE> --depend_single_line --no_depend_system_headers") + set(CMAKE_DEPFILE_FLAGS_${lang} "--depend=<DEP_FILE> --depend_single_line --no_depend_system_headers") set(CMAKE_${lang}_LINKER_WRAPPER_FLAG "-Xlinker" " ") endmacro() 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 fd8c2b7..cafc7dd 100644 --- a/Modules/Compiler/Clang-CUDA.cmake +++ b/Modules/Compiler/Clang-CUDA.cmake @@ -2,7 +2,13 @@ include(Compiler/Clang) __compiler_clang(CUDA) # Set explicitly, because __compiler_clang() doesn't set this if we're simulating MSVC. -set(CMAKE_DEPFILE_FLAGS_CUDA "-MD -MT <OBJECT> -MF <DEPFILE>") +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-ASM.cmake b/Modules/Compiler/GNU-ASM.cmake index 94af401..a935416 100644 --- a/Modules/Compiler/GNU-ASM.cmake +++ b/Modules/Compiler/GNU-ASM.cmake @@ -6,7 +6,7 @@ set(CMAKE_ASM_SOURCE_FILE_EXTENSIONS s;S;asm) __compiler_gnu(ASM) if(CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDOR_MATCH STREQUAL "GNU assembler") - set(CMAKE_DEPFILE_FLAGS_ASM${ASM_DIALECT} "--MD <DEPFILE>") + set(CMAKE_DEPFILE_FLAGS_ASM${ASM_DIALECT} "--MD <DEP_FILE>") set(CMAKE_ASM${ASM_DIALECT}_LINK_EXECUTABLE "<CMAKE_LINKER> <FLAGS> <CMAKE_ASM${ASM_DIALECT}_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>") set(CMAKE_ASM_DEFINE_FLAG "--defsym ") 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/GNU.cmake b/Modules/Compiler/GNU.cmake index 81ab3a2..928e726 100644 --- a/Modules/Compiler/GNU.cmake +++ b/Modules/Compiler/GNU.cmake @@ -48,7 +48,7 @@ macro(__compiler_gnu lang) # distcc does not transform -o to -MT when invoking the preprocessor # internally, as it ought to. Work around this bug by setting -MT here # even though it isn't strictly necessary. - set(CMAKE_DEPFILE_FLAGS_${lang} "-MD -MT <OBJECT> -MF <DEPFILE>") + set(CMAKE_DEPFILE_FLAGS_${lang} "-MD -MT <DEP_TARGET> -MF <DEP_FILE>") endif() # Initial configuration flags. diff --git a/Modules/Compiler/IAR.cmake b/Modules/Compiler/IAR.cmake index f3938a9..b8c0770 100644 --- a/Modules/Compiler/IAR.cmake +++ b/Modules/Compiler/IAR.cmake @@ -49,7 +49,7 @@ macro(__compiler_iar_ilink lang) set(CMAKE_${lang}_CREATE_ASSEMBLY_SOURCE "<CMAKE_${lang}_COMPILER> ${CMAKE_IAR_${lang}_FLAG} --silent <SOURCE> <DEFINES> <INCLUDES> <FLAGS> -lAH <ASSEMBLY_SOURCE> -o <OBJECT>.dummy") set(CMAKE_${lang}_RESPONSE_FILE_LINK_FLAG "-f ") - set(CMAKE_DEPFILE_FLAGS_${lang} "--dependencies=ns <DEPFILE>") + set(CMAKE_DEPFILE_FLAGS_${lang} "--dependencies=ns <DEP_FILE>") string(APPEND CMAKE_${lang}_FLAGS_INIT " ") string(APPEND CMAKE_${lang}_FLAGS_DEBUG_INIT " -r") @@ -85,7 +85,7 @@ macro(__compiler_iar_xlink lang) set(CMAKE_${lang}_CREATE_ASSEMBLY_SOURCE "<CMAKE_${lang}_COMPILER> ${CMAKE_IAR_${lang}_FLAG} --silent <SOURCE> <DEFINES> <INCLUDES> <FLAGS> -lAH <ASSEMBLY_SOURCE> -o <OBJECT>.dummy") set(CMAKE_${lang}_RESPONSE_FILE_LINK_FLAG "-f ") - set(CMAKE_DEPFILE_FLAGS_${lang} "--dependencies=ns <DEPFILE>") + set(CMAKE_DEPFILE_FLAGS_${lang} "--dependencies=ns <DEP_FILE>") string(APPEND CMAKE_${lang}_FLAGS_INIT " ") string(APPEND CMAKE_${lang}_FLAGS_DEBUG_INIT " -r") diff --git a/Modules/Compiler/Intel-C.cmake b/Modules/Compiler/Intel-C.cmake index ec3bfd8..a7c71bd 100644 --- a/Modules/Compiler/Intel-C.cmake +++ b/Modules/Compiler/Intel-C.cmake @@ -5,7 +5,13 @@ string(APPEND CMAKE_C_FLAGS_MINSIZEREL_INIT " -DNDEBUG") string(APPEND CMAKE_C_FLAGS_RELEASE_INIT " -DNDEBUG") string(APPEND CMAKE_C_FLAGS_RELWITHDEBINFO_INIT " -DNDEBUG") -set(CMAKE_DEPFILE_FLAGS_C "-MD -MT <OBJECT> -MF <DEPFILE>") +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 b71b946..dd9681e 100644 --- a/Modules/Compiler/Intel-CXX.cmake +++ b/Modules/Compiler/Intel-CXX.cmake @@ -5,7 +5,13 @@ string(APPEND CMAKE_CXX_FLAGS_MINSIZEREL_INIT " -DNDEBUG") string(APPEND CMAKE_CXX_FLAGS_RELEASE_INIT " -DNDEBUG") string(APPEND CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT " -DNDEBUG") -set(CMAKE_DEPFILE_FLAGS_CXX "-MD -MT <OBJECT> -MF <DEPFILE>") +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 2e9792a..e4d5c97 100644 --- a/Modules/Compiler/Intel-ISPC.cmake +++ b/Modules/Compiler/Intel-ISPC.cmake @@ -3,7 +3,13 @@ include(Compiler/CMakeCommonCompilerMacros) # Not aware of any verbose flag for ISPC #set(CMAKE_ISPC_VERBOSE_FLAG ) -set(CMAKE_DEPFILE_FLAGS_ISPC "-M -MT <OBJECT> -MF <DEPFILE>") +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 95a51f6..3e8d4eb 100644 --- a/Modules/Compiler/NVIDIA-CUDA.cmake +++ b/Modules/Compiler/NVIDIA-CUDA.cmake @@ -28,7 +28,15 @@ if (CMAKE_CUDA_COMPILER_VERSION VERSION_GREATER_EQUAL 10.2.89) # The -MD flag was only added to nvcc in 10.2 so # before that we had to invoke the compiler twice # to get header dependency information - set(CMAKE_DEPFILE_FLAGS_CUDA "-MD -MT <OBJECT> -MF <DEPFILE>") + 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") diff --git a/Modules/Compiler/QCC.cmake b/Modules/Compiler/QCC.cmake index 10e1389..7fbfd10 100644 --- a/Modules/Compiler/QCC.cmake +++ b/Modules/Compiler/QCC.cmake @@ -14,7 +14,7 @@ macro(__compiler_qcc lang) set(CMAKE_${lang}_COMPILE_OPTIONS_SYSROOT "-Wc,-isysroot,") set(CMAKE_INCLUDE_SYSTEM_FLAG_${lang} "-Wp,-isystem,") - set(CMAKE_DEPFILE_FLAGS_${lang} "-Wp,-MD,<DEPFILE> -Wp,-MT,<OBJECT> -Wp,-MF,<DEPFILE>") + set(CMAKE_DEPFILE_FLAGS_${lang} "-Wp,-MD,<DEP_FILE> -Wp,-MT,<DEP_TARGET> -Wp,-MF,<DEP_FILE>") set(CMAKE_${lang}_LINKER_WRAPPER_FLAG "-Wl,") set(CMAKE_${lang}_LINKER_WRAPPER_FLAG_SEP ",") diff --git a/Modules/Compiler/SunPro-C.cmake b/Modules/Compiler/SunPro-C.cmake index 7e962b8..c98656f 100644 --- a/Modules/Compiler/SunPro-C.cmake +++ b/Modules/Compiler/SunPro-C.cmake @@ -22,7 +22,7 @@ string(APPEND CMAKE_C_FLAGS_MINSIZEREL_INIT " -xO2 -xspace -DNDEBUG") string(APPEND CMAKE_C_FLAGS_RELEASE_INIT " -xO3 -DNDEBUG") string(APPEND CMAKE_C_FLAGS_RELWITHDEBINFO_INIT " -g -xO2 -DNDEBUG") -set(CMAKE_DEPFILE_FLAGS_C "-xMD -xMF <DEPFILE>") +set(CMAKE_DEPFILE_FLAGS_C "-xMD -xMF <DEP_FILE>") # Initialize C link type selection flags. These flags are used when # building a shared library, shared module, or executable that links diff --git a/Modules/Compiler/SunPro-CXX.cmake b/Modules/Compiler/SunPro-CXX.cmake index c946c64..aa8a9c5 100644 --- a/Modules/Compiler/SunPro-CXX.cmake +++ b/Modules/Compiler/SunPro-CXX.cmake @@ -22,7 +22,7 @@ string(APPEND CMAKE_CXX_FLAGS_MINSIZEREL_INIT " -xO2 -xspace -DNDEBUG") string(APPEND CMAKE_CXX_FLAGS_RELEASE_INIT " -xO3 -DNDEBUG") string(APPEND CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT " -g -xO2 -DNDEBUG") -set(CMAKE_DEPFILE_FLAGS_CXX "-xMD -xMF <DEPFILE>") +set(CMAKE_DEPFILE_FLAGS_CXX "-xMD -xMF <DEP_FILE>") # Initialize C link type selection flags. These flags are used when # building a shared library, shared module, or executable that links diff --git a/Modules/Compiler/TI.cmake b/Modules/Compiler/TI.cmake index f631688..c8c1635 100644 --- a/Modules/Compiler/TI.cmake +++ b/Modules/Compiler/TI.cmake @@ -18,7 +18,7 @@ macro(__compiler_ti lang) set(CMAKE_${lang}_RESPONSE_FILE_FLAG "--cmd_file=") set(CMAKE_INCLUDE_FLAG_${lang} "--include_path=") - set(CMAKE_DEPFILE_FLAGS_${lang} "--preproc_with_compile --preproc_dependency=<DEPFILE>") + set(CMAKE_DEPFILE_FLAGS_${lang} "--preproc_with_compile --preproc_dependency=<DEP_FILE>") set(CMAKE_${lang}_CREATE_PREPROCESSED_SOURCE "<CMAKE_${lang}_COMPILER> --preproc_only ${__COMPILER_TI_SOURCE_FLAG_${lang}}=<SOURCE> <DEFINES> <INCLUDES> <FLAGS> --output_file=<PREPROCESSED_SOURCE>") set(CMAKE_${lang}_CREATE_ASSEMBLY_SOURCE "<CMAKE_${lang}_COMPILER> --compile_only --skip_assembler ${__COMPILER_TI_SOURCE_FLAG_${lang}}=<SOURCE> <DEFINES> <INCLUDES> <FLAGS> --output_file=<ASSEMBLY_SOURCE>") diff --git a/Modules/Compiler/XL.cmake b/Modules/Compiler/XL.cmake index fc71ab4..8b9d4a9 100644 --- a/Modules/Compiler/XL.cmake +++ b/Modules/Compiler/XL.cmake @@ -30,5 +30,5 @@ macro(__compiler_xl lang) set(CMAKE_${lang}_CREATE_PREPROCESSED_SOURCE "<CMAKE_${lang}_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -E <SOURCE> > <PREPROCESSED_SOURCE>") set(CMAKE_${lang}_CREATE_ASSEMBLY_SOURCE "<CMAKE_${lang}_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -S <SOURCE> -o <ASSEMBLY_SOURCE>") - set(CMAKE_DEPFILE_FLAGS_${lang} "-MF <DEPFILE> -qmakedep=gcc") + set(CMAKE_DEPFILE_FLAGS_${lang} "-MF <DEP_FILE> -qmakedep=gcc") endmacro() 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-Clang.cmake b/Modules/Platform/Windows-Clang.cmake index 6275043..d10ea8f 100644 --- a/Modules/Platform/Windows-Clang.cmake +++ b/Modules/Platform/Windows-Clang.cmake @@ -27,7 +27,7 @@ macro(__windows_compiler_clang_gnu lang) set(CMAKE_SHARED_MODULE_SUFFIX ".dll") set(CMAKE_STATIC_LIBRARY_SUFFIX ".lib") if(NOT "${lang}" STREQUAL "ASM") - set(CMAKE_DEPFILE_FLAGS_${lang} "-MD -MT <OBJECT> -MF <DEPFILE>") + set(CMAKE_DEPFILE_FLAGS_${lang} "-MD -MT <DEP_TARGET> -MF <DEP_FILE>") endif() set(CMAKE_FIND_LIBRARY_PREFIXES "lib" "") @@ -111,7 +111,7 @@ macro(__enable_llvm_rc_preprocessing clang_option_prefix) set(CMAKE_RC_PREPROCESSOR CMAKE_CXX_COMPILER) endif() if(DEFINED CMAKE_RC_PREPROCESSOR) - set(CMAKE_DEPFILE_FLAGS_RC "${clang_option_prefix}-MD ${clang_option_prefix}-MF ${clang_option_prefix}<DEPFILE>") + set(CMAKE_DEPFILE_FLAGS_RC "${clang_option_prefix}-MD ${clang_option_prefix}-MF ${clang_option_prefix}<DEP_FILE>") # The <FLAGS> are passed to the preprocess and the resource compiler to pick # up the eventual -D / -C options passed through the CMAKE_RC_FLAGS. set(CMAKE_RC_COMPILE_OBJECT "<CMAKE_COMMAND> -E cmake_llvm_rc <SOURCE> <OBJECT>.pp <${CMAKE_RC_PREPROCESSOR}> <DEFINES> -DRC_INVOKED <INCLUDES> <FLAGS> -E -- <SOURCE> ++ <CMAKE_RC_COMPILER> <DEFINES> -I <SOURCE_DIR> <INCLUDES> <FLAGS> /fo <OBJECT> <OBJECT>.pp") diff --git a/Modules/Platform/Windows-Intel-C.cmake b/Modules/Platform/Windows-Intel-C.cmake index 06d8f50..3cbc7a5 100644 --- a/Modules/Platform/Windows-Intel-C.cmake +++ b/Modules/Platform/Windows-Intel-C.cmake @@ -1,4 +1,11 @@ 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 <OBJECT> -QMF <DEPFILE>") +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 666de6e..6539f64 100644 --- a/Modules/Platform/Windows-Intel-CXX.cmake +++ b/Modules/Platform/Windows-Intel-CXX.cmake @@ -2,4 +2,11 @@ include(Platform/Windows-Intel) 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 <OBJECT> -QMF <DEPFILE>") +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 7608056..c3b7e50 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -227,6 +227,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.cxx b/Source/cmGlobalUnixMakefileGenerator3.cxx index 9c3a533..11e2cd6 100644 --- a/Source/cmGlobalUnixMakefileGenerator3.cxx +++ b/Source/cmGlobalUnixMakefileGenerator3.cxx @@ -44,6 +44,7 @@ cmGlobalUnixMakefileGenerator3::cmGlobalUnixMakefileGenerator3(cmake* cm) #endif this->IncludeDirective = "include"; + this->LineContinueDirective = "\\\n"; this->DefineWindowsNULL = false; this->PassMakeflags = false; this->UnixCD = true; diff --git a/Source/cmGlobalUnixMakefileGenerator3.h b/Source/cmGlobalUnixMakefileGenerator3.h index 77d0827..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; } @@ -170,6 +176,7 @@ public: void ComputeTargetObjectDirectory(cmGeneratorTarget* gt) const override; std::string IncludeDirective; + std::string LineContinueDirective; bool DefineWindowsNULL; bool PassMakeflags; bool UnixCD; @@ -218,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/cmGlobalWatcomWMakeGenerator.cxx b/Source/cmGlobalWatcomWMakeGenerator.cxx index d6a7afa..3e2d92d 100644 --- a/Source/cmGlobalWatcomWMakeGenerator.cxx +++ b/Source/cmGlobalWatcomWMakeGenerator.cxx @@ -25,6 +25,7 @@ cmGlobalWatcomWMakeGenerator::cmGlobalWatcomWMakeGenerator(cmake* cm) #endif cm->GetState()->SetWatcomWMake(true); this->IncludeDirective = "!include"; + this->LineContinueDirective = "&\n"; this->DefineWindowsNULL = true; this->UnixCD = false; this->MakeSilentFlag = "-h"; @@ -37,7 +38,6 @@ void cmGlobalWatcomWMakeGenerator::EnableLanguage( mf->AddDefinition("WATCOM", "1"); mf->AddDefinition("CMAKE_QUOTE_INCLUDE_PATHS", "1"); mf->AddDefinition("CMAKE_MANGLE_OBJECT_FILE_NAMES", "1"); - mf->AddDefinition("CMAKE_MAKE_LINE_CONTINUE", "&"); mf->AddDefinition("CMAKE_MAKE_SYMBOLIC_RULE", ".SYMBOLIC"); mf->AddDefinition("CMAKE_GENERATOR_CC", "wcl386"); mf->AddDefinition("CMAKE_GENERATOR_CXX", "wcl386"); diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h index 30371c5..09e820a 100644 --- a/Source/cmLocalGenerator.h +++ b/Source/cmLocalGenerator.h @@ -43,6 +43,13 @@ enum class cmSourceOutputKind OutputOrByproduct }; +/** What scanner to use for dependencies lookup. */ +enum class cmDependencyScannerKind +{ + CMake, + Compiler +}; + /** Target and source file which have a specific output. */ struct cmSourcesWithOutput { diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index dd27084..08cefb7 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -5,18 +5,22 @@ #include <algorithm> #include <cassert> #include <cstdio> +#include <functional> #include <sstream> #include <utility> #include <cm/memory> +#include <cm/string_view> #include <cm/vector> #include <cmext/algorithm> #include "cmsys/FStream.hxx" #include "cmsys/Terminal.h" +#include "cmCMakePath.h" #include "cmCustomCommand.h" // IWYU pragma: keep #include "cmCustomCommandGenerator.h" +#include "cmDependsCompiler.h" #include "cmFileTimeCache.h" #include "cmGeneratedFileStream.h" #include "cmGeneratorExpression.h" @@ -50,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('.'); @@ -65,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()) @@ -552,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"; } @@ -1298,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( @@ -1721,178 +1827,193 @@ void cmLocalUnixMakefileGenerator3::ClearDependencies(cmMakefile* mf, cmDepends clearer; clearer.SetVerbose(verbose); for (std::string const& file : files) { - std::string dir = cmSystemTools::GetFilenamePath(file); + auto snapshot = mf->GetState()->CreateBaseSnapshot(); + cmMakefile lmf(mf->GetGlobalGenerator(), snapshot); + lmf.ReadListFile(file); - // Clear the implicit dependency makefile. - std::string dependFile = dir + "/depend.make"; - clearer.Clear(dependFile); + if (!lmf.GetSafeDefinition("CMAKE_DEPENDS_LANGUAGES").empty()) { + std::string dir = cmSystemTools::GetFilenamePath(file); - // Remove the internal dependency check file to force - // regeneration. - std::string internalDependFile = dir + "/depend.internal"; - cmSystemTools::RemoveFile(internalDependFile); - } -} - -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(std::string sourceDir, std::string binaryDir) - : SourceDir(std::move(sourceDir)) - , BinaryDir(std::move(binaryDir)) - { - } + // Clear the implicit dependency makefile. + std::string dependFile = dir + "/depend.make"; + clearer.Clear(dependFile); - // Operator evaluating the predicate - bool operator()(const std::string& path) const - { - // Keep all relative paths: - if (!cmSystemTools::FileIsFullPath(path)) { - return false; + // Remove the internal dependency check file to force + // regeneration. + std::string internalDependFile = dir + "/depend.internal"; + cmSystemTools::RemoveFile(internalDependFile); } - // If it's an absolute path, check if it starts with the source - // directory: - return ( - !(IsInDirectory(SourceDir, path) || IsInDirectory(BinaryDir, path))); - } -private: - // Helper function used by the predicate - static bool IsInDirectory(const std::string& baseDir, - const std::string& testDir) - { - // First check if the test directory "starts with" the base directory: - if (!cmHasPrefix(testDir, baseDir)) { - 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 does, then check that it's either the same string, or that the - // next character is a slash: - return ((testDir.size() == baseDir.size()) || - (testDir[baseDir.size()] == '/')); } - - // The path to the source directory - std::string SourceDir; - // The path to the binary directory - std::string 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 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); + } + if (cmProp xform = + target->GetProperty("IMPLICIT_DEPENDS_INCLUDE_TRANSFORM")) { + cmExpandList(*xform, transformRules); } - for (std::string const& include : includes) { - cmakefileStream << " \"" - << this->MaybeConvertToRelativePath(binaryDir, include) - << "\"\n"; + 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) @@ -2049,16 +2170,18 @@ std::string cmLocalUnixMakefileGenerator3::GetTargetDirectory( } cmLocalUnixMakefileGenerator3::ImplicitDependLanguageMap const& -cmLocalUnixMakefileGenerator3::GetImplicitDepends(const cmGeneratorTarget* tgt) +cmLocalUnixMakefileGenerator3::GetImplicitDepends( + const cmGeneratorTarget* tgt, cmDependencyScannerKind scanner) { - return this->ImplicitDepends[tgt->GetName()]; + return this->ImplicitDepends[tgt->GetName()][scanner]; } void cmLocalUnixMakefileGenerator3::AddImplicitDepends( const cmGeneratorTarget* tgt, const std::string& lang, - const std::string& obj, const std::string& src) + const std::string& obj, const std::string& src, + cmDependencyScannerKind scanner) { - this->ImplicitDepends[tgt->GetName()][lang][obj].push_back(src); + this->ImplicitDepends[tgt->GetName()][scanner][lang][obj].push_back(src); } void cmLocalUnixMakefileGenerator3::CreateCDCommand( diff --git a/Source/cmLocalUnixMakefileGenerator3.h b/Source/cmLocalUnixMakefileGenerator3.h index 5edca2a..14dd0ba 100644 --- a/Source/cmLocalUnixMakefileGenerator3.h +++ b/Source/cmLocalUnixMakefileGenerator3.h @@ -13,6 +13,7 @@ #include "cmDepends.h" #include "cmLocalCommonGenerator.h" +#include "cmLocalGenerator.h" class cmCustomCommand; class cmCustomCommandGenerator; @@ -152,23 +153,21 @@ public: // File pairs for implicit dependency scanning. The key of the map // is the depender and the value is the explicit dependee. - struct ImplicitDependFileMap : public cmDepends::DependencyMap - { - }; - struct ImplicitDependLanguageMap - : public std::map<std::string, ImplicitDependFileMap> - { - }; - struct ImplicitDependTargetMap - : public std::map<std::string, ImplicitDependLanguageMap> - { - }; + using ImplicitDependFileMap = cmDepends::DependencyMap; + using ImplicitDependLanguageMap = + std::map<std::string, ImplicitDependFileMap>; + using ImplicitDependScannerMap = + std::map<cmDependencyScannerKind, ImplicitDependLanguageMap>; + using ImplicitDependTargetMap = + std::map<std::string, ImplicitDependScannerMap>; ImplicitDependLanguageMap const& GetImplicitDepends( - cmGeneratorTarget const* tgt); + cmGeneratorTarget const* tgt, + cmDependencyScannerKind scanner = cmDependencyScannerKind::CMake); - void AddImplicitDepends(cmGeneratorTarget const* tgt, - const std::string& lang, const std::string& obj, - const std::string& src); + void AddImplicitDepends( + cmGeneratorTarget const* tgt, const std::string& lang, + const std::string& obj, const std::string& src, + cmDependencyScannerKind scanner = cmDependencyScannerKind::CMake); // write the target rules for the local Makefile into the stream void WriteLocalAllRules(std::ostream& ruleFileStream); diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index 71660a0..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" @@ -23,6 +25,7 @@ #include "cmGlobalUnixMakefileGenerator3.h" #include "cmLinkLineComputer.h" // IWYU pragma: keep #include "cmLocalCommonGenerator.h" +#include "cmLocalGenerator.h" #include "cmLocalUnixMakefileGenerator3.h" #include "cmMakefile.h" #include "cmMakefileExecutableTargetGenerator.h" @@ -325,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. @@ -472,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); @@ -511,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()); @@ -553,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); } } @@ -688,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 @@ -782,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 @@ -953,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); @@ -978,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); } @@ -987,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 = @@ -1387,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( @@ -1425,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 = @@ -1543,12 +1669,7 @@ void cmMakefileTargetGenerator::WriteObjectsVariable( << this->GeneratorTarget->GetName() << "\n" << variableName << " ="; std::string object; - std::string lineContinue; - if (cmProp p = this->Makefile->GetDefinition("CMAKE_MAKE_LINE_CONTINUE")) { - lineContinue = *p; - } else { - lineContinue = "\\"; - } + const auto& lineContinue = this->GlobalGenerator->LineContinueDirective; cmProp pchExtension = this->Makefile->GetDefinition("CMAKE_PCH_EXTENSION"); @@ -1556,7 +1677,7 @@ void cmMakefileTargetGenerator::WriteObjectsVariable( if (cmSystemTools::StringEndsWith(obj, cmToCStr(pchExtension))) { continue; } - *this->BuildFileStream << " " << lineContinue << "\n"; + *this->BuildFileStream << " " << lineContinue; *this->BuildFileStream << cmLocalUnixMakefileGenerator3::ConvertToQuotedOutputPath( obj, useWatcomQuote); @@ -1579,7 +1700,7 @@ void cmMakefileTargetGenerator::WriteObjectsVariable( for (std::string const& obj : this->ExternalObjects) { object = this->LocalGenerator->MaybeConvertToRelativePath(currentBinDir, obj); - *this->BuildFileStream << " " << lineContinue << "\n"; + *this->BuildFileStream << " " << lineContinue; *this->BuildFileStream << cmLocalUnixMakefileGenerator3::ConvertToQuotedOutputPath( obj, useWatcomQuote); @@ -1843,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/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index 6085b25..4ac08e0 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -548,6 +548,7 @@ cmNinjaRule GetScanRule( scanVars.Object = "$out"; // for RULE_LAUNCH_COMPILE scanVars.PreprocessedSource = "$out"; scanVars.DependencyFile = rule.DepFile.c_str(); + scanVars.DependencyTarget = "$out"; // Scanning needs the same preprocessor settings as direct compilation would. scanVars.Source = vars.Source; @@ -750,8 +751,8 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang, const std::string flagsName = cmStrCat("CMAKE_DEPFILE_FLAGS_", lang); std::string depfileFlags = mf->GetSafeDefinition(flagsName); if (!depfileFlags.empty()) { - cmSystemTools::ReplaceString(depfileFlags, "<DEPFILE>", "$DEP_FILE"); - cmSystemTools::ReplaceString(depfileFlags, "<OBJECT>", "$out"); + cmSystemTools::ReplaceString(depfileFlags, "<DEP_FILE>", "$DEP_FILE"); + cmSystemTools::ReplaceString(depfileFlags, "<DEP_TARGET>", "$out"); cmSystemTools::ReplaceString( depfileFlags, "<CMAKE_C_COMPILER>", cmToCStr(mf->GetDefinition("CMAKE_C_COMPILER"))); diff --git a/Source/cmRulePlaceholderExpander.cxx b/Source/cmRulePlaceholderExpander.cxx index f5f9c67..5363fef 100644 --- a/Source/cmRulePlaceholderExpander.cxx +++ b/Source/cmRulePlaceholderExpander.cxx @@ -3,7 +3,6 @@ #include "cmRulePlaceholderExpander.h" #include <cctype> -#include <cstring> #include <utility> #include "cmOutputConverter.h" @@ -20,11 +19,6 @@ cmRulePlaceholderExpander::cmRulePlaceholderExpander( { } -cmRulePlaceholderExpander::RuleVariables::RuleVariables() -{ - memset(this, 0, sizeof(*this)); -} - std::string cmRulePlaceholderExpander::ExpandRuleVariable( cmOutputConverter* outputConverter, std::string const& variable, const RuleVariables& replaceValues) @@ -141,6 +135,11 @@ std::string cmRulePlaceholderExpander::ExpandRuleVariable( return replaceValues.DependencyFile; } } + if (replaceValues.DependencyTarget) { + if (variable == "DEP_TARGET") { + return replaceValues.DependencyTarget; + } + } if (replaceValues.Fatbinary) { if (variable == "FATBINARY") { return replaceValues.Fatbinary; diff --git a/Source/cmRulePlaceholderExpander.h b/Source/cmRulePlaceholderExpander.h index c8d107d..710f8a6 100644 --- a/Source/cmRulePlaceholderExpander.h +++ b/Source/cmRulePlaceholderExpander.h @@ -27,45 +27,45 @@ public: // ExpandRuleVariables struct RuleVariables { - RuleVariables(); - const char* CMTargetName; - const char* CMTargetType; - const char* TargetPDB; - const char* TargetCompilePDB; - const char* TargetVersionMajor; - const char* TargetVersionMinor; - const char* Language; - const char* AIXExports; - const char* Objects; - const char* Target; - const char* LinkLibraries; - const char* Source; - const char* AssemblySource; - const char* PreprocessedSource; - const char* Output; - const char* Object; - const char* ObjectDir; - const char* ObjectFileDir; - const char* Flags; - const char* ObjectsQuoted; - const char* SONameFlag; - const char* TargetSOName; - const char* TargetInstallNameDir; - const char* LinkFlags; - const char* Manifests; - const char* LanguageCompileFlags; - const char* Defines; - const char* Includes; - const char* DependencyFile; - const char* FilterPrefix; - const char* SwiftLibraryName; - const char* SwiftModule; - const char* SwiftModuleName; - const char* SwiftOutputFileMap; - const char* SwiftSources; - const char* ISPCHeader; - const char* Fatbinary; - const char* RegisterFile; + const char* CMTargetName = nullptr; + const char* CMTargetType = nullptr; + const char* TargetPDB = nullptr; + const char* TargetCompilePDB = nullptr; + const char* TargetVersionMajor = nullptr; + const char* TargetVersionMinor = nullptr; + const char* Language = nullptr; + const char* AIXExports = nullptr; + const char* Objects = nullptr; + const char* Target = nullptr; + const char* LinkLibraries = nullptr; + const char* Source = nullptr; + const char* AssemblySource = nullptr; + const char* PreprocessedSource = nullptr; + const char* Output = nullptr; + const char* Object = nullptr; + const char* ObjectDir = nullptr; + const char* ObjectFileDir = nullptr; + const char* Flags = nullptr; + const char* ObjectsQuoted = nullptr; + const char* SONameFlag = nullptr; + const char* TargetSOName = nullptr; + const char* TargetInstallNameDir = nullptr; + const char* LinkFlags = nullptr; + const char* Manifests = nullptr; + const char* LanguageCompileFlags = nullptr; + const char* Defines = nullptr; + const char* Includes = nullptr; + const char* DependencyFile = nullptr; + const char* DependencyTarget = nullptr; + const char* FilterPrefix = nullptr; + const char* SwiftLibraryName = nullptr; + const char* SwiftModule = nullptr; + const char* SwiftModuleName = nullptr; + const char* SwiftOutputFileMap = nullptr; + const char* SwiftSources = nullptr; + const char* ISPCHeader = nullptr; + const char* Fatbinary = nullptr; + const char* RegisterFile = nullptr; }; // Expand rule variables in CMake of the type found in language rules 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 0b02184..1995e4b 100644 --- a/Tests/RunCMake/CMakeLists.txt +++ b/Tests/RunCMake/CMakeLists.txt @@ -204,7 +204,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() @@ -1054,12 +1054,14 @@ else CMAKE_CXX_SOURCES="${CMAKE_CXX_SOURCES} \ cmDepends \ cmDependsC \ + cmDependsCompiler \ cmGlobalUnixMakefileGenerator3 \ cmLocalUnixMakefileGenerator3 \ cmMakefileExecutableTargetGenerator \ cmMakefileLibraryTargetGenerator \ cmMakefileTargetGenerator \ cmMakefileUtilityTargetGenerator \ + cmProcessTools \ " JSONCPP_CXX_SOURCES= |