Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .bazelrc
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,12 @@ build:linux --cxxopt=-Wno-conversion
# Chained from build:asan; Apple toolchains do not match on Linux and are ignored.
build:asan_macos --extra_toolchains=@local_config_apple_cc_toolchains//:all
build:asan_macos --copt=-Wno-macro-redefined
# Lets CPPVARIABLES.bzl's debug_build_macos_asan config_setting (BUILD.bazel)
# detect this config and skip -mmacosx-version-min: local_config_apple_cc_
# toolchains' generated compile command already carries its own
# `-target arm64-apple-macosX.Y`, and setting both is a hard error under
# -Werror (clang -Woverriding-option).
build:asan_macos --define=macos_asan=true

# ThreadSanitizer configuration
# Usage: bazel test --config=tsan //path:target
Expand Down
20 changes: 20 additions & 0 deletions .github/workflows/ci_linux.yml
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,26 @@ jobs:
- name: Run all tests
run: bazelisk test --verbose_failures //...

# Python wheel: dds3_wheel_dist is tagged manual (its platform select
# has no arm for Linux ARM64/Intel macOS, see python/BUILD.bazel), so
# the build above does not produce it -- build it explicitly here.
# Building it alone never runs `pip install` on the packaged .whl,
# so a mistagged or incomplete archive would go unnoticed. 3.14
# matches the cp314 tag dds3_wheel sets for its compiled _dds3
# extension (see python/BUILD.bazel).
- name: Setup Python
uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0
with:
python-version: "3.14"

- name: Build and smoke-test Python wheel
run: |
bazelisk build --verbose_failures //python:dds3_wheel_dist
wheel="$(ls bazel-bin/python/dist/*.whl)"
python3 -m venv "$RUNNER_TEMP/dds3_wheel_venv"
"$RUNNER_TEMP/dds3_wheel_venv/bin/pip" install --no-index --no-deps "$wheel"
"$RUNNER_TEMP/dds3_wheel_venv/bin/python" -c "import dds3; assert dds3.api_root() == 'dds.hpp'; print('dds3 wheel OK:', dds3.__file__)"

# --- Non-default-flag builds below. Each mutates the active Bazel
# config (bazel-bin, etc.), so they are kept together and last, after
# everything above that depends on the default configuration.
Expand Down
20 changes: 20 additions & 0 deletions .github/workflows/ci_macos.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,26 @@ jobs:
- name: Run all tests
run: bazelisk test --verbose_failures //...

# Python wheel: dds3_wheel_dist is tagged manual (its platform select
# has no arm for Linux ARM64/Intel macOS, see python/BUILD.bazel), so
# the build above does not produce it -- build it explicitly here.
# Building it alone never runs `pip install` on the packaged .whl,
# so a mistagged or incomplete archive would go unnoticed. 3.14
# matches the cp314 tag dds3_wheel sets for its compiled _dds3
# extension (see python/BUILD.bazel).
- name: Setup Python
uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0
with:
python-version: "3.14"

- name: Build and smoke-test Python wheel
run: |
bazelisk build --verbose_failures //python:dds3_wheel_dist
wheel="$(ls bazel-bin/python/dist/*.whl)"
python3 -m venv "$RUNNER_TEMP/dds3_wheel_venv"
"$RUNNER_TEMP/dds3_wheel_venv/bin/pip" install --no-index --no-deps "$wheel"
"$RUNNER_TEMP/dds3_wheel_venv/bin/python" -c "import dds3; assert dds3.api_root() == 'dds.hpp'; print('dds3 wheel OK:', dds3.__file__)"

# .NET binding — this job is the only CI coverage of the AArch64 ABI, which
# is what the managed struct-layout tests exist to guard: a layout mismatch
# there corrupts results silently rather than throwing. Linux covers SysV
Expand Down
27 changes: 27 additions & 0 deletions .github/workflows/ci_windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,33 @@ jobs:

# .NET binding lives in CI – Windows .NET (ci_windows_dotnet.yml).

# Python wheel: dds3_wheel_dist is tagged manual (its platform select
# has no arm for Linux ARM64/Intel macOS, see python/BUILD.bazel), so
# the build above does not produce it -- build it explicitly here.
# Building it alone never runs `pip install` on the packaged .whl, so
# a mistagged or incomplete archive would go unnoticed. 3.14 matches
# the cp314 tag dds3_wheel sets for its compiled _dds3 extension (see
# python/BUILD.bazel). --config=opt matches every other bazelisk build
# invocation on this job (avoids MSVC D9025).
- name: Setup Python
uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0
with:
python-version: "3.14"

- name: Build and smoke-test Python wheel
shell: pwsh
run: |
bazelisk build --config=opt --verbose_failures //python:dds3_wheel_dist
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
$wheel = Get-ChildItem -Path "bazel-bin/python/dist" -Filter *.whl | Select-Object -First 1
if (-not $wheel) { Write-Error "no wheel found in bazel-bin/python/dist"; exit 1 }
python -m venv "$env:RUNNER_TEMP/dds3_wheel_venv"
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
& "$env:RUNNER_TEMP/dds3_wheel_venv/Scripts/pip.exe" install --no-index --no-deps $wheel.FullName
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
& "$env:RUNNER_TEMP/dds3_wheel_venv/Scripts/python.exe" -c "import dds3; assert dds3.api_root() == 'dds.hpp'; print('dds3 wheel OK:', dds3.__file__)"
exit $LASTEXITCODE

- name: Upload test logs - Windows
if: always()
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
Expand Down
40 changes: 40 additions & 0 deletions BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,34 @@ config_setting(
values = {"compilation_mode": "dbg"},
)

# More specific than debug_build_macos (a strict superset of its conditions,
# so select() resolves it instead rather than erroring as ambiguous):
# --config=asan on macOS (build:asan_macos in .bazelrc) swaps in
# local_config_apple_cc_toolchains, whose generated compile command already
# carries its own `-target arm64-apple-macosX.Y`. CPPVARIABLES.bzl must not
# also set -mmacosx-version-min there -- clang treats the combination as a
# hard error under -Werror (-Woverriding-option).
config_setting(
name = "debug_build_macos_asan",
constraint_values = [
"@platforms//os:osx",
],
values = {"compilation_mode": "dbg"},
define_values = {"macos_asan": "true"},
)

# More specific than build_macos (any CPU): needed where a select() arm must
# pick a CPU-qualified value (e.g. python/BUILD.bazel's macOS wheel platform
# tag) and a wrong-arch match would silently mislabel the output rather than
# failing closed like build_windows does for non-x86_64.
config_setting(
name = "build_macos_arm64",
constraint_values = [
"@platforms//os:osx",
"@platforms//cpu:arm64",
],
)

config_setting(
name = "build_linux",
constraint_values = [
Expand All @@ -28,6 +56,18 @@ config_setting(
values = {"compilation_mode": "dbg"},
)

# More specific than build_linux (any CPU): needed where a select() arm must
# pick a CPU-qualified value (e.g. python/BUILD.bazel's Linux wheel platform
# tag) and a wrong-arch match would silently mislabel the output rather than
# failing closed like build_windows does for non-x86_64.
config_setting(
name = "build_linux_x86_64",
constraint_values = [
"@platforms//os:linux",
"@platforms//cpu:x86_64",
],
)

config_setting(
name = "build_windows",
constraint_values = [
Expand Down
24 changes: 22 additions & 2 deletions CPPVARIABLES.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,30 @@ DDS_CPPOPTS = select({
"-O3",
"-flto=thin",
"-mtune=generic",
# Matches dds3_wheel's macosx_11_0_arm64 platform tag
# (python/BUILD.bazel) -- without this, the real floor baked into
# the .so is whatever the host's default Xcode/SDK picks, which the
# tag would then misrepresent.
"-mmacosx-version-min=11.0",
"-fPIC",
"-Wpedantic",
"-Wall",
"-Wno-character-conversion",
"-Werror",
],
"//:debug_build_macos": [
"-g",
"-mtune=generic",
"-mmacosx-version-min=11.0",
"-fPIC",
"-Wpedantic",
"-Wall",
"-Wno-character-conversion",
"-Werror",
],
# Same as debug_build_macos but without -mmacosx-version-min: see the
# config_setting's comment in BUILD.bazel for why asan can't take it.
"//:debug_build_macos_asan": [
"-g",
"-mtune=generic",
"-fPIC",
Expand Down Expand Up @@ -96,8 +113,11 @@ DDS_LOCAL_DEFINES = select({
})

DDS_LINKOPTS = select({
"//:build_macos": ["-flto=thin"],
"//:debug_build_macos": [],
"//:build_macos": ["-flto=thin", "-mmacosx-version-min=11.0"],
"//:debug_build_macos": ["-mmacosx-version-min=11.0"],
# No -mmacosx-version-min: see the debug_build_macos_asan arm in
# DDS_CPPOPTS above.
"//:debug_build_macos_asan": [],
"//:build_linux": [],
"//:debug_build_linux": [],
"//conditions:default": [],
Expand Down
8 changes: 6 additions & 2 deletions docs/python_interface.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,15 @@ The DDS (Double Dummy Solver) library provides a Python interface for analyzing
## Building the Python Interface

### Prerequisites
- Python 3.10+ (tested with 3.10, 3.11, 3.12, 3.14)
- Bazel as pinned in [`.bazelversion`](../.bazelversion) (use
[bazelisk](https://github.com/bazelbuild/bazelisk), which picks it up
automatically)
automatically) — no host Python install is required to *build*: Bazel
downloads its own hermetic CPython via `rules_python`.
- C++ compiler (clang 15+ or GCC 11+)
- To *use* the built wheel, a CPython 3.14 interpreter: `MODULE.bazel` pins
exactly one toolchain version (3.14), `_dds3` links the full CPython API
(not the stable `abi3` ABI), and `dds3_wheel` is tagged `cp314`/`cp314`
accordingly — pip will refuse to install it on any other CPython version.

### Build Instructions

Expand Down
72 changes: 72 additions & 0 deletions python/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,36 @@ py_test(
],
)

# Guard: dds3_wheel must carry CPython/platform tags, not py_wheel's
# py3-none-any defaults, since _dds3 is a compiled extension.
py_test(
name = "ci_wheel_tags_test",
size = "small",
main = "tests/ci_wheel_tags_test.py",
srcs = ["tests/ci_wheel_tags_test.py"],
data = ["BUILD.bazel"],
)

# Guard: CI actually `pip install`s the packaged wheel (not just Bazel's own
# py_library layout) on all three host OSes.
py_test(
name = "ci_wheel_smoke_test",
size = "small",
main = "tests/ci_wheel_smoke_test.py",
srcs = ["tests/ci_wheel_smoke_test.py"],
data = ["//.github/workflows:all_workflows"],
)

# Guard: macOS deployment target (CPPVARIABLES.bzl) must match the floor
# dds3_wheel advertises in its macosx_<floor>_arm64 platform tag.
py_test(
name = "ci_macos_deployment_target_test",
size = "small",
main = "tests/ci_macos_deployment_target_test.py",
srcs = ["tests/ci_macos_deployment_target_test.py"],
data = ["BUILD.bazel", "//:windows_cppopts_config_files"],
)

# Guard: MemorySanitizer config + Linux CI job stay wired together.
py_test(
name = "ci_msan_test",
Expand Down Expand Up @@ -300,18 +330,60 @@ py_test(
],
)

# _dds3 links against the full CPython API (no Py_LIMITED_API/abi3) for the
# CPython version MODULE.bazel pins (python_version = "3.14"); the py_wheel
# defaults (python_tag="py3", abi="none", platform="any") would mislabel this
# compiled extension as a universal pure-Python wheel.
#
# manual: the platform select below has no arm for Linux ARM64 or Intel
# macOS (by design -- see the arm comments), so on those hosts a plain
# `bazelisk build //...`/`bazelisk test //...` would otherwise fail at
# analysis time on this unrequested target. CI builds dds3_wheel_dist
# explicitly by name (see e.g. ci_linux.yml) on its three supported hosts,
# which is unaffected by manual.
py_wheel(
name = "dds3_wheel",
distribution = "dds3",
version = "1.0.0",
tags = ["manual"],
python_tag = "cp314",
abi = "cp314",
platform = select({
Comment thread
zzcgumn marked this conversation as resolved.
Resolved
# CI builds on plain ubuntu-latest with this repo's own hermetic
# LLVM -- no manylinux sysroot or auditwheel step -- so a
# manylinux2014 tag would overclaim glibc-floor portability.
# linux_x86_64 is the honest, non-portable tag for how this is
# actually built. Keyed on the CPU-specific build_linux_x86_64, not
# build_linux (which matches any Linux CPU per
# specs/build-system.md): an aarch64 Linux build has no matching arm
# here and fails closed at analysis time, rather than silently
# mistagging an ARM extension as x86_64.
"//:build_linux_x86_64": "linux_x86_64",
# Keyed on the CPU-specific build_macos_arm64, not build_macos
# (which matches any macOS CPU per specs/build-system.md): an
# x86_64 mac build has no matching arm here and fails closed at
# analysis time, the same fail-closed behavior build_windows
# already has for non-x86_64, rather than silently mistagging.
# 11.0 is enforced, not assumed: CPPVARIABLES.bzl sets
# -mmacosx-version-min=11.0 for both compile and link on
# build_macos/debug_build_macos, so the .so's actual LC_BUILD_VERSION
# minos matches this tag (verified via `otool -l`) rather than
# floating with whatever SDK the runner's Xcode happens to default
# to. Guarded by ci_macos_deployment_target_test.
"//:build_macos_arm64": "macosx_11_0_arm64",
Comment thread
zzcgumn marked this conversation as resolved.
Resolved
"//:build_windows": "win_amd64",
}),
deps = [":dds3_lib", ":_dds3_in_package"],
strip_path_prefixes = ["python/"],
entry_points = {},
)

# manual for the same reason as dds3_wheel above: it wraps dds3_wheel, whose
# platform select fails closed (no arm) on Linux ARM64 or Intel macOS.
py_wheel_dist(
name = "dds3_wheel_dist",
out = "dist",
wheel = ":dds3_wheel",
tags = ["manual"],
)

Loading
Loading