threads: make it the threading package itself

`threads` was `{ model, package }`, but more recently the threading
packages also declare their model as `passthru.threadModel` (e.g. `mcf`
for `windows.mcfgthreads`, `posix` for `windows.pthreads`). The latter
technique is more idiomatic for Nixpkgs, and was done as part of the GCC
NG work.

Now, let's roll that out everywhere. Make `threads` just the package, or
`null`, and read the model off it.

- GCC "legacy": `gcc` now takes `threadsCross` as that package and
  derives `--enable-threads` from it, still defaulting to `win32`.

  - `dxvk`, because it was overriding `gcc`, is updated accordingly.

- GCC NG: `gccNGPackages` no longer needs to duplicate the logic. It can
  just use `threads` rather than make its own. Some comments were moved
  around to better homes accordingly.

No derivation hashes should be changed.

Assisted-by: Claude Code (Claude Opus 5.5)
This commit is contained in:
John Ericson
2026-10-26 00:18:04 -04:00
parent b95002873b
commit aa6fcb683a
11 changed files with 35 additions and 36 deletions

View File

@@ -14,10 +14,7 @@ stdenvNoCC.mkDerivation (
overrideCC stdenv (
stdenv.cc.override (old: {
cc = old.cc.override {
threadsCross = {
model = "win32";
package = null;
};
threadsCross = null;
};
})
);

View File

@@ -33,7 +33,7 @@ let
reproducibleBuild = true;
profiledCompiler = false;
libcCross = if !buildIsTarget then targetPackages.libc or pkgs.libc else null;
threadsCross = if !buildIsTarget then targetPackages.threads or pkgs.threads else { };
threadsCross = if !buildIsTarget then targetPackages.threads or pkgs.threads else null;
isl = if stdenv.hostPlatform.isDarwin then null else isl_0_20;
# do not allow version skew when cross-building gcc
#

View File

@@ -111,7 +111,7 @@ let
if targetPlatform.isUnix then
"posix"
else if targetPlatform.isWindows then
(threadsCross.model or "win32")
(threadsCross.threadModel or "win32")
else
"single"
}"

View File

@@ -85,7 +85,5 @@ in
++ optionals (zlib != null) [ zlib ]
++ optionals (langGo && stdenv.hostPlatform.isMusl) [ libucontext ];
depsTargetTarget = optionals (
!withoutTargetLibc && threadsCross != { } && threadsCross.package != null
) [ threadsCross.package ];
depsTargetTarget = optionals (!withoutTargetLibc && threadsCross != null) [ threadsCross ];
}

View File

@@ -25,7 +25,7 @@
);
in
mkFlags libcCross
++ lib.optionals (!withoutTargetLibc) (mkFlags (threadsCross.package or null))
++ lib.optionals (!withoutTargetLibc) (mkFlags threadsCross)
++ mkFlags (libcCross.w32api or null);
EXTRA_LDFLAGS_FOR_TARGET =
@@ -50,6 +50,6 @@
);
in
mkFlags libcCross
++ lib.optionals (!withoutTargetLibc) (mkFlags (threadsCross.package or null))
++ lib.optionals (!withoutTargetLibc) (mkFlags threadsCross)
++ mkFlags (libcCross.w32api or null);
}

View File

@@ -45,7 +45,7 @@
enablePlugin ? _systemInfo.buildIsHost, # Whether to support user-supplied plug-ins
name ? "gcc",
libcCross ? null,
threadsCross ? { }, # for MinGW
threadsCross ? null, # for MinGW
withoutTargetLibc ? stdenv.targetPlatform.libc == null,
flex,
gnused ? null,
@@ -199,7 +199,7 @@ assert langGo -> langCC;
assert langAda -> gnat-bootstrap != null;
# threadsCross is just for MinGW
assert threadsCross != { } -> stdenv.targetPlatform.isWindows;
assert threadsCross != null -> stdenv.targetPlatform.isWindows;
# profiledCompiler builds inject non-determinism in one of the compilation stages.
# If turned on, we can't provide reproducible builds anymore

View File

@@ -15,7 +15,7 @@
binutils,
buildGccPackages,
targetGccPackages,
windows,
threads,
makeScopeWithSplicing',
otherSplices,
...
@@ -141,18 +141,10 @@ makeScopeWithSplicing' {
};
in
{
# Where the libc's own threading is not the one we want, a separate
# library supplies it: MinGW offers only `win32`, and `mcfgthreads` gives
# `mcf`, which is the better answer on Windows. `null`, the answer
# everywhere else, means "whatever the libc offers".
# The model is not written down here; the package declares it, in the
# same `passthru.threadModel` a libc uses.
#
# This stays out of the bootstrap cycle by itself: it is built with
# `windows.crossThreadsStdenv`, which on `useGccNG` platforms is stage 3
# — real libc, bootstrap single-threaded libgcc — the very compiler that
# goes on to build the threaded `libgcc-libc`.
threads = if stdenv.hostPlatform.isMinGW then windows.mcfgthreads else null;
# See `threads` in pkgs/top-level/all-packages.nix. It is re-bound in
# this scope only to make overriding it for the other runtime libraries
# easier.
inherit threads;
stdenv = overrideCC stdenv gccPackages.gcc;

View File

@@ -40,7 +40,7 @@ stdenv.mkDerivation (finalAttrs: {
depsBuildTarget = lib.optional isCross targetCC;
depsTargetTarget = lib.optional stdenv.targetPlatform.isMinGW targetPackages.threads.package;
depsTargetTarget = lib.optional stdenv.targetPlatform.isMinGW targetPackages.threads;
postPatch = ''
patchShebangs .

View File

@@ -40,7 +40,7 @@ stdenv.mkDerivation (finalAttrs: {
depsBuildTarget = lib.optional isCross targetCC;
depsTargetTarget = lib.optional stdenv.targetPlatform.isMinGW targetPackages.threads.package;
depsTargetTarget = lib.optional stdenv.targetPlatform.isMinGW targetPackages.threads;
postPatch = ''
patchShebangs .

View File

@@ -31,6 +31,9 @@ makeScopeWithSplicing' {
if stdenv.hostPlatform.useLLVM or false then
buildPackages.llvmPackages.clangNoLibcxx
else if stdenv.hostPlatform.useGccNG or false then
# This stage of the `gccNGPackages` bootstrap chain has a real libc
# and a bootstrap single-threaded libgcc. The threading library
# built with this is what the threaded `libgcc-libc` then links.
buildPackages.gccNGPackages.gccWithLibcAndBasicLibgcc
else
buildPackages.gccWithoutTargetLibc.override (old: {

View File

@@ -4018,7 +4018,7 @@ with pkgs;
libcxx ? null,
extraPackages ? lib.optional (
cc.isGNU or false && stdenv.targetPlatform.isMinGW
) targetPackages.threads.package,
) targetPackages.threads,
nixSupport ? { },
...
}@extraArgs:
@@ -5516,14 +5516,23 @@ with pkgs;
else
throw "Unknown libc ${libc}";
# An optional threading library to be used by GCC's runtime libraries.
#
# When non-null, this package will be used for that purpose. When null, libc
# will be used instead.
#
# The package (like libc, for the sake of the fallback case when this is
# null) declares its model as `passthru.threadModel`.
#
# On MinGW the libc offers only `win32`; `windows.mcfgthreads` gives `mcf`,
# and `windows.pthreads` would give `posix`. `windows.mcfgthreads` is our
# default there because it is both fast / minimally diverged from native and
# featureful.
threads =
lib.optionalAttrs (stdenv.hostPlatform.isMinGW && !(stdenv.hostPlatform.useLLVM or false))
{
# other possible values: win32 or posix
model = "mcf";
# For win32 or posix set this to null
package = windows.mcfgthreads;
};
if stdenv.hostPlatform.isMinGW && !(stdenv.hostPlatform.useLLVM or false) then
windows.mcfgthreads
else
null;
# Only supported on Linux and only on glibc
glibcLocales =