aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2026-10-31 19:28:15 +0900
committerOphestra <cat@gensokyo.uk>2026-10-31 23:47:47 +0900
commitaed48ee842aedf792e15b3818db73429ac823d66 (patch)
tree1a069044e4b1e519ca8678e1a589f277cc6613d5
parent609a5bee539e82b18d799d00dc7ce374f5edc41b (diff)
internal/rosa: document toolchains and azalea
This is quite difficult to figure out just from reading source code. This change documents as much of azalea as possible, excluding some fields intended for internal use only. Signed-off-by: Ophestra <cat@gensokyo.uk>
-rw-r--r--internal/rosa/doc.go549
-rw-r--r--internal/rosa/rosa.go1
2 files changed, 549 insertions, 1 deletions
diff --git a/internal/rosa/doc.go b/internal/rosa/doc.go
new file mode 100644
index 00000000..9c61a751
--- /dev/null
+++ b/internal/rosa/doc.go
@@ -0,0 +1,549 @@
+/*
+Package rosa implements the Rosa OS build system via package [hakurei.app/pkg].
+
+Software packages required by the Rosa OS base system are included in the
+package directory. By default, these built-in packages are embedded at compile
+time. The penv build tag may be used to specify the pathname of the source code
+of this package at runtime via the environment variable ROSA_SOURCE. Note that
+changes to Go code still requires recompilation.
+
+Software packages not part of the Rosa OS base system must not be added to
+the built-in package directory. Additional Azalea source code may be registered
+using the [S.RegisterAzalea] function in a new instance of [S]. The
+[Rosa OS packages repository] is a good place to put additional packages.
+
+# Native artifacts
+
+Package rosa implements custom [hakurei.app/pkg] artifacts. This package must
+not be used alongside other packages also implementing custom artifacts. As a
+protection against simple cases of this, importing this package sets the
+extension variant identification string to [Extension].
+
+# Toolchain stages
+
+Rosa OS has three kinds of toolchain stages, with two sets of each and an
+additional [Stage3] final stage. This adds up to a total of seven stages,
+however not all of them are normally used.
+
+Every Rosa OS package is rooted in a binary seed containing at least a
+shell and a LLVM toolchain. The early stage, a stage where the unexported
+isStage0 method returns true, provides an environment from this binary seed
+using only native artifacts. This stage does not support many fields of the
+[PackageAttr] structure or [Helper] primitives. Special care must be taken for
+packages compiled against this toolchain.
+
+The intermediate stage (where the unexported isIntermediate method returns true)
+and the std stage (where the unexported isStd method returns true) are
+functionally identical. They support all [PackageAttr] fields and [Helper]
+primitives. The purpose of the intermediate stage is to complete a 3-stage
+bootstrap for the mksh shell and LLVM toolchain.
+
+The final [Stage3] toolchain should generally only be used to validate 3-stage
+determinism of the LLVM toolchain itself, by building a fourth LLVM stage. This
+works around deficiencies in the CMake-based build system of the LLVM project
+when compiling a dynamically-linked LLVM toolchain against a dynamically-linked
+host LLVM toolchain.
+
+The set of Gentoo-derived toolchains are rooted in a Gentoo Linux stage3
+tarball. These are for completing the 3-stage bootstrap of the initial Rosa OS
+stage0 toolchain distribution only and is never used again. This bootstrap
+path might become broken from time to time. Historically, this is also required
+when bootstrapping a completely new architecture, however that is now done via
+cross-compilation, so the Gentoo bootstrap path is no longer invoked. The
+unexported isRosa method returns whether a toolchain is not rooted in Gentoo.
+
+# Declaring packages
+
+Rosa OS packages are described using the Azalea language. Packages must be
+declared at the top level:
+
+ package hakurei-source {
+ // short user-facing description, included in package metadata
+ description = "hakurei source tree";
+ // whether to exclude from listings in exported functions
+ exclude = true;
+
+ // package version, # adds it to the current scope; if source is set and
+ // refers to a package declared at the top level, this defaults to the
+ // version of that package
+ version# = "0.4.10";
+
+ // a non-nil output artifact bypasses the build system
+ output = remoteGit {
+ url = "https://src.rosa.moe/hakurei";
+ // using the version variable previously added to the scope
+ tag = "v"+version;
+ checksum = "SZdto_lQCgwebCqUHJREQcHwwO1pHn3euOwFvXYEri0G-46zUhx0hX4buFt2XvkS";
+ };
+ }
+
+ package hakurei-dist {
+ // short user-facing description, included in package metadata
+ description = "low-level userspace tooling for Rosa OS "+
+ "(distribution tarball)";
+
+ // project home page, included in package metadata
+ website = "https://hakurei.app";
+
+ // project identifier on release-monitoring.org, to check for updates
+ anitya = 388834;
+
+ // if non-empty, provides a maintainer-facing reason of blocked update
+ // and prevent checking for updates via anitya
+ block = "";
+
+ // if non-nil, overrides the version filtering function
+ latest = anityaFallback;
+
+ // artifact containing the source tree, placed in /usr/src/ under a
+ // directory named after the package, see section "Source fetchers";
+ // this can also refer to a package declared at the top level like done
+ // here
+ source = hakurei-source;
+
+ // pathnames of patches to apply to source, relative to the Azalea file;
+ // must be within the base directory
+ patches = [];
+
+ // unconditionally enter source directory early
+ enterSource = true;
+
+ // allow writes to the source tree, with all writes going to an
+ // anonymous instance of tmpfs
+ writable = true;
+
+ // make all files writable in the source tree
+ chmod = true;
+
+ // additional files to make available, relative to the Azalea file,
+ // within the base directory
+ files = {
+ // specifying a relative pathname places the file in /usr/src/ under
+ // the specified name
+ ".config": arch+".config";
+
+ // specifying an absolute pathname places the file at the specified
+ // pathname as is
+ "/sbin/installkernel": "installkernel";
+ // if the contents of the file begins with certain sequences of
+ // bytes, it is automatically made executable
+ "/sbin/depmod": "depmod";
+
+ // prefix is the Rosa OS installation prefix, with the leading path
+ // separator
+ prefix+"/oldconfig": "oldconfig";
+ };
+
+ // whether the resulting artifact dodges all other artifacts with this
+ // field set when being scheduled to cure
+ exclusive = false;
+
+ // whether the build process does not require the LLVM toolchain
+ minimal = false;
+
+ // whether this package is allowed in bootstrap stages
+ bootstrap = true;
+
+ // whether this package requires libc; defaults to true
+ libc = true;
+
+ // additional environment variables
+ env = [
+ "CGO_ENABLED=1",
+ "GOCACHE=/tmp/gocache",
+ "CC=clang -O3 -Werror",
+ ];
+
+ // runs before script emitted by exec, implies enterSource if non-empty
+ early = "";
+
+ // programs to make available in /bin/
+ bin = [ "hostname" ];
+
+ // whether to replace /usr/bin/ with a symlink to /bin/
+ populateUsrBin = false;
+
+ // build system helper, see section "Build system helpers"
+ exec = generic {
+ chdir = false;
+ cross = `
+ export HAKUREI_ARCH='`+arch+`'
+ export HAKUREI_SYSROOT='`+prefix+`/`+arch+`'
+
+ export PKG_CONFIG_SYSROOT_DIR='`+prefix+`/`+arch+`'
+ export PKG_CONFIG_LIBDIR='`+prefix+`/`+arch+prefix+`/lib/pkgconfig:`+
+ prefix+`/`+arch+``+prefix+`/share/pkgconfig'
+ `;
+ build = `
+ NAME=make`;
+ check = `
+ NAME=all`;
+ install = `
+ DESTDIR=/work "./${NAME}.sh"
+ `;
+ };
+
+ // if non-nil, measures the outcome of the package and fails if it does
+ // not match the specified checksum value
+ checksum = nil;
+
+ // native utilities used during the build
+ tools = [
+ go,
+ pkgconf,
+ net-tools,
+ acl,
+ wayland,
+ wayland-protocols,
+ ];
+
+ // packages made available for the target architecture, in the cross
+ // sysroot if cross-compiling
+ inputs = [
+ libseccomp,
+ acl,
+ fuse,
+ xcb,
+ wayland,
+ wayland-protocols,
+ util-linux,
+ kernel-headers,
+ ];
+
+ // additional packages to place under directories named after each
+ // package in /usr/src/
+ extra = [];
+
+ // if non-empty, packages specified in extra are overlay-mounted under
+ // this pathname instead
+ overlay = "";
+
+ // inputs made available only during cross-compilation; setting this to
+ // nil indicates that this package does not require cross-compilation
+ // because its outcome is identical regardless of the target
+ cross = [];
+
+ // native utilities made available only during cross-compilation
+ native = [];
+
+ // whether explicitly specified runtime dependencies are combined with
+ // resolved runtimes instead of overriding it
+ join = false;
+
+ // runtime dependencies, resolved from inputs if unset
+ runtime = nil;
+
+ // whether this package is unlikely to become a runtime dependency
+ unlikely = true;
+ }
+
+# Built-in constants
+
+ prefix Rosa OS installation prefix
+ prefixR Rosa OS installation prefix relative to sysroot
+ unversioned special version string denoting an unversioned package
+
+ hostTriple Rosa OS host triple of the current system
+ hostArch architecture target name of the current system
+ hostLinuxArch architecture name used by Linux for the current system
+
+ triple Rosa OS host triple of the target system
+ arch architecture target name of the target system
+ linuxArch architecture name used by Linux for the target system
+ llvmArch architecture name used by LLVM for the target system
+
+ jobsE expression for preferred job count
+ jobsFlagE expression for flag with preferred job count (such as -j8)
+ jobsLE expression for twice of preferred job count
+ jobsLFlagE expression for flag with twice of preferred job count (such
+ as -j16)
+
+ loadE expression for preferred loadavg target
+ loadFlagE expression for flag with preferred loadavg target (such as
+ -l9)
+
+ anityaFallback version filter function pointer, returns the first stable
+ version, or latest if that is unavailable
+
+# Library functions
+
+replace returns a copy of the string s with the first n non-overlapping
+instances of old replaced by new. If old is empty, it matches at the beginning
+of the string and after each UTF-8 sequence, yielding up to k+1 replacements for
+a k-rune string. If n == 0, there is no limit on the number of replacements.
+
+ replace {
+ s = "2.9.0";
+ old = ".";
+ new = "_";
+ n = 2;
+ }
+ // returns "2_9_0"
+
+slice returns a subslice of elems.
+
+ slice {
+ elems = split {
+ s = "2.42.4";
+ sep = ".";
+ n = 3;
+ };
+ start = 0;
+ end = 2;
+ }
+ // returns [ "2", "42" ]
+
+join concatenates elems to create a single string. The separator string sep is
+placed between elements in the resulting string.
+
+ join {
+ elems = slice {
+ elems = split {
+ s = "2.42.4";
+ sep = ".";
+ n = 3;
+ };
+ end = 2;
+ };
+ sep = ".";
+ }
+ // returns "2.42"
+
+arch returns the value specified for the identifier referring to the target
+architecture. As a special case, the cross identifier is matched if currently
+cross-compiling, and the target architecture did not match any value specified
+before the cross identifier.
+
+ arch {
+ cross = unset;
+ default = arch;
+
+ amd64 = "x86";
+ ppc64le = "powerpc";
+ riscv64 = "riscv";
+ }
+
+# Source fetchers
+
+remoteTar reads an (optionally compressed) tar stream from url and unpacks its
+contents. It is a cure error if the checksum of the full stream read until EOF
+from url does not match the specified checksum.
+
+ remoteTar {
+ url = "https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-"+version+".tar.gz";
+ checksum = "e-OfydG1EoUUuOCLHZn2XXt1h3ONKo9fg67IAcYSfU-3c8HrBXJ259AtdC8CZdk0";
+
+ // available decompressors: gzip, bzip2, zstd
+ //
+ // defaults to uncompressed
+ compress = gzip;
+ };
+
+remoteFile reads the stream from url until EOF. It is a cure error if the
+checksum of the full stream read from url does not match the specified checksum.
+
+ remoteFile {
+ url = "https://web.archive.org/web/"+version+"id_/"+
+ "https://www.iana.org/assignments/enterprise-numbers.txt";
+ checksum = "IplVyf7P4PDhhDovWCzL6jPGmF0T75InOCv2IOTMoR7khHUcRfki1pY93kobuXHF";
+ };
+
+remoteGit downloads a remote git repository using the git package. It is a cure
+error if the checksum of the [hakurei.app/pkg] archive of the resulting
+directory does not match the specified checksum.
+
+ output = remoteGit {
+ url = "https://src.rosa.moe/hakurei";
+ tag = "v"+version;
+ checksum = "SZdto_lQCgwebCqUHJREQcHwwO1pHn3euOwFvXYEri0G-46zUhx0hX4buFt2XvkS";
+ };
+
+remoteGitLab downloads the specified ref from a GitLab instance. It is a cure
+error if the checksum of the compressed tar stream read from the GitLab instance
+does not match the specified checksum.
+
+ remoteGitLab {
+ domain = "gitlab.freedesktop.org";
+ suffix = "wayland/wayland";
+ ref = version;
+ checksum = "79UJi1LDcQBoYl_yR7Jnt3OXptvyklTdJB7GZIeF_Zb0q0ETQRBp5RqsltdZOTAp";
+ };
+
+remoteGitHub downloads the specified tag from Microsoft Github. It is a cure
+error if the checksum of the compressed tar stream read from Microsoft Github
+does not match the specified checksum.
+
+ remoteGitHub {
+ suffix = "nss-dev/nss";
+ tag = "NSS_"+join {
+ elems = split {
+ s = version;
+ sep = ".";
+ n = 3;
+ };
+ sep = "_";
+ }+"_RTM";
+ checksum = "GBkrmgdeEjvmLuWq6_EX5nkfebL4ojBE0yHsBgeijX7cnoLA5aOY2Z-GIolJwFy_";
+ };
+
+# Build system helpers
+
+generic directly passes build script segments for invocations of one-off build
+scripts too specific to fit into any other [Helper] implementation.
+
+ generic {
+ // whether to enter a newly created work directory; defaults to true
+ chdir = false;
+
+ // runs only if cross-compiling
+ cross = `
+ export HAKUREI_ARCH='`+arch+`'
+ export HAKUREI_SYSROOT='`+prefix+`/`+arch+`'
+
+ export PKG_CONFIG_SYSROOT_DIR='`+prefix+`/`+arch+`'
+ export PKG_CONFIG_LIBDIR='`+prefix+`/`+arch+prefix+`/lib/pkgconfig:`+
+ prefix+`/`+arch+``+prefix+`/share/pkgconfig'
+ `;
+
+ // runs first, or after cross if cross-compiling
+ build = `
+ NAME=make`;
+
+ // runs after build, if testing is enabled
+ check = `
+ NAME=all`;
+
+ // runs after build and check
+ install = `
+ DESTDIR=/work "./${NAME}.sh"
+ `;
+ }
+
+make wraps the make program and optionally an autotools-generated build system.
+
+ make {
+ // whether to enter a newly created work directory; defaults to true
+ chdir = true;
+
+ // command to generate the build system if non-empty
+ generate = "";
+
+ // runs before configure
+ preConfigure = "";
+
+ // cross targets to pass to the configure script, the zero value passes
+ // the Rosa OS target triples, the string `""` causes the corresponding
+ // flag(s) to be omitted
+ host, build = "";
+
+ // whether to let autotools infer the target triple
+ autoTarget = false;
+
+ // whether to pass sysroot pathname to the configure script, defaults
+ // to true
+ sysroot = true;
+
+ // do not clear program prefix/suffix
+ defaultName = false;
+
+ // alternative name for the configure script if non-empty
+ configureName = "";
+
+ // generate autoconf arguments regardless of configureName
+ forceAutoconf = false;
+
+ // flags passed to the configure script
+ configure = {
+ "disable-multilib";
+ "enable-default-pie";
+ "disable-nls";
+ "with-gnu-as";
+ "with-gnu-ld";
+ "with-system-zlib";
+ "enable-languages": "c,c++,go";
+ "with-native-system-header-dir": prefix+"/include";
+
+ "with-multilib-list": arch {
+ amd64, arm64 = "''";
+ };
+ };
+
+ // runs before make
+ preMake = "";
+
+ // additional make arguments
+ make = [
+ "BOOT_CFLAGS='-O2 -g'",
+ "bootstrap",
+ ];
+
+ // runs before check
+ preCheck = "";
+
+ // replaces the check arguments if non-empty
+ check = nil;
+
+ // replaces the default install command if non-empty
+ install = "";
+ };
+
+cmake builds and tests a CMake project with specified CACHE entries.
+
+ cmake {
+ // path elements joined with source
+ append = [ "compiler-rt/lib/builtins" ];
+
+ // CMake CACHE entries
+ cache = {
+ "LLVM_HOST_TRIPLE": triple;
+ "LLVM_ENABLE_RTTI": "ON";
+ "LLVM_BUILD_LLVM_DYLIB": "ON";
+ "LLVM_LINK_LLVM_DYLIB": "ON";
+ "LLVM_ENABLE_PER_TARGET_RUNTIME_DIR": "ON";
+
+ "COMPILER_RT_DEFAULT_TARGET_ONLY": "ON";
+ };
+
+ // runs after install
+ postInstall = "";
+
+ // replaces the default test command if non-empty; explicitly setting
+ // this to nil disables testing entirely
+ test = nil;
+ };
+
+meson builds and tests a meson project.
+
+ meson {
+ // whether to use muon instead of meson
+ muon = false;
+
+ // -D flags passed to the setup command
+ setup = {
+ "default_library": "both";
+ "documentation": "false";
+ "tests": "true";
+ };
+
+ // runs after setup
+ preCompile = "";
+
+ // runs after compile
+ postCompile = "";
+
+ // whether to run the test suite; defaults to true
+ test = true;
+
+ // names of test suites to skip
+ skipTests = [];
+
+ // whether to run tests with interactive input/output
+ interactiveTest = false;
+
+ // runs after install
+ postInstall = "";
+ };
+
+[Rosa OS packages repository]: https://src.rosa.moe/packages
+*/
+package rosa
diff --git a/internal/rosa/rosa.go b/internal/rosa/rosa.go
index 71755ef9..c50a7efe 100644
--- a/internal/rosa/rosa.go
+++ b/internal/rosa/rosa.go
@@ -1,4 +1,3 @@
-// Package rosa provides Rosa OS toolchain artifacts and miscellaneous software.
package rosa
import (