| # Python 2.7.18 — Bazel Module |
| |
| Builds `python27.dll` from source using MSVC via the local file registry at |
| `ext_libraries/modules/python/`. |
| |
| ## Registry layout |
| |
| ``` |
| ext_libraries/modules/python/ |
| metadata.json |
| 2.7.18/ |
| MODULE.bazel |
| source.json ← URL + overlay hashes |
| overlay/ |
| MODULE.bazel |
| BUILD.bazel ← cc_binary + filegroup + cc_library |
| PC/config.c ← minimal built-in module table (replaces stock PC/config.c) |
| PC/pyconfig.h ← removes #pragma comment(lib,"python27.lib") auto-link |
| ``` |
| |
| ## Targets |
| |
| | Target | Output | |
| |--------|--------| |
| | `@python//:python27` | `python27.dll` (linkshared) | |
| | `@python//:python27_implib` | `python27.if.lib` (interface_library filegroup) | |
| | `@python//:python_headers` | `Include/*.h` + `PC/pyconfig.h` | |
| |
| ## Key build decisions |
| |
| ### `_socket` is linked in, not built as `_socket.pyd` |
| Upstream CPython builds a set of *extension modules* as separate `.pyd` DLLs |
| (`PCbuild/_socket.vcproj`, `select`, `unicodedata`, `_ssl`, `_ctypes`, …). |
| This port has **no `.pyd` extension-module targets at all** — `python27.dll` |
| contains only what `PC/config.c` lists in `_PyImport_Inittab`. |
| |
| `socketmodule.c` is the one exception, compiled into `python27.dll` and listed |
| in the overlay's `PC/config.c` as `{"_socket", init_socket}`. It is not |
| optional: [main/pyuno/source/module/uno.py](../../../main/pyuno/source/module/uno.py) |
| does `import socket` at module scope ("since on Windows sal3.dll no longer calls |
| WSAStartup"), so without `_socket` every `import uno` raises |
| `ImportError: No module named _socket`. That kills `import pythonloader`, so |
| `pyuno_loader.cxx`'s `CreateInstance()` throws before `activate()` is ever |
| reached and the whole Python UNO loader is dead — visible as an empty tree and |
| greyed buttons in Tools ▸ Macros ▸ Organize Macros ▸ Python, with the exception |
| swallowed by `ProviderCache`. `ws2_32.lib` was already in `linkopts`. |
| |
| Expect `warning C4005: 'INVALID_SOCKET' : macro redefinition` — `socketmodule.c` |
| defines it before including the SDK's `winsock2.h`. Harmless, same value. |
| |
| **Still missing**: every other extension module. A Python macro that imports |
| `select`, `unicodedata`, `_ssl`, `_ctypes`, `pyexpat`, `bz2` … will fail the same |
| way. Add them the same way (source into `_MODULE_SRCS` + entry in `PC/config.c`) |
| as they are needed, or build real `.pyd` targets — `//build/rules:copy_file.bzl` |
| exists for the `.dll` → `.pyd` rename, see `main/pyuno/readme.md`. |
| |
| ### No DEF file |
| Python 2.7.18's tarball does not include `PC/python27.def`. Exports are |
| produced via `__declspec(dllexport)` through the `Py_BUILD_CORE` → |
| `PyAPI_FUNC` macro chain. No `win_def_file` is needed. |
| |
| ### PC/pyconfig.h — no ./configure needed |
| The Windows pre-generated `PC/pyconfig.h` is used directly. No autoconf step. |
| |
| ### Defines |
| - `Py_BUILD_CORE` — enables `__declspec(dllexport)` on all public API |
| - `NTDDI_VERSION=0x06010000` — pre-empts `pyconfig.h`'s XP-era `#ifndef` |
| which conflicts with the toolchain's `/D_WIN32_WINNT=0x0601` (Vista) |
| - `MS_WINDOWS`, `WITH_THREAD`, `NT_THREADS` — omitted; `PC/pyconfig.h` |
| already defines them (adding them again causes C4005 redefinition warnings) |
| - `snprintf=_snprintf` — omitted; `Python/pyport.h` handles this for MSVC |
| |
| ### include paths |
| - `Include/` — public Python headers (`Python.h` etc.) |
| - `PC/` — `pyconfig.h` (Windows pre-generated) |
| - `Python/` — internal headers (`importdl.h`, used by `PC/import_nt.c`) |
| |
| ### Excluded source files |
| |
| **Python/ (Unix-only or conflicts):** |
| | File | Reason | |
| |------|--------| |
| | `dynload_aix/atheos/beos/dl/hpux/os2/shlib/stub.c` | OS-specific dynloaders | |
| | `dynload_next.c` | macOS/NeXTStep — requires `mach-o/dyld.h` | |
| | `mactoolboxglue.c` | macOS — requires `Carbon/Carbon.h` | |
| | `getcwd.c` | POSIX fallback; Windows uses `_getcwd` from CRT | |
| | `dup2.c`, `strdup.c` | POSIX shims not needed on Windows | |
| | `pyfpe.c` | SIGFPE handling (Unix-only) | |
| | `sigcheck.c` | Stub superseded by `Modules/signalmodule.c` | |
| | `intrcheck.c` | Stub superseded by `Modules/signalmodule.c` | |
| | `frozenmain.c` | Frozen-exe launcher — unresolved `PyWinFreeze_*` | |
| |
| **Parser/ (pgen build-tool files not part of the runtime DLL):** |
| | File | Reason | |
| |------|--------| |
| | `pgenmain.c` | pgen `main()` — duplicates `pythonrun`/`errors` symbols | |
| | `tokenizer_pgen.c` | pgen tokenizer — duplicates `tokenizer.c` symbols | |
| | `pgen.c` | Parser generator — build tool only | |
| | `printgrammar.c` | pgen utility — build tool only | |
| | `intrcheck.c` | Stub superseded by `Modules/signalmodule.c` | |
| |
| Note: `Parser/intrcheck.c` is distinct from `Python/intrcheck.c` — both exist |
| in the source tree. Both must be excluded; only the `Parser/` one was causing |
| the linker conflict (it is picked up by `glob(["Parser/*.c"])`). |
| |
| ### getopt.c — kept |
| `Python/getopt.c` is Python's own command-line option parser providing |
| `_PyOS_GetOpt`, `_PyOS_optind`, `_PyOS_optarg` etc. required by |
| `Modules/main.c`. It is NOT a POSIX shim and must NOT be excluded. |
| |
| ### Overlay PC/config.c |
| The stock `PC/config.c` references modules not compiled into this minimal DLL |
| (CJK codecs, zlib, mmap, audioop, imageop, lsprof, hotshot). An overlay |
| `PC/config.c` is provided that lists only the modules actually compiled in. |
| |
| ### Overlay cache update procedure |
| After any change to an overlay file: |
| 1. Recompute SHA-256: `cat overlay/FILE | openssl dgst -sha256 -binary | base64` |
| 2. Update `source.json` with `"sha256-<base64>"` for the changed file |
| 3. Run `bazel mod deps --lockfile_mode=refresh` |
| 4. Run `bazel build @python//:python27` |
| |
| If the analysis cache persists stale (observed with glob changes to external |
| modules), run `bazel shutdown` before `bazel mod deps --lockfile_mode=refresh`. |