ghc-compiler-python 9.4.8__py3-none-any.whl → 9.4.9__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,10 @@
1
1
  """ghc-compiler-python: Native GHC and Cabal packaged as a Python Wheel."""
2
2
 
3
- __version__ = "9.4.8"
3
+ # The distribution version and the compiler version are separate axes and no
4
+ # longer agree. 9.4.8 published a wrapper that rejected every Windows machine
5
+ # without a system gcc; PyPI forbids re-uploading a version, so the fix ships
6
+ # as 9.4.9. The compiler inside is still GHC 9.4.8 and still says so.
7
+ __version__ = "9.4.9"
4
8
  __ghc_version__ = "9.4.8"
5
9
  __cabal_version__ = "3.10.3.0"
6
10
  __author__ = "ghc-compiler-python contributors"
@@ -39,13 +39,30 @@ import zipfile
39
39
  from pathlib import Path
40
40
  from typing import NoReturn, Optional
41
41
 
42
+ #: The compiler actually inside the payload. This is GHC's own version and it
43
+ #: moves only when the bindist does.
42
44
  GHC_VERSION = "9.4.8"
43
45
 
46
+ #: The distribution coordinate: the git tag, the release, the payload asset
47
+ #: names, the cache directory, and the version on PyPI.
48
+ #:
49
+ #: These were one constant until 9.4.9, which read well while the two agreed
50
+ #: and became a trap the moment they had to diverge. 9.4.8 shipped a wrapper
51
+ #: that rejected every Windows machine without a system gcc; PyPI forbids
52
+ #: re-uploading a version, so the fix needed a new one, and a single constant
53
+ #: made "publish a fixed wheel" and "claim a GHC release that does not exist"
54
+ #: the same edit.
55
+ #:
56
+ #: They are now separate axes. The package version is 9.4.9; the compiler it
57
+ #: installs is, and reports itself as, 9.4.8. `ghc-wrapper --numeric-version`
58
+ #: answers for the compiler, never for the package.
59
+ RELEASE_VERSION = "9.4.9"
60
+
44
61
  #: Release assets are addressed by tag, so a wheel always fetches the payload
45
62
  #: built alongside it rather than whatever happens to be newest.
46
63
  _RELEASE_BASE = (
47
64
  "https://github.com/Saimonokuma/GHC-COMPILER-PYTHON/releases/download"
48
- f"/v{GHC_VERSION}"
65
+ f"/v{RELEASE_VERSION}"
49
66
  )
50
67
 
51
68
  _HASH_MANIFEST = Path(__file__).resolve().parent / "payload_hashes.json"
@@ -107,7 +124,7 @@ def _archive_suffix() -> str:
107
124
 
108
125
 
109
126
  def payload_name() -> str:
110
- return f"ghc-payload-{GHC_VERSION}-{platform_tag()}{_archive_suffix()}"
127
+ return f"ghc-payload-{RELEASE_VERSION}-{platform_tag()}{_archive_suffix()}"
111
128
 
112
129
 
113
130
  def payload_url() -> str:
@@ -142,7 +159,7 @@ def cache_root() -> Path:
142
159
 
143
160
  def payload_root() -> Path:
144
161
  """Where this version's toolchain lives once installed."""
145
- return cache_root() / GHC_VERSION / platform_tag()
162
+ return cache_root() / RELEASE_VERSION / platform_tag()
146
163
 
147
164
 
148
165
  def is_installed() -> bool:
@@ -196,7 +213,7 @@ def _offline_hint() -> str:
196
213
  "If this machine has no network access, install the self-contained "
197
214
  "wheel instead — it bundles the toolchain and never downloads:\n"
198
215
  f" {_RELEASE_BASE}/"
199
- f"ghc_compiler_python-{GHC_VERSION}-py3-none-{platform_tag()}.whl"
216
+ f"ghc_compiler_python-{RELEASE_VERSION}-py3-none-{platform_tag()}.whl"
200
217
  )
201
218
 
202
219
 
@@ -206,7 +223,7 @@ def _download(url: str, dest: Path, quiet: bool) -> None:
206
223
  sys.stderr.write(f" from {url}\n")
207
224
 
208
225
  request = urllib.request.Request(
209
- url, headers={"User-Agent": f"ghc-compiler-python/{GHC_VERSION}"}
226
+ url, headers={"User-Agent": f"ghc-compiler-python/{RELEASE_VERSION}"}
210
227
  )
211
228
  try:
212
229
  with urllib.request.urlopen(request, timeout=_DOWNLOAD_TIMEOUT) as response:
@@ -358,7 +375,7 @@ def ensure_payload(quiet: bool = False) -> Path:
358
375
 
359
376
  expected = _expected_digest()
360
377
 
361
- with _DirectoryLock(cache_root() / f".lock-{GHC_VERSION}-{platform_tag()}"):
378
+ with _DirectoryLock(cache_root() / f".lock-{RELEASE_VERSION}-{platform_tag()}"):
362
379
  if is_installed():
363
380
  return root
364
381
 
@@ -390,7 +407,7 @@ def ensure_payload(quiet: bool = False) -> Path:
390
407
 
391
408
  _restore_exec_bits(unpacked)
392
409
  (unpacked / ".complete").write_text(
393
- f"{GHC_VERSION} {platform_tag()}\n", encoding="utf-8"
410
+ f"{RELEASE_VERSION} {platform_tag()}\n", encoding="utf-8"
394
411
  )
395
412
 
396
413
  if root.exists():
@@ -1,5 +1,5 @@
1
1
  {
2
- "ghc-payload-9.4.8-macosx_11_0_arm64.tar.xz": "eb826736bb3fa238603183089872fced21231660bc5c1e74067c77a7a77965f9",
3
- "ghc-payload-9.4.8-manylinux_2_39_x86_64.tar.xz": "09b4127c288f0c08f77ec4bfbcd2dbc4192566d84b0db4d7c16942dc53d7fd72",
4
- "ghc-payload-9.4.8-win_amd64.zip": "31629e8a008d3adf83e0869463c1a3bdf696ae02bf5be51fa110cc8cba484d1d"
2
+ "ghc-payload-9.4.9-macosx_11_0_arm64.tar.xz": "6cc3d01e5e69524001d9211138382093c41d09da852aeee7f871b0d563afb31c",
3
+ "ghc-payload-9.4.9-manylinux_2_39_x86_64.tar.xz": "13dc0b399796c6a2fadeb1f11154cfa9e7698507fb9ba07cf0e5aa7a2024293a",
4
+ "ghc-payload-9.4.9-win_amd64.zip": "4ff104a37873757d7c2f4414360a08c3f07ccb49aa018c8b29a70c7cb4989e14"
5
5
  }
@@ -223,10 +223,56 @@ def _resolve_binary(name: str) -> str:
223
223
  )
224
224
 
225
225
 
226
- def _validate_c_linker() -> None:
227
- """Pre-flight validation: assert the existence of a host C-linker."""
228
- if not shutil.which("gcc") and not shutil.which("clang"):
229
- _die("FATAL ERROR: The GHC compiler requires a host C-linker (gcc or clang).")
226
+ #: Where the Windows bindist keeps the C toolchain it ships with itself,
227
+ #: relative to the toolchain root. Verified against the published payload:
228
+ #: mingw/bin/clang.exe and mingw/bin/ld.exe are both present. GHC 9.4.8 for
229
+ #: Windows drives clang, not gcc.
230
+ _BUNDLED_LINKERS = (
231
+ "mingw/bin/clang.exe",
232
+ "mingw/bin/gcc.exe",
233
+ "mingw/bin/clang",
234
+ "mingw/bin/gcc",
235
+ )
236
+
237
+
238
+ def _bundled_c_linker(root: Optional[Path]) -> Optional[Path]:
239
+ """Return the C compiler shipped inside the toolchain, if there is one."""
240
+ if root is None:
241
+ return None
242
+ for relative in _BUNDLED_LINKERS:
243
+ candidate = root / relative
244
+ if candidate.is_file():
245
+ return candidate
246
+ return None
247
+
248
+
249
+ def _validate_c_linker(root: Optional[Path] = None) -> None:
250
+ """Assert that a C toolchain GHC can actually drive is reachable.
251
+
252
+ GHC shells out to a C compiler to assemble and link, so its absence is
253
+ worth catching before the user sees a confusing error from deep inside
254
+ the compiler. But *where* that compiler comes from differs by platform:
255
+
256
+ Unix GHC uses the system cc. Absent means absent.
257
+ Windows the bindist carries its own. mingw/bin/clang.exe and
258
+ mingw/bin/ld.exe live inside the payload, and that toolchain
259
+ is the single largest reason the Windows payload is 395 MB
260
+ against 87 MB for Linux.
261
+
262
+ Checking only `shutil.which` therefore rejected every Windows machine
263
+ without a system gcc -- including machines that had just downloaded a
264
+ complete toolchain and were holding it in the cache. CI never caught it
265
+ because the windows-latest runner installs mingw via chocolatey, so a
266
+ system compiler is always on PATH there. The delivered path found it on
267
+ the first real user run.
268
+ """
269
+ if shutil.which("gcc") or shutil.which("clang"):
270
+ return
271
+
272
+ if _bundled_c_linker(root) is not None:
273
+ return
274
+
275
+ _die("FATAL ERROR: The GHC compiler requires a host C-linker (gcc or clang).")
230
276
 
231
277
 
232
278
  def _find_platform_lib_subdir() -> str:
@@ -309,6 +355,16 @@ def _sterilize_environment() -> dict:
309
355
  ghc_root / "lib" / f"ghc-{GHC_VERSION}",
310
356
  ghc_root / "lib" / f"ghc-{GHC_VERSION}" / "lib",
311
357
  Path(_find_platform_lib_subdir() or "."),
358
+ # Shipped inside the payload, so the thin-wheel path is as
359
+ # self-contained as the Windows one. GHC 9.4.8 links against
360
+ # ncurses 5; Ubuntu 24.04 ships ncurses 6 and has no
361
+ # libtinfo.so.5, so without this the first command a user runs
362
+ # dies with "error while loading shared libraries".
363
+ #
364
+ # This is the Linux twin of the mingw case above: the payload
365
+ # carries the dependency, and the launcher has to be willing to
366
+ # look inside the payload for it.
367
+ ghc_root / "vendor-lib",
312
368
  # auditwheel vendors shared objects here on the offline wheel.
313
369
  Path(__file__).resolve().parent.parent / "ghc_compiler_python.libs",
314
370
  ]
@@ -676,7 +732,23 @@ def _ghc_pkg_recache(pkg_db_dir: str, env: dict) -> None:
676
732
 
677
733
  def _execute_tool(tool_name: str, extra_args: Optional[List[str]] = None) -> NoReturn:
678
734
  """Generic subprocess proxy for bundled Haskell tooling."""
679
- _validate_c_linker()
735
+ # Acquire the toolchain first. Everything below describes or patches it,
736
+ # and none of that can be done correctly before it exists.
737
+ #
738
+ # The previous order validated the linker, sterilised the environment and
739
+ # ran _resolve_runtime_paths -- which rewrites @GHC_PREFIX@ to the real
740
+ # root -- and only then called _resolve_binary, which is what actually
741
+ # downloads the payload. On a thin-wheel install there was no toolchain on
742
+ # disk during the patch step, so _ghc_root_or_prefix fell back to
743
+ # sys.prefix, the resource scan found nothing, and the placeholders were
744
+ # left unresolved.
745
+ #
746
+ # This never showed up in CI because the offline wheel ships the toolchain
747
+ # inside the package, so a bundled root is present from the first line and
748
+ # the ordering makes no observable difference. It only breaks on the path
749
+ # every PyPI user takes.
750
+ root = _ghc_root()
751
+ _validate_c_linker(root)
680
752
  env = _sterilize_environment()
681
753
  _resolve_runtime_paths(env)
682
754
  binary_path = _resolve_binary(tool_name)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ghc-compiler-python
3
- Version: 9.4.8
3
+ Version: 9.4.9
4
4
  Summary: Native GHC 9.4.8 compiler and Cabal 3.10.3.0 tooling packaged as an isolated Python Wheel
5
5
  Project-URL: Homepage, https://github.com/Saimonokuma/GHC-COMPILER-PYTHON
6
6
  Project-URL: Source, https://github.com/Saimonokuma/GHC-COMPILER-PYTHON
@@ -80,9 +80,9 @@ The PyPI package is **~17 KiB**. It fetches the toolchain for your platform on f
80
80
  Self-contained wheels with the toolchain already bundled live on the [releases page](https://github.com/Saimonokuma/GHC-COMPILER-PYTHON/releases). These never contact the network:
81
81
 
82
82
  ```bash
83
- pip install ghc_compiler_python-9.4.8-py3-none-manylinux_2_38_x86_64.manylinux_2_39_x86_64.whl # Linux
84
- pip install ghc_compiler_python-9.4.8-py3-none-macosx_11_0_arm64.whl # macOS
85
- pip install ghc_compiler_python-9.4.8-py3-none-win_amd64.whl # Windows
83
+ pip install ghc_compiler_python-9.4.9-py3-none-manylinux_2_38_x86_64.manylinux_2_39_x86_64.whl # Linux
84
+ pip install ghc_compiler_python-9.4.9-py3-none-macosx_11_0_arm64.whl # macOS
85
+ pip install ghc_compiler_python-9.4.9-py3-none-win_amd64.whl # Windows
86
86
  ```
87
87
 
88
88
  > The Linux offline wheel carries the tags `manylinux_2_38` **and** `manylinux_2_39`, so it installs on glibc 2.38 or newer. That floor is not chosen — auditwheel derives it by inspecting the versioned symbols the binaries actually reference. A tag lower than the binaries support would install on systems where the toolchain then fails at runtime, so the build states what is true rather than what would be convenient. On older distributions use the thin wheel; its payload is a plain tarball and carries no such constraint.
@@ -0,0 +1,10 @@
1
+ ghc_compiler_python/__init__.py,sha256=EQl3IbIry2EdSHPHCO3qj5PgXEDzKOUlpGcqf6lc_m8,609
2
+ ghc_compiler_python/bootstrap.py,sha256=eDe0uRaIFhDWfEjntQP9F043PiHvWljmVnL9Xqix3Bo,15902
3
+ ghc_compiler_python/payload_hashes.json,sha256=_fyFJqESXvFLgVyulav8Pk8M-3mhYekegxGAoRU5s_Q,344
4
+ ghc_compiler_python/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
+ ghc_compiler_python/wrapper.py,sha256=RLeOeGc2kn9CVrebHIpbjfWiI-yWn8qcmjIJ5HwyK4s,31021
6
+ ghc_compiler_python-9.4.9.dist-info/METADATA,sha256=wlN_tefM9ZittG3MKTrmOsSUwBBpFMmw6KO6y503xrA,9247
7
+ ghc_compiler_python-9.4.9.dist-info/WHEEL,sha256=lCkmxWfQsSc9CfIClYeavTdQeEX2toPqufh9gI35EQA,87
8
+ ghc_compiler_python-9.4.9.dist-info/entry_points.txt,sha256=9QtlqeGuoonFb4bB4F-gLlBbY0koqkTJ2PknLFrvsvo,610
9
+ ghc_compiler_python-9.4.9.dist-info/licenses/LICENSE,sha256=OOef9xbIXwIBos0C1icJ5Z_i44n_VO33KjqyeBTa-tk,1068
10
+ ghc_compiler_python-9.4.9.dist-info/RECORD,,
@@ -1,10 +0,0 @@
1
- ghc_compiler_python/__init__.py,sha256=N4kbpSKof782d2NNXc5JGUwbpJD7GDB-PpMT0PJbNuk,306
2
- ghc_compiler_python/bootstrap.py,sha256=kISTQ9uEFDvTccL__a0q94_stYDUCCfqBkYA1be2ySU,14985
3
- ghc_compiler_python/payload_hashes.json,sha256=r-HmvRveNzX92xGq-3K8JGcnTFdGp8KIXkub5CmDg_A,344
4
- ghc_compiler_python/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
- ghc_compiler_python/wrapper.py,sha256=golkrZaFxSl0iXzy-0blkaW-ic0f3Q6FPRCAPVZOw4A,27705
6
- ghc_compiler_python-9.4.8.dist-info/METADATA,sha256=B4Kbst9XS3NafvbWI1CarYQakEDjfCDyF5SQIbQfi40,9247
7
- ghc_compiler_python-9.4.8.dist-info/WHEEL,sha256=lCkmxWfQsSc9CfIClYeavTdQeEX2toPqufh9gI35EQA,87
8
- ghc_compiler_python-9.4.8.dist-info/entry_points.txt,sha256=9QtlqeGuoonFb4bB4F-gLlBbY0koqkTJ2PknLFrvsvo,610
9
- ghc_compiler_python-9.4.8.dist-info/licenses/LICENSE,sha256=OOef9xbIXwIBos0C1icJ5Z_i44n_VO33KjqyeBTa-tk,1068
10
- ghc_compiler_python-9.4.8.dist-info/RECORD,,