Problem with _socket und pyexpat on Cygwin

Why compiling CPython 3.13.7 myself

I am compiling Python myself, because:

  1. For some calculation I need scipy, numpy and matplotlib.
  2. I am bound to Windows here, but I can use Cygwin. I am using matplotlib with LaTeX, installed in Cygwin.
  3. There is no Cygwin package for scipy.
  4. A self-built scipy uses numpy-2.x.
  5. The matplotlib package of Cygwin is built against numpy 1.x.
  6. When building matplotib myself, the latest GCC 13 is used, but Cygwin’s Python 3.9 is GCC-11-compiled, leading to trouble with pybind11.

I’d like to have a fully functional, recent Python stack in Cygwin.

So I decided to build my whole Python environment myself, with full control in all details.

Dependencies

Software Package(s)
gdb gdb 14.2-1
lzma lzma-devel, liblzma5 5.8.1-1
glibc not supported for Cygwin
libstdc++ libstdc++6 13.4.0-1
openssl openssl, libssl3, libssl-devel 3.0.17-1
readline libreadline8, libreadline-devel 8.3-1
zlib zlib, zlib-devel 1.3.1-1
libzstd libzstd1, libzstd-devel 1.5.7-1
libffi libffi8, libffi-devel 3.4.7-1
bzip2 bzip2, libbz2-devel 1.0.8-1
xz xz 5.8.1-1 (no -devel package)
sqlite libsqlite3_0, sqlite3, libsqlite3-devel 3.49.1-1
libuuid libuuid1, libuuid-devel 2.40.2-2
gdbm libgdbm6, gdbm, libgdbm-devel 1.24-1
perf Bound to the Linux kernel
expat libexpat1, libexpat-devel, expat 2.6.4-1
mpdecimal mpdecimal-4.0.1 home brewn
Tcl/Tk tcl, tcl-devel, tcl-tk, tcl-tk-devel 8.6.12-1
X11 libX11-devel 1.8.10-1; libXext-devel 1.3.6-1; libXft-devel 2.3.7-1; libXrender-devel 0.9.12-1
Sockets libgcrypt-devel 1.11.2-1; libnsl-devel, libnsl2 1.2.0-1

/usr/local/

I compiled libmpdec myself and installed it to /usr/local, so I’ve set

export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig

such that pkg-config can find it.

Compiling CPython 3.13.7

After installing the abovementioned libraries, only two errors remain in the make step:

[ERROR] _asyncio failed to import: No module named '_socket'
[ERROR] _elementtree failed to import: No module named 'pyexpat'
Following modules built successfully but were removed because they could not be imported:
_asyncio                  _elementtree

_socket

The _socket module exists and looks healthy. It remains to me as a pure miracle why it cannot be imported. cygcheck as well as ldd provide output looking sensible, as follows:

$ cygcheck Modules/_socket.cpython-313.dll

N:\Vollzugriff\Builds\2025\CPython\Python-3.13.7\Modules\_socket.cpython-313.dll
  N:\Vollzugriff\Builds\2025\CPython\Python-3.13.7\libpython3.13.dll
    N:\Vollzugriff\Programme\Cygwin\bin\cygwin1.dll
      C:\WINDOWS\system32\KERNEL32.dll
        C:\WINDOWS\system32\ntdll.dll
        C:\WINDOWS\system32\KERNELBASE.dll
    N:\Vollzugriff\Programme\Cygwin\bin\cygintl-8.dll
      N:\Vollzugriff\Programme\Cygwin\bin\cygiconv-2.dll
    N:\Vollzugriff\Programme\Cygwin\bin\cyggcc_s-seh-1.dll

$ ldd Modules/_socket.cpython-313.dll

	ntdll.dll => /cygdrive/c/WINDOWS/SYSTEM32/ntdll.dll (0x7ffe9bf50000)
	KERNEL32.DLL => /cygdrive/c/WINDOWS/System32/KERNEL32.DLL (0x7ffe9b700000)
	KERNELBASE.dll => /cygdrive/c/WINDOWS/System32/KERNELBASE.dll (0x7ffe998b0000)
	msvcrt.dll => /cygdrive/c/WINDOWS/System32/msvcrt.dll (0x7ffe9a8e0000)
	libpython3.13.dll => /home/Friedrich/N/Builds/2025/CPython/Python-3.13.7/libpython3.13.dll (0x4426d0000)
	cygwin1.dll => /usr/bin/cygwin1.dll (0x7ffe352c0000)
	cygintl-8.dll => /usr/bin/cygintl-8.dll (0x5ee2d0000)
	cyggcc_s-seh-1.dll => /usr/bin/cyggcc_s-seh-1.dll (0x50caa0000)
	cygiconv-2.dll => /usr/bin/cygiconv-2.dll (0x3ff670000)
	advapi32.dll => /cygdrive/c/WINDOWS/System32/advapi32.dll (0x7ffe9ba70000)
	sechost.dll => /cygdrive/c/WINDOWS/System32/sechost.dll (0x7ffe9b230000)
	RPCRT4.dll => /cygdrive/c/WINDOWS/System32/RPCRT4.dll (0x7ffe9bdf0000)
	bcrypt.dll => /cygdrive/c/WINDOWS/System32/bcrypt.dll (0x7ffe99ea0000)
	CRYPTBASE.DLL => /cygdrive/c/WINDOWS/SYSTEM32/CRYPTBASE.DLL (0x7ffe98f90000)
	bcryptPrimitives.dll => /cygdrive/c/WINDOWS/System32/bcryptPrimitives.dll (0x7ffe99cb0000)

pyexpat

I consider the following ./configure snippet as relevant:

configure:14403: checking for --with-system-expat
configure:14415: result: no

As like for _socket, the module exists and looks good; the $ cygcheck and $ ldd calls look very similar to the ones provided for _socket.

It looks to me like if the expat library wasn’t found. It lives in /usr/lib/, and pkg-config knows it. I’ve been told that Python uses some “predefined” expat in case that it isn’t found as an external library. This would explain that the pyexpat module was built, even when the external library wasn’t found.

Summary

The Python dependencies look good. The make call for CPython 3.13.7 almost succeeds, with only _socket and pyexpat leading to problems. These are Python extension modules, are succesfully built and “look healthy”.

It is beyond my capacity to understand what is going wrong here. So any pointer would be greatly appreciated.

Summary

To maybe diagnose the problem, but mostly in order to get a functional, at least semi-recent Python interpreter, I stepped back to Python 3.12 and 3.11 today.

Here are my findings.

With my current Python3.11 used here, which I succeeded to make install, I am not even able to import math:

>>> import math
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ModuleNotFoundError: No module named 'math'

Finally, some checks have been recommended to me:

>>> import sys
>>> sys.path
['', '/usr/local/lib/python311.zip', '/usr/local/lib/python3.11', '/usr/local/lib/python3.11/lib-dynload', '/usr/local/lib/python3.11/site-packages']

>>> import importlib.machinery
>>> print(importlib.machinery.EXTENSION_SUFFIXES)
['.dll']

>>> import sysconfig
>>> sysconfig.get_config_var("SOABI")
'cpython-311'

The path and the "SOABI" value are correct, but importlib.machinery.EXTENSION_SUFFIXES is not.

All built-in extension modules are located in /usr/local/lib/python3.11/lib-dynload/. Those files in /usr/local/lib/python3.11/lib-dynload/ are named, e.g.:

math.cpython-311.dll

But importlib.machinery.EXTENSION_SUFFIXES contains only '.dll', not '.cpython-311.dll'. Because of this, python3.11 cannot locate the math extension module, and completes processing >>> import math with:

ModuleNotFoundError: No module named 'math'

Notice, that the error is not ImportError: DLL load failed or comparable.

Now, when I copy math.cpython-311.dll to math.dll (still in /usr/local/lib/python3.11/lib-dynload/), math becomes importable:

>>> import math
>>>

Relevant material

I am providing here supplemental logs which might be of relevance to the reader.

Failure in make for Python 3.12

I tried to compile Python 3.12, which failed with the message:

gcc -L/home/Friedrich/N/Builds/2025/CPython/Python-3.12.11     -o Programs/_testembed Programs/_testembed.o libpython3.12.dll.a -lintl -ldl                         -lm
sed -e "s,/usr/bin/env python3,/usr/local/bin/python3.12," < ./Tools/scripts/2to3 > build/scripts-3.12/2to3-3.12
sed -e "s,/usr/bin/env python3,/usr/local/bin/python3.12," < ./Tools/scripts/idle3 > build/scripts-3.12/idle3.12
sed -e "s,/usr/bin/env python3,/usr/local/bin/python3.12," < ./Tools/scripts/pydoc3 > build/scripts-3.12/pydoc3.12
sed -e "s,@EXENAME@,/usr/local/bin/python3.12," < ./Misc/python-config.in >python-config.py
LC_ALL=C sed -e 's,\$(\([A-Za-z0-9_]*\)),\$\{\1\},g' < Misc/python-config.sh >python-config
Traceback (most recent call last):
  File "/home/Friedrich/N/Builds/2025/CPython/Python-3.12.11/./Tools/build/check_extension_modules.py", line 25, in <module>
    import pathlib
  File "/home/Friedrich/N/Builds/2025/CPython/Python-3.12.11/Lib/pathlib.py", line 20, in <module>
    from urllib.parse import quote_from_bytes as urlquote_from_bytes
  File "/home/Friedrich/N/Builds/2025/CPython/Python-3.12.11/Lib/urllib/parse.py", line 36, in <module>
    import math
ModuleNotFoundError: No module named 'math'
make: *** [Makefile:1152: checksharedmods] Error 1

The ultimate failure is here:

ModuleNotFoundError: No module named 'math'

Which might be comparable to the attempt above with math.

Notice

I used here for configuration

LDFLAGS=-L$(pwd) ./configure --prefix /usr/local --with-system-expat

where $(pwd) amounts to /home/Friedrich/N/Builds/2025/CPython/Python-3.12.11. Without this, linking issues appeared, AFAIR related to the main libpython3.12.dll, which is located top in the build directory.

Attempting to install Python 3.12

I was told that testing the modules “in-tree” might fail, and I should just install the Python and then run $ python3.12 -m test. However, I obtain in (python3.12) $ make install:

Log origin directory: /home/Friedrich/N/Builds
Relative cwd: ./2025/CPython/Python-3.12.11
Command: make install

if test "no-framework" = "no-framework" ; then \
	/usr/bin/install -c python.exe /usr/local/bin/python3.12; \
else \
	/usr/bin/install -c -s Mac/pythonw /usr/local/bin/python3.12; \
fi
if test "3.12" != "3.12"; then \
	if test -f /usr/local/bin/python3.12 -o -h /usr/local/bin/python3.12; \
	then rm -f /usr/local/bin/python3.12; \
	fi; \
	(cd /usr/local/bin; ln -s python3.12 python3.12); \
fi
if test "x" != "x" ; then \
	rm -f /usr/local/bin/python3.12-32; \
	lipo  \
		-output /usr/local/bin/python3.12-32 \
		/usr/local/bin/python3.12; \
fi
if test "x" != "x" ; then \
	rm -f /usr/local/bin/python3.12-intel64; \
	lipo  \
		-output /usr/local/bin/python3.12-intel64 \
		/usr/local/bin/python3.12; \
fi
# Install macOS debug information (if available)
if test -d "python.exe.dSYM"; then \
	echo  /usr/local/bin/python3.12; \
	 /usr/local/bin/python3.12; \
fi
if test "no-framework" = "no-framework" ; then \
	if test -d "libpython3.12.dll.a.dSYM"; then \
		echo  /usr/local/lib/libpython3.12.dll.a; \
		 /usr/local/lib/libpython3.12.dll.a; \
	fi \
else \
	if test -d "libpython3.12.dll.a.dSYM"; then \
		echo  /libpython3.12.dll.a; \
       /libpython3.12.dll.a; \
	fi \
fi
Traceback (most recent call last):
  File "/home/Friedrich/N/Builds/2025/CPython/Python-3.12.11/./Tools/build/check_extension_modules.py", line 25, in <module>
    import pathlib
  File "/home/Friedrich/N/Builds/2025/CPython/Python-3.12.11/Lib/pathlib.py", line 20, in <module>
    from urllib.parse import quote_from_bytes as urlquote_from_bytes
  File "/home/Friedrich/N/Builds/2025/CPython/Python-3.12.11/Lib/urllib/parse.py", line 36, in <module>
    import math
ModuleNotFoundError: No module named 'math'
make: *** [Makefile:1152: checksharedmods] Error 1

Again the same pattern of a “missing” math module.

Attempting to test Python 3.13

I tried to just $ make test the Python 3.13 I obtained yesterday:

Log origin directory: /home/Friedrich/N/Builds/2025
Relative cwd: ./CPython/Python-3.13.7
Command: make test

gcc -shared -Wl,--enable-auto-image-base      Modules/_asynciomodule.o  -L. -lpython3.13 -o Modules/_asyncio.cpython-313.dll
gcc -shared -Wl,--enable-auto-image-base      Modules/_elementtree.o  -L. -lpython3.13 -o Modules/_elementtree.cpython-313.dll
[ERROR] _asyncio failed to import: No module named '_socket'
[ERROR] _elementtree failed to import: No module named 'pyexpat'
Following modules built successfully but were removed because they could not be imported:
_asyncio                  _elementtree                                     

Checked 112 modules (33 built-in, 76 shared, 1 n/a on cygwin-3.6.4-x86_64, 0 disabled, 0 missing, 2 failed on import)
./python.exe -E  -m test --fast-ci --timeout= 
Traceback (most recent call last):
  File "<frozen runpy>", line 198, in _run_module_as_main
  File "<frozen runpy>", line 88, in _run_code
  File "/home/Friedrich/N/Builds/2025/CPython/Python-3.13.7/Lib/test/__main__.py", line 1, in <module>
    from test.libregrtest.main import main
  File "/home/Friedrich/N/Builds/2025/CPython/Python-3.13.7/Lib/test/libregrtest/main.py", line 2, in <module>
    import random
  File "/home/Friedrich/N/Builds/2025/CPython/Python-3.13.7/Lib/random.py", line 53, in <module>
    from math import log as _log, exp as _exp, pi as _pi, e as _e, ceil as _ceil
ModuleNotFoundError: No module named 'math'
make: *** [Makefile:2202: test] Error 1

Once more, importing math fails.

Conclusion

I am not an expert, but in the light of the “monkey-fix” for >>> import math by renaming:

/usr/local/lib/python3.11/lib-dynload/math.cpython-311.dll

to

/usr/local/lib/python3.11/lib-dynload/math.dll

maybe the problem can be diagnosed in its entirety.

Acknowledgements

The idea to look at importlib.machinery.EXTENSION_SUFFIXES originated from ChatGPT.

Speculations

With the highest degree of caution I would guess: Possibly there is a bug in the code deducing importlib.machinery.EXTENSION_SUFFIXES from sysconfig.get_config_var("SOABI") on Cygwin?

Maybe the math module is just the first built-in module ever loaded in the startup procedure of the scripts above?