# How to share precompiled headers via an interface library

**URL:** https://discourse.cmake.org/t/how-to-share-precompiled-headers-via-an-interface-library/9933
**Category:** Code
**Tags:** comp:clang, gen:ninja, tool:cmake
**Created:** [January 25, 2024, 6:03pm UTC](https://discourse.cmake.org/t/how-to-share-precompiled-headers-via-an-interface-library/9933 "2024-01-25T18:03:10Z")
**Posts on this page:** 8
**Page:** 1

<div class="post-metadata">

### Author: ![Kentzo](https://discourse.cmake.org/user_avatar/discourse.cmake.org/kentzo/32/4122_2.png) [@Kentzo](https://discourse.cmake.org/u/Kentzo)
#### Post date: [January 25, 2024, 6:03pm UTC](https://discourse.cmake.org/t/how-to-share-precompiled-headers-via-an-interface-library/9933/1 "2024-01-25T18:03:10Z")

</div>

From [target\_precompile\_headers](https://cmake.org/cmake/help/latest/command/target_precompile_headers.html):

> A notable exception to this is where an [interface library](https://cmake.org/cmake/help/latest/manual/cmake-buildsystem.7.html#interface-libraries) is created to define a commonly used set of precompile headers in one place and then other targets link to that interface library privately. In this case, the interface library exists specifically to propagate the precompile headers to its consumers and the consumer is effectively still in control, since it decides whether to link to the interface library or not.

But how can I make it work? I tried the following:

```cmake
    cmake_minimum_required(VERSION 3.16.0)

    add_library(shared_pch INTERFACE)
    target_precompile_headers(shared_pch INTERFACE pch.h)
    set_target_properties(shared_pch PROPERTIES INTERFACE_POSITION_INDEPENDENT_CODE ON)

    add_library(libA SHARED ...)
    target_link_libraries(libA PRIVATE shared_pch)

    add_library(libB SHARED ...)
    target_link_libraries(libA PRIVATE shared_pch)

```

but the compilation time increased compared to the “old” approach:

```cmake
    cmake_minimum_required(VERSION 3.16.0)

    add_library(shared_pch STATIC)
    file(GENERATE OUTPUT empty_pch.cpp CONTENT "/*dummy pch file*/")
    target_sources(shared_pch empty_pch.cpp)
    set_target_properties(shared_pch PROPERTIES
        PRECOMPILE_HEADERS pch.h
        POSITION_INDEPENDENT_CODE ON
    )

    add_library(libA SHARED ...)
    target_precompile_headers(libA REUSE_FROM shared_pch)

    add_library(libB SHARED ...)
    target_precompile_headers(libB REUSE_FROM shared_pch)

```

Possibly related to [PCH: Don't understand that part of the doc](https://discourse.cmake.org/t/pch-dont-understand-that-part-of-the-doc/7321)

---

<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, 2:11pm UTC](https://discourse.cmake.org/t/how-to-share-precompiled-headers-via-an-interface-library/9933/2 "2024-01-26T14:11:04Z")

</div>

> [@Kentzo](#):
>
> but the compilation time increased compared to the “old” approach:

There’s no guarantee that PCH is faster than any other strategy. Can you benchmark where the difference(s) are?

---

<div class="post-metadata">

### Author: ![Kentzo](https://discourse.cmake.org/user_avatar/discourse.cmake.org/kentzo/32/4122_2.png) [@Kentzo](https://discourse.cmake.org/u/Kentzo)
#### Post date: [January 26, 2024, 7:40pm UTC](https://discourse.cmake.org/t/how-to-share-precompiled-headers-via-an-interface-library/9933/3 "2024-01-26T19:40:23Z")

</div>

Thank you for taking time to help with this problem.

> Can you benchmark where the difference(s) are?

Comparing the build logs of the [old](https://github.com/KDAB/GammaRay/actions/runs/7637161294/job/20805489165?pr=941) and [new](https://github.com/KDAB/GammaRay/actions/runs/7645378040/job/20831803731?pr=940) approaches it seems the build time doubled. This appears to be due to precompiled headers being rebuilt for each target rather than being reused: just 1 mention of _cmake\_pch.hxx.pch_ with the old approach and 42 with the new.

> There’s no guarantee that PCH is faster than any other strategy.

And yet the “old” approach was faster. My intent is to pre-compile [a bunch of Qt headers](https://github.com/KDAB/GammaRay/blob/ea79be430b1a548f75000a25ca37f43d7e2d30aa/core/pch.h) once which are then reused by other targets in the project. In general, considering the two excerpts in my original post, is it expected for them to result in identical behavior?

* * *

Perhaps the doc intends to say that an INTERFACE library does not propagate precompiled headers (and in fact it precompiles nothing), but rather it propagates headers marked for precompilation which are then precompiled by each material target, independently? Thus the doc excerpt should be read as:

> A notable exception to this is where an [interface library](https://cmake.org/cmake/help/latest/manual/cmake-buildsystem.7.html#interface-libraries) is created to define a commonly used set of ~~precompile~~ headers _to precompile_ in one place and then other targets link to that interface library privately. In this case, the interface library exists specifically to propagate the ~~precompile~~ headers _to precompile_ to its consumers, _independently from each other_, and the consumer is effectively still in control, since it decides whether to link to the interface library or not.

---

<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, 8:11pm UTC](https://discourse.cmake.org/t/how-to-share-precompiled-headers-via-an-interface-library/9933/4 "2024-01-26T20:11:32Z")

</div>

That could be the case; I’m not that familiar with the PCH feature though.

Cc: @cristianadam @brad.king

---

<div class="post-metadata">

### Author: ![cristianadam](https://discourse.cmake.org/user_avatar/discourse.cmake.org/cristianadam/32/124_2.png) [@cristianadam](https://discourse.cmake.org/u/cristianadam)
#### Post date: [January 26, 2024, 9:18pm UTC](https://discourse.cmake.org/t/how-to-share-precompiled-headers-via-an-interface-library/9933/5 "2024-01-26T21:18:03Z")

</div>

The first signature will pass the list of precompile headers into `PRECOMPILE_HEADERS` or `INTERFACE_PRECOMPILE_HEADERS` properties.

But only the `REUSE_FROM` signature of `target_precompile_headers` will get the targets to reuse the PCH. This sets the `PRECOMPILE_HEADERS_REUSE_FROM` property.

What you want is a `INTERFACE_PRECOMPILE_HEADERS_REUSE_FROM` property, but this doesn’t exist. You would have to live with the static library approach.

---

<div class="post-metadata">

### Author: ![Kentzo](https://discourse.cmake.org/user_avatar/discourse.cmake.org/kentzo/32/4122_2.png) [@Kentzo](https://discourse.cmake.org/u/Kentzo)
#### Post date: [January 27, 2024, 8:19am UTC](https://discourse.cmake.org/t/how-to-share-precompiled-headers-via-an-interface-library/9933/6 "2024-01-27T08:19:01Z")

</div>

I see, so my later guess was confirmed.

---

<div class="post-metadata">

### Author: ![cristianadam](https://discourse.cmake.org/user_avatar/discourse.cmake.org/cristianadam/32/124_2.png) [@cristianadam](https://discourse.cmake.org/u/cristianadam)
#### Post date: [January 27, 2024, 8:27am UTC](https://discourse.cmake.org/t/how-to-share-precompiled-headers-via-an-interface-library/9933/7 "2024-01-27T08:27:42Z")

</div>

If you have multiple interface libraries which you use and they all have precompile headers, they will all sum up in the target.

Whilst with pch artifacts, you can have only one, at least on MSVC, if I remember correctly. MSVC also requires that you copy the artifact. I think it would be fine for clang and gcc.

---

<div class="post-metadata">

### Author: ![Kentzo](https://discourse.cmake.org/user_avatar/discourse.cmake.org/kentzo/32/4122_2.png) [@Kentzo](https://discourse.cmake.org/u/Kentzo)
#### Post date: [January 27, 2024, 9:04am UTC](https://discourse.cmake.org/t/how-to-share-precompiled-headers-via-an-interface-library/9933/8 "2024-01-27T09:04:13Z")

</div>

This project is not that complex, it’s just one set of headers for precompilation and reuse by all material targets.
