aboutsummaryrefslogtreecommitdiffhomepage
path: root/internal/rosa/rosa.go
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2026-07-30 00:16:57 +0900
committerOphestra <cat@gensokyo.uk>2026-07-30 00:18:22 +0900
commit6487b41d922f56d46167802780fcde62d1f27095 (patch)
treea17e76fcb4cd790c3396a26960d45430672c0637 /internal/rosa/rosa.go
parent7908fb9583cb6af84345508390ec9ea9fc986763 (diff)
internal/rosa: remove legacy exec helper
This change also adds a fourth stage to the bootstrap machinery, offering more correct toolchain validation that works around LLVM dynamic linking flaws. Signed-off-by: Ophestra <cat@gensokyo.uk>
Diffstat (limited to 'internal/rosa/rosa.go')
-rw-r--r--internal/rosa/rosa.go254
1 files changed, 121 insertions, 133 deletions
diff --git a/internal/rosa/rosa.go b/internal/rosa/rosa.go
index 77dc1592..8287795d 100644
--- a/internal/rosa/rosa.go
+++ b/internal/rosa/rosa.go
@@ -121,6 +121,12 @@ const (
// Std denotes the standard Rosa OS toolchain.
Std
+ // Stage3 denotes the stage3 Rosa OS toolchain built on [Std]. Software
+ // built on this toolchain should be identical to [Std]. This is generally
+ // for validation of LLVM 3-stage nondeterminism only, due to dynamic
+ // linking complications.
+ Stage3
+
// _stageEnd is the total number of stages available and does not denote a
// valid toolchain.
_stageEnd
@@ -149,7 +155,7 @@ func (t Stage) isIntermediate() bool {
// isStd returns whether t is considered functionally equivalent to [Std].
func (t Stage) isStd() bool {
switch t {
- case stageStdGentoo, Std:
+ case stageStdGentoo, Std, Stage3:
return true
default:
return false
@@ -198,17 +204,6 @@ const scriptName = "all"
// build script under.
var absCureScript = AbsSystem.Append(scriptName)
-const (
- // TExclusive denotes an exclusive [pkg.Artifact].
- TExclusive = 1 << iota
- // TEarly hints for an early variant of toybox to be used when available.
- TEarly
- // TNoToolchain excludes the LLVM toolchain.
- TNoToolchain
- // THostNet arranges for a [pkg.KindExecNet] to be created.
- THostNet
-)
-
var (
_stage0Dist = H("stage0-dist")
_mksh = H("mksh")
@@ -218,102 +213,6 @@ var (
_patch = H("patch")
)
-// New returns a [pkg.Artifact] based on a [Toolchain] via s.
-func (t Toolchain) New(
- name string,
- flag int,
- extra []pkg.Artifact,
- knownChecksum *pkg.Checksum,
- env []string,
- script string,
-
- paths ...pkg.ExecPath,
-) pkg.Artifact {
- const lcMessages = "LC_MESSAGES=C.UTF-8"
-
- var support []pkg.Artifact
- switch t.stage {
- case stageGentoo, stageEarly:
- name += "-boot"
- support = append(support, extra...)
- support = append(support, NewEtc(true))
- if t.stage == stageEarly {
- _, a := t.MustLoad(_stage0Dist)
- support = append(support, a)
- } else if t.gentooStage3 == nil {
- panic(os.ErrInvalid)
- } else {
- support = append(support,
- t.gentooStage3,
- gentooOverlay{t.gentooStage3},
- )
- env = append(env,
- "CC=clang",
- "CXX=clang++",
- )
- }
- env = fixupEnviron(env, []string{
- EnvTriple + "=" + t.triple(),
- lcMessages,
- "LDFLAGS=" + t.earlyLDFLAGS(true),
- }, "/system/bin",
- "/usr/bin",
- )
-
- case stageIntermediateGentoo, stageStdGentoo,
- stageIntermediate, Std:
- if t.stage.isIntermediate() {
- name += "-std"
- }
-
- toybox := _toybox
- if flag&TEarly != 0 {
- toybox = _toyboxEarly
- }
-
- base := _llvm
- if flag&TNoToolchain != 0 {
- base = _musl
- }
-
- support = slices.Concat(extra, t.S.New(t.stage-1).Append([]pkg.Artifact{
- NewEtc(false),
- },
- base,
- _mksh,
- toybox,
- ))
- env = fixupEnviron(env, []string{
- EnvTriple + "=" + t.triple(),
- lcMessages,
- }, "/system/bin", "/bin")
-
- default:
- panic("unsupported toolchain " + strconv.Itoa(int(t.stage)))
- }
-
- return pkg.NewExec(
- name, t.arch, knownChecksum, pkg.ExecTimeoutMax,
- flag&THostNet != 0,
- flag&TExclusive != 0,
- fhs.AbsRoot, env,
- absCureScript,
- nil,
-
- slices.Concat([]pkg.ExecPath{pkg.Path(
- fhs.AbsRoot, true,
- support...,
- ), pkg.Path(
- absCureScript, false,
- pkg.NewFile(scriptName, []byte(
- "#!/system/bin/sh\n"+
- "set -eu -o pipefail\n"+
- script,
- )),
- )}, paths)...,
- )
-}
-
// HasStageEarly returns whether a stage0 distribution is available.
func (s *S) HasStageEarly() (ok bool) {
func() {
@@ -364,7 +263,7 @@ function apply {
}
}
- return t.NewPackage(name+"-src", Unversioned, nil, &PackageAttr{
+ return t.New(name+"-src", Unversioned, nil, &PackageAttr{
Paths: paths,
}, &GenericHelper{
Build: buf.String(),
@@ -379,7 +278,7 @@ const helperInPlace = "\x00"
// Helper is a build system helper for [Toolchain.NewPackage].
type Helper interface {
// extra returns helper-specific dependencies.
- extra(flag int) P
+ extra() P
// wantsChmod returns whether the source directory should be made writable.
wantsChmod() bool
@@ -421,12 +320,19 @@ type PackageAttr struct {
// Whether to replace /usr/bin/ with a symlink to /bin/.
PopulateUsrBin bool
+ // Hint for an early variant of toybox to be used when available.
+ Early bool
+ // Exclude the LLVM toolchain.
+ NoToolchain bool
+ // Whether the resulting [pkg.Artifact] is exclusive.
+ Exclusive bool
+ // Whether to create [pkg.KindExecNet] instead of [pkg.KindExec].
+ HostNet bool
+
// Unregistered extras.
Extra []pkg.Artifact
// Passed through to [Toolchain.New], before source.
Paths []pkg.ExecPath
- // Passed through to [Toolchain.New].
- Flag int
}
// pa holds whether an [ArtifactH] is present.
@@ -467,8 +373,8 @@ func (t Toolchain) Append(a []pkg.Artifact, handles ...ArtifactH) []pkg.Artifact
return a
}
-// NewPackage constructs a [pkg.Artifact] via a build system helper.
-func (t Toolchain) NewPackage(
+// New constructs a [pkg.Artifact] via a build system helper.
+func (t Toolchain) New(
name, version string,
source pkg.Artifact,
attr *PackageAttr,
@@ -486,25 +392,96 @@ func (t Toolchain) NewPackage(
if version != Unversioned {
rn = name + "-" + version
}
+
+ root := make([]pkg.Artifact, 0, 1<<3+len(attr.Extra)+len(extra))
+ root = append(root, attr.Extra...)
+
+ const lcMessages = "LC_MESSAGES=C.UTF-8"
+ srn := rn
+ env := slices.Clone(attr.Env)
+
+ var extraBoot []ArtifactH
+ switch t.stage {
+ case stageGentoo, stageEarly:
+ srn += "-boot"
+ root = append(root, NewEtc(true))
+ if t.stage == stageEarly {
+ extraBoot = append(extraBoot, _stage0Dist)
+ } else if t.gentooStage3 == nil {
+ panic(os.ErrInvalid)
+ } else {
+ env = append(env,
+ "CC=clang",
+ "CXX=clang++",
+ )
+ }
+ env = fixupEnviron(env, []string{
+ EnvTriple + "=" + t.triple(),
+ lcMessages,
+ "LDFLAGS=" + t.earlyLDFLAGS(true),
+ }, "/system/bin",
+ "/usr/bin",
+ )
+
+ case stageIntermediateGentoo, stageStdGentoo,
+ stageIntermediate, Std, Stage3:
+ if t.stage.isIntermediate() {
+ srn += "-std"
+ }
+
+ if t.stage == Stage3 {
+ srn += "-stage4"
+ }
+
+ toybox := _toybox
+ if attr.Early {
+ toybox = _toyboxEarly
+ }
+
+ base := _llvm
+ if attr.NoToolchain {
+ base = _musl
+ }
+
+ root = append(root, NewEtc(false))
+ extraBoot = append(extraBoot,
+ base,
+ _mksh,
+ toybox,
+ )
+ env = fixupEnviron(env, []string{
+ EnvTriple + "=" + t.triple(),
+ lcMessages,
+ }, "/system/bin", "/bin")
+
+ default:
+ panic("unsupported toolchain " + strconv.Itoa(int(t.stage)))
+ }
+
wantsChmod, wantsWrite := helper.wantsChmod(), helper.wantsWrite()
- extraRes := make([]pkg.Artifact, 0, 1<<3+len(attr.Extra)+len(extra))
- extraRes = append(extraRes, attr.Extra...)
{
pv := paGet()
- for _, p := range helper.extra(attr.Flag) {
- extraRes = t.appendHandle(extraRes, pv, p)
+ for _, p := range helper.extra() {
+ root = t.appendHandle(root, pv, p)
}
for _, p := range extra {
- extraRes = t.appendHandle(extraRes, pv, p)
+ root = t.appendHandle(root, pv, p)
+ }
+ boot := t.S.New(t.stage - 1)
+ for _, p := range extraBoot {
+ root = boot.appendHandle(root, pv, p)
}
paPut(pv)
}
- var (
- scriptEarly string
- sourceSuffix string
- )
+ if t.stage == stageGentoo {
+ root = append(root,
+ t.gentooStage3,
+ gentooOverlay{t.gentooStage3},
+ )
+ }
+ var scriptEarly string
dir, create := helper.wantsDir()
helperScriptEarly := helper.scriptEarly()
if attr.EnterSource ||
@@ -529,7 +506,7 @@ cd '/usr/src/` + name + `/'
if source != nil {
paths = slices.Concat(attr.Paths, []pkg.ExecPath{
pkg.Path(AbsUsrSrc.Append(
- name+sourceSuffix,
+ name,
), attr.Writable || wantsWrite, t.NewPatchedSource(
rn, source, !attr.Chmod && !wantsChmod, attr.Patches...,
)),
@@ -556,14 +533,25 @@ ln -s ../bin /usr/`
scriptEarly += " /bin/)\n"
}
- return t.New(
- rn,
- attr.Flag,
- extraRes,
- attr.KnownChecksum,
- attr.Env,
- scriptEarly+helper.script(t, name),
- paths...,
+ return pkg.NewExec(
+ srn, t.arch, attr.KnownChecksum, pkg.ExecTimeoutMax,
+ attr.HostNet,
+ attr.Exclusive,
+ fhs.AbsRoot, env,
+ absCureScript,
+ nil,
+
+ slices.Concat([]pkg.ExecPath{pkg.Path(
+ fhs.AbsRoot, true,
+ root...,
+ ), pkg.Path(
+ absCureScript, false,
+ pkg.NewFile(scriptName, []byte(
+ "#!/system/bin/sh\n"+
+ "set -eu -o pipefail\n"+
+ scriptEarly+helper.script(t, name),
+ )),
+ )}, paths)...,
)
}
@@ -581,7 +569,7 @@ type GenericHelper struct {
var _ Helper = new(GenericHelper)
// extra is a noop.
-func (*GenericHelper) extra(int) P { return nil }
+func (*GenericHelper) extra() P { return nil }
// wantsChmod returns false.
func (*GenericHelper) wantsChmod() bool { return false }