AUTOUIC change in 3.8 breaks libs using multi-inheritance approach
In CMake 3.8.0 the behavior of AUTOUIC
changed:
When using AUTOMOC or AUTOUIC, generated moc_*, .moc and ui_ are placed in the <CMAKE_CURRENT_BINARY_DIR>/_autogen/include directory which is automatically added to the target’s INCLUDE_DIRECTORIES. It is therefore not necessary anymore to have CMAKE_CURRENT_BINARY_DIR in the target’s INCLUDE_DIRECTORIES.
This is a nice change, as projects no longer have to add ${CMAKE_CURRENT_BINARY_DIR}
to their include directories.
However, consider a widget library foo
that uses AUTOUIC
and that is following the multi-inheritance approach when using its generated Ui::
classes, for the convenience of not having to qualify UI element accesses with ui->
. The merits of doing so in a library can be discussed, since it exposes a lot of implementation through the public header, making it very hard to stay ABI stable. But remember that foo
might be an application internal library not meant for public consumption. In such uses, it's totally reasonable to use the multi-inheritance approach.
So for example, say that foo
has a header MyWidget.h
like
#include "ui_MyWidget.h"
class MyWidget : public QDialog, private Ui::MyWidget { ... }
It would then add ${CMAKE_CURRENT_BINARY_DIR}
as a PUBLIC
include directory with
target_include_directories(foo PUBLIC "${CMAKE_CURRENT_BINARY_DIR}")
It's added as PUBLIC
so that the users of foo
can include MyWidget.h
without getting errors about a missing ui_MyWidget.h
.
In 3.8.0, the generated ui_MyWidget.h
is instead put into ${CMAKE_CURRENT_BINARY_DIR}/foo_autogen/include
, which is automatically added to the include directories. It is not however added as PUBLIC
. This is reasonable, but means that users of foo
will now get errors about a missing ui_MyWidget.h
.
The only workarounds available to foo
are
-
Switch to the member-pointer approach instead, meaning possibly a lot of code have to be updated. With that approach, it's enough to include
ui_MyWidget.h
in the implementation file (MyWidget.cpp
) and the problem disappears. -
Manually re-add the
${CMAKE_CURRENT_BINARY_DIR}/foo_autogen/include
that CMake added automatically, in order to make it public:
target_include_directories(foo PUBLIC "${CMAKE_CURRENT_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/foo_autogen/include")
(The ${CMAKE_CURRENT_BINARY_DIR}
added as well, to stay compatible with CMake < 3.8.0).
Since both workarounds require changes to the code (in 1 possibly quite a lot), it would have been nice if this change was accompanied by a policy, so that one could choose to stick with the old behavior.