Fil-C on Nix

Filnix wiki

mbrock/filnix

toolchain/wrappers.nix

λpkgs, filc, filc-sysroot, filc-binutils, useCcache?
pkgs
filc
filc-sysroot
filc-binutils
useCcachedefault true
let
10lib=
import../lib inherit pkgs;
11inherit lib
setupCcache
12inherit filc
filc-libcxx filc-glibc
13filc3xx=
used by filcache

ccache wrapper with version script handling

16filcache=
λflavor
pkgs.writeShellScriptBin"ccache-${flavor}"
# Nix normalizes mtimes, and store paths have fixed lengths. Hash the
# compiler wrapper, whose contents pin the runtime and SaRCAsm paths.
export CCACHE_COMPILERCHECK=content
${pkgs.lib.optionalString¬useCcache "export CCACHE_DISABLE=1\n"}# Fil-C Clang driver has special version script handling.
#
# This only works if we give the version script flag
# to the Clang driver, not to the actual linker.
#
# When version scripts aren't "pizlonated" properly,
# you get a bunch of linker errors when building anything
# that uses version scripts (e.g. OpenSSL).
#
# XXX: This shouldn't really be in the ccache setup wrapper.
# Handle both -Wl,--version-script=file and -Wl,--version-script -Wl,file
new_args=()
prev_was_version_script=0
for arg in "$@"; do
if [[ "$arg" == "-Wl,--version-script="* ]]; then
# Form 1: -Wl,--version-script=file
new_args+=("--version-script=''${arg#-Wl,--version-script=}")
elif [[ "$arg" == "-Wl,-version-script="* ]]; then
# Form 1 with one dash, as in PulseAudio
new_args+=("--version-script=''${arg#-Wl,-version-script=}")
elif [[ "$arg" == "-Wl,--version-script,"* ]]; then
# Form 2: -Wl,--version-script,file
new_args+=("--version-script=''${arg#-Wl,--version-script,}")
elif [[ "$arg" == "-Wl,-version-script" ]] || [[ "$arg" == "-Wl,--version-script" ]]; then
# Form 3: -Wl,-version-script or -Wl,--version-script (file comes next)
prev_was_version_script=1
elif [[ $prev_was_version_script -eq 1 ]]; then
# This is the file argument
new_args+=("--version-script=''${arg#-Wl,}")
prev_was_version_script=0
else
new_args+=("$arg")
fi
done
exec ${pkgs.ccache}/bin/ccache ${filc3xx}/bin/${flavor} "''${new_args[@]}"

The role salt of the wrappers' environment variables (NIX_CFLAGS_COMPILE_<salt>, NIX_LDFLAGS_<salt>, NIX_CC_WRAPPER_TARGET_HOST_<salt>, ...). Nixpkgs derives it from the target platform, and pkgs is the build platform's package set, so the Fil-C wrappers got the native wrappers' salt. Each then accepted the other's flags: libraries in nativeBuildInputs came first in Fil-C links, and Fil-C libraries reached depsBuildBuild compilers' links. Use the Fil-C platform's salt (flake.nix: crossSystem.config) and keep the empty target prefix. checks.wrapper-roles tests the separation.

74filcSuffixSalt=
"${lib.filcArch}_unknown_linux_gnufilc0"
uses lib used by withFilcSuffixSalt
75withFilcSuffixSalt=
λwrapper
wrapper.overrideAttrs
λold
78env=
old.env // suffixSalt = filcSuffixSalt;
81passthru=
old.passthru // suffixSalt = filcSuffixSalt;
in
rec
88filc-cc=
pkgs.runCommand"filc-cc"

Recipes list stdenv.cc.cc.lib to get GCC's runtime libraries (e.g. fluidsynth, for SDL_mixer). Fil-C's compiler has a single output; lib.getLib stdenv.cc.cc already falls back to it, so make .lib name the same derivation. The wrapper links libc++ itself.

95passthru.lib=

passthru = {

hardeningUnsupportedFlags=
"fortify" "fortify3" "stackprotector" "stackclashprotection"

};

mkdir -p $out/bin
ln -s ${filcache"clang"}/bin/ccache-clang $out/bin/clang
ln -s ${filcache"clang"}/bin/ccache-clang $out/bin/filcc
ln -s ${filcache"clang++"}/bin/ccache-clang++ $out/bin/clang++
ln -s ${filcache"clang++"}/bin/ccache-clang++ $out/bin/filc++
122filc-bintools=
pkgs.wrapBintoolsWith
126defaultHardeningFlags=
[ ]
128extraBuildCommands=
echo "-L${filc-glibc}/lib" >> $out/nix-support/libc-ldflags
echo "-lpizlo -lyoloc -lyolom -lc++ -lc++abi" >> $out/nix-support/libc-ldflags
echo "${filc-sysroot}/lib/${lib.dynamicLinker}" > $out/nix-support/dynamic-linker
# libc-ldflags reach every link, also through the cc wrapper's -Wl
# flags, but a relocatable link (ld -r) makes an object and must not
# name the runtime's shared libraries.
cat > $out/nix-support/ld-wrapper-hook <<'EOF'
if (( relocatable )); then
filcStrip() {
local flag
filcKept=()
for flag in "$@"; do
case "$flag" in
-lpizlo | -lyoloc | -lyolom | -lc++ | -lc++abi) ;;
*) filcKept+=("$flag") ;;
esac
done
}
filcStrip ''${params+"''${params[@]}"}
params=(''${filcKept+"''${filcKept[@]}"})
filcStrip ''${extraAfter+"''${extraAfter[@]}"}
extraAfter=(''${filcKept+"''${filcKept[@]}"})
fi
EOF
157filcc=
pkgs.wrapCCWithcc = filc-cc; libc = filc-sysroot; libcxx = filc-libcxx; bintools = filc-bintools; isClang = true; gccForLibs = null; isCcache = true; extraBuildCommands = '' echo "-Wno-unused-command-line-argument" >> $out/nix-support/cc-cflags echo "-L${filc-libcxx}/lib" >> $out/nix-support/cc-ldflags echo "-gz=none" >> $out/nix-support/cc-cflags '';.overrideAttrs

Let Nixpkgs apply its Clang-specific handling to Fil-C's Clang.

There is no GCC tree to use for libraries; callPackage would otherwise supply the top-level gccForLibs.

The ccache wrapper rewrites version-script flags, which a response file would hide from it.

λold
179env=
old.env // suffixSalt = filcSuffixSalt;
182passthru=
old.passthru or { }
//
183inherit
filc-glibc

Keep ABI-specific build-system integration outside the expensive compiler and runtime derivations. nm itself continues to report real ELF symbols.

188setupHooks=
old.setupHooks
++
190out=
null
substituted by the cc-wrapper builder
191python=
"${pkgs.python3}/bin/python3"
pkgs.replaceVars./header-references-hook.sh removeReferencesTo = "${pkgs.removeReferencesTo}/bin/remove-references-to";
202filenv=
pkgs.overrideCCpkgs.stdenv filcc