NulledPointer NulledPointer - 2 months ago 8
C++ Question

Specify explicit header files in CMake

I have precompiled header file stdafx.h which is specific to each target. My CMake project roughly looks like below:

include_directories(<prefix>/include_a)
include_directories(<prefix>/include_b) #<---- contains stdafx.h that should NOT be used
include_directories(<project_dir>/) #<----- contains stdafx.h that should be used

add_executable(<project_name> <sources>)


Problem: I want to exclude precompiled header that comes as part of
<prefix>/include_b
directory. If thats not possible then specify header files explicitly. I know
gcc
supports
-include
option but is there any cleaner option with CMake that fits my requirement?

Answer

Turning my comment into an answer

If you don't want to force an include file (which is not explicitly supported by CMake), I think the answer lays in the order of your include paths.

First here is the test code I used to reproduce your problem:

cmake_minimum_required(VERSION 3.0)
project(IncDirOrder)

file(WRITE "prefix/include_a/stdafx.h" "#error include_a/stdafx.h")
file(WRITE "prefix/include_b/stdafx.h" "#error include_b/stdafx.h")
file(WRITE "include/stdafx.h" "")
file(WRITE "main.cpp" "#include \"stdafx.h\"\nint main() { return 0; }")

include_directories(prefix/include_a)
include_directories(prefix/include_b)  
include_directories(include)  

add_executable(${PROJECT_NAME} main.cpp)

Possible Solutions to Influence the Order of Include Paths

  1. Reorder the include_directories() calls (if possible):

    include_directories(include)  
    include_directories(prefix/include_a)
    include_directories(prefix/include_b)  
    
  2. The use of the BEFORE keyword:

    include_directories(BEFORE include)  
    

    or

    target_include_directories(${PROJECT_NAME} BEFORE PUBLIC include)
    
  3. Going by the assumption that the other pre-compiled headers are also accompanied by a library, I would generally recommend the use of target_include_directories(). Then you automatically have the desired behavior (local includes do come first before interface includes):

    cmake_minimum_required(VERSION 3.0)
    project(IncDirOrderWithLibs)
    
    file(WRITE "prefix/source_a/stdafx.cpp" "#define LibA\n#include \"stdafx.h\"")
    file(WRITE "prefix/include_a/stdafx.h" "#ifndef LibA\n#error include_a/stdafx.h\n#endif")
    file(WRITE "prefix/source_b/stdafx.cpp" "#define LibB\n#include \"stdafx.h\"")
    file(WRITE "prefix/include_b/stdafx.h" "#ifndef LibB\n#error include_b/stdafx.h\n#endif")
    file(WRITE "include/stdafx.h" "")
    file(WRITE "main.cpp" "#include \"stdafx.h\"\nint main() { return 0; }")
    
    add_library(LibA "prefix/source_a/stdafx.cpp")
    target_include_directories(LibA PUBLIC prefix/include_a)
    
    add_library(LibB "prefix/source_b/stdafx.cpp")
    target_link_libraries(LibB LibA)
    target_include_directories(LibB PUBLIC prefix/include_b)
    
    add_executable(${PROJECT_NAME} main.cpp)
    target_link_libraries(${PROJECT_NAME} LibB)
    target_include_directories(${PROJECT_NAME} PRIVATE include)
    

References