# Does the target\_include\_directories() command strip out duplicate paths added?

**URL:** <https://discourse.cmake.org/t/does-the-target-include-directories-command-strip-out-duplicate-paths-added/769>\
**Category:** Code\
**Created:** [March 5, 2020, 11:43am UTC](https://discourse.cmake.org/t/does-the-target-include-directories-command-strip-out-duplicate-paths-added/769 "2020-03-05T11:43:22Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![ClausKlein](https://discourse.cmake.org/user_avatar/discourse.cmake.org/clausklein/32/352_2.png) [@ClausKlein](https://discourse.cmake.org/u/ClausKlein)\
**Post date:** [March 5, 2020, 11:43am UTC](https://discourse.cmake.org/t/does-the-target-include-directories-command-strip-out-duplicate-paths-added/769/1 "2020-03-05T11:43:22Z")

</div>

Yes, it does ( **BUT** as good it can); see the following exemple project:

```cmake
cmake_minimum_required(VERSION 3.8 FATAL_ERROR)
project(test C)

file(WRITE ${CMAKE_BINARY_DIR}/main.c "int main(void){return 0;}\n")
add_executable(main main.c)

get_filename_component(SRC ${CMAKE_SOURCE_DIR}/../test REALPATH CACHE)
get_filename_component(BIN ${CMAKE_BINARY_DIR} REALPATH CACHE)
message("SRC=${SRC}")
message("BIN=${BIN}")

target_include_directories(main
    PRIVATE . ..
    ${CMAKE_BINARY_DIR}
    ${CMAKE_SOURCE_DIR}
    ${SRC}
    ${BIN}
)

```

```auto
test/build$ ninja -v
[0/1] /usr/bin/cmake.exe -S/e/workspace/cpp/test -B/e/workspace/cpp/test/build
SRC=/e/workspace/cpp/test
BIN=/e/workspace/cpp/test/build
-- Configuring done
-- Generating done
-- Build files have been written to: /e/workspace/cpp/test/build
[1/2] /usr/bin/cc.exe -I../. -I../.. -I. -I../ -MD -MT CMakeFiles/main.dir/main.c.o -MF CMakeFiles/main.dir/main.c.o.d -o CMakeFiles/main.dir/main.c.o -c main.c
[2/2] : && /usr/bin/cc.exe -Wl,--enable-auto-import CMakeFiles/main.dir/main.c.o -o main.exe -Wl,--out-implib,libmain.dll.a -Wl,--major-image-version,0,--minor-image-version,0 && :

```

---

<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:** [March 5, 2020, 2:10pm UTC](https://discourse.cmake.org/t/does-the-target-include-directories-command-strip-out-duplicate-paths-added/769/2 "2020-03-05T14:10:10Z")

</div>

Part of that is the Ninja generator normalizing many paths. The other is that CMake deduplicates include paths by textual equivalence (possibly with a trailing `/` being ignored). Anything else would generally result in a lot more work being done at generate time.

I don’t recommend using `.` and `..` in your include directories; the working directory of the compiler is different for different generators, so they don’t mean the same thing. I think using absolute paths here would generally make things more readable and be closer to what you want.

---

<div class="post-metadata">

**Author:** ![craig.scott](https://discourse.cmake.org/user_avatar/discourse.cmake.org/craig.scott/32/20_2.png) [@craig.scott](https://discourse.cmake.org/u/craig.scott)\
**Post date:** [March 5, 2020, 9:53pm UTC](https://discourse.cmake.org/t/does-the-target-include-directories-command-strip-out-duplicate-paths-added/769/3 "2020-03-05T21:53:32Z")

</div>

> [@ben.boeckel](#):
>
> I don’t recommend using `.` and `..` in your include directories; the working directory of the compiler is different for different generators, so they don’t mean the same thing. I think using absolute paths here would generally make things more readable and be closer to what you want.

It shouldn’t matter. The `target_include_directories()` command internally converts relative paths to absolute before storing them in the `INCLUDE_DIRECTORIES` target property. It treats relative paths as being relative to the current source directory.

---

<div class="post-metadata">

**Author:** ![ClausKlein](https://discourse.cmake.org/user_avatar/discourse.cmake.org/clausklein/32/352_2.png) [@ClausKlein](https://discourse.cmake.org/u/ClausKlein)\
**Post date:** [March 6, 2020, 8:55am UTC](https://discourse.cmake.org/t/does-the-target-include-directories-command-strip-out-duplicate-paths-added/769/4 "2020-03-06T08:55:07Z")

</div>

The . and … was only used to show the problem.  
IMHO: converting too realpath while generating would be better and not to expensive.  
It whould reduce the build time too.

Interesting is the result if the build dir is not part of source dir.

```auto
../.build$ ninja -v
[0/1] /usr/bin/cmake.exe -S/e/workspace/cpp/test -B/e/workspace/cpp/.build
SRC=/e/workspace/cpp/test
BIN=/e/workspace/cpp/.build
-- Configuring done
-- Generating done
-- Build files have been written to: /e/workspace/cpp/.build
[1/2] /usr/bin/cc.exe -I/e/workspace/cpp/test/. -I/e/workspace/cpp/test/.. -I. -I/e/workspace/cpp/test -MD -MT CMakeFiles/main.dir/main.c.o -MF CMakeFiles/main.dir/main.c.o.d -o CMakeFiles/main.dir/main.c.o -c main.c
[2/2] : && /usr/bin/cc.exe -Wl,--enable-auto-import CMakeFiles/main.dir/main.c.o -o main.exe -Wl,--out-implib,libmain.dll.a -Wl,--major-image-version,0,--minor-image-version,0 && :

```

---

<div class="post-metadata">

**Author:** ![ferdnyc](https://discourse.cmake.org/user_avatar/discourse.cmake.org/ferdnyc/32/267_2.png) [@ferdnyc](https://discourse.cmake.org/u/ferdnyc)\
**Post date:** [March 9, 2020, 6:16am UTC](https://discourse.cmake.org/t/does-the-target-include-directories-command-strip-out-duplicate-paths-added/769/5 "2020-03-09T06:16:38Z")

</div>

> [@ClausKlein](#):
>
> The . and … was only used to show the problem.  
> IMHO: converting too realpath while generating would be better and not to expensive.  
> It whould reduce the build time too.

I wonder. `REALPATH` has other effects that may be undesirable. For instance, it also resolves symlinks, so if there are two include paths and one is symlinked to the other, that one will be eliminated. Which is _probably_ fine… except when it isn’t.

Ultimately, is it CMake’s job to be pruning directories out of the include list at _generate_ time, when those directories are meant to be consumed at _build_ time? There could be situations where paths that are listed in `target_include_directories()` will end up looking different during the build process than they do when generating. CMake trying to be _too_ smart could cause problems for some users.

I mean, ultimately, what you point to as a “problem” is **only** a problem because you _actually specified_ the same directory multiple times, in different forms. CMake merely passed along the parameters you gave it to the build system. Perhaps the right answer is simply, “Don’t do that.”?

---

<div class="post-metadata">

**Author:** ![ClausKlein](https://discourse.cmake.org/user_avatar/discourse.cmake.org/clausklein/32/352_2.png) [@ClausKlein](https://discourse.cmake.org/u/ClausKlein)\
**Post date:** [March 9, 2020, 9:21am UTC](https://discourse.cmake.org/t/does-the-target-include-directories-command-strip-out-duplicate-paths-added/769/6 "2020-03-09T09:21:59Z")

</div>

I do not want to use “.” and “…”

But sompe people/code generators (i.e. **Ninja** ) do!

I want that **cmake** generators normalize include directories with i.e. unix _ **realpath** _:

```auto
NAME
       realpath - print the resolved path

SYNOPSIS
       realpath [OPTION]... FILE...

DESCRIPTION
       Print the resolved absolute file name; all but the last component must exist

       -e, --canonicalize-existing
              all components of the path must exist

       -m, --canonicalize-missing
              no path components need exist or be a directory

       -L, --logical
              resolve '..' components before symlinks

       -P, --physical
              resolve symlinks as encountered (default)

       -q, --quiet
              suppress most error messages

       --relative-to=DIR
              print the resolved path relative to DIR

       --relative-base=DIR
              print absolute paths unless paths below DIR

       -s, --strip, --no-symlinks
              don't expand symlinks

       -z, --zero
              end each output line with NUL, not newline

       --help display this help and exit

       --version
              output version information and exit

```

---

<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:** [March 9, 2020, 1:11pm UTC](https://discourse.cmake.org/t/does-the-target-include-directories-command-strip-out-duplicate-paths-added/769/7 "2020-03-09T13:11:26Z")

</div>

Then [this issue](https://gitlab.kitware.com/cmake/cmake/issues/13894) is the one you want. It looks like using absolute paths confuses ninja’s depslog, so it cannot be done unconditionally right now.

---

<div class="post-metadata">

**Author:** ![ClausKlein](https://discourse.cmake.org/user_avatar/discourse.cmake.org/clausklein/32/352_2.png) [@ClausKlein](https://discourse.cmake.org/u/ClausKlein)\
**Post date:** [March 9, 2020, 3:31pm UTC](https://discourse.cmake.org/t/does-the-target-include-directories-command-strip-out-duplicate-paths-added/769/8 "2020-03-09T15:31:43Z")

</div>

I have tried to fix ninja generator, but now the BuildDepends ctests fails for ninja?

```auto
klein_cl@2d-oehsdg:~/Workspace/cpp/cmake$ git diff
diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h
index 88194b7a29..25cfce232d 100644
--- a/Source/cmLocalGenerator.h
+++ b/Source/cmLocalGenerator.h
@@ -144,7 +144,7 @@ public:
   std::string GetIncludeFlags(const std::vector<std::string>& includes,
                               cmGeneratorTarget* target,
                               const std::string& lang,
- bool forceFullPaths = false,
+ bool forceFullPaths = true,
                               bool forResponseFile = false,
                               const std::string& config = "");
 
diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx
index 3803621fd1..236e682d50 100644
--- a/Source/cmNinjaTargetGenerator.cxx
+++ b/Source/cmNinjaTargetGenerator.cxx
@@ -211,8 +211,8 @@ void cmNinjaTargetGenerator::AddIncludeFlags(std::string& languageFlags,
   // Add include directory flags.
   std::string includeFlags = this->LocalGenerator->GetIncludeFlags(
     includes, this->GeneratorTarget, language,
- language == "RC", // full include paths for RC needed by cmcldeps
- false, config);
+ true, //XXX language == "RC", // full include paths for RC needed by cmcldeps
+ false, config); //TODO: why not forceFullPaths? CK
   if (this->GetGlobalGenerator()->IsGCCOnWindows()) {
     std::replace(includeFlags.begin(), includeFlags.end(), '\\', '/');
   }
@@ -1155,8 +1155,8 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
         cmSystemTools::GetParentDirectory(source->GetFullPath()));
 
       std::string sourceDirectoryFlag = this->LocalGenerator->GetIncludeFlags(
- sourceDirectory, this->GeneratorTarget, language, false, false,
- config);
+ sourceDirectory, this->GeneratorTarget, language, true, false,
+ config); // TODO Why not forceFullpath? CK
 
       vars["INCLUDES"] = cmStrCat(sourceDirectoryFlag, ' ', vars["INCLUDES"]);
     }
klein_cl@2d-oehsdg:~/Workspace/cpp/cmake$ 

```

---

<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:** [March 9, 2020, 3:34pm UTC](https://discourse.cmake.org/t/does-the-target-include-directories-command-strip-out-duplicate-paths-added/769/9 "2020-03-09T15:34:29Z")

</div>

Yes. That’s why the issue is still open. The `ninja` tool itself does not support us writing absolute paths right now. [https://github.com/ninja-build/ninja/issues/1251](https://github.com/ninja-build/ninja/issues/1251)

---

<div class="post-metadata">

**Author:** ![ClausKlein](https://discourse.cmake.org/user_avatar/discourse.cmake.org/clausklein/32/352_2.png) [@ClausKlein](https://discourse.cmake.org/u/ClausKlein)\
**Post date:** [March 9, 2020, 3:44pm UTC](https://discourse.cmake.org/t/does-the-target-include-directories-command-strip-out-duplicate-paths-added/769/10 "2020-03-09T15:44:08Z")

</div>

Ok, I can live with the workaround to have the _ **binary\_dir** _ outsite _ **source\_dir** _.

But this show, that the **realpath()** sould be used too!  
and `auto end = cmRemoveDuplicates(allIncludeDirs);`

```cmake
target_include_directories(main
    PRIVATE . .. /dir1 /dir2 /dir1 /dir2 /dir1/../dir2 /dir2/../dir1
)

```

---

<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:** [March 9, 2020, 5:05pm UTC](https://discourse.cmake.org/t/does-the-target-include-directories-command-strip-out-duplicate-paths-added/769/11 "2020-03-09T17:05:32Z")

</div>

`realpath` has some…issues in CMake due to an old feature to support an uncommon use case that affects too much. It’s on our list to reduce its scope. [https://gitlab.kitware.com/cmake/cmake/issues/16228](https://gitlab.kitware.com/cmake/cmake/issues/16228)

(Cc: @brad.king)

---

<div class="post-metadata">

**Author:** ![ClausKlein](https://discourse.cmake.org/user_avatar/discourse.cmake.org/clausklein/32/352_2.png) [@ClausKlein](https://discourse.cmake.org/u/ClausKlein)\
**Post date:** [March 9, 2020, 5:28pm UTC](https://discourse.cmake.org/t/does-the-target-include-directories-command-strip-out-duplicate-paths-added/769/12 "2020-03-09T17:28:32Z")

</div>

Thanks for your support
