# 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:** 5
**Page:** 1

<div class="post-metadata">

### Author: ![jasonaylward](https://discourse.cmake.org/user_avatar/discourse.cmake.org/jasonaylward/32/2219_2.png) [@jasonaylward](https://discourse.cmake.org/u/jasonaylward)
#### Post date: [April 6, 2023, 7:26pm UTC](https://discourse.cmake.org/t/clarification-on-public-private-with-target-source-group/7845/1 "2023-04-06T19:26:01Z")

</div>

I’ve read over the documentation and a few threads on when and why use PRIVATE over PUBLIC when adding files to a target but I still don’t really get it.

I see that I have a library XYZ and if I say

```auto
target_sources(XYZ
    PRIVATE
        foo.cpp
    PUBLIC
       foo.h

```

that if I have an executable APP target that says `target_link_libraries(APP PRIVATE XYZ)`, that foo.h is inside the APP group on Xcode. If I make both foo.cpp and foo.h PUBLIC, then the APP group has both files in Xcode.

That’s convenient from a coding standpoint, I have all my files in one group but I don’t really see a downside. Is it just the case when you want to build the XYZ library and ship it with a bundle of header files? Or does it actually effect how the executable APP is built?

---

<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.

---

<div class="post-metadata">

### Author: ![jasonaylward](https://discourse.cmake.org/user_avatar/discourse.cmake.org/jasonaylward/32/2219_2.png) [@jasonaylward](https://discourse.cmake.org/u/jasonaylward)
#### Post date: [April 7, 2023, 1:18pm UTC](https://discourse.cmake.org/t/clarification-on-public-private-with-target-source-group/7845/3 "2023-04-07T13:18:17Z")

</div>

No, @craig.scott , not what I was expecting but totally an answer I was hoping for. Thanks for such a thorough explanation.  
The discrepancy in how PUBLIC/PRIVATE effects compilation was exactly the type of thing I wanted to be sure I WASN’T doing so it’s good to know that I should, at the very least, go back to my original paradigm of public headers and private .cpp’s.

I’ll start looking into file sets and see if that helps with anything. I’d really like the generated Xcode and VS projects to resemble what the developers would have setup themselves so that it’s as invisible as possible.

I’ve found that the following will successfully reorganize all the code from my library target (XYZ) into the original folder structure in the IDE, so that’s really helpful.

```auto
# inside the XYZ CMakeLists.txt
get_target_property(TARGET_SOURCES XYZ SOURCES)
source_group(TREE ${CMAKE_SOURCE_DIR} FILES ${TARGET_SOURCES})

```

The issue I’m still trying to solve, if you have any ideas, is removing files from the IDE that are shown redundantly.

If there was a way to say something like the pseudocode below, it would be nice to hide the library code inside the APP target because it’s already in the library target in the IDE.

```auto
#inside the APP CMakeLists.txt
get_target_property(TARGET_SOURCES XYZ SOURCES)
source_group(<HIDE> FILES ${TARGET_SOURCES})

```

(Hope that makes sense)

---

<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 7, 2023, 8:40pm UTC](https://discourse.cmake.org/t/clarification-on-public-private-with-target-source-group/7845/4 "2023-04-07T20:40:13Z")

</div>

> [@jasonaylward](#):
>
> If there was a way to say something like the pseudocode below, it would be nice to hide the library code inside the APP target because it’s already in the library target in the IDE.

That sounds to me like you still have something `PUBLIC` which should instead be `PRIVATE`.

---

<div class="post-metadata">

### Author: ![jasonaylward](https://discourse.cmake.org/user_avatar/discourse.cmake.org/jasonaylward/32/2219_2.png) [@jasonaylward](https://discourse.cmake.org/u/jasonaylward)
#### Post date: [April 10, 2023, 1:11pm UTC](https://discourse.cmake.org/t/clarification-on-public-private-with-target-source-group/7845/5 "2023-04-10T13:11:47Z")

</div>

I’ve got it all looking correct in Xcode now and the tests compile and pass so I think I’m good to go.  
I needed to target all the .h files under PRIVATE as well.

Thanks again @craig.scott for all the help and feedback
