Skip to main content

AppImage

Bundle a Linux binary into a single self-contained .AppImage with linuxdeploy

Anodizer can bundle a built Linux binary plus its desktop integration into a single self-contained, runnable .AppImage using linuxdeploy's appimage output plugin.

Classification

Packager — creates .AppImage files from Linux binaries. Not a publisher; linuxdeploy must be on PATH. One .AppImage is produced per matching Linux target, so a multi-arch build yields distinct, non-colliding outputs.

Minimal config

appimages:
  - desktop: contrib/MyApp.desktop
    icon: contrib/myapp.png

Full config reference

appimages:
  - id: helix                        # optional; unique identifier
    ids: [helix-bin]                 # optional; filter by build IDs
    filename: ""                     # optional; output filename template
    name: ""                         # optional; APP name + AppDir basename
    desktop: contrib/Helix.desktop   # required; .desktop entry (template)
    icon: contrib/helix.png          # required; icon path (template)
    appdir_extra:                    # optional; files/dirs copied into the AppDir
      - src: runtime/                #   src path (file or dir)
        dst: usr/lib/helix/runtime   #   dst relative to the AppDir root
    update_information: "gh-releases-zsync|helix-editor|helix|latest|helix-*.AppImage.zsync"
    runtime_harvest:                 # optional; run the built binary to populate a dir
      command: "{{ ArtifactPath }} --populate-runtime {{ HarvestDir }}"
      dir: usr/lib/helix/runtime     #   AppDir-relative bundle destination
    extra_args: []                   # optional; extra linuxdeploy CLI arguments
    os: ["linux"]                    # optional; target OS filter (AppImage is Linux-only)
    arch: []                         # optional; target architecture filter
    skip: false                      # optional (alias: disable)

linuxdeploy invocation

linuxdeploy is spawned as:

linuxdeploy --appdir <AppDir> -d <desktop> -i <icon> --output appimage [extra_args...]

with the env it reads set on the process:

Env varSource
VERSIONthe release version ({{ Version }})
ARCHAppImage arch token (x86_64, aarch64, armhf, i686)
APPname (defaults to project name)
OUTPUTalways appimage
UPDATE_INFORMATIONupdate_information, set only when configured (zsync delta updates)

AppRun is generated by linuxdeploy by default. To ship a custom AppRun (e.g. one that sets HELIX_RUNTIME), drop it into the AppDir via appdir_extra with dst: AppRun.

Runtime harvest

Some applications populate a runtime data directory by running their own binary (helix runs a loader to fetch tree-sitter grammars / themes / queries). The runtime_harvest hook models this:

runtime_harvest:
  command: "{{ ArtifactPath }} --populate-runtime {{ HarvestDir }}"
  dir: usr/lib/helix/runtime
  • {{ ArtifactPath }} resolves to the host-native binary's path and {{ HarvestDir }} to the absolute harvest output dir. The command is run once via sh -c.

  • The harvested data is architecture-independent, so it is produced once on the host-native binary and reused for every target's AppImage — no QEMU. If a pure cross build has no host-native binary, the stage emits a clear error rather than silently skipping.

  • The harvested tree is staged at dist/.appimage-runtime/<id>/, so an archive extra_files glob can ship the same runtime/ in tarballs:

    archives:
      - files:
          - "dist/.appimage-runtime/helix/**"

Config fields

FieldTypeDefaultDescription
idstringdefaultUnique identifier
idslistall buildsFilter by build IDs
filenamestring{project}-{version}-{arch}.AppImageOutput filename (template)
namestringproject nameAPP name + AppDir basename
desktopstringrequired.desktop entry path (template)
iconstringrequiredIcon path (template)
appdir_extralistnoneFiles/dirs copied into the AppDir
update_informationstringnonezsync update metadata (UPDATE_INFORMATION)
runtime_harvestobjectnoneHost-once binary-run hook (see above)
extra_argslistnoneExtra linuxdeploy CLI arguments
oslist["linux"]Target OS filter
archlistallTarget architecture filter
skipstring/boolnoneSkip this config (alias: disable)

appdir_extra entries

FieldAliasTypeDescription
srcsourcestringSource path (file or directory)
dstdestinationstringDestination relative to the AppDir root

runtime_harvest

FieldTypeDescription
commandstringCommand template run once on the host ({{ ArtifactPath }}, {{ HarvestDir }})
dirstringAppDir-relative directory the harvested assets are bundled into

Authentication

Not applicable — AppImage creation is a local build step with no external service calls.

Common gotchas

  • linuxdeploy must be on PATH: the stage errors if it is not found.
  • One .AppImage per platform: binaries are grouped by OS + arch; each group produces one AppImage. Use os / arch to restrict targets.
  • .AppImage extension is auto-appended when a custom filename template omits it.
  • Harvest needs a host-native binary: a pure cross build (no artifact for the host target) errors instead of silently skipping the harvest.
  • Distinct configs sharing an arch must set filename:: two appimages: entries that differ only by id and target the same arch render the same default output name and clobber on disk — give each an explicit filename: to disambiguate.

Republish / update behavior

Not applicable — this is a local packaging stage, not a publisher. The resulting .AppImage is checksummed, signed, attested, and uploaded to the release like any other artifact.

Behavior

  • Groups binary artifacts by platform (os + arch), creating one .AppImage per platform
  • The runtime harvest runs once on the host binary and is reused per arch
  • IDs must be unique across all AppImage configs
  • The .AppImage is a release-uploadable artifact (checksum / sign / attest / release pick it up)
  • Skippable with --skip appimage