Additional Language Toolchains
Beyond the compilers and runtimes that the system itself is built on, InterGenOS packages seven further language toolchains. They are built from source through the same pipeline as everything else, signed into the same mirror, and verified by the same package manager.
None of these seven are on the installation image. They are available from the signed mirror and you install the ones you want. This page says so first because getting it backwards is the single most misleading thing a package page can do: it sends you looking for a command that is not on your disk.
The seven
| Toolchain | Version | Package name | Primary command |
|---|---|---|---|
| PHP | 8.4.11 | php | php |
| OpenJDK | 24.0.2 | openjdk | java, javac |
| Erlang/OTP | 29.0.3 | erlang | erl, erlc, escript |
| Julia | 1.12.6 | julia | julia |
| Zig | 0.16.0 | zig | zig |
| GHC (Glasgow Haskell Compiler) | 9.14.1 | ghc | ghc, ghc-pkg |
| R | 4.6.1 | R | R, Rscript |
Note the capital letter in R — that is the package name as well as the command.
Installing them
sudo pkm sync # refresh and verify the signed index
sudo pkm install php
sudo pkm install openjdk erlang julia zig ghc R
Every install verifies the mirror index signature and then the package’s own hash before anything lands on disk, exactly as described in The Transparent Package Manager and Reproducibility & Verification. Nothing about these packages is a special case.
To remove one again:
sudo pkm remove julia
Why they are not on the image
InterGenOS assigns every package a tier, and the tier decides whether the package ships on the installation image or lives only on the mirror. All seven of these toolchains are in the extra tier, and extra packages are mirror-only by default.
This is not an accident of packaging; it is the shipping rule the build applies. The image is meant to boot, install, and give you a working desktop with a verified boot chain — not to carry every language runtime anyone might want. A developer who needs Haskell installs Haskell. Someone who never touches Erlang never pays for it in image size, attack surface, or update volume. That is the same minimization argument made in Attack-Surface Minimization, applied to language runtimes.
The practical consequence: on a freshly installed machine, php, java, erl, julia, zig, ghc and R are all absent until you install them, and you need working access to the mirror (or a local copy of it) at the time you install. See Using InterGenOS Offline for how to install packages on a machine with no network.
Where the commands land
Six of the seven install into the ordinary system prefix, so their commands are on your PATH the moment installation finishes:
| Toolchain | Installed command paths |
|---|---|
| PHP | /usr/bin/php, /usr/bin/phpize, /usr/sbin/php-fpm |
| Erlang/OTP | /usr/bin/erl, /usr/bin/erlc, /usr/bin/escript |
| Julia | /usr/bin/julia |
| Zig | /usr/bin/zig |
| GHC | /usr/bin/ghc, /usr/bin/ghc-pkg |
| R | /usr/bin/R, /usr/bin/Rscript |
OpenJDK is the exception, and it is handled. A JDK is a self-contained tree rather than a set of loose binaries, so it installs under /opt — /opt/jdk-24.0.2+12/ — with a stable /opt/jdk symlink pointing at whichever version is current. Because /opt/jdk/bin is not on the default PATH, the package also installs /etc/profile.d/openjdk.sh, which adds it. The script is idempotent: it checks whether the directory is already on PATH before prepending it, so re-sourcing your profile does not accumulate duplicate entries.
That file is sourced by login shells, so:
# After installing openjdk, start a new login shell, or source it directly:
. /etc/profile.d/openjdk.sh
java -version
Modern Java needs neither JAVA_HOME nor CLASSPATH set for ordinary use, and the package deliberately does not set them.
If java is still not found after opening a fresh terminal, check in this order: that the package is installed (pkm list | grep openjdk), that /opt/jdk/bin/java exists, that /etc/profile.d/openjdk.sh exists, and that your shell is actually a login shell that reads /etc/profile.
A note on PATH and /opt generally
If a package installs a tree under /opt, something has to put that tree’s bin directory on your PATH or the commands are effectively invisible — you would have to know and type the /opt path yourself. The mechanism InterGenOS uses is a small script in /etc/profile.d/, which is what OpenJDK ships.
This is worth knowing as a general diagnostic habit rather than as a warning about these seven. If you ever install something and find its command missing while the files are clearly present on disk, look for whether a /etc/profile.d entry exists for it, and remember that such entries only take effect in a new login shell.
Building them yourself
All seven are ordinary InterGenOS packages with recipes in the package tree, so anything in Building Packages from Source applies to them unchanged. There is nothing special about their build definitions: a package.yml describing the package and a build.sh describing how it is compiled and installed.