# Internal/external headers

**URL:** https://discourse.cmake.org/t/internal-external-headers/9908
**Category:** Usage
**Created:** [January 23, 2024, 4:40am UTC](https://discourse.cmake.org/t/internal-external-headers/9908 "2024-01-23T04:40:04Z")
**Posts on this page:** 4
**Page:** 1

<div class="post-metadata">

### Author: ![bramtayl](https://discourse.cmake.org/user_avatar/discourse.cmake.org/bramtayl/32/2931_2.png) [@bramtayl](https://discourse.cmake.org/u/bramtayl)
#### Post date: [January 23, 2024, 4:40am UTC](https://discourse.cmake.org/t/internal-external-headers/9908/1 "2024-01-23T04:40:04Z")

</div>

I have a project C++ project with both private and public headers. I want to make the private headers available to other targets, plugins and executables I’m building in the project, but only the external headers available to end users. I’m not sure how to do this. I thought maybe I should make an “internal” library with both private and public headers, and a “public” library linked to the “internal” library with only public headers available. But I’m not sure how to do that?

---

<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: [January 23, 2024, 1:04pm UTC](https://discourse.cmake.org/t/internal-external-headers/9908/2 "2024-01-23T13:04:53Z")

</div>

You can use `$<BUILD_LOCAL_INTERFACE>` (new in CMake 3.26) to hide targets from `EXPORT` sets. So something like:

```cmake
add_library(internal_headers INTERFACE)
# prep `internal_headers`

## All project-local users of `public_headers` will be able to use internal headers
add_library(public_headers INTERFACE)
target_link_libraries(public_headers INTERFACE "$<BUILD_LOCAL_INTERFACE:internal_headers>")

## Or use on specific targets (still possible if `public_headers` is not required)
add_library(mylib)
target_link_libraries(mylib PRIVATE "$<BUILD_LOCAL_INTERFACE:internal_headers>")

```

`$<BUILD_INTERFACE>` will hide it from `install(EXPORT)`, but still require the target for `export(EXPORT)` uses though, but it is new from CMake 3.0.

---

<div class="post-metadata">

### Author: ![bramtayl](https://discourse.cmake.org/user_avatar/discourse.cmake.org/bramtayl/32/2931_2.png) [@bramtayl](https://discourse.cmake.org/u/bramtayl)
#### Post date: [January 24, 2024, 4:17am UTC](https://discourse.cmake.org/t/internal-external-headers/9908/3 "2024-01-24T04:17:31Z")

</div>

> [@ben.boeckel](#):
>
> $\<BUILD\_LOCAL\_INTERFACE\>

Hm I still don’t understand…Why do we need an interface target?

Say I have something like this:

```auto
add_library(MyLibrary SHARED ${my_sources})
target_include_directories(MyLibrary PRIVATE ${private_include_dirs})
target_include_directories(MyLibrary PUBLIC ${public_include_dirs})

add_library(InternalPlugin SHARED ${internal_plugin_sources})
target_link_libraries(InternalPlugin PRIVATE MyLibrary)

add_library(RegularPlugin SHARED ${regular_plugin_sources})
target_link_libraries(RegularPlugin PRIVATE MyLibrary)

```

Is there a way to make the headers in `${private_include_dirs}` available to `InternalPlugin` but not `RegularPlugin`?

---

<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: [January 26, 2024, 1:48pm UTC](https://discourse.cmake.org/t/internal-external-headers/9908/4 "2024-01-26T13:48:19Z")

</div>

> [@bramtayl](#):
>
> > [@ben.boeckel](#):
> >
> > $\<BUILD\_LOCAL\_INTERFACE\>
> 
> Hm I still don’t understand…Why do we need an interface target?

The genex has nothing to do with target types; it’s about the interface of the exported information of the target.

> [@bramtayl](#):
>
> Is there a way to make the headers in `${private_include_dirs}` available to `InternalPlugin` but not `RegularPlugin`?

Move the private headers to an `INTERFACE` target that you link where needed. In order to avoid having to export it, you can use the `$<BUILD_LOCAL_INTERFACE>` or `$<BUILD_INTERFACE>` generator expressions.
