diff options
| author | Ophestra <cat@gensokyo.uk> | 2026-01-19 02:27:45 +0900 |
|---|---|---|
| committer | Ophestra <cat@gensokyo.uk> | 2026-01-19 02:29:06 +0900 |
| commit | 7f3d1d6375278377ca0b179436a9079add1722ce (patch) | |
| tree | 942cc079b3c4f1909e02b29f67108a0f1a730b3e /internal | |
| parent | 3a4f20b759bc9c8315320d27fc308bb75d2150a3 (diff) | |
internal/rosa: llvm artifact abstraction
The llvm bootstrap is multi-stage by nature, and cannot be completed in a single artifact.
Signed-off-by: Ophestra <cat@gensokyo.uk>
Diffstat (limited to 'internal')
| -rw-r--r-- | internal/rosa/llvm.go | 191 |
1 files changed, 191 insertions, 0 deletions
diff --git a/internal/rosa/llvm.go b/internal/rosa/llvm.go new file mode 100644 index 00000000..e3eccc80 --- /dev/null +++ b/internal/rosa/llvm.go @@ -0,0 +1,191 @@ +package rosa + +import ( + "slices" + "strconv" + "strings" + + "hakurei.app/container/check" + "hakurei.app/internal/pkg" +) + +// llvmAttr holds the attributes that will be applied to a new [pkg.Artifact] +// containing a LLVM variant. +type llvmAttr struct { + flags int + + // Concatenated with default environment for CMakeAttr.Env. + env []string + // Concatenated with generated entries for CMakeAttr.Cache. + cmake [][2]string + // Override CMakeAttr.Append. + append []string + // Concatenated with default dependencies for CMakeAttr.Extra. + extra []pkg.Artifact + // Concatenated with default fixup for CMakeAttr.Script. + script string + // Passed through to CMakeAttr.Prefix. + prefix *check.Absolute +} + +const ( + llvmProjectClang = 1 << iota + llvmProjectLld + + llvmProjectAll = 1<<iota - 1 + + llvmRuntimeCompilerRT = 1 << iota + llvmRuntimeLibunwind + llvmRuntimeLibc + llvmRuntimeLibcxx + llvmRuntimeLibcxxABI + + llvmAll = 1<<iota - 1 + llvmRuntimeAll = llvmAll - (2 * llvmProjectAll) - 1 +) + +// llvmFlagName resolves a llvmAttr.flags project or runtime flag to its name. +func llvmFlagName(flag int) string { + switch flag { + case llvmProjectClang: + return "clang" + case llvmProjectLld: + return "lld" + + case llvmRuntimeCompilerRT: + return "compiler-rt" + case llvmRuntimeLibunwind: + return "libunwind" + case llvmRuntimeLibc: + return "libc" + case llvmRuntimeLibcxx: + return "libcxx" + case llvmRuntimeLibcxxABI: + return "libcxxabi" + + default: + panic("invalid flag " + strconv.Itoa(flag)) + } +} + +// newLLVM returns a [pkg.Artifact] containing a LLVM variant. +func (t Toolchain) newLLVM(variant string, attr *llvmAttr) pkg.Artifact { + const ( + version = "21.1.8" + checksum = "8SUpqDkcgwOPsqHVtmf9kXfFeVmjVxl4LMn-qSE1AI_Xoeju-9HaoPNGtidyxyka" + ) + if attr == nil { + panic("LLVM attr must be non-nil") + } + + var projects, runtimes []string + for i := 1; i < llvmProjectAll; i <<= 1 { + if attr.flags&i != 0 { + projects = append(projects, llvmFlagName(i)) + } + } + for i := (llvmProjectAll + 1) << 1; i < llvmRuntimeAll; i <<= 1 { + if attr.flags&i != 0 { + runtimes = append(runtimes, llvmFlagName(i)) + } + } + + var script, scriptEarly string + + cache := [][2]string{ + {"CMAKE_BUILD_TYPE", "Release"}, + + {"LLVM_HOST_TRIPLE", `"${ROSA_TRIPLE}"`}, + {"LLVM_DEFAULT_TARGET_TRIPLE", `"${ROSA_TRIPLE}"`}, + } + if len(projects) > 0 { + cache = append(cache, + [2]string{"LLVM_ENABLE_PROJECTS", `"${ROSA_LLVM_PROJECTS}"`}) + } + if len(runtimes) > 0 { + cache = append(cache, + [2]string{"LLVM_ENABLE_RUNTIMES", `"${ROSA_LLVM_RUNTIMES}"`}) + } + + cmakeAppend := []string{"llvm"} + if attr.append != nil { + cmakeAppend = attr.append + } else { + cache = append(cache, + [2]string{"LLVM_ENABLE_LIBCXX", "ON"}, + [2]string{"LLVM_USE_LINKER", "lld"}, + + [2]string{"LLVM_INSTALL_BINUTILS_SYMLINKS", "ON"}, + [2]string{"LLVM_INSTALL_CCTOOLS_SYMLINKS", "ON"}, + ) + } + + extra := []pkg.Artifact{ + t.NewPython(), + t.NewKernelHeaders(), + } + if t == toolchainStage3 { + extra = nil + } + + if attr.flags&llvmProjectClang != 0 { + cache = append(cache, + [2]string{"CLANG_DEFAULT_CXX_STDLIB", "libc++"}, + [2]string{"CLANG_DEFAULT_RTLIB", "compiler-rt"}, + ) + } + if attr.flags&llvmProjectLld != 0 { + script += ` +ln -s ld.lld /work/system/bin/ld +` + } + if attr.flags&llvmRuntimeCompilerRT != 0 { + if attr.append == nil { + cache = append(cache, + [2]string{"COMPILER_RT_USE_LLVM_UNWINDER", "ON"}) + } + } + if attr.flags&llvmRuntimeLibunwind != 0 { + cache = append(cache, + [2]string{"LIBUNWIND_USE_COMPILER_RT", "ON"}) + } + if attr.flags&llvmRuntimeLibcxx != 0 { + cache = append(cache, + [2]string{"LIBCXX_HAS_MUSL_LIBC", "ON"}, + [2]string{"LIBCXX_USE_COMPILER_RT", "ON"}, + ) + + if t > toolchainStage3 { + // libcxxabi fails to compile if c++ headers not prefixed in /usr + // is found by the compiler, and doing this is easier than + // overriding CXXFLAGS; not using mv here to avoid chown failures + scriptEarly += ` +cp -r /system/include /usr/include && rm -rf /system/include +` + } + } + if attr.flags&llvmRuntimeLibcxxABI != 0 { + cache = append(cache, + [2]string{"LIBCXXABI_USE_COMPILER_RT", "ON"}, + [2]string{"LIBCXXABI_USE_LLVM_UNWINDER", "ON"}, + ) + } + + return t.NewViaCMake("llvm", version, variant, pkg.NewHTTPGetTar( + nil, "https://github.com/llvm/llvm-project/archive/refs/tags/"+ + "llvmorg-"+version+".tar.gz", + mustDecode(checksum), + pkg.TarGzip, + ), &CMakeAttr{ + Cache: slices.Concat(cache, attr.cmake), + Append: cmakeAppend, + Extra: slices.Concat(attr.extra, extra), + Prefix: attr.prefix, + + Env: slices.Concat([]string{ + "ROSA_LLVM_PROJECTS=" + strings.Join(projects, ";"), + "ROSA_LLVM_RUNTIMES=" + strings.Join(runtimes, ";"), + }, attr.env), + ScriptEarly: scriptEarly, Script: script + attr.script, + }) +} |
