diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 32fc485..4cd64cb 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -2,7 +2,7 @@ name: python-tests on: push: - branches: [main, py_wheel] + branches: [main, py_wheel*] release: types: [published] @@ -82,9 +82,16 @@ jobs: - windows-latest - ubuntu-latest build-target: - - py310 - - py311 - - py312-stable-api + - cp310-cp310 + - cp311-cp311 + - cp312-abi3 + include: + - build-target: cp310-cp310 + python-version: "3.10" + - build-target: cp311-cp311 + python-version: "3.11" + - build-target: cp312-abi3 + python-version: "3.12" continue-on-error: true steps: - name: Checkout @@ -95,7 +102,7 @@ jobs: - name: Setup Python uses: actions/setup-python@v5 with: - python-version: ${{ matrix.build-target == 'py310' && '3.10' || matrix.build-target == 'py311' && '3.11' || '3.12' }} + python-version: ${{ matrix.python-version }} cache: "pip" cache-dependency-path: pyproject.toml @@ -123,17 +130,17 @@ jobs: git clone https://github.com/microsoft/vcpkg.git "${{ github.workspace }}/.vcpkg" ls "${{ github.workspace }}/.vcpkg" - - name: Install libyaml-cpp (Linux) - if: runner.os == 'Linux' - run: | - sudo apt-get update - sudo apt-get install -y build-essential gcc g++ libyaml-cpp0.8 libyaml-cpp-dev + # - name: Install libyaml-cpp (Linux) + # if: runner.os == 'Linux' + # run: | + # sudo apt-get update + # sudo apt-get install -y build-essential gcc g++ libyaml-cpp0.8 libyaml-cpp-dev - - name: Set compiler env (Linux) - if: runner.os == 'Linux' - run: | - echo "CC=gcc" >> "$GITHUB_ENV" - echo "CXX=g++" >> "$GITHUB_ENV" + # - name: Set compiler env (Linux) + # if: runner.os == 'Linux' + # run: | + # echo "CC=gcc" >> "$GITHUB_ENV" + # echo "CXX=g++" >> "$GITHUB_ENV" - name: Install libyaml-cpp (macOS) if: runner.os == 'macOS' @@ -172,38 +179,28 @@ jobs: if: runner.os == 'Linux' uses: pypa/cibuildwheel@v2.23.0 env: - CIBW_BUILD: ${{ matrix.build-target == 'py310' && 'cp310-manylinux_x86_64' || matrix.build-target == 'py311' && 'cp311-manylinux_x86_64' || 'cp312-manylinux_x86_64' }} + CIBW_BUILD: ${{ matrix.build-target == 'cp310-cp310' && 'cp310-manylinux_x86_64' || matrix.build-target == 'cp311-cp311' && 'cp311-manylinux_x86_64' || 'cp312-manylinux_x86_64' }} CIBW_SKIP: "*-musllinux_*" CIBW_MANYLINUX_X86_64_IMAGE: manylinux_2_28 + CIBW_CONFIG_SETTINGS: ${{ matrix.build-target == 'cp312-abi3' && 'wheel.py-api=cp312' || 'wheel.py-api=' }} CIBW_BEFORE_ALL_LINUX: | dnf install -y git gcc gcc-c++ make zip unzip tar curl perl git clone https://github.com/microsoft/vcpkg.git /project/.vcpkg /project/.vcpkg/bootstrap-vcpkg.sh -disableMetrics CIBW_ENVIRONMENT_LINUX: >- VCPKG_ROOT=/project/.vcpkg - ${{ matrix.build-target == 'py312-stable-api' && 'SKBUILD_WHEEL_PY_API=cp312' || '' }} SKBUILD_CMAKE_DEFINE="CMAKE_TOOLCHAIN_FILE=/project/.vcpkg/scripts/buildsystems/vcpkg.cmake;QRET_BUILD_PYTHON=ON;QRET_PYTHON_WITH_ALGORITHM=ON" with: package-dir: . output-dir: dist - - name: Build wheel (non-stable API, non-Linux) - if: runner.os != 'Linux' && matrix.build-target != 'py312-stable-api' - env: - SKBUILD_CMAKE_DEFINE: "CMAKE_TOOLCHAIN_FILE=${{env.VCPKG_ROOT}}/scripts/buildsystems/vcpkg.cmake;QRET_BUILD_PYTHON=ON;QRET_PYTHON_WITH_ALGORITHM=ON" - run: | - python -m pip install --upgrade pip build pytest coverage wheel numpy - python -m build --wheel - shell: bash - - - name: Build wheel (stable API, non-Linux) - if: runner.os != 'Linux' && matrix.build-target == 'py312-stable-api' + - name: Build wheel (non-Linux) + if: runner.os != 'Linux' env: - SKBUILD_WHEEL_PY_API: "cp312" SKBUILD_CMAKE_DEFINE: "CMAKE_TOOLCHAIN_FILE=${{env.VCPKG_ROOT}}/scripts/buildsystems/vcpkg.cmake;QRET_BUILD_PYTHON=ON;QRET_PYTHON_WITH_ALGORITHM=ON" run: | python -m pip install --upgrade pip build pytest coverage wheel numpy - python -m build --wheel + python -m build --wheel -Cwheel.py-api=${{ matrix.build-target == 'cp312-abi3' && 'cp312' || '' }} shell: bash - name: Embed newsynth binary and LICENSE files into wheel @@ -223,11 +220,67 @@ jobs: # Copy downloaded license files. find "$PWD/externals/newsynth-license" -mindepth 1 -maxdepth 1 -type f -exec cp {} "$pkg_dir/" \; + # Remove unexpected top-level lib64 directory from the wheel payload. + rm -rf "$wheel_dir/lib64" + rm -f "$wheel_file" python -m wheel pack "$wheel_dir" -d dist ls -la "$pkg_dir" shell: bash + - name: Validate wheel filename and extension tags + run: | + wheel_file=$(ls dist/*.whl) + wheel_name=$(basename "$wheel_file") + echo "Built wheel: $wheel_name" + + expected_tag="${{ matrix.build-target }}-" + + if [[ "$wheel_name" != *"$expected_tag"* ]]; then + echo "Unexpected wheel ABI tag for ${{ matrix.build-target }}." + echo "Actual filename: $wheel_name" + echo "Expected filename to contain: $expected_tag" + exit 1 + fi + + check_dir="dist/wheel-check" + rm -rf "$check_dir" + mkdir -p "$check_dir" + python -m zipfile -e "$wheel_file" "$check_dir" + + target_tag="${{ matrix.build-target }}" + py_tag="${target_tag%%-*}" + abi_tag="${target_tag#*-}" + py_major_minor="${py_tag#cp}" + py_major="${py_major_minor:0:1}" + py_minor="${py_major_minor:1}" + cpython_tag="cpython-${py_major}${py_minor}" + found_ext=0 + + while IFS= read -r ext_file; do + found_ext=1 + ext_name=$(basename "$ext_file") + echo "Found extension stub: $ext_name" + if [[ "$ext_name" == *"$abi_tag"* || "$ext_name" == *"$py_tag"* || "$ext_name" == *"$cpython_tag"* ]]; then + continue + fi + + if [[ "${{ runner.os }}" == "Windows" && "$ext_name" == *.pyd ]]; then + echo "Accepting untagged Windows extension stub: $ext_name" + continue + fi + + echo "Extension stub tag mismatch for ${{ matrix.build-target }}: $ext_name" + echo "Expected extension filename to contain one of: $abi_tag, $py_tag, $cpython_tag" + exit 1 + done < <(find "$check_dir" -type f \( -name "*.so" -o -name "*.dylib" -o -name "*.lib" -o -name "*.pyd" \)) + + if [ "$found_ext" -eq 0 ]; then + echo "No extension stub (*.so/*.dylib/*.lib/*.pyd) found in wheel." + exit 1 + fi + shell: bash + - name: Upload Python artifacts if: always() uses: actions/upload-artifact@v4 @@ -330,7 +383,7 @@ jobs: - name: Download wheel artifact uses: actions/download-artifact@v4 with: - name: pyqret-wheel-${{ matrix.os }}-${{ matrix.python-version == '3.10' && 'py310' || matrix.python-version == '3.11' && 'py311' || 'py312-stable-api' }} + name: pyqret-wheel-${{ matrix.os }}-${{ matrix.python-version == '3.10' && 'cp310-cp310' || matrix.python-version == '3.11' && 'cp311-cp311' || 'cp312-abi3' }} path: dist - name: Install wheel