# Transitive dependencies for include directories break

**URL:** https://discourse.cmake.org/t/transitive-dependencies-for-include-directories-break/4035
**Category:** Usage
**Created:** [September 4, 2021, 8:00am UTC](https://discourse.cmake.org/t/transitive-dependencies-for-include-directories-break/4035 "2021-09-04T08:00:41Z")
**Posts on this page:** 6
**Page:** 1

<div class="post-metadata">

### Author: ![Ronald](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/r/ea666f/32.png) [@Ronald](https://discourse.cmake.org/u/Ronald)
#### Post date: [September 4, 2021, 8:00am UTC](https://discourse.cmake.org/t/transitive-dependencies-for-include-directories-break/4035/1 "2021-09-04T08:00:41Z")

</div>

`dump_target_includes` is a macro for testing

```cmake
macro(dump_target_includes TARGET_NAME)
    set(OUT_TMP "====dump_target_includes begin (${TARGET_NAME})====")

    set(INCLUDE_DIRS $<TARGET_PROPERTY:${TARGET_NAME},INCLUDE_DIRECTORIES>)
    set(INTERFACE_INCLUDE_DIRS $<TARGET_PROPERTY:${TARGET_NAME},INTERFACE_INCLUDE_DIRECTORIES>)

    string(CONCAT OUT_TMP ${OUT_TMP} "\n\n----INCLUDE_DIRECTORIES----")
    foreach(PATH ${INCLUDE_DIRS})
        string(CONCAT OUT_TMP ${OUT_TMP} "\n${PATH}")
    endforeach()

    string(CONCAT OUT_TMP ${OUT_TMP} "\n\n----INTERFACE_INCLUDE_DIRECTORIES----")
    foreach(PATH ${INTERFACE_INCLUDE_DIRS})
        string(CONCAT OUT_TMP ${OUT_TMP} "\n${PATH}")
    endforeach()

    string(CONCAT OUT_TMP ${OUT_TMP} "\n\n====dump_target_includes end (${TARGET_NAME})====")

    file(GENERATE OUTPUT test_debug_genex.log
                  CONTENT ${OUT_TMP})
endmacro() 

```

## lib a

installed as a standalone lib

## lib b

lib b depends on lib a, also installed as a standalone lib

```cmake
target_link_libraries(b PUBLIC a)
dump_target_includes(b)

```

The dump shows that `INTERFACE_INCLUDE_DIRECTORIES` of a is in `INCLUDE_DIRECTORIES` and `INTERFACE_INCLUDE_DIRECTORIES` of b, no problem

## app c

app c depends on lib b

```cmake
find_package(b REQUIRED)
dump_target_includes(b)

```

The dump shows that `INTERFACE_INCLUDE_DIRECTORIES` of a is NOT in `INCLUDE_DIRECTORIES` and `INTERFACE_INCLUDE_DIRECTORIES` of b, and app c failed to build for it can not find header files in a.

Why do transitive dependencies from a to c break?

BTW I have used genex `$<BUILD_INTERFACE:...>` and `$<INSTALL_INTERFACE:...>` around.

---

<div class="post-metadata">

### Author: ![ben.boeckel](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/b/ea5d25/32.png) [@ben.boeckel](https://discourse.cmake.org/u/ben.boeckel)
#### Post date: [September 4, 2021, 5:06pm UTC](https://discourse.cmake.org/t/transitive-dependencies-for-include-directories-break/4035/2 "2021-09-04T17:06:33Z")

</div>

They don’t break; you just can’t ask for them during the configure stage. What do you want this information for?

Edit: See also this question:

> [@Getting all PUBLIC & INTERFACE definitions including from dependencies](https://discourse.cmake.org/t/getting-all-public-interface-definitions-including-from-dependencies/3697):
>
> Hi. I have stumbled upon an use case where I think this might come handy, but I am not sure if possible in current CMake. My project specifies a target A which depends on targets B & C. For third party integration, I instruct users to specify the needed include, library paths and definitions. This day I got bitten by not specifying all definitions which created an API/ABI inconsistency (Compiled A target used different struct size than the users integration). To combat this, I was thinking of…

---

<div class="post-metadata">

### Author: ![Ronald](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/r/ea666f/32.png) [@Ronald](https://discourse.cmake.org/u/Ronald)
#### Post date: [September 4, 2021, 5:42pm UTC](https://discourse.cmake.org/t/transitive-dependencies-for-include-directories-break/4035/3 "2021-09-04T17:42:02Z")

</div>

> [@ben.boeckel](#):
>
> you just can’t ask for them during the configure stage

No, I have used `file(GENERATE ...)`, it can get genex values in generation stage.

---

<div class="post-metadata">

### Author: ![ben.boeckel](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/b/ea5d25/32.png) [@ben.boeckel](https://discourse.cmake.org/u/ben.boeckel)
#### Post date: [September 4, 2021, 7:57pm UTC](https://discourse.cmake.org/t/transitive-dependencies-for-include-directories-break/4035/4 "2021-09-04T19:57:14Z")

</div>

OK, that wasn’t clear. The thing is that `b` has a link dependency on `a`. When CMake generates the full tree for use in a compilation line, _that_ is when the full dependency tree is traversed and expanded. CMake cannot, in general, compute this full tree on-demand because there are ways of constructing them that depend on the target being linked. For example, this will make the include directories depend on whether an executable or library is consuming it:

```cmake
target_include_directories(foo
  INTERFACE
    "$<$<STREQUAL:$<TARGET_PROPERTY,TYPE>,EXECUTABLE>:executable/only/include>")

```

There’s an issue about getting the transitive dependency closure of a target, but I can’t find it right now.

---

<div class="post-metadata">

### Author: ![Ronald](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/r/ea666f/32.png) [@Ronald](https://discourse.cmake.org/u/Ronald)
#### Post date: [September 5, 2021, 4:13am UTC](https://discourse.cmake.org/t/transitive-dependencies-for-include-directories-break/4035/5 "2021-09-05T04:13:58Z")

</div>

The `CMakeLists.txt` below for **app c** works as expected,  
i.e. INTERFACE\_INCLUDE\_DIRECTORIES of a is in INCLUDE\_DIRECTORIES and `INTERFACE_INCLUDE_DIRECTORIES` of b

```cmake
find_package(a REQUIRED)
find_package(b REQUIRED)
dump_target_includes(b)

```

for comparison, the `CMakeLists.txt` below for **app c** doesn’t work as expected,  
i.e. INTERFACE\_INCLUDE\_DIRECTORIES of a is **not** in INCLUDE\_DIRECTORIES or `INTERFACE_INCLUDE_DIRECTORIES` of b

```cmake
find_package(b REQUIRED)
dump_target_includes(b)

```

BTW, the revised version of `dump_target_includes`

```cmake
macro(dump_target_includes TARGET_NAME)
    set(OUT_TMP "====dump_target_includes begin (${TARGET_NAME})====\n\n")

    set(INCLUDE_DIRS $<TARGET_PROPERTY:${TARGET_NAME},INCLUDE_DIRECTORIES>)
    set(INTERFACE_INCLUDE_DIRS $<TARGET_PROPERTY:${TARGET_NAME},INTERFACE_INCLUDE_DIRECTORIES>)

    string(CONCAT OUT_TMP ${OUT_TMP} "----INCLUDE_DIRECTORIES----\n")

    string(CONCAT OUT_TMP ${OUT_TMP} $<JOIN:$<TARGET_PROPERTY:${TARGET_NAME},INCLUDE_DIRECTORIES>,\n>\n\n)

    string(CONCAT OUT_TMP ${OUT_TMP} "----INTERFACE_INCLUDE_DIRECTORIES----\n")

    string(CONCAT OUT_TMP ${OUT_TMP} $<JOIN:$<TARGET_PROPERTY:${TARGET_NAME},INTERFACE_INCLUDE_DIRECTORIES>,\n>\n\n)

    string(CONCAT OUT_TMP ${OUT_TMP} "====dump_target_includes end (${TARGET_NAME})====")

    file(GENERATE OUTPUT test_debug_genex.log
                  CONTENT ${OUT_TMP})
endmacro()

```

---

<div class="post-metadata">

### Author: ![ben.boeckel](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/b/ea5d25/32.png) [@ben.boeckel](https://discourse.cmake.org/u/ben.boeckel)
#### Post date: [September 6, 2021, 2:21pm UTC](https://discourse.cmake.org/t/transitive-dependencies-for-include-directories-break/4035/6 "2021-09-06T14:21:14Z")

</div>

No, that’s because the include directories are added after analyzing the interface _link_ libraries of `b`. It sees `a` in that list and then traverses it. You just cannot get the full transitive closure using genexes today (and it’s unlikely to be implemented).
