From b2980da20b29083bcfcfb69cafe164131d457f71 Mon Sep 17 00:00:00 2001 From: Jacob Heider Date: Fri, 6 Feb 2026 15:43:26 -0500 Subject: [PATCH] shim layering we need our shims to massage our build variables on linux properly (otherwise, we have to recreate logic every time we use gcc). this adds proper layered fallback to included tooling. obviously envvars can still override. --- build/build.ts | 83 +++++++++++++++++++++++++---------- lib/porcelain/build-script.ts | 7 ++- share/toolchain/shim | 22 ++-------- 3 files changed, 71 insertions(+), 41 deletions(-) diff --git a/build/build.ts b/build/build.ts index 0ce017ce..cf46c001 100755 --- a/build/build.ts +++ b/build/build.ts @@ -161,47 +161,86 @@ if (ghout) { /////////////////////////////////////////////////////////////////// function make_toolchain() { - const deps = new Set(config.deps.dry.build.concat(config.deps.dry.runtime).map(x => x.project)) - - if (deps.has('llvm.org') || deps.has('gnu.org/gcc')) { + if (yml?.build?.skip === 'shims' || yml?.build?.skip?.includes?.('shims')) { return } if (host().platform != "darwin") { + const deps = new Set(config.deps.dry.build.concat(config.deps.dry.runtime).map(x => x.project)) + const has_gcc = deps.has('gnu.org/gcc') + const has_llvm = deps.has('llvm.org') + const has_binutils = deps.has('gnu.org/binutils') + // rm ∵ // https://github.com/pkgxdev/brewkit/issues/303 const d = config.path.home.join('toolchain').rm({ recursive: true }).mkdir('p') + const prefix = useConfig().prefix - const symlink = (names: string[], {to}: {to: string}) => { + const llvm = (bin: string) => prefix.join('llvm.org/v*/bin', bin) + const gcc = (bin: string) => prefix.join('gnu.org/gcc/v*/bin', bin) + const binutils = (bin: string) => prefix.join('gnu.org/binutils/v*/bin', bin) + + const symlink = (names: string[], target: Path) => { for (const name of names) { const path = d.join(name) if (path.exists()) continue - const target = useConfig().prefix.join('llvm.org/v*/bin', to) path.ln('s', { target }) } } - symlink(["cc", "gcc", "clang"], {to: "clang"}) - symlink(["c++", "g++", "clang++"], {to: "clang++"}) - symlink(["cpp"], {to: "clang-cpp"}) + // compilers + if (has_gcc && has_llvm) { + symlink(["cc", "gcc"], gcc("gcc")) + symlink(["c++", "g++"], gcc("g++")) + symlink(["clang"], llvm("clang")) + symlink(["clang++"], llvm("clang++")) + symlink(["cpp"], gcc("cpp")) + } else if (has_gcc) { + symlink(["cc", "gcc"], gcc("gcc")) + symlink(["c++", "g++"], gcc("g++")) + symlink(["cpp"], gcc("cpp")) + } else { + // llvm is default; build-script.ts adds +llvm.org to env if not already a dep + symlink(["cc", "gcc", "clang"], llvm("clang")) + symlink(["c++", "g++", "clang++"], llvm("clang++")) + symlink(["cpp"], llvm("clang-cpp")) + } - if (host().platform == "linux") { - symlink(["ld"], {to: "ld.lld"}) + // linker + if (has_binutils) { + symlink(["ld"], binutils("ld")) + } else if (host().platform == "linux") { + symlink(["ld"], llvm("ld.lld")) } else if (host().platform == "windows") { - symlink(["ld"], {to: "lld-link"}) + symlink(["ld"], llvm("lld-link")) } - symlink(["ld.lld"], {to: "ld.lld"}) - symlink(["lld-link"], {to: "lld-link"}) - - symlink(["ar"], {to: "llvm-ar"}) - symlink(["as"], {to: "llvm-as"}) - symlink(["nm"], {to: "llvm-nm"}) - symlink(["objcopy"], {to: "llvm-objcopy"}) - symlink(["ranlib"], {to: "llvm-ranlib"}) - symlink(["readelf"], {to: "llvm-readelf"}) - symlink(["strings"], {to: "llvm-strings"}) - symlink(["strip"], {to: "llvm-strip"}) + if (has_llvm || !has_gcc) { + symlink(["ld.lld"], llvm("ld.lld")) + symlink(["lld-link"], llvm("lld-link")) + } + + // utilities + if (has_binutils) { + symlink(["ar"], binutils("ar")) + symlink(["as"], binutils("as")) + symlink(["nm"], binutils("nm")) + symlink(["objcopy"], binutils("objcopy")) + symlink(["ranlib"], binutils("ranlib")) + symlink(["readelf"], binutils("readelf")) + symlink(["strings"], binutils("strings")) + symlink(["strip"], binutils("strip")) + } else { + symlink(["ar"], llvm("llvm-ar")) + symlink(["as"], llvm("llvm-as")) + symlink(["nm"], llvm("llvm-nm")) + symlink(["objcopy"], llvm("llvm-objcopy")) + symlink(["ranlib"], llvm("llvm-ranlib")) + symlink(["readelf"], llvm("llvm-readelf")) + symlink(["strings"], llvm("llvm-strings")) + symlink(["strip"], llvm("llvm-strip")) + } } + // always return shim path — on Darwin the shim handles -Werror filtering and rpath injection via ruby return new Path(new URL(import.meta.url).pathname).join("../../share/toolchain/bin") } diff --git a/lib/porcelain/build-script.ts b/lib/porcelain/build-script.ts index 88f939c3..0c7936f8 100644 --- a/lib/porcelain/build-script.ts +++ b/lib/porcelain/build-script.ts @@ -9,7 +9,12 @@ const { host } = utils export default async function(config: Config, PATH?: Path): Promise { const depset = new Set(config.deps.gas.map(x => x.pkg.project)) const depstr = (deps: PackageRequirement[]) => deps.map(x => `"+${utils.pkg.str(x)}"`).join(' ') - const env_plus = `${depstr(config.deps.dry.runtime)} ${depstr(config.deps.dry.build)}`.trim() + let env_plus = `${depstr(config.deps.dry.runtime)} ${depstr(config.deps.dry.build)}`.trim() + + // if no compiler is an explicit dep, add llvm as default (was previously done per-invocation in the shim) + if (host().platform != 'darwin' && !depset.has('llvm.org') && !depset.has('gnu.org/gcc')) { + env_plus = `${env_plus} "+llvm.org"`.trim() + } const user_script = await usePantry().getScript(config.pkg, 'build', config.deps.gas, config) const pkgx = find_in_PATH('pkgx') diff --git a/share/toolchain/shim b/share/toolchain/shim index 95d83f7c..4f5e6eb4 100755 --- a/share/toolchain/shim +++ b/share/toolchain/shim @@ -3,32 +3,18 @@ tool=$(basename "$0") if [ "$(uname)" != Darwin ]; then - if [ -x /usr/local/bin/pkgx ]; then - # removed from PATH deliberately - #TODO like, probs we should set PKGX or something before removing it from PATH - pkgx=/usr/local/bin/pkgx - else - # if not the above probs this is running in pkgx CI/CD - pkgx="${PKGX_DIR:-$HOME/.pkgx}/pkgx.sh/v*/bin/pkgx" - fi - # prevent fork bombs (shouldn't be possible but who knows) - export PATH="/usr/bin:/bin:/usr/sbin:/sbin" - - # NOTE this slows down configure scripts a shit tonne - # 1. a fix is speeding up pkgx resolution by caching the pantry - # 2. or do this once and store the env to a file that we can then source - set -a - eval "$("$pkgx" +llvm.org)" + # ensure $HOME/toolchain (real binaries) is found before shim dir to prevent recursion + export PATH="$HOME/toolchain:$PATH" if printf "%s\n" "$@" | grep -qxF -- '-shared'; then - has_shared=1 + has_shared=1 fi filtered_args=() for arg in "$@"; do # -shared and -pie conflict. libs aren't executables, so accept the -shared if [ "$arg" = "-pie" ] && [ "$has_shared" = "1" ]; then - continue + continue fi if [ "$arg" != -Werror ]; then