summaryrefslogtreecommitdiff
path: root/docs/handbook/images4docker/qt6-verification.md
blob: b29343e19f79a860b57c105f317af0b2b9c8bd2a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
# images4docker — Qt6 Verification

## Purpose

Every Dockerfile in images4docker includes a mandatory **Qt6 toolchain
verification gate**.  This gate runs at the end of the `RUN` instruction,
after all packages have been installed.  If the gate fails, the entire
Docker build fails — there is **no fallback to Qt5** and no option to skip
the check.

This ensures that every image published to `ghcr.io/project-tick-infra/images/`
is guaranteed to have a working Qt6 toolchain available.

---

## How the Gate Works

### Step 1: PATH Extension

Before checking for Qt6 binaries, the `PATH` environment variable is extended
to include all known Qt6 installation directories:

**Standard path extension** (most distributions):

```sh
export PATH="$PATH:/usr/lib/qt6/bin:/usr/lib64/qt6/bin:/opt/qt6/bin:/root/.nix-profile/bin"
```

**Extended path** (Amazon Linux 2023, Gentoo, NixOS, Oracle Linux, Void Linux):

```sh
export PATH="$PATH:/usr/lib/qt6/bin:/usr/lib64/qt6/bin:/usr/libexec/qt6:/opt/qt6/bin:/root/.nix-profile/bin"
```

The extended variant adds `/usr/libexec/qt6` for distributions where Qt6
installs its binaries under `libexec`.

### Step 2: Binary Search

The gate checks for the presence of Qt6 binaries using a multi-pronged approach:

**Command-based checks** (via `command -v` — checks `$PATH`):

```sh
command -v qmake6 >/dev/null 2>&1
command -v qmake-qt6 >/dev/null 2>&1
command -v qtpaths6 >/dev/null 2>&1
```

**Absolute path checks** (via `[ -x ... ]` — checks specific filesystem locations):

Standard set:
```sh
[ -x /usr/lib/qt6/bin/qmake ]
[ -x /usr/lib64/qt6/bin/qmake ]
[ -x /usr/lib/qt6/bin/qtpaths ]
[ -x /usr/lib64/qt6/bin/qtpaths ]
```

Extended set (Oracle Linux, Gentoo, NixOS, Amazon Linux 2023, Void Linux):
```sh
[ -x /usr/libexec/qt6/qmake ]
[ -x /usr/libexec/qt6/qtpaths ]
```

### Step 3: Pass or Fail

All checks are combined with `||` (logical OR).  If **any single check**
succeeds, the gate passes:

```sh
if command -v qmake6 >/dev/null 2>&1 \
   || command -v qmake-qt6 >/dev/null 2>&1 \
   || command -v qtpaths6 >/dev/null 2>&1 \
   || [ -x /usr/lib/qt6/bin/qmake ] \
   || [ -x /usr/lib64/qt6/bin/qmake ] \
   || [ -x /usr/lib/qt6/bin/qtpaths ] \
   || [ -x /usr/lib64/qt6/bin/qtpaths ]; then
    true;
  else
    echo "Qt6 toolchain not found" >&2;
    exit 1;
  fi
```

If **all checks fail**, the gate prints "Qt6 toolchain not found" to stderr
and exits with code 1, which causes the Docker `RUN` instruction to fail
and aborts the build.

---

## Actual Dockerfile Snippet

Here is the exact verification code as it appears in the Dockerfiles (shown
in formatted form — the actual files have it on a single `RUN` line):

```sh
set -eux

# ... package installation ...

# PATH extension
export PATH="$PATH:/usr/lib/qt6/bin:/usr/lib64/qt6/bin:/opt/qt6/bin:/root/.nix-profile/bin"

# Qt6 verification gate
if command -v qmake6 >/dev/null 2>&1 \
     || command -v qmake-qt6 >/dev/null 2>&1 \
     || command -v qtpaths6 >/dev/null 2>&1 \
     || [ -x /usr/lib/qt6/bin/qmake ] \
     || [ -x /usr/lib64/qt6/bin/qmake ] \
     || [ -x /usr/lib/qt6/bin/qtpaths ] \
     || [ -x /usr/lib64/qt6/bin/qtpaths ]; then
  true
else
  echo "Qt6 toolchain not found" >&2
  exit 1
fi
```

---

## Why These Specific Binaries?

### qmake6

`qmake6` is the Qt 6 version of the qmake build system.  On most distributions,
the `qt6-base-dev` or `qt6-qtbase-devel` package installs it as `qmake6`.

### qmake-qt6

Some distributions (especially Debian-based ones) install the Qt6 qmake as
`qmake-qt6` instead of `qmake6`.  The `-qt6` suffix is a Debian packaging
convention to allow multiple Qt versions to coexist.

### qtpaths6

`qtpaths6` is a Qt6 utility that reports installation paths (plugin directory,
library directory, etc.).  It is a lightweight Qt6 binary that confirms the
Qt6 runtime is properly installed, without needing a full build tool like qmake.

### Why check absolute paths too?

On some distributions, Qt6 binaries are installed to non-standard locations
that may not be in `$PATH`:

| Path                          | Used by                                          |
|-------------------------------|--------------------------------------------------|
| `/usr/lib/qt6/bin/qmake`     | Debian, Ubuntu (32-bit or arch-independent)      |
| `/usr/lib64/qt6/bin/qmake`   | Fedora, RHEL family (64-bit lib directory)       |
| `/usr/libexec/qt6/qmake`     | Oracle Linux, Gentoo, Amazon Linux 2023, Void    |
| `/usr/lib/qt6/bin/qtpaths`   | Debian, Ubuntu                                   |
| `/usr/lib64/qt6/bin/qtpaths` | Fedora, RHEL family                              |
| `/usr/libexec/qt6/qtpaths`   | Oracle Linux, Gentoo, Amazon Linux 2023, Void    |
| `/opt/qt6/bin/`              | Custom Qt6 installations (from source or installer)|
| `/root/.nix-profile/bin/`    | NixOS (Nix profile symlinks)                     |

---

## Which Dockerfiles Use Which Path Variant?

### Standard Qt6 paths (7 check locations, 4 PATH dirs)

Used by 30 Dockerfiles:

- All **AlmaLinux** images (alma-9, alma-10)
- All **Alpine** images (alpine-319 through alpine-latest)
- **Arch** (arch-latest)
- All **CentOS Stream** images (centos-stream9, centos-stream10)
- All **Debian** images (bookworm, bookworm-slim, bullseye, bullseye-slim, stable-slim, trixie-slim)
- All **Devuan** images (devuan-chimaera, devuan-daedalus)
- All **Fedora** images (fedora-40, fedora-41, fedora-42, fedora-latest)
- **Kali** (kali-rolling)
- All **openSUSE** images (opensuse-leap-155, opensuse-leap-156, opensuse-tumbleweed)
- All **Rocky** images (rocky-9, rocky-10)
- All **Ubuntu** images (ubuntu-2004, ubuntu-2204, ubuntu-2404, ubuntu-latest)
- **Amazon Linux 2** (amazonlinux-2)

```sh
export PATH="$PATH:/usr/lib/qt6/bin:/usr/lib64/qt6/bin:/opt/qt6/bin:/root/.nix-profile/bin"

# Checks: qmake6, qmake-qt6, qtpaths6 (via command -v)
#   plus: /usr/lib/qt6/bin/qmake, /usr/lib64/qt6/bin/qmake,
#          /usr/lib/qt6/bin/qtpaths, /usr/lib64/qt6/bin/qtpaths
```

### Extended Qt6 paths (9 check locations, 5 PATH dirs)

Used by 6 Dockerfiles:

- **Amazon Linux 2023** (amazonlinux-2023)
- **Gentoo** (gentoo-stage3)
- **NixOS** (nix-latest)
- **Oracle Linux** 8, 9, 10 (oraclelinux-8, oraclelinux-9, oraclelinux-10)
- **Void Linux** (void-latest)

```sh
export PATH="$PATH:/usr/lib/qt6/bin:/usr/lib64/qt6/bin:/usr/libexec/qt6:/opt/qt6/bin:/root/.nix-profile/bin"

# Checks: qmake6, qmake-qt6, qtpaths6 (via command -v)
#   plus: /usr/lib/qt6/bin/qmake, /usr/lib64/qt6/bin/qmake,
#          /usr/lib/qt6/bin/qtpaths, /usr/lib64/qt6/bin/qtpaths,
#          /usr/libexec/qt6/qmake, /usr/libexec/qt6/qtpaths
```

---

## Images Excluded from Active CI Matrix

The README notes that approximately **35 of 40** images are in the active CI
build matrix.  The ~5 excluded images are those where Qt6 packages are not
reliably available:

| Image                            | Reason for exclusion                                |
|----------------------------------|-----------------------------------------------------|
| `amazonlinux-2`                  | Based on RHEL 7 era; no Qt6 in default repos       |
| `debian-bullseye` / `bullseye-slim` | Debian 11 shipped Qt 5.15, not Qt6              |
| `devuan-chimaera`                | Based on Debian Bullseye, same Qt6 limitation       |
| `ubuntu-2004`                    | Ubuntu 20.04 does not ship Qt6                      |

These images are still maintained in the repository for potential future use
(e.g., if Qt6 becomes available via backports or PPAs), but they are not built
in the regular CI workflow.

---

## Failure Behaviour

When the Qt6 gate fails:

1. The `echo "Qt6 toolchain not found" >&2` message is printed to stderr.
2. `exit 1` terminates the shell with a non-zero exit code.
3. The `RUN` instruction fails.
4. Docker aborts the build.
5. The CI workflow reports a build failure for that image target.
6. The failed image is **not** pushed to the container registry.

Because `set -eux` is active at the top of the `RUN` block:
- `-e`: Exit immediately if any command fails.
- `-u`: Treat unset variables as errors.
- `-x`: Print each command before executing (useful for debugging in CI logs).

---

## Why No Qt5 Fallback?

The project has made a deliberate decision to require Qt6:

1. **Qt5 is end-of-life** — Qt 5.15 LTS support ended.  New features and
   security fixes only go into Qt6.
2. **API consistency** — supporting both Qt5 and Qt6 would require conditional
   compilation paths, increasing maintenance burden.
3. **Clear signal** — if a distribution cannot provide Qt6, it is too old to
   be a supported build target.

---

## Verifying Qt6 Locally

To test whether Qt6 would be found in a specific image, you can run:

```bash
docker run --rm <image> sh -c '
  export PATH="$PATH:/usr/lib/qt6/bin:/usr/lib64/qt6/bin:/opt/qt6/bin"
  echo "qmake6:    $(command -v qmake6 2>/dev/null || echo NOT FOUND)"
  echo "qmake-qt6: $(command -v qmake-qt6 2>/dev/null || echo NOT FOUND)"
  echo "qtpaths6:  $(command -v qtpaths6 2>/dev/null || echo NOT FOUND)"
  for p in /usr/lib/qt6/bin/qmake /usr/lib64/qt6/bin/qmake \
           /usr/lib/qt6/bin/qtpaths /usr/lib64/qt6/bin/qtpaths \
           /usr/libexec/qt6/qmake /usr/libexec/qt6/qtpaths; do
    [ -x "$p" ] && echo "Found: $p" || echo "Missing: $p"
  done
'
```

---

## Related Documentation

- [Overview](overview.md) — project summary
- [Architecture](architecture.md) — Dockerfile template structure
- [Base Images](base-images.md) — per-image deep dive
- [CI/CD Integration](ci-cd-integration.md) — how the workflow builds and verifies
- [Troubleshooting](troubleshooting.md) — debugging Qt6 failures