aboutsummaryrefslogtreecommitdiffhomepage
path: root/internal
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2026-01-19 02:27:45 +0900
committerOphestra <cat@gensokyo.uk>2026-01-19 02:29:06 +0900
commit7f3d1d6375278377ca0b179436a9079add1722ce (patch)
tree942cc079b3c4f1909e02b29f67108a0f1a730b3e /internal
parent3a4f20b759bc9c8315320d27fc308bb75d2150a3 (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.go191
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,
+ })
+}