Skip to content

Link a static libmpdec into Linux builds for Python 3.15+ - #418

Open
austinmatherne-wk wants to merge 5 commits into
actions:mainfrom
austinmatherne-wk:fix-315-decimal
Open

austinmatherne-wk wants to merge 5 commits into
actions:mainfrom
austinmatherne-wk:fix-315-decimal

Conversation

@austinmatherne-wk

Copy link
Copy Markdown

Fixes actions/setup-python#1376

Python 3.15 no longer falls back to the bundled libmpdec when configure can't find a system copy (what's new). The Ubuntu builds of 3.15.0 ship without the C _decimal module as a result. decimal then falls back to _pydecimal, which is slower and raises ValueError for values over 4300 digits. The RHEL builder has the same problem.

Installing libmpdec-dev doesn't fix it. Ubuntu 24.04 has no mpdecimal package, and the tarballs would then need libmpdec installed on the runner. --without-system-libmpdec works for 3.15, but 3.16 removes the bundled copy and the flag (what's new).

For 3.15+, the Ubuntu and RHEL builders now download mpdecimal 4.0.1, check its SHA-256, build it as a static library, and pass it to configure through LIBMPDEC_CFLAGS and LIBMPDEC_LIBS. It's the same tarball and hash that CPython's macOS installer uses. _decimal has no runtime dependency on libmpdec, and builds before 3.15 are unchanged.

python-modules.py now checks for _decimal as well. Importing decimal succeeds through _pydecimal, so the existing check didn't catch this.

Testing:

  • 3.15.0 on all six Ubuntu platforms, default and free-threaded, in my fork: https://github.com/austinmatherne-wk/python-versions/actions/runs/40336601178. All 24 build and test jobs pass, and CPython's test_decimal passes during the PGO build.
  • 3.16.0a1 on Ubuntu 24.04 in Docker, using the builder's Configure(). _decimal imports and doesn't link to libmpdec.
  • I couldn't test RHEL because those runners aren't available to forks.

Notes:

  • The published 3.15.0 Linux tarballs need a rebuild after this merges to pick up _decimal.
  • Updating mpdecimal later means changing the version and hash together in BuildLibmpdec().

Python 3.15 no longer falls back to its bundled libmpdec when configure
can't find a system copy, and 3.16 removes the bundled copy entirely,
so the Ubuntu builds silently drop the C _decimal module. Ubuntu 24.04
doesn't package mpdecimal.

Build mpdecimal 4.0.1 from its release tarball, verified against the
SHA-256 that CPython's macOS installer pins, and link it statically so
the artifact doesn't need libmpdec on the runner.

Fixes actions/setup-python#1376
Same change as the Ubuntu builder. The RHEL builder doesn't install
mpdecimal-devel either, so Python 3.15+ builds there also lose
_decimal.
Importing decimal succeeds even without _decimal because it falls back
to _pydecimal, so the existing check didn't catch a missing C
extension.
@austinmatherne-wk
austinmatherne-wk requested a review from a team as a code owner October 26, 2026 15:05
@pylaterreur

Copy link
Copy Markdown

I checked this locally with the builder's configure flags on 3.15.0 (Ubuntu, gcc 15.2): without libmpdec _decimal is missing, as in the 24.04 build log; with this PR's static libmpdec 4.0.1 it is built, needs only libc and libm, and test_decimal -u decimal,cpu passes (736 run, 9 skipped). The free-threaded configure behaves the same. Thanks for this, it also fixes the 22.04 and arm64 builds.

Two optional notes, neither blocking:

  • Building mpdecimal with CFLAGS='-fPIC -O3 -fvisibility=hidden' matches how CPython compiled its bundled libmpdec in the 3.14 builds. With -fPIC alone, _decimal exports 239 libmpdec symbols (3.14.8 exports none) and big-number arithmetic is slower: 200k-digit division and sqrt took 17.00G instructions against 14.12G with the flags above, and factorial(100000) 2.47G against 2.34G. Small precisions don't change. Diff: main...pylaterreur:python-versions:pr418-libmpdec-cflags (one line in nix-python-builder.psm1).
  • Execute-Command doesn't stop on failure, so if the mpdecimal build ever failed, _decimal would silently disappear again; the new _decimal import test is what would catch it.

The published 3.15.0 Linux tarballs will need a rebuild after this merges.

pylaterreur and others added 2 commits October 27, 2026 00:15
The bundled libmpdec in the 3.14 builds was compiled with CPython's own
flags, -O3 and -fvisibility=hidden among them. mpdecimal's configure
defaults to -O2 and exports every libmpdec symbol, so _decimal from
the static library exports about 240 mpd_* symbols and runs slower on
large numbers.

Pass the same two flags to mpdecimal's configure. Its default -O2
still comes first, so -O3 wins.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GwUvhmzgfkiZ6vo4uGyesN
Execute-Command logs failures without stopping, so a failed mpdecimal
build used to surface only later, as the missing _decimal module in the
module tests. Check for libmpdec.a after installing and exit with an
error instead.
@austinmatherne-wk

Copy link
Copy Markdown
Author

Thanks! I cherry picked your commit. I also added added a commit which stops the build if libmpdec.a doesn't get built.

@pylaterreur

Copy link
Copy Markdown

@v-HarithaVattikuti could you review this when you have a moment? Until it ships, the Ubuntu 3.15.0 builds that setup-python serves have no _decimal (CPython 3.15 removed the bundled libmpdec fallback), so import decimal fails on hosted runners. Verified earlier in this thread that the PR fixes it.

🤖 Generated with Claude Code

https://claude.ai/code/session_01GwUvhmzgfkiZ6vo4uGyesN

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Python 3.15.0 on Ubuntu is missing the C _decimal module

2 participants