target_include_directories() vs headers in target_sources()

Looking for advice on how to think about when to add directories with headers in them as target_include_directories() vs adding every header file by hand using target_sources().

One thing I’ve noted is that I struggle to tell the linker which one to use if different headers with the same name (say utils.h) exists on different levels in a code base. Is target_sources() the most practical solution in that case?
Would appreciate some rules of thumb type advice on this, thanks.

1 Like

target_include_directories is relevant to the preprocessor (which is usually part of the compiler), since it allows to resolve #include preprocessor directives.

Adding headers with target_sources is relevant to IDEs (Visual Studio, Xcode, etc.) so they can display these header files, even if they are not directly compiled.

So these 2 functions are doing quite different things, and I can’t think of any situation where you would have to choose between them.

I hope this helps.

1 Like

I was asking myself the same question.

The documentation of target_sources says :

Specifies sources to use when building a target and/or its dependents.

There is no mention of display in the documentation of this function.

Are you not confused with the command source_group ?

The situation has changed with the advent of file sets. Now you can define a HEADERS file set with target_sources(), and it does affect the header search path in a way that you probably don’t need target_include_directories() any more. See the target_sources documentation for details.

3 Likes

Yes, I discovered file sets today wy reading one of your post on your web site (so I bought your book some hours ago…).
But I don’t really understand how to use them.

Especially FILE_SET <set> : what is this set name used for ?

In the Professional CMake book, there’s a section on file sets in “Chapter 35: Installing”. The next edition will split things out to earlier sections for more logical flow and to make file set details easier to find.

Especially FILE_SET <set> : what is this set name used for ?

The set name is primarily useful with install(TARGETS ... FILE_SET ...). This is a very convenient way to install headers that are in PUBLIC and INTERFACE header sets. You also need the set name when you are adding files to a file set progressively, such as when you have them spread across multiple directories and you want to add each directory’s files in its own target_sources() call.