# Clarification on PUBLIC/PRIVATE with target\_source\_group

**URL:** https://discourse.cmake.org/t/clarification-on-public-private-with-target-source-group/7845
**Category:** Code
**Created:** [April 6, 2023, 7:26pm UTC](https://discourse.cmake.org/t/clarification-on-public-private-with-target-source-group/7845 "2023-04-06T19:26:01Z")
**Posts on this page:** 1
**Showing post:** 2

<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: [April 6, 2023, 11:58pm UTC](https://discourse.cmake.org/t/clarification-on-public-private-with-target-source-group/7845/2 "2023-04-06T23:58:07Z")

</div>

You pretty much never want a `.cpp` file to be anything but `PRIVATE`. The only target that should be compiling the `.cpp` file is the target you are adding it to (there are exceptions, but those scenarios are exceedingly rare). If you add a `.cpp` file as `PUBLIC`, you are saying that it should be compiled into the current target _and anything that links to it_. Note that this is not talking about linking the object file produced from the `.cpp` file, we’re talking about _compiling_ it. In your example, `foo.cpp` will be compiled as part of `APP` and also as part of `XYZ`. The object file compiled into `APP` will be used and the one compiled into `XYZ` is not used. The one compiled into `APP` shouldn’t be there, you only want it compiled into `XYZ` and linking to `XYZ` should then pick up that one.

For a header, the situation is considerably more involved. It has been common for IDEs to not show a header in its file lists unless the header was added to a target. Thus, it was common to see headers added directly in calls to `add_executable()` and `add_library()`. By extension, it made sense to add them using `target_sources()` too, but then you had to decide if `PRIVATE`, `PUBLIC` or `INTERFACE` was the most appropriate. Since headers don’t get compiled directly, the only real difference used to be that these keywords controlled which target(s) that file would appear under in IDEs. The usual way this played out was that a header-only library would get represented as an interface library, which in earlier versions of CMake meant you had no choice but to add headers as `INTERFACE`. CMake 3.19 added the ability to add headers to interface libraries as `PRIVATE` (or equivalently to list them in the call to `add_library()`), which allowed the header to be seen as part of that target in IDEs instead of the target’s consumers. For targets that were not interface libraries, headers would normally be added as `PRIVATE` so that those headers were associated with that target in IDE file lists.

CMake 3.23 is where things got much more interesting. That release added file sets, which fundamentally changed the recommended way to add headers to your project. Now the `PRIVATE`, `PUBLIC` and `INTERFACE` keywords have different impacts when used for a file set, affecting not just IDEs but also things like header search paths, installation of the headers, and verification of whether headers are self-contained. File sets brought much more powerful capabilities and meaning to headers and how they are used in a project and by consumers of that project. Fundamentally though, the high level meaning of `PRIVATE`, `PUBLIC` and `INTERFACE` still means something similar when defining a file set with `target_sources()`. `PRIVATE` means “only used when building this target”, `INTERFACE` means “only used by things that consume this target, not the target itself”, and `PUBLIC` merges both of those together. Thus, when you define a headers file set, you need to consider whether the headers are part of that target’s public API or not. Typically, I recommend defining two separate file sets for a target, one to contain the public headers (I often call that header set “api”) and another to contain the private headers (which I typically just call “private”). IDEs _should_ associate headers specified in a file set with the target they are being added to by the `target_sources()` call in all cases, but I don’t know if they will still use the old behavior of showing non-private headers under consumers of the target.

Probably not quite what you were expecting, but hopefully that fills out a bit more of the landscape for you to explore.

---

_[View the full topic](https://discourse.cmake.org/t/clarification-on-public-private-with-target-source-group/7845)._
