cmakebuildinclude-pathninjacompileoptions

How can I tell CMake to put include directory flags after the compiler option flags in its object compile command?


I am facing problems due to the target holding the include paths first and then the compiler options after. How can I set the include paths after the compiler options for compiling source files of a target?

My CMakeLists.txt file:

project(HelloWorld)
cmake_minimum_required(VERSION 3.0)
add_library(HELLO_WORLD_LIB
                STATIC
                src/helloWorld.cpp
    )
target_include_directories(
            HELLO_WORLD_LIB AFTER PUBLIC D:\\temp\\includes 
        )
target_compile_options(HELLO_WORLD_LIB BEFORE PUBLIC -cpp -remap)
set_target_properties(HELLO_WORLD_LIB
        PROPERTIES
            OUTPUT_NAME hello
            ARCHIVE_OUTPUT_DIRECTORY  D:\\temp\\CMakeHelloWorld
            SUFFIX .a
    )

My cmake call:

call cmake -GNinja -S ./.. -DCMAKE_INSTALL_PREFIX=../_bin
call cmake --build . --config Debug --verbose -d keeprsp
call cmake --install .

The console output:

-- Configuring done
-- Generating done
-- Build files have been written to: D:/temp/CMakeHelloWorld/_build
[1/2] C:\mingw\test25_comp_8.1.0_testversion\bin\c++.exe -ID:/temp/includes -cpp -remap -MD -MT CMakeFiles/HELLO_WORLD_LIB.dir/src/helloWorld.cpp.obj -MF CMakeFiles\HELLO_WORLD_LIB.dir\src\helloWorld.cpp.obj.d -o CMakeFiles/HELLO_WORLD_LIB.dir/src/helloWorld.cpp.obj -c ../src/helloWorld.cpp
[2/2] cmd.exe /C "cd . && C:\cmake\.8-3.20.2\bin\cmake.exe -E rm -f ..\libhello.a && C:\mingw\test25_comp_8.1.0_testversion\bin\ar.exe qc ..\libhello.a  CMakeFiles/HELLO_WORLD_LIB.dir/src/helloWorld.cpp.obj && C:\mingw\test25_comp_8.1.0_testversion\bin\ranlib.exe ..\libhello.a && cd ."
-- Install configuration: ""

However if I try to add the include paths after compiler options, it sits before the compiler options. How can I set the compiler options before the include directories? like C:\mingw\test25_comp_8.1.0_testversion\bin\c++.exe -cpp -remap -ID:/temp/includes.


Solution

  • The relevant CMake variable is CMAKE_CXX_COMPILE_OBJECT, which is the configuration point for what template to use for the command to compile an object. The default value is set in Modules/CMakeCXXInformation.cmake, and overrides are specified in various Modules/Platform/* or Modules/Compiler/* files. If you're curious, you can grep for the overrides with the following regex: set.*CXX_COMPILE_OBJECT.

    The default one is set like this:

    set(CMAKE_CXX_COMPILE_OBJECT
      "<CMAKE_CXX_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT> -c <SOURCE>")
    

    You probably want something like this (set it in your own CMakeLists.txt file, or in a toolchain file):

    set(CMAKE_CXX_COMPILE_OBJECT
      "<CMAKE_CXX_COMPILER> <DEFINES> <FLAGS> <INCLUDES> -o <OBJECT> -c <SOURCE>")
    

    As far as I can tell, this configuration point is "global". I'm not aware of how to specify it with different values for different targets or source files.


    If you're working with the Ninja generator and need this kind of change to affect the generated .rsp files, I think you'd need to build a modified version of CMake from source, since that behaviour seems to be baked into the binaries instead of CMake script files in the Modules/ directory. The relecant source file is Source/cmNinjaTargetGenerator.cxx. Look at the lines of code that do rule.RspContent = and you'll see:

    rule.RspContent =
      cmStrCat(' ', scanVars.Defines, ' ', scanVars.Includes, ' ', scanFlags);
    

    You'd probably need to switch the order of scanVars.Includes and scanVars.scanFlags.

    If you choose to make a modified CMake binary, as always, make sure you comply with the software licence.