Skip to content

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

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

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

Conversation

@gianlucarenzi

@gianlucarenzi gianlucarenzi commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

This adds three architectures to appimagetool: riscv64, ppc64le and big endian ppc64. It needs the runtimes for them, proposed in AppImage/type2-runtime#156: until that is merged, the CI jobs of the new architectures here cannot download runtime-<arch> from the continuous release.

Recognizing the architectures

  • riscv64: ELF e_machine 243, or ARCH=riscv64;
  • ppc64le: e_machine 21 with ELFDATA2LSB, or ARCH=ppc64le, ppc64el (Debian) or powerpc64le (Rust, LLVM);
  • ppc64 (big endian): e_machine 21 with ELFDATA2MSB, or ARCH=ppc64, ppc64be, powerpc64 or powerpc64be.

The names in the files are those of uname -m. To tell the two PowerPC apart, read_elf_e_machine_field() now reads the byte order; before, it read e_machine always as little endian, so a big endian AppDir was never recognized (EM_PPC64 came out as 0x1500): that is a separate commit. The number of architectures is no longer hardcoded (fARCH_COUNT).

It needs #133 (section headers in the byte order of the file), without which packing a big endian runtime on a little endian machine crashes. #133 is merged now and the branch is rebased on main, so its commit is no longer part of this PR.

#148 (only use ELF files for determining the architecture) changes read_elf_e_machine_field() too: whichever is merged second needs a small rebase.

Building appimagetool for them

  • riscv64 and ppc64le: Alpine containers emulated by QEMU (setup-qemu-action), as there are no GitHub runners for them; riscv64 needs alpine:3.20 (3.19 has no riscv64 images).
  • ppc64: Alpine has no big endian ppc64, and Debian has no static builds of all the dependencies, so ci/build-in-debian.sh builds it in Debian ports (sid), linked dynamically against the glib, gpgme, libgcrypt and libcurl of Debian, and puts the libraries it needs but glibc into the AppImage (usr/lib, found through LD_LIBRARY_PATH set by AppRun), with mksquashfs, zsyncmake and desktop-file-validate from Debian. The build checks that nothing but glibc is left outside. The CI job makes the system with debootstrap and runs it with the qemu-user-static of Ubuntu.

Tested

  • The CI of this branch (in a fork, with the runtimes of the type2-runtime PR) builds appimagetool for all the architectures, the new ones included.
  • The CI here, after the rebase, builds appimagetool for riscv64, ppc64le and ppc64 too (7 to 11 minutes under QEMU); those three jobs fail only afterwards, when they download runtime-<arch>, which the type2-runtime continuous release does not have yet.
  • appimagetool for x86_64 packs AppDirs of riscv64, ppc64le and ppc64 (detected from the ELF files or given with ARCH, all the names above), with update information and .zsync.
  • RITMO, a Qt 6 application, packed this way on riscv64, ppc64le and ppc64, starts and runs emulated by QEMU (https://github.com/gianlucarenzi/RITMO-Music-Tracker).
  • Not tried on real riscv64 or POWER hardware yet.

Built AppImages of appimagetool: https://github.com/gianlucarenzi/appimagetool/releases/tag/ports-2.

appimage_get_elf_section_offset_and_length() read e_shoff, e_shnum,
e_shstrndx, sh_name, sh_offset and sh_size as they are in the file: with the
runtime of a big endian architecture (ppc64) on a little endian machine, it
got wrong offsets and read past the mapping, so appimagetool crashed
(segmentation fault) when embedding the update information or the MD5
digest. They now go through file16/32/64_to_cpu(), which know the byte order
from e_ident; open() and mmap() failures are reported instead of crashing.

read_elf32() converted the 32 bit sh_offset and sh_size with
file64_to_cpu(): file32_to_cpu() now.
read_elf_e_machine_field() always read it as little endian, so the
architecture of a big endian AppDir (e.g. ppc64, s390x) was never
recognized: EM_PPC64 (0x0015) came out as 0x1500. EI_DATA now tells the
byte order.
Recognize AppDirs for 64-bit RISC-V (ELF e_machine 243, or ARCH=riscv64),
little endian 64-bit PowerPC (e_machine 21 with ELFDATA2LSB, or
ARCH=ppc64le, ppc64el or powerpc64le) and big endian 64-bit PowerPC
(e_machine 21 with ELFDATA2MSB, or ARCH=ppc64, ppc64be, powerpc64 or
powerpc64be). The names in the files are those of uname -m: riscv64,
ppc64le, ppc64. read_elf_e_machine_field() also returns the byte order,
which tells the two PowerPC apart, and the number of architectures is no
longer hardcoded (fARCH_COUNT).
GitHub has no RISC-V and POWER runners: the CI sets up QEMU
(setup-qemu-action) for these jobs and runs the Alpine containers emulated.
riscv64 needs alpine:3.20, as 3.19 has no riscv64 images.
Alpine Linux has no big endian ppc64, and Debian has no static builds of
all the dependencies: ci/build-in-debian.sh links appimagetool dynamically
against the glib, gpgme, libgcrypt and libcurl of Debian ports (sid) and
puts the libraries it needs, but glibc, into the AppImage (usr/lib), found
through LD_LIBRARY_PATH set by AppRun. mksquashfs, zsyncmake and
desktop-file-validate come from Debian, with their libraries. The build
checks that nothing but glibc is left outside the AppImage.

The CI job makes the Debian ports system with debootstrap and runs the
build in it, emulated by the qemu-user-static of Ubuntu (the binfmt image
of setup-qemu-action has no big endian ppc64).

@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 five commits (the first is #133) and the build scripts. The source changes are correct; the CI part has dependencies and the same open points as type2-runtime#156.

Source (commits 2 and 3): correct. read_elf_e_machine_field() now reads EI_DATA and converts e_machine with GINT16_FROM_BE for big-endian files, which fixes the 0x1500-for-0x0015 misread. EM_RISCV is 243 and EM_PPC64 is 21 for both byte orders, so splitting ppc64 and ppc64le on EI_DATA is the right way. fARCH_COUNT replaces the hardcoded 4 in count_archs() and in main()'s archs[], which was easy to miss when adding entries. One fragile spot, not wrong: the ARCH text matching relies on the n of g_ascii_strncasecmp() including the terminating nul ("ppc64" with n=6) so that ppc64 does not also match ppc64le. It works, but an exact g_ascii_strcasecmp() would say what is meant and not break when someone adjusts a length.

Dependencies, before this can be green:

  1. fetch_runtime() downloads runtime-<arch> from type2-runtime's continuous release, and ci/build-in-debian.sh does the same with wget. That release has only aarch64, armhf, i686 and x86_64 today, so the riscv64, ppc64le and ppc64 jobs cannot finish until type2-runtime#156 is merged and has published its runtimes; users of the new architectures need --runtime-file until then. Merge order is #133, then type2-runtime#156, then this.
  2. The ppc64 appimagetool is built on Debian sid and linked dynamically against sid's glibc, with the other libraries bundled. It will therefore only run on ppc64 systems with a glibc at least as new as sid's at build time, unlike the other architectures, whose static musl builds run anywhere. Since ppc64 exists only in Debian ports, that is inherent to the approach; it should be documented on the release page so users know.

CI, same points as on type2-runtime#156: the upload job now needs: build-debian-ports, so a failure of the emulated four-hour Debian job blocks the release for every architecture; the keyring is pinned to debian-ports-archive-keyring_2026.02.04_all.deb in the Debian pool, which keeps only the current version, so that URL breaks on the next keyring upload. At the time of writing, the aarch64 and armhf builds of this PR have passed and the others are still running.


Generated by Claude Code

…README

Points of the review:
- the new ARCH names are compared with g_ascii_strcasecmp(): the n of
  g_ascii_strncasecmp() included the terminating nul so that ppc64 did not
  match ppc64le, which an exact comparison says directly (tried with the
  x86_64 build: ppc64 and powerpc64 are big endian, ppc64le and PPC64EL
  little endian, riscv64 RISC-V, ppc64x is refused);
- the keyring of Debian ports comes from the package index, as the pool
  keeps only its current version;
- the upload job no longer fails with build-debian-ports;
- README: how to build riscv64, ppc64le and ppc64; the ppc64 build needs a
  glibc at least as new as that of Debian sid at build time; the runtimes
  of the new architectures come from type2-runtime releases that have
  them, else --runtime-file.
@gianlucarenzi

Copy link
Copy Markdown
Contributor Author

Thanks, @probonopd. c96d17a: the new ARCH names are compared exactly with g_ascii_strcasecmp(); the Debian ports keyring is resolved from the package index; the upload job no longer depends on the ppc64 job; and the README now documents the riscv64/ppc64le/ppc64 builds, the glibc requirement of the ppc64 build, and --runtime-file until type2-runtime publishes the new runtimes. Merge order as you suggested: #133, type2-runtime#156, then this one.

read_elf_e_machine_field() always read it as little endian, so the
architecture of a big endian AppDir (e.g. ppc64, s390x) was never
recognized: EM_PPC64 (0x0015) came out as 0x1500. EI_DATA now tells the
byte order.
Recognize AppDirs for 64-bit RISC-V (ELF e_machine 243, or ARCH=riscv64),
little endian 64-bit PowerPC (e_machine 21 with ELFDATA2LSB, or
ARCH=ppc64le, ppc64el or powerpc64le) and big endian 64-bit PowerPC
(e_machine 21 with ELFDATA2MSB, or ARCH=ppc64, ppc64be, powerpc64 or
powerpc64be). The names in the files are those of uname -m: riscv64,
ppc64le, ppc64. read_elf_e_machine_field() also returns the byte order,
which tells the two PowerPC apart, and the number of architectures is no
longer hardcoded (fARCH_COUNT).
GitHub has no RISC-V and POWER runners: the CI sets up QEMU
(setup-qemu-action) for these jobs and runs the Alpine containers emulated.
riscv64 needs alpine:3.20, as 3.19 has no riscv64 images.
Alpine Linux has no big endian ppc64, and Debian has no static builds of
all the dependencies: ci/build-in-debian.sh links appimagetool dynamically
against the glib, gpgme, libgcrypt and libcurl of Debian ports (sid) and
puts the libraries it needs, but glibc, into the AppImage (usr/lib), found
through LD_LIBRARY_PATH set by AppRun. mksquashfs, zsyncmake and
desktop-file-validate come from Debian, with their libraries. The build
checks that nothing but glibc is left outside the AppImage.

The CI job makes the Debian ports system with debootstrap and runs the
build in it, emulated by the qemu-user-static of Ubuntu (the binfmt image
of setup-qemu-action has no big endian ppc64).
…README

Points of the review:
- the new ARCH names are compared with g_ascii_strcasecmp(): the n of
  g_ascii_strncasecmp() included the terminating nul so that ppc64 did not
  match ppc64le, which an exact comparison says directly (tried with the
  x86_64 build: ppc64 and powerpc64 are big endian, ppc64le and PPC64EL
  little endian, riscv64 RISC-V, ppc64x is refused);
- the keyring of Debian ports comes from the package index, as the pool
  keeps only its current version;
- the upload job no longer fails with build-debian-ports;
- README: how to build riscv64, ppc64le and ppc64; the ppc64 build needs a
  glibc at least as new as that of Debian sid at build time; the runtimes
  of the new architectures come from type2-runtime releases that have
  them, else --runtime-file.
gianlucarenzi1971 and others added 2 commits November 9, 2026 08:48
The build scripts download runtime-$ARCH from the type2-runtime
continuous release, which has no riscv64, ppc64le and ppc64 runtimes
until AppImage/type2-runtime#156 is merged. RUNTIME_URL_BASE (in GitHub
Actions, the repository variable of the same name) points them to
another release, e.g. that of a fork of type2-runtime, so that a fork
can build the AppImages of the new architectures meanwhile.

Unset or empty, nothing changes: the runtime still comes from the
type2-runtime continuous release.
…i/appimagetool into ports-riscv64-ppc64le-ppc64

# Conflicts:
#	.github/workflows/build.yml
#	README.md
#	ci/build-in-debian.sh
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.

3 participants