How to force cmake use -MMD flag instead of -MD

Tool chain used is arm-none-eabi-gcc.
I need to compile the project using -MMD flag.
I’ve try CMAKE_C_FLAGS and add_compile_options().
Nothing is work.
CMake will append -MD automatically.
I believe when compiler see gcc -MMD -MD, compiler will use -MD.
How do I make CMake use -MMD flag instead of -MD?

It doesn’t look like CMake provides a way to do that. You might be able to replace it in the CMAKE_DEPFILE_FLAGS_<LANG> variable though.

At least for Ninja build, this doesn’t longer work on OSX!

In what way?

set(CMAKE_DEPFILE_FLAGS_CXX "-MMD" CACHE STRING "dependency flag" FORCE)

grep -r  -- -MD CMakeFiles/rules.ninja 
CMakeFiles/rules.ninja:  command = ${LAUNCHER}${CODE_CHECK}/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/c++ $DEFINES $INCLUDES $FLAGS -MD -MT $out -MF $DEP_FILE -o $out -c $in
CMakeFiles/rules.ninja:  command = ${LAUNCHER}${CODE_CHECK}/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/c++ $DEFINES $INCLUDES $FLAGS -MD -MT $out -MF $DEP_FILE -o $out -c $in
bash-5.2$ 
bash-5.2$ cmake --workflow --preset default --fresh 2>&1 | grep CMAKE_DEPFILE_FLAGS_
/Users/clausklein/Workspace/cpp/ModernCmakeStarter/CMakeLists.txt(20):  set(CMAKE_DEPFILE_FLAGS_CXX -MMD CACHE STRING dependency flag FORCE )
/Users/clausklein/Workspace/cpp/ModernCmakeStarter/CMakeLists.txt(21):  set(CMAKE_DEPFILE_FLAGS_C -MMD CACHE STRING dependency flag FORCE )
/usr/local/Cellar/cmake/3.27.6/share/cmake/Modules/Compiler/GNU.cmake(52):  set(CMAKE_DEPFILE_FLAGS_CXX -MD -MT <DEP_TARGET> -MF <DEP_FILE> )
/usr/local/Cellar/cmake/3.27.6/share/cmake/Modules/Compiler/AppleClang-CXX.cmake(7):  if(( NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER ) AND CMAKE_GENERATOR MATCHES Makefiles AND CMAKE_DEPFILE_FLAGS_CXX )
/usr/local/Cellar/cmake/3.27.6/share/cmake/Modules/Compiler/GNU.cmake(52):  set(CMAKE_DEPFILE_FLAGS_CXX -MD -MT <DEP_TARGET> -MF <DEP_FILE> )
/usr/local/Cellar/cmake/3.27.6/share/cmake/Modules/Compiler/AppleClang-CXX.cmake(7):  if(( NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER ) AND CMAKE_GENERATOR MATCHES Makefiles AND CMAKE_DEPFILE_FLAGS_CXX )
bash-5.2$ 

Here maybe a problem too on OSX Modules/Compiler/Clang-CXX.cmake

if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 16.0)
  if("x${CMAKE_CXX_COMPILER_FRONTEND_VARIANT}" STREQUAL "xGNU")
    string(CONCAT CMAKE_EXPERIMENTAL_CXX_SCANDEP_SOURCE
      "\"${CMAKE_CXX_COMPILER_CLANG_SCAN_DEPS}\""
      " -format=p1689"
      " --"
      " <CMAKE_CXX_COMPILER> <DEFINES> <INCLUDES> <FLAGS>"
      " -x c++ <SOURCE> -c -o <OBJECT>"
      " -MT <DYNDEP_FILE>"
      " -MD -MF <DEP_FILE>"
      " > <DYNDEP_FILE>")
    set(CMAKE_EXPERIMENTAL_CXX_MODULE_MAP_FORMAT "clang")
    set(CMAKE_EXPERIMENTAL_CXX_MODULE_MAP_FLAG "@<MODULE_MAP_FILE>")
    set(CMAKE_EXPERIMENTAL_CXX_MODULE_BMI_ONLY_FLAG "--precompile")
  endif()
endif()

… and there are more:

bash-5.2$ grep -r  -- -MD Modules 
Modules/CMakeASM_NASMInformation.cmake:  set(CMAKE_DEPFILE_FLAGS_ASM_NASM "-MD <DEP_FILE> -MT <DEP_TARGET>")
Modules/Platform/Windows-NVIDIA-CUDA.cmake:  set(_MDd "-MDd ")
Modules/Platform/Windows-NVIDIA-CUDA.cmake:  set(_MD "-MD ")
Modules/Platform/Windows-NVIDIA-CUDA.cmake:set(CMAKE_CUDA_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDLL      -Xcompiler=-MD)
Modules/Platform/Windows-NVIDIA-CUDA.cmake:set(CMAKE_CUDA_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebugDLL -Xcompiler=-MDd)
Modules/Platform/Windows-Clang.cmake:    set(CMAKE_DEPFILE_FLAGS_${lang} "-MD -MT <DEP_TARGET> -MF <DEP_FILE>")
Modules/Platform/Windows-Clang.cmake:      set(CMAKE_DEPFILE_FLAGS_RC "${clang_option_prefix}-MD ${clang_option_prefix}-MF ${clang_option_prefix}<DEP_FILE>")
Modules/Platform/Windows-MSVC.cmake:    set(CMAKE_${lang}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDLL      -MD)
Modules/Platform/Windows-MSVC.cmake:    set(CMAKE_${lang}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebugDLL -MDd)
Modules/UseSWIG.cmake:      set(swig_depends_flags -MF "${swig_depends_filename}" -MD)
Modules/Compiler/NVIDIA-CUDA.cmake:  # The -MD flag was only added to nvcc in 10.2 so
Modules/Compiler/NVIDIA-CUDA.cmake:  set(CMAKE_DEPFILE_FLAGS_CUDA "-MD -MT <DEP_TARGET> -MF <DEP_FILE>")
Binary file Modules/Compiler/.Clang-CXX.cmake.swp matches
Modules/Compiler/IntelLLVM.cmake:    set(CMAKE_DEPFILE_FLAGS_${lang} "-MD -MT <DEP_TARGET> -MF <DEP_FILE>")
Modules/Compiler/Intel-C.cmake:set(CMAKE_DEPFILE_FLAGS_C "-MD -MT <DEP_TARGET> -MF <DEP_FILE>")
Modules/Compiler/GNU-ASM.cmake:  set(CMAKE_DEPFILE_FLAGS_ASM${ASM_DIALECT} "--MD <DEP_FILE>")
Modules/Compiler/LCC.cmake:    set(CMAKE_DEPFILE_FLAGS_${lang} "-MD -MT <DEP_TARGET> -MF <DEP_FILE>")
Modules/Compiler/NVHPC-C.cmake:  set(CMAKE_DEPFILE_FLAGS_C "-MD -MT <DEP_TARGET> -MF <DEP_FILE>")
Modules/Compiler/NVHPC-C.cmake:  # Before NVHPC 21.07 the `-MD` flag implicitly
Modules/Compiler/NVHPC-C.cmake:  set(CMAKE_C_DEPENDS_EXTRA_COMMANDS "<CMAKE_C_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -x c -M <SOURCE> -MT <OBJECT> -MD<DEP_FILE>")
Modules/Compiler/QCC.cmake:  set(CMAKE_DEPFILE_FLAGS_${lang} "-Wp,-MD,<DEP_FILE> -Wp,-MT,<DEP_TARGET> -Wp,-MF,<DEP_FILE>")
Modules/Compiler/Clang-CXX.cmake:      " -MD -MF <DEP_FILE>"
Modules/Compiler/Intel-CXX.cmake:set(CMAKE_DEPFILE_FLAGS_CXX "-MD -MT <DEP_TARGET> -MF <DEP_FILE>")
Modules/Compiler/NVHPC-CXX.cmake:  set(CMAKE_DEPFILE_FLAGS_CXX "-MD -MT <DEP_TARGET> -MF <DEP_FILE>")
Modules/Compiler/NVHPC-CXX.cmake:  # Before NVHPC 21.07 the `-MD` flag implicitly
Modules/Compiler/NVHPC-CXX.cmake:  set(CMAKE_CXX_DEPENDS_EXTRA_COMMANDS "<CMAKE_CXX_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -x c++ -M <SOURCE> -MT <OBJECT> -MD<DEP_FILE>")
Modules/Compiler/GNU.cmake:    set(CMAKE_DEPFILE_FLAGS_${lang} "-MD -MT <DEP_TARGET> -MF <DEP_FILE>")
Modules/Compiler/Clang-CUDA.cmake:set(CMAKE_DEPFILE_FLAGS_CUDA "-MD -MT <DEP_TARGET> -MF <DEP_FILE>")
bash-5.2$ 

You’ll want to string(REPLACE) on the variable (and the others you found) to not drop other important flags, Also, local variables mask cache variables, so using the cache is unlikely to be effective.

That cause my problem!

@ben.boeckel with this setting after project()

if(UNIX)
  set(CMAKE_DEPFILE_FLAGS_C "-MMD")
  set(CMAKE_DEPFILE_FLAGS_CXX "-MMD")
endif()

the flags are used, but than there are no dependecies at all?

klein_cl:~/Workspace/cpp/ModernCmakeStarter/build/user$ ninja -t deps
_deps/fmt-build/CMakeFiles/fmt.dir/src/os.cc.o: #deps 0, deps mtime 1696411728991046200 (VALID)

_deps/fmt-build/CMakeFiles/fmt.dir/src/format.cc.o: #deps 0, deps mtime 1696411731741763100 (VALID)

CMakeFiles/greeter.dir/Unity/unity_0_cxx.cxx.o: #deps 0, deps mtime 1696411732034372400 (VALID)

klein_cl:~/Workspace/cpp/ModernCmakeStarter/build/user$

You removed the -MF and -MT flags that are needed to:

  • write them to a file
  • with an output that ninja accepts

So the only correct undocumented way would be after project(...):

if(UNIX AND CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
  set(CMAKE_DEPFILE_FLAGS_C "-MMD -MT <DEP_TARGET> -MF <DEP_FILE>")
  set(CMAKE_DEPFILE_FLAGS_CXX "-MMD -MT <DEP_TARGET> -MF <DEP_FILE>")
endif()