0

I have a quite large CMake-based project and found that while generating solution for Visual Studio on Windows I got current project home directory as an include directory. E.g. here's content of root directory:

- A
   - impl
     - source.cpp
   - header.h
   - CMakeLists.txt
- B
- CMakeLists.txt

In source.cpp I accidentally wrote #include "header.h" instead of #include <A/header.h>. And such solution was successfully compiled since the directory A for some reason was added to the list called "Additional Include Directories" in Visual Studio project (i.e. in command-line added as one more /I option).

Same source slice gives error on Linux build similar to header.h not found (and it's expected behavior).

Which steps should I take to find the source why does CMake adds target A's root directory to the list of include_directories. I used the answer to print a list of project related include directories. CMake version is 3.27.1.

αλεχολυτ
  • 4,792
  • 1
  • 35
  • 71
  • have you set https://cmake.org/cmake/help/latest/variable/CMAKE_INCLUDE_CURRENT_DIR.html ? – Alan Birtles Aug 03 '23 at 16:32
  • 1
    In Visual Studio any file included with quotation marks will be searched for in the current directory. AFAIK you cannot change this except by changing the quotation marks to `<>`. – john Aug 03 '23 at 16:33
  • @john If by "current directory" you mean the directory containing the file with the `#include "..."` directive: that's not VS specific behaviour, but standard behaviour... – fabian Aug 03 '23 at 17:18
  • @fabian define "standard". I thought it was implementation-defined. – starball Aug 04 '23 at 18:32
  • @starball standard [says](https://eel.is/c++draft/cpp.include) that it's implementation-defined. – αλεχολυτ Aug 09 '23 at 08:28
  • @john VS docs [say](https://learn.microsoft.com/en-us/cpp/preprocessor/hash-include-directive-c-cpp?view=msvc-170&redirectedfrom=MSDN) additionally: *"In the directories of the currently opened include files, in the reverse order in which they were opened. The search begins in the directory of the parent include file and continues upward through the directories of any grandparent include files"*. But for some reason I can't repro such behavior in VS2022. – αλεχολυτ Aug 09 '23 at 08:30
  • @AlanBirtles that's what I checked first. Unfortunately my case was slightly harder. See [comment](https://stackoverflow.com/questions/76829989/find-the-place-where-the-current-target-directory-is-added-as-include-directory/76830285#comment135495172_76830285). – αλεχολυτ Aug 09 '23 at 08:33

1 Answers1

1

You may want to print the [INTERFACE_]INCLUDE_DIRECTORIES via a custom target using generator expressions. This could allow you to go through the dependencies recursively until you find the root of the issue. This will not help you detect the use of the include_directories command though.

print_target_info.cmake

foreach(TGT IN LISTS TARGETS)
    message("---------- Target ${TGT} -----------------")
    message("Interface include dirs:")
    foreach(DIR IN LISTS ${TGT}_INTERFACE_INCLUDE_DIRS)
        message(" - '${DIR}'")
    endforeach()
    message("Include dirs:")
    foreach(DIR IN LISTS ${TGT}_INCLUDE_DIRS)
        message(" - '${DIR}'")
    endforeach()
endforeach()

CMakeLists.txt

function(add_print_target_info_command)
    set(INFO)
    foreach(TGT IN LISTS ARGN)
        list(APPEND INFO
            -D "${TGT}_INTERFACE_INCLUDE_DIRS=$<TARGET_PROPERTY:${TGT},INTERFACE_INCLUDE_DIRECTORIES>"
            -D "${TGT}_INCLUDE_DIRS=$<TARGET_PROPERTY:${TGT},INCLUDE_DIRECTORIES>"
        )
    endforeach()
    
    message("INFO=${INFO}")
    add_custom_target(print_target_info
        COMMAND
            ${CMAKE_COMMAND}
                -D "TARGETS=${ARGN}"
                ${INFO}
                -P ${CMAKE_CURRENT_SOURCE_DIR}/print_target_info.cmake
        VERBATIM
    )
endfunction()

add_print_target_info_command(
    A B C D # list of the names of the targets to print the include directories for 
)

This allows you to see the info in the command line output when building the target print_target_info.

In addition you could use the --graphviz=... option to make identifying dependencies easier, perhaps even spotting differences between both platforms

fabian
  • 80,457
  • 12
  • 86
  • 114
  • Thanks for your answer. Actually I found the root of issue by looking for `include_directories` in CMake related files on the top level and found the culprit call with `CMAKE_CURRENT_SOURCE_DIR` operand. – αλεχολυτ Aug 08 '23 at 09:47