diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 528f981..f8c9808 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -24,10 +24,14 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-latest] + os: [ubuntu-latest, macos-latest] steps: + - name: Install X11 dependencies (macOS) + if: runner.os == 'macOS' + run: brew install libx11 libxpm pkg-config + - name: install X11 dependencies if: ${{ runner.os == 'Linux' }} run: | @@ -90,7 +94,8 @@ jobs: - name: Download build artifacts from this run uses: actions/download-artifact@v4 with: - name: vmol-wheels-${{ runner.os }}-${{ github.ref_name }}-${{ github.run_number }} + pattern: vmol-wheels-*-${{ github.ref_name }}-${{ github.run_number }} + merge-multiple: true path: dist - name: Publish to TestPyPI diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index b13b176..7d4e1dd 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -1,6 +1,28 @@ name: Build wheels on: + workflow_dispatch: + inputs: + package-dir: + type: string + required: false + default: ./python + output-dir: + type: string + required: false + default: wheelhouse + cibw-build: + type: string + required: false + default: "" + cibw-skip: + type: string + required: false + default: "*-musllinux_*" + upload-artifact: + type: boolean + required: false + default: true workflow_call: inputs: package-dir: @@ -26,8 +48,11 @@ on: jobs: build_wheels: - name: Build wheels - runs-on: ubuntu-latest + name: Build wheels on ${{ matrix.os }} + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, macos-latest] steps: @@ -56,6 +81,12 @@ jobs: env: CIBW_BUILD: ${{ inputs.cibw-build }} CIBW_SKIP: ${{ inputs.cibw-skip }} + CIBW_BEFORE_ALL_MACOS: | + brew install libx11 libxpm pkg-config + CIBW_ENVIRONMENT_MACOS: MACOSX_DEPLOYMENT_TARGET=15.0 + CIBW_REPAIR_WHEEL_COMMAND_MACOS: > + DYLD_LIBRARY_PATH=$(brew --prefix)/lib + delocate-wheel --require-archs {delocate_archs} -w {dest_dir} -v {wheel} CIBW_BEFORE_ALL_LINUX: | if [ -f /etc/alpine-release ]; then # musllinux (Alpine) apk add --no-cache libx11-dev libxpm-dev pkgconf diff --git a/.gitignore b/.gitignore index 9c6ac0f..b5f9e8a 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,4 @@ vmol.egg-info/ python/build python/dist python/src +wheelhouse/ diff --git a/python/setup.py b/python/setup.py index 6da5c76..ade1d46 100644 --- a/python/setup.py +++ b/python/setup.py @@ -1,6 +1,7 @@ from setuptools import setup, Extension import subprocess import os +import sys import tempfile import shutil from pathlib import Path @@ -29,6 +30,32 @@ def rel_posix(path): return os.path.relpath(path, start=setup_dir).replace(os.sep, "/") +def get_x11_config(): + # On Linux, X11 headers/libs are in standard system paths — nothing extra needed. + # On macOS, Homebrew installs them to non-default locations, so we probe for them. + if sys.platform != 'darwin': + return [], [] + try: + inc = subprocess.run( + ['pkg-config', '--cflags-only-I', 'x11', 'xpm'], + check=True, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, text=True, + ).stdout.split() + lib = subprocess.run( + ['pkg-config', '--libs-only-L', 'x11', 'xpm'], + check=True, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, text=True, + ).stdout.split() + return [f[2:] for f in inc if f.startswith('-I')], \ + [f[2:] for f in lib if f.startswith('-L')] + except Exception: + pass + for prefix in ['/opt/homebrew', '/usr/local']: + if Path(f'{prefix}/include/X11/Xlib.h').exists(): + return [f'{prefix}/include'], [f'{prefix}/lib'] + raise RuntimeError( + 'X11 headers not found. Install with: brew install libx11 libxpm pkg-config' + ) + + setup_dir = Path(__file__).parent src_dir = setup_dir.parent / "src" @@ -45,12 +72,15 @@ def rel_posix(path): f'-DBUILD_USER="{os.getenv("USER")}@{os.getenv("HOSTNAME")}"', f'-DBUILD_DIRECTORY="{os.getcwd()}"'] +x11_inc, x11_lib = get_x11_config() + setup( version=get_git_version_hash(), include_package_data=True, ext_modules=[Extension('vmol.v', sources=c_files, - include_dirs=include_dirs, + include_dirs=include_dirs + x11_inc, + library_dirs=x11_lib, libraries = ['X11', 'Xpm'], extra_compile_args=['-std=gnu11', '-O2', ] + VERSION_FLAGS,