forked from rosa/hakurei
This enables easier reuse of the patchset. Signed-off-by: Ophestra <cat@gensokyo.uk>
365 lines
8.5 KiB
Go
365 lines
8.5 KiB
Go
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<<iota - 1
|
|
|
|
llvmRuntimeCompilerRT = 1 << iota
|
|
llvmRuntimeLibunwind
|
|
llvmRuntimeLibc
|
|
llvmRuntimeLibcxx
|
|
llvmRuntimeLibcxxABI
|
|
llvmRuntimeLibclc
|
|
|
|
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"
|
|
case llvmRuntimeLibclc:
|
|
return "libclc"
|
|
|
|
default:
|
|
panic("invalid flag " + strconv.Itoa(flag))
|
|
}
|
|
}
|
|
|
|
// newLLVMVariant returns a [pkg.Artifact] containing a LLVM variant.
|
|
func (t Toolchain) newLLVMVariant(variant string, attr *llvmAttr) pkg.Artifact {
|
|
if attr == nil {
|
|
panic("LLVM attr must be non-nil")
|
|
}
|
|
|
|
var projects, runtimes []string
|
|
for i := 1; i < llvmProjectAll; i <<= 1 {
|
|
if attr.pr&i != 0 {
|
|
projects = append(projects, llvmFlagName(i))
|
|
}
|
|
}
|
|
for i := (llvmProjectAll + 1) << 1; i < llvmRuntimeAll; i <<= 1 {
|
|
if attr.pr&i != 0 {
|
|
runtimes = append(runtimes, llvmFlagName(i))
|
|
}
|
|
}
|
|
|
|
var script string
|
|
|
|
cache := []KV{
|
|
{"CMAKE_BUILD_TYPE", "Release"},
|
|
|
|
{"LLVM_HOST_TRIPLE", `"${ROSA_TRIPLE}"`},
|
|
{"LLVM_DEFAULT_TARGET_TRIPLE", `"${ROSA_TRIPLE}"`},
|
|
}
|
|
if len(projects) > 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]
|
|
}
|