Portable GDB distribution for the SvNR debugger, built as part of the FEntwumS project.
What ships is a relocated, self-contained GDB binary that the OneWare Studio Extension Manager downloads and the SvNR debugger plugin uses.
| Platform | Version | Release asset | Produced by |
|---|---|---|---|
| linux-x86_64 | 17.2 | gdb-linux-x86_64.tar.gz |
CI (GitHub Actions) |
| macOS ARM64 | 17.2 | gdb-macos-arm64.tar.gz |
CI (GitHub Actions) |
| windows-x86_64 | 17.2 | gdb-windows-x86_64.zip |
CI (GitHub Actions) |
Since v0.4.0 all three are built without Python scripting. Every archive holds
the binary at the same relative path: bin/gdb-multiarch, bin/gdb-multiarch.exe
on Windows. The plugin therefore needs no per-platform special case.
Every archive comes with a .sha256 file holding its checksum. Windows ships
as .zip -- double-click extraction without an extra tool -- the other two
as .tar.gz. All three are
produced entirely in CI; there is no local build step left.
Binaries are no longer produced on a developer machine but in CI. The
authoritative definition is the workflow .github/workflows/build-gdb.yml,
which holds one explicit job per platform (build-linux, build-macos,
build-windows) — deliberately no matrix, since package management, configure
flags and verification differ too much per platform.
Triggering a release — a tag matching v* starts the workflow:
git tag v0.4.1
git push origin v0.4.1
The workflow builds GDB from the official GNU sources, verifies the result,
and automatically attaches the archive and its checksum to the GitHub release
for that tag. Creating the release on GitHub first (web UI or
gh release create) pushes the tag as well and starts the same run.
Trial run without a release — Actions tab → Build GDB → Run workflow. The form offers four checkboxes:
with_python— unticked by default; tick it to build the-pyvariant. Applies to linux and macOS only; Windows never builds with Pythonbuild_linux/build_macos/build_windows— ticked by default; which platforms to build, so a trial run can be limited to the job you are working on
The platform checkboxes only affect a manual start. A tag push always builds all three. The result is kept for 30 days as a workflow artifact, without creating a release.
The GDB version is maintained in the workflow's env block (GDB_VERSION,
GDB_SHA256).
The job runs on ubuntu-latest but builds inside an ubuntu:20.04 container.
The reason is the binding to the host system's libraries: their binary
compatibility only holds upwards. An artifact produced on a newer distribution
would not start on the VM image used in teaching (Ubuntu 20.04) — conversely,
an artifact produced here also runs on newer systems. This affects glibc
(2.31 at most) and — with scripting enabled — libpython (3.8).
The job runs on macos-14 (Apple Silicon). A native GDB build fails there:
the top-level configure moves gdb into noconfigdirs when host and target
are identical, because native debugging is unsupported on arm64 Darwin. Passing
--target=m68k-elf makes host and target differ and keeps gdb in the build
plan — and m68k is the architecture the SvNR needs anyway. The
Check that GDB is part of the build plan step exists to catch exactly this
failure mode before make runs.
Two consequences of the cross build:
- the binary is installed as
m68k-elf-gdb; the workflow renames it tobin/gdb-multiarch(orbin/gdb-multiarch-pywith Python scripting), the same name every platform ships - after
stripthe binary is ad-hoc signed (codesign --force --sign -), otherwise Gatekeeper blocks it on other machines
gmp and mpfr come from Homebrew and are passed to configure explicitly via
--with-gmp / --with-mpfr, so the freshly linked binary references
/opt/homebrew/... at runtime. The Relocate bundle step removes that
dependency:
- every Homebrew dylib the binary needs is copied into
lib/— transitively, so libraries pulled in by other libraries are caught as well. The list is discovered from the binary rather than hardcoded, so it follows whatever configure actually linked - for the
-pyvariant,Python.frameworkis copied intoFrameworks/ - all absolute Homebrew paths are rewritten to
@loader_path-relative references viainstall_name_tool, and each dylib's own ID is pointed at@rpath - everything is re-signed ad hoc, because
install_name_toolinvalidates signatures — and without a signature Gatekeeper blocks the binary on other machines
The Portability check step afterwards is a hard gate: a remaining
/opt/homebrew reference in the binary fails the build.
The job runs on windows-latest and builds in the MSYS2 UCRT64 environment
(msys2/setup-msys2@v2); all run steps go through shell: 'msys2 {0}', set
once via the job's defaults. Dependencies come from pacman
(mingw-w64-ucrt-x86_64-{gcc,gmp,mpfr,expat,ncurses,zlib} plus make and
texinfo).
Native debugging is supported on x86_64 Windows, so unlike macOS no --target
detour is needed — m68k comes from --enable-targets=all. The binary is
bin/gdb-multiarch.exe. LDFLAGS="-static" is passed but does not reach the
final link of gdb, so the binary keeps importing the UCRT64 libraries
(libexpat-1, libgmp-10, libmpfr-6, libncursesw6, libiconv-2, zlib1,
libstdc++-6, libgcc_s_seh-1, libwinpthread-1). The Bundle mingw DLLs
step therefore copies them next to the binary — transitively, discovered from
the image rather than hardcoded — which works because Windows searches the
directory of the executable before the system ones. This mirrors what the macOS
job does with its Homebrew dylibs.
Dependencies are inspected with objdump -p | grep "DLL Name" rather than
ldd, which under MSYS2 reports the MSYS view instead of the PE imports. The
Portability check is a hard gate: every imported DLL that exists under
/ucrt64/bin must also sit in bin/. It used to be a mere warning, and that
is how v0.3.1 shipped a binary that could not start without MSYS2 while CI
stayed green. No code signing and no glibc check apply here.
This applies to linux and macOS. Windows is deliberately built without
Python: the mingw interpreter cannot be linked statically, so the -py
variant would drag a libpython DLL onto the target machine and defeat the
-static linking that makes the Windows artifact self-contained.
By default the build leaves the interpreter out (WITH_PYTHON: 'false'). The
OneWare debugger talks to GDB only through the machine interface and runs no
Python scripts, so the leaner variant is all it needs.
The -py variant embeds the interpreter and is recognizable by the suffix in
the asset name. Only this variant can run GDB Python scripts, such as the RAM
commands from the preliminary work. The price is a dynamic dependency on
exactly libpython3.8 — matching the VM image, but not arbitrary systems; the
binary does not start where that version is missing, and the standard library
is not included in the bundle. Up to v0.3.2 the linux and macOS assets were
this variant.
The workflow aborts if any of these conditions is violated:
- the SHA256 of the source tarball matches
GDB_SHA256 gdbis present as a build target in the generated Makefile- expat is active (
--with-expatingdb --configuration) - m68k appears in the architecture list (the SvNR's host architecture)
- the embedded Python interpreter is actually operational (
-pyvariant only) - on macOS, the binary contains no
/opt/homebrewreference after relocation - on Windows, every imported mingw DLL is bundled next to the binary
On Linux it additionally logs ldd and the highest referenced GLIBC symbol
version, so the 2.31 limit can be traced in the log. On macOS the equivalent is
otool -L; there is no glibc counterpart to check.
All three artifacts are based on GDB 17.2 and are built in CI directly from the
official sources of the Free Software Foundation. On macOS, gmp, mpfr and,
for the -py variant, Python come from Homebrew and are
bundled into the artifact by the relocation step. The underlying GDB sources
are available from the Free Software Foundation:
https://ftp.gnu.org/gnu/gdb/gdb-17.2.tar.xz
GDB is licensed under the GPLv3. This redistribution complies with that
license; the sources are publicly accessible via the link above. See LICENSE
for the full license text.
These checks run automatically in the workflow (see Automated checks). To repeat them by hand on a downloaded macOS bundle:
- Portable:
otool -L bin/gdb-multiarchshows only@loader_path/...,/usr/lib/...and/System/...references. No/opt/homebrew/...paths. - Multiarch:
bin/gdb-multiarch --batch -ex 'set architecture' 2>&1 | grep m68kreturns a hit (m68k is the SvNR's host architecture). - Functional:
bin/gdb-multiarch --versionprints "GNU gdb (GDB) 17.2".
The SvNR debugger plugin declares GDB as a package in
FEntwumsSvnrExtensionModule.cs (GdbPackage) of
FEntwumS.SVNRExtension
and points at the release URLs of the current assets, since package 1.0.3 at
v0.4.0. The package manager does not check the .sha256 files; they are there
for manual verification.
macOS, after the relocation step (self-contained):
bin/gdb-multiarch # the actual binary (stripped, ad-hoc signed)
lib/ # rewritten dylibs (mpfr, gmp, ...)
Frameworks/ # -py variant only: Python.framework (for Dolata's m/M scripts)
share/, include/ # data files from the install prefix
Linux and Windows (plain install prefix):
bin/gdb-multiarch # the actual binary (stripped)
share/, include/ # data files from the install prefix
The archives are flat: they unpack to bin/, share/ and so on, without a
platform-named directory in between. On Windows the binary is
bin/gdb-multiarch.exe. It stays under bin/ on purpose — GDB derives its
data directory from the location of its own executable as ../share/gdb, and
a binary moved to the archive root would look for it one level too high, which
breaks Python scripting.
The exact layout is whatever make install puts under the prefix; the
Diagnostics after make step prints it into the workflow log.
Usage: extract the bundle anywhere and run the binary under bin/.
Remaining runtime
dependencies per platform:
- macOS: none. Homebrew dylibs and, in the
-pyvariant, the Python framework travel inside the bundle - Linux: the target system's
glibc(≤ 2.31 required at build time) and, for the-pyvariant,libpython3.8 - Windows: nothing beyond the system DLLs thanks to
-static— there is no-pyvariant here, so no mingw Python DLL either