Skip to content

automoc failure if using target_link_libraries(PUBLIC) for library without .cpp files and precompiled headers

Hello, I just ran into the following issue

Description

  • Library A has a PUBLIC precompiled header
  • Library B doesn't have any .cpp files
  • Library B uses the Q_OBJECT macro
  • Link the libraries by target_link_libraries(B PUBLIC A)

I get the following error:

ninja: error: 'CMakeFiles/B.dir/.pch', needed by 'CMakeFiles/B.dir/B_autogen/mocs_compilation.cpp.obj', missing and no known rule to make it

The setup:

  • Using cmake version 3.18.0
  • Using Ninja generator
  • Using windows compiler
  • Using Qt 5.14.2 msvc2017_64

Files:

a.hpp a.cpp b.hpp CMakeLists.txt

a.hpp:

#pragma once
class A {};

a.cpp:

#include "a.hpp"

b.hpp:

#include "a.hpp"
#include <QObject>

class B : QObject{
    Q_OBJECT
};

CMakeLists.txt:

cmake_minimum_required(VERSION 3.18)

project(test LANGUAGES CXX)

add_library(A a.cpp)
target_include_directories(A PUBLIC "${CMAKE_CURRENT_LIST_DIR}")
target_precompile_headers(A PUBLIC <a.hpp>)

find_package(Qt5 COMPONENTS Core)
set (CMAKE_AUTOMOC ON)
add_library(B b.hpp)
target_link_libraries(B PUBLIC A Qt5::Core)

This works with cmake version 3.17.3, but doesn't with 3.18.0

I know library B should be an INTERFACE library and shouldn't have the .hpp file put into the sources, but because the automoc generates a .cpp file library B becomes a normal library. It's only the precompiled header which breaks it.

In case this "automoc makes B a non-interface library" is too much abuse (which I could totally understand) there should probably be a way to catch this error earlier, because it took me quite some time to narrow this down. (although I don't know enough about CMakes internals to know how to catch that.)

To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information