Fil-C on Nix

Filnix wiki

mbrock/filnix

ports.nix

Fil-C package ports - list-based structure

Each port: (for pkgs.package [transforms...])
Explicit names: { bash = for pkgs.bash [...]; }

λpkgs, prev, final
let
12inherit import./ports inherit pkgs lib pkgs;
for arg use pin src broken markAsNotNecessarilyInsecure skipTests skipCheck parallelize serialize tool link patch skipPatch removeCFlag addCFlag removeCMakeFlag addCMakeFlag addMakeFlag removeMakeFlag addMesonFlag removeMesonFlag configure removeConfigureFlag wip astRewrite github gnu gnuTarGz

Nixpkgs' Bash patches use -p0; the pinned importer emits -p1 paths. Apply our unwind buffer fix separately without changing their strip level.

47bashUnwindPatch=
λold
48postPatch=
old.postPatch or ""
uses use

For programs that dlopen() optional libraries by soname and declare them in .note.dlopen ELF notes (systemd, kbd). Natively the notes make autoPatchelfHook add the libraries to RUNPATH. Under Fil-C neither half works: section() on globals is dropped, so there are no notes, and Fil-C's dlopen() does not search the caller's RUNPATH (docs/filc-findings.md). So rewrite every soname literal in the source that a build input provides to its absolute path, and put the notes back (they then carry the same paths), since make-initrd-ng reads them to copy a binary's dlopen()ed libraries into the initrd.

62dlopenByPath=
λold
63postPatch=
old.postPatch or ""
+
for soname in $(grep -rhoE '"lib[A-Za-z0-9_+-]+\.so\.[0-9.]+"' src | tr -d '"' | sort -u); do
for dir in ${toStringmapp: "${p.lib or p.out or p}/lib" old.buildInputs}; do
if [ -e "$dir/$soname" ]; then
grep -rlF "\"$soname\"" src | xargs sed -i "s|\"$soname\"|\"$dir/$soname\"|g"
echo "dlopen: $soname -> $dir/$soname"
break
fi
done
done
76postFixup=
old.postFixup or ""
+
for output in $(getAllOutputNames); do
${pkgs.buildPackages.python3.interpreter} ${./ports/restore-dlopen-notes.py} \
${pkgs.buildPackages.binutils-unwrapped}/bin/objcopy "''${!output}"
done
uses use

Mozilla's root store from NSS 3.131.1, which removes the emSign roots behind the October 2026 eMudhra key compromise (emSign ECC Root CA - G3, emSign Root CA - C1 and emSign ECC Root CA - C3). Used for cacert; the NSS port's libnssckbi is p11-kit's trust module, which reads the host's trust store at runtime instead of compiled-in roots.

89nssCertdata=
pkgs.fetchurl
90urls=
"https://hg-edge.mozilla.org/projects/nss/raw-file/NSS_3_131_1_RTM/lib/ckfw/builtins/certdata.txt" "https://raw.githubusercontent.com/nss-dev/nss/refs/tags/NSS_3_131_1_RTM/lib/ckfw/builtins/certdata.txt"
94hash=
"sha256-PsK00kDcEsdH6vRQBh24SvdXxIO72jAvninOtdcL5RA="

The build platform's guile, to compile Scheme modules to .go files (the bytecode is the same). As an input it would propagate its native libunistring and libgc onto the Fil-C link path, so only its programs are exposed.

101guileForBuild=
pkgs.runCommand"guile-for-build" { }
mkdir -p $out/bin
ln -s ${pkgs.buildPackages.guile_3_0}/bin/* $out/bin/

The Fil-C guile, for builds that must load Fil-C extensions or run tests with it at build time. It runs on the build machine.

108filcGuileForBuild=
pkgs.runCommand"filc-guile-for-build" { }
mkdir -p $out/bin
ln -s ${final.guile_3_0}/bin/* $out/bin/

Guile libraries whose tests load Fil-C code (their own extension or a C library through the FFI) must run them with the Fil-C guile; Nixpkgs' cross build would use the build platform's.

116guileTestsOnFilc=
λold
117preCheck=
old.preCheck or ""
+
export PATH=${final.guile_3_0}/bin:$PATH
for f in pre-inst-env pre-inst-guile; do
if [ -f $f ]; then
substituteInPlace $f --replace-quiet \
${pkgs.buildPackages.guile_3_0}/bin/guile ${final.guile_3_0}/bin/guile
fi
done
126checkFlags=
old.checkFlags or [ ] ++ "GUILE=${final.guile_3_0}/bin/guile"
uses use
131fftwPort=
λold
138nativeBuildInputs=
builtins.filterdep: ¬pkgs.lib.hasInfix"gfortran" dep.name or "" old.nativeBuildInputs

Nixpkgs adds LLVM's OpenMP when the compiler is Clang.

142buildInputs=
builtins.filterdep: ¬pkgs.lib.hasInfix"openmp" dep.name or "" old.buildInputs or [ ]
145configureFlags=
builtins.filterf: ¬builtins.elemf "--enable-openmp" "--enable-avx512" old.configureFlags
++
"--disable-fortran"
"--disable-openmp"

Fil-C does not yet lower AVX-512 gather intrinsics.

"--disable-avx512"
159doCheck=
true
uses use
in
import./ports/pipewire-consumers.nix inherit pkgs prev final;
import./ports/media.nix inherit pkgs;
import./ports/tpm2.nix inherit pkgs final;

Core Libraries

let
172boostPort=
λboost
174boost for boost
patch./ports/patch/boost-filc.patch

1.86's B2 still accepts context-impl from the Context Jamfile.

pkgs.lib.optionalpkgs.lib.versionAtLeastboost.version "1.87" patch./patches/boost-context-feature.patch
patch./patches/boost-gdb-scripts.patch
patch./patches/boost-function-vtable-tag.patch
patch./patches/boost-test-execution-monitor.patch

io_context's executor keeps its context pointer and flag bits in a uintptr_t; the first use_service through a strand trapped.

patch./patches/boost-asio-io-context-executor-pointer.patch
use
λold

error_code keeps its source_location pointer in a uintptr_t with a flag bit, which drops the capability, and what() then trapped (Boost.URL's parse errors in Nix). Keep no location instead.

191postPatch=
old.postPatch or ""
+
"\n"
+
substituteInPlace boost/system/detail/error_code.hpp --replace-fail \
'( loc? reinterpret_cast<boost::uintptr_t>( loc ): 2 )' '2'
arg

Match upstream pizlix: Context and Coroutine2 use ucontext. The older Coroutine v1 library requires fcontext and is omitted.

202toolset=
"clang"
203extraB2Args=
"context-impl=ucontext" "--without-coroutine"
use
209doCheck=
true
210checkPhase=
runHook preCheck
$CXX -std=c++17 -I. ${./tests/boost-context.cpp} \
-Lstage/lib -Wl,-rpath,"$PWD/stage/lib" -lboost_context -lboost_json -pthread -o boost-check
LD_LIBRARY_PATH="$PWD/stage/lib" ./boost-check
$CXX -std=c++17 -I. ${./tests/boost-continuation.cpp} \
-Lstage/lib -Wl,-rpath,"$PWD/stage/lib" -lboost_context -pthread -o continuation-check
LD_LIBRARY_PATH="$PWD/stage/lib" ./continuation-check
$CXX -std=c++17 -I. ${./tests/boost-asio.cpp} -pthread -o asio-check
./asio-check
$CXX -std=c++17 -I. ${./tests/boost-error-code.cpp} -o error-code-check
./error-code-check
# Boost.Test, both as the compiled library and header-only. The
# module deliberately fails some cases, so compare its summary.
$CXX -std=c++17 -I. -DBOOST_TEST_DYN_LINK ${./tests/boost-test.cpp} \
-Lstage/lib -Wl,-rpath,"$PWD/stage/lib" -lboost_unit_test_framework -o boost-test-check
sed 's|<boost/test/unit_test.hpp>|<boost/test/included/unit_test.hpp>|' \
${./tests/boost-test.cpp} > boost-test-included.cpp
$CXX -std=c++17 -I. boost-test-included.cpp -o boost-test-included-check
for check in ./boost-test-check ./boost-test-included-check; do
status=0
LD_LIBRARY_PATH="$PWD/stage/lib" $check --report_level=short \
--color_output=no > boost-test.log 2>&1 || status=$?
cat boost-test.log
test "$status" = 201
sed -n '/^Test module/,$p' boost-test.log | sed '/^$/d' \
done
runHook postCheck
in
245boost186=
boostPortpkgs.boost186
246boost187=
boostPortpkgs.boost187
let
252icuPort=
λicu patches
254icu for icu
mappatch patches
toolpkgs.autoreconfHook
toolpkgs.pkg-config
use

Nixpkgs unpacks into icu/source; the upstream tree has icu4c/source.

261patchFlags=
"-p3"

ICU disables its upstream suite for cross builds; its "test" target is just a directory. Exercise the real target libraries explicitly.

264doCheck=
true
265checkPhase=
runHook preCheck
$CXX ${./tests/icu.cpp} -Icommon -Ii18n -Llib \
-Wl,-rpath,"$PWD/lib" -licui18n -licuuc -licudata -o icu-check
./icu-check
LD_LIBRARY_PATH="$PWD/lib" ./bin/uconv -V
runHook postCheck
in

abseil-cpp is an alias of this LTS branch, so both names get the port.

298abseil-cpp_202601=
298abseil-cpp_202601

Upstream Fil-C's port: Status, Cord, Mutex and BitGenRef keep pointers in integer words, which drops their capabilities.

patch./ports/patch/abseil-cpp-20260107.1.patch

[[clang::annotate]] in the public headers crashed FilPizlonator in every consumer (protobuf, re2).

patch./patches/abseil-cpp-no-refactor-annotate.patch
308re2

Exhaustive tests exceed remote builders' 900 s silence limit. Stream actual progress, rather than skipping tests or masking a stuck test.

patch./patches/re2-test-progress.patch

Override Nixpkgs' typed CMAKE_CTEST_ARGUMENTS, keeping its timeout.

addCMakeFlag"-DCMAKE_CTEST_ARGUMENTS=--timeout;999999;--verbose"
let
318protobufPort=
λsourcePatch

Tagged pointers in integer words, byte-wise swaps and inline assembly in the C++ runtime (see the patch headers).

The Fil-C driver rewrites version scripts itself and cannot parse extern "C++" { ... } blocks, so linking libprotobuf aborted. The maps only hide non-protobuf symbols; skip them.

addCMakeFlag"-Dprotobuf_HAVE_LD_VERSION_SCRIPT=OFF"
λold

Fil-C keeps a musttail call only when every pointer argument is the caller's own argument. The table-driven parser advances ptr, so field-to-field tail calls would add a frame per field; PROTOBUF_TAILCALL false makes each field return to the parse loop. Runs after Nixpkgs rewrites this #if for older versions.

332postPatch=
old.postPatch or ""
+
sed -i 's/^\(#if \w*(clang::musttail)\)/\1 \&\& !defined(__FILC__)/' \
src/google/protobuf/port_def.inc
grep -q '(clang::musttail) && !defined(__FILC__)' \
src/google/protobuf/port_def.inc
340randomOrderingTest=
λold

Map salts its integer hash with the table address and rotates the key by its low 6 bits; Fil-C's allocator returns tables with the same low bits, so small maps iterate in a fixed order. Only this statistical check of order randomization fails (4609 others pass in 34.1); iteration order is unspecified either way.

347preCheck=
old.preCheck or ""
+
export GTEST_FILTER=-MapImplTest.RandomOrdering
uses use
in
372mpfr
addCFlag"-DNO_ASM"
use
λold
375postPatch=
old.postPatch or ""
+
# Fil-C aborts and allocation-size traps terminate with SIGTRAP.
substituteInPlace tests/tests.c --replace-fail SIGABRT SIGTRAP
382ada

CMake's env emulator must not replace ctest's target path lookup.

patch./patches/ada-cross-emulator-test.patch
387SDL_compat

Keep the symbol loader out of line: SDL12_compat.c compiles in 30 s, not 873 s (see the patch).

patch./patches/sdl12-symbol-loader.patch

sdl12-compat dlopens SDL2 by bare soname and relies on its RUNPATH, which Fil-C's loader ignores for dlopen (see docs/filc-findings.md). Name the libraries Nix selected, as the sdl2-compat port does for SDL3. (The testver check also needs sdl2-compat's -Bsymbolic-functions.)

use
λold
396postPatch=
old.postPatch or ""
+
substituteInPlace src/SDL12_compat.c \
--replace-fail '"libSDL2-2.0.so.0"' '"${pkgs.lib.getLibfinal.sdl2-compat}/lib/libSDL2-2.0.so.0"' \
--replace-fail '"libX11.so.6"' '"${pkgs.lib.getLibfinal.libx11}/lib/libX11.so.6"'
404smpeg

GTK 2 only serves the gtv demo player; SDL_mixer needs just the library, so keep GTK 2 out of its closure.

useold: buildInputs = builtins.filterdep: ¬pkgs.lib.hasPrefix"gtk+" dep.name or "" old.buildInputs;
configure"--disable-gtk-player"

Nixpkgs links everything with -lX11, which GTK used to provide.

linkfinal.libx11
417oniguruma

Hash keys and values carry pointers; ordinary longs lose capabilities.

patch./patches/oniguruma-pointer-data.patch
422zlib
pin"1.4" "sha256-At0Vl4NnenScBK290CtVuKK8x+BU9Rt2tUkZmpFq1YQ="

Included in 1.4; applying Nixpkgs' older fix would reverse it.

skipPatch"export-variable.patch"
patch./ports/patch/zlib-1.4.patch

Nixpkgs builds minizip from zlib's source with a patch that installs ints.h. minizip needs no Fil-C changes and uses only zlib's public API, so use Nixpkgs' source for both packages.

432minizip
use
434inherit pkgs.zlib
src version
435sourceRoot=
"zlib-${pkgs.zlib.version}/contrib/minizip"
439zlib-ng
pin"2.2.4" "sha256-pzNDwwk+XNxQ2Td5l8OBW4eP0RC/ZRHCx3WfKvuQ9aM="
444openssl=
445openssl-sarcasm=
445openssl-sarcasm for ./ports/openssl-sarcasm.nix
448libev

Replace inline asm mfence with __atomic_thread_fence (Fil-C can't handle inline asm)

use
λattrs
451postPatch=
attrs.postPatch or ""
+
substituteInPlace ev.c \
--replace-fail '#define ECB_MEMORY_FENCE __asm__ __volatile__ ("mfence" : : : "memory")' \
'#define ECB_MEMORY_FENCE __atomic_thread_fence(__ATOMIC_SEQ_CST)' \
--replace-fail '#define ECB_MEMORY_FENCE_ACQUIRE __asm__ __volatile__ ("" : : : "memory")' \
'#define ECB_MEMORY_FENCE_ACQUIRE __atomic_thread_fence(__ATOMIC_ACQUIRE)' \
--replace-fail '#define ECB_MEMORY_FENCE_RELEASE __asm__ __volatile__ ("" : : : "memory")' \
'#define ECB_MEMORY_FENCE_RELEASE __atomic_thread_fence(__ATOMIC_RELEASE)'

(for pkgs.attr [

(pin "2.5.2" "sha256-Ob9nRS+kHQlIwhl2AQU/SLPXigKTiXNDMqYwmmgMbIc=")
(patch ./ports/patch/attr-2.5.2.patch)

])

472expat
pin"2.7.1" "sha256-NUVSVEuPmQEuUGL31XDsd/FLQSo/9cfY0NrmLA0hfDA="
patch./ports/patch/expat-2.7.1.patch
477nspr

NSPR's x86_64 atomics are hand-written assembly (os_Linux_x86_64.s), which Fil-C cannot assemble or check. Use the __sync builtins, as NSPR already does on loongarch and or1k, and build no .s file.

patch./patches/nspr-filc-atomics.patch
addMakeFlag"PR_MD_ASFILES="

PR_Accept(fd, NULL, ...) passed a length pointer with a null address, which Linux ignores but Fil-C's accept rejects; pass no length.

patch./patches/nspr-null-peer-address.patch

PLArena keeps its addresses as integers and PL_ARENA_ALLOCATE cast them back to pointers, which have no capability under Fil-C; NSS's first arena allocation trapped. Derive them from the arena header.

patch./patches/nspr-arena-pointer-provenance.patch

Nixpkgs runs no tests; NSPR's own suite covers the atomics, threads and loopback I/O (about 100 programs, a few minutes).

use
493doCheck=
true
494checkPhase=
runHook preCheck
make -C pr/tests
(cd pr/tests && ./runtests.sh "$PWD/../../dist")
runHook postCheck
504cacert=
504cacert
use
506version=
"3.131.1"
512nss

The same integer-to-pointer cast as NSPR's arenas, in NSS's arena-zeroing code.

patch./patches/nss-arena-pointer-provenance.patch

freebl's cpuid asm (cache line size for RSA) sets flags without a "cc" clobber, which Fil-C rejects when it runs.

patch./patches/nss-cpuid-cc-clobber.patch

Saved digest state put the context at offset 12, so SHA-256's function pointers lost their capabilities on the way through PK11_CloneContext and every TLS 1.3 handshake trapped. Pad the header.

patch./patches/nss-softoken-state-alignment.patch

The TLS RSA key exchange swaps the real and fake premaster keys with a constant-time XOR mask on the pointers, leaving bare integers.

patch./patches/nss-ssl-cswap-symkey.patch
use
λold

NSS keys its x86-64 assembly and intrinsics (AES-NI, PCLMUL, SHA-NI, AVX2 HACL*, the amd64 bignum and arcfour assembly) on target_arch=="x64". Build for a target NSS does not know, which selects the portable C code, and keep 64-bit words and __int128.

531buildPhase=
builtins.replaceStrings"--target x64" "--target filc -Dhave_int128_support=1" old.buildPhase

pk11_gtest and freebl_gtest initialize large std::vector test-vector tables in one static constructor, which takes Fil-C's pipeline over 20 minutes per file (SROA on the instrumented function). Skip them.

539postPatch=
old.postPatch
+
sed -i -e '/gtests\/pk11_gtest\//d' -e '/gtests\/freebl_gtest\//d' nss.gyp
# selfserv listens on the preferred loopback address for
# "localhost" (::1 where IPv6 is up), but ssl.sh forced tstclnt to
# IPv4 and could never connect; let tstclnt pick the same address.
sed -i 's/tstclnt -4 /tstclnt /' tests/ssl/ssl.sh
# dbtests requires the bigdb key dump to finish in under 5 seconds
# of wall time; under Fil-C on a loaded builder it flakes. Keep the
# check but allow a minute.
sed -i 's/test ''${TIMEARRAY\[0\]} -lt 5/test ''${TIMEARRAY[0]} -lt 60/' \
tests/dbtests/dbtests.sh
grep -q 'TIMEARRAY\[0\]} -lt 60' tests/dbtests/dbtests.sh

Run a subset of NSS's QA suites against the build tree, before installPhase rearranges the output: ciphers, certutil and the cert database, SDR, CRMF, S/MIME, EC, and TLS coverage and client auth. tools.sh (pk12util's cipher matrix, ~800 checks) passed locally but takes over half an hour under Fil-C.

557doCheck=
true
558checkPhase=
runHook preCheck
(
cd tests
export HOST=localhost DOMSUF=localdomain USE_IP=TRUE IP_ADDRESS=localhost
export DIST=$(dirname $out) OBJDIR=$(basename $out)
export OS_ARCH=Linux DLL_PREFIX=lib DLL_SUFFIX=so BUILT_OPT=1 USE_64=1
export TESTDIR=$TMPDIR/nss-tests NSS_CYCLES=standard
export NSS_TESTS="cipher lowhash cert dbtests sdr crmf smime ec ssl"
export NSS_SSL_TESTS=normal_normal NSS_SSL_RUN="cov auth"
./all.sh > $TMPDIR/nss-tests.log 2>&1 || true
)
sed -n '/^Tests summary/,$p' $TMPDIR/nss-tests.log
if ! grep -q '^Failed: *0$' $TMPDIR/nss-tests.log; then
grep -E 'FAILED|Failed' $TMPDIR/nss-tests.log | head -100
exit 1
fi
runHook postCheck
580libffi
patch./ports/patch/libffi-3.8.0.patch

Closure handlers may write to their by-value arguments, which the runtime passes in the read-only zargs() buffer (cffi's test_callback_large_struct).

patch./patches/libffi-closure-writable-args.patch
toolpkgs.autoreconfHook
configure"--disable-static"
configure"--disable-exec-static-tramp"
592libpng=
592libpng
pin"1.6.43" "sha256-alygZSOSotfJ2yrltAIQhDwLvAgcvUEIJasAzFnxSmw="
patch./ports/patch/libpng-1.6.43.patch
usepostPatch = "";
skipCheck"slow and occasionally flaky"
601libjpeg_turbo=
602libjpeg_turbo
patch./ports/patch/libjpeg-turbo-3.0.1.patch

The x86-64 SIMD extensions are NASM assembly; build the Arm Neon intrinsics instead, translated to SSE by the SIMDe headers.

patch./patches/libjpeg-turbo-simde-neon.patch
addCMakeFlag"-DSIMDE_NEON=1"
addCMakeFlag"-DREQUIRE_SIMD=1"
addCFlag"-isystem ${pkgs.buildPackages.simde}/include"
addCMakeFlag"-DCMAKE_SKIP_INSTALL_RPATH=ON"
argnasm = pkgs.hello;
616libxml2
patch./ports/patch/libxml2-2.14.4.patch
argpythonSupport = false;
skipCheck"python tests fail"

db and db5 are aliases of db53; override it so all three get the port.

634db53=
634db53

Private environments stored heap pointers in integer offsets and mutex IDs; give them the offset-based shared-region layout.

patch./patches/db-private-regions.patch

db_load without -h opens a private environment.

use
640doInstallCheck=
true
641installCheckPhase=
printf 'key\nvalue\n' | "$bin/bin/db_load" -T -t btree t.db
"$bin/bin/db_dump" -p t.db | grep -qx ' value'
649nettle
removeConfigureFlag"--enable-fat"
configure"--disable-assembler"
654pcre2
656libarchive
pin"3.7.4" "sha256-z3/IW59mPAbcK3A2t+5U0CcSFn4EsHvcxMJ1U6vy1v8="
patch./ports/patch/libarchive-3.7.4.patch
skipCheck"some tests fail"
skipPatch"mac"
663libedit
pin"20240808-3.1" "sha256-XwVzNJ13xKSJZxkc3WY03Xql9jmMalf+A3zAJpbWCZ8="
patch./ports/patch/libedit-20240808-3.1.patch
668libidn2 for pkgs.callPackage"${pkgs.path}/pkgs/development/libraries/libidn2" { }

Special case - libiconv comes from glibc in cross-compilation

674libiconv=
675pname=
"libiconv"
676attrs=
old: { }
677overrideArgs=
{ }
681pth

configure's makecontext probe passes a void (*)(void *) to makecontext, which Clang rejects, so pth fell back to setjmp/longjmp with a hand-patched jmp_buf stack pointer (sjljlx), which does not exist for this libc. Fil-C implements makecontext/swapcontext, so use pth's standard SUSv2 ucontext backend.

configure"--with-mctx-mth=mcsc"
configure"--with-mctx-dsp=sc"
configure"--with-mctx-stk=mc"
use
691doCheck=
true

maketest ignores test_std's exit status.

693checkPhase=
runHook preCheck
make test_std
./test_std
runHook postCheck

Core Utilities

704coreutils
skipCheck"too slow in Fil-C"
709bash=
709bash
arginteractive = true;

unwind_protect saves jmp_bufs in a misaligned buffer, losing their capabilities: bash -c 'set -e; false' crashed.

bashUnwindPatch
skipCheck"interactive mode issues"
717bashNonInteractive=
717bash
arginteractive = false;

unwind_protect saves jmp_bufs in a misaligned buffer, losing their capabilities: bash -c 'set -e; false' crashed.

bashUnwindPatch
skipCheck"test issues"
726busybox
arg
728enableStatic=
false
729enableMinimal=
false

These assembly implementations lack SaRCAsm capability signatures. Use BusyBox's portable C SHA implementations.

732extraConfig=
"CONFIG_SHA1_HWACCEL n\nCONFIG_SHA256_HWACCEL n"

The Makefile calls plain cc (filcc has no target prefix), and the build platform's compiler, there for HOSTCC, comes first on PATH: the result was a native busybox. Name the Fil-C compiler explicitly.

use
λold
738makeFlags=
old.makeFlags or [ ]
++
"CC=${final.stdenv.cc}/bin/cc"

Partial links (-r) of built-in.o: the Fil-C driver adds its own main even there, which then clashes in the final link.

"LD=${final.stdenv.cc.bintools}/bin/ld"

Fil-C's libc has no vfork; busybox vforks only to exec or exit.

addCFlag"-Dvfork=fork"

Under clang, busybox writes its const global pointers through an asm statement that launders the pointer, which Fil-C refuses. Make those globals plain variables (busybox's documented switch) and take the ordinary assignment path.

addCFlag"-DBB_GLOBAL_CONST="
use
λold
753postPatch=
old.postPatch or ""
+
"\n"
+
substituteInPlace include/libbb.h libbb/const_hack.c --replace-fail \
'#if defined(__clang_major__) && __clang_major__ >= 9' \
'#if defined(__clang_major__) && __clang_major__ >= 9 && !defined(__FILC__)'
# printf %s passes the string to printf as a long long when the sizes
# match, which drops its capability; take the char * path instead.
substituteInPlace coreutils/printf.c --replace-fail \
'if (sizeof(argument) == sizeof(llv)) {' 'if (0) {'

nixpkgs' separate debug info adds -Wa,--compress-debug-sections, which Fil-C's assembler rejects, and busybox skips the preConfigure hook removeCFlag relies on.

useseparateDebugInfo = false;
772diffutils
patch./ports/patch/diffutils-3.12.patch
toolpkgs.perl
usepostPatch = "patchShebangs man/help2man";
skipTests"too slow"
779dash
pin"0.5.12" "sha256-akdKxG6LCzKRbExg32lMggWNMpfYs4W3RQgDDKSo8oo="
patch./ports/patch/dash-0.5.12.patch
784file
skipCheck"some magic tests fail"
788gawk
skipCheck"locale tests fail"
792a2ps
use
λold

gnulib's old obstack.h aligns pointers relative to (char *) 0, which drops their capabilities; align relative to the chunk.

796postPatch=
old.postPatch or ""
+
substituteInPlace lib/obstack.h --replace-fail \
'__BPTR_ALIGN (sizeof (ptrdiff_t) < sizeof (void *) ? (B) : (char *) 0,' \
'__BPTR_ALIGN ((B),'
substituteInPlace tests/backup.tst tests/styles.tst \
--replace-quiet /bin/rm rm
803doCheck=
true
804preCheck=
"patchShebangs contrib tests"

Pointers that Guile keeps as scm_t_bits words, weak tables on FUGC, continuations without C stack copying: see docs/guile.md.

811guile_3_0=
811guile_3_0
patch./ports/patch/guile-3.0.11.patch

Nixpkgs' cross-build fix is already in 3.0.11.

skipPatch"c117f8edc471d3362043d88959d73c6a37e7e1e9"

Guile's JIT emits machine code.

configure"--disable-jit"
use
λold
818depsBuildBuild=
pkgs.stdenv.cc
819nativeBuildInputs=
old.nativeBuildInputs ++ guileForBuild

A smoke test of the installed interpreter. The test suite is run by hand (docs/guile.md); like Nixpkgs, the build skips it.

822doInstallCheck=
true
823installCheckPhase=
runHook preInstallCheck
$out/bin/guile -c '
(use-modules (ice-9 match) (srfi srfi-1) (ice-9 format))
(define (fib n) (if (< n 2) n (+ (fib (- n 1)) (fib (- n 2)))))
(unless (= (fib 20) 6765) (exit 1))
(unless (equal? (match (list 1 2 3) ((a . b) b)) (list 2 3)) (exit 1))
(gc)
(unless (= (fold + 0 (iota 100000)) 4999950000) (exit 1))
(unless (string=? (format #f "~a-~s" 1 "x") "1-\"x\"") (exit 1))
(unless (= 3 (call/cc (lambda (k) (+ 1 (k 3))))) (exit 1))
(display "guile ok\n")'
runHook postInstallCheck

Nixpkgs lists guile only as a host input, so configure finds no guile to compile the modules with. The build platform's guile cannot load Fibers' Fil-C extension, which configure checks for, so use the Fil-C guile itself: it runs on the build machine.

844gnu-shepherd=
844gnu-shepherd
useold: nativeBuildInputs = old.nativeBuildInputs ++ filcGuileForBuild;

Pure Guile. As with gnu-shepherd, configure needs a guile, and its tests run with the Fil-C one.

852lilypond=
852lilypond

The default TeX is built from the host package set, since it is a derived value that splicing does not reach; it only runs at build time.

arg

WIP: the Fil-C ghostscript-with-X fails configure (its -lz check links the build platform's zlib), so the lilypond wrapper puts the build platform's gs on PATH for PDF output.

860ghostscript=
pkgs.buildPackages.ghostscript
861tex=
pkgs.buildPackages.texliveSmall.withPackagesps: with ps; epsf fontinst fontware lh metafont
use
λold

Nixpkgs lists guile only as a build tool. LilyPond links libguile, and the build runs the Fil-C lilypond (it runs on the build machine) to compile its Scheme files.

875nativeBuildInputs=
builtins.filterd: ¬pkgs.lib.hasPrefix"guile" d.name or "" old.nativeBuildInputs ++ guileForBuild
880buildInputs=
old.buildInputs ++ final.guile_3_0

configure sets CROSS=yes, which drops the rules that run the programs (help2man, lilypond itself) but not the targets that need them. Fil-C programs run on the build machine.

884makeFlags=
old.makeFlags or [ ] ++ "CROSS=no"

handle_broken_dependencies () replaces the system's all-elements Grob_array, so the old one can be collected and deleted while this function still reads it through a reference (a use-after-free that Fil-C stops in 19 regression tests). Keep its SCM alive until the end.

890postPatch=
old.postPatch or ""
+
substituteInPlace lily/system.cc \
--replace-fail \
'std::vector<Grob *> &all_elts = all_elements ()->array_reference ();' \
'SCM all_elts_scm = get_object (this, "all-elements");
std::vector<Grob *> &all_elts = all_elements ()->array_reference ();' \
--replace-fail \
'debug_output (_f ("Element count %zu", count + all_elts.size ()) + "\n");' \
'debug_output (_f ("Element count %zu", count + all_elts.size ()) + "\n");
scm_remember_upto_here_1 (all_elts_scm);'
904guile-zlib=
905guile-gcrypt=
905guile-gcrypt

Otherwise configure finds the build platform's libgcrypt-config and records that libgcrypt for the FFI.

configure"--with-libgcrypt-prefix=${final.libgcrypt.dev}"
configure"--with-libgcrypt-libdir=${pkgs.lib.getLibfinal.libgcrypt}/lib"
guileTestsOnFilc
912guile-lzlib=
912guile-lzlib

configure finds liblz by running ldd on a test program, which does not work for a Fil-C program.

configure"guile_cv_liblz_libdir=${final.lzlib.out}/lib/liblz.so"
guileTestsOnFilc
918guile-zstd=
919guile-lzma=
920guile-sqlite3=
920guile-sqlite3
guileTestsOnFilc
921guile-git=
921guile-git
guileTestsOnFilc

Connecting to a socket that never accepts times out with a GITERR_OS error instead of GITERR_NET with the Fil-C libgit2.

use
λold
926preCheck=
old.preCheck or ""
+
substituteInPlace tests/clone.scm --replace-fail \
'(test-equal "clone beyond timeout"' \
'(test-skip 1) (test-equal "clone beyond timeout"'
933guile-avahi=
933guile-avahi

Clang reports an unused static function that GCC does not.

addCFlag"-Wno-error=unused-function"
guileTestsOnFilc
939guix=
939guix

configure takes libgcrypt from the build platform's libgcrypt-config otherwise; the path also ends up in guix/config.scm for the FFI.

configure"--with-libgcrypt-prefix=${final.libgcrypt.dev}"
configure"--with-libgcrypt-libdir=${pkgs.lib.getLibfinal.libgcrypt}/lib"
use
λold

graphviz (for documentation figures) fails to build natively at this Nixpkgs pin (its X variant installs no vimdot), so use the variant without X. slirp4netns (for container networking) needs libseccomp, and the Fil-C runtime does not support the seccomp system call.

951nativeBuildInputs=
builtins.filterd: ¬builtins.elemd.pname or "" "graphviz" "slirp4netns" old.nativeBuildInputs ++ pkgs.buildPackages.graphviz-nox
960propagatedBuildInputs=
builtins.filterd: d.pname or "" ≢ "slirp4netns" old.propagatedBuildInputs

The build-time tools (guile, makeinfo for the translated manuals) need a UTF-8 locale; the native build gets it from glibcLocales' hook, which does not apply here.

966LOCALE_ARCHIVE=
"${pkgs.buildPackages.glibcLocales}/lib/locale/locale-archive"
967LC_ALL=
"C.UTF-8"

The wrapper records $GUILE_LOAD_PATH, which also holds the build platform's Guile libraries (used to compile the modules); their FFI bindings point at native libraries, which a Fil-C process cannot load. Keep only the host's.

972preInstall=
old.preInstall or ""
+
hostOnly() { printf %s "$1" | tr : '\n' | grep -- -gnufilc0- | paste -sd: -; }
export GUILE_LOAD_PATH=$(hostOnly "$GUILE_LOAD_PATH")
export GUILE_LOAD_COMPILED_PATH=$(hostOnly "$GUILE_LOAD_COMPILED_PATH")
980mcron=
980mcron
useold: nativeBuildInputs = old.nativeBuildInputs ++ filcGuileForBuild;
986mailutils=
986mailutils

Configure finds GNU gss unusable for Fil-C.

removeConfigureFlag"--with-gssapi"
use
λold

guile-config runs an unprefixed pkg-config; give it the host's, so that it reports the Fil-C guile.

992nativeBuildInputs=
old.nativeBuildInputs ++ guileForBuild pkgs.writeShellScriptBin"pkg-config" ''exec "$PKG_CONFIG" "$@"''

The Guile binding tests load the Fil-C libmu_scm, so they need the Fil-C guile (it runs on the build machine).

998preCheck=
old.preCheck or ""
+
export PATH=${final.guile_3_0}/bin:$PATH

Out-of-bounds reads that Fil-C stops: imap4d's LIST reads ref[-1] for an empty reference; in test helpers, a memmove from the wrong offset, a loop that tests the output pointer instead of the input, and argv[i][len - 1] on an empty argument.

1005postPatch=
old.postPatch or ""
+
substituteInPlace imap4d/list.c \
--replace-fail "if (ref[refinfo.reflen-1] != pfx->delim" \
"if (refinfo.reflen > 0 && ref[refinfo.reflen-1] != pfx->delim"
# Its word-wrapping stream kept writing after a failed flush
# (EPIPE when mail --version is piped into sed, which quits
# after the first line), past the end of its line buffer.
substituteInPlace libmailutils/stream/wordwrap.c --replace-fail \
" _wordwrap_flush_line (str, iptr[n]);" \
" { int rc = _wordwrap_flush_line (str, iptr[n]); if (rc) return rc; }"
substituteInPlace testsuite/cwdrepl.c \
--replace-fail 'size_t rest = n - start;' 'size_t rest = n - off;'
substituteInPlace libmailutils/tests/encode2047.c \
--replace-fail 'for (p = buf; *p;)' 'for (p = buf; *buf;)'
substituteInPlace libmailutils/tests/tesh.c \
--replace-fail "if (argv[i][len - 1] == ';')" \
"if (len > 0 && argv[i][len - 1] == ';')"
1032gnumake
patch./ports/patch/make-4.4.1.patch
argguileSupport = false;
1042gnutar
patch./ports/patch/tar-1.35.patch
skipPatch"acl-2.4.0-name-conflicts.patch" also part of the port
argaclSupport = false;

Build Tools

qemu-img is only on the PATH of cloud-localds and the other image tools in $out, and the Fil-C QEMU does not build yet. growpart, in the guest output that NixOS's boot.growPartition uses, does not need it.

1062cloud-utils
argqemu-utils = pkgs.emptyDirectory;
1066cmake

No Fil-C source patch; Nixpkgs 26.05's patches only apply to 4.x.

skipCheck"some tests fail"
addCMakeFlag"-DCMAKE_VERBOSE_MAKEFILE=ON"
addCMakeFlag"-DCMAKE_CXX_COMPILER=${pkgs.lib.getBinprev.stdenv.cc}/bin/c++"
addCMakeFlag"-DCMAKE_C_COMPILER=${pkgs.lib.getBinprev.stdenv.cc}/bin/cc"
addCMakeFlag"-DCMAKE_EXE_LINKER_FLAGS=-lm"

Only the C API is used. Avoid the unsupported target Fortran compiler and OpenMP runtime. The other precisions are overrides of this one.

1079v4l-utils

The BPF decoders are compiled by a clang for the BPF target.

argwithBPF = false;
1085ffmpeg-headless=
1085ffmpeg-headless

Upstream Fil-C's FFmpeg 8.0.1 port applies unchanged to 8.1.

patch./ports/patch/ffmpeg-8.0.1.patch
use
λold

8.1 keeps the log callback in an atomic_uintptr_t, which drops the function pointer's capability; every av_log call trapped.

1091postPatch=
old.postPatch or ""
+
"\n"
+
substituteInPlace libavutil/log.c \
--replace-fail \
'static atomic_uintptr_t av_log_callback = (uintptr_t)av_log_default_callback;' \
'static void (*_Atomic av_log_callback)(void*, int, const char*, va_list) = av_log_default_callback;' \
--replace-fail \
'atomic_store_explicit(&av_log_callback, (uintptr_t)callback,' \
'atomic_store_explicit(&av_log_callback, callback,'
# flashsv2 rebased block pointers from one buffer into another
# with a pointer difference, keeping the first buffer's bounds.
substituteInPlace libavcodec/flashsv2enc.c --replace-fail \
's->key_blocks[i].enc += (s->keybuffer - s->encbuffer);' \
's->key_blocks[i].enc = s->keybuffer + (s->key_blocks[i].enc - s->encbuffer);'

Hand-written x86 assembly and inline assembly; upstream builds the same way.

configure"--disable-asm"

CUDA kernels would be compiled by a clang for the NVPTX target.

arg
1114withCudaLLVM=
false
1115withNvcodec=
false

x265 builds its 10/12-bit variants with GCC, and vid.stab uses OpenMP; neither toolchain targets Fil-C.

1118withX265=
false
1119withVidStab=
false
1125libgbm=
1125libgbm

Mesa's BLAKE3 has hand-written x86-64 assembly; use its C versions, as Mesa itself does for x32.

use
λold
1129postPatch=
old.postPatch or ""
+
"\n"
+
substituteInPlace src/util/blake3/meson.build \
--replace-fail "elif cc.sizeof('void *') == 4" "elif true"
1140imlib2

Hand-written AMD64 blending assembly.

configure"--enable-amd64=no"
1145libvpx

Build without the x86 assembly and intrinsics dispatch.

removeConfigureFlag"--target=x86_64-linux-gcc"
configure"--target=generic-gnu"
argruntimeCpuDetectSupport = false;
1152libgit2
patch./patches/libgit2-configmap-cache-clear.patch

xdiff adds src/util as a SYSTEM include directory, which then comes after the wrapper's -isystem for Fil-C glibc, whose obsolete <regexp.h> stub shadows libgit2's own "regexp.h".

use
λold
1158postPatch=
old.postPatch or ""
+
"\n"
+
substituteInPlace deps/xdiff/CMakeLists.txt \
--replace-fail "target_include_directories(xdiff SYSTEM PRIVATE" \
"target_include_directories(xdiff PRIVATE"

Video codecs: build the portable C code paths, without hand-written assembly or intrinsics dispatch.

1171x264
configure"--disable-asm"
1172svt-av1
removeCMakeFlag"-DSVT_AV1_LTO=ON"
addCMakeFlag"-DCOMPILE_C_ONLY=ON"
1176libavif

Honor allocation-failure returns for sizes that cannot be C objects.

patch./patches/libavif-allocation-size.patch
1180libaom
addCMakeFlag"-DAOM_TARGET_CPU=generic"

Keep the owning malloc pointer's capability in the aligned header.

patch./patches/libaom-allocation-pointer.patch
useold: passthru = old.passthru or { } // tests = old.passthru.tests or { } // allocation-encoder = import./tests/libaom.nix pkgs = final;;;;
1193onetbb

tbbmalloc carves objects out of raw mmap chunks, so its pointers carry no capability; TBB falls back to malloc without it.

addCMakeFlag"-DTBBMALLOC_BUILD=OFF"
  • queuing_rw_mutex tags its queue pointers in std::atomic<uintptr_t>; keep them in std::atomic<char*> and set the tag by pointer arithmetic.
  • Clang claims __GNUC__ 4, so TBB picked a "lock; notb" fence and stmxcsr/fstcw for the FPU state, inline asm with memory operands that Fil-C refuses; use std::atomic_thread_fence and <fenv.h>.
patch./patches/onetbb-fil-c.patch
use
λold
1204postPatch=
old.postPatch or ""
+
"\n"
+
# The tests use doctest, whose signal handling needs sigaltstack.
sed -i '/#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN/a #define DOCTEST_CONFIG_NO_POSIX_SIGNALS' \
test/common/test.h
grep -q DOCTEST_CONFIG_NO_POSIX_SIGNALS test/common/test.h
1213disabledTests=
old.disabledTests or [ ]
++

They expect allocations of nearly 2^64 bytes to throw bad_alloc; Fil-C stops the program instead.

"test_allocators"
"conformance_allocators"

Its own cpuid inline asm does not declare the clobbered ecx.

"test_mutex"

Not usable yet: the task scheduler and collaborative_call_once still keep pointers in integers and trap in most tests, and test_eh_algorithms spins. Marked unsupported so that dependents (libblake3's useTBB, ...) leave it out.

1225meta=
old.meta // badPlatforms = old.meta.badPlatforms or [ ] ++ prev.stdenv.hostPlatform.system;
1233libblake3
addCMakeFlag"-DBLAKE3_SIMD_TYPE=none"
1235wavpack
configure"--disable-asm"

Its MMX/SSE routines are yasm assembly, which Fil-C cannot link.

1238xvidcore
configure"--disable-assembly"
1240libopus
patch./ports/patch/opus-1.5.2.patch

Without the x86 intrinsics and their run-time CPU dispatch.

addMesonFlag"-Dintrinsics=disabled"
addMesonFlag"-Drtcd=disabled"
1249libopenmpt
patch./patches/libopenmpt-x87-control-word.patch

Found by Fil-C: a use-after-free when libc++'s codecvt returns partial, as it does for non-ASCII text in the C locale.

patch./patches/libopenmpt-codecvt-partial.patch

libpulseaudio is pulseaudio.override { libOnly = true; }, so this covers the library, the daemon and its modules.

1258pulseaudio

pa_atomic_ptr_t kept pointers in a uintptr_t, dropping their capabilities (pa_once's mutex came back null).

patch./patches/pulseaudio-atomic-ptr.patch
use
λold

PA_WARN_REFERENCE emits .gnu.warning sections as module asm, which FilPizlonator does not accept; drop the link-time warnings.

1265postPatch=
old.postPatch or ""
+
substituteInPlace src/pulsecore/macro.h --replace-fail \
'#if defined(__GNUC__) && defined(__ELF__)' '#if 0'
# Report no MMX/SSE, so the inline-asm mixing and volume routines
# stay unused.
substituteInPlace src/pulsecore/cpu-x86.c --replace-fail \
'/* get standard level */' 'return;'
# Fil-C's abort() raises SIGTRAP, and SIGBUS handlers are refused.
sed -i 's/\(test_replace_fail_[0-9]\), SIGABRT/\1, SIGTRAP/' \
src/tests/core-util-test.c
sed -i "/\[ 'sigbus-test', 'sigbus-test.c',/,+1d" src/tests/meson.build

The mix and remap benchmarks outlast their 120 s check timeout.

1278env=
old.env or { } // CK_TIMEOUT_MULTIPLIER = "5";

The C implementations instead of the perlasm AES, SHA, bignum and RC4 routines.

1286libressl
addCMakeFlag"-DENABLE_ASM=OFF"
use
λold

explicit_bzero's test inspects a signal handler's sigaltstack.

1290postPatch=
old.postPatch or ""
+
"\n"
+
substituteInPlace tests/CMakeLists.txt --replace-fail \
'add_test(explicit_bzero explicit_bzero)' ""
1300physfs
use
λold

The LZMA SDK's PIC cpuid saves %rbx in %rdi around cpuid, so the asm clobbers %ebx without saying so, which FilPizlonator rejects. Name %ebx as the output instead.

1305postPatch=
old.postPatch or ""
+
substituteInPlace src/physfs_lzmasdk.h --replace-fail \
'#if defined(MY_CPU_AMD64) && defined(__PIC__)' \
'#if defined(MY_CPU_AMD64) && defined(__PIC__) && !defined(__FILC__)'
1313btrfs-progs
use
λold

Only the table-driven CRC32C: the PCLMUL one is hand-written assembly, and the SSE4.2 one emits crc32 as .byte inline asm.

1317postPatch=
old.postPatch or ""
+
"\n"
+
substituteInPlace Makefile --replace-fail \
'CRYPTO_OBJECTS += crypto/crc32c-pcl-intel-asm_64.o' ""
substituteInPlace crypto/crc32c.c --replace-fail \
'#ifdef __x86_64__' '#if defined(__x86_64__) && !defined(__FILC__)'

The suites that need neither root nor a block device: the hash test vectors and speed test, and the string-table and array units.

1328doCheck=
true
1329checkTarget=
"test-hash test-string-table test-array"
1333isa-l
use
λold

Build as for an unknown CPU: the portable C "base" functions, without the yasm/nasm kernels and their multibinary dispatch.

1337postPatch=
old.postPatch or ""
+
substituteInPlace configure.ac --replace-fail \
'[x86_64], [CPU="x86_64"],' '[x86_64], [CPU=""],' \
--replace-fail '-D_FORTIFY_SOURCE=2 \' '\'

igzip's base hash-table reset calls wmemset, and Fil-C's glibc has no __wmemset_chk.

1344hardeningDisable=
old.hardeningDisable or [ ] ++ "fortify"

The unit tests for every function set.

1346doCheck=
true

pname is crypto++.

1352cryptopp=
1352cryptopp
use
λold

Plain C++ instead of the inline asm and SIMD intrinsics; e.g. SecureWipeBuffer's repstos has the pointer as an asm output. Set in config_asm.h so programs using the headers agree.

1357postPatch=
old.postPatch or ""
+
substituteInPlace config_asm.h --replace-fail \
'// #define CRYPTOPP_DISABLE_ASM 1' \
'#if defined(__FILC__)
# define CRYPTOPP_DISABLE_ASM 1
#endif'
# Integer's x86-64 word arithmetic is inline asm regardless;
# multiply through unsigned __int128 as on other 64-bit targets.
substituteInPlace integer.cpp --replace-fail \
'((defined(__aarch64__) || defined(__x86_64__)) && defined(CRYPTOPP_WORD128_AVAILABLE))' \
'((defined(__aarch64__) || (defined(__x86_64__) && !defined(__FILC__))) && defined(CRYPTOPP_WORD128_AVAILABLE))'
1373rubberband
use
λold

RTENTRY__ annotates the real-time entry points with __attribute__((annotate)), which crashes FilPizlonator.

1377postPatch=
old.postPatch or ""
+
"\n"
+
substituteInPlace src/common/sysutils.h --replace-fail \
'# define RTENTRY__ __attribute__((annotate("realtime")))' \
'# define RTENTRY__'

Nixpkgs disables the Boost.Test suite for want of Boost.

1386buildInputs=
old.buildInputs or [ ] ++ final.boost
1387doCheck=
true
removeMesonFlag"-Dtests=disabled"
addMesonFlag"-Dtests=enabled"
1393libcamera

LTTng-UST tracepoints; the tracer's own tests exercise signal and namespace machinery Fil-C does not provide.

arg
1397withTracing=
false

jinja2, PyYAML and ply run on the build Python (3.13); the Fil-C set is for the ported 3.12, so meson could not import jinja2.

1400python3Packages=
pkgs.python3Packages

The experimental Python bindings would need the Fil-C Python.

addMesonFlag"-Dpycamera=disabled"
patch./patches/libcamera-no-dynamic.patch
1407polkit

polkit's hand-written get_type functions keep the GType in a volatile gsize, but GType is a pointer in Fil-C's GLib; use a GType with g_once_init_{enter,leave}_pointer (GLib 2.80).

patch./patches/polkit-pointer-gtype.patch

The runaway-script test needs asynchronous pthread_cancel, which Fil-C does not deliver (SIGCANCEL is reserved by the runtime); it hung forever. Under Fil-C a runaway rules script is not killed.

patch./patches/polkit-filc-no-runaway-test.patch

gtk-doc generates an unported GType scanner; GIR generation stays on.

removeMesonFlag"-Dgtk_doc=true"
addMesonFlag"-Dgtk_doc=false"
1421libgudev

The tests preload umockdev, whose Vala-generated code assumes integer GTypes, and LD_PRELOAD interposition does not apply to Fil-C symbols.

use
λold
1425doCheck=
false

GType is a pointer in Fil-C's GLib.

1427postPatch=
old.postPatch or ""
+
substituteInPlace gudev/gudevenumtypes.c.template \
--replace-fail 'static gsize static_g_define_type_id' \
'static GType static_g_define_type_id' \
--replace-fail 'g_once_init_enter (' 'g_once_init_enter_pointer (' \
--replace-fail 'g_once_init_leave (' 'g_once_init_leave_pointer ('
# Clang has no -export-dynamic driver flag (GCC passes it to ld).
substituteInPlace gudev/meson.build \
--replace-fail "'-export-dynamic'," "'-Wl,--export-dynamic',"
1440libical

The libical-glib install check runs PyGObject on the build platform, which the Fil-C Python port's package overrides (pyports.nix) also reach and break.

use
1445doInstallCheck=
false
1446nativeInstallCheckInputs=
[ ]
1450libshout

configure only finds -lssl, but libshout also calls libcrypto directly.

addCFlag"-Wl,-lcrypto"
1455ell
patch./patches/ell-no-debug-section.patch

test-ecdh wraps l_getrandom with ld --wrap, whose __real_ symbol Fil-C does not rename.

skipCheck"ld --wrap"
1462bluez

BlueZ builds against the copy of ELL's headers in its tarball.

patch./patches/ell-no-debug-section.patch
patch./patches/bluez-no-debug-section.patch

The MIDI profile stores pointers into ALSA's packed snd_seq_ev_ext, at a misaligned offset where Fil-C cannot keep a capability.

removeConfigureFlag"--enable-midi"
configure"--disable-midi"
use
λold

The installed test scripts run on Fil-C Python with its dbus-python and PyGObject. The build Python's wrapPython would give them the build interpreter and search its own, empty, site-packages layout.

1474nativeBuildInputs=
map
λp
pkgs.lib.hasPrefix"wrap-python-hook" p.name or ""
→
final.python3Packages.wrapPython
else
old.nativeBuildInputs
1484liburcu

Use compiler atomics instead of the x86 inline assembly ones.

configure"--enable-compiler-atomic-builtins"

The x86 header still used inline-assembly barriers ("lock; addl"), which Fil-C rejects when they run, and the memb flavor probed membarrier(2), which Fil-C refuses by stopping the program. Use the generic builtin barriers and the existing no-membarrier fallback. With that, the unit tests (674) pass and run again. rculfhash (BIND's dns tests) also needed the generic fls instead of bsr assembly, its node flags set and cleared with zorptr/zandptr rather than integer math, which dropped the next pointers' capabilities, and REMOVED_FLAG set by pointer CAS, since an integer atomic or was not seen by atomic pointer loads.

patch./patches/liburcu-filc.patch
use
λold
1499postCheck=
old.postCheck or ""
+
$CC -Iinclude ${./tests/liburcu-lfht.c} -Lsrc/.libs \
-Wl,-rpath,"$PWD/src/.libs" -lurcu -lurcu-cds -pthread \
-o lfht-test
./lfht-test
1508lttng-ust

With liburcu's compiler-builtin atomics, uatomic_or on the tagged node->next pointer does not compile; set the flag with a CAS loop.

patch./patches/lttng-ust-rculfhash-removed-flag.patch

Fil-C has no dl_iterate_phdr, which the base-address statedump uses to list loaded objects; skip that statedump.

patch./patches/lttng-ust-no-dl-iterate-phdr.patch

liblttng-ust-common's constructor probed membarrier(2), which Fil-C refuses by stopping the program; use the existing smp_mb fallback.

patch./patches/lttng-ust-no-membarrier.patch

Fil-C has no __start_/__stop_ section symbols, and the weak references in <lttng/tracepoint.h> crashed every instrumented program at startup; register each tracepoint from a constructor.

patch./patches/lttng-ust-tracepoint-ctor-registration.patch

libnuma's numa_preferred() trips a bounds check in Fil-C's get_mempolicy wrapper (docs/filc-findings.md), which the ring buffer calls for every channel.

configure"--disable-numa"
1528mbedtls
patch./patches/mbedtls-test-cli-crt-ec-der-len.patch

AES-NI, PadLock and bignum inline assembly pass pointers to asm.

use
λold
1532postPatch=
old.postPatch or ""
+
"\n"
+
for option in MBEDTLS_AESNI_C MBEDTLS_PADLOCK_C MBEDTLS_HAVE_ASM; do
${pkgs.python3}/bin/python3 scripts/config.py unset $option
done
1543libpq

libpq refuses to link anything named like exit. Fil-C 0.687 lowers small allocas to filc_allocate_without_exiting, which never exits.

use
λold
1547postPatch=
old.postPatch or ""
+
substituteInPlace src/interfaces/libpq/Makefile \
--replace-fail '-e __tsan_func_exit' '-e __tsan_func_exit -e _without_exiting'

Nixpkgs uses -flto with Clang to drop unused pg_config paths (and the dev-output references they carry). Fil-C has no LTO linker plugin, so garbage-collect sections at link time instead, as with GCC.

useold: env = old.env // CFLAGS = "-fdata-sections -ffunction-sections -Wl,--gc-sections";;

Fil-C keeps each function's name and source file for its stack traces outside the debug sections. Inlined OpenSSL header functions thus name openssl-dev headers, which outputChecks forbids in $out.

toolpkgs.removeReferencesTo
use
λold
1565postInstall=
old.postInstall
+
"\n"
+
remove-references-to ${pkgs.lib.concatMapStringsSep" " d: "-t ${pkgs.lib.getDevd}" builtins.filterd: d ? dev old.buildInputs} $out/lib/*.so*
1578libmpdclient

Nixpkgs lists the check library and pkg-config as native check inputs; meson looks the library up for the host at configure time.

use
λold
1582nativeBuildInputs=
old.nativeBuildInputs ++ pkgs.pkg-config
1583nativeCheckInputs=
[ ]
1584checkInputs=
final.check
1588liblc3

Meson's default b_lto would hand bitcode to the linker.

addMesonFlag"-Db_lto=false"
1593mpdecimal

The x64 configuration multiplies with mulq inline assembly that Fil-C rejects, so str(decimal.Decimal("1.5")) trapped in every Fil-C Python.

configure"MACHINE=ansi64"
1600gmp=
1600gmp

Upstream Fil-C disables this standalone assembly timing helper in generated configure; the port extractor deliberately omits that file.

use
λold
1604postPatch=
old.postPatch or ""
+
substituteInPlace configure \
--replace-fail 'SPEED_CYCLECOUNTER_OBJ_64=x86_64.lo' 'SPEED_CYCLECOUNTER_OBJ_64=' \
--replace-fail 'cyclecounter_size_64=2' 'cyclecounter_size_64='
configure"--disable-assembly"
configure"--disable-fat"

Compression

patch./ports/patch/xz-5.8.4.patch
skipCheck"too slow"

The port changes Makefile.am; regenerate with Nixpkgs' Autotools.

toolpkgs.autoreconfHook
1624zstd
patch./ports/patch/zstd-1.5.6.patch

1.5.7's pointer-select inline asm is independent of ZSTD_DISABLE_ASM.

patch./patches/zstd-pointer-select.patch
patch./patches/zstd-lz4-checksum.patch
skipCheck"too slow"
addCFlag"-DZSTD_DISABLE_ASM"
1633lz4
src"1.11.0" "sha256-JH5fpk2l97de49077UhAdjlsnr6CVNnM9pPrYoAMXiY=" v: "https://github.com/lz4/lz4/releases/download/v${v}/lz4-${v}.tar.gz"

Already included in the new release.

skipPatch"CVE-2025-62813.patch"
patch./ports/patch/lz4-1.11.0.patch
1643gnupatch=
1643gnupatch
src"2.8.1" "sha256-MkDHlZxTR8jtNH48QgHAM3v0JA1c8J1oiJ5Y7qujDhc=" v: "mirror://gnu/patch/patch-${v}.tar.xz"

Only the target package changes; native build tools remain Nixpkgs'.

1651patchelf
src"0.19.3" "sha256-+sdqPAtzDo1T6h0QzWAVMi14yZAK+Rc28sylHVg3thI=" v: "https://github.com/NixOS/patchelf/releases/download/${v}/patchelf-${v}.tar.gz"

These are deliberately unusual ELF/assembly fixtures, not installed programs. Run the Fil-C patchelf against native fixtures, including non-PIE files and assembly that has no SaRCAsm annotations.

use
λold
1660preCheck=
old.preCheck or ""
+
export PATH=${pkgs.buildPackages.glibc.bin}/bin:$PATH
# The native wrapper has its own role salt in this cross build.
export NIX_DONT_SET_RPATH_${pkgs.buildPackages.stdenv.cc.suffixSalt}=1
substituteInPlace tests/no-rpath.sh --replace-fail \
'--print-interpreter ../src/patchelf' '--print-interpreter no-rpath'
1667checkFlags=
old.checkFlags or [ ] ++ "CC=${pkgs.buildPackages.stdenv.cc}/bin/cc" "CCAS=${pkgs.buildPackages.stdenv.cc}/bin/cc" "CXX=${pkgs.buildPackages.stdenv.cc}/bin/c++"
1675lzo
skipTests"too slow"
configure"--disable-asm"

Networking

1682curl
argidnSupport = true;
argpslSupport = true;
argzstdSupport = true;
argbrotliSupport = true;
argscpSupport = false;
skipCheck"network tests flaky"
1691git
pin"2.46.0" "sha256-fxI0YqKLfKPr4mB0hfcWhVTCsQ38FVx+xGMAZmrCf5U="
skipPatch"git-send-email-honor-PATH.patch"

Test adjustments for newer releases; the suite is skipped below.

skipPatch"t7703-ignore-ls-total.patch"
skipPatch"expect-gui--askyesno-failure-in-t1517.patch"
patch./ports/patch/git-2.46.0.patch
argwithManual = true;
argperlSupport = false;
argpythonSupport = true;
argsendEmailSupport = false;
argzlib-ng = pkgs.zlib;
skipTests"too slow"
removeMakeFlag"ZLIB_NG=1"
1707nghttp2
src"1.71.0" "sha256-wPVRIdiGUOS5InrsKM669mTSQXymD+cL4PjTiCn1IRY=" v: "https://github.com/nghttp2/nghttp2/releases/download/v${v}/nghttp2-${v}.tar.xz"
configure"--disable-app"
addCFlag"-Wno-deprecated-literal-operator"
1716openssh
pin"10.6p2" "sha256-muRIcgkM8vBrPPn/FH5/FvMJZxNAdj7S+ZJIOYrinVs="
patch./ports/patch/openssh-10.6p2.patch
skipCheck"let's see"

preCheck preloads libredirect, whose dlsym(RTLD_NEXT, ...) interposition cannot work under Fil-C; referencing it would still build it.

usepreCheck = "";
use
1724installCheckPhase=
for binary in ssh sshd; do
echo "verifying OpenSSH version $version"
output=$($out/bin/$binary -V 2>&1)
echo "got output: $output"
echo "expected output: $(printf '^OpenSSH_%s,' "$version")"
if ! echo "$output" | grep -P "$(printf '^OpenSSH_%s,' "$version")"; then
echo "OpenSSH version verification failed"
exit 1
fi
done
argwithFIDO = false;

Cross autoconf can't run its malloc(0) test and assumes the worst, defining malloc as an rpl_malloc nobody provides. glibc's is fine.

1742davfs2
configure"ac_cv_func_malloc_0_nonnull=yes"
configure"ac_cv_func_realloc_0_nonnull=yes"
1747libssh2
skipCheck"network tests flaky"
configure"--disable-examples-build"
1752unbound
configure"ac_cv_type_pthread_spinlock_t=no"

With dnstap (unbound-full), Nixpkgs puts protobuf-c only in nativeBuildInputs, so a cross build has protoc-c but not the library.

useold: pkgs.lib.optionalAttrspkgs.lib.elem"--enable-dnstap" old.configureFlags or [ ] buildInputs = old.buildInputs ++ final.protobufc;
1766bind

Fixes CVE-2026-19630, -94300, -96888 and -97313 (2026-10-21).

pin"9.20.30" "sha256-nhRDpApyowJyy8MZbQIKay4mk3ERyD5Z4QHoLh47T+8="

Read named.conf, rndc.conf and rndc.key from /etc/bind, as Debian and ISC's image do, rather than the store; bind-dist relies on it.

configure"--sysconfdir=/etc/bind"

isc_mempool kept free lists of message names, rdatasets and netmgr sockets and requests, so a use after isc_mempool_put reached a live recycled object that Fil-C cannot flag. Free each one, as BIND does under ASan.

patch./patches/bind-mempool-no-freelist.patch

A qp-trie node kept its leaf and reader pointers split across two uint32_t halves of a 12-byte node, so every lookup read a pointer without a capability. Under Fil-C the word is a void * (16-byte nodes), tagged with pointer arithmetic.

patch./patches/bind-qp-node-pointer.patch

Under Fil-C a local whose address escapes is a zeroed heap allocation, and so is the temporary behind a large compound-literal assignment. Each query made about 60 KB of them (QP-trie chains and iterators, search contexts, the client and netmgr requests), which drove the collector. Initialize in place, allocate only what a call needs, and reuse one zone search context per thread.

patch./patches/bind-filc-heap-temporaries.patch

Three unit tests mock a library function by defining it in the test executable (doh_test's isc__nm_tcp_freebind, query_test's ns_client_error). Fil-C binds calls between a library's own translation units locally, so the mocks never run (docs/filc-findings.md); leave those tests out.

patch./patches/bind-tests-interposed-mocks.patch

Security

1799libseccomp

seccomp_init probed the seccomp() syscall (317), which Fil-C refuses by stopping the program, so every test died (rc=133). Report the syscall as missing; filters still load through prctl(PR_SET_SECCOMP), which Fil-C passes through, but without TSYNC or user notification.

patch./patches/libseccomp-filc-no-seccomp-syscall.patch

The regression suite only simulates filters; load one for real.

use
λold
1807postCheck=
old.postCheck or ""
+
-Lsrc/.libs -Wl,-rpath,"$PWD/src/.libs" -lseccomp -o prctl-filter
./prctl-filter
1828libgcrypt
configure"--disable-asm"

Upstream's port, rebased: --disable-asm alone leaves inline asm in mpi/longlong.h (bsrq in _gcry_mpi_get_nbits, used by RSA), OCB's ocb_get_l (rep;bsf, which gnupg's t-protect reached) and Keccak, all of which Fil-C traps on. sexp_null_cond selects its pointer as a pointer: rebuilt from masked integers it had no capability unless LLVM folded the round trip (filcc -O0 and nanofil trapped in gcry_pk_decrypt; nanofil/docs/ub.md).

patch./ports/patch/libgcrypt-1.12.2.patch

configure's probe mlocks malloc'ed memory, which Fil-C stops as a safety error, so it concluded mlock is broken and secure memory was never locked (GCRYCTL_INIT_SECMEM failed; t-secmem, t-sexp). The secure memory pool itself is mmapped, which mlock accepts.

configure"gnupg_cv_have_broken_mlock=no"
configure"gcry_cv_gcc_amd64_platform_as_ok=no"
useconfigurePlatforms = "host";
use
1846buildPhase=
sed -i '/HAVE_GCC_ASM_VOLATILE_MEMORY/d' config.h
touch config.status
make -j$NIX_BUILD_CORES

The default check phase runs only after the default build phase (foundMakefile), so the tests were skipped.

1853checkPhase=
runHook preCheck
make -j$NIX_BUILD_CORES check
runHook postCheck
1865libsodium
configure"--disable-ssp"
configure"--disable-asm"

sodium_free finds its guard pages from a pointer rebuilt from a masked integer, which had no capability unless LLVM folded the round trip (filcc -O0 and nanofil trapped; nanofil/docs/ub.md).

patch./ports/patch/libsodium-unprotected-ptr.patch
1874libtasn1
skipTests"one test fails"
1878libgpg-error
use
let
1881lock-obj-gnufilc0=
pkgs.writeText"lock-obj-pub.x86_64-unknown-linux-gnufilc0.h"
## File created by gen-posix-lock-obj - DO NOT EDIT
## To be included by mkheader into gpg-error.h
typedef struct
{
long _vers;
union {
volatile char _priv[40];
long _x_align;
long *_xp_align;
} u;
} gpgrt_lock_t;
#define GPGRT_LOCK_INITIALIZER {1,{{0,0,0,0,0,0,0,0, \
0,0,0,0,0,0,0,0, \
0,0,0,0,0,0,0,0, \
0,0,0,0,0,0,0,0, \
0,0,0,0,0,0,0,0}}}
##
## Local Variables:
## mode: c
## buffer-read-only: t
## End:
##
in
1909postPatch=
cp ${lock-obj-gnufilc0} src/syscfg/lock-obj-pub.x86_64-unknown-linux-gnufilc0.h
1912postConfigure=
cp ${lock-obj-gnufilc0} src/lock-obj-pub.native.h
1919libkrb5

The upstream patch is rooted above Nixpkgs' sourceRoot (src/).

use
λold
1922prePatch=
old.prePatch or ""

pname is cyrus-sasl, so name the attribute explicitly.

1930cyrus_sasl=
1930cyrus_sasl

Upstream backport: configure never defined HAVE_TIME_H, so time() and clock() were implicitly declared; Clang rejects that (GCC and nixpkgs only warn), and the implicit int return truncates time_t.

patch./patches/cyrus-sasl-time-h.patch

mariadb-connector-c and libmysqlclient are aliases of the 3.3 series.

1944mariadb-connector-c_3_3=
1944mariadb-connector-c_3_3

Its export map is an implicit linker script with VERSION blocks and unmangled symbol aliases; gold rejects it and only the driver's --version-script handling knows Fil-C's symbol names.

patch./patches/mariadb-connector-c-version-script.patch
1952p11-kit
skipTests"1 failure"
1956libtirpc

The source still uses K&R function definitions, which C23 removed. Autoreconf'd configure asks for -std=gnu23 (GCC accepts them there anyway; Clang does not), so keep Clang's gnu17 default.

configure"ac_cv_prog_cc_c23=no"
1963rpcbind

Same K&R definitions as libtirpc (rpcinfo.c).

configure"ac_cv_prog_cc_c23=no"
1968duktape
patch./patches/duktape-valstack-rebase.patch
use
1971doInstallCheck=
true
1972installCheckPhase=
"$out/bin/duk" ${./tests/duktape-valstack.js}

Graphics

1980pixman
usemesonFlags = "-Dgnu-inline-asm=disabled" "-Dmmx=disabled" "-Dsse2=disabled" "-Dssse3=disabled";
skipTests"some tests fail"
1996pango

1.57 requires GLib 2.82; the GLib port is 2.80.4.

use
1999version=
"1.56.3"
2000src=
pkgs.fetchurl
2001url=
"mirror://gnome/sources/pango/1.56/pango-1.56.3.tar.xz"
2002hash=
"sha256-JgYlK8Jc2NJOG39+ksOicrN6zWc0NHtztHpIKDS6JJE="
patch./ports/patch/pango-1.54.0.patch
2012graphene
patch./ports/patch/graphene-1.10.8.patch

gtk-doc generates an unported GType scanner; GIR generation stays on.

argwithDocumentation = false;
2018libepoxy

Nixpkgs ties EGL to X11, but GTK's Wayland backend also needs EGL.

use
λold
2021mesonFlags=
builtins.filterf: ¬pkgs.lib.hasPrefix"-Degl=" f old.mesonFlags ++ "-Degl=yes"
2026propagatedBuildInputs=
pkgs.lib.uniqueold.propagatedBuildInputs ++ final.libGL
2029env=
old.env // NIX_CFLAGS_COMPILE = old.env.NIX_CFLAGS_COMPILE or "" + pkgs.lib.optionalStringold.env.NIX_CFLAGS_COMPILE or "" ≡ "" " -DLIBGL_PATH=\"${pkgs.lib.getLibfinal.libGL}/lib\"";
2039fontconfig

ports/patch/fontconfig-2.15.0.patch rebased onto Nixpkgs' 2.17.

patch./patches/fontconfig-2.17-filc.patch
use
2043postPatch=
sed -i 's/ftglue.c/ftglue.c fcfilc.h fcfilc.c/' src/Makefile.am
toolpkgs.autoreconfHook
skipTests"tests pass but some test needs weird deps"
2051freetype
patch./ports/patch/freetype-2.13.3.patch
skipPatch"subpixel-rendering.patch" no need
skipPatch"enable-table-validation.patch" no need
2057harfbuzz
patch./ports/patch/harfbuzz-9.0.0.patch
argwithGraphite2 = false;
skipCheck"fuzzing fails"

The upstream 3.4.4 port also applies to Nixpkgs' 3.6.5 release.

The 1.4 series needs the EOL libsoup 2.

2105libhandy
patch./patches/libhandy-destroy-visible-child.patch
use
λold

librsvg is Rust; there is no Rust target for Fil-C. The icons are pre-rendered below.

2110checkInputs=
builtins.filterdep: ¬pkgs.lib.hasInfix"librsvg" dep.name or "" old.checkInputs or [ ]
2113postPatch=
old.postPatch or ""
+
# The target has no Rust SVG loader. Keep symbolic icon recoloring by
# embedding GTK's encoded PNG format, generated with native tools.
for icon in src/icons/scalable/*/*.svg; do
directory=$(dirname "$icon" | sed s,scalable,128x128,)
mkdir -p "$directory"
GDK_PIXBUF_MODULE_FILE=${pkgs.librsvg}/${pkgs.gdk-pixbuf.binaryDir}/loaders.cache \
${pkgs.gtk3.dev}/bin/gtk-encode-symbolic-svg "$icon" 128x128 -o "$directory"
png="$directory/$(basename "$icon" .svg).symbolic.png"
test -s "$png"
substituteInPlace src/handy.gresources.xml --replace-fail \
"<file preprocess=\"xml-stripblanks\">''${icon#src/}</file>" \
"<file>''${png#src/}</file>"
done
use
2137glib
pin"2.80.4" "sha256-JOApxd/JtE5Fc2l63zMHipgnxIk4VVAEs7kJb6TqA08="
patch./ports/patch/glib-2.80.4.patch
patch./patches/glib-gtype-api-ceiling.patch
patch./patches/glib-atomic-pointer-load.patch
patch./patches/glib-pointer-bit-wait.patch
patch./patches/glib-inline.patch
skipPatch"split-dev-programs.patch"
patch./patches/glib-split-backport.patch
arg
2147libsysprof-capture=
null

Keep the bootstrap GLib free of scanner inputs as well as GIR output.

2149withIntrospection=
false

gdbus-codegen runs on the build Python (3.13); the Fil-C set's packaging is for the ported 3.12, leaving codegen's path empty.

2152python3Packages=
pkgs.python3Packages
skipTests"many failures"
usemesonFlags = "-Ddevbindir=${placeholder"dev"}/bin" "-Dglib_debug=disabled" "-Ddocumentation=true" pkgs.lib.mesonBool"dtrace" false pkgs.lib.mesonBool"systemtap" false "-Dnls=enabled" pkgs.lib.mesonEnable"introspection" false "-Dtests=false";

gio-querymodules loads the modules it indexes, so consumers must run this one rather than the build GLib's. Meson prefers a cross file's binaries over its native pkg-config lookup.

use
λold
2171postFixup=
old.postFixup or ""
+
mkdir -p "$dev/share/meson"
cat > "$dev/share/meson/gio-querymodules.ini" <<EOF
[binaries]
gio-querymodules = '$dev/bin/gio-querymodules'
EOF
cat >> "$dev/nix-support/setup-hook" <<EOF
if (( hostOffset == 0 )) && [[ -z "\''${filcGioQuerymodulesCrossFile-}" ]]; then
filcGioQuerymodulesCrossFile=1
mesonFlagsArray+=("--cross-file=$dev/share/meson/gio-querymodules.ini")
fi
EOF
2189gobject-introspection-unwrapped=
2189gobject-introspection-unwrapped
pin"1.80.1" "sha256-od98Qk4VvaGrY5wA6QUbmt9c6hqeUS+KYDtTzRmbxtg="
patch./ports/patch/gobject-introspection-1.80.1.patch
patch./patches/gobject-introspection-filc-tools.patch
patch./patches/gobject-introspection-link-environment.patch
skipPatch"Prefer-some-getters-over-others.patch"
arg
2196propagateFullGlib=
false

Fil-C executables run directly on the build machine. Bootstrap the scanner here instead of recursively asking for a prebuilt scanner.

2199gobject-introspection-unwrapped=
null
removeMesonFlag"-Dgi_cross_use_prebuilt_gi=true"
addMesonFlag"-Dgi_cross_use_prebuilt_gi=false"
use
λold
2204nativeBuildInputs=
builtins.filterinput: input ≢ null old.nativeBuildInputs

_giscanner is compiled with Fil-C and must be loaded by Fil-C Python.

2208mesonFlags=
old.mesonFlags ++ "-Dpython=${final.python3.withPackagesps: ps.mako ps.markdown ps.setuptools}/bin/python3"
2217outputs=
builtins.filteroutput: output ≢ "devdoc" old.outputs

The installed scanner also needs this when inspecting downstream dumpers; a build-only PATH entry would leave those scans broken.

2220postPatch=
old.postPatch or ""
+
substituteInPlace giscanner/shlibs.py \
--replace-fail "['ldd', binary.args[0]]" "['${pkgs.glibc.bin}/bin/ldd', binary.args[0]]"

GLib's bootstrap build has no scanner. Install the GLib metadata generated here, which GI 1.80 otherwise keeps only for its tests. Also retain our patched test sources instead of Nixpkgs' native ones.

2227postInstall=
mkdir -p "$dev/share/gir-1.0" "$out/lib/girepository-1.0"
for namespace in GLib GObject GModule Gio; do
cp "gir/$namespace-2.0.gir" "$dev/share/gir-1.0/"
cp "gir/$namespace-2.0.typelib" "$out/lib/girepository-1.0/"
done
2242weston

The test runner collected its tests from a linker section; register them from constructors instead (upstream Fil-C's 12.0.5 patch).

patch./ports/patch/weston-15.0.1.patch

Nixpkgs' Neat VNC 1.0 update; the VNC backend is off.

skipPatch"8a1c91e771312d1e0d0cd92495ef717402784dae.patch"
argpipewireSupport = false;
argrdpSupport = false;
argremotingSupport = false;
argvaapiSupport = false;
argvncSupport = false;
argxwaylandSupport = false;
arglcmsSupport = false;
addMesonFlag"-Dsystemd=false"
2258seatd
argsystemd = final.systemdLibs;
2262alsa-lib

ALSA's .symver module assembly is not part of the Fil-C ABI.

configure"--without-versioned"
patch./patches/alsa-link-warning.patch

snd_seq_ev_ext and snd_seq_ev_quote are packed, which puts their pointers at misaligned offsets. Fil-C cannot keep a capability there (a constant initializer used to crash the compiler, and the compiler workaround was unsound), so drop packed under Fil-C. That grows snd_seq_event_t from 28 to 32 bytes, so the ALSA sequencer (MIDI via /dev/snd/seq) no longer matches the kernel; PCM audio is unaffected.

patch./patches/alsa-seq-unpacked-pointers.patch
2275spandsp

Nixpkgs passes CC=${targetPrefix}cc, which is just "cc" for Fil-C, and its depsBuildBuild puts the build GCC's cc first on PATH, so the library came out native (and PipeWire's mSBC codec failed to link).

removeMakeFlag"CC=cc"
addMakeFlag"CC=${prev.stdenv.cc}/bin/cc"
2283ffado
use
λold

Fil-C uses glibc, although nixpkgs' isGnu is false for gnufilc0. The unnecessary standalone argp overrides glibc's implementation and traps in hol_entry_short_iterate when printing --help.

2288buildInputs=
builtins.filterdep: dep.pname or "" ≢ "argp-standalone" old.buildInputs
2291env=
old.env or { } // NIX_LDFLAGS = pkgs.lib.replaceStrings"-largp" "" old.env.NIX_LDFLAGS or "";
2296postPatch=
old.postPatch or ""
+
# Fil-C programs can run on the build platform, so nixpkgs skips
# its cross substitutions, but pkg-config is still target-prefixed.
# Keep the working C/C++ probes and select the target's wrapper.
substituteInPlace SConstruct admin/pkgconfig.py \
--replace-fail 'pkg-config' "$PKG_CONFIG"
# SCons 4.9 added extra_libs before call; the old positional calls
# now try to link libraries named after each character of lrint().
substituteInPlace SConstruct \
--replace-fail '"c", "lrint(3.2);"' '"c", call="lrint(3.2);"' \
--replace-fail '"c", "lrintf(3.2);"' '"c", call="lrintf(3.2);"'
# This is a build tool, not a target library. Use its native binary
# without putting native D-Bus libraries on the Fil-C link path.
substituteInPlace SConstruct admin/dbus.py \
--replace-fail 'dbusxx-xml2cpp' \
'${pkgs.buildPackages.dbus_cplusplus}/bin/dbusxx-xml2cpp'
# Clang rejects these as C++11 user-defined literal suffixes.
substituteInPlace src/libstreaming/digidesign/DigidesignTransmitStreamProcessor.cpp \
--replace-fail '"PRIu64"' '" PRIu64 "'
# glibc's explicit-scheduling pthread_create path has an unsupported
# inline syscall. Only the debug logger uses ordinary scheduling;
# leave the audio threads' real-time behavior unchanged.
substituteInPlace config_debug.h.in \
--replace-fail 'DEBUG_MESSAGE_BUFFER_REALTIME 1' \
'DEBUG_MESSAGE_BUFFER_REALTIME 0'
2322doCheck=
true
2323checkPhase=
runHook preCheck
# SCons creates the SONAME symlink only during installation.
ln -s libffado.so src/libffado.so.2
export LD_LIBRARY_PATH="$PWD/src:''${LD_LIBRARY_PATH-}"
grep -Fx '#define HAVE_LRINT 1' config.h
grep -Fx '#define HAVE_LRINTF 1' config.h
# Hardware-free checks. The utility and buffer tests always exit
# zero even on assertion failures, so inspect their results too.
src/test-unittests-util > util.log 2>&1
cat util.log
grep -Fx 'passed: 5' util.log
grep -Fx 'failed: 0' util.log
tests/test-devicestringparser
tests/test-timestampedbuffer -v 0
tests/test-timestampedbuffer -v 0 -s 999 -c 2000
tests/test-bufferops > bufferops.log 2>&1
cat bufferops.log
test "$(grep -c 'Checking results' bufferops.log)" = 3
if grep -F 'bad result' bufferops.log; then exit 1; fi
# Device discovery, streaming and cycle-time ioctls require a
# FireWire controller/interface; build their tests, don't run them.
runHook postCheck
2347postInstallCheck=
old.postInstallCheck or ""
+
# Exercise installed tools and their argument parser, not hardware.
"$bin/bin/ffado-test" --help
"$bin/bin/ffado-dbus-server" --help
2355pipewire

1.6.6 test-loop/cancel_thread_while_dispatching aborts in pthread_cancel: "libgcc_s.so.6661 must be installed for pthread_cancel to work". The current Fil-C runtime does not support this cancellation path.

broken"PipeWire test-loop cancellation requires unsupported Fil-C pthread_cancel (libgcc_s.so.6661)"

Linker-section registration, pointer capabilities and test runtime fixes; see docs/shared-library-unblocks.md.

patch./patches/pipewire-log-topics.patch
patch./patches/pipewire-test-suites.patch
patch./patches/pipewire-pulse-modules.patch
patch./patches/pipewire-cpu-probe.patch
patch./patches/pipewire-pointer-arithmetic.patch
patch./patches/pipewire-pointer-properties.patch
patch./patches/pipewire-test-runtime.patch
use
λold

Valgrind's client requests are inline assembly on pointers, which Fil-C rejects at run time; every pwtest suite died on them.

2372env=
old.env or { } // NIX_CFLAGS_COMPILE = "-DNVALGRIND";

The Fil-C cc-wrapper shares the build GCC's role infix (x86_64_unknown_linux_gnu), so with a build compiler in depsBuildBuild it also reads the *_FOR_BUILD flags. The native GLib (for gdbus-codegen) then landed in RUNPATH ahead of the Fil-C GLib, and the modules using GLib failed to dlopen. Only the build GCC's compiler checks use these flags here.

2381preConfigure=
old.preConfigure or ""
+
unset NIX_LDFLAGS_FOR_BUILD NIX_CFLAGS_COMPILE_FOR_BUILD
2384preCheck=
old.preCheck or ""
+
export FUGC_THREADS="$NIX_BUILD_CORES"
# Two independently loaded modules share the pointer-string table
# (pipewire-pointer-properties.patch) under concurrent use.
for module in a b; do
$CC -shared -fPIC -I../spa/include \
${./tests/pipewire-pointer-module.c} -Lspa -lspa-filc-pointers \
-Wl,-rpath,"$PWD/spa" -o "pointer-$module.so"
done
$CC -O2 ${./tests/pipewire-pointer-properties.c} -ldl -pthread \
-o pointer-check
timeout 30 ./pointer-check
mesonCheckFlagsArray+=(--num-processes "$NIX_BUILD_CORES")

The GStreamer elements register GTypes through gsize once-inits.

removeMesonFlag"-Dgstreamer"
addMesonFlag"-Dgstreamer=disabled"
addMesonFlag"-Dgstreamer-device-provider=disabled"

PipeWire links libsystemd; it does not need the service manager's programs.

argsystemd = final.systemdLibs;

ROC's build takes ragel (and so colm and a target GCC) from the host package set.

argrocSupport = false;

ModemManager's libmbim, libqmi and libqrtr generate GType code that assumes integer GTypes; PipeWire only uses it for HFP modem calls.

argmodemmanager = final.modemmanager.overrideAttrsold: meta = old.meta // badPlatforms = prev.stdenv.hostPlatform.system;;;

Nixpkgs enables the native HFP backend's ModemManager support whenever BlueZ is available.

removeMesonFlag"-Dbluez5-backend-native-mm=enabled"
addMesonFlag"-Dbluez5-backend-native-mm=disabled"
2423libglvnd
configure"--disable-asm"
2427libinput
pin"1.29.1" "sha256-4BVHu9370s5hqugS/Lj/JEXwXXmmVRSMfjkvqpI9aq8="
patch./ports/patch/libinput-1.29.1.patch

1.29 predates the Lua plugin option Nixpkgs 26.05 sets.

argluaSupport = false;
removeMesonFlag"-Dlua-plugins=disabled"
arglibwacom = pkgs.hello;
addMesonFlag"-Dlibwacom=false"
addMesonFlag"-Ddebug-gui=false"
2439libxkbcommon=
2440libxkbcommon

The upstream 1.11 X11 test hunk does not apply to 1.13, and X11 is disabled here. Keep only the still-needed version-script adaptation.

patch./patches/libxkbcommon-version-scripts.patch
skipTests"eh"
addMesonFlag"-Denable-x11=false"
2459openexr
patch./patches/openexr-chunk-table-pointer.patch
patch./patches/openexr-frame-buffer-pointers.patch

Inline assembly with memory operands (the DWA AVX path, fnstcw and fldcw for FPU exceptions) is beyond Fil-C, as are the AVX2 gathers in the vendored OpenJPH.

addCMakeFlag"-DOPENEXR_IMF_HAVE_GCC_INLINE_ASM_AVX=OFF"
addCMakeFlag"-DIEX_HAVE_CONTROL_REGISTER_SUPPORT=OFF"
addCMakeFlag"-DIEX_HAVE_SIGCONTEXT_CONTROL_REGISTER_SUPPORT=OFF"
addCMakeFlag"-DOJPH_DISABLE_SIMD=ON"
use
λold

The exhaustive threaded tile matrix exceeds CTest's 1500-second default with Fil-C under load. Keep the whole test, with a larger bound.

2472postPatch=
old.postPatch or ""
+
echo 'set_tests_properties(OpenEXR.testMultiTiledPartThreading PROPERTIES TIMEOUT 7200)' >> src/test/OpenEXRTest/CMakeLists.txt

Compares OpenEXRCore's CPU detection with the C++ library's, which without the inline assembly no longer reports AVX.

2477disabledTests=
old.disabledTests or [ ] ++ "OpenEXRCore.testCPUIdent"
2494rdkafka
use
λold

The CRC32C path detects SSE 4.2 with inline cpuid, which Fil-C cannot run; every client died in rd_kafka_new(). Use the software CRC32C.

2499postPatch=
old.postPatch or ""
+
substituteInPlace packaging/cmake/config.h.in --replace-fail \
'#cmakedefine01 WITH_CRC32C_HW' '#define WITH_CRC32C_HW 0'
2507uwimap=
2507uwimap

Fil-C's libc has no vfork; c-client only uses it to spawn rsh/ssh.

addCFlag"-Dvfork=fork"
2513libraw
use
λold

The pkg-config files name GCC's C++ runtime; Fil-C's is libc++. Magick++ failed to link against -lstdc++.

2517postPatch=
old.postPatch or ""
+
substituteInPlace libraw.pc.in libraw_r.pc.in --replace-fail -lstdc++ -lc++
2523imagemagick
arg

librsvg is Rust, which has no Fil-C target.

2526librsvgSupport=
false

libheif's x265 encoder builds its 10/12-bit variants with GCC.

2528libheifSupport=
false

libjxl's Highway picks SIMD targets with xgetbv spelled as raw opcode bytes, which Fil-C refuses; past that it would dispatch to AVX2 and AVX-512 intrinsics, which Fil-C does not all lower (the AVX2 gathers in OpenEXR's OpenJPH did not).

2533libjxlSupport=
false
2537libevdev
pin"1.11.0" "sha256-Y/TqFImFihCQgOC0C9Q+TgkDoeEuqIjVgduMSVdHwtA="
patch./ports/patch/libevdev-1.11.0.patch
2542valgrind
broken"not yet ported"

objc_msgSend and the block trampolines are assembly, and Clang's GNUstep ABI registers classes and selectors through __start_/__stop_ section symbols, which Fil-C does not provide (docs/filc-findings.md).

2546gnustep-libobjc
broken"Objective-C runtime not ported"
2548cups
arggnutls = final.openssl;

Its pname is ghostscript-with-X, so name the attribute explicitly.

2559dbus
argsystemdMinimal = final.systemdLibs;
arglibapparmor = final.hello;

dbus 1.16 builds with Meson.

removeMesonFlag"-Dapparmor"
addMesonFlag"-Dapparmor=disabled"

Development Tools & Libraries

let
2571fmtPort=
λfmt argStorePatch
2573fmt for fmt

Works around Fil-C's clang passing small records that contain unions as integers, which dropped the pointers in one-argument make_format_args stores (wide and custom-type formatting).

patchargStorePatch
use

float_test.isnan: the Fil-C runtime leaves FE_INEXACT set at start. util_test.format_system_error: allocating SIZE_MAX / 2 bytes is a Fil-C safety panic, not std::bad_alloc. See docs/filc-findings.md.

2582preCheck=
export GTEST_FILTER=-float_test.isnan:util_test.format_system_error
uses for patch use
in
2594asio

Boost.Coroutine (v1) needs fcontext and is not in the Boost port; only the spawn examples use it.

removeConfigureFlag"--enable-boost-coroutine"

The same io_context executor fix as Boost.Asio's.

patch./patches/asio-io-context-executor-pointer.patch
use
λold

FilPizlonator's frame-slot coloring needs well over an hour to compile this test at -O2 (10 s at -O0); see "Frame-slot coloring is cubic" in docs/filc-findings.md. Drop it until the fork has the linear coloring.

2605postPatch=
old.postPatch or ""
+
sed -i '/^\tunit\/execution\/any_executor \\$/d' src/tests/Makefile.am
! grep -q '^.unit/execution/any_executor ' src/tests/Makefile.am
2612clucene_core

libc++ drops std::binary_function in C++17; the patch Nixpkgs uses for Darwin removes it from the (installed) headers.

patch
pkgs.fetchpatch
2617url=
"https://869170.bugs.gentoo.org/attachment.cgi?id=858825"
2618hash=
"sha256-TbAfBKdXh+1HepZc8J6OhK1XGwhwBCMvO8QBDsad998="

Nixpkgs skips the suite: cl_test is not built by default, and building it needs C++14, a missing <unistd.h>, and then fails on the contribs tests' include paths. Index and search through the installed headers.

use
2625doInstallCheck=
true
2626installCheckPhase=
runHook preInstallCheck
$CXX ${./tests/clucene-core.cpp} -I$out/include -I$out/lib \
-L$out/lib -Wl,-rpath,$out/lib -lclucene-core -lclucene-shared \
-o clucene-check
./clucene-check
runHook postInstallCheck
2637doxygen
use
λold

Release builds turn on IPO, which has CMake archive with llvm-ar (missing, and Fil-C has no LTO anyway), as Nixpkgs does on Darwin.

2641postPatch=
old.postPatch
+
substituteInPlace CMakeLists.txt \
--replace-fail 'set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)' \
'set(CMAKE_INTERPROCEDURAL_OPTIMIZATION FALSE)'

The suite runs doxygen on each test input and compares the XML output with xmllint. 012_cite needs bibtex to resolve citations; that is not Fil-C.

2649doCheck=
true
2650nativeCheckInputs=
old.nativeCheckInputs or [ ] ++ pkgs.libxml2.bin
2651checkPhase=
runHook preCheck
ctest -E '^012_cite$' --output-on-failure -j$NIX_BUILD_CORES
runHook postCheck
2659ntk

FLTK-era sources use register, an error in Clang's default C++17.

addCFlag"-Wno-register"

Page headers and stack marks are tagged pointers stored as size_t.

patch./patches/z3-page-headers-pointers.patch
use
λold

Nixpkgs' import check runs the build platform's Python, which finds neither the Fil-C Python's site-packages nor a loadable libz3. Solve something through the bindings with the Fil-C Python instead.

2671pythonImportsCheck=
[ ]
2672postInstallCheck=
old.postInstallCheck or ""
+
PYTHONPATH=$python/${final.python3.sitePackages} ${final.python3}/bin/python3 -c '
import z3
x = z3.Int("x")
s = z3.Solver()
s.add(x > 2, x < 4)
assert s.check() == z3.sat and s.model()[x].as_long() == 3
print("z3 python ok")'
2684capstone

csh is a size_t holding the handle's address, which drops the capability; every call after cs_open trapped.

patch./patches/capstone-handle-ptrtable.patch
2690glog
patch./patches/glog-filc-refused-signals.patch
use

Excluded besides Nixpkgs' "logging":

  • striplog*: they catch LOG(FATAL)'s abort() with a SIGABRT handler, but Fil-C's abort() stops the process without raising SIGABRT (docs/filc-findings.md).
  • stacktrace, symbolize: they take code addresses of labels and functions and expect native frames; Fil-C has neither.
2699checkPhase=
runHook preCheck
ctest -E "^(logging|striplog.*|stacktrace|symbolize)$" --output-on-failure
runHook postCheck
2707unittest-cpp
use
λold

CrashingTestsAreReportedAsFailures calls a null function pointer and expects the SIGSEGV handler to turn that into a failure. Under Fil-C the call is a safety panic, and SIGSEGV handlers are refused.

2712postPatch=
old.postPatch or ""
+
substituteInPlace tests/TestTest.cpp --replace-fail \
'#if defined(NDEBUG)' '#if defined(NDEBUG) && !defined(__FILC__)'
2719doctest
addCFlag"-Wno-reserved-macro-identifier"
addCFlag"-Wl,-lm"

The self-tests install signal handlers on an alternate stack (sigaltstack) and break into the debugger with llvm.debugtrap; Fil-C supports neither. The library is header-only.

skipCheck"sigaltstack and debugtrap"
2728catch2

As for Catch2 v3 below, but v2 is a single header: turn its fatal-signal handler (sigaltstack) off by default under Fil-C.

use
λold
2732postPatch=
old.postPatch or ""
+
substituteInPlace single_include/catch2/catch.hpp --replace-fail \
'#define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED' \
'#define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED
#if defined(__FILC__) && !defined(CATCH_CONFIG_NO_POSIX_SIGNALS)
#define CATCH_CONFIG_NO_POSIX_SIGNALS
#endif'

Named explicitly: the pname is "catch2", which is Catch2 v2's attribute.

2745catch2_3=
2745catch2_3

Catch2's fatal-signal handler runs on an alternate stack (sigaltstack), which Fil-C does not support; every test run aborted in FatalConditionHandler::engage_platform. Fil-C also refuses handlers for SIGSEGV and the like, so the handler could not work anyway. The option is written to catch_user_config.hpp, so test suites that link this Catch2 skip the handler too.

addCMakeFlag"-DCATCH_CONFIG_NO_POSIX_SIGNALS=ON"

Their suites use doctest, whose signal handling needs sigaltstack.

2757nlohmann_json
addCMakeFlag"-DCMAKE_CXX_FLAGS=-DDOCTEST_CONFIG_NO_POSIX_SIGNALS"
2760toml11
addCMakeFlag"-DCMAKE_CXX_FLAGS=-DDOCTEST_CONFIG_NO_POSIX_SIGNALS"
2764gettext
useold: env = old.env // gettextNeedsLdflags = false;;
2772elfutils
configure"--disable-symbol-versioning"
configure"--disable-debuginfod"
addCFlag"-Wno-error=unused-parameter"
argenableDebuginfod = false;

0.194's configure requires pkg-config; Nixpkgs adds it only for debuginfod.

toolpkgs.pkg-config
skipTests"some tests fail"
2782libcbor
patch./patches/libcbor-test-math.patch

Fil-C emits instrumented objects; the final native linker cannot consume the LLVM bitcode produced by libcbor's automatic IPO selection.

addCMakeFlag"-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=OFF"
addCMakeFlag"-DWITH_EXAMPLES=OFF"
addCMakeFlag"-DSANITIZE=OFF"
usedoCheck = true;
2792libapparmor

Configure runs the target Python config tool when linking its extension. Since 4.1 it also imports setuptools with that interpreter.

configure"PYTHON=${final.python3.withPackagesps: ps.setuptools}/bin/python3"
configure"PYTHON_CONFIG=${final.python3}/bin/python3-config"
2802libcap_ng=
2802libcap_ng
use
λold

capng_change_id applies ambient capabilities, but the Fil-C runtime rejects prctl(PR_CAP_AMBIENT) with ENOSYS, so it returns -9.

2806postPatch=
old.postPatch or ""
+
substituteInPlace src/test/Makefile.am \
--replace-fail "thread_test change_id_test" "thread_test"
2812pam=
2812linux-pam
skipCheck"test setup issues"
2815cmocka
skipTests"some tests fail"
addCMakeFlag"-DWITH_EXAMPLES=OFF"
2820libbsd
serialize

The Fil-C compiler wrapper puts filc-glibc's headers first with -isystem, so libbsd's -isystem include/bsd overlay came after them and its #include_next wrappers never applied (setproctitle_init was undeclared). -I directories are searched before every -isystem one.

use
2827postPatch=
for f in src/Makefile.am src/Makefile.in test/Makefile.am test/Makefile.in; do
substituteInPlace $f --replace-fail '-isystem $(top_srcdir)' '-I$(top_srcdir)'
done
substituteInPlace src/libbsd-overlay.pc.in \
--replace-fail '-isystem ''${includedir}' '-I''${includedir}'
# Fil-C's syscall() stops the program on close_range (436); glibc's
# close_range() goes through the runtime.
substituteInPlace src/closefrom.c \
--replace-fail 'syscall(SYS_close_range, fd, max_fd, flags)' \
'close_range(fd, max_fd, flags)'
# Expected failures, each a Fil-C limitation rather than a libbsd bug:
# explicit_bzero's test needs sigaltstack, which the runtime does not
# support; nlist looks up C names, but Fil-C symbols are pizlonated_*;
# proctitle links libbsd-ctor, whose hand-placed .init_array entry
# Fil-C never calls, so setproctitle_init must be called explicitly.
for f in test/Makefile.am test/Makefile.in; do
echo 'XFAIL_TESTS = explicit_bzero nlist proctitle' >> $f
done
2852rhash
use
2854preConfigure=
sed -i 's/,-soname/ -Wl,-soname/' configure
addCFlag"-DRHASH_NO_ASM=1"
2861fasttext
addCFlag"-Wl,-lm"
2865scrypt
skipTests"some tests fail"
2869libmicrohttpd for pkgs.callPackage./packages/libmicrohttpd.nix { }

Languages

nixpkgs only packages Perl 5.42; the Fil-C port targets 5.40.0.

2875perl5=
2876perl5
arg
2878version=
"5.40.0"
2879sha256=
"sha256-x0A0jzVzljJ6l5XT6DI7r9D+ilx4NfwcuroMyN/nFh8="

Nixpkgs builds perl.pkgs with its own perl5 attribute; use the port.

2881self=
final.perl5

buildPerlPackage puts perl in nativeBuildInputs, which Nixpkgs 26.05 resolves to the package set's build-host splice. That was the build platform's perl, which configured XS modules with its own Config and then loaded the Fil-C objects in their tests. Fil-C programs run on the build machine, so splice the port there. Module fixes from ports/perl-modules.nix apply to the scope, so dependents and withPackages see them.

2889passthruFun=
λargs
let
2892upstream=
import"${prev.path}/pkgs/development/interpreters/perl" callPackage = f: a: a.passthruFun or final.callPackagef a;.perl5args // perlOnBuildForHost = args.self;
used by pkgs

Recover Nixpkgs' passthruFun, which calls callPackage itself.

2898pkgs=
upstream.pkgs.overrideScopeimport./ports/perl-modules.nix
uses upstream
in
//
2902inherit
pkgs
2903withPackages=
f: upstream.buildEnv.overrideextraLibs = fpkgs;
patch./ports/patch/perl-5.40.0.patch
patch./patches/perl-5.40-only-c-locale.patch
patch./patches/perl-5.40-encode-shared-ptrtable.patch
patch./patches/perl-5.40-b-overlay-key.patch
patch./patches/perl-5.40-digest-sha-ptrtable.patch
patch./patches/perl-5.40-custom-op-ptrtable.patch
patch./patches/perl-5.40-mro-ptrtable.patch
use
λold

postPatch replaces the bundled Compress-Raw-Zlib with a newer release, discarding the port's typemap change.

2916postPatch=
old.postPatch
+
substituteInPlace cpan/Compress-Raw-Zlib/typemap \
--replace-fail '$var = INT2PTR($type, tmp);' \
'$var = zptrtable_decode(Perl_xsub_ptrtable, tmp);'
skipCheck"too slow"

NO overrides arg - that breaks withPackages!

2929python312=
2929python312
pin"3.12.5" "sha256-+oouEsXmILCfU+ZbzYdVDS5aHi4Ev4upkdzFUROHY5c="
patch./ports/patch/Python-3.12.5.patch
patch./patches/python-code-header-cxx.patch
patch./patches/python-filc-triplet-detection.patch
patch./patches/python-faulthandler.patch

nixpkgs' separate debug info adds -Wa,--compress-debug-sections, which Fil-C's assembler rejects.

useseparateDebugInfo = false;
argenableLTO = false;
configure"--without-pymalloc"
configure"--without-freelists"
configure"ac_cv_func_chflags=no"
configure"ac_cv_func_lchflags=no"
configure"ac_cv_func_sigaltstack=no"
configure"ac_cv_gcc_asm_for_x64=no"
configure"ac_cv_gcc_asm_for_x87=no"
configure"ac_cv_gcc_asm_for_mc68881=no"

Nixpkgs assumes x87 double rounding when cross compiling. With no x87 inline assembly to fix the precision, that disables short float repr (repr(12.3) == '12.300000000000001'). Fil-C uses SSE2 arithmetic.

removeConfigureFlag"ac_cv_x87_double_rounding=yes"
configure"ac_cv_x87_double_rounding=no"

Fil-C's libc is libc.so.6666. CDLL("libc.so.6") loaded the runtime's inner libc instead, where no Fil-C function is found (finix's limine hook died on libc.syncfs), and find_library("c") found nothing.

use
λold
2956postPatch=
old.postPatch or ""
+
"\n"
+
substituteInPlace Lib/ctypes/__init__.py --replace-fail \
' self._name = name' \
' if name == "libc.so.6": name = "libc.so.6666"
self._name = name'
substituteInPlace Lib/ctypes/util.py --replace-fail \
' # See issue #9998' \
' if name == "c": return "libc.so.6666"
# See issue #9998'
argpackageOverrides = import./ports/pythonPorts-as-overlay.nix pkgs;
2977ruby_3_3=
patch./ports/patch/ruby-3.3.10.patch

Upstream's Fil-C port uses pthread coroutines, not native assembly.

configure"--with-coroutine=pthread"

Autoconf 2.73 would record CC as "clang -std=gnu23" in rbconfig, which native gem extensions then inherit; keep the compiler default.

configure"ac_cv_prog_cc_c23=no"

Disable ractor shareability deep checking - requires rb_objspace_reachable_objects_from which isn't implemented in Fil-C. Return false = conservatively assume not shareable.

astRewrite"ractor.c" "c" "bool rb_ractor_shareable_p_continue($PARAM) { $$$BODY }" "bool rb_ractor_shareable_p_continue($PARAM) { #ifdef __FILC__ return false; #else $$$BODY #endif }"

Also patch rb_ractor_make_shareable to skip traversal

astRewrite"ractor.c" "c" "VALUE rb_ractor_make_shareable(VALUE $OBJ) { $$$BODY }" "VALUE rb_ractor_make_shareable(VALUE $OBJ) { #ifdef __FILC__ FL_SET_RAW($OBJ, RUBY_FL_SHAREABLE); return $OBJ; #else $$$BODY #endif }"

Terminal & System

3016libcap
pin"2.70" "sha256-I6bviq2vHj6HX2M7stEWz++JUtunvHxWmxNFjhlSsw8="
argwithGo = false;
argusePam = false;
3023binutils-unwrapped=
3023binutils-unwrapped
src"2.43.1" "sha256-vsqsXSleA3WHtjpC+tV/49nXuD9HjrJLZ/nuxdDxhy8=" version: "mirror://gnu/binutils/binutils-${version}.tar.bz2"
patch./ports/patch/binutils-2.43.1.patch
3031kbd

ports/patch/kbd-2.6.4.patch rebased onto Nixpkgs' 2.9.

patch./patches/kbd-2.9-filc.patch

dlopen()s zlib, bzip2, xz and zstd for compressed keymaps.

dlopenByPath

Only there to act on the .note.dlopen notes. Under Fil-C it found no notes and replaced the RUNPATH with kbd's own lib directory, dropping the Fil-C runtime's (it skips libraries beside the interpreter, which ld-fil1 does not search by default), so loadkeys could not start.

usedontAutoPatchelf = true;

Nixpkgs' own systemd (260); systemdMinimal and systemdLibs derive from this port through .override, so all three get the same fixes. patches/systemd-260-filc.patch rebases upstream Fil-C's 256.4 patch (ports/patch/systemd-256.4.patch) and adds what 260 needs; its header lists each change.

3049systemd=
3049systemd
patch./patches/systemd-260-filc.patch
argwithKexectools = false;
argwithLibseccomp = false;

EFI/BPF/kexec emit kernel or firmware code, outside Fil-C userspace.

arg
3055withLibBPF=
false
3056withEfi=
false
3057withBootloader=
false

257+ dlopen()s zstd, lz4, xz, kmod, cryptsetup, PAM, ...; without the notes the initrd gets no libkmod and loads no kernel modules.

dlopenByPath
use

the automatic patchelf hook was segfaulting while trying to patch some debug info files?!

3065separateDebugInfo=
false

Nixpkgs 26.05 bans bash from the closure; libapparmor's Python bindings bring the Fil-C interpreter (and its bash) along.

3068disallowedRequisites=
[ ]

this seems to not be a real problem

useautoPatchelfIgnoreMissingDeps = "*";
broken"not yet ported"

The tests run texi2any with the build platform's Perl, which cannot load the Fil-C build's XS modules (and its headers lack crypt.h).

3083texinfoInteractive=
3083texinfoInteractive
skipCheck"tests run the build platform's Perl against Fil-C XS modules"
3088ttyd
skipCheck"network service tests"
3092acl

The *xattrat calls and openat2 went through raw syscall(), which stops a Fil-C program; setfacl died in NixOS's resolvconf service.

patch./patches/acl-2.4-filc.patch
3102e2fsprogs
argwithFuse = false;
skipTests"requires special setup"
3107sqlite
arginteractive = true;
skipCheck"too slow"
removeCFlag"-DSQLITE_ENABLE_STMT_SCANSTATUS"

The suite dumps deeply nested values recursively; Fil-C frames are larger than native ones and overflow the default 8 MiB stack.

use
λold
3117preInstallCheck=
old.preInstallCheck or ""
+
ulimit -s 65536

callPackage splices python3Packages by name, and the build platform's is 3.13, so setuptools came from 3.13 while the build ran the ported 3.12. The 3.12 set splices against its own build-platform 3.12.

3126nixos-rebuild-ng
argpython3Packages = final.python312.pkgs;

A test uses Generator's one-argument form, which needs Python 3.13.

use
λold
3130postPatch=
old.postPatch or ""
+
"\n"
+
substituteInPlace tests/test_tmpdir.py \
--replace-fail 'typing.Generator[None]' 'typing.Generator[None, None, None]'

Fil-C's libc has no vfork. At shutdown PID 1 vforks a child to reboot and stays suspended until the child is gone; fork and wait for it instead.

3142finit
use
λold
3144postPatch=
old.postPatch or ""
+
"\n"
+
substituteInPlace src/sig.c --replace-fail 'if (vfork()) {' \
'if (({ pid_t p = fork(); if (p > 0) waitpid(p, NULL, 0); p; })) {'

Fil-C's syscall() stops the program on clone3 instead of returning ENOSYS, so PID 1 died starting its first service. Start with finit's own fork() fallback, which moves the child into its cgroup after the fork.

+
substituteInPlace src/clone3.c --replace-fail \
'static int use_clone3 = 1;' 'static int use_clone3 = 0;'

Found by Fil-C: keventd NUL-terminates what recv returned, so a uevent that fills its 1024-byte buffer (common during coldplug) wrote one byte past it. Leave room for the terminator.

+
substituteInPlace src/keventd.c --replace-fail \
'recv(pfd.fd, buf, sizeof(buf), MSG_DONTWAIT)' \
'recv(pfd.fd, buf, sizeof(buf) - 1, MSG_DONTWAIT)'

The upstream port (ports/patch/dhcpcd-10.0.8.patch) predates the move of compat/rbtree.h to vendor/; without it dhcpcd stopped at startup.

3176strace
usepostPatch = "sed -i 's/ vfork/ fork/g' */strace.c";

libunwind's register-level unwinder is hand-written assembly without SaRCAsm annotations. strace uses elfutils for -k instead.

arglibunwind = null;

Web & Network Services

3189redis

Aligned encoded reply buffers; no madvise on the heap after fork.

patch./patches/redis-filc.patch
use
λold
3193makeFlags=
old.makeFlags
++

Redis's default -O3 turns on LTO, which Fil-C does not have.

"OPTIMIZATION=-O2"

The test modules' Makefile hard-codes gcc.

"CC=cc"
"LD=cc"

The tests call pgrep; Nixpkgs' ps here is procps' ps alone.

3201nativeCheckInputs=
old.nativeCheckInputs ++ pkgs.procps
3202checkPhase=
let
3204skips=

The jemalloc shim ignores malloc_conf, and has no per-size accounting or active defragmentation, so fragmentation always reads 1.00.

"--tags -defrag"
''--skiptest "je_malloc_conf compile-time tuning is active"''
''--skiptest "Reduce defrag CPU usage when module data can't be defragged"''

Fil-C gives the program copies of argv, so rewriting them does not change /proc/<pid>/cmdline.

''--skiptest "Process title set as expected"''

Crash reports need SIGSEGV handlers, which Fil-C refuses.

"--skipunit unit/moduleapi/crash"

The key metadata API passes pointers as uint64_t, which drops their capability; the test modules store strings that way.

"--skipunit unit/moduleapi/keymeta"
"--skipunit unit/moduleapi/ksn_notify_side_effect"

They load payloads that request exabyte allocations and expect zmalloc to fail; Fil-C stops the program instead.

''--skiptest "corrupt payload: fuzzer findings - OOM in dictExpand"''
''--skiptest "corrupt payload: fuzzer findings - huge string"''

Crash reports with stack traces: SIGSEGV handlers again, and the port builds without backtrace support.

"--skipunit integration/logging"

redis-cli's cluster tests start nodes and give them a fixed time to agree on the cluster. Under load the Fil-C nodes missed it in two of them (add-node, and functions on add-node) on swa.

"--skipunit unit/cluster/cli"
3232last=
''--skiptest "Check MEMORY USAGE for embedded key strings with jemalloc"''
in
assert pkgs.lib.hasInfixlast old.checkPhase
builtins.replaceStrings"./runtest \\\n" last
"set -o pipefail\n./runtest \\\n"
pkgs.lib.concatMapStringss: s + " \\\n " skips + last + " 2>&1 | sed -u -e 's/\\r/\\n/g' -e 's/\\x1b\\[[0-9;]*m//g'"

The test runner redraws lines with carriage returns and colours them, which leaves the Nix log blank.

old.checkPhase
3251postPatch=
old.postPatch or ""
+
# Nixpkgs' system-jemalloc patch still builds deps/jemalloc, whose
# configure fails; Redis links the jemalloc shim instead.
sed -i 's/^\tDEPENDENCY_TARGETS+= jemalloc$//' src/Makefile
! grep -q 'DEPENDENCY_TARGETS+= jemalloc' src/Makefile
# runtest invokes make itself, outside stdenv's makeFlags. Bind Fil-C
# descriptors to each module's entrypoint even when the built-in
# vectorset also exports RedisModule_OnLoad.
substituteInPlace tests/modules/Makefile --replace-fail \
'SHOBJ_LDFLAGS ?= -shared' 'SHOBJ_LDFLAGS ?= -shared -Wl,-Bsymbolic'

nginx builds, but its worker processes share pointers through shared memory zones, which Fil-C capabilities do not survive; the same rule refuses the PostgreSQL server on Fil-C systems (lib/block-rust-go.nix). Refuse it at evaluation, saying what to do instead.

let
3271refuse=
λold
3272meta=
old.meta or { }
//
3273problems=
old.meta.problems or { }
//
3274filc=
3275kind=
"broken"
3276message=
"nginx cannot be Fil-C: its processes share memory that holds pointers, and a Fil-C pointer's capability does not cross processes. Use lighttpd, or keep nginx native with filc.native = native: { inherit (native) nginxStable; };"
uses use
in
3283nginxStable=
3283nginxStable
refuse
3284nginxMainline=
3284nginxMainline
refuse
3289apacheHttpd=
3289apacheHttpd

Nixpkgs links libgcc_s for pthread_cancel, which the Fil-C libc has.

useold: env = old.env or { } // NIX_LDFLAGS = "";;

Its pointer-size check runs a program, assumed to fail when cross-compiling.

configure"ap_cv_void_ptr_lt_long=no"

A pointer one process stores in shared memory has no capability in another. mod_auth_digest's client table links entries by rmm offset instead; mod_ldap's shared cache, which is pointers and callbacks throughout, gives way to its per-process cache.

patch./patches/httpd-auth-digest-shm-offsets.patch
patch./patches/httpd-ldap-per-process-cache.patch
3307postgresql_18=
3307postgresql_18

x86 inline asm (spinlock, atomics, popcnt) becomes __sync builtins; Datum, which carries pointers, becomes a pointer type; and sorts swap elements whole, so their pointers keep their capabilities.

patch./patches/postgresql-filc.patch

Its libpq, as in the libpq port: Fil-C's filc_allocate_without_exiting is not exit.

use
λold
3315postPatch=
old.postPatch or ""
+
substituteInPlace src/interfaces/libpq/Makefile \
--replace-fail '-e __tsan_func_exit' '-e __tsan_func_exit -e _without_exiting'

No LTO linker plugin for Fil-C; see libpq. Setting CFLAGS drops configure's -O2, and at -O0 Fil-C takes over 15 silent minutes on the grammar (gram.c), which builders stop. Datum is a pointer here, so int-to-Datum conversions are implicit.

useold: env = old.env // CFLAGS = "-O2 -Wno-int-conversion -fdata-sections -ffunction-sections -Wl,--gc-sections";;

Configure assumes a cross build's linker lacks it, and the server's modules need its symbols.

configure"LDFLAGS_EX_BE=-Wl,--export-dynamic"

Glibc's sync_file_range makes its system call with inline asm.

configure"ac_cv_func_sync_file_range=no"

Its tests run a server, whose backends share pointers.

skipTests"the server's processes share pointers"
arg
3337jitSupport=
false
3338perlSupport=
false
3339pythonSupport=
false
3340tclSupport=
false
3345lighttpd
patch./patches/lighttpd-filc.patch
patch./patches/lighttpd-ls-hpack-pointers.patch

The Fil-C glibc's preadv2 makes the system call with inline assembly, which stops the program; lighttpd reads static files for HTTP/2 with it. Without it, lighttpd uses pread.

configure"ac_cv_func_preadv2=no"
argenableMagnet = true;
argenableWebDAV = true;
argenablePam = true;
arglua5_1 = pkgs.lua5;
skipCheck"test suite issues"
3359tor
arg
3361systemd=
final.systemdLibs
3362libseccomp=
null

libcap = null;

configure"ac_cv_header_execinfo_h=no"
configure"ac_cv_func_backtrace=no"
configure"ac_cv_func_backtrace_symbols=no"
configure"ac_cv_func_backtrace_symbols_fd=no"
configure"ac_cv_search_backtrace=no"
addCFlag"-DED25519_NO_INLINE_ASM=1"

dimap_search picked the onion key by masking uintptr_t copies of two pointers, which drops the capability: every ntor v3 handshake trapped. The patch selects from a pointer pair by index instead, still without a branch on the keys; recheck its assembly when the toolchain changes (docs/filc-findings.md).

patch./patches/tor-dimap-search-pointer.patch

20 pass, 2 skip, 3 fail: test-memwipe reads freed memory on purpose, and the hashx and equix tests want HashX's JIT, which Fil-C can't run.

skipTests"memwipe reads freed memory; hashx and equix want a JIT"
3382torsocks
toolpkgs.glibc.bin
arglibcap = null;
use
3386postPatch=
sed -i \
-e 's,\(local app_path\)=`which $1`,\1=`type -P $1`,' \
src/bin/torsocks.in
skipTests"2 failing tests"

Alternative Implementations & VMs

3398tinycc=
3398tinycc
patch./patches/tinycc-alignment.patch
use
λold
3401preConfigure=
echo ${old.version} > VERSION
3404configureFlags=
"--cc=$CC" "--ar=$AR" "--crtprefix=${pkgs.glibc}/lib" "--sysincludepaths={B}/include:${pkgs.glibc.dev}/include" "--libpaths=$lib/lib/tcc:$lib/lib:${pkgs.glibc}/lib" "--elfinterp=${pkgs.glibc}/lib/ld-linux-x86-64.so.2"
toolpkgs.glibc.bin
skipTests"-run feature incompatible with Fil-C"
3418quickjs

Nixpkgs' 2026-06-04 release rather than upstream Fil-C's 2024-02-14 snapshot: the old one crashed on greedy regexps under Fil-C and is far too slow for yt-dlp's challenge solver (it asks for >= 2025-04-26).

patch./patches/quickjs-2026-filc.patch

Fil-C frames are larger; the native 1 MiB JS stack limit overflows on yt-dlp's solver, which runs qjs without --stack-size.

addCFlag"-DJS_DEFAULT_STACK_SIZE=4194304"
use
λold
3427doCheck=
true
3428checkTarget=
"test"
3429postCheck=
old.postCheck or ""
+
$CC -UNDEBUG -I. ${./tests/quickjs-sab.c} libquickjs.a \
-lm -lpthread -ldl -o quickjs-sab-test
./quickjs-sab-test
cp ${./tests/quickjs-worker-sab.js} tests/quickjs-worker-sab.js
./qjs tests/quickjs-worker-sab.js

The install check reuses $out for a temporary file.

3437postInstallCheck=
old.postInstallCheck or ""
+
${builtins.placeholder"out"}/bin/qjs ${./tests/quickjs-regexp.js}
3443trealla
arglineEditingLibrary = "readline";
use
3446version=
"unstable-2026-11-10"

GitHub's archive bytes for this commit changed; hash the contents.

3448src=
pkgs.fetchFromGitHub
3449owner=
"trealla-prolog"
3450repo=
"trealla"
3451rev=
"98a821db66715618e358c36c7d7164213c0f6820"
3452hash=
"sha256-kU3Vgtk7Ni7nYVJ/ii++EForHclMh1WrQpyNYKgpqmQ="
use
λold
3456postPatch=
builtins.replaceStrings"Makefile" "GNUmakefile" old.postPatch
3459makeFlags=
old.makeFlags ++ "READLINE=1" "LIBDIR=$(out)/share/trealla"
3463postInstall=
old.postInstall or ""
+
mkdir -p $out/share/trealla/library
find library -name '*.pl' -exec cp --parents -t $out/share/trealla {} +
patch./patches/trealla-filc-ffi-zptrtable.patch
patch./patches/trealla-filc-tabling-cursors.patch
patch./patches/trealla-goal-expansion-share-cells.patch
patch./patches/trealla-heap-page-mark.patch
skipTests"runtime coverage lives in checks.x86_64-linux.trealla"

SWI-Prolog with the core and its packages that need no further libraries, plus PCRE, YAML and SSL. Left out: Java (JPL), ODBC/CQL, Berkeley DB, Python (janus, MQI), xpce and the Qt console, the archive package, readline and libedit, the C++ interface (cpp) and tcmalloc. The patch keeps capabilities where SWI stores pointers as integers (VM code arguments, stack offsets, foreign redo contexts, PL_put_pointer through an exact ptrtable), rebases pointers into moved blocks instead of adding the distance moved, leaves objects other threads may still read to Fil-C's collector, and measures the C stack at the frame setjmp records rather than at a local's address, which Fil-C may keep in the heap. Pointers that other threads replace (by CAS or assignment) while one reads them without a lock are declared ATOMIC_PTR(T), _Atomic(T), so every access is atomic: under Fil-C a plain pointer load reads address and capability separately, tears against a racing store and traps (nanofil/docs/m4.md, SWI-Prolog).

3491swi-prolog
arg
3493withDb=
false
3494withJava=
false
3495withOdbc=
false
3496withPython=
false
3497withGui=
false
3498withNativeCompiler=
false
patch./patches/swi-prolog-9.2.9-filc.patch
use
λold
3502buildInputs=
builtins.filterp: ¬builtins.elemp.pname or "" "gperftools" "libarchive" "readline" "libedit" old.buildInputs
3511cmakeFlags=
old.cmakeFlags
++
"-DUSE_TCMALLOC=OFF"
"-DINSTALL_DOCUMENTATION=OFF"

Fil-C has no sigaltstack; it catches stack overflow itself.

"-DHAVE_SIGALTSTACK="
"-DSWIPL_PACKAGE_LIST=chr;clib;clpqr;inclpr;http;nlp;paxos;redis;stomp;pengines;pldoc;plunit;protobufs;RDF;semweb;sgml;table;utf8proc;zlib;pcre;yaml;ssl"
3518doCheck=
true
3519checkPhase=
runHook preCheck
# Only http:proxy runs once more when it alone failed: its
# "unused" port is one it found free and released, which a test
# running beside it can take.
ctest -j$NIX_BUILD_CORES --timeout 900 --output-on-failure || {
! grep -qv ':http:proxy$' Testing/Temporary/LastTestsFailed.log &&
ctest --rerun-failed --timeout 900 --output-on-failure
}
runHook postCheck

A smoke test of the installed swipl and its libraries.

3531doInstallCheck=
true
3532installCheckPhase=
runHook preInstallCheck
cat >smoke.pl <<'EOF'
:- use_module(library(clpfd)).
:- use_module(library(sgml)).
:- use_module(library(crypto)).
:- use_module(library(pcre)).
:- initialization(main, main).
main :-
X is 2^200 mod 1000000007, X =:= 499445072,
length(L, 8), L ins 1..8, all_different(L), sum(L, #=, 36),
once(labeling([], L)), L == [1,2,3,4,5,6,7,8],
thread_create(numlist(1, 100000, _), T), thread_join(T, true),
load_html(string("<p class=a>hi</p>"), [element(p, [class=a], [hi])], []),
crypto_data_hash(abc, H, [algorithm(sha256)]),
sub_atom(H, 0, _, _, ba7816bf),
re_matchsub("(\\d+)-(\\d+)", "x 12-34 y", Sub, []),
get_dict(1, Sub, "12"),
garbage_collect, garbage_collect_atoms,
writeln('swipl ok').
EOF
$out/bin/swipl smoke.pl
runHook postInstallCheck
3564kittydoom=
3567luajit
broken"JIT compiler not compatible with Fil-C"
3571rspamd
argwithLuaJIT = false;

Emacs

3578emacs30=
3578emacs30
arg
3580gnutls=
null
3581dbus=
null
3582withX=
false
3583withGTK3=
false
3584withXwidgets=
false
3585withMailutils=
false
3586withNS=
false
3587withPgtk=
false
3588withImageMagick=
false
3589withGpm=
false
3590withSystemd=
true
3591withNativeCompilation=
false
3592withCsrc=
true
3593withCairo=
false
3594withAthena=
false
3595withMotif=
false
3596withDbus=
false
3597withAlsaLib=
false
3598withGlibNetworking=
false
3599withXinput2=
false
3600withJansson=
true

The fork below is a git tree without a generated configure.

3602srcRepo=
true
pin"30.1" "sha256-eTWjpRgLXbA9OQZnbrWPIHPcbj/QYkv58I3IWx5lCIQ="
linkfinal.zlib
use
3607src=
pkgs.fetchFromGitHub
3608owner=
"mbrock"
3609repo=
"emacs"
3610rev=
"5b417a5303636d4b3fbed28d9ff6b41e148caa9b"
3611hash=
"sha256-E/weXr9KaUMSZiVHMphPsfhvlX9RgeUpQSuH52JwQUY="

Nixpkgs' patches target 30.2; the fork is based on 30.1.

skipPatch"02_all_ts-query-pred.patch"
patch./patches/emacs-fork-ts-query-pred.patch
skipPatch"CVE-2026-79992.patch"
patch./patches/emacs-fork-CVE-2026-79992.patch
configure"--with-gnutls=ifavailable"
configure"--with-dumping=none"
configure"--with-pdumper=no"
configure"--with-unexec=no"
configure"--with-native-compilation=yes"
configure"--with-native-compilation-backend=comphack"
configure"--with-comphack-cc=${final.gnufilc0}/bin/clang"
addMakeFlag"NATIVE_COMP_ZYGOTE=yes"
addMakeFlag"NATIVE_COMP_ZYGOTE_JOBS=12"
use
λold
3629preBuild=
old.preBuild or ""
+
# Fil-C's larger native frames overflow the usual 8 MiB stack while
# Comphack compiles large preloaded files such as window.el.
ulimit -S -s 65536
3634postInstall=
old.postInstall or ""
+
# A no-dump Emacs runs loadup.el at startup before startup.el can
# process EMACSNATIVELOADPATH. Make the installed ELNs visible at
# the early path derived from the executable prefix.
ln -s "lib/emacs/${old.version}/native-lisp" "$out/native-lisp"

Fil-C sizes the main thread's stack from RLIMIT_STACK at startup. Byte-compiling large packages such as eat overflows 8 MiB too, so raise the soft limit in every build that uses this Emacs.

3643setupHook=
pkgs.writeText"emacs-setup-hook.sh"
builtins.readFileold.setupHook
+
if [[ $(ulimit -S -s) != unlimited && $(ulimit -S -s) -lt 65536 ]]; then
ulimit -S -s 65536 2>/dev/null || true
fi
skipCheck"some tests fail"

Python Variants

3660python311=
3660python311
broken"use python 3.12"
3664python313=
3664python313
broken"use python 3.12"

Broken / WIP

3671colm
broken"null pointer dereference in bootstrap"

Keyed as written: Nixpkgs' ragel is ragelStable, so ragel follows it.

3677ragelStable=
3677ragelStable
broken"depends on colm which is broken"
3682gnutls

Upstream's 3.8.7.1 fix also applies to Nixpkgs' 3.8.9 release.

patch./ports/patch/gnutls-3.8.7.1.patch
configure"--disable-hardware-acceleration"
3688at-spi2-core
src"2.60.5" "sha256-YFmnfVB0OP9sjW0GAl+Pn1d0+g+Oq+nJsFmxzEHhu8A=" v: "https://download.gnome.org/sources/at-spi2-core/2.60/at-spi2-core-${v}.tar.xz"
patch./ports/patch/at-spi2-core-2.60.5.patch
toolpkgs.python3
addMesonFlag"-Dintrospection=enabled"

glibmm 2.88 needs GLib 2.87; 2.80 is the newest series that accepts the Fil-C GLib 2.80.

3710glibmm_2_68=
3710glibmm_2_68
src"2.80.1" "sha256-8aDA7FFON3S/mTOW8X9yEGtAkSx9fMnRDaMboVUX4/U=" v: "mirror://gnome/sources/glibmm/2.80/glibmm-${v}.tar.xz"
patch./patches/glibmm-gtype.patch

Match the Fil-C GTK 4.14; gtkmm 4.22 needs GTK 4.22.

3717gtkmm4=
3717gtkmm4
src"4.14.0" "sha256-k1CgREt0TKPcaVhuvRtnB1IJIrbZ9PIyEDzmA6Jx7No=" v: "mirror://gnome/sources/gtkmm/4.14/gtkmm-${v}.tar.xz"
use

Fil-C GTK has no X11 backend; run the tests on Broadway instead of Xvfb.

3724nativeCheckInputs=
[ ]
3725checkPhase=
runHook preCheck
export XDG_RUNTIME_DIR="$TMPDIR/runtime"
mkdir -m 700 "$XDG_RUNTIME_DIR"
export GDK_BACKEND=broadway BROADWAY_DISPLAY=:5 GTK_A11Y=none
${final.gtk4.out}/bin/gtk4-broadwayd :5 &
broadway_pid=$!
for _ in $(seq 100); do
[ -S "$XDG_RUNTIME_DIR/broadway6.socket" ] && break
sleep 0.1
done
meson test --print-errorlogs
kill "$broadway_pid"
runHook postCheck

Its pname is libdbusmenu-glib.

3755libgsf
patch./patches/libgsf-gtype-switch.patch

Every test is skipped without unzip on PATH.

useold: nativeCheckInputs = old.nativeCheckInputs ++ pkgs.unzip;
3763libhighscore

--doc-format appeared in gobject-introspection 1.83.2; the Fil-C GI is 1.80, pinned with GLib 2.80. It only selects the doc comment syntax recorded in the GIR.

use
λold
3768postPatch=
old.postPatch or ""
+
substituteInPlace src/meson.build --replace-fail "'--doc-format=gi-docgen'," ""
3771doCheck=
true
3779vala

The build valac has the same patch (ports/build-tools.nix), and its setup hook has the shipped C regenerated.

patch./patches/vala-pointer-once.patch
patch./patches/vala-gen-introspect-gtype.patch
3786dconf
patch./patches/dconf-filc-gtype.patch

Vala is used only to generate API metadata here, not linked into dconf.

arg
3790vala=
pkgs.vala
3791withDocs=
false
use
λold
3794postPatch=
old.postPatch or ""
+
# Keep the ABI checks, comparing against Fil-C's exported names.
sed -i 's/^/pizlonated_/' client/symbols.txt gsettings/symbols.txt

Named explicitly: the pname is "gtk+". GTK 2 has no upstream Fil-C port; this applies the GTK 3 port's pointer-GType changes to 2.24.33 (see docs/gtk-ports.md).

3809gtk3=
3809gtk3
pin"3.24.52" "sha256-gJMfpHKne5oWT2dA48C0RPrGdwBUYy01p/+dZ55ee58="
patch./ports/patch/gtk-3.24.52.patch

GTK3 does not request GLib among its generator inputs itself.

toolfinal.buildPackages.glib
removeMesonFlag"-Dgtk_doc=true"
addMesonFlag"-Dgtk_doc=false"
useold: outputs = builtins.filteroutput: output ≢ "devdoc" old.outputs;
arg
3820x11Support=
false
3821xineramaSupport=
false
3822waylandSupport=
true
3823broadwaySupport=
true
3827gtk4=
3827gtk4
pin"4.14.5" "sha256-VUfyufAGsTOZPgcLh8F4BOBR79o5E/6soRCPor5B4k0="

Nixpkgs' 32-bit Vulkan fix targets newer releases; Vulkan is off here.

skipPatch"fix-32bit-VkImage-null.patch"
patch./ports/patch/gtk-4.14.5.patch
patch./patches/gtk4-broadway-node-alignment.patch
linkfinal.libdrm
addMesonFlag"-Dintrospection=enabled"

Keep the UI toolkit independent of the optional GStreamer video backend and its complete codec/plugin dependency tree.

addMesonFlag"-Dmedia-gstreamer=disabled"
useold: buildInputs = builtins.filterinput: ¬builtins.eleminput.pname or "" "gst-plugins-base" "gst-plugins-bad" old.buildInputs;
arg
3848x11Support=
false
3849xineramaSupport=
false
3850waylandSupport=
true
3851broadwaySupport=
true
3852vulkanSupport=
false
3853trackerSupport=
false
3862graphite2
patch./patches/graphite2-program-pool-capabilities.patch
patch./patches/graphite2-justify-alignment.patch
patch./patches/graphite2-python-pointer-results.patch
use
λold

Let the Fil-C driver supply its runtime, not upstream's explicit GCC runtime. The C linker language and no-libstdc++ test remain.

3869postPatch=
old.postPatch or ""
+
substituteInPlace src/CMakeLists.txt \
--replace-fail '-nodefaultlibs ' "" \
--replace-fail 'target_link_libraries(graphite2 c gcc)' 'target_link_libraries(graphite2 c)'

The text comparison tests load graphite2 through ctypes.

3875nativeBuildInputs=
builtins.filterp: ¬pkgs.lib.hasPrefix"python3" p.pname or p.name or "" old.nativeBuildInputs ++ final.python3.withPackagesps: ps.fonttools

Compare JSON traces as well as printed shaping goldens.

3883cmakeFlags=
old.cmakeFlags ++ "-DGRAPHITE2_NTRACING=OFF"
3887xapian

With more than one descriptor, glibc's nftw opens subdirectories through __openat64_nocancel, a raw syscall that Fil-C's libc still lacks (docs/filc-findings.md). One descriptor avoids that path.

use
λold
3892postPatch=
old.postPatch or ""
+
substituteInPlace tests/harness/unixcmds.cc --replace-fail \
'nftw(filename.c_str(), rm_rf_nftw_helper, 10, flags)' \
'nftw(filename.c_str(), rm_rf_nftw_helper, 1, flags)'
3900proj

The unit tests link GoogleTest, so they need the Fil-C build of it; Nixpkgs lists gtest as a native check input.

use
λold
3904nativeCheckInputs=
builtins.filterp: p.pname or "" ≢ "gtest" old.nativeCheckInputs ++ pkgs.buildPackages.sqlite

test_projinfo.sh runs sqlite3, which a native build finds through the sqlite build input.

3909checkInputs=
old.checkInputs or [ ] ++ final.gtest
3917potrace

Its bsf/bsr helpers branch inside the asm (jnz), which Fil-C's safe inline assembly does not accept. Use the portable versions.

use
λold
3921postPatch=
old.postPatch or ""
+
substituteInPlace src/bitops.h --replace-fail \
'#if defined(HAVE_I386)' '#if defined(HAVE_I386) && !defined(__FILC__)'
3941rsync
src"3.5.2" "sha256-oQ1ZGCUlHgcPdMmN89qtGV3vTtgbSi3hYWkCauoz9sg=" v: "https://github.com/RsyncProject/rsync/releases/download/v${v}/rsync-${v}.tar.gz"
patch./patches/rsync-filc-io-priority.patch
use
λold

IDN support is enabled by default starting with 3.5.2.

3949buildInputs=
old.buildInputs ++ final.libidn2
3950preBuild=
old.preBuild
+
# New tests embed executable scripts; patchShebangs cannot see them.
substituteInPlace testsuite/rrsync-receiver-file-arg_test.py \
--replace-fail '#!/usr/bin/env python3' '#!${pkgs.buildPackages.python3}/bin/python3'
substituteInPlace testsuite/rsync-ssl-type-option_test.py \
--replace-fail '#!/usr/bin/env bash' '#!${pkgs.stdenv.shell}'

These tests LD_PRELOAD shims that use dlsym(RTLD_NEXT, ...), which Fil-C refuses (docs/filc-findings.md).

3959preCheck=
old.preCheck
+
export RSYNC_EXCLUDE="$RSYNC_EXCLUDE,source-change-size-continues,hardlinks-emlink-recovery"
3965kronosnet

Cross builds skip configure's doxygen2man search and leave DOXYGEN2MAN empty, so no man pages are made and install-man3 fails.

configure"DOXYGEN2MAN=${pkgs.buildPackages.libqb}/bin/doxygen2man"

The LanguageMachines stack (ticcutils, timbl, frog, ...).

let

AX_CHECK_ZLIB, AX_CXX_COMPILE_STDCXX_17 and friends come from autoconf-archive. Nixpkgs lists it in buildInputs, where a cross build's aclocal does not look.

3977autoconfArchive=
toolpkgs.buildPackages.autoconf-archive
uses tool

The libraries use ICU's regex and transliterator (icu-i18n) but link only icu-uc and icu-io. GNU ld finds i18n through icu-io's DT_NEEDED; Fil-C's gold does not, so programs linking them failed.

3981icuI18n=
λold
3982postPatch=
old.postPatch or ""
+
substituteInPlace configure.ac --replace-fail \
'[icu-uc >= 50 icu-io]' '[icu-uc >= 50 icu-io icu-i18n]'
uses use
3987port=
λsteps name
3988inherit
name
3989value=
3989… for pkgs.${name}
steps
uses for
in
builtins.listToAttrsmapportautoconfArchive icuI18n "frog" "libfolia" "mbt" "ticcutils" "timbl" "timblserver" ++ mapportautoconfArchive "frogdata" "uctodata"
//
4012ucto=
4012ucto
autoconfArchive
icuI18n

configure asks a bare pkg-config (absent in a cross build) for uctodata's prefix, so the data directory was compiled in as /share/ucto/ and ucto (and frog) found no languages.

use
λold
4019postPatch=
old.postPatch or ""
+
substituteInPlace configure.ac --replace-fail \
'`pkg-config --' '`$PKG_CONFIG --'
4028recode

The warning setup adds gnulib's lib/ with -isystem, which comes after the Fil-C libc's -isystem, so lib/fcntl.h (O_BINARY) was shadowed by libc's. Plain -I searches it first.

configure"--disable-gcc-warnings"

The tests build a Fil-C extension module (from Cython's C output) and import it, so they need the Fil-C Python rather than the build's, without the build Python's module path and sysconfig name.

use
λold
4037preCheck=
old.preCheck or ""
+
unset PYTHONPATH _PYTHON_HOST_PLATFORM _PYTHON_SYSCONFIGDATA_NAME
4040checkFlags=
old.checkFlags or [ ] ++ "PYTHON=${final.python3.withPackagesps: ps.setuptools}/bin/python3"
4046rustc
broken"oh sweet summer child"