text: December 2020 saw the launch of Qt 6 – the first new major version since 2012. I wanted to find out how fit Qt 6.0 is for Qt embedded systems. I took the driver terminal of the ROPA sugar beet harvesters and migrated it from Qt 5.12 to Qt 6.0 as a side project. The migration was smooth, but incomplete. The driver terminal uses the Qt modules Multimedia and SerialBus, which haven’t been ported to Qt 6 yet. An update of the driver terminal would have to wait at least until the end of 2021, when Qt 6.2 will finally be feature-complete.
  Introduction
  The migration to Qt 6 is my 5th Qt migration. The migrations from Qt 1 to Qt 2, from Qt 2 to Qt 3 and from Qt 4 to Qt 5 were fairly smooth. The migration of an IDE for formal verification and of the driver terminal of a forage harvester were a matter of 2-3 days. The migration from Qt 3 to Qt 4 was extremely painful. Migrating an IDE for Bluetooth development took me 6 months.
  I was curious how long I would need to migrate the driver terminal of a sugar beet harvester from Qt 5.12 to Qt 6.0. The driver terminal has 350 source files (.cpp, .h, .qml) with 50K lines of hand-written code. It also has 45 source files with 74K lines of generated code for the terminal-machine communication.
  The guide Porting to Qt 6 from the official Qt documentation is the starting point for the migration. It suggests to port the application to Qt 5.15 in a first step and to Qt 6.0 in a second step. The Qt developers made the APIs of Qt 5.15 as similar as possible to the APIs of Qt 6.0 to reduce the migration efforts.
  I’ll describe step by step how to change the CMake files, how to fix the warnings and errors flagged by the C++ compiler, how to find the QML incompatibilities and how to set up the development environment for Qt 6.0.
  Migrating from Qt 5.12 to Qt 5.15
  The harvester application runs with Qt 5.12. We install Qt 5.15.2 and QtCreator 4.13 on our development PC. The PC should run Ubuntu 16.04 or newer.
  C++ Compiler Warnings and Errors
  The harvester application consists of three CMake projects: the executable
  Main, the library
  Hmi and the library
  Can. We switch on the deprecation warnings by adding the line
  target_compile_definitions(${PROJECT_NAME} PUBLIC "QT_DISABLE_DEPRECATED_BEFORE=0x050F00")
  to the
  CMakeLists.txt of each project. This macro triggers a warning for every function that is deprecated in Qt 5.15 or older. Sometimes the use of a deprecated function causes an error. The next subsections list the C++ compiler warnings and errors I encountered while migrating the harvester application from Qt 5.12 to Qt 5.15.
  The documentation page Obsolete Classes lists all the classes that may be removed in future releases and all the classes with functions that may be removed in future releases. The documentation often gives a hint how to replace an obsolete class or function.
  Error/Warning: ‘endl’ is deprecated: Use Qt::endl
  Problem:
  QTextStream os(&dbFile); os << QStringLiteral("[access]") << endl;
  Most occurrences of
  endl triggered the warning:
  'endl' is deprecated: Use Qt::endl. Some occurrences triggered an error:
  ‘endl’ was not declared in this scope. The compiler couldn’t distinguish between
  std::endl and
  Qt::endl.
  Fix:
  QTextStream os(&dbFile);os << QStringLiteral("[access]") << Qt::endl;
  We replace each occurrence of
  endl by
  Qt::endl. All stream manipulators are now prefixed with the Qt namespace: for example,
  Qt::hex,
  Qt::fixed,
  Qt::left and
  Qt::ws.
  Error: ‘longMonthName’ is not a member of ‘QDate’
  Problem:
  return QDate::longMonthName(i, QDate::StandaloneFormat);
  The static function
  QDate::longMonthName was removed from
  QDate.
  Fix:
  return QLocale().monthName(i);
  The documentation of
  QDate::longMonthName hints at
  QLocale for a replacement.
  QLocale::monthName returns the long month name by default.
  Error: no matching function for call to ‘QProcess::execute(const char [10])’
  Problem:
  QProcess::execute("/bin/sync");
  The variant of
  QProcess::execute with the command as its only argument was removed.
  Fix:
  QProcess::execute("/bin/sync", {});
  We must always use the two-argument variant, where the second argument is a
  QStringList with the options and arguments of the command. As
  sync doesn’t have any arguments or options, the second argument is the empty list.
  Error: ‘mapped’ is not a member of ‘QSignalMapper’
  Problem:
  using MappedSignal = void(QSignalMapper::*)(int); connect(&m_impl->m_signalMapper, static_cast<MappedSignal>(&QSignalMapper::mapped), m_impl.data(), &DriverModel::Impl::onDriverChanged);
  Before Qt 5.15,
  QSignalMapper::mapped had an overload for each of the four types of the single argument:
  QObject*,
  QWidget*,
  const QString& and
  int. We had to tell the compiler with a
  static_cast which overload to use in the connect statements. The overloads are obsolete in Qt 5.15.
  Fix:
  connect(&m_impl->m_signalMapper, &QSignalMapper::mappedInt, m_impl.data(), &DriverModel::Impl::onDriverChanged);
  From Qt 5.15, the four overloads have different names
  mappedInt,
  mappedObject,
  mappedString and
  mappedWidget. This eliminates the cast and makes the code simpler.
  Error: no member named ‘insertMulti’ in ‘QMap >’
  Problem:
  QMap<int, std::function<void()>> importCalls; importCalls.insertMulti(0, [this, path]( {m_customerModel.importCsvFile(path);});
  Before Qt 5.15,
  QMap distinguished between maps and multi-maps by
  insert and
  insertMulti.
  Fix:
  QMultiMap<int, std::function<void()>> importCalls; importCalls.insert(0, [this, path]( {m_customerModel.importCsvFile(path);});
  Qt 5.15 introduces a new class
  QMultiMap, which inherits from
  QMap. We insert elements into a
  QMultiMap with
  insert now.
  Error/Warning: ‘QString::SplitBehavior’ has not been declared
  Problem:
  auto nameParts = customer->name() .split(' ', QString::SkipEmptyParts);
  Like many other enum constants,
  QString::SkipEmptyParts was moved into the namespace
  Qt. The problem often occurs as a warning:
  ‘... QString::split ...’ is deprecated: Use Qt::SplitBehavior variant instead [-Wdeprecated-declarations]
  Fix:
  auto nameParts = customer->name() .split(' ', Qt::SkipEmptyParts);
  The warning tells us what to do. We replace
  QString::SplitBehavior by
  Qt::SplitBehavior.
  Error: call of overloaded ‘append()’ is ambiguous
  Problem:
  QVector<QPair<QString, QString>> m_counterCats; m_counterCats.append({"Gesamt", ""});
  QVector<T>::append has gained a third overload for rvalue references
  T&& in addition to the existing
  const T& and
  const QVector<T>&. The C++17 compiler cannot distinguish between these three overloads.
  Fix:
  QVector<QPair<QString, QString>> m_counterCats; m_counterCats.append(QPair<QString, QString>{"Gesamt", ""});
  We must help the C++17 compiler by spelling out the type of the appended element.
  QML Runtime Errors
  Unfortunately, we don’t have a friendly compiler telling us which lines of our QML code are deprecated. The documentation page Obsolete QML Types lists the known obsolete types, properties and methods. It’s worth going through these lists and checking our QML code for problems. I didn’t find any problems in the harvester QML code.
  Before we test the most common usage scenarios (hopefully in an automated way), we update the versions in the
  import statements. I had to perform the following replacements in the QML files.
  Qt 5.12 -> Qt 5.15 import QtQuick 2.10 -> import QtQuick 2.15 import QtQuick.Controls 2.3 -> import QtQuick.Controls 2.15 import QtMultimedia 5.8 -> import QtMultimedia 5.15
  In my case, testing the most common usage scenarios unearthed a single problem about signal handlers or slots in
  Connections types.
  Warning: QML Connections: Implicitly defined onFoo properties in Connections are deprecated
  Problem:
  Connections { target: csvExportModel onMessageOccurred: messagePane.text = message }
  The signal handler
  onMessageOccurred is implicitly defined as a function.
  Fix:
  Connections { target: csvExportModel function onMessageOccurred(message) { messagePane.text = message } }
  We must define
  onMessageOccurred as a function explicitly with an argument list.
  Migrating from Qt 5.15 to Qt 6.0
  I installed QtCreator 4.14, as it is the first release that fully supports Qt 6. QtCreator 4.14 adds proper syntax highlighting for Qt 6 code and some improvements for CMake. My development PC ran Ubuntu 18.04.
  When I installed Qt 6.0 with the online installer, I encountered this error:
  My Internet search lead me to QTBUG-89218. The comment section reveals that Ubuntu 18.04 is not a supported development platform any more. We have two options. We can upgrade to Ubuntu 20.04 or newer or we can build Qt 6.0 from sources. If our application uses one of the Qt modules not yet ported to Qt 6 (e.g., QtSerialBus, QtMultimedia, QtWebEngine), we will have to build Qt 6.0 from sources any way and port the missing module to Qt 6.0. I ended up doing both.
  Building with CMake
  Updating CMakeLists.txt Files
  The
  CMakeLists.txt files refer to Qt 5 explicitly in
  find_package and
  target_link_libraries commands.
  find_package(Qt5 COMPONENTS Core Gui Qml REQUIRED) target_link_libraries(${PROJECT_NAME} Ag::Can Ag::Hmi Qt5::Core Qt5::Gui Qt5::Qml )
  We must change Qt 5 to Qt 6.
  find_package(Qt6 COMPONENTS Core Gui Qml REQUIRED) target_link_libraries(${PROJECT_NAME} Ag::Can Ag::Hmi Qt6::Core Qt6::Gui Qt6::Qml )
  Qt5 was built on C++11. The top-level
  CMakeLists.txt file contained the following lines.
  set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON)
  Qt6 requires C++17. We must change the top-level
  CMakeLists.txt file accordingly.
  set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON)
  Setting Up the QtCreator Kit
  When I started QtCreator 4.14 the first time after installing Qt 6.0, the auto-detected kit for Qt 6.0.0 was messed up. It referred to outdated C and C++ compilers from a Qt 5.14 installation and the system CMake 3.16 from Ubuntu 20.04. We can fix this mess in the QtCreator dialog Tools | Options | Kits.
  - We clone the auto-detected read-only kit for Qt 6.0.0.
  - We define
  /usr/bin/gccand
  /usr/bin/g++from Ubuntu 20.04 as the new C and C++ Compilers. Both compilers are version 9.3. GCC9 supports C++17. If we must work with different compiler versions, we set the Compilers to
  /usr/bin/gcc-9and
  /usr/bin/g++-9.
  - We define the CMake coming with Qt6 –
  /path/to/Qt6.0.0/Tools/CMake/bin/cmake(version 3.19) – as the CMake Tool of the kit. Qt 6 requires at least CMake 3.18.
  - The CMake generator is Ninja and the extra generator is <none>.
  When we run CMake to configure the project, the CMake command should look similar to this:
  /path/to/Qt6.0.0/Tools/CMake/bin/cmake -S /private/Projects/Ag/terminal -B /tmp/QtCreator-UDwQep/qtc-cmake-sOofIBPC -GNinja -DCMAKE_BUILD_TYPE:String=Debug -DQT_QMAKE_EXECUTABLE:STRING=/path/to/Qt6.0.0/6.0.0/gcc_64/bin/qmake -DCMAKE_PREFIX_PATH:STRING=/path/to/Qt/Qt6.0.0/6.0.0/gcc_64 -DCMAKE_C_COMPILER:STRING=/usr/bin/gcc-9 -DCMAKE_CXX_COMPILER:STRING=/usr/bin/g++-9
  We can force a re-configuration of the project by removing the build directory recursively and by running Build | Run CMake.
  Core5Compat Library
  The Core5Compat library adds the obsolete Qt 5 classes and functions that didn’t make it into Qt 6. We can add
  Core5Compat to the
  find_package commands and
  Qt6::Core5Compat to the
  target_link_libraries commands. If we do, the compiler will flag occurrences of
  QRegExp,
  QTextCodec and some other classes from
  Qt6::Core as warnings instead of errors (see this post for a mapping between obsolete Qt 5 classes and their Qt 6 replacements).
  Core5Compat makes the transition from Qt 5 to Qt 6 smoother. We must fix fewer errors before our application builds and runs again. I didn’t use Core5Compat, because I learned about it too late. I could fix the resulting errors in a mechanical way like replacing
  QRegExp functions by their counterparts in
  QRegularExpression. I spent a lot more time on adapting some C++11 code to the higher standards of the C++17 compiler and on porting
  QtSerialBus in a quick-and-dirty way to Qt 6.
  C++ Compiler Errors and Warnings
  Many Qt 5 Modules Still Missing in Qt 6
  Qt 5 modules like Multimedia, SerialBus, SerialPort, RemoteObjects, Virtual Keyboard, Charts, Bluetooth, WebEngine and WebView didn’t make it into Qt 6 (see this post for a complete list). Few will become available in Qt 6.1 (planned for April 2021) and the rest in Qt 6.2 (planned for September 2021).
  If an application depends on one of these modules, we cannot release this application in a product before the end of 2021. The harvester application depends on Multimedia and SerialBus. I used two different approaches to compile the application.
  The application uses Multimedia to show two video streams in the upper and lower half of a full-screen widget. I avoided porting Multimedia to Qt 6 by commenting out the few lines referring to Multimedia.
  The application uses SerialBus for the CAN communication with the harvester. Commenting out the CAN communication would have caused a significant rewriting of the application code. So, I opted for porting the CanBus submodule of SerialBus from Qt 5 to Qt 6.
  We first build Qt 6.0.0 from Git. Then, we build SerialBus in an extra step. We download the sources of SerialBus with the command (executed in the top-level directory of the source tree):
  perl init-repository -f --module-subset=qtserialbus
  SerialBus is still built with QMake. From the top-level build directory, we call
  $ /path/to/Qt6.0.0/bin/qmake /path/to/qt5/qtserialbus/qtserialbus.pro $ make
  As the harvester application doesn’t use ModBus, we can eliminate all the errors and warnings about ModBus by removing the ModBus source and header files from
  qt5/qtserialbus/src/serialbus/serialbus.pro. Porting SerialBus to Qt 6 involved replacing several occurrences of
  QString::midRef and
  QString::leftReft by
  QString::mid and
  QString::left, respectively.
  The
  Can library of the harvester application depends on
  SerialBus. We must provide CMake configurations files for SerialBus itself (
  Qt6SerialBusConfig.cmake) and for each CAN plugin (e.g.,
  Qt6SerialBus_SocketCanBusPlugin.cmake). These files are located in
  /path/to/Qt6.0.0/lib/cmake/Qt6SerialBus. I took the quick-and-dirty route and replaced every occurrence of 5, 5.15 and 5.15.2 by 6, 6.0 and 6.0.0, respectively – until running CMake on the application succeeded.
  Error: no match for ‘operator<’ (operand types are ‘const QVariant’ and ‘const QVariant’)
  Problem:
  QMap<std::pair<QString, QVariant>, QObject *> m_entities; m_impl->m_entities.insert(it.key(), it.value());
  The function
  it.key() returns an object of type
  std::pair<QString, QVariant>, which is the same as the key type of the
  QMap. QMap requires the definition of
  operator< on the key type to know where to insert new values.
  QMap compares whether the pair
  p1 is less than
  p2, where both
  p1 and
  p2 have the type
  std::pair<QString, QVariant>. If
  p1.first is equal to
  p2.first, the comparison must evaluate
  p1.second < p2.second. G++-9 rightly complains that
  operator< is not defined for
  QVariants. G++-7 overlooked the missing
  operator< for
  QVariants.
  Fix:
  QMap<std::pair<QString, QString>, QObject *> m_entities; m_impl->m_entities.insert(it.key(), it.value());
  Converting a
  QVariant into a
  QString with
  QVariant::toString() works for most types supported by
  QVariant. As
  m_entities only uses supported types for the second element of its key, we can safely replace
  QVariant by
  QString in the key type.
  Error: QTextCodec: No such file or directory
  Problem:
  #include <QTextCodec> ... QTextStream is{&csvFile}; is.setCodec(QTextCodec::codecForName("ISO-8859-1"));
  The class
  QTextCodec was removed from Qt 6 and was replaced by the new class
  QStringConverter. Similarly, the classes
  QTextEncoder and
  QTextDecoder were replaced by
  QStringEncoder and
  QStringDecoder (see this post). Code using any of the old classes doesn’t compile.
  Fix:
  #include <QStringConverter> ... QTextStream is{&csvFile}; is.setEncoding(QStringConverter::Latin1);
  We include the header of the replacement class
  QStringConverter. A search through the functions of
  QStringConverter makes
  setEncoding the most likely replacement for
  setCodec. Understanding that ISO-8859-1 is the formal name for Latin1 helps us call
  setEncoding with the right constant
  QStringConverter::Latin1.
  Error: QRegExp: No such file or directory
  Problem:
  #include <QRegExp> // In anonymous namespace QRegExp &rxHexFilename() { static QRegExp rx("_(A\\d\\d)_V_(\\d\\d)_(\\d\\d)\\.hex$"); return rx; } // In constructor auto pos = rxHexFilename().indexIn(fileName); auto ecuName = rxHexFilename().cap(1); if (pos == -1 || ...) { return; } m_version = QString("v%1.%2") .arg(rxHexFilename().cap(2).toUInt()) .arg(rxHexFilename().cap(3).toUInt()); m_ecuType = fileName.left(fileName.size() - rxHexFilename().matchedLength());
  Replacing
  QRegExp – a relic of Qt 4 – by
  QRegularExpression has been in the making since Qt 5.0.
  QRegularExpression is the only way to work with regular expressions in Qt 6. The interface has changed considerably.
  Fix:
  #include <QRegularExpression> // In anonymous namespace const QRegularExpression rxHexFilename("_(A\\d\\d)_V_(\\d\\d)_(\\d\\d)\\.hex$"); // In constructor auto match = rxHexFilename.match(fileName); auto ecuName = match.captured(1); if (!match.hasMatch() || ...) { return; } m_version = QString("v%1.%2") .arg(match.captured(2).toUInt()) .arg(match.captured(3).toUInt()); m_ecuType = fileName.left(fileName.size() - match.capturedLength(0));
  The function for matching a string against a regular expression has got its natural name:
  match (instead of
  indexIn). It returns a
  QRegularExpressionMatch object
  match instead of an index. We retrieve the
  nth captured substring by calling
  match.captured(nth). match.hasMatch() tells us whether the string matched the regular expression.
  QRegExp::matchedLength returns the length of the substring matching the complete regular expression. This substring is the same as the 0th captured substring
  match.captured(0), which has the length
  match.capturedLength(0).
  Error: ‘class QString’ has no member named ‘midRef’
  Problem:
  subDev = m_deviceName.midRef(splitPos + 1).toLatin1();
  The function
  QString::midRef is obsolete in Qt 6. The same goes for the function
  QString::leftRef.
  Fix:
  subDev = m_deviceName.mid(splitPos + 1).toLatin1();
  We replace
  QString::midRef and
  QString::leftRef by
  QString::mid and
  QString::left, respectively.
  Error: cannot convert ‘QString’ to ‘const QFileInfo&’
  Problem:
  QString extractVersion(const QFileInfo &info) const; QString fileName(...); auto version = extractVersion(fileName);
  In Qt 5, the function
  extractVersion implicitly converts the
  QString
  filename into a
  QFileInfo object with the constructor
  QFileInfo(const QString &). In Qt 6, this constructor is marked
  explicit, which blocks the implicit conversion.
  Fix:
  QString extractVersion(const QFileInfo &info) const; QString fileName(...); auto version = extractVersion(
  QFileInfo(fileName));
  We get rid of the error by calling the constructor
  QFileInfo(const QString &) explicitly.
  Error: invalid application of ‘sizeof’ to incomplete type ‘IntegerRangeModel’
  Problem:
  class IntegerRangeModel; class DateTimeModel : public QObject { Q_OBJECT Q_PROPERTY(IntegerRangeModel* days READ days CONSTANT)
  The forward declaration of
  IntegerRangeModel was good enough for the
  Q_PROPERTY definition in Qt 5, because
  days is declared as a pointer. Qt 6 added a static assertion. A further error message documents the violation of the static assertion:
  static_assert(sizeof(T), "Type argument of Q_PROPERTY or Q_DECLARE_METATYPE(T*) must be fully defined");
  Fix:
  #include "IntegerRangeModel.h"; class DateTimeModel : public QObject { Q_OBJECT Q_PROPERTY(IntegerRangeModel* days READ days CONSTANT)
  We eliminate the error message by including the header file for
  IntegerRangeModel instead of forward declaring
  IntegerRangeModel.
  Warning: ‘Type’ is deprecated: Use QMetaType::Type instead. [-Wdeprecated-declarations]
  Problem:
  EntityColumn(const QString &name, QVariant::Type type, ...)
  The enumeration
  QVariant::Type lists the types that can be stored in a
  QVariant. It is roughly a subset of the enumeration
  QMetaType::Type, which lists the types that are known to Qt’s meta object system. Replacing
  QVariant::Type by
  QMetaType::Type suggested itself.
  QVariant::Type is not contained in Qt 6 any more.
  Fix:
  EntityColumn(const QString &name, QMetaType::Type type, ...)
  In Qt 6, we use
  QMetaType::Type instead of
  QVariant::Type. We must also replace obsolete enum constants like
  QVariant::Invalid,
  QVariant::UInt and
  QVariant::Bool by
  QMetaType::UnknownType,
  QMetaType::UInt and
  QMetaType::Bool, respectively.
  Error: cannot convert ‘QVariant::Type’ to ‘QMetaType::Type’
  Problem:
  bool typesAreAffine(QMetaType::Type sqlType, ...) const; QSqlField tableColumn = ...; if (!typesAreAffine(tableColumn.type(), ...)) ...
  Originally, the first argument of
  typesAreAffine had the type
  QVariant::Type, which was replaced by
  QMetaType::Type by the previous migration step. The function
  QSqlField::type with the return type
  QVariant::Type doesn’t exist in Qt 6.
  Fix:
  bool typesAreAffine(QMetaType::Type sqlType, ...) const; QSqlField tableColumn = ...; if (!typesAreAffine(QMetaType::Type(tableColumn.metaType().id()), ...)) ...
  We substitute the Qt 6 function
  QSqlField::metaType() for the now obsolete Qt 5 function
  QSqlField::type().
  QSqlField::metaType() returns a
  QMetaType object. We retrieve the type ID of the
  QMetaType object with
  id(), which returns an
  int instead of a
  QMetaType::Type to be open for custom meta types.
  QMetaType::Type(typeID) creates a enum constant from the integer
  typeID.
  Error: warning: conversion from ‘qsizetype’ {aka ‘long long int’} to ‘int’ may change value [-Wconversion]
  Problem:
  QList<QFileInfo> m_dirEntries. int DirectoryModel::rowCount(const QModelIndex &parent) const { Q_UNUSED(parent) return m_impl->m_dirEntries.size(); }
  Starting with Qt 6.0,
  QList<T>::size() has the return type
  qsizetype, which is equivalent to
  long long int. The class DirectoryModel indirectly derives from
  QAbstractItemModel, which declares the pure virtual function
  rowCount like this:
  virtual int rowCount(const QModelIndex &parent = QModelIndex()) const = 0
  The
  return statement may narrow a
  long long int value to an
  int value, which may change the value. It seems that the Qt developers forgot to change the return type of
  rowCount from
  int to
  qsizetype.
  Functions like
  beginInsertRows,
  beginRemoveRows,
  beginMoveRows and
  beginInsertColumns also take
  int-type arguments. We may have to watch out for narrowing conversions as well.
  Fix:
  QList<QFileInfo> m_dirEntries. int DirectoryModel::rowCount(const QModelIndex &parent) const { Q_UNUSED(parent) return static_cast<int>(m_impl->m_dirEntries.size()); }
  Sometimes there is no way around a static cast. This is one of those times. We force the
  qsizetype value into an int
  value and silence the error.
  Warning: conversion from ‘size_t’ {aka ‘long unsigned int’} to ‘uint’ {aka ‘unsigned int’} may change value [-Wconversion]
  Problem:
  enum class UnitId : quint16 { ... } inline uint qHash(UnitId unit) { return qHash(static_cast<quint16>(unit)); }
  qHash functions return
  uint values in Qt 5, where
  uint is
  unsigned int. In Qt 6, they return
  size_t values, where
  size_t is
  long unsigned int. The
  qHash function in the
  return statement is a built-in hash function. It returns a
  long unsigned int value, which may be narrowed to a an
  unsigned int value by the custom-defined hash function. As this may change the value, the compiler emits a warning.
  Fix:
  enum class UnitId : quint16 { ... } inline size_t qHash(UnitId unit) { return qHash(static_cast<quint16>(unit)); }
  We change the return type of the custom-defined hash function from
  uint to
  size_t.
  Warning: ‘static QQmlFileSelector* QQmlFileSelector::get(QQmlEngine*)’ is deprecated [-Wdeprecated-declarations]
  Problem:
  auto fs = QQmlFileSelector::get(engine); fs->setExtraSelectors({"left"});
  The static function
  QQmlFileSelector::get returns the file selector currently active on the QML
  engine. It is obsolete in Qt 6, because it duplicates the functionality provided by the
  QQmlFileSelector constructor.
  Fix:
  auto fs = new QQmlFileSelector(engine); fs->setExtraSelectors({"left"});
  Creating a
  QQmlFileSelector object on the heap does the same as calling
  QQmlFileSelector::get. We must create the object on the heap, because the constructor argument
  engine takes ownership of the file selector.
  Error: using typedef-name ‘using QStringList = class QList<QString>’ after ‘class’
  Problem:
  class QStringList;
  An included Qt header file introduces the type definition
  using QStringList = class QList<QString>. The problematic line forward declares this type definition, which the compiler doesn’t like.
  Fix:
  #include <QStringList>
  We replace the forward declaration by the inclusion of the header file.
  Error: ‘QLatin1Literal’ was not declared in this scope; did you mean ‘QStringLiteral’?
  Problem:
  QStringList errors; Q_ASSERT_X(false, __PRETTY_FUNCTION__, errors.join(QLatin1Literal("; ")).toUtf8());
  QLatin1Literal doesn’t exist in Qt 6 any more.
  Fix:
  QStringList errors; Q_ASSERT_X(false, __PRETTY_FUNCTION__, errors.join(QLatin1String("; ")).toUtf8());
  We replace
  QLatin1Literal by
  QLatin1String.
  Conclusion
  Good news first: Migrating the driver terminal with 50K lines of hand-written code and another 74K lines of generated code from Qt 5.12 to Qt 6.0 was a very smooth affair. It took me 1.5 days. Writing this post took me longer.
  Now for the bad news: The driver terminal cannot be released with Qt 6 before the end of 2021. Qt Modules like MultiMedia, SerialBus, RemoteObjects, Charts and WebEngine didn’t make it into Qt 6.0. When I look back at my last 15 years of architecting and building Qt embedded systems, I couldn’t have built a single one with Qt 6.0.
  Qt 6 is a technology preview and will stay so until Qt 6.2. Qt 6.2 will be the first feature-complete Qt 6 release. It is planned for the autumn of 2021.