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-py.tar.gz |
CI (GitHub Actions) |
| macOS ARM64 | 17.2 | gdb-macos-arm64-py.tar.gz |
CI (GitHub Actions) |
| windows-x86_64 | 17.2 | gdb-windows-x86_64.zip |
CI (GitHub Actions) |
Every archive holds the binary at the same relative path: bin/gdb-multiarch-py
with Python scripting, 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 v17.2-1
git push origin v17.2-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.
Trial run without a release — Actions tab → Build GDB → Run workflow. The form offers four checkboxes, all ticked by default:
with_python— build the variant without Python scripting when unticked. Applies to linux and macOS only; Windows never builds with Pythonbuild_linux/build_macos/build_windows— 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-py(orbin/gdb-multiarchwithout 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 embeds the interpreter (WITH_PYTHON: 'true'),
recognizable by the -py 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 standard library is not included in the
bundle. The variant without Python (asset without the suffix) is leaner and
sufficient as long as the data is displayed in the user interface.
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 (linux and macOS)
- 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
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-multiarch-pyshows only@loader_path/...,/usr/lib/...and/System/...references. No/opt/homebrew/...paths. - Multiarch:
bin/gdb-multiarch-py --batch -ex 'set architecture' 2>&1 | grep m68kreturns a hit (m68k is the SvNR's host architecture). - Functional:
bin/gdb-multiarch-py --versionprints "GNU gdb (GDB) 17.2".
In oneware-extension.json, the SvNR debugger plugin points at the release
URL of the current asset and checks its SHA256 sum.
macOS, after the relocation step (self-contained):
bin/gdb-multiarch-py # the actual binary (stripped, ad-hoc signed)
lib/ # rewritten dylibs (mpfr, gmp, ...)
Frameworks/ # 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-py # 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