Skip to content

Add riscv64, ppc64le and ppc64 (big endian) - #156

Open
gianlucarenzi wants to merge 4 commits into
AppImage:mainfrom
gianlucarenzi:ports-riscv64-ppc64le-ppc64
Open

gianlucarenzi wants to merge 4 commits into
AppImage:mainfrom
gianlucarenzi:ports-riscv64-ppc64le-ppc64

Conversation

@gianlucarenzi

@gianlucarenzi gianlucarenzi commented Oct 13, 2026 •

Copy link
Copy Markdown

This adds three architectures to the runtime: riscv64, ppc64le and big endian ppc64.

riscv64 and ppc64le

Built like the others, in Alpine containers (Alpine has riscv64 and ppc64le images), static PIE with musl. GitHub has no RISC-V and POWER runners, so the CI sets up QEMU (setup-qemu-action) for these two jobs and runs the containers emulated. The only changes are the mapping to the Docker platforms in create-build-container.sh and the names in build-runtime.sh (runtime-riscv64, runtime-ppc64le).

ppc64 (big endian)

Alpine has no big endian ppc64, so it is built in a Debian ports (sid) system, the only distribution that still has it:

  • glibc and gcc instead of musl and clang, plain -static instead of static PIE: the Makefile gets STATIC_PIE and MIMALLOC, which can be emptied on the command line, and build-runtime.sh passes RUNTIME_MAKE_ARGS to make;
  • libfuse and squashfuse from source with scripts/common/install-dependencies.sh, as for the others; zstd, zlib (and mimalloc, if Debian has its static library: it has not, so malloc of glibc is used) from Debian (scripts/debian-ports/build-in-debian.sh);
  • Debian ports has no Docker images: the CI job build-debian-ports makes the system with debootstrap, imports it into Docker and runs it with the qemu-user-static of Ubuntu (the binfmt image of setup-qemu-action has no big endian ppc64).

The result is ELF 64-bit MSB executable, 64-bit PowerPC, Power ELF V1 ABI, statically linked, the ABI of Debian ppc64. The linker warns about dlopen in libfuse (for FUSE modules, which the runtime does not use).

Building with gcc found the overflow fixed in #155, which this branch is based on (its commit will drop out of this PR once #155 is merged).

Tested

Note for testing under qemu-user: the binfmt_misc rule of QEMU wants zeros in bytes 8-15 of the ELF header, where an AppImage has its magic bytes, so an AppImage gives "Exec format error" there (on real machines it runs).

Built runtimes are available at https://github.com/gianlucarenzi/type2-runtime/releases/tag/ports-1.

…m for the nul

"%s.%s" of a path of up to PATH_MAX - 1 characters could overflow
portable_dir: snprintf() now fails cleanly on a path that is too long.
Found by gcc's -Wformat-overflow (an error with -Werror) when building for
ppc64 with gcc. The three readlink() calls into fullpath could fill all of
it, and the terminating nul then went past its end: they now read at most
sizeof(fullpath) - 1 bytes.
Build the runtime for 64-bit RISC-V and for little endian 64-bit PowerPC
as for the other architectures, in Alpine containers (Alpine has riscv64
and ppc64le images): create-build-container.sh maps the architectures to
the Docker platforms and build-runtime.sh names the binaries runtime-riscv64
and runtime-ppc64le. GitHub has no RISC-V and POWER runners, so the CI sets
up QEMU (setup-qemu-action) for these jobs and runs the containers emulated.
Alpine Linux has no big endian ppc64, so the runtime is built in a Debian
ports (sid) system made with debootstrap and run by QEMU (the
qemu-user-static of Ubuntu: the binfmt image of setup-qemu-action has no
big endian ppc64): glibc instead of musl, gcc instead of clang, no static
PIE. libfuse and squashfuse come from source as for the other
architectures; zstd, zlib and, if its static library is there, mimalloc
from Debian (scripts/debian-ports/build-in-debian.sh). meson installs
libfuse into /usr/lib64, which pkg-config and gcc of Debian (multiarch) do
not search, so the script adds it; udev.pc, which the build of libfuse
reads, comes from systemd-dev, as the maintainer scripts of systemd crash
under QEMU.

The Makefile gets STATIC_PIE and MIMALLOC, which can be emptied on the
command line, and build-runtime.sh passes RUNTIME_MAKE_ARGS to make and
names the binary runtime-ppc64 (ELF 64-bit MSB PowerPC, ELFv1 ABI as
Debian ppc64).
@TheAssassin

Copy link
Copy Markdown
Member

Please stop spamming LLM-generated pull requests nobody explicitly asked for and create issues first. This one adds a lot of custom code that would need to be reviewed manually first, and more importantly, maintained long term.

@gianlucarenzi

gianlucarenzi commented Oct 13, 2026 via email

Copy link
Copy Markdown
Author

@TheAssassin

Copy link
Copy Markdown
Member

This was not a no, it was a "slow down and be more communicative". For future work, please start a discussion first.

This MR might still be relevant.

@github-actions

Copy link
Copy Markdown

@probonopd probonopd left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I read the three commits (the first is #155) and the build scripts they change. The approach is sound; four points for the maintainers to decide on.

What holds up. riscv64 and ppc64le reuse the existing Alpine container path under QEMU: alpine:3.21 has both architectures, the Docker platform names (linux/riscv64, linux/ppc64le) are right, and the new file matching for the runtime suffixes is correct ("RISC-V"; "64-bit MSB" / "64-bit LSB" together with "PowerPC"). Big-endian ppc64 has no Alpine, so it is built in a Debian sid system made by debootstrap, imported into Docker and run with Ubuntu's qemu-user-static, with gcc and glibc and -static without -static-pie. The Makefile's new STATIC_PIE and MIMALLOC variables default to today's values, so the existing builds are unchanged. The bot's test build produced artifacts for all seven architectures.

Points to consider:

  1. The upload job now needs: build-debian-ports. Debian ports is unstable by nature and that job runs emulated with a four-hour timeout; when it fails, no release is published for any architecture. I would let the release job tolerate that job's failure (or keep ppc64 out of the release gate) so the established architectures do not depend on it.
  2. The keyring is fetched as debian-ports-archive-keyring_2026.02.04_all.deb from the Debian pool. The pool keeps only the current version, so this URL breaks on the next keyring upload. Resolving the current file name from the package index (Packages of main) avoids that.
  3. build-debian-ports has no Sign step, so the ppc64 runtime would be the only unsigned file on the release page.
  4. As the description says, the runtimes were tested only under QEMU, not on RISC-V or POWER hardware. Together with the maintenance of a second build path (debootstrap, glibc, gcc) that is the part that needs a maintainer's yes, per the discussion above.

Generated by Claude Code

@Samueru-sama

Copy link
Copy Markdown

You might wanna consider using the zig compiler to build all the arches, it removes the need for qemu and separate docker images. example

…t gated

Points of the review:
- the keyring of Debian ports was fetched by a fixed file name from the
  pool, which keeps only the current version; its name now comes from the
  package index (dists/sid/main/binary-all/Packages.xz);
- the ppc64 runtime is signed as the others (the Sign step of the build
  job, skipped without the secret);
- the upload job no longer fails with build-debian-ports: when the
  emulated Debian ports build fails, the release goes out with the other
  architectures.
@gianlucarenzi

Copy link
Copy Markdown
Author

Thanks for the review, @probonopd. 9ddbab1 addresses points 1–3: the upload job no longer depends on build-debian-ports succeeding (if the emulated ppc64 build fails, the release goes out without runtime-ppc64); the keyring file name is resolved from the Debian package index instead of being pinned; and the ppc64 runtime now goes through the same Sign step as the others. On point 4: right, the runtimes were tested only under QEMU, I have no RISC-V or POWER hardware, so that's the maintainers' call.

@TheAssassin understood, and sorry for the burst of PRs. I'll open an issue first for anything further. (Also sorry for my empty reply above, my mail client sent only the quote.)

@Samueru-sama thanks for the zig pointer, I'll look into it; if the maintainers prefer that route it could be a separate PR.

@github-actions

Copy link
Copy Markdown

@TheAssassin

Copy link
Copy Markdown
Member

You might wanna consider using the zig compiler to build all the arches, it removes the need for qemu and separate docker images. example

Would still require the binary userland in the right architecture. We are optimizing away the need to maintain such things manually by just using Docker with QEMU, which in general works quite well. Yes, we trade runtime for usability, but that's more than acceptable to me.

debootstrap

This is what really prevents me from having a closer look. This is way over the top, it effectively works against the remaining build concept. I think we should build on only one platform. If Alpine doesn't support a specific architecture, then we probably shouldn't bother with it.

@gianlucarenzi

gianlucarenzi commented Oct 14, 2026 via email

Copy link
Copy Markdown
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants