aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2026-02-10 21:24:25 +0900
committerOphestra <cat@gensokyo.uk>2026-02-10 22:31:08 +0900
commit0061d11f939157e181a908f50b0ffb4c991e0375 (patch)
treefc611a4624f1a13951a17e38aead148214a7a62b
parentfb101a02f21d048515561659b06bfc2a35568c56 (diff)
internal/rosa: use self-hosted stage0
This removes the bootstrap dependency on Gentoo stage3 tarball. Signed-off-by: Ophestra <cat@gensokyo.uk>
-rw-r--r--cmd/mbf/main.go34
-rw-r--r--internal/rosa/rosa.go90
-rw-r--r--internal/rosa/stage0.go36
3 files changed, 125 insertions, 35 deletions
diff --git a/cmd/mbf/main.go b/cmd/mbf/main.go
index 83bb6714..9828a8f1 100644
--- a/cmd/mbf/main.go
+++ b/cmd/mbf/main.go
@@ -111,15 +111,31 @@ func main() {
{
var (
+ flagGentoo string
+ flagChecksum string
+
flagStage0 bool
)
c.NewCommand(
"stage3",
"Check for toolchain 3-stage non-determinism",
func(args []string) (err error) {
- _, _, _, stage1 := (rosa.Std - 2).NewLLVM()
- _, _, _, stage2 := (rosa.Std - 1).NewLLVM()
- _, _, _, stage3 := rosa.Std.NewLLVM()
+ std := rosa.Std
+ if flagGentoo != "" {
+ std -= 3 // magic number to discourage misuse
+
+ var checksum pkg.Checksum
+ if len(flagChecksum) != 0 {
+ if err = pkg.Decode(&checksum, flagChecksum); err != nil {
+ return
+ }
+ }
+ rosa.SetGentooStage3(flagGentoo, checksum)
+ }
+
+ _, _, _, stage1 := (std - 2).NewLLVM()
+ _, _, _, stage2 := (std - 1).NewLLVM()
+ _, _, _, stage3 := std.NewLLVM()
var (
pathname *check.Absolute
checksum [2]unique.Handle[pkg.Checksum]
@@ -153,7 +169,7 @@ func main() {
if flagStage0 {
if pathname, _, err = cache.Cure(
- rosa.Std.Load(rosa.Stage0),
+ std.Load(rosa.Stage0),
); err != nil {
return err
}
@@ -164,6 +180,16 @@ func main() {
},
).
Flag(
+ &flagGentoo,
+ "gentoo", command.StringFlag(""),
+ "Bootstrap from a Gentoo stage3 tarball",
+ ).
+ Flag(
+ &flagChecksum,
+ "checksum", command.StringFlag(""),
+ "Checksum of Gentoo stage3 tarball",
+ ).
+ Flag(
&flagStage0,
"stage0", command.BoolFlag(false),
"Create bootstrap stage0 tarball",
diff --git a/internal/rosa/rosa.go b/internal/rosa/rosa.go
index b82b09a8..e9e720fa 100644
--- a/internal/rosa/rosa.go
+++ b/internal/rosa/rosa.go
@@ -2,6 +2,7 @@
package rosa
import (
+ "errors"
"log"
"runtime"
"slices"
@@ -101,9 +102,23 @@ func earlyCXXFLAGS() string {
type Toolchain uintptr
const (
- // toolchainBusybox denotes a busybox installation from the busyboxBin
- // binary distribution. This is for decompressing unsupported formats.
- toolchainBusybox Toolchain = iota
+ // _toolchainBusybox denotes a busybox installation from the busyboxBin
+ // binary distribution. This is defined as a toolchain to make use of the
+ // toolchain abstractions to preprocess toolchainGentoo and is not a real,
+ // functioning toolchain. It does not contain any compilers.
+ _toolchainBusybox Toolchain = iota
+
+ // toolchainGentoo denotes the toolchain in a Gentoo stage3 tarball. Special
+ // care must be taken to compile correctly against this toolchain.
+ toolchainGentoo
+
+ // toolchainIntermediateGentoo is like to toolchainIntermediate, but
+ // compiled against toolchainGentoo.
+ toolchainIntermediateGentoo
+
+ // toolchainStdGentoo is like Std, but bootstrapped from toolchainGentoo.
+ // This toolchain creates the first [Stage0] distribution.
+ toolchainStdGentoo
// toolchainStage0 denotes the stage0 toolchain. Special care must be taken
// to compile correctly against this toolchain.
@@ -125,7 +140,7 @@ const (
// stage0Concat concatenates s and values. If the current toolchain is
// toolchainStage0, stage0Concat returns s as is.
func stage0Concat[S ~[]E, E any](t Toolchain, s S, values ...E) S {
- if t == toolchainStage0 {
+ if t == toolchainStage0 || t == toolchainGentoo {
return s
}
return slices.Concat(s, values)
@@ -134,7 +149,7 @@ func stage0Concat[S ~[]E, E any](t Toolchain, s S, values ...E) S {
// stage0ExclConcat concatenates s and values. If the current toolchain is not
// toolchainStage0, stage0ExclConcat returns s as is.
func stage0ExclConcat[S ~[]E, E any](t Toolchain, s S, values ...E) S {
- if t == toolchainStage0 {
+ if t == toolchainStage0 || t == toolchainGentoo {
return slices.Concat(s, values)
}
return s
@@ -182,6 +197,25 @@ const (
TEarly
)
+var (
+ // gentooStage3 is the url of a Gentoo stage3 tarball.
+ gentooStage3 string
+ // gentooStage3Checksum is the expected checksum of gentooStage3.
+ gentooStage3Checksum pkg.Checksum
+)
+
+// SetGentooStage3 sets the Gentoo stage3 tarball url and checksum. It panics
+// if given zero values or if these values have already been set.
+func SetGentooStage3(url string, checksum pkg.Checksum) {
+ if gentooStage3 != "" {
+ panic(errors.New("attempting to set Gentoo stage3 url twice"))
+ }
+ if url == "" {
+ panic(errors.New("attempting to set Gentoo stage3 url to the zero value"))
+ }
+ gentooStage3, gentooStage3Checksum = url, checksum
+}
+
// New returns a [pkg.Artifact] compiled on this toolchain.
func (t Toolchain) New(
name string,
@@ -197,49 +231,45 @@ func (t Toolchain) New(
var support []pkg.Artifact
switch t {
- case toolchainBusybox:
+ case _toolchainBusybox:
name += "-early"
support = slices.Concat([]pkg.Artifact{newBusyboxBin()}, extra)
env = fixupEnviron(env, nil, "/system/bin")
- case toolchainStage0:
+ case toolchainGentoo, toolchainStage0:
name += "-boot"
- var seed string
- switch runtime.GOARCH {
- case "amd64":
- seed = "c5_FwMnRN8RZpTdBLGYkL4RR8ampdaZN2JbkgrFLe8-QHQAVQy08APVvIL6eT7KW"
- case "arm64":
- seed = "79uRbRI44PyknQQ9RlFUQrwqplup7vImiIk6klefL8TN-fT42TXMS_v4XszwexCb"
-
- default:
- panic("unsupported target " + runtime.GOARCH)
- }
- support = slices.Concat([]pkg.Artifact{
- cureEtc{},
- toolchainBusybox.New("stage0", 0, nil, nil, nil, `
-tar -C /work -xf /usr/src/stage0.tar.xz
+ support = append(support, cureEtc{})
+ if t == toolchainStage0 {
+ support = append(support, NewStage0())
+ } else {
+ support = append(support, _toolchainBusybox.New("gentoo", 0, nil, nil, nil, `
+tar -C /work -xf /usr/src/stage3.tar.xz
rm -rf /work/dev/ /work/proc/
ln -vs ../usr/bin /work/bin
mkdir -vp /work/system/bin
-ln -vs ../../bin/sh /work/system/bin
-`, pkg.Path(AbsUsrSrc.Append("stage0.tar.xz"), false,
+(cd /work/system/bin && ln -vs \
+ ../../bin/sh \
+ ../../usr/lib/llvm/*/bin/* \
+ .)
+`, pkg.Path(AbsUsrSrc.Append("stage3.tar.xz"), false,
pkg.NewHTTPGet(
- nil, "https://basement.gensokyo.uk/seed/"+seed,
- mustDecode(seed),
+ nil, gentooStage3,
+ gentooStage3Checksum,
),
- )),
- }, extra)
+ )))
+ }
+ support = slices.Concat(support, extra)
env = fixupEnviron(env, []string{
EnvTriplet + "=" + triplet(),
lcMessages,
"LDFLAGS=" + earlyLDFLAGS(true),
}, "/system/bin",
"/usr/bin",
- "/usr/lib/llvm/21/bin",
)
- case toolchainIntermediate, Std:
- if t < Std {
+ case toolchainIntermediateGentoo, toolchainStdGentoo,
+ toolchainIntermediate, Std:
+ if t == toolchainIntermediateGentoo || t == toolchainIntermediate {
name += "-std"
}
diff --git a/internal/rosa/stage0.go b/internal/rosa/stage0.go
index 7b347255..faa25e37 100644
--- a/internal/rosa/stage0.go
+++ b/internal/rosa/stage0.go
@@ -1,6 +1,11 @@
package rosa
-import "hakurei.app/internal/pkg"
+import (
+ "runtime"
+ "sync"
+
+ "hakurei.app/internal/pkg"
+)
func (t Toolchain) newStage0() pkg.Artifact {
musl, compilerRT, runtimes, clang := t.NewLLVM()
@@ -37,3 +42,32 @@ tar \
`)
}
func init() { artifactsF[Stage0] = Toolchain.newStage0 }
+
+var (
+ // stage0 stores the tarball unpack artifact.
+ stage0 pkg.Artifact
+ // stage0Once is for lazy initialisation of stage0.
+ stage0Once sync.Once
+)
+
+// NewStage0 returns a stage0 distribution created from curing [Stage0].
+func NewStage0() pkg.Artifact {
+ stage0Once.Do(func() {
+ var seed string
+ switch runtime.GOARCH {
+ case "amd64":
+ seed = "tqM1Li15BJ-uFG8zU-XjgFxoN_kuzh1VxrSDVUVa0vGmo-NeWapSftH739sY8EAg"
+
+ default:
+ panic("unsupported target " + runtime.GOARCH)
+ }
+
+ stage0 = pkg.NewHTTPGetTar(
+ nil, "https://hakurei.app/seed/20260210/"+
+ "stage0-"+triplet()+".tar.bz2",
+ mustDecode(seed),
+ pkg.TarBzip2,
+ )
+ })
+ return stage0
+}