Hi, Continuing a discussion started over at [1]. Moving this to a new thread so that other thread can focus on Unix cleanup, and both threads can get CI coverage...
1. In a few places, it is alleged that both __CYGWIN__ and WIN32 might be defined at the same time. Do you think we should try to get rid of that possibility? I understand that we have to have a few tests for __CYGWIN__ here and there, because eg file permissions don't work quite right and there's not much we can do about that. But it seems a bit unhelpful if we also have to worry about a more-or-less POSIX-ish build taking WIN32 paths at uncertain times if we forget to defend against that, or wonder why some places are not consistent. A quick recap of the three flavours of Windows platform we have to handle, as I understand it: * MSVC: Windowsy toolchain, Windowsy C * custom perl scripts instead of configure * msbuild instead of make * MSVC compiler * Windows C APIs * we provide our own emulation of some POSIX C APIs on top * MSYS: Unixy toolchain, Windowsy C * configure (portname = "win32") * make * GCC compiler * Windows C APIs * we provide our own emulation of some POSIX C APIs on top * Cygwin: Unixy toolchain, Unixy C * configure (portname = "cygwin") * make * GCC compiler * POSIX C APIs (emulations provided by the Cygwin runtime libraries) (The configure/make part will be harmonised by the Meson project.) The macro WIN32 is visibly defined by something in/near msbuild in MSVC builds: /D WIN32 is right here in the build transcripts (whereas the compiler defines _WIN32; good compiler). I am not sure how exactly it is first defined in MSYS builds; I suspect that MSYS gcc might define it itself, but I don't have access to MSYS to check. As for Cygwin, the only translation unit where I could find both __CYGWIN__ and WIN32 defined is dirmod.c, and that results from including <windows.h> and ultimately <minwindef.h> (even though WIN32 isn't defined yet at that time). I couldn't understand why we do that, but I probably didn't read enough commit history. The purpose of dirmod.c on Cygwin today is only to wrap otherwise pure POSIX code in retry loops to handle those spurious EACCES errors due to NT sharing violations, so there is no need for that. Proposal: let's make it a programming rule that we don't allow definitions from Windows headers to leak into Cygwin translation units, preferably by never including them, or if we really must, let's grant specific exemptions in an isolated and well documented way. We don't seem to need any such exemptions currently. Places where we currently worry about the contradictory macros could become conditional #error directives instead. 2. To make it possible to test any of that, you either need a working Windows+Cygwin setup, or working CI. I'm a salty old Unix hacker so I opted for the latter, and I also hope this will eventually be useful to others. Unfortunately I haven't figured out how to get everything working yet, so some of the check-world tests are failing. Clues most welcome! The version I'm posting here is set to run always, so that cfbot will show it alongside others. But I would imagine that if we got a committable-quality version of this, it'd probably be opt-in, so you'd have to say "ci-os-only: cygwin", or "ci-os-only: cygwin, windows" etc in a commit to your private github account to ask for it (or maybe we'll come up with a way to tell cfbot we want the full works of CI checks; the same decision will come up for MSYS, OpenBSD and NetBSD CI support that my colleague is working on). There are other things to fix too, including abysmal performance; see commit message. 3. You can't really run PostgreSQL on Cygwin for real, because its implementation of signals does not have reliable signal masking, so unsubtle and probably also subtle breakage occurs. That was reported upstream by Noah years ago, but they aren't working on a fix. lorikeet shows random failures, and presumably any CI system will do the same... I even wondered about putting our own magic entry/exit macros into signal handlers, that would use atomics to implement a second level of signal masking (?!) but that's an uncommonly large bandaid for a defective platform... and trying to fix Cygwin itself is a rabbithole too far for me. 4. When building with Cygwin GCC 11.3 you get a bunch of warnings that don't show up on other platforms, seemingly indicating that it interprets -Wimplicit-fallthrough=3 differently. Huh? [1] https://www.postgresql.org/message-id/CA%2BhUKGKZ_FjkBnjGADk%2Bpa2g4oKDcG8%3DSE5V23sPTP0EELfyzQ%40mail.gmail.com
From 8f300f5b804d5fd2268709d40e31b52c86d6799c Mon Sep 17 00:00:00 2001 From: Thomas Munro <thomas.mu...@gmail.com> Date: Mon, 25 Jul 2022 23:05:10 +1200 Subject: [PATCH 1/2] WIP CI support for Cygwin. XXX Doesn't get all the way through yet... XXX Needs some --with-X options XXX This should use a canned Docker image with all the right packages installed XXX We would never want this to run by default in CI, but it'd be nice to be able to ask for it with ci-os-only! (See commented out line) XXX configure is soooo slooow, can we cache it?! Compiling is also insanely slow, but ccache gets it down to a couple of minutes if you're lucky XXX I don't know how to put variables like BUILD_JOBS into the scripts XXX I have no idea if crash dump works, and if this should share elements with the msys work in commitfest #3575 --- .cirrus.yml | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/.cirrus.yml b/.cirrus.yml index f23d6cae55..b5238f5f52 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -456,6 +456,57 @@ task: path: "crashlog-*.txt" type: text/plain +task: + name: Windows - Cygwin + + env: + CPUS: 4 + BUILD_JOBS: 4 + TEST_JOBS: 8 + + #only_if: $CIRRUS_CHANGE_MESSAGE =~ '.*\nci-os-only:[^\n]*cygwin.*' + + windows_container: + image: cirrusci/windowsservercore:2019 + os_version: 2019 + cpu: $CPUS + memory: 4G + + ccache_cache: + folder: C:\tools\cygwin\tmp\ccache + + sysinfo_script: | + chcp + systeminfo + powershell -Command get-psdrive -psprovider filesystem + set + + setup_additional_packages_script: | + choco install -y --no-progress cygwin + C:\tools\cygwin\cygwinsetup.exe -q -P cygrunsrv,make,gcc-core,ccache,binutils,libtool,pkg-config,flex,bison,zlib-devel,libssl-devel,libreadline-devel,perl,perl-IPC-Run + C:\tools\cygwin\bin\bash.exe --login -c "cygserver-config -y" || EXIT /b 1 + C:\tools\cygwin\bin\bash.exe --login -c "echo 'kern.ipc.semmni 1024' >> /etc/cygserver.conf" || EXIT /b 1 + C:\tools\cygwin\bin\bash.exe --login -c "echo 'kern.ipc.semmns 1024' >> /etc/cygserver.conf" || EXIT /b 1 + C:\tools\cygwin\bin\bash.exe --login -c "net start cygserver" || EXIT /b 1 + + configure_script: + - C:\tools\cygwin\bin\bash.exe --login -c "cd '%cd%' && CCACHE_DIR=/tmp/ccache ./configure --enable-cassert --enable-debug --enable-tap-tests CC='ccache gcc'" || EXIT /b 1 + + build_script: + - C:\tools\cygwin\bin\bash.exe --login -c "cd '%cd%' && CCACHE_DIR=/tmp/ccache make -s -j4 world-bin" || EXIT /b 1 + + test_world_script: + - C:\tools\cygwin\bin\bash.exe --login -c "cd '%cd%' && CCACHE_DIR=/tmp/ccache make -s -j1 check-world -Otarget" || EXIT /b 1 + + on_failure: + <<: *on_failure + crashlog_artifacts: + path: "crashlog-*.txt" + type: text/plain + + always: + upload_caches: ccache + task: name: CompilerWarnings -- 2.35.1
From ea47a8af0332876629b53620788d40bcb7b1e96c Mon Sep 17 00:00:00 2001 From: Thomas Munro <thomas.mu...@gmail.com> Date: Tue, 26 Jul 2022 12:56:06 +1200 Subject: [PATCH 2/2] WIP Do not pollute Cygwin namespace with Windows headers. Establish that __CYGWIN__ and WIN32 should generally not be defined at the same time. If ever it's necessary to access Windows APIs directly when building for Cygwin, that should be done in an extremely localized way, not allowing Windows macros and declarations to leak into other translation units. dirmod.c initially looked like a potential case for a localized exemption, but on closer inspection it doesn't currently have any reason to include <windows.h> -- so don't. In passing, remove anachronistic comments about ancient Windows versions. --- src/include/pg_config_manual.h | 2 +- src/include/port.h | 17 +++++++------ src/port/dirmod.c | 46 +++++++++++++++++----------------- 3 files changed, 33 insertions(+), 32 deletions(-) diff --git a/src/include/pg_config_manual.h b/src/include/pg_config_manual.h index 5ee2c46267..0d1d5d7c9b 100644 --- a/src/include/pg_config_manual.h +++ b/src/include/pg_config_manual.h @@ -148,7 +148,7 @@ * fork()). On other platforms, it's only useful for verifying those * otherwise Windows-specific code paths. */ -#if defined(WIN32) && !defined(__CYGWIN__) +#if defined(WIN32) #define EXEC_BACKEND #endif diff --git a/src/include/port.h b/src/include/port.h index d39b04141f..8cf1112a54 100644 --- a/src/include/port.h +++ b/src/include/port.h @@ -18,10 +18,12 @@ /* * Windows has enough specialized port stuff that we push most of it off * into another file. - * Note: Some CYGWIN includes might #define WIN32. */ -#if defined(WIN32) && !defined(__CYGWIN__) +#if defined(WIN32) #include "port/win32_port.h" +#if defined(__CYGWIN__) +#error "__CYGWIN__ should not be defined at the same time as WIN32" +#endif #endif /* socket has a different definition on WIN32 */ @@ -150,7 +152,7 @@ extern int pg_disable_aslr(void); #define EXE "" #endif -#if defined(WIN32) && !defined(__CYGWIN__) +#if defined(WIN32) #define DEVNULL "nul" #else #define DEVNULL "/dev/null" @@ -276,12 +278,11 @@ extern int pgunlink(const char *path); * Win32 also doesn't have symlinks, but we can emulate them with * junction points on newer Win32 versions. * - * Cygwin has its own symlinks which work on Win95/98/ME where - * junction points don't, so use those instead. We have no way of - * knowing what type of system Cygwin binaries will be run on. - * Note: Some CYGWIN includes might #define WIN32. + * Cygwin has its own symlinks that work where junction points don't, so use + * those instead. We have no way of knowing what type of system Cygwin + * binaries will be run on. */ -#if defined(WIN32) && !defined(__CYGWIN__) +#if defined(WIN32) extern int pgsymlink(const char *oldpath, const char *newpath); extern int pgreadlink(const char *path, char *buf, size_t size); extern bool pgwin32_is_junction(const char *path); diff --git a/src/port/dirmod.c b/src/port/dirmod.c index 7ce042e75d..1bfbead098 100644 --- a/src/port/dirmod.c +++ b/src/port/dirmod.c @@ -6,8 +6,10 @@ * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * This includes replacement versions of functions that work on - * Win32 (NT4 and newer). + * This includes replacement versions of functions that work on Windows. + * For Cygwin, the purpose of these replacements is to provide retry loops + * around POSIX functions. For native Windows, we also redirect to + * native Windows APIs. * * IDENTIFICATION * src/port/dirmod.c @@ -21,25 +23,24 @@ #include "postgres_fe.h" #endif +#if defined(WIN32) && defined(__CYGWIN__) +#error "WIN32 should not be defined at the same time as __CYGWIN__" +#endif + +#if !defined(WIN32) && !defined(__CYGWIN__) +#error "one of WIN32 or __CYGWIN__ is expected" +#endif + /* Don't modify declarations in system headers */ -#if defined(WIN32) || defined(__CYGWIN__) #undef rename #undef unlink -#endif #include <unistd.h> #include <sys/stat.h> -#if defined(WIN32) || defined(__CYGWIN__) -#ifndef __CYGWIN__ +#if defined(WIN32) #include <winioctl.h> -#else -#include <windows.h> -#include <w32api/winioctl.h> #endif -#endif - -#if defined(WIN32) || defined(__CYGWIN__) /* * pgrename @@ -56,24 +57,24 @@ pgrename(const char *from, const char *to) * someone else to close the file, as the caller might be holding locks * and blocking other backends. */ -#if defined(WIN32) && !defined(__CYGWIN__) +#if defined(WIN32) while (!MoveFileEx(from, to, MOVEFILE_REPLACE_EXISTING)) #else while (rename(from, to) < 0) #endif { -#if defined(WIN32) && !defined(__CYGWIN__) +#if defined(WIN32) DWORD err = GetLastError(); _dosmaperr(err); /* - * Modern NT-based Windows versions return ERROR_SHARING_VIOLATION if - * another process has the file open without FILE_SHARE_DELETE. - * ERROR_LOCK_VIOLATION has also been seen with some anti-virus - * software. This used to check for just ERROR_ACCESS_DENIED, so - * presumably you can get that too with some OS versions. We don't - * expect real permission errors where we currently use rename(). + * Windows returns ERROR_SHARING_VIOLATION if another process has the + * file open without FILE_SHARE_DELETE. ERROR_LOCK_VIOLATION has also + * been seen with some anti-virus software. This used to check for + * just ERROR_ACCESS_DENIED, so presumably you can get that too with + * some OS versions. We don't expect real permission errors where we + * currently use rename(). */ if (err != ERROR_ACCESS_DENIED && err != ERROR_SHARING_VIOLATION && @@ -121,10 +122,9 @@ pgunlink(const char *path) /* We undefined these above; now redefine for possible use below */ #define rename(from, to) pgrename(from, to) #define unlink(path) pgunlink(path) -#endif /* defined(WIN32) || defined(__CYGWIN__) */ -#if defined(WIN32) && !defined(__CYGWIN__) /* Cygwin has its own symlinks */ +#if defined(WIN32) /* * pgsymlink support: @@ -352,4 +352,4 @@ pgwin32_is_junction(const char *path) } return ((attr & FILE_ATTRIBUTE_REPARSE_POINT) == FILE_ATTRIBUTE_REPARSE_POINT); } -#endif /* defined(WIN32) && !defined(__CYGWIN__) */ +#endif /* defined(WIN32) */ -- 2.35.1