How to share precompiled headers via an interface library

From target_precompile_headers:

A notable exception to this is where an interface library 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_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_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

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

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

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

Cc: @cristianadam @brad.king

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.

I see, so my later guess was confirmed.

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.

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