Package: qt6-base-dev
Version: 6.6.2+dfsg-8
Severity: important
Justification: build regression affecting multiple downstreams
User: debian-cr...@lists.debian.org
Usertags: ftcbfs
X-Debbugs-Cc: debian-cr...@lists.debian.org
Control: affects -1 + src:qt6-declarative

Hi,

qt6-declarative fails to cross build from source since around 6.6. The
last successful version was 6.4.2+dfsg-4 and the first known failing is
6.6.2+dfsg-3. Since then the failure is:

|    dh_install -a -O--buildsystem=cmake\+ninja
| dh_install: warning: Cannot find (any matches for) 
"usr/lib/arm-linux-gnueabihf/qt6/qml/QmlTime/qmltime.qmltypes" (tried in ., 
debian/tmp)
| 
| dh_install: warning: qml6-module-qmltime missing files: 
usr/lib/arm-linux-gnueabihf/qt6/qml/QmlTime/qmltime.qmltypes
| dh_install: error: missing files, aborting
| make: *** [debian/rules:17: binary-arch] Error 255
| dpkg-buildpackage: error: debian/rules binary-arch subprocess returned exit 
status 2

Now getting to the bottom of this is a lot like searching for a needle
in a haystack. I haven't found the needle, but I'm pretty confident in
discarding much of the haystack.

In diagnosing this, I very much relied on differential builds. I
instrumented the rules to add --trace-expand to the cmake invocation and
compared a native and cross build log. A native build generates the file
as:

| [4905/6992] cd /<<PKGBUILDDIR>>/obj-x86_64-linux-gnu/tools/qmltime && 
/<<PKGBUILDDIR>>/obj-x86_64-linux-gnu/lib/qt6/libexec/qmltyperegistrar 
--generate-qmltypes=/<<PKGBUILDDIR>>/obj-x86_64-linux-gnu/lib/x86_64-linux-gnu/qt6/qml/QmlTime/qmltime.qmltypes
 --import-name=QmlTime --major-version=1 --minor-version=0 
--follow-foreign-versioning 
@/<<PKGBUILDDIR>>/obj-x86_64-linux-gnu/tools/qmltime/qmltypes/qmltime_foreign_types.txt
 -o 
/<<PKGBUILDDIR>>/obj-x86_64-linux-gnu/tools/qmltime/qmltime_qmltyperegistrations.cpp
 
/<<PKGBUILDDIR>>/obj-x86_64-linux-gnu/tools/qmltime/meta_types/qt6qmltime_none_metatypes.json
 && /usr/bin/cmake -E make_directory 
/<<PKGBUILDDIR>>/obj-x86_64-linux-gnu/tools/qmltime/.qt/qmltypes && 
/usr/bin/cmake -E touch 
/<<PKGBUILDDIR>>/obj-x86_64-linux-gnu/tools/qmltime/.qt/qmltypes/qmltime.qmltypes

I could not find qmltime.qmltypes in the cross build log, which
initially led me to the wrong path as I was searching for things that
would inhibit building it. Eventually, I dug into the differences in the
--trace-expand output and noticed that the cross build log has a
qmltime_native.qmltypes and that actually gets installed. It just
happens to not be called qmltime.qmltypes and that makes dh_install
unhappy.

So where does this "_native" suffix come from? It originates in
/usr/lib/$DEB_HOST_MULTIARCH/cmake/Qt6/QtToolHelpers.cmake:

| # Sets QT_WILL_BUILD_TOOLS if tools will be built and 
QT_WILL_RENAME_TOOL_TARGETS
| # if those tools have replaced naming.
| function(qt_check_if_tools_will_be_built)
|     # By default, we build our own tools unless we're cross-building.
|     set(need_target_rename FALSE)
|     if(CMAKE_CROSSCOMPILING)
|         set(will_build_tools FALSE)
|         if(QT_FORCE_BUILD_TOOLS)
|             set(will_build_tools TRUE)
|             set(need_target_rename TRUE)
|         endif()
|     else()
|         set(will_build_tools TRUE)
|         if(QT_FORCE_FIND_TOOLS)
|             set(will_build_tools FALSE)
|             if(QT_FORCE_BUILD_TOOLS)
|                 set(will_build_tools TRUE)
|                 set(need_target_rename TRUE)
|             endif()
|         endif()
|     endif()
| 
|     set(QT_WILL_BUILD_TOOLS ${will_build_tools} CACHE INTERNAL "Are tools 
going to be built" FORCE)
|     set(QT_WILL_RENAME_TOOL_TARGETS ${need_target_rename} CACHE INTERNAL
|         "Do tool targets need to be renamed" FORCE)
| endfunction()

and

| # Returns the tool name for a given tool target.
| # This is the inverse of qt_get_tool_target_name.
| function(qt_tool_target_to_name out_var target)
|     set(name ${target})
|     if (QT_WILL_RENAME_TOOL_TARGETS)
|         string(REGEX REPLACE "_native$" "" name ${target})
|     endif()
|     set(${out_var} ${name} PARENT_SCOPE)
| endfunction()

In essence, this is a cross/native difference. When cross compiling, we
may decide whether we need to build tools skip them and merely use the
native ones. When we do build them, they get renamed. (Why?) In a native
build, we can opt to use installed tools by setting QT_FORCE_FIND_TOOLS
and then if we still want to build them, they also get renamed.

For cross compilation, we're between a rock and a hard place. Either we
set QT_FORCE_BUILD_TOOLS (and this seems to be implied by
QT_BUILD_TOOLS_WHEN_CROSSCOMPILING, which we already set in d/rules) and
then we end up with the _native suffix or we don't set it and then we
end up without those tools. In neither case will the build system
install them into the desired place. Bummer.

I also find the "_native" naming strange. In the Debian world, we tend
to use "native" in a similar meaning as "build" (i.e. the architecture
we are using to perform the build), but those "*_native" things actually
do get compiled with a host architecture compiler. In most other
contexts, I would expect the "host" objects to keep their name and
perform the renaming on the "build" (or "native") objects. Could it be
that this is a bug in qt6-base-dev? I mean the code still is fairly
fresh and only broke relatively recently.

The last successful build used qt6-base 6.4.2+dfsg-21.1+b1 and the first
failing build used 6.6.2+dfsg-8.

Digging into the history,
https://github.com/qt/qtbase/commit/acfbe3b7795c741b269fc23ed2c51c5937cd7f4f
looks very suspicious to me. Could it be that it is the one that breaks
it? The underlying bug report is
https://bugreports.qt.io/browse/QTBUG-99683.

In any case, we should likely replace QT_BUILD_TOOLS_WHEN_CROSSCOMPILING
with QT_FORCE_BUILD_TOOLS in most qt6 packages. You can find the
affected ones:
https://codesearch.debian.net/search?q=QT_BUILD_TOOLS_WHEN_CROSSCOMPILING+path%3Adebian%2Frules&literal=1

Can someone from the Qt team handle this replacement? I mean like
committing it to git now without a need to upload this change right now.
Would you prefer me filing separate bugs for qt6-wayland, qt6-quick3d,
qt6-scxml, qt6-shadertools and qt6-remoteobjects?

Is anyone able to take this to Qt upstream?

Helmut

Reply via email to