# Can't reuse PCH generated when compiling a library

**URL:** https://discourse.cmake.org/t/cant-reuse-pch-generated-when-compiling-a-library/15107
**Category:** Code
**Created:** [August 24, 2025, 4:52pm UTC](https://discourse.cmake.org/t/cant-reuse-pch-generated-when-compiling-a-library/15107 "2025-08-24T16:52:17Z")
**Posts on this page:** 12
**Page:** 1

<div class="post-metadata">

### Author: ![nicolamori](https://discourse.cmake.org/user_avatar/discourse.cmake.org/nicolamori/32/1278_2.png) [@nicolamori](https://discourse.cmake.org/u/nicolamori)
#### Post date: [August 24, 2025, 4:52pm UTC](https://discourse.cmake.org/t/cant-reuse-pch-generated-when-compiling-a-library/15107/1 "2025-08-24T16:52:17Z")

</div>

I am trying to use precompiled headers in my project, but I’m finding a strange issue. I put together [a simple reproducer](https://basket.fi.infn.it:443/f/127b2c0608/?raw=1), where I have a header which I want to precompile when building a shared library (lib1) and then reuse when building another library (lib2). The compiler issues a warning when compiling the latter, informing that the PCH cannot be reused due to the `-Dlib1_EXPORTS` flag being missing.

According to my investigations the `-Dlib1_EXPORTS` compiler flag is automatically added by CMake when compiling `lib1` and also the PCH, while for `lib2` it just adds `-Dlib2_EXPORTS`. These different flags make the reusage of the PCH impossible.

I didn’t find any hint about the meaning of these flags, why they are added, and eventually how to remove them; I only saw that they are not added to executable targets, but this says not much to me. The [documentation](https://cmake.org/cmake/help/latest/command/target_precompile_headers.html) about `target_precompile_headers` does not prescribe any particular care to be taken to avoid this issue in the `Reusing Precompile Headers` section; it just says that the flags must be identical. It seems really strange to me that the PCH reusage machinery fails like this in this very simple case, so I must be doing something terribly wrong, but I cannot figure out what.

I am using CMake 4.1.0 on ArchLinux.

Thanks in advance for any help.

---

<div class="post-metadata">

### Author: ![retif](https://discourse.cmake.org/user_avatar/discourse.cmake.org/retif/32/1776_2.png) [@retif](https://discourse.cmake.org/u/retif)
#### Post date: [August 24, 2025, 5:51pm UTC](https://discourse.cmake.org/t/cant-reuse-pch-generated-when-compiling-a-library/15107/2 "2025-08-24T17:51:54Z")

</div>

> [@nicolamori](#):
>
> the `-Dlib1_EXPORTS` compiler flag is automatically added by CMake

> [@nicolamori](#):
>
> why they are added

You are correct to say that this one is added automatically by CMake. It happens when the library is `SHARED` (_so that one could do `#ifdef SomeLibrary_EXPORTS` in their sources_).

> [@nicolamori](#):
>
> how to remove them

From what I see in the documentation, you’d need to unset (_or set to `FALSE`?_) [ENABLE\_EXPORTS](https://cmake.org/cmake/help/latest/prop_tgt/ENABLE_EXPORTS.html#prop_tgt:ENABLE_EXPORTS) for the target(s) or [CMAKE\_SHARED\_LIBRARY\_ENABLE\_EXPORTS](https://cmake.org/cmake/help/latest/variable/CMAKE_SHARED_LIBRARY_ENABLE_EXPORTS.html#variable:CMAKE_SHARED_LIBRARY_ENABLE_EXPORTS) for the entire project (_to affect all the targets_).

> [@nicolamori](#):
>
> The compiler issues a warning when compiling the latter, informing that the PCH cannot be reused due to the `-Dlib1_EXPORTS` flag being missing.

Why does that happen, and what one should do in this case (_as removing the `*_EXPORTS` compile definitions doesn’t seem to be the way to go_) - that I don’t know, and I’d be curious to see what others have to say on the matter.

---

<div class="post-metadata">

### Author: ![nicolamori](https://discourse.cmake.org/user_avatar/discourse.cmake.org/nicolamori/32/1278_2.png) [@nicolamori](https://discourse.cmake.org/u/nicolamori)
#### Post date: [August 25, 2025, 10:29am UTC](https://discourse.cmake.org/t/cant-reuse-pch-generated-when-compiling-a-library/15107/3 "2025-08-25T10:29:58Z")

</div>

From what I understood from the `ENABLE_EXPORTS` documentation you linked, disabling exports for a shared library would prevent the possibility to link it to an executable, actually making it almost useless. If this is correct then I’d say this is not a solution that would work for me…

---

<div class="post-metadata">

### Author: ![nicolamori](https://discourse.cmake.org/user_avatar/discourse.cmake.org/nicolamori/32/1278_2.png) [@nicolamori](https://discourse.cmake.org/u/nicolamori)
#### Post date: [August 27, 2025, 12:54pm UTC](https://discourse.cmake.org/t/cant-reuse-pch-generated-when-compiling-a-library/15107/4 "2025-08-27T12:54:00Z")

</div>

Any help? I can’t believe such a trivially triggerable error went unnoticed up to now, I must be doing some gross error here…

---

<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: [August 27, 2025, 10:10pm UTC](https://discourse.cmake.org/t/cant-reuse-pch-generated-when-compiling-a-library/15107/5 "2025-08-27T22:10:47Z")

</div>

You’re not going to like this answer… While what you’re trying to do seems reasonable, it can’t get past the fundamental restriction that to re-use a PCH, all options have to be identical. Because you have shared libraries involved with symbol visibility enabled, you can’t satisfy that requirement. When building the shared library whose PCH you want to re-use, a compiler define has to be set to a certain value to make symbols get exported. For literally all other code using that shared library, that same compiler define has to have a different value, which is how all that other code _imports_ rather than _exports_ those symbols.

What does this mean for you? Well, if you’re building shared libraries, you won’t be able to re-use PCH between them. Static libraries, yes that would be fine, but not shared libraries. Or you could throw away all the goodness that symbol visibility gives you, which would remove the need for symbol exporting and importing, but please don’t do that!

---

<div class="post-metadata">

### Author: ![nicolamori](https://discourse.cmake.org/user_avatar/discourse.cmake.org/nicolamori/32/1278_2.png) [@nicolamori](https://discourse.cmake.org/u/nicolamori)
#### Post date: [August 28, 2025, 3:14pm UTC](https://discourse.cmake.org/t/cant-reuse-pch-generated-when-compiling-a-library/15107/6 "2025-08-28T15:14:53Z")

</div>

So is the `-Dlib1_EXPORTS` needed by the compiler to export symbols? I’m not an expert of build tools, but I’m pretty sure I worked with makefile projects which produced working shared libraries also without this flag.

Eventually, just to give it a try: how do I manually remove the compiler flag? I checked the CMake documentation but I found no command to remove compiler flags, only to add.

---

<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: [August 28, 2025, 9:47pm UTC](https://discourse.cmake.org/t/cant-reuse-pch-generated-when-compiling-a-library/15107/7 "2025-08-28T21:47:48Z")

</div>

As a thought experiment, when building the shared library, the compiler has to interpret the headers one way (because it has to build that code exporting the symbols from there). When building code that _uses_ the shared library, it has to interpret the headers a different way (importing the symbols from there). A PCH can’t support both scenarios at once, so you can’t use a single PCH for both cases. The `lib1_EXPORTS` symbol is just the way you’re seeing that manifested in the build. You can probably come up with other ways to avoid the compiler definition and tell the compiler what to do another way, but the underlying limitation will still apply and you still won’t be able to use a single PCH for both scenarios.

---

<div class="post-metadata">

### Author: ![nicolamori](https://discourse.cmake.org/user_avatar/discourse.cmake.org/nicolamori/32/1278_2.png) [@nicolamori](https://discourse.cmake.org/u/nicolamori)
#### Post date: [August 29, 2025, 7:10am UTC](https://discourse.cmake.org/t/cant-reuse-pch-generated-when-compiling-a-library/15107/8 "2025-08-29T07:10:48Z")

</div>

Thanks for the explanation, but I still don’t understand. The `lib1_EXPORTS` flag is never explicitly used in my headers, and as far as I can see it’s not even in the involved automatically generated headers by CMake. Moreover, according to what I have been able to understand searching the web, a compiler flag with a name following the `*_EXPORTS` pattern is not a special GCC flag which might determine a special behavior. Plus, as I wrote above, I obtained working shared libraries in makefile projects without that flag, so I still don’t understand why it’s necessary for CMake (it’s present even when a not using PCHs so I guess it’s not strictly related to those).

I found a bit of info [here](https://cmake.cmake.narkive.com/Fli19zGr/import-exports-for-shared-libraries) about a possible meaning of this flag and it sort of matches what you write about the ability to import/export symbols from/to libraries, but it’s a Windows-specific trick which I’ve never seen under Linux, so from it I wouldn’t say that the flag is absolutely necessary under Linux (which is my target environment).

To prove that the flag is not strictly needed I manually tuned the reproducer linked in my first post. First, I compiled as usual with the `VERBOSE=1` command line flag for `make` to print the compiler invocation commands, then I cleaned the build and issued all the commands manually removing the `*_EXPORTS` flag:

```auto
# Compile the PCH
$ /usr/bin/c++ -fPIC -Winvalid-pch -x c++-header -include /tmp/PCHRepro/CMakeFiles/lib1.dir/cmake_pch.hxx -MD -MT CMakeFiles/lib1.dir/cmake_pch.hxx.gch -MF CMakeFiles/lib1.dir/cmake_pch.hxx.gch.d -o CMakeFiles/lib1.dir/cmake_pch.hxx.gch -c /tmp/PCHRepro/CMakeFiles/lib1.dir/cmake_pch.hxx.cxx

# Compile lib1
$ /usr/bin/c++ -fPIC -Winvalid-pch -include /tmp/PCHRepro/CMakeFiles/lib1.dir/cmake_pch.hxx -MD -MT CMakeFiles/lib1.dir/lib1.cpp.o -MF CMakeFiles/lib1.dir/lib1.cpp.o.d -o CMakeFiles/lib1.dir/lib1.cpp.o -c /tmp/PCHRepro/lib1.cpp

# Compile lib2
$ /usr/bin/c++ -fPIC -Winvalid-pch -include /tmp/PCHRepro/CMakeFiles/lib1.dir/cmake_pch.hxx -MD -MT CMakeFiles/lib2.dir/lib2.cpp.o -MF CMakeFiles/lib2.dir/lib2.cpp.o.d -o CMakeFiles/lib2.dir/lib2.cpp.o -c /tmp/PCHRepro/lib2.cpp

```

In this way the compiler does not complain about any missing flag when reusing the PCH, everything compiles and links fine, and I even added a simple main calling functions from the two libraries to be sure that absolutely everything works.

So, coming back to the begin of this long post, I still don’t understand…

---

<div class="post-metadata">

### Author: ![codeling](https://discourse.cmake.org/user_avatar/discourse.cmake.org/codeling/32/1700_2.png) [@codeling](https://discourse.cmake.org/u/codeling)
#### Post date: [August 29, 2025, 7:24pm UTC](https://discourse.cmake.org/t/cant-reuse-pch-generated-when-compiling-a-library/15107/9 "2025-08-29T19:24:03Z")

</div>

Under Linux, by default all symbols are exported from a shared library. You can change this to symbols being hidden by default (through the flag `-fvisibility=hidden`, and see e.g. here for reasons why this is a good idea: [Exported Symbols of Shared Libraries (GNU Gnulib)](https://www.gnu.org/software/gnulib/manual/html_node/Exported-Symbols-of-Shared-Libraries.html) ). To selectively export symbols, you need to add a marker (` __attribute__ (( __visibility__ ("default")))`) to them.

Typically you do this with a macro - and this macro then adds the marker, but only if currently compiling the shared library itself (based on a define such as the \_EXPORTS).

So if you are (as is done by default) just exposing all symbols (with all the downsides as mentioned in the article linked above, then yes, technically you don’t need the macro.

Windows actually has the opposite default behavior - there all symbols are hidden by default and must be explicitly marked as visible; so if you are developing cross-platform code, having the default behavior to be the same on all can actually also make things easier through consistency

---

<div class="post-metadata">

### Author: ![nicolamori](https://discourse.cmake.org/user_avatar/discourse.cmake.org/nicolamori/32/1278_2.png) [@nicolamori](https://discourse.cmake.org/u/nicolamori)
#### Post date: [August 30, 2025, 8:08am UTC](https://discourse.cmake.org/t/cant-reuse-pch-generated-when-compiling-a-library/15107/10 "2025-08-30T08:08:41Z")

</div>

Thanks for the additional insight. I’m not developing for cross-platform, just for Linux, and exposing the full API of my libraries is not an issue for me (it’s what I am doing currently and it creates no problem). So I’d really like to remove the \_EXPORTS flag to be able to reuse PCHs across libraries and see if it brings any benefit to build time, how can this be done?

---

<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: [August 30, 2025, 11:06pm UTC](https://discourse.cmake.org/t/cant-reuse-pch-generated-when-compiling-a-library/15107/11 "2025-08-30T23:06:18Z")

</div>

The thing you’re probably looking for is the [`DEFINE_SYMBOL`](https://cmake.org/cmake/help/latest/prop_tgt/DEFINE_SYMBOL.html) target property. I’m not sure if setting it to an empty string will achieve what you want. The CMake code might treat that the same as unset, or it might lead to an invalid symbol name, etc.

---

<div class="post-metadata">

### Author: ![Angew](https://discourse.cmake.org/user_avatar/discourse.cmake.org/angew/32/229_2.png) [@Angew](https://discourse.cmake.org/u/Angew)
#### Post date: [September 3, 2025, 1:08pm UTC](https://discourse.cmake.org/t/cant-reuse-pch-generated-when-compiling-a-library/15107/12 "2025-09-03T13:08:01Z")

</div>

If it turns out impossible to disable `DEFINE_SYMBOL`, it should be possible to work around this by setting it to the same thing for all of your projects which want to share PCHs. The set of defines would then be the same and the compiler shouldn’t complain.
