Search code examples
cgcccmakemakefilec-preprocessor

Making CMake use -dD -dI switches when generating preprocessed C files via Makefile?


Consider the following CMake example:

cmake_minimum_required(VERSION 3.13)

if (NOT(EXISTS "${CMAKE_SOURCE_DIR}/main.c" AND NOT IS_DIRECTORY "${CMAKE_SOURCE_DIR}/main.c"))
  message("${Cyan}Creating ${CMAKE_SOURCE_DIR}/main.c${ColourReset}")
  # https://stackoverflow.com/questions/7637539/how-to-split-strings-across-multiple-lines-in-cmake
  # https://stackoverflow.com/questions/69574555/cmake-filegenerate-output-output-file-how-to-write-content-on-multiple
  # https://stackoverflow.com/questions/67674998/cmakelists-create-string-with-new-lines
  # https://stackoverflow.com/questions/26193171/cmake-how-to-create-a-file-with-make-command # example for file(write
  FILE(WRITE ${CMAKE_SOURCE_DIR}/main.c
    "#include <stdio.h>\n"
    "#define MYDEFINE 1\n"
    "\n"
    "int main() {\n"
    "  printf(\"Hello from mytest main .exe (MYDEFINE: %d)!\\n\", MYDEFINE);\n"
    "  return 0;\n"
    "}\n"
  )
endif() # NOT(EXISTS "${CMAKE_SOURCE_DIR}/main.c"

project(mytest C)
set(CMAKE_C_STANDARD 11)
set(${PROJECT_NAME}_sources
    main.c
)

add_executable(${PROJECT_NAME} ${${PROJECT_NAME}_sources})

I am in MINGW64 (MSYS2) bash shell in Windows 10, so I use "MSYS Makefiles" - but I guess the discussion holds for "Unix Makefiles" as well; anyways, I build this project with:

mkdir build
cd build/
cmake  ../ -DCMAKE_BUILD_TYPE=Debug -G "MSYS Makefiles"

Then I can run make, everything builds:

$ make
make[1]: Entering directory '/c/tmp/mytest/build'
make[2]: Entering directory '/c/tmp/mytest/build'
Scanning dependencies of target mytest
make[2]: Leaving directory '/c/tmp/mytest/build'
make[2]: Entering directory '/c/tmp/mytest/build'
[ 50%] Building C object CMakeFiles/mytest.dir/main.c.obj
[100%] Linking C executable mytest.exe
make[2]: Leaving directory '/c/tmp/mytest/build'
[100%] Built target mytest
make[1]: Leaving directory '/c/tmp/mytest/build'

$ ./mytest.exe
Hello from mytest main .exe (MYDEFINE: 1)!

As mentioned in Only run C preprocessor in cmake? :

CMake automatically generates make targets for preprocessing files. For each foo.c in your project there's a foo.i make target that will run only the preprocessor (with all the relevant -D and -I flags etc.).

Well, I would in fact like these flags from How to know (in GCC) when given macro/preprocessor symbol gets declared? :

# shows preprocessed source kept with macros and include directives 
g++ -E -dD -dI -P file.cc  

... where -dD and -dI are described in Preprocessor Options (Using the GNU Compiler Collection (GCC))

Anyways, when I try this in my example:

$ make VERBOSE=1 main.c.i
make -f CMakeFiles/mytest.dir/build.make CMakeFiles/mytest.dir/main.c.i
make[1]: Entering directory '/c/tmp/mytest/build'
Preprocessing C source to CMakeFiles/mytest.dir/main.c.i
/C/msys64/mingw64/bin/gcc.exe   -g   -std=gnu11 -E /C/tmp/mytest/main.c > CMakeFiles/mytest.dir/main.c.i
make[1]: Leaving directory '/c/tmp/mytest/build'

... I can see only -g and -E is used.

How can I change my CMakeLists.txt, so that when I issue the command make main.c.i to obtain preprocessed output, the command ran is gcc -g -std=gnu11 -dD -dI -E ..., that is, it will also include the -dD -dI options?


Solution

  • The simplest would be:

    add_compile_commands(-dD -dI)
    

    The proper way could be to add after project() call:

    set(CMAKE_C_CREATE_PREPROCESSED_SOURCE "<CMAKE_C_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -dD -dI -E <SOURCE> > <PREPROCESSED_SOURCE>" CACHE "STRING" "" FORCE)