From 7f3d1d6375278377ca0b179436a9079add1722ce Mon Sep 17 00:00:00 2001 From: Ophestra Date: Mon, 19 Jan 2026 02:27:45 +0900 Subject: [PATCH] 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 --- internal/rosa/llvm.go | 191 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 191 insertions(+) create mode 100644 internal/rosa/llvm.go diff --git a/internal/rosa/llvm.go b/internal/rosa/llvm.go new file mode 100644 index 0000000..e3eccc8 --- /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< 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, + }) +}