name: Nightly Build on: schedule: # Run at 2 AM UTC every day - cron: '0 2 * * *' workflow_dispatch: inputs: force_build: description: 'Force nightly build' required: false default: 'true' publish_test_pypi: description: 'Publish to Test PyPI' required: false type: boolean default: false permissions: contents: write env: MAJOR: '4' MINOR: '15' PATCH: '7' jobs: # ============================================================================ # BUILD STAGE # ============================================================================ mac-build-x64: name: "Mac Build x64" runs-on: macos-latest timeout-minutes: 90 steps: - name: Checkout code uses: actions/checkout@v6.0.2 - name: Setup Python uses: actions/setup-python@v6 with: python-version: '3.x' - name: Build run: python scripts/mk_unix_dist.py --dotnet-key=$GITHUB_WORKSPACE/resources/z3.snk --arch=x64 - name: Upload artifact uses: actions/upload-artifact@v6 with: name: macOsBuild path: dist/*.zip retention-days: 2 mac-build-arm64: name: "Mac ARM64 Build" runs-on: macos-latest timeout-minutes: 90 steps: - name: Checkout code uses: actions/checkout@v6.0.2 - name: Setup Python uses: actions/setup-python@v6 with: python-version: '3.x' - name: Build run: python scripts/mk_unix_dist.py --dotnet-key=$GITHUB_WORKSPACE/resources/z3.snk --arch=arm64 - name: Upload artifact uses: actions/upload-artifact@v6 with: name: MacArm64 path: dist/*.zip retention-days: 2 # ============================================================================ # VALIDATION STAGE # ============================================================================ validate-macos-headerpad-x64: name: "Validate macOS x64 dylib headerpad" needs: [mac-build-x64] runs-on: macos-latest timeout-minutes: 15 steps: - name: Checkout code uses: actions/checkout@v6.0.2 - name: Download macOS x64 Build uses: actions/download-artifact@v7.0.0 with: name: macOsBuild path: artifacts - name: Extract build run: | cd artifacts unzip z3-*-x64-osx*.zip Z3_DIR=$(find . -maxdepth 1 -type d -name "z3-*" | head -n 1) echo "Z3_DIR=$Z3_DIR" >> $GITHUB_ENV - name: Test install_name_tool with headerpad run: | cd artifacts/$Z3_DIR/bin # Get the original install name ORIGINAL_NAME=$(otool -D libz3.dylib | tail -n 1) echo "Original install name: $ORIGINAL_NAME" # Create a test path with same length as typical setup-z3 usage # This simulates what setup-z3 does: changing to absolute path TEST_PATH="/Users/runner/hostedtoolcache/z3/latest/x64/z3-test-dir/bin/libz3.dylib" # Try to change the install name - this will fail if headerpad is insufficient install_name_tool -id "$TEST_PATH" -change "$ORIGINAL_NAME" "$TEST_PATH" libz3.dylib # Verify the change was successful NEW_NAME=$(otool -D libz3.dylib | tail -n 1) echo "New install name: $NEW_NAME" if [ "$NEW_NAME" = "$TEST_PATH" ]; then echo "✓ install_name_tool succeeded - headerpad is sufficient" else echo "✗ install_name_tool failed to update install name" exit 1 fi validate-macos-headerpad-arm64: name: "Validate macOS ARM64 dylib headerpad" needs: [mac-build-arm64] runs-on: macos-latest timeout-minutes: 15 steps: - name: Checkout code uses: actions/checkout@v6.0.2 - name: Download macOS ARM64 Build uses: actions/download-artifact@v7.0.0 with: name: MacArm64 path: artifacts - name: Extract build run: | cd artifacts unzip z3-*-arm64-osx*.zip Z3_DIR=$(find . -maxdepth 1 -type d -name "z3-*" | head -n 1) echo "Z3_DIR=$Z3_DIR" >> $GITHUB_ENV - name: Test install_name_tool with headerpad run: | cd artifacts/$Z3_DIR/bin # Get the original install name ORIGINAL_NAME=$(otool -D libz3.dylib | tail -n 1) echo "Original install name: $ORIGINAL_NAME" # Create a test path with same length as typical setup-z3 usage # This simulates what setup-z3 does: changing to absolute path TEST_PATH="/Users/runner/hostedtoolcache/z3/latest/arm64/z3-test-dir/bin/libz3.dylib" # Try to change the install name - this will fail if headerpad is insufficient install_name_tool -id "$TEST_PATH" -change "$ORIGINAL_NAME" "$TEST_PATH" libz3.dylib # Verify the change was successful NEW_NAME=$(otool -D libz3.dylib | tail -n 1) echo "New install name: $NEW_NAME" if [ "$NEW_NAME" = "$TEST_PATH" ]; then echo "✓ install_name_tool succeeded - headerpad is sufficient" else echo "✗ install_name_tool failed to update install name" exit 1 fi ubuntu-build: name: "Ubuntu build" runs-on: ubuntu-latest timeout-minutes: 90 steps: - name: Checkout code uses: actions/checkout@v6.0.2 - name: Setup Python uses: actions/setup-python@v6 with: python-version: '3.x' - name: Build run: python scripts/mk_unix_dist.py --dotnet-key=$GITHUB_WORKSPACE/resources/z3.snk - name: Clone z3test run: git clone https://github.com/z3prover/z3test z3test - name: Test run: python z3test/scripts/test_benchmarks.py build-dist/z3 z3test/regressions/smt2 - name: Upload artifact uses: actions/upload-artifact@v6 with: name: UbuntuBuild path: dist/*.zip retention-days: 2 ubuntu-arm64: name: "Ubuntu ARM64 build" runs-on: ubuntu-latest timeout-minutes: 90 steps: - name: Checkout code uses: actions/checkout@v6.0.2 - name: Setup Python uses: actions/setup-python@v6 with: python-version: '3.x' - name: Download ARM toolchain run: curl -L -o /tmp/arm-toolchain.tar.xz 'https://developer.arm.com/-/media/Files/downloads/gnu/13.3.rel1/binrel/arm-gnu-toolchain-13.3.rel1-x86_64-aarch64-none-linux-gnu.tar.xz' - name: Extract ARM toolchain run: | mkdir -p /tmp/arm-toolchain/ tar xf /tmp/arm-toolchain.tar.xz -C /tmp/arm-toolchain/ --strip-components=1 - name: Build run: | export PATH="/tmp/arm-toolchain/bin:/tmp/arm-toolchain/aarch64-none-linux-gnu/libc/usr/bin:$PATH" echo $PATH stat /tmp/arm-toolchain/bin/aarch64-none-linux-gnu-gcc python scripts/mk_unix_dist.py --nodotnet --arch=arm64 - name: Upload artifact uses: actions/upload-artifact@v6 with: name: UbuntuArm64 path: dist/*.zip retention-days: 2 ubuntu-doc: name: "Ubuntu Doc build" runs-on: ubuntu-latest timeout-minutes: 90 steps: - name: Checkout code uses: actions/checkout@v6.0.2 - name: Setup Python uses: actions/setup-python@v6 with: python-version: '3.x' - name: Install dependencies run: | pip3 install importlib-resources sudo apt-get update sudo apt-get install -y ocaml opam libgmp-dev doxygen graphviz - name: Setup OCaml run: | opam init -y eval $(opam config env) opam install zarith ocamlfind -y - name: Build run: | eval $(opam config env) python scripts/mk_make.py --ml cd build make -j3 make -j3 examples make -j3 test-z3 cd .. - name: Generate documentation run: | eval $(opam config env) cd doc python3 mk_api_doc.py --mld --z3py-package-path=../build/python/z3 python3 mk_params_doc.py mkdir -p api/html/ml ocamldoc -html -d api/html/ml -sort -hide Z3 -I $(ocamlfind query zarith) -I ../build/api/ml ../build/api/ml/z3enums.mli ../build/api/ml/z3.mli cd .. - name: Create documentation archive run: zip -r z3doc.zip doc/api - name: Upload artifact uses: actions/upload-artifact@v6 with: name: UbuntuDoc path: z3doc.zip retention-days: 2 manylinux-python-amd64: name: "Python bindings (manylinux AMD64)" runs-on: ubuntu-latest timeout-minutes: 90 container: quay.io/pypa/manylinux_2_28_x86_64:latest steps: - name: Checkout code uses: actions/checkout@v6.0.2 - name: Setup Python environment run: | /opt/python/cp38-cp38/bin/python -m venv $PWD/env echo "$PWD/env/bin" >> $GITHUB_PATH - name: Install build tools run: pip install build git+https://github.com/rhelmot/auditwheel - name: Build wheels run: cd src/api/python && python -m build && AUDITWHEEL_PLAT= auditwheel repair --best-plat dist/*.whl && cd ../../.. - name: Test wheels run: pip install ./src/api/python/wheelhouse/*.whl && python - release_files.txt gh release create Nightly \ --title "Nightly" \ --notes "Automated nightly build from commit ${{ github.sha }}" \ --prerelease \ --target ${{ github.sha }} \ $(cat release_files.txt | tr '\n' ' ') publish-test-pypi: name: "Publish to test.PyPI" if: ${{ github.event.inputs.publish_test_pypi == 'true' }} needs: [python-package] runs-on: ubuntu-latest environment: pypi permissions: id-token: write contents: read steps: - name: Download Python packages uses: actions/download-artifact@v7.0.0 with: name: PythonPackages path: dist - name: Publish to PyPI uses: pypa/gh-action-pypi-publish@release/v1 with: packages-dir: dist repository-url: https://test.pypi.org/legacy/