package rosa import ( "runtime" "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, }) } // NewLLVM returns LLVM toolchain across multiple [pkg.Artifact]. func (t Toolchain) NewLLVM() (musl, compilerRT, runtimes, clang pkg.Artifact) { var target string switch runtime.GOARCH { case "386", "amd64": target = "X86" default: panic("unsupported target " + runtime.GOARCH) } minimalDeps := [][2]string{ {"LLVM_ENABLE_ZLIB", "OFF"}, {"LLVM_ENABLE_ZSTD", "OFF"}, {"LLVM_ENABLE_LIBXML2", "OFF"}, } compilerRT = t.newLLVM("compiler-rt", &llvmAttr{ env: []string{ ldflags(false), }, cmake: [][2]string{ // libc++ not yet available {"CMAKE_CXX_COMPILER_TARGET", ""}, {"COMPILER_RT_BUILD_BUILTINS", "ON"}, {"COMPILER_RT_DEFAULT_TARGET_ONLY", "ON"}, {"LLVM_ENABLE_PER_TARGET_RUNTIME_DIR", "ON"}, // does not work without libunwind {"COMPILER_RT_BUILD_CTX_PROFILE", "OFF"}, {"COMPILER_RT_BUILD_LIBFUZZER", "OFF"}, {"COMPILER_RT_BUILD_MEMPROF", "OFF"}, {"COMPILER_RT_BUILD_PROFILE", "OFF"}, {"COMPILER_RT_BUILD_SANITIZERS", "OFF"}, {"COMPILER_RT_BUILD_XRAY", "OFF"}, }, append: []string{"compiler-rt"}, extra: []pkg.Artifact{t.NewMusl(&MuslAttr{ Headers: true, Env: []string{ "CC=clang", }, })}, script: ` mkdir -p "${ROSA_INSTALL_PREFIX}/lib/clang/21/lib/" ln -s \ "../../../${ROSA_TRIPLE}" \ "${ROSA_INSTALL_PREFIX}/lib/clang/21/lib/" ln -s \ "clang_rt.crtbegin-$(uname -m).o" \ "${ROSA_INSTALL_PREFIX}/lib/${ROSA_TRIPLE}/crtbeginS.o" ln -s \ "clang_rt.crtend-$(uname -m).o" \ "${ROSA_INSTALL_PREFIX}/lib/${ROSA_TRIPLE}/crtendS.o" `, }) musl = t.NewMusl(&MuslAttr{ Extra: []pkg.Artifact{compilerRT}, Env: []string{ ldflags(false), "CC=clang", "LIBCC=/system/lib/clang/21/lib/" + triplet() + "/libclang_rt.builtins.a", "AR=ar", "RANLIB=ranlib", }, }) runtimes = t.newLLVM("runtimes", &llvmAttr{ env: []string{ ldflags(false), }, flags: llvmRuntimeLibunwind | llvmRuntimeLibcxx | llvmRuntimeLibcxxABI, cmake: slices.Concat([][2]string{ // libc++ not yet available {"CMAKE_CXX_COMPILER_WORKS", "ON"}, {"LIBCXX_HAS_ATOMIC_LIB", "OFF"}, {"LIBCXXABI_HAS_CXA_THREAD_ATEXIT_IMPL", "OFF"}, }, minimalDeps), append: []string{"runtimes"}, extra: []pkg.Artifact{ compilerRT, musl, }, }) clang = t.newLLVM("clang", &llvmAttr{ flags: llvmProjectClang | llvmProjectLld, env: []string{ "CFLAGS=" + cflags, "CXXFLAGS=" + cxxflags(), ldflags(false), }, cmake: slices.Concat([][2]string{ {"LLVM_TARGETS_TO_BUILD", target}, {"CMAKE_CROSSCOMPILING", "OFF"}, {"CXX_SUPPORTS_CUSTOM_LINKER", "ON"}, }, minimalDeps), extra: []pkg.Artifact{ musl, compilerRT, runtimes, }, }) return }