diff options
| author | Ophestra <cat@gensokyo.uk> | 2026-07-30 00:16:57 +0900 |
|---|---|---|
| committer | Ophestra <cat@gensokyo.uk> | 2026-07-30 00:18:22 +0900 |
| commit | 6487b41d922f56d46167802780fcde62d1f27095 (patch) | |
| tree | a17e76fcb4cd790c3396a26960d45430672c0637 /internal/rosa/rosa.go | |
| parent | 7908fb9583cb6af84345508390ec9ea9fc986763 (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.go | 254 |
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 } |
