Skip to content

wheels: harden supply chain, slim wheels, rehearse PyPI publish #487

wheels: harden supply chain, slim wheels, rehearse PyPI publish

wheels: harden supply chain, slim wheels, rehearse PyPI publish #487

Workflow file for this run

name: MLIR AIE Distro
permissions:
contents: read
on:
pull_request:
paths:
- '.github/workflows/mlirAIEDistro.yml'
workflow_dispatch:
inputs:
DEBUG_ENABLED:
description: 'Run the build with tmate debugging enabled (https://github.com/marketplace/actions/debugging-with-tmate)'
type: boolean
required: false
default: false
DEBUG_OS:
description: 'which runner os to run the tmate action in (if the tmate action is run)'
type: string
default: 'windows-2022'
required: false
DEBUG_ARCH:
description: 'which runner arch to run the tmate action in (if the tmate action is run)'
type: string
default: 'x86_64'
required: false
DEBUG_DETACHED:
description: 'whether to launch tmate in detached mode (if the tmate action is run)'
type: boolean
required: false
default: true
AIE_COMMIT:
description: 'AIE commit to build'
type: string
required: false
default: ''
concurrency:
# PR runs from the same PR cancel earlier in-flight runs (standard supersede).
# workflow_dispatch serializes per-event so the second publish waits for the
# first — preventing the upload race that PR #2789 worked around with
# `replacesArtifacts: false`.
group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.event.pull_request.number || github.event_name }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
jobs:
get_aie_project_commit:
name: Get canonical AIE Project commit
runs-on: ubuntu-latest
outputs:
AIE_PROJECT_COMMIT: ${{ steps.get_aie_project_commit.outputs.AIE_PROJECT_COMMIT }}
DATETIME: ${{ steps.get_aie_project_commit.outputs.DATETIME }}
steps:
- name: Get AIE-project commit
id: get_aie_project_commit
shell: bash
run: |
if [ x"${{ inputs.AIE_COMMIT }}" == x"" ]; then
sudo apt install jq
if [ x"${{ github.event_name }}" == x"pull_request" ]; then
AIE_PROJECT_COMMIT="${{ github.event.pull_request.head.sha }}"
AIE_PROJECT_COMMIT="${AIE_PROJECT_COMMIT:0:8}"
else
AIE_PROJECT_COMMIT=$(curl -s https://api.github.com/repos/Xilinx/mlir-aie/commits/${{ github.ref_name }} | jq -r '.sha[:8]')
fi
else
AIE_PROJECT_COMMIT="${{ inputs.AIE_COMMIT }}"
fi
echo "AIE_PROJECT_COMMIT=${AIE_PROJECT_COMMIT}" | tee -a $GITHUB_OUTPUT
DATETIME=$(date +"%Y%m%d%H")
echo "DATETIME=${DATETIME}" | tee -a $GITHUB_OUTPUT
build_distro_wheels:
needs: get_aie_project_commit
name: ${{ matrix.OS }} ${{ matrix.ARCH }} rtti=${{ matrix.ENABLE_RTTI }}
continue-on-error: true
runs-on: ${{ matrix.OS }}
permissions:
contents: read
id-token: write
attestations: write
outputs:
MLIR_AIE_WHEEL_VERSION: ${{ steps.get_wheel_version.outputs.MLIR_AIE_WHEEL_VERSION }}
strategy:
fail-fast: false
matrix:
include:
- OS: ubuntu-22.04
ARCH: x86_64
ENABLE_RTTI: ON
- OS: windows-2022
ARCH: AMD64
ENABLE_RTTI: ON
# Disabled because macos mlir wheels are out of date, and we don't currently build for them
# - OS: macos-12
# ARCH: x86_64
# ENABLE_RTTI: ON
# - OS: macos-14
# ARCH: arm64
# ENABLE_RTTI: ON
# disabled because openssl dep isn't being compiled from source
# (and hence system openssl can't be linked against during cross-compile)
# - OS: ubuntu-22.04
# ARCH: aarch64
# ENABLE_RTTI: ON
- OS: ubuntu-22.04
ARCH: x86_64
ENABLE_RTTI: OFF
- OS: windows-2022
ARCH: AMD64
ENABLE_RTTI: OFF
# Disabled because macos mlir wheels are out of date, and we don't currently build for them
# - OS: macos-12
# ARCH: x86_64
# ENABLE_RTTI: OFF
# - OS: macos-14
# ARCH: arm64
# ENABLE_RTTI: OFF
# disabled because openssl dep isn't being compiled from source
# (and hence system openssl can't be linked against during cross-compile)
# - OS: ubuntu-22.04
# ARCH: aarch64
# ENABLE_RTTI: OFF
steps:
- name: set ENV
shell: bash
run: |
PIP_FIND_LINKS_URL="https://github.com/Xilinx/mlir-aie/releases/expanded_assets/mlir-distro"
if [ x"${{ github.event_name }}" == x"pull_request" ]; then
PIP_FIND_LINKS_URL="$PIP_FIND_LINKS_URL https://github.com/Xilinx/mlir-aie/releases/expanded_assets/dev-wheels"
fi
echo "PIP_FIND_LINKS=$PIP_FIND_LINKS_URL" | tee -a $GITHUB_ENV
echo "ENABLE_RTTI=${{ matrix.ENABLE_RTTI }}" | tee -a $GITHUB_ENV
- name: set ENV macos
if: contains(matrix.OS, 'macos')
shell: bash
run: |
echo "OSX_VERSION=$(sw_vers -productVersion)" | tee -a $GITHUB_ENV
- name: Checkout actions
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
# checkout just the actions in order to pick and choose
# where the actual repo is checked out manually (see actions/setup_base)
sparse-checkout: .github/actions
- uses: ./.github/actions/setup_base
id: setup_base
with:
# optional
DEBUG_ENABLED: ${{ inputs.DEBUG_ENABLED }}
DEBUG_OS: ${{ inputs.DEBUG_OS }}
DEBUG_ARCH: ${{ inputs.DEBUG_ARCH }}
DEBUG_DETACHED: ${{ inputs.DEBUG_DETACHED }}
# required
MATRIX_OS: ${{ matrix.OS }}
MATRIX_ARCH: ${{ matrix.ARCH }}
# We don't get OpenSSL for free on Windows. Manage the pain.
# Try vcpkg's GHA cache to avoid building OpenSSL for every matrix element.
- name: Enable vcpkg binary caching
if: ${{ runner.os == 'Windows' }}
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9
with:
script: |
core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL)
core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN)
# Install OpenSSL so bootgen.exe can build against it.
- name: Install OpenSSL
if: ${{ runner.os == 'Windows' }}
shell: pwsh
run: |
$vcpkgRoot = $env:VCPKG_INSTALLATION_ROOT
if ($vcpkgRoot) {
$vcpkg = Join-Path $vcpkgRoot "vcpkg.exe"
} else {
$vcpkg = (Get-Command vcpkg.exe -ErrorAction Stop).Source
$vcpkgRoot = Split-Path -Parent $vcpkg
}
Remove-Item Env:VCPKG_ROOT -ErrorAction SilentlyContinue
$env:VCPKG_BINARY_SOURCES = "clear;x-gha,readwrite"
& $vcpkg install openssl:x64-windows-static
"OPENSSL_ROOT_DIR=$($vcpkgRoot.Replace('\','/'))/installed/x64-windows-static" |
Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
- uses: ./.github/actions/setup_ccache
id: setup_ccache
with:
MATRIX_OS: ${{ matrix.OS }}
MATRIX_ARCH: ${{ matrix.ARCH }}
EXTRA_KEY: mlir-aie-distro-rtti-${{ matrix.ENABLE_RTTI }}
- name: Shift workspace root
id: workspace_root
shell: bash
working-directory: ${{ env.TEMP }}
run: |
ls "${{ steps.setup_base.outputs.WORKSPACE_ROOT }}"
if [ x"${{ runner.os }}" == x"Windows" ]; then
WORKSPACE_ROOT="${{ steps.setup_base.outputs.WORKSPACE_ROOT }}\utils\mlir_aie_wheels"
else
WORKSPACE_ROOT="${{ steps.setup_base.outputs.WORKSPACE_ROOT }}/utils/mlir_aie_wheels"
fi
echo "WORKSPACE_ROOT=$WORKSPACE_ROOT" | tee -a $GITHUB_OUTPUT
- name: Get AIE
id: get_aie
working-directory: ${{ steps.workspace_root.outputs.WORKSPACE_ROOT }}
shell: bash
run: |
AIE_REPO="${{ github.event.pull_request.head.repo.full_name || github.repository }}"
git clone --recursive https://github.com/${AIE_REPO}.git
pushd mlir-aie
git reset --hard ${{ needs.get_aie_project_commit.outputs.AIE_PROJECT_COMMIT }}
git submodule update
popd
- name: Copy clone-llvm.sh for wheel build
working-directory: ${{ steps.workspace_root.outputs.WORKSPACE_ROOT }}
shell: bash
run: cp ../clone-llvm.sh .
- name: Compute wheel version on host
id: wheel_version
shell: bash
working-directory: ${{ steps.workspace_root.outputs.WORKSPACE_ROOT }}
env:
REF_TYPE: ${{ github.ref_type }}
REF_NAME: ${{ github.ref_name }}
run: |
set -euo pipefail
if [[ "${REF_TYPE}" == "tag" && "${REF_NAME}" == v* ]]; then
VERSION="${REF_NAME#v}"
else
VERSION=$(AIE_WHEEL_KEEP_LOCAL=1 python _version_helper.py)
fi
if [[ -z "${VERSION}" ]]; then
echo "::error::computed wheel version is empty" >&2
exit 1
fi
if ! [[ "${VERSION}" =~ ^[A-Za-z0-9][A-Za-z0-9.+_-]*$ ]]; then
echo "::error::computed wheel version contains unexpected characters: ${VERSION}" >&2
exit 1
fi
echo "Computed AIE_WHEEL_VERSION=${VERSION}"
echo "version=${VERSION}" >> "${GITHUB_OUTPUT}"
# build
- name: build distro wheels
if: ${{ matrix.OS != 'ubuntu-22.04' || matrix.ARCH != 'aarch64' }}
shell: bash
working-directory: ${{ steps.workspace_root.outputs.WORKSPACE_ROOT }}
run: |
export PIP_NO_BUILD_ISOLATION=false
if [ x"${{ runner.os }}" == x"Windows" ]; then
export CMAKE_ARGS="-DOPENSSL_USE_STATIC_LIBS=TRUE"
fi
CIBW_ARCHS=${{ matrix.ARCH }} \
CMAKE_GENERATOR=Ninja \
DATETIME=${{ needs.get_aie_project_commit.outputs.DATETIME }} \
HOST_CCACHE_DIR=${{ steps.setup_ccache.outputs.HOST_CCACHE_DIR }} \
CIBW_CONTAINER_ENGINE_ARGS="-v ${{ steps.setup_ccache.outputs.HOST_CCACHE_DIR }}:/host${{ steps.setup_ccache.outputs.HOST_CCACHE_DIR }}" \
AIE_PROJECT_COMMIT=${{ needs.get_aie_project_commit.outputs.AIE_PROJECT_COMMIT }} \
AIE_WHEEL_KEEP_LOCAL=1 \
AIE_WHEEL_VERSION=${{ steps.wheel_version.outputs.version }} \
MATRIX_OS=${{ matrix.OS }} \
PARALLEL_LEVEL=2 \
cibuildwheel --output-dir wheelhouse
- name: Repair wheels (Windows)
if: ${{ runner.os == 'Windows' }}
shell: pwsh
working-directory: ${{ steps.workspace_root.outputs.WORKSPACE_ROOT }}
run: |
python -m pip install --upgrade pip
pip install --require-hashes -r ci-tools.lock
$opensslBin = Join-Path $env:OPENSSL_ROOT_DIR "bin"
New-Item -ItemType Directory -Force -Path wheelhouse\repaired_wheel | Out-Null
$wheels = Get-ChildItem wheelhouse\mlir_aie*.whl | ForEach-Object { $_.FullName }
python -m delvewheel repair --ignore-existing --analyze-existing-exes --add-path "$opensslBin" -w wheelhouse\repaired_wheel $wheels
Remove-Item wheelhouse\mlir_aie*.whl -Force
Move-Item wheelhouse\repaired_wheel\*.whl wheelhouse\
Remove-Item wheelhouse\repaired_wheel -Recurse -Force
- name: build aarch ubuntu wheel
if: ${{ matrix.OS == 'ubuntu-22.04' && matrix.ARCH == 'aarch64' }}
working-directory: ${{ steps.workspace_root.outputs.WORKSPACE_ROOT }}
shell: bash
run: |
# https://askubuntu.com/a/729214
pushd /usr/include/openssl
sudo ln -s /usr/include/x86_64-linux-gnu/openssl/opensslconf.h opensslconf.h
popd
export PIP_NO_BUILD_ISOLATION=false
pip install --upgrade pip
pip install --require-hashes -r requirements.lock
pip install --require-hashes -r python/requirements_dev.lock
CIBW_ARCHS=${{ matrix.ARCH }} MATRIX_OS=${{ matrix.OS }} ./scripts/download_mlir.sh
CIBW_ARCHS=${{ matrix.ARCH }} \
CMAKE_GENERATOR=Ninja \
DATETIME=${{ needs.get_aie_project_commit.outputs.DATETIME }} \
AIE_PROJECT_COMMIT=${{ needs.get_aie_project_commit.outputs.AIE_PROJECT_COMMIT }} \
AIE_WHEEL_KEEP_LOCAL=1 \
AIE_WHEEL_VERSION=${{ steps.wheel_version.outputs.version }} \
MATRIX_OS=${{ matrix.OS }} \
PARALLEL_LEVEL=2 \
pip wheel . -v -w wheelhouse --no-build-isolation
- name: Validate wheel metadata
working-directory: ${{ steps.workspace_root.outputs.WORKSPACE_ROOT }}
shell: bash
run: |
python -m pip install --require-hashes -r ci-tools.lock
python -m twine check --strict wheelhouse/*.whl
- name: Generate build provenance attestation
if: github.event_name != 'pull_request'
uses: actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32 # v4.1.0
with:
subject-path: ${{ steps.workspace_root.outputs.WORKSPACE_ROOT }}/wheelhouse/*.whl
- name: Clean
working-directory: ${{ steps.workspace_root.outputs.WORKSPACE_ROOT }}
shell: bash
run: |
rm -rf mlir-aie
rm -rf build
- name: Docker prune
if: contains(inputs.MATRIX_OS, 'ubuntu')
shell: bash
run: |
docker system prune -a -f
- name: Get wheel version
id: get_wheel_version
working-directory: ${{ steps.workspace_root.outputs.WORKSPACE_ROOT }}
shell: bash
run: |
python -m pip install --upgrade pip
pip install --require-hashes -r ci-tools.lock
WHL=$(ls wheelhouse/mlir_aie*whl)
echo "MLIR_AIE_WHEEL_VERSION=$(python -c "import pkginfo; w = pkginfo.Wheel('$WHL'); print(w.version.split('+')[0] + '+' + w.version.split('+')[1].rsplit('.', 1)[-1])")" | tee -a $GITHUB_OUTPUT
- name: Download cache from container ubuntu
if: (matrix.OS == 'ubuntu-22.04' && matrix.ARCH == 'x86_64') && (success() || failure())
working-directory: ${{ steps.workspace_root.outputs.WORKSPACE_ROOT }}
shell: bash
run: |
ccache -s
HOST_CCACHE_DIR="$(ccache --get-config cache_dir)"
rm -rf $HOST_CCACHE_DIR
mv ./wheelhouse/.ccache $HOST_CCACHE_DIR
ls -la $HOST_CCACHE_DIR
ccache -s
# For whatever reason, the timestamps on all of the files that come out of the docker container
# are some amount ahead in time (maybe 12 hours?). that means if you try to rebuild at any point
# within that window ccache will not hit because the timestamps of the cached objects are ahead of
# your build time. I'm not 100% sure about this explanation/mechanism but this fixed ccache misses for me.
- name: Reset datetime ccache
working-directory: ${{ steps.workspace_root.outputs.WORKSPACE_ROOT }}
shell: bash
run: |
ccache --print-stats
HOST_CCACHE_DIR="$(ccache --get-config cache_dir)"
# Set the timestamp to the beginning of the current hour.
find $HOST_CCACHE_DIR -exec touch -a -m -t 201108231405.14 {} \;
# The important parts of the wheels (all the LLVM/MLIR archives) have nothing to do with the
# python version. With py3-none you can pip install them in any python venv. Unfortunately though this does
# mean that the python bindings themselves will confusingly not work in other envs (!=3.12)
- name: rename non-windows
if: ${{ matrix.OS == 'ubuntu-22.04' || matrix.OS == 'macos-12' || matrix.OS == 'macos-14' }}
working-directory: ${{ steps.workspace_root.outputs.WORKSPACE_ROOT }}
shell: bash
run: |
rename 's/cp312-cp312/py3-none/' wheelhouse/mlir_aie*whl
if [ x"${{ matrix.OS }}" == x"ubuntu-22.04" ] && [ x"${{ matrix.ARCH }}" == x"aarch64" ]; then
rename 's/x86_64/aarch64/' wheelhouse/mlir_aie*whl
fi
- name: rename windows
if: ${{ runner.os == 'Windows' }}
working-directory: ${{ steps.workspace_root.outputs.WORKSPACE_ROOT }}
run: |
ls wheelhouse/mlir_aie*whl | Rename-Item -NewName {$_ -replace 'cp312-cp312', 'py3-none' }
- name: Upload distro wheels
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
path: ${{ steps.workspace_root.outputs.WORKSPACE_ROOT }}/wheelhouse/*.whl
name: build_artifact_${{ matrix.OS }}_${{ matrix.ARCH }}_rtti_${{ matrix.ENABLE_RTTI }}
smoke_test_wheels:
name: test ${{ matrix.OS }} ${{ matrix.ARCH }} rtti=${{ matrix.ENABLE_RTTI }}
needs: build_distro_wheels
runs-on: ${{ matrix.OS }}
strategy:
fail-fast: false
matrix:
include:
- OS: ubuntu-22.04
ARCH: x86_64
ENABLE_RTTI: ON
- OS: windows-2022
ARCH: AMD64
ENABLE_RTTI: ON
- OS: ubuntu-22.04
ARCH: x86_64
ENABLE_RTTI: OFF
- OS: windows-2022
ARCH: AMD64
ENABLE_RTTI: OFF
steps:
- name: Checkout reqs
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
sparse-checkout: |
python/requirements.txt
python/requirements_dev.txt
python/requirements_dev.lock
utils/mlir_aie_wheels/vendor_eudsl.py
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
with:
name: build_artifact_${{ matrix.OS }}_${{ matrix.ARCH }}_rtti_${{ matrix.ENABLE_RTTI }}
path: dist
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6
with:
python-version: '3.12'
- name: test
shell: bash
run: |
python -m pip install --upgrade pip
python utils/mlir_aie_wheels/vendor_eudsl.py \
--requirements python/requirements.txt \
--install-non-eudsl
pip install --require-hashes -r python/requirements_dev.lock
unzip -o -q dist/mlir_aie*py3-none*.whl
export PYTHONPATH=mlir_aie/python
python -c 'import aie.ir'
python -c 'import aie.extras'
python -c 'import aie.helpers'
upload_wheels:
needs: smoke_test_wheels
runs-on: ubuntu-latest
permissions:
id-token: write
contents: write
strategy:
fail-fast: false
matrix:
include:
- OS: ubuntu-22.04
ARCH: x86_64
ENABLE_RTTI: ON
# - OS: ubuntu-22.04
# ARCH: aarch64
# ENABLE_RTTI: ON
- OS: windows-2022
ARCH: AMD64
ENABLE_RTTI: ON
- OS: ubuntu-22.04
ARCH: x86_64
ENABLE_RTTI: OFF
# - OS: ubuntu-22.04
# ARCH: aarch64
# ENABLE_RTTI: OFF
- OS: windows-2022
ARCH: AMD64
ENABLE_RTTI: OFF
steps:
- name: Checkout rehearsal script + ci-tools.lock
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
sparse-checkout: |
utils/mlir_aie_wheels/scripts/pypi_rehearsal.sh
utils/mlir_aie_wheels/ci-tools.lock
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
with:
# unpacks default artifact into dist/
# if `name: artifact` is omitted, the action will create extra parent dir
name: build_artifact_${{ matrix.OS }}_${{ matrix.ARCH }}_rtti_${{ matrix.ENABLE_RTTI }}
path: dist
# See mlirDistro.yml for the rationale: a PEP 427 build tag makes the
# uploaded asset name unique per CI run so concurrent uploads cannot
# collide. Skipped on workflow_dispatch so the canonical `latest-wheels`
# release keeps deterministic filenames.
- name: Inject build tag for non-canonical wheel uploads
if: github.event_name != 'workflow_dispatch'
shell: bash
working-directory: dist
run: |
shopt -s nullglob
wheels=( *.whl )
if [ ${#wheels[@]} -eq 0 ]; then
echo "::error::No wheels found in dist/; cannot inject build tag."
exit 1
fi
BUILD_TAG="${{ github.run_id }}_${{ github.run_attempt }}"
for w in "${wheels[@]}"; do
newname=$(echo "$w" | sed -E "s/-(py3-none-[^-]+)\.whl$/-${BUILD_TAG}-\1.whl/")
if [ "$w" != "$newname" ]; then mv "$w" "$newname"; fi
done
ls -la
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6
with:
python-version: '3.12'
- name: PyPI publish rehearsal
shell: bash
run: |
python -m pip install --require-hashes -r utils/mlir_aie_wheels/ci-tools.lock
bash utils/mlir_aie_wheels/scripts/pypi_rehearsal.sh dist dist_stripped \
'mlirAIEDistro / ${{ matrix.OS }} ${{ matrix.ARCH }} rtti=${{ matrix.ENABLE_RTTI }}'
- name: Release current commit
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }}
uses: ncipollo/release-action@a2e71bdd4e7dab70ca26a852f29600c98b33153e # v1.12.0
with:
artifacts: "dist/*.whl"
token: "${{ secrets.GITHUB_TOKEN }}"
tag: ${{ github.event_name == 'workflow_dispatch' && 'latest-wheels' || 'dev-wheels' }}
name: ${{ github.event_name == 'workflow_dispatch' && 'latest-wheels' || 'dev-wheels' }}
removeArtifacts: false
allowUpdates: true
replacesArtifacts: false
omitBodyDuringUpdate: true
makeLatest: false