bpo-21536: On Cygwin, C extensions must be linked with libpython (GH-13549)

It is also possible to link against a library or executable with a
statically linked libpython, but not both with the same DLL.  In fact
building a statically linked python is currently broken on Cygwin
for other (related) reasons.

The same problem applies to other POSIX-like layers over Windows
(MinGW, MSYS) but Python's build system does not seem to attempt
to support those platforms at the moment.
diff --git a/Doc/distutils/apiref.rst b/Doc/distutils/apiref.rst
index cbeedab..2601d30 100644
--- a/Doc/distutils/apiref.rst
+++ b/Doc/distutils/apiref.rst
@@ -290,7 +290,7 @@
    .. versionchanged:: 3.8
 
       On Unix, C extensions are no longer linked to libpython except on
-      Android.
+      Android and Cygwin.
 
 
 .. class:: Distribution
diff --git a/Doc/whatsnew/3.8.rst b/Doc/whatsnew/3.8.rst
index b91f7bc..b5d70b5 100644
--- a/Doc/whatsnew/3.8.rst
+++ b/Doc/whatsnew/3.8.rst
@@ -138,7 +138,8 @@
 build option.
 (Contributed by Victor Stinner in :issue:`36465`.)
 
-On Unix, C extensions are no longer linked to libpython except on Android.
+On Unix, C extensions are no longer linked to libpython except on Android
+and Cygwin.
 It is now possible
 for a statically linked Python to load a C extension built using a shared
 library Python.
@@ -163,8 +164,8 @@
 
 On the other hand, ``pkg-config python3.8 --libs`` no longer contains
 ``-lpython3.8``. C extensions must not be linked to libpython (except on
-Android, case handled by the script); this change is backward incompatible on
-purpose.
+Android and Cygwin, whose cases are handled by the script);
+this change is backward incompatible on purpose.
 (Contributed by Victor Stinner in :issue:`36721`.)
 
 f-strings now support =  for quick and easy debugging
@@ -1061,12 +1062,12 @@
   instead.
   (Contributed by Victor Stinner in :issue:`36728`.)
 
-* On Unix, C extensions are no longer linked to libpython except on
-  Android. When Python is embedded, ``libpython`` must not be loaded with
+* On Unix, C extensions are no longer linked to libpython except on Android
+  and Cygwin. When Python is embedded, ``libpython`` must not be loaded with
   ``RTLD_LOCAL``, but ``RTLD_GLOBAL`` instead. Previously, using
-  ``RTLD_LOCAL``, it was already not possible to load C extensions which were
-  not linked to ``libpython``, like C extensions of the standard library built
-  by the ``*shared*`` section of ``Modules/Setup``.
+  ``RTLD_LOCAL``, it was already not possible to load C extensions which
+  were not linked to ``libpython``, like C extensions of the standard
+  library built by the ``*shared*`` section of ``Modules/Setup``.
 
 * Use of ``#`` variants of formats in parsing or building value (e.g.
   :c:func:`PyArg_ParseTuple`, :c:func:`Py_BuildValue`, :c:func:`PyObject_CallFunction`,
diff --git a/Lib/distutils/command/build_ext.py b/Lib/distutils/command/build_ext.py
index c3b9602..2d7cdf0 100644
--- a/Lib/distutils/command/build_ext.py
+++ b/Lib/distutils/command/build_ext.py
@@ -714,20 +714,32 @@
                 # don't extend ext.libraries, it may be shared with other
                 # extensions, it is a reference to the original list
                 return ext.libraries + [pythonlib]
-        # On Android only the main executable and LD_PRELOADs are considered
-        # to be RTLD_GLOBAL, all the dependencies of the main executable
-        # remain RTLD_LOCAL and so the shared libraries must be linked with
-        # libpython when python is built with a shared python library (issue
-        # bpo-21536).
         else:
+            # On Android only the main executable and LD_PRELOADs are considered
+            # to be RTLD_GLOBAL, all the dependencies of the main executable
+            # remain RTLD_LOCAL and so the shared libraries must be linked with
+            # libpython when python is built with a shared python library (issue
+            # bpo-21536).
+            # On Cygwin (and if required, other POSIX-like platforms based on
+            # Windows like MinGW) it is simply necessary that all symbols in
+            # shared libraries are resolved at link time.
             from distutils.sysconfig import get_config_var
+            link_libpython = False
             if get_config_var('Py_ENABLE_SHARED'):
-                # Either a native build on an Android device or the
-                # cross-compilation of Python.
-                if (hasattr(sys, 'getandroidapilevel') or
-                        ('_PYTHON_HOST_PLATFORM' in os.environ and
-                         get_config_var('ANDROID_API_LEVEL') != 0)):
-                    ldversion = get_config_var('LDVERSION')
-                    return ext.libraries + ['python' + ldversion]
+                # A native build on an Android device or on Cygwin
+                if hasattr(sys, 'getandroidapilevel'):
+                    link_libpython = True
+                elif sys.platform == 'cygwin':
+                    link_libpython = True
+                elif '_PYTHON_HOST_PLATFORM' in os.environ:
+                    # We are cross-compiling for one of the relevant platforms
+                    if get_config_var('ANDROID_API_LEVEL') != 0:
+                        link_libpython = True
+                    elif get_config_var('MACHDEP') == 'cygwin':
+                        link_libpython = True
+
+            if link_libpython:
+                ldversion = get_config_var('LDVERSION')
+                return ext.libraries + ['python' + ldversion]
 
         return ext.libraries
diff --git a/Misc/NEWS.d/3.8.0a4.rst b/Misc/NEWS.d/3.8.0a4.rst
index b92e60a..80e01d9 100644
--- a/Misc/NEWS.d/3.8.0a4.rst
+++ b/Misc/NEWS.d/3.8.0a4.rst
@@ -1052,7 +1052,8 @@
 .. nonce: ACQkiC
 .. section: Build
 
-On Unix, C extensions are no longer linked to libpython except on Android.
+On Unix, C extensions are no longer linked to libpython except on Android
+and Cygwin.
 
 It is now possible for a statically linked Python to load a C extension
 built using a shared library Python.
diff --git a/configure b/configure
index 9f2007f..c76eb7a 100755
--- a/configure
+++ b/configure
@@ -15129,9 +15129,9 @@
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LDVERSION" >&5
 $as_echo "$LDVERSION" >&6; }
 
-# On Android the shared libraries must be linked with libpython.
+# On Android and Cygwin the shared libraries must be linked with libpython.
 
-if test -z "$ANDROID_API_LEVEL"; then
+if test -z "$ANDROID_API_LEVEL" -o "$MACHDEP" != "cygwin"; then
   LIBPYTHON=''
 else
   LIBPYTHON="-lpython${VERSION}${ABIFLAGS}"
diff --git a/configure.ac b/configure.ac
index 0baf0d6..99d99ae 100644
--- a/configure.ac
+++ b/configure.ac
@@ -4620,9 +4620,9 @@
 LDVERSION='$(VERSION)$(ABIFLAGS)'
 AC_MSG_RESULT($LDVERSION)
 
-# On Android the shared libraries must be linked with libpython.
+# On Android and Cygwin the shared libraries must be linked with libpython.
 AC_SUBST(LIBPYTHON)
-if test -z "$ANDROID_API_LEVEL"; then
+if test -z "$ANDROID_API_LEVEL" -o "$MACHDEP" != "cygwin"; then
   LIBPYTHON=''
 else
   LIBPYTHON="-lpython${VERSION}${ABIFLAGS}"