package rosa import ( "runtime" "slices" "strconv" "strings" "sync" "hakurei.app/internal/pkg" ) // llvmSource is the unpatched upstream LLVM monorepo. var llvmSource = newFromGitHub( "llvm/llvm-project", "llvmorg-"+llvmVersion, llvmChecksum, ) // llvmAttr holds the attributes that will be applied to a new [pkg.Artifact] // containing a LLVM variant. type llvmAttr struct { // Enabled projects and runtimes. pr int // Concatenated with default environment for PackageAttr.Env. env []string // Concatenated with generated entries for CMakeHelper.Cache. cmake []KV // Override CMakeHelper.Append. append []string // Passed through to PackageAttr.NonStage0. nonStage0 []pkg.Artifact // Concatenated with default fixup for CMakeHelper.Script. script string // Patch name and body pairs. patches []KV } const ( llvmProjectClang = 1 << iota llvmProjectLld llvmProjectAll = 1< 0 { cache = append(cache, []KV{ {"LLVM_ENABLE_PROJECTS", `"${ROSA_LLVM_PROJECTS}"`}, }...) } if len(runtimes) > 0 { cache = append(cache, []KV{ {"LLVM_ENABLE_RUNTIMES", `"${ROSA_LLVM_RUNTIMES}"`}, }...) } cmakeAppend := []string{"llvm"} if attr.append != nil { cmakeAppend = attr.append } return t.NewPackage("llvm", llvmVersion, llvmSource, &PackageAttr{ Patches: slices.Concat(attr.patches, llvmPatches), NonStage0: attr.nonStage0, Env: slices.Concat([]string{ "ROSA_LLVM_PROJECTS=" + strings.Join(projects, ";"), "ROSA_LLVM_RUNTIMES=" + strings.Join(runtimes, ";"), }, attr.env), Flag: TExclusive, }, &CMakeHelper{ Variant: variant, Cache: slices.Concat(cache, attr.cmake), Append: cmakeAppend, Script: script + attr.script, }, Python, Perl, Diffutils, Bash, Gawk, Coreutils, Findutils, KernelHeaders, ) } // newLLVM returns LLVM toolchain across multiple [pkg.Artifact]. func (t Toolchain) newLLVM() (musl, compilerRT, runtimes, clang pkg.Artifact) { target := "'AArch64;RISCV;X86'" if t.isStage0() { switch runtime.GOARCH { case "386", "amd64": target = "X86" case "arm64": target = "AArch64" case "riscv64": target = "RISCV" default: panic("unsupported target " + runtime.GOARCH) } } minimalDeps := []KV{ {"LLVM_ENABLE_ZLIB", "OFF"}, {"LLVM_ENABLE_ZSTD", "OFF"}, {"LLVM_ENABLE_LIBXML2", "OFF"}, } muslHeaders, _ := t.newMusl(true, []string{ "CC=clang", }) compilerRT = t.newLLVMVariant("compiler-rt", &llvmAttr{ env: stage0ExclConcat(t, []string{}, "LDFLAGS="+earlyLDFLAGS(false), ), cmake: []KV{ // libc++ not yet available {"CMAKE_CXX_COMPILER_TARGET", ""}, {"COMPILER_RT_BUILD_BUILTINS", "ON"}, {"COMPILER_RT_DEFAULT_TARGET_ONLY", "OFF"}, {"COMPILER_RT_SANITIZERS_TO_BUILD", "asan"}, {"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_XRAY", "OFF"}, }, append: []string{"compiler-rt"}, nonStage0: []pkg.Artifact{ muslHeaders, }, script: ` mkdir -p "/work/system/lib/clang/` + llvmVersionMajor + `/lib/" ln -s \ "../../../${ROSA_TRIPLE}" \ "/work/system/lib/clang/` + llvmVersionMajor + `/lib/" ln -s \ "clang_rt.crtbegin-` + linuxArch() + `.o" \ "/work/system/lib/${ROSA_TRIPLE}/crtbeginS.o" ln -s \ "clang_rt.crtend-` + linuxArch() + `.o" \ "/work/system/lib/${ROSA_TRIPLE}/crtendS.o" `, }) musl, _ = t.newMusl(false, stage0ExclConcat(t, []string{ "CC=clang", "LIBCC=/system/lib/clang/" + llvmVersionMajor + "/lib/" + triplet() + "/libclang_rt.builtins.a", "AR=ar", "RANLIB=ranlib", }, "LDFLAGS="+earlyLDFLAGS(false), ), compilerRT) runtimes = t.newLLVMVariant("runtimes", &llvmAttr{ env: stage0ExclConcat(t, []string{}, "LDFLAGS="+earlyLDFLAGS(false), ), pr: llvmRuntimeLibunwind | llvmRuntimeLibcxx | llvmRuntimeLibcxxABI, cmake: slices.Concat([]KV{ {"LIBUNWIND_USE_COMPILER_RT", "ON"}, {"LIBCXX_HAS_MUSL_LIBC", "ON"}, {"LIBCXX_USE_COMPILER_RT", "ON"}, {"LIBCXXABI_USE_COMPILER_RT", "ON"}, {"LIBCXXABI_USE_LLVM_UNWINDER", "ON"}, // 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"}, nonStage0: []pkg.Artifact{ compilerRT, musl, }, }) clang = t.newLLVMVariant("clang", &llvmAttr{ pr: llvmProjectClang | llvmProjectLld, env: stage0ExclConcat(t, []string{}, "CFLAGS="+earlyCFLAGS, "CXXFLAGS="+earlyCXXFLAGS(), "LDFLAGS="+earlyLDFLAGS(false), ), cmake: slices.Concat([]KV{ {"LLVM_ENABLE_LIBCXX", "ON"}, {"LLVM_USE_LINKER", "lld"}, {"LLVM_INSTALL_BINUTILS_SYMLINKS", "ON"}, {"LLVM_INSTALL_CCTOOLS_SYMLINKS", "ON"}, {"LLVM_LIT_ARGS", "'--verbose'"}, {"CLANG_DEFAULT_LINKER", "lld"}, {"CLANG_DEFAULT_CXX_STDLIB", "libc++"}, {"CLANG_DEFAULT_RTLIB", "compiler-rt"}, {"CLANG_DEFAULT_UNWINDLIB", "libunwind"}, {"LLVM_TARGETS_TO_BUILD", target}, {"CMAKE_CROSSCOMPILING", "OFF"}, {"CXX_SUPPORTS_CUSTOM_LINKER", "ON"}, }, minimalDeps), nonStage0: []pkg.Artifact{ musl, compilerRT, runtimes, }, script: ` ln -s ld.lld /work/system/bin/ld ln -s clang /work/system/bin/cc ln -s clang++ /work/system/bin/c++ ninja check-all `, }) return } func init() { artifactsM[LLVMCompilerRT] = Metadata{ f: func(t Toolchain) (pkg.Artifact, string) { _, compilerRT, _, _ := t.newLLVM() return compilerRT, llvmVersion }, Name: "llvm-compiler-rt", Description: "LLVM runtime: compiler-rt", Website: "https://llvm.org/", } artifactsM[LLVMRuntimes] = Metadata{ f: func(t Toolchain) (pkg.Artifact, string) { _, _, runtimes, _ := t.newLLVM() return runtimes, llvmVersion }, Name: "llvm-runtimes", Description: "LLVM runtimes: libunwind, libcxx, libcxxabi", Website: "https://llvm.org/", } artifactsM[LLVMClang] = Metadata{ f: func(t Toolchain) (pkg.Artifact, string) { _, _, _, clang := t.newLLVM() return clang, llvmVersion }, Name: "clang", Description: `an "LLVM native" C/C++/Objective-C compiler`, Website: "https://llvm.org/", ID: 1830, } artifactsM[Libclc] = Metadata{ f: func(t Toolchain) (pkg.Artifact, string) { return t.newLLVMVariant("libclc", &llvmAttr{ cmake: []KV{ {"LIBCLC_TARGETS_TO_BUILD", "all"}, }, append: []string{"libclc"}, script: "ninja test", }), llvmVersion }, Name: "libclc", Description: "an open source, BSD/MIT dual licensed implementation of the library requirements of the OpenCL C programming language", Website: "https://libclc.llvm.org/", } } var ( // llvm stores the result of Toolchain.newLLVM. llvm [_toolchainEnd][4]pkg.Artifact // llvmOnce is for lazy initialisation of llvm. llvmOnce [_toolchainEnd]sync.Once ) // NewLLVM returns LLVM toolchain across multiple [pkg.Artifact]. func (t Toolchain) NewLLVM() (musl, compilerRT, runtimes, clang pkg.Artifact) { llvmOnce[t].Do(func() { llvm[t][0], llvm[t][1], llvm[t][2], llvm[t][3] = t.newLLVM() }) return llvm[t][0], llvm[t][1], llvm[t][2], llvm[t][3] }