Skip to content

Developers

Dmitriy Kuminov edited this page Nov 22, 2022 · 19 revisions

This section contains information related to developing Qt on OS/2.

Repository Structure

The original Qt source code is hosted in a number of git repositories with URLs like git://code.qt.io/qt/PROJECT.git where PROJECT is one of numerous Qt modules (qt5, qtbase etc). The web interface for these repositories is available at http://code.qt.io/cgit/qt/.

While it was technically possible to mirror these git repositories (via upstream remotes) in our own repositories at GitHub and perform OS/2 development on dedicated branches, we decided not to do so. Mostly because the original Qt history is huge and the Qt team generates too many new commits every day. Having it all in our repositories would drag too much attention from the OS/2 development and occupy additional hard disk space for nothing. Instead, we will create a clean repository for each Qt module that we decide to work on and use a method of "squashing" all intermediate commits between import points into a new one which is then pushed to our repository on a special branch named vendor. Import points are usually official Qt releases (originally tagged as vX.Y.Z where X.Y.Z is the released Qt version number).

The vendor branch then becomes a starting point and a future merge source for the master branch where all OS/2 development takes place. Once a new Qt release is imported into vendor (as a single "squashed" commit tagged as vX.Y.Z for convenience), it is then merged to master once we decide to move all our OS/2 work to a new version and start working on it. This scheme is flexible enough and also allows to support the development (maintenance) of several OS/2 versions of Qt independently by creating branches from master which are to be named X.Y[.Z] according to their start point.

Once a new OS/2 release of Qt is out, it is tagged as vX.Y.Z-os2[-NNN] where X.Y.Z is the Qt version number this release is based on. The optional NNN part names an OS/2-specific release of a given Qt version. There may be multiple OS/2 releases of the same Qt version because we try to provide new OS/2 releases as soon as we can and don't wait until all features of a particular Qt version are implemented on OS/2. For this reason, our release cycle will most likely not match the Qt release cycle. For beta releases, NNN is usually bN where N is a sequential number of a beta release.

Adding a new OS/2 repository for a Qt module

Let's assume the Qt module name is PROJECT and the starting point for the OS/2 work is vX.Y.Z. The main trick here is to use git reset to squash all commits into one (we cannot use git merge --squash here as it won't work for empty repositories without any commits). Note that we could also unpack the original tarball here and add everything to our repository with git add ., but this is not as good as git reset (or as git merge --sauash if we could do it) because some information is lost when creating tarballs out of git repositories. For example, we would lose original commits recoded for git submodules (if there are any) as well as all files marked with a git-ignore attribute in .gitattributes (there might be a plenty). Using git reset ensures all this information is preserved in our squashed commit.

  1. Create an empty repository at GitHub named PROJECT-os2 and clone it locally
  2. Link it to the Qt repository: git remote add upstream git://code.qt.io/qt/PROJECT.git
  3. List original tags matching vX.Y.Z: git ls-remote --tags upstream | grep vX.Y.Z
  4. Inspect the output and record the original commit NNNN matching vX.Y.Z
  5. Fetch upstream commits up to and including NNNN w/o tags (to avoid name clashes): git fetch upstream --depth=1 --no-tags NNNN (note that NNNN must be a full hex commit name)
  6. Check out commit NNNN to the index and working tree (will also change HEAD): git reset --hard NNNN
  7. Drop HEAD to make the repository empty again (w/o commits): git update-ref -d HEAD
  8. Create the initial commit: git commit
  9. Use the following commit message (replace X.Y.Z, PROJECT and NNNN with real values):
vendor: Import vX.Y.Z.

Source URL:    git://code.qt.io/qt/PROJECT.git
Source Commit: NNNN
  1. Tag the result: git tag vX.Y.Z
  2. Push it to GitHub: git push && git push --tags
  3. Create a vendor branch: git branch vendor
  4. Push it to GitHub: git push -u origin vendor

Importing a new version of a Qt module to an OS/2 repository

This is similar to adding a new repository but there are a few differences. Note that we cannot use git merge --squash here as well, because it can only squash from the beginning of the history while we need the previous import as a starting point. Therefore we have to use the git reset trick again. Let's assume that you have our GitHub repository PROJECT-os2 already checked out and upstream that points to the original PROJECT repository is already set up.

  1. Switch to the vendor branch: git checkout vendor && git pull
  2. List original tags matching vX.Y.Z: git ls-remote --tags upstream | grep vX.Y.Z
  3. Inspect the output and record the original commit NNNN matching vX.Y.Z
  4. Fetch upstream commits up to and including NNNN w/o tags (to avoid name clashes): git fetch upstream --depth=1 --no-tags NNNN (note that NNNN must be a full hex commit name)
  5. Check out commit NNNN to the index and working tree (will also change HEAD): git reset --hard NNNN
  6. Reset HEAD back to what it was before (to restore our history): git reset --soft ORIG_HEAD
  7. Commit the result: git commit
  8. Use the following commit message (replace X.Y.Z, PROJECT and NNNN with real values):
vendor: Import vX.Y.Z.

Source URL:    git://code.qt.io/qt/PROJECT.git
Source Commit: NNNN
  1. Tag the result: git tag vX.Y.Z
  2. Push it to GitHub: git push && git push --tags
  3. Switch back to master (if needed): git checkout master

If you also want to merge the new upstream version to the master branch, then also do the following (assumes the master branch):

  1. Pull the latest master changes: git pull
  2. Create a branch for the previous version (for hot fixes & back-ports): git branch X'.Y'.Z'
  3. Merge everything since last time it was done: git merge vendor --no-commit
  4. Fix conflicts (if any) and commit the result: git commit
  5. Use the following commit message (replace X.Y.Z with real values):
Merge vendor vX.Y.Z.

Conflicts resolved:
    ....
    (conflicting file listing from the standard merge message, if any)
  1. Push it to GitHub: git push
  2. Push the previous version's branch to GitHub: git push -u origin X'.Y'.Z'

Building Qt

The original instructions for building Qt 5 from the Git repository are located here. They are, for the most part, applicable to OS/2 as well so read them first. Below is a typical list of steps that takes OS/2 specifics into account.

  1. Install mandatory packages:
    yum install dash-sh gcc gcc-wlink gcc-wrc make perl git gawk libc-devel libcx-devel
  2. Install packages necessary to auto-enable common Qt features:
    yum install zlib-devel libicu-devel libjpeg-devel libpng-devel freetype-devel fontconfig-devel openssl-devel cups-devel sqlite-devel
  3. Clone the repository: git clone https://github.com/bitwiseworks/qt5-os2.git qt5
  4. Go to the cloned directory: cd qt5
  5. Initialize the submodules: sh init-repository-os2.sh [--branch]
    The --branch option is only necessary if you are a developer who intends to push submodule commits to their respective branches from .gitmodules.
  6. Create a shadow build directory:
    cd ..; mkdir qt5-dev-build; cd qt5-dev-build
  7. Configure the build (from the shadow build directory):
    sh ../qt5/configure -developer-build -opensource -confirm-license -force-debug-info -nomake examples -nomake tests -no-opengl -system-sqlite -openssl-linked
    The -developer-build option will enable the debug build by default and will generate more debug data. The two -nomake options will save some time by not building examples and tests. The -sqlite option is needed to enable using system-provided SQLite3 DLLs. The -no-opengl option disables the OpenGL support and is a must for now (see https://github.com/bitwiseworks/qtbase-os2/issues/12 for details).
  8. Make it: make -jN all (where N is the number of CPUs on your machine).

Note that by default Qt will be configured in debug_and_release mode with optimized_tools and debug being the default build mode when make is run w/o explicit targets. debug_and_release means that both debug and release builds will co-exist in the same build tree. optimized_tools builds qmake, rcc and some other tools in release mode by default. This creates some non-obvious problems when building. E.g. running just make will fail when building uic and friends if the release DLLs are missing. Running make debug will succeed here but will fail with some tests since there are single mode tests that don't have debug or release targets. Therefore, the only safe way to go in such a configuration is make all which will build everything, including both release and debug (meaning it will take approximately two times longer).

As an alternative, Qt may be configured for either release or debug with -release or -debug configure options, respectively. Also, optimized tools may be disabled with -optimized-tools=no. In such a case, make without targets will work fine. It is, however, recommended to have both debug and release builds for debugging purposes.

Debugging Qt

Qt 5 comes with the built-in logging facility available to applications (see QLoggingCategory, qCDebug and friends). The logging facility groups log messages into user-defined categories and assigns them one of predefined severity levels (debug, info, warning, critical and fatal) using respective qCXxx calls. The default message handler prints log messages to the console. The user may control which severity levels for which categories are enabled using the environment QT_LOGGING_RULES variable which has a very simple syntax: a semicolon separated list of <category_name>[.<level>]=true|false entries. Category names may contain an asterisk to perform wildcard matching: E.g.

QT_LOGGING_RULES="*.debug=false;my.category.debug=true"

This logging facility is used by various parts of Qt itself to provide means to debug it. This kind of logging is usually available both in release and debug builds of Qt but the debug severity level is usually disabled by default and needs to be explicitly enabled using QT_LOGGING_RULES. A good start is just to set a detailed message format and enable everything to be logged, like this:

QT_MESSAGE_PATTERN="[%{pid}-%{threadid}:%{time HH:mm:ss.zzz}] %{function}:%{line}:${category}: %{message}"
QT_LOGGING_RULES="*=true"

Then you may disable categories and levels you don't need with a more specific QT_LOGGING_RULES setting.

The OS/2 code in Qt also employs this technique. However, due to the lack of the trace severity level in Qt, we use the debug level to log very frequent messages (e.g. PM message flow) and the info level for less verbose messages (which are still useful only for debugging). For this reason, we disable both debug and info levels for our categories by default and they need to be explicitly enabled to become visible. The OS/2 code defines the following categories:

Category Purpose
qt.core.events General Qt event flow (only in debug level)
qt.qpa.windows PM window creation and management (debug is not currently used)
qt.qpa.backingstore Raster window composition details, debug enables PNG creation for each paint event
qt.qpa.events Qt event flow for PM windows, debug enables frequent events like paint, resize, mouse and keyboard
qt.qpa.messages PM message flow (only in debug level)
Clone this wiki locally