Skip to content

PCH: TARGET_OBJECTS contains precompiled headers

Description

I recently tried the new cmake feature Linking Object Libraries via $<TARGET_OBJECTS>, but I had some issues to make it work properly with gcc precompiled headers.

I would expect the following cmake code to produce a valid build:

# create an object library
add_library(lib1 OBJECT)
...
target_precompile_headers(lib1 PRIVATE ${CMAKE_SOURCE_DIR}/lib1/precompiledheaders.h)

# create an interface library via TARGET_OBJECTS
target_link_libraries(lib1-interface INTERFACE lib1 $<TARGET_OBJECTS:lib1>)

# create the main target, reuse precompiled headers
add_executable(cmake_bug main.cpp)
target_precompile_headers(cmake_bug REUSE_FROM lib1)
target_link_libraries(cmake_bug PRIVATE lib1-interface)

But instead it fails with the following log:

cmake --build <build-dir> --target cmake_bug
Scanning dependencies of target lib1
[ 25%] Building CXX object CMakeFiles/lib1.dir/cmake_pch.hxx.gch
[ 50%] Building CXX object CMakeFiles/lib1.dir/lib1/lib1.cpp.o
[ 50%] Built target lib1
Scanning dependencies of target cmake_bug
[ 75%] Building CXX object CMakeFiles/cmake_bug.dir/main.cpp.o
[100%] Linking CXX executable cmake_bug
CMakeFiles/lib1.dir/cmake_pch.hxx.gch: file not recognized: file format not recognized
collect2: error: ld returned 1 exit status
make[3]: *** [CMakeFiles/cmake_bug.dir/build.make:97: cmake_bug] Error 1
make[2]: *** [CMakeFiles/Makefile2:111: CMakeFiles/cmake_bug.dir/all] Error 2
make[1]: *** [CMakeFiles/Makefile2:118: CMakeFiles/cmake_bug.dir/rule] Error 2
make: *** [Makefile:137: cmake_bug] Error 2

If you try to compile the minimal reproducible example I crafted and have a look at the generated debug file in <build_dir>/debug, you will notice that the expansion of $<TARGET_OBJECTS:lib1> contains the following:

<build_dir>/CMakeFiles/lib1.dir/cmake_pch.hxx.gch;
<build_dir>/CMakeFiles/lib1.dir/lib1/lib1.cpp.o

As a consequence, the cmake generated command in <build_dir>/CMakeFiles/cmake_bug.dir/link.txt contains a.gch file

/usr/local/bin/g++ -g CMakeFiles/cmake_bug.dir/main.cpp.o -o cmake_bug CMakeFiles/lib1.dir/cmake_pch.hxx.gch CMakeFiles/lib1.dir/lib1/lib1.cpp.o

while IMO it should just contain the *.o object files

/usr/local/bin/g++ -g CMakeFiles/cmake_bug.dir/main.cpp.o -o cmake_bug CMakeFiles/lib1.dir/lib1/lib1.cpp.o

Known workarounds

I managed to obtain a successful gcc build by filtering out the gch files with a generator expression such as

target_link_libraries(lib1-interface INTERFACE lib1 $<FILTER:$<TARGET_OBJECTS:lib1>,EXCLUDE,.*\\.gch>)

the generator expression now correctly expands to

<build_dir>/CMakeFiles/lib1.dir/lib1/lib1.cpp.o

and the content of the link.txt file in this case is the same as if I did

+ target_link_libraries(cmake_bug PRIVATE lib1)
- target_link_libraries(cmake_bug PRIVATE lib1-interface)

You can trigger the successful build in the minimal example by passing -DCOMPILE_WITH_WORKAROUND=on

System Info and toolchain

  • OS: Ubuntu 20.04
  • Cmake: 3.21.4, 3.22.0-rc2
  • Compiler: gcc-9.3.0, gcc-11.1
Edited by Brad King
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information