cygwin: add as a cross-compilation target, and get hello to build (#444470)

Changed files
+912 -31
lib
pkgs
build-support
bintools-wrapper
cc-wrapper
setup-hooks
by-name
co
cocom-tool-set
development
compilers
libraries
openssl
os-specific
stdenv
top-level
+6 -3
lib/systems/default.nix
···
"ucrt"
else if final.isMinGW then
"msvcrt"
+
else if final.isCygwin then
+
"cygwin"
else if final.isWasi then
"wasilibc"
else if final.isWasm && !final.isWasi then
···
sharedLibrary =
if final.isDarwin then
".dylib"
-
else if final.isWindows then
+
else if (final.isWindows || final.isCygwin) then
".dll"
else
".so";
···
// {
staticLibrary = if final.isWindows then ".lib" else ".a";
library = if final.isStatic then final.extensions.staticLibrary else final.extensions.sharedLibrary;
-
executable = if final.isWindows then ".exe" else "";
+
executable = if (final.isWindows || final.isCygwin) then ".exe" else "";
};
# Misc boolean options
useAndroidPrebuilt = false;
···
{
linux = "Linux";
windows = "Windows";
+
cygwin = "CYGWIN_NT";
darwin = "Darwin";
netbsd = "NetBSD";
freebsd = "FreeBSD";
···
"openbsd"
else if final.isSunOS then
"sunos"
-
else if final.isWindows then
+
else if (final.isWindows || final.isCygwin) then
"win32"
else
null;
+4
lib/systems/examples.nix
···
useLLVM = true;
};
+
x86_64-cygwin = {
+
config = "x86_64-pc-cygwin";
+
};
+
# BSDs
aarch64-freebsd = {
+1 -2
lib/systems/inspect.nix
···
kernel = kernels.windows;
};
isCygwin = {
-
kernel = kernels.windows;
-
abi = abis.cygnus;
+
kernel = kernels.cygwin;
};
isMinGW = {
kernel = kernels.windows;
+19 -13
lib/systems/parse.nix
···
isLinux
isPower64
isWindows
+
isCygwin
;
inherit (lib.types)
···
execFormat = pe;
families = { };
};
+
cygwin = {
+
execFormat = pe;
+
families = { };
+
};
ghcjs = {
execFormat = unknown;
families = { };
···
types.abi = enum (attrValues abis);
abis = setTypes types.openAbi {
-
cygnus = { };
msvc = { };
# Note: eabi is specific to ARM and PowerPC.
···
throw "system string '${lib.concatStringsSep "-" l}' with 1 component is ambiguous";
"2" = # We only do 2-part hacks for things Nix already supports
if elemAt l 1 == "cygwin" then
-
{
-
cpu = elemAt l 0;
-
kernel = "windows";
-
abi = "cygnus";
-
}
+
mkSkeletonFromList [
+
(elemAt l 0)
+
"pc"
+
"cygwin"
+
]
# MSVC ought to be the default ABI so this case isn't needed. But then it
# becomes difficult to handle the gnu* variants for Aarch32 correctly for
# minGW. So it's easier to make gnu* the default for the MinGW, but
···
else
elemAt l 2;
}
+
# lots of tools expect a triplet for Cygwin, even though the vendor is just "pc"
+
else if elemAt l 2 == "cygwin" then
+
{
+
cpu = elemAt l 0;
+
vendor = elemAt l 1;
+
kernel = "cygwin";
+
}
else
throw "system string '${lib.concatStringsSep "-" l}' with 3 components is ambiguous";
"4" = {
···
getVendor args.vendor
else if isDarwin parsed then
vendors.apple
-
else if isWindows parsed then
+
else if (isWindows parsed || isCygwin parsed) then
vendors.pc
else
vendors.unknown;
···
abi,
...
}:
-
if abi == abis.cygnus then
-
"${cpu.name}-cygwin"
-
else if kernel.families ? darwin then
-
"${cpu.name}-darwin"
-
else
-
"${cpu.name}-${kernelName kernel}";
+
if kernel.families ? darwin then "${cpu.name}-darwin" else "${cpu.name}-${kernelName kernel}";
tripleFromSystem =
{
+1 -2
lib/tests/systems.nix
···
++ illumos
++ wasi
++ windows
+
++ cygwin
++ embedded
++ mmix
++ js
···
"x86_64-openbsd"
];
testwindows = mseteq windows [
-
"i686-cygwin"
-
"x86_64-cygwin"
"aarch64-windows"
"i686-windows"
"x86_64-windows"
+3
pkgs/build-support/bintools-wrapper/default.nix
···
}
fi
''
+
+ optionalString (libc.w32api or null != null) ''
+
echo '-L${lib.getLib libc.w32api}${libc.libdir or "/lib/w32api"}' >> $out/nix-support/libc-ldflags
+
''
)
##
+18 -6
pkgs/build-support/cc-wrapper/default.nix
···
libc_dev = optionalString (libc != null) (getDev libc);
libc_lib = optionalString (libc != null) (getLib libc);
cc_solib = getLib cc + optionalString (targetPlatform != hostPlatform) "/${targetPlatform.config}";
+
cc_bin = getBin cc + optionalString (targetPlatform != hostPlatform) "/${targetPlatform.config}";
# The wrapper scripts use 'cat' and 'grep', so we may need coreutils.
coreutils_bin = optionalString (!nativeTools) (getBin coreutils);
···
]
++ optional (cc.langC or true) ./setup-hook.sh
++ optional (cc.langFortran or false) ./fortran-hook.sh
-
++ optional (targetPlatform.isWindows) (
+
++ optional (targetPlatform.isWindows || targetPlatform.isCygwin) (
stdenvNoCC.mkDerivation {
name = "win-dll-hook.sh";
dontUnpack = true;
-
installPhase = ''
-
echo addToSearchPath "LINK_DLL_FOLDERS" "${cc_solib}/lib" > $out
-
echo addToSearchPath "LINK_DLL_FOLDERS" "${cc_solib}/lib64" >> $out
-
echo addToSearchPath "LINK_DLL_FOLDERS" "${cc_solib}/lib32" >> $out
-
'';
+
installPhase =
+
if targetPlatform.isCygwin then
+
''
+
echo addToSearchPath "LINK_DLL_FOLDERS" "${cc_bin}/lib" >> $out
+
''
+
else
+
''
+
echo addToSearchPath "LINK_DLL_FOLDERS" "${cc_solib}/lib" > $out
+
echo addToSearchPath "LINK_DLL_FOLDERS" "${cc_solib}/lib64" >> $out
+
echo addToSearchPath "LINK_DLL_FOLDERS" "${cc_solib}/lib32" >> $out
+
'';
}
);
···
for dir in "${cc}"/lib/gcc/*/*/include-fixed; do
include '-idirafter' ''${dir} >> $out/nix-support/libc-cflags
done
+
''
+
+ optionalString (libc.w32api or null != null) ''
+
echo '-idirafter ${lib.getDev libc.w32api}${
+
libc.incdir or "/include/w32api"
+
}' >> $out/nix-support/libc-cflags
''
+ ''
+73
pkgs/build-support/setup-hooks/cygwin-dll-link.sh
···
+
addLinkDLLPaths() {
+
addToSearchPath "LINK_DLL_FOLDERS" "$1/lib"
+
addToSearchPath "LINK_DLL_FOLDERS" "$1/bin"
+
}
+
+
addEnvHooks "$targetOffset" addLinkDLLPaths
+
+
addOutputDLLPaths() {
+
for output in $(getAllOutputNames); do
+
addToSearchPath "LINK_DLL_FOLDERS" "${!output}/lib"
+
addToSearchPath "LINK_DLL_FOLDERS" "${!output}/bin"
+
done
+
}
+
+
postInstallHooks+=(addOutputDLLPaths)
+
+
_dllDeps() {
+
"$OBJDUMP" -p "$1" \
+
| sed -n 's/.*DLL Name: \(.*\)/\1/p' \
+
| sort -u
+
}
+
+
_linkDeps() {
+
local target="$1" dir="$2" check="$3"
+
echo 'target:' "$target"
+
local dll
+
_dllDeps "$target" | while read dll; do
+
echo ' dll:' "$dll"
+
if [[ -e "$dir/$dll" ]]; then continue; fi
+
# Locate the DLL - it should be an *executable* file on $LINK_DLL_FOLDERS.
+
local dllPath="$(PATH="$(dirname "$target"):$LINK_DLL_FOLDERS" type -P "$dll")"
+
if [[ -z "$dllPath" ]]; then
+
if [[ -z "$check" || -n "${allowedImpureDLLsMap[$dll]}" ]]; then
+
continue
+
fi
+
echo unable to find $dll in $LINK_DLL_FOLDERS >&2
+
exit 1
+
fi
+
echo ' linking to:' "$dllPath"
+
CYGWIN+=\ winsymlinks:nativestrict ln -sr "$dllPath" "$dir"
+
# That DLL might have its own (transitive) dependencies,
+
# so add also all DLLs from its directory to be sure.
+
_linkDeps "$dllPath" "$dir" ""
+
done
+
}
+
+
linkDLLs() {
+
if [ ! -d "$prefix" ]; then return; fi
+
(
+
set -e
+
shopt -s globstar nullglob
+
+
local -a allowedImpureDLLsArray
+
concatTo allowedImpureDLLsArray allowedImpureDLLs
+
+
local -A allowedImpureDLLsMap;
+
+
for dll in "${allowedImpureDLLsArray[@]}"; do
+
allowedImpureDLLsMap[$dll]=1
+
done
+
+
cd "$prefix"
+
+
# Iterate over any DLL that we depend on.
+
local target
+
for target in {bin,libexec}/**/*.{exe,dll}; do
+
[[ ! -f "$target" || ! -x "$target" ]] ||
+
_linkDeps "$target" "$(dirname "$target")" "1"
+
done
+
)
+
}
+
+
fixupOutputHooks+=(linkDLLs)
+43
pkgs/by-name/co/cocom-tool-set/package.nix
···
+
{
+
lib,
+
stdenv,
+
fetchurl,
+
autoreconfHook,
+
bison,
+
}:
+
stdenv.mkDerivation (finalAttrs: {
+
pname = "cocom";
+
version = "0.996";
+
+
src = fetchurl {
+
url = "mirror://sourceforge/cocom/cocom-${finalAttrs.version}.tar.gz";
+
hash = "sha256-4UOrVW15o17zHsHiQIl8m4qNC2aT5QorbkfX/UsgBRk=";
+
};
+
+
env = {
+
RANLIB = "${stdenv.cc.targetPrefix}gcc-ranlib";
+
NIX_CFLAGS_COMPILE = toString [
+
"-Wno-error=implicit-int"
+
"-Wno-error=implicit-function-declaration"
+
];
+
};
+
+
autoreconfFlags = "REGEX";
+
+
strictDeps = true;
+
+
nativeBuildInputs = [
+
autoreconfHook
+
bison
+
];
+
+
hardeningDisable = [ "format" ];
+
+
meta = {
+
description = "Tool set oriented towards the creation of compilers";
+
homepage = "https://cocom.sourceforge.net/";
+
license = lib.licenses.gpl2Plus;
+
maintainers = with lib.maintainers; [ puffnfresh ];
+
platforms = lib.platforms.unix;
+
};
+
})
+1 -1
pkgs/development/compilers/gcc/common/configure-flags.nix
···
++ lib.optional (
lib.systems.equals targetPlatform hostPlatform && targetPlatform.isx86_32
) "--with-arch=${stdenv.hostPlatform.parsed.cpu.name}"
-
++ lib.optional targetPlatform.isNetBSD "--disable-libssp" # Provided by libc.
+
++ lib.optional (targetPlatform.isNetBSD || targetPlatform.isCygwin) "--disable-libssp" # Provided by libc.
++ lib.optionals hostPlatform.isSunOS [
"--enable-long-long"
"--enable-libssp"
+6 -2
pkgs/development/compilers/gcc/common/extra-target-flags.nix
···
]
);
in
-
mkFlags libcCross ++ lib.optionals (!withoutTargetLibc) (mkFlags (threadsCross.package or null));
+
mkFlags libcCross
+
++ lib.optionals (!withoutTargetLibc) (mkFlags (threadsCross.package or null))
+
++ mkFlags (libcCross.w32api or null);
EXTRA_LDFLAGS_FOR_TARGET =
let
···
)
);
in
-
mkFlags libcCross ++ lib.optionals (!withoutTargetLibc) (mkFlags (threadsCross.package or null));
+
mkFlags libcCross
+
++ lib.optionals (!withoutTargetLibc) (mkFlags (threadsCross.package or null))
+
++ mkFlags (libcCross.w32api or null);
}
+4 -1
pkgs/development/compilers/gcc/common/libgcc.nix
···
useLibgccFromTargetLibc = libcCross != null && libcCross ? passthru.libgcc;
enableLibGccOutput =
-
(!stdenv.targetPlatform.isWindows || (lib.systems.equals stdenv.targetPlatform stdenv.hostPlatform))
+
(
+
!(stdenv.targetPlatform.isWindows || stdenv.targetPlatform.isCygwin)
+
|| (lib.systems.equals stdenv.targetPlatform stdenv.hostPlatform)
+
)
&& !langJit
&& !stdenv.hostPlatform.isDarwin
&& enableShared
+14
pkgs/development/compilers/gcc/patches/default.nix
···
}
.${majorVersion} or [ ]
)
+
+
++ optional targetPlatform.isCygwin (fetchpatch {
+
name = "libstdc-fix-compilation-in-freestanding-win32.patch";
+
url = "https://inbox.sourceware.org/gcc-patches/20250922182808.2599390-2-corngood@gmail.com/raw";
+
hash = "sha256-+EYW9lG8CviVX7RyNHp+iX+8BRHUjt5b07k940khbbY=";
+
})
+
+
++ optionals targetPlatform.isCygwin [
+
(fetchpatch {
+
name = "cygwin-fix-compilation-with-inhibit_libc.patch";
+
url = "https://inbox.sourceware.org/gcc-patches/20250926170154.2222977-1-corngood@gmail.com/raw";
+
hash = "sha256-mgzMRvgPdhj+Q2VRsFhpE2WQzg0CvWsc5/FRAsSU1Es=";
+
})
+
]
+2
pkgs/development/libraries/openssl/default.nix
···
cat ${conf} > $etc/etc/ssl/openssl.cnf
'';
+
allowedImpureDLLs = [ "CRYPT32.dll" ];
+
postFixup =
lib.optionalString (!stdenv.hostPlatform.isWindows) ''
# Check to make sure the main output and the static runtime dependencies
+25
pkgs/os-specific/cygwin/default.nix
···
+
{
+
makeScopeWithSplicing',
+
generateSplicesForMkScope,
+
}:
+
+
let
+
otherSplices = generateSplicesForMkScope "cygwin";
+
in
+
makeScopeWithSplicing' {
+
inherit otherSplices;
+
f =
+
self:
+
let
+
callPackage = self.callPackage;
+
in
+
{
+
w32api = callPackage ./w32api { };
+
w32api-headers = callPackage ./w32api { headersOnly = true; };
+
+
newlib-cygwin = callPackage ./newlib-cygwin { };
+
# this is here to avoid symlinks being made to cygwin1.dll in /nix/store
+
newlib-cygwin-nobin = callPackage ./newlib-cygwin/nobin.nix { };
+
newlib-cygwin-headers = callPackage ./newlib-cygwin { headersOnly = true; };
+
};
+
}
+168
pkgs/os-specific/cygwin/newlib-cygwin/default.nix
···
+
{
+
lib,
+
stdenv,
+
stdenvNoCC,
+
stdenvNoLibc,
+
autoreconfHook,
+
bison,
+
buildPackages,
+
cocom-tool-set,
+
flex,
+
perl,
+
w32api,
+
w32api-headers,
+
+
headersOnly ? false,
+
}:
+
+
(if headersOnly then stdenvNoCC else stdenvNoLibc).mkDerivation (
+
finalAttrs:
+
{
+
pname = "newlib-cygwin${lib.optionalString headersOnly "-headers"}";
+
version = "3.6.4";
+
+
src = buildPackages.fetchgit {
+
url = "https://cygwin.com/git/newlib-cygwin.git";
+
rev = "cygwin-${finalAttrs.version}";
+
hash = "sha256-+WYKwqcDAc7286GzbgKKAxNJCOf3AeNnF8XEVPoor+g=";
+
};
+
+
outputs = [
+
"out"
+
]
+
++ lib.optionals (!headersOnly) [
+
"bin"
+
"dev"
+
"man"
+
];
+
+
patches = [
+
# Newer versions of gcc don't like struct winsize being used before being
+
# declared. Backport of https://cygwin.com/cgit/newlib-cygwin/commit/?id=73600d68227e125af24b7de7c3fccbd4eb66ee03
+
./fix-winsize.patch
+
]
+
++ lib.optional (!headersOnly) [
+
# https://cygwin.com/pipermail/cygwin-developers/2020-September/011970.html
+
# This is required for boost coroutines to work. After we get to the point
+
# where nix runs on cygwin, we can attempt to upstream this again.
+
./store-tls-pointer-in-win32-tls.patch
+
]
+
# After cygwin hosted builds are working, we should upstream this
+
++ lib.optional (
+
!headersOnly && stdenvNoLibc.hostPlatform != stdenvNoLibc.buildPlatform
+
) ./fix-cross.patch;
+
+
passthru.w32api = if headersOnly then w32api-headers else w32api;
+
+
meta = {
+
homepage = "https://cygwin.com/";
+
description = "A DLL which provides substantial POSIX API functionality on Windows.";
+
license = with lib.licenses; [
+
# newlib
+
gpl2
+
# winsup
+
gpl3
+
];
+
platforms = lib.platforms.cygwin;
+
maintainers = [ lib.maintainers.corngood ];
+
};
+
}
+
// (
+
if headersOnly then
+
{
+
dontConfigure = true;
+
dontBuild = true;
+
+
installPhase = ''
+
mkdir -p $out/include/
+
cp -r newlib/libc/include/* $out/include/
+
cp -r winsup/cygwin/include/* $out/include/
+
'';
+
}
+
else
+
{
+
postPatch = ''
+
patchShebangs --build winsup/cygwin/scripts
+
'';
+
+
autoreconfFlags = [
+
"winsup"
+
]
+
# Only reconfigure root when fix-cross.patch is applied. Otherwise the
+
# autoconf version check will fail.
+
++ lib.optional (stdenvNoLibc.hostPlatform != stdenvNoLibc.buildPlatform) ".";
+
+
env =
+
let
+
libflag = "-Wl,-L${lib.getLib w32api}${w32api.libdir or "/lib/w32api"}";
+
in
+
{
+
CFLAGS_FOR_TARGET = toString [
+
libflag
+
];
+
+
CXXFLAGS_FOR_TARGET = toString [
+
"-Wno-error=register"
+
libflag
+
];
+
};
+
+
strictDeps = true;
+
+
depsBuildBuild = [ buildPackages.stdenv.cc ];
+
+
nativeBuildInputs = [
+
autoreconfHook
+
bison
+
cocom-tool-set
+
flex
+
perl
+
];
+
+
buildInputs = [ w32api ];
+
+
makeFlags = [
+
"tooldir=${placeholder "out"}"
+
];
+
+
enableParallelBuilding = true;
+
+
# this is explicitly -j1 in cygwin.cygport
+
# without it the install order is non-deterministic
+
enableParallelInstalling = false;
+
+
hardeningDisable = [
+
# conflicts with internal definition of 'bzero'
+
"fortify"
+
"stackprotector"
+
];
+
+
configurePlatforms = [
+
"build"
+
"target"
+
];
+
+
configureFlags = [
+
"--disable-shared"
+
"--disable-doc"
+
"--enable-static"
+
"--disable-dumper"
+
"--with-cross-bootstrap"
+
]
+
++ lib.optional (stdenvNoLibc.hostPlatform != stdenvNoLibc.buildPlatform) [
+
"ac_cv_prog_CC=gcc"
+
];
+
+
allowedImpureDLLs = [
+
"ADVAPI32.dll"
+
"PSAPI.DLL"
+
"NETAPI32.dll"
+
"SHELL32.dll"
+
"USER32.dll"
+
"USERENV.dll"
+
"dbghelp.dll"
+
"ntdll.dll"
+
];
+
}
+
)
+
)
+55
pkgs/os-specific/cygwin/newlib-cygwin/fix-cross.patch
···
+
Disable strict autoconf version check so we can autoreconf in nixpkgs.
+
+
diff --git a/config/override.m4 b/config/override.m4
+
index 8b954d3cb..60c4cfd12 100644
+
--- a/config/override.m4
+
+++ b/config/override.m4
+
@@ -44,7 +44,6 @@ AC_DEFUN([_GCC_AUTOCONF_VERSION_CHECK],
+
[m4_fatal([Please use exactly Autoconf ]_GCC_AUTOCONF_VERSION[ instead of ]m4_defn([m4_PACKAGE_VERSION])[.])])
+
])
+
m4_define([AC_INIT], m4_defn([AC_INIT])[
+
-_GCC_AUTOCONF_VERSION_CHECK
+
])
+
+
+
+
This is needed for target linking to find e.g. crt0.o.
+
diff --git a/configure.ac b/configure.ac
+
index 05ddf6987..f5bbd5c72 100644
+
--- a/configure.ac
+
+++ b/configure.ac
+
@@ -3166,7 +3166,7 @@ case " $target_configdirs " in
+
*" --with-newlib "*)
+
case "$target" in
+
*-cygwin*)
+
- FLAGS_FOR_TARGET=$FLAGS_FOR_TARGET' -L$$r/$(TARGET_SUBDIR)/winsup/cygwin -isystem $$s/winsup/cygwin/include'
+
+ FLAGS_FOR_TARGET=$FLAGS_FOR_TARGET' -B$$r/$(TARGET_SUBDIR)/winsup/cygwin -isystem $$s/winsup/cygwin/include'
+
;;
+
esac
+
+
+
Autoconf clears EXEEXT= in cross, which breaks installation of utils/cygserver.
+
+
AC_CHECK_LIB is disabled in cross after AC_NO_EXECUTABLES.
+
diff --git a/winsup/configure.ac b/winsup/configure.ac
+
index e7ac814b1..14b56e130 100644
+
--- a/winsup/configure.ac
+
+++ b/winsup/configure.ac
+
@@ -40,6 +40,8 @@ AM_PROG_AS
+
AC_LANG(C)
+
AC_LANG(C++)
+
+
+EXEEXT=.exe
+
+
+
AC_ARG_WITH([cross-bootstrap],[AS_HELP_STRING([--with-cross-bootstrap],[do not build programs using the MinGW toolchain or check for MinGW libraries (useful for bootstrapping a cross-compiler)])],[],[with_cross_bootstrap=no])
+
+
AC_CYGWIN_INCLUDES
+
@@ -135,8 +137,6 @@ AM_CONDITIONAL(BUILD_DUMPER, [test "x$build_dumper" = "xyes"])
+
# libbfd.a doesn't have a pkgconfig file, so we guess what it's dependencies
+
# are, based on what's present in the build environment
+
BFD_LIBS="-lintl -liconv -liberty -lz"
+
-AC_CHECK_LIB([sframe], [sframe_decode], [BFD_LIBS="${BFD_LIBS} -lsframe"])
+
-AC_CHECK_LIB([zstd], [ZSTD_isError], [BFD_LIBS="${BFD_LIBS} -lzstd"])
+
AC_SUBST([BFD_LIBS])
+
+
AC_CONFIG_FILES([
+31
pkgs/os-specific/cygwin/newlib-cygwin/fix-winsize.patch
···
+
diff --git a/winsup/cygwin/include/sys/termios.h b/winsup/cygwin/include/sys/termios.h
+
index d1b4a0af5..75e0c5348 100644
+
--- a/winsup/cygwin/include/sys/termios.h
+
+++ b/winsup/cygwin/include/sys/termios.h
+
@@ -282,6 +282,12 @@ struct termios
+
speed_t c_ospeed;
+
};
+
+
+struct winsize
+
+{
+
+ unsigned short ws_row, ws_col;
+
+ unsigned short ws_xpixel, ws_ypixel;
+
+};
+
+
+
#define termio termios
+
+
#ifdef __cplusplus
+
@@ -313,13 +319,6 @@ int tcsetwinsize(int fd, const struct winsize *winsz);
+
#define cfgetospeed(tp) ((tp)->c_ospeed)
+
#endif
+
+
-/* Extra stuff to make porting stuff easier. */
+
-struct winsize
+
-{
+
- unsigned short ws_row, ws_col;
+
- unsigned short ws_xpixel, ws_ypixel;
+
-};
+
-
+
#define TIOCGWINSZ (('T' << 8) | 1)
+
#define TIOCSWINSZ (('T' << 8) | 2)
+
#define TIOCLINUX (('T' << 8) | 3)
+9
pkgs/os-specific/cygwin/newlib-cygwin/nobin.nix
···
+
{
+
emptyDirectory,
+
newlib-cygwin,
+
}:
+
+
newlib-cygwin
+
// {
+
bin = emptyDirectory;
+
}
+88
pkgs/os-specific/cygwin/newlib-cygwin/remove-definitions-that-conflict-with-mingw.patch
···
+
From cc95494ed527e64fcd1ade7ed7ae44f9e0a6fa8a Mon Sep 17 00:00:00 2001
+
From: David McFarland <corngood@gmail.com>
+
Date: Tue, 9 Sep 2025 15:04:45 -0300
+
Subject: [PATCH] remove definitions that conflict with mingw
+
+
---
+
winsup/cygwin/fhandler/socket_inet.cc | 2 ++
+
winsup/cygwin/fhandler/socket_local.cc | 2 ++
+
winsup/cygwin/local_includes/ntdll.h | 20 --------------------
+
winsup/cygwin/net.cc | 2 ++
+
4 files changed, 6 insertions(+), 20 deletions(-)
+
+
diff --git a/winsup/cygwin/fhandler/socket_inet.cc b/winsup/cygwin/fhandler/socket_inet.cc
+
index 63cc498f1..03681c07b 100644
+
--- a/winsup/cygwin/fhandler/socket_inet.cc
+
+++ b/winsup/cygwin/fhandler/socket_inet.cc
+
@@ -20,7 +20,9 @@
+
#undef u_long
+
#define u_long __ms_u_long
+
#include <w32api/ws2tcpip.h>
+
+#define cmsghdr __ms_cmsghdr
+
#include <w32api/mswsock.h>
+
+#undef cmsghdr
+
#include <w32api/mstcpip.h>
+
#include <netinet/tcp.h>
+
#include <netinet/udp.h>
+
diff --git a/winsup/cygwin/fhandler/socket_local.cc b/winsup/cygwin/fhandler/socket_local.cc
+
index e4a88169b..b832d8a84 100644
+
--- a/winsup/cygwin/fhandler/socket_local.cc
+
+++ b/winsup/cygwin/fhandler/socket_local.cc
+
@@ -21,7 +21,9 @@
+
#define u_long __ms_u_long
+
#include "ntsecapi.h"
+
#include <w32api/ws2tcpip.h>
+
+#define cmsghdr __ms_cmsghdr
+
#include <w32api/mswsock.h>
+
+#undef cmsghdr
+
#include <unistd.h>
+
#include <asm/byteorder.h>
+
#include <sys/socket.h>
+
diff --git a/winsup/cygwin/local_includes/ntdll.h b/winsup/cygwin/local_includes/ntdll.h
+
index 4497fe53f..bf86a8293 100644
+
--- a/winsup/cygwin/local_includes/ntdll.h
+
+++ b/winsup/cygwin/local_includes/ntdll.h
+
@@ -489,26 +489,6 @@ typedef struct _FILE_DISPOSITION_INFORMATION_EX // 64
+
ULONG Flags;
+
} FILE_DISPOSITION_INFORMATION_EX, *PFILE_DISPOSITION_INFORMATION_EX;
+
+
-typedef struct _FILE_STAT_INFORMATION // 68
+
-{
+
- LARGE_INTEGER FileId;
+
- LARGE_INTEGER CreationTime;
+
- LARGE_INTEGER LastAccessTime;
+
- LARGE_INTEGER LastWriteTime;
+
- LARGE_INTEGER ChangeTime;
+
- LARGE_INTEGER AllocationSize;
+
- LARGE_INTEGER EndOfFile;
+
- ULONG FileAttributes;
+
- ULONG ReparseTag;
+
- ULONG NumberOfLinks;
+
- ACCESS_MASK EffectiveAccess;
+
-} FILE_STAT_INFORMATION, *PFILE_STAT_INFORMATION;
+
-
+
-typedef struct _FILE_CASE_SENSITIVE_INFORMATION // 71
+
-{
+
- ULONG Flags;
+
-} FILE_CASE_SENSITIVE_INFORMATION, *PFILE_CASE_SENSITIVE_INFORMATION;
+
-
+
enum {
+
FILE_LINK_REPLACE_IF_EXISTS = 0x01,
+
FILE_LINK_POSIX_SEMANTICS = 0x02,
+
diff --git a/winsup/cygwin/net.cc b/winsup/cygwin/net.cc
+
index 737e494f8..6a1a0d079 100644
+
--- a/winsup/cygwin/net.cc
+
+++ b/winsup/cygwin/net.cc
+
@@ -18,7 +18,9 @@ details. */
+
#undef u_long
+
#define u_long __ms_u_long
+
#include <w32api/ws2tcpip.h>
+
+#define cmsghdr __ms_cmsghdr
+
#include <w32api/mswsock.h>
+
+#undef cmsghdr
+
#include <w32api/iphlpapi.h>
+
#define gethostname cygwin_gethostname
+
#include <unistd.h>
+
--
+
2.50.1
+
+246
pkgs/os-specific/cygwin/newlib-cygwin/store-tls-pointer-in-win32-tls.patch
···
+
From f74059ffbcf53d8ff4db59ca9e7b07d58bd3e3c6 Mon Sep 17 00:00:00 2001
+
From: David McFarland <corngood@gmail.com>
+
Date: Fri, 4 Sep 2020 10:15:57 -0300
+
Subject: [PATCH] Cygwin: store tls pointer in win32 tls
+
+
Use WIN32 TLS instead of stack-relative pointers for TLS. This allows windows
+
fibers and boost coroutines to be used without crashing whenever a syscall is
+
made from a fiber.
+
+
NOTE: This should be submitted upstream, but there is a blocker first. In the
+
main branch there are conflicts with new ARM64 support. In addition to fixing
+
the conflicts, we should actually test whether ARM64 builds work too, first.
+
---
+
winsup/cygwin/create_posix_thread.cc | 2 ++
+
winsup/cygwin/cygtls.cc | 15 +++++++++++++++
+
winsup/cygwin/dcrt0.cc | 1 +
+
winsup/cygwin/fork.cc | 1 +
+
winsup/cygwin/include/cygwin/config.h | 2 +-
+
winsup/cygwin/init.cc | 12 ++++++++----
+
winsup/cygwin/local_includes/cygtls.h | 7 +++++--
+
winsup/cygwin/scripts/gendef | 15 ++++++++++-----
+
8 files changed, 43 insertions(+), 12 deletions(-)
+
+
diff --git a/winsup/cygwin/create_posix_thread.cc b/winsup/cygwin/create_posix_thread.cc
+
index 3fcd61707..85c1a8af3 100644
+
--- a/winsup/cygwin/create_posix_thread.cc
+
+++ b/winsup/cygwin/create_posix_thread.cc
+
@@ -52,6 +52,7 @@ pthread_wrapper (PVOID arg)
+
/* Set stack values in TEB */
+
PTEB teb = NtCurrentTeb ();
+
teb->Tib.StackBase = wrapper_arg.stackbase;
+
+ _set_tls();
+
teb->Tib.StackLimit = wrapper_arg.stacklimit ?: wrapper_arg.stackaddr;
+
/* Set DeallocationStack value. If we have an application-provided stack,
+
we set DeallocationStack to NULL, so NtTerminateThread does not deallocate
+
@@ -250,6 +251,7 @@ create_new_main_thread_stack (PVOID &allocationbase)
+
return NULL;
+
NtCurrentTeb()->Tib.StackBase = ((PBYTE) allocationbase + stacksize);
+
NtCurrentTeb()->Tib.StackLimit = stacklimit;
+
+ _set_tls();
+
return ((PBYTE) allocationbase + stacksize - 16);
+
}
+
+
diff --git a/winsup/cygwin/cygtls.cc b/winsup/cygwin/cygtls.cc
+
index 13d133f47..d23f9b42a 100644
+
--- a/winsup/cygwin/cygtls.cc
+
+++ b/winsup/cygwin/cygtls.cc
+
@@ -17,6 +17,20 @@ details. */
+
#include "sigproc.h"
+
#include "exception.h"
+
+
+extern DWORD cygtls_slot;
+
+
+
+void _set_tls(TEB *teb)
+
+{
+
+ TlsSetValue(cygtls_slot, teb->Tib.StackBase);
+
+}
+
+
+
+_cygtls* _current_tls()
+
+{
+
+ register void *ret;
+
+ __asm __volatile__ ("movl cygtls_slot(%%rip),%%r10d\nmovq %%gs:0x1480(,%%r10d,8),%0" : "=r" (ret) : : "r10");
+
+ return (_cygtls *) ((PBYTE) ret - __CYGTLS_PADSIZE__);
+
+}
+
+
+
/* Two calls to get the stack right... */
+
void
+
_cygtls::call (DWORD (*func) (void *, void *), void *arg)
+
@@ -25,6 +39,7 @@ _cygtls::call (DWORD (*func) (void *, void *), void *arg)
+
/* Initialize this thread's ability to respond to things like
+
SIGSEGV or SIGFPE. */
+
exception protect;
+
+ _set_tls();
+
_my_tls.call2 (func, arg, buf);
+
}
+
+
diff --git a/winsup/cygwin/dcrt0.cc b/winsup/cygwin/dcrt0.cc
+
index f4c09befd..e6ba488f2 100644
+
--- a/winsup/cygwin/dcrt0.cc
+
+++ b/winsup/cygwin/dcrt0.cc
+
@@ -462,6 +462,7 @@ child_info_fork::alloc_stack ()
+
StackBase in the child to be the same as in the parent, so that the
+
computation of _my_tls is correct. */
+
teb->Tib.StackBase = (PVOID) stackbase;
+
+ _set_tls(teb);
+
}
+
}
+
+
diff --git a/winsup/cygwin/fork.cc b/winsup/cygwin/fork.cc
+
index f88acdbbf..582f1a454 100644
+
--- a/winsup/cygwin/fork.cc
+
+++ b/winsup/cygwin/fork.cc
+
@@ -141,6 +141,7 @@ frok::child (volatile char * volatile here)
+
myself->pid, myself->ppid, __builtin_frame_address (0));
+
sigproc_printf ("hParent %p, load_dlls %d", hParent, load_dlls);
+
+
+ _set_tls();
+
/* Make sure threadinfo information is properly set up. */
+
if (&_my_tls != _main_tls)
+
{
+
diff --git a/winsup/cygwin/include/cygwin/config.h b/winsup/cygwin/include/cygwin/config.h
+
index 2a7083278..21ce484cf 100644
+
--- a/winsup/cygwin/include/cygwin/config.h
+
+++ b/winsup/cygwin/include/cygwin/config.h
+
@@ -37,7 +37,7 @@ extern inline struct _reent *__getreent (void)
+
{
+
register char *ret;
+
#ifdef __x86_64__
+
- __asm __volatile__ ("movq %%gs:8,%0" : "=r" (ret));
+
+ __asm __volatile__ ("movl cygtls_slot(%%rip),%%r10d\nmovq %%gs:0x1480(,%%r10d,8),%0" : "=r" (ret) : : "r10");
+
#else
+
#error unimplemented for this target
+
#endif
+
diff --git a/winsup/cygwin/init.cc b/winsup/cygwin/init.cc
+
index ce6484aff..392ac8600 100644
+
--- a/winsup/cygwin/init.cc
+
+++ b/winsup/cygwin/init.cc
+
@@ -11,7 +11,7 @@ details. */
+
#include "ntdll.h"
+
#include "shared_info.h"
+
+
-static DWORD _my_oldfunc;
+
+DWORD NO_COPY cygtls_slot;
+
+
static char *search_for = (char *) cygthread::stub;
+
unsigned threadfunc_ix[8];
+
@@ -22,7 +22,9 @@ static bool dll_finished_loading;
+
static void
+
threadfunc_fe (VOID *arg)
+
{
+
- _cygtls::call ((DWORD (*) (void *, void *)) TlsGetValue (_my_oldfunc), arg);
+
+ PVOID f = TlsGetValue (cygtls_slot);
+
+ _set_tls();
+
+ _cygtls::call ((DWORD (*) (void *, void *)) f, arg);
+
}
+
+
/* If possible, redirect the thread entry point to a cygwin routine which
+
@@ -59,7 +61,7 @@ munge_threadfunc ()
+
for (i = 0; threadfunc_ix[i]; i++)
+
if (!threadfunc || ebp[threadfunc_ix[i]] == threadfunc)
+
ebp[threadfunc_ix[i]] = (char *) threadfunc_fe;
+
- TlsSetValue (_my_oldfunc, threadfunc);
+
+ TlsSetValue (cygtls_slot, threadfunc);
+
}
+
}
+
}
+
@@ -78,6 +80,8 @@ dll_entry (HANDLE h, DWORD reason, void *static_load)
+
switch (reason)
+
{
+
case DLL_PROCESS_ATTACH:
+
+ cygtls_slot = TlsAlloc ();
+
+ _set_tls();
+
init_console_handler (false);
+
+
cygwin_hmodule = (HMODULE) h;
+
@@ -94,7 +98,6 @@ dll_entry (HANDLE h, DWORD reason, void *static_load)
+
memcpy (_REENT, _GLOBAL_REENT, sizeof (struct _reent));
+
+
dll_crt0_0 ();
+
- _my_oldfunc = TlsAlloc ();
+
dll_finished_loading = true;
+
break;
+
case DLL_PROCESS_DETACH:
+
@@ -102,6 +105,7 @@ dll_entry (HANDLE h, DWORD reason, void *static_load)
+
shared_destroy ();
+
break;
+
case DLL_THREAD_ATTACH:
+
+ _set_tls();
+
if (dll_finished_loading)
+
munge_threadfunc ();
+
break;
+
diff --git a/winsup/cygwin/local_includes/cygtls.h b/winsup/cygwin/local_includes/cygtls.h
+
index 306497a33..e3a216280 100644
+
--- a/winsup/cygwin/local_includes/cygtls.h
+
+++ b/winsup/cygwin/local_includes/cygtls.h
+
@@ -301,8 +301,11 @@ private:
+
#include "cygerrno.h"
+
#include "ntdll.h"
+
+
-#define _my_tls (*((_cygtls *) ((PBYTE) NtCurrentTeb()->Tib.StackBase \
+
- - __CYGTLS_PADSIZE__)))
+
+void _set_tls(TEB*);
+
+inline void _set_tls() { _set_tls(NtCurrentTeb()); }
+
+_cygtls* _current_tls();
+
+
+
+#define _my_tls (*_current_tls())
+
extern _cygtls *_main_tls;
+
extern _cygtls *_sig_tls;
+
+
diff --git a/winsup/cygwin/scripts/gendef b/winsup/cygwin/scripts/gendef
+
index 861a2405b..9a4479bd8 100755
+
--- a/winsup/cygwin/scripts/gendef
+
+++ b/winsup/cygwin/scripts/gendef
+
@@ -118,7 +118,8 @@ EOF
+
.seh_proc _sigfe_maybe
+
_sigfe_maybe: # stack is aligned on entry!
+
.seh_endprologue
+
- movq %gs:8,%r10 # location of bottom of stack
+
+ movl cygtls_slot(%rip),%r10d
+
+ movq %gs:0x1480(,%r10d,8),%r10 # location of bottom of stack
+
leaq _cygtls.initialized(%r10),%r11 # where we will be looking
+
cmpq %r11,%rsp # stack loc > than tls
+
jge 0f # yep. we don't have a tls.
+
@@ -131,7 +132,8 @@ _sigfe_maybe: # stack is aligned on entry!
+
.seh_proc _sigfe
+
_sigfe: # stack is aligned on entry!
+
.seh_endprologue
+
- movq %gs:8,%r10 # location of bottom of stack
+
+ movl cygtls_slot(%rip),%r10d
+
+ movq %gs:0x1480(,%r10d,8),%r10 # location of bottom of stack
+
1: movl \$1,%r11d
+
xchgl %r11d,_cygtls.stacklock(%r10) # try to acquire lock
+
testl %r11d,%r11d # it will be zero
+
@@ -154,7 +156,8 @@ _sigfe: # stack is aligned on entry!
+
_sigbe: # return here after cygwin syscall
+
# stack is aligned on entry!
+
.seh_endprologue
+
- movq %gs:8,%r10 # address of bottom of tls
+
+ movl cygtls_slot(%rip),%r10d
+
+ movq %gs:0x1480(,%r10d,8),%r10 # address of bottom of tls
+
1: movl \$1,%r11d
+
xchgl %r11d,_cygtls.stacklock(%r10) # try to acquire lock
+
testl %r11d,%r11d # it will be zero
+
@@ -249,7 +252,8 @@ sigdelayed:
+
2:
+
.seh_endprologue
+
+
- movq %gs:8,%r12 # get tls
+
+ movl cygtls_slot(%rip),%r12d
+
+ movq %gs:0x1480(,%r12d,8),%r12 # get tls
+
movl _cygtls.saved_errno(%r12),%r15d # temporarily save saved_errno
+
movq \$_cygtls.start_offset,%rcx # point to beginning of tls block
+
addq %r12,%rcx # and store as first arg to method
+
@@ -316,7 +320,8 @@ stabilize_sig_stack:
+
subq \$0x20,%rsp
+
.seh_stackalloc 32
+
.seh_endprologue
+
- movq %gs:8,%r12
+
+ movl cygtls_slot(%rip),%r12d
+
+ movq %gs:0x1480(,%r12d,8),%r12
+
1: movl \$1,%r10d
+
xchgl %r10d,_cygtls.stacklock(%r12) # try to acquire lock
+
testl %r10d,%r10d
+
--
+
2.50.1
+
+62
pkgs/os-specific/cygwin/w32api/default.nix
···
+
{
+
lib,
+
stdenvNoCC,
+
stdenvNoLibc,
+
autoreconfHook,
+
windows,
+
+
headersOnly ? false,
+
}:
+
+
(if headersOnly then stdenvNoCC else stdenvNoLibc).mkDerivation (
+
{
+
pname = "w32api${lib.optionalString headersOnly "-headers"}";
+
+
inherit (windows.mingw_w64_headers)
+
version
+
src
+
;
+
+
outputs = [
+
"out"
+
]
+
++ lib.optional (!headersOnly) "dev";
+
+
configureFlags = [ (lib.enableFeature true "w32api") ];
+
+
enableParallelBuilding = true;
+
+
passthru = {
+
incdir = "/include/w32api/";
+
libdir = "/lib/w32api/";
+
};
+
+
meta = {
+
description = "MinGW w32api package for Cygwin";
+
inherit (windows.mingw_w64_headers.meta)
+
homepage
+
downloadPage
+
license
+
;
+
platforms = lib.platforms.unix ++ lib.platforms.windows;
+
teams = [ lib.maintainers.corngood ];
+
};
+
}
+
// (
+
if headersOnly then
+
{
+
preConfigure = ''
+
cd mingw-w64-headers
+
'';
+
}
+
else
+
{
+
nativeBuildInputs = [ autoreconfHook ];
+
+
hardeningDisable = [
+
"stackprotector"
+
"fortify"
+
];
+
}
+
)
+
)
+1
pkgs/os-specific/windows/default.nix
···
newScope,
overrideCC,
stdenvNoLibc,
+
emptyDirectory,
}:
lib.makeScope newScope (
+18
pkgs/stdenv/generic/make-derivation.nix
···
"disallowedRequisites"
"allowedReferences"
"allowedRequisites"
+
"allowedImpureDLLs"
];
inherit (stdenv)
···
isLinux
isDarwin
isWindows
+
isCygwin
isOpenBSD
isStatic
isMusl
···
sandboxProfile ? "",
propagatedSandboxProfile ? "",
+
allowedImpureDLLs ? [ ],
+
hardeningEnable ? [ ],
hardeningDisable ? [ ],
···
nativeBuildInputs
++ optional separateDebugInfo' ../../build-support/setup-hooks/separate-debug-info.sh
++ optional isWindows ../../build-support/setup-hooks/win-dll-link.sh
+
++ optional isCygwin ../../build-support/setup-hooks/cygwin-dll-link.sh
++ optionals doCheck nativeCheckInputs
++ optionals doInstallCheck nativeInstallCheckInputs;
···
"/bin/sh"
];
__propagatedImpureHostDeps = computedPropagatedImpureHostDeps ++ __propagatedImpureHostDeps;
+
}
+
)
+
// optionalAttrs (isWindows || isCygwin) (
+
let
+
dlls =
+
allowedImpureDLLs
+
++ lib.optionals isCygwin [
+
"KERNEL32.dll"
+
"cygwin1.dll"
+
];
+
in
+
{
+
allowedImpureDLLs = if dlls != [ ] then dlls else null;
}
)
// (
+8 -1
pkgs/top-level/all-packages.nix
···
isl = if !stdenv.hostPlatform.isDarwin then isl_0_20 else null;
withoutTargetLibc = true;
-
langCC = false;
+
langCC = stdenv.targetPlatform.isCygwin; # can't compile libcygwin1.a without C++
libcCross = libc1;
targetPackages.stdenv.cc.bintools = binutilsNoLibc;
enableShared =
···
# temporarily disabled due to breakage;
# see https://github.com/NixOS/nixpkgs/pull/243249
&& !stdenv.targetPlatform.isWindows
+
&& !stdenv.targetPlatform.isCygwin
&& !(stdenv.targetPlatform.useLLVM or false);
};
bintools = binutilsNoLibc;
···
windows.mingw_w64_headers or fallback
else if libc == "nblibc" then
netbsd.headers
+
else if libc == "cygwin" then
+
cygwin.newlib-cygwin-headers
else
null;
···
if stdenv.hostPlatform.isMinGW then windows.mingw_w64 else windows.sdk
else if libc == "ucrt" then
if stdenv.hostPlatform.isMinGW then windows.mingw_w64 else windows.sdk
+
else if libc == "cygwin" then
+
cygwin.newlib-cygwin-nobin
else if libc == "libSystem" then
if stdenv.hostPlatform.useiOSPrebuilt then darwin.iosSdkPkgs.libraries else darwin.libSystem
else if libc == "fblibc" then
···
v4l-utils = callPackage ../os-specific/linux/v4l-utils { };
windows = recurseIntoAttrs (callPackages ../os-specific/windows { });
+
+
cygwin = recurseIntoAttrs (callPackages ../os-specific/cygwin { });
wpa_supplicant = callPackage ../os-specific/linux/wpa_supplicant { };
+6
pkgs/top-level/release-cross.nix
···
windows.pthreads = nativePlatforms;
};
+
cygwinCommon = {
+
hello = nativePlatforms;
+
};
+
wasiCommon = {
gmp = nativePlatforms;
boehmgc = nativePlatforms;
···
# Test some cross builds on 64 bit mingw-w64
crossMingwW64 = mapTestOnCross systems.examples.mingwW64 windowsCommon;
+
+
x86_64-cygwin = mapTestOnCross systems.examples.x86_64-cygwin cygwinCommon;
# Linux on mipsel
fuloongminipc = mapTestOnCross systems.examples.fuloongminipc linuxCommon;