Skip to content

Build binary wheels with cibuildwheel via the ivpm-build backend - #1

Merged
mballance merged 14 commits into
mainfrom
ci/cibuildwheel-binary-wheels
Jun 25, 2026
Merged

Build binary wheels with cibuildwheel via the ivpm-build backend#1
mballance merged 14 commits into
mainfrom
ci/cibuildwheel-binary-wheels

Conversation

@mballance

Copy link
Copy Markdown
Member

Enables cibuildwheel to produce self-contained binary wheels for dv-solve. The native solver libraries are loaded via ctypes, so wheels are tagged py3-none-<platform> (platform-specific but interpreter/ABI agnostic) using the platform-tagging fix landed in ivpm-build.

Changes

  • pyproject.toml — switch to ivpm_build.backend; [tool.ivpm-build] stages the three native libs at the package root, headers into share/include, and the SV package into share/sv; [tool.cibuildwheel] builds one wheel per platform and smoke-tests that the bundled lib loads.
  • CMakeLists.txt — install public headers to include/dv_solve (excludes the kissat fork).
  • lib.py — search the installed package dir + build/lib(64) (L1), platform-correct lib names (L2), actionable not-found error (L3).
  • init.pyget_libs/get_libdirs/get_incdirs/get_deps/get_svdirs/get_dpi_lib discovery helpers.
  • MANIFEST.in — ship C/CMake/SV sources + tests in the sdist.
  • .github/workflows/wheels.yml — Linux (x86_64 + aarch64; two most-recent manylinux baselines 2_34 and 2_28), macOS (x86_64 + arm64), Windows, plus sdist.

Verified locally

  • project → dv_solve-0.0.1-py3-none-linux_x86_64.whl with all libs/headers/SV bundled
  • installs into a clean venv with no source tree and the native lib loads
  • sdist is complete and a wheel builds from it

Notes

  • The build requirement is pinned to ivpm-build @ git+...@main until a PyPI release carrying the platform-tag fix is cut.
  • Windows (MSVC + Ninja) is the least-exercised path; Linux/macOS are validated locally.

🤖 Generated with Claude Code

mballance and others added 14 commits June 21, 2026 15:23
Switch packaging to ivpm-build's PEP 517 backend so CI can produce
self-contained binary wheels (native libs loaded via ctypes; no compiler
needed at install time). With ivpm-build's platform-tagging fix, the wheel is
correctly tagged py3-none-<platform> rather than a pure-Python py3-none-any.

pyproject.toml:
  - build-backend = ivpm_build.backend (pinned to git main until a PyPI
    release carrying the platform-tag fix is available)
  - [tool.ivpm-build]: cmake=true + extra-data staging the three native libs
    (dv_solve, dv_solve_dpi, dv_solve_debug) at the package root, the public C
    headers into share/include, and the SV package into share/sv
  - [tool.cibuildwheel]: build one wheel per platform (cp311-*, since the lib
    is interpreter/ABI agnostic), smoke-test that the bundled lib loads, and
    install cmake via dnf in the manylinux container (ninja comes from the
    backend's build requires)

CMakeLists.txt: install public headers to include/dv_solve (excluding the
vendored kissat fork).

lib.py: search the installed package dir and build/lib(64) (L1), use
platform-correct library names for .so/.dylib/.dll (L2), and raise an
actionable not-found error with searched paths and build instructions (L3);
ctx/bvsat/problem use the shared helper.

__init__.py: get_libs/get_libdirs/get_incdirs/get_deps/get_svdirs/get_dpi_lib
for C and SystemVerilog consumers, resolving wheel vs source-tree layout.

MANIFEST.in: ship CMakeLists.txt, cmake/, src/c, src/sv and tests/ in the
sdist so it builds from source.

.github/workflows/wheels.yml: build wheels across Linux (x86_64 + aarch64,
the two most-recent manylinux baselines 2_34 and 2_28), macOS (x86_64 +
arm64) and Windows, plus an sdist.

Verified locally: project->wheel is py3-none-linux_x86_64 with all libs,
headers and SV bundled; installs into a clean venv and the native lib loads;
sdist is complete and a wheel builds from it.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
cibuildwheel 2.21.x does not recognize the short "manylinux_2_34" alias and
passed it to docker as a literal image name, failing every 2_34 job. Use the
full quay.io image paths (manylinux_2_28 / manylinux_2_34, x86_64 / aarch64),
which are version-independent. The manylinux_2_28 x86_64 build already passed,
confirming the packaging itself is correct.

Scope the matrix to Linux (the two most-recent manylinux baselines x x86_64 +
aarch64). macOS and Windows are dropped for now: the vendored kissat fork does
not compile under AppleClang (implicit memset / missing string.h) or MSVC
(GCC/Clang-only -W/-std flags). Those are C-portability fixes, separate from
packaging, to be addressed before re-adding those platforms.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
cibuildwheel 2.21.3 crashes on the manylinux_2_34 image because it probes the
EOL cp38 interpreter the image no longer ships. v4.x dropped Python 3.8, so it
builds cleanly against 2_34. Add a concurrency group so superseded emulated
runs are cancelled instead of running to completion.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…hon >=3.10

The newer manylinux images (manylinux_2_28/2_34 :latest) ship gcc 14, where
-Wimplicit-function-declaration is a hard error by default (it was only a
warning under the older gcc that cibuildwheel's pinned image digests used, and
likewise an error on AppleClang). Three latent implicit declarations blocked
the wheel build:

  - kissat fork internal.c: the custom-allocator init path calls memset() but
    the file never included <string.h> (upstream used kissat_calloc here).
  - kissat vector.c: bare memcpy/memset/memmove without <string.h>.
  - zsp_costguided.c called solver_set_value_selector() with no prototype in
    scope; added the declaration to zsp_ctx.h (it was only defined in
    zsp_ctx.c).

Verified: the full CMake build (all targets) compiles cleanly under
-Werror=implicit-function-declaration -Werror=implicit-int with gcc 13.

Also bump requires-python to >=3.10: 3.8 is EOL (which is why manylinux_2_34
no longer ships cp38) and 3.9 is nearly so. The wheel is py3-none, so it still
installs on any CPython >= 3.10.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a macOS job (macos-13 x86_64 + macos-14 arm64) to confirm the C
portability fixes let the wheel build under AppleClang. Linux and sdist jobs
are gated off with if: false for fast turnaround; revert this commit to
restore the full matrix.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
First attempt at native MSVC Windows wheels. Adds a compat layer under
src/c/compat/win/ rather than editing the kissat/dv-solve sources:

  - msvc_compat.h: force-included (/FI) into every TU; maps the GCC builtins
    (__builtin_clz*/ctz*/prefetch/alloca and the unsigned add/mul overflow
    checks via _Generic + x64 intrinsics) and defines S_ISDIR/S_ISREG.
  - unistd.h / sys/time.h / sys/resource.h shims: POSIX I/O aliases
    (access/isatty/unlink/getpid/popen...), struct timeval/rusage, and the
    R_OK/_SC_* constants.
  - win_compat.c: Win32 backings for gettimeofday (GetSystemTimePreciseAsFile-
    Time), getrusage (GetProcessTimes + GetProcessMemoryInfo) and sysconf
    (GetSystemInfo), compiled into the kissat static lib on MSVC.

CMake:
  - kissat.cmake guards the GCC-only flags behind else(); the MSVC branch adds
    the compat include dir, /FI, the Win32 defines, win_compat.c and psapi, and
    drops the non-existent -lm.
  - CMakeLists enables CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS so the ctypes loader
    can resolve the DLL's symbols, force-includes the shim for the dv-solve
    targets, and adds RUNTIME/ARCHIVE install destinations so the .dll and
    import .lib land in build/lib.

CI: temporarily switch the matrix to a single Windows job (Linux + sdist stay
disabled) for fast iteration. Verified the non-MSVC build still configures and
links on Linux.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
MSVC rejects __attribute__((format(...))) / ((always_inline)) in kissat's
error.h/format.h. Define __attribute__(x) to nothing in the force-included
compat header.
COUNT_RADIX was sized by a const size_t (WIDTH_RADIX = 1<<8); in C that is a
VLA, which MSVC rejects. Use the literal bound (256) directly.
zsp_prop_templates.c used unsigned __int128 for one 64x64 mul-mod; MSVC has no
__int128. Add zsp_mulmod_u64() using _umul128/_udiv128 on MSVC and __int128
elsewhere (a,b < m precondition keeps _udiv128 in range).
dv-solve timing helpers (zsp_placement/costguided/contradiction/bbsolver) use
POSIX clock_gettime(CLOCK_MONOTONIC). Add the macro + a QueryPerformanceCounter
(monotonic) / GetSystemTimePreciseAsFileTime (realtime) implementation.
IMPLIED_BY_LEARNT was a ({ ... }) statement expression (GCC/Clang only).
Extract it into a static inline function and make the macro a thin call
wrapper so the call sites are unchanged and it compiles under MSVC.
The dv-solve-smt2 CLI and the C unit-test executables are dev tools, not part
of any wheel, and they pull in POSIX setenv/unsetenv and the internal
lcg_dbg_bail data symbol (not exported from the DLL). Gate them behind a new
DV_SOLVE_BUILD_TOOLS option, forced off on MSVC. The three shared libraries
(the wheel payload) still build.
All platforms build now. build_wheels covers Linux (x86_64+aarch64, manylinux
2_34+2_28), macOS arm64 and Windows AMD64 on every run; macOS x86_64 (legacy,
slow to schedule) runs only on release tags / manual dispatch; plus sdist.
The platform-tagging fix is now on PyPI (ivpm-build 0.2.0.27908268978), so
replace the 'ivpm-build @ git+...@main' build requirement with a versioned
PyPI dependency (>= that build). Verified an isolated 'python -m build' resolves
it from PyPI, produces a py3-none-linux_x86_64 wheel, and the installed lib
loads.
@mballance
mballance merged commit 5a0aa13 into main Jun 25, 2026
8 checks passed
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.

1 participant