diff --git a/.github/workflows/build-and-test-wheels.yml b/.github/workflows/build-and-test-wheels.yml new file mode 100644 index 000000000..5200cd051 --- /dev/null +++ b/.github/workflows/build-and-test-wheels.yml @@ -0,0 +1,183 @@ +name: Build and test Python wheels and make PyPI release + +on: + workflow_dispatch: + push: + paths: + - '.github/workflows/build-wheels.yml' + - 'include/**' + - 'scripts/**' + - 'src/**' + - 'CMakeLists.txt' + - 'setup.py' + - 'pyproject.toml' + branches: [master] + release: + types: [published] + +jobs: + build_wheels: + name: Build wheels on ${{ matrix.os }} + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-22.04, macos-12, macos-14] + fail-fast: false + + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Report OS + run: | + echo ${{ matrix.os }} + echo ${{ runner.os }} + uname -p + + - name: Set up QEMU + if: runner.os == 'Linux' + uses: docker/setup-qemu-action@v2 + with: + platforms: all + + - name: Build manylinux wheels + if: matrix.os == 'ubuntu-22.04' + uses: pypa/cibuildwheel@v2.19.2 + env: + # Configure cibuildwheel to build native archs, and some emulated ones + CIBW_ARCHS_LINUX: x86_64 aarch64 + CIBW_BUILD_VERBOSITY: 1 + + - name: Build macOS Intel wheels + if: matrix.os == 'macos-12' + uses: pypa/cibuildwheel@v2.19.2 + env: + CIBW_ARCHS_MACOS: x86_64 + CIBW_ENVIRONMENT_MACOS: VIZDOOM_MACOS_ARCH=x86_64 HOMEBREW_NO_AUTO_UPDATE=1 HOMEBREW_NO_INSTALL_CLEANUP=1 MACOSX_DEPLOYMENT_TARGET=12.0 + CIBW_BUILD_VERBOSITY: 1 + + - name: Build macOS Apple Silicon wheels + if: matrix.os == 'macos-14' + uses: pypa/cibuildwheel@v2.19.2 + env: + CIBW_ARCHS_MACOS: arm64 + CIBW_ENVIRONMENT_MACOS: VIZDOOM_MACOS_ARCH=arm64 HOMEBREW_NO_AUTO_UPDATE=1 HOMEBREW_NO_INSTALL_CLEANUP=1 MACOSX_DEPLOYMENT_TARGET=14.0 + CIBW_BUILD_VERBOSITY: 1 + + - name: Report built wheels + run: | + ls -l ./wheelhouse/*.whl + + - name: Upload artifacts + uses: actions/upload-artifact@v3 + with: + path: ./wheelhouse/*.whl + + test_wheels: + name: Test wheels on ${{ matrix.os }} + needs: [build_wheels] + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-22.04, ubuntu-24.04, macos-12, macos-13, macos-14] + python-version: ['3.8', '3.9', '3.10', '3.11', '3.12'] + fail-fast: false + + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Set up Python ${{ matrix.python-version }} environment + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + + - name: Download all dists + uses: actions/download-artifact@v3 + with: + # Unpacks default artifact into dist/ + # If `name: artifact` is omitted, the action will create extra parent dir + name: artifact + path: dist + + - name: Report dist directory + run: ls -l dist + + - name: Report environment + run: | + echo ${{ matrix.os }} + echo ${{ runner.os }} + uname -p + python -c "import sys; print(sys.version)" + + - name: Install macOS Intel wheel on ${{ matrix.os }} + if: matrix.os == 'macos-12' || matrix.os == 'macos-13' + run: | + export PYTHON_VERSION=$(python -c "import sys; print(f'{sys.version_info.major}{sys.version_info.minor}')") + export WHEEL=$(ls dist/vizdoom*cp${PYTHON_VERSION}*macosx*x86_64.whl) + python -m pip install ${WHEEL}[test] + + - name: Install macOS Apple Silicon wheel on ${{ matrix.os }} + if: matrix.os == 'macos-14' + run: | + export PYTHON_VERSION=$(python -c "import sys; print(f'{sys.version_info.major}{sys.version_info.minor}')") + export WHEEL=$(ls dist/vizdoom*cp${PYTHON_VERSION}*macosx*arm64.whl) + python -m pip install ${WHEEL}[test] + + - name: Install manylinux wheel on ${{ matrix.os }} + if: matrix.os == 'ubuntu-22.04' || matrix.os == 'ubuntu-24.04' + run: | + export PYTHON_VERSION=$(python -c "import sys; print(f'{sys.version_info.major}{sys.version_info.minor}')") + export WHEEL=$(ls dist/vizdoom*cp${PYTHON_VERSION}*manylinux*x86_64.whl) + python -m pip install ${WHEEL}[test] + + - name: Import check + run: python -c "import vizdoom" + + - name: Run tests + # Skip tests on macOS with Apple Silicon, because they are slow (TODO: investigate) + if: matrix.os != 'macos-14' + run: pytest tests + + build_sdist: + name: Build source distribution + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Build sdist + run: pipx run build --sdist + + - name: Upload sdist + uses: actions/upload-artifact@v3 + with: + path: dist/*.tar.gz + + upload_pypi: + name: Upload to PyPI + needs: [build_wheels, build_sdist, test_wheels] + runs-on: ubuntu-latest + environment: pypi + permissions: + id-token: write + if: github.event_name == 'release' && github.event.action == 'published' + steps: + - name: Download all dists + uses: actions/download-artifact@v3 + with: + # Unpacks default artifact into dist/ + # If `name: artifact` is omitted, the action will create extra parent dir + name: artifact + path: dist + + - name: Publish to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 + with: + password: ${{ secrets.PYPI_API_TOKEN }} + # To test: + # with: + # repository_url: https://test.pypi.org/legacy/ diff --git a/.github/workflows/build-wheels.yml b/.github/workflows/build-wheels.yml deleted file mode 100644 index d0cd8b5cc..000000000 --- a/.github/workflows/build-wheels.yml +++ /dev/null @@ -1,115 +0,0 @@ -name: Build Python wheels and make PyPI release - -on: - workflow_dispatch: - push: - paths: - - '.github/workflows/build-wheels.yml' - - 'include/**' - - 'scripts/**' - - 'src/**' - - 'CMakeLists.txt' - - 'setup.py' - - 'pyproject.toml' - branches: [master] - release: - types: [published] - -jobs: - build_wheels: - name: Build wheels on ${{ matrix.os }} - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-22.04, macos-13, macos-14] - - steps: - - uses: actions/checkout@v4 - with: - submodules: recursive - - - name: Report OS - run: | - echo ${{ matrix.os }} - echo ${{ runner.os }} - uname -p - - - name: Set up QEMU - if: runner.os == 'Linux' - uses: docker/setup-qemu-action@v2 - with: - platforms: all - - - name: Build manylinux wheels - if: matrix.os == 'ubuntu-22.04' - uses: pypa/cibuildwheel@v2.19.2 - env: - # Configure cibuildwheel to build native archs, and some emulated ones - CIBW_ARCHS_LINUX: x86_64 aarch64 - CIBW_BUILD_VERBOSITY: 3 - CIBW_REPAIR_WHEEL_COMMAND_LINUX: > - auditwheel show {wheel} && auditwheel repair -w {dest_dir} {wheel} - - - name: Build macOS Intel wheels - if: matrix.os == 'macos-13' - uses: pypa/cibuildwheel@v2.19.2 - env: - CIBW_ARCHS_MACOS: x86_64 - CIBW_BUILD_VERBOSITY: 3 - - - name: Build macOS Apple Silicon wheels - if: matrix.os == 'macos-14' - uses: pypa/cibuildwheel@v2.19.2 - env: - CIBW_ARCHS_MACOS: arm64 - CIBW_BUILD_VERBOSITY: 3 - - - name: Report built wheels - run: | - ls -l ./wheelhouse/*.whl - - - name: Upload artifacts - uses: actions/upload-artifact@v3 - with: - path: ./wheelhouse/*.whl - - build_sdist: - name: Build source distribution - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - submodules: recursive - - - name: Build sdist - run: pipx run build --sdist - - - name: Upload sdist - uses: actions/upload-artifact@v3 - with: - path: dist/*.tar.gz - - upload_pypi: - name: Upload to PyPI - needs: [build_wheels, build_sdist] - runs-on: ubuntu-latest - environment: pypi - permissions: - id-token: write - if: github.event_name == 'release' && github.event.action == 'published' - steps: - - name: Download all dists - uses: actions/download-artifact@v3 - with: - # Unpacks default artifact into dist/ - # If `name: artifact` is omitted, the action will create extra parent dir - name: artifact - path: dist - - - name: Publish to PyPI - uses: pypa/gh-action-pypi-publish@release/v1 - with: - password: ${{ secrets.PYPI_API_TOKEN }} - # To test: - # with: - # repository_url: https://test.pypi.org/legacy/ diff --git a/cmake_modules/FindSDL2.cmake b/cmake_modules/FindSDL2.cmake index 614426ccc..213fd288a 100644 --- a/cmake_modules/FindSDL2.cmake +++ b/cmake_modules/FindSDL2.cmake @@ -35,7 +35,7 @@ # Modified by Eric Wing. # Added code to assist with automated building by using environmental variables # and providing a more controlled/consistent search behavior. -# Added new modifications to recognize OS X frameworks and +# Added new modifications to recognize macOS frameworks and # additional Unix paths (FreeBSD, etc). # Also corrected the header search path to follow "proper" SDL2 guidelines. # Added a search for SDL2main which is needed by some platforms. @@ -70,6 +70,8 @@ # (To distribute this file outside of CMake, substitute the full # License text for the above reference.) +file(GLOB SDL2_SEARCH_PATHS "/usr/local/Cellar/sdl2/2.*" "/opt/homebrew/Cellar/sdl2/2.*") + FIND_PATH(SDL2_INCLUDE_DIR SDL.h HINTS $ENV{SDL2DIR} @@ -79,10 +81,13 @@ FIND_PATH(SDL2_INCLUDE_DIR SDL.h /Library/Frameworks /usr/local/include/SDL2 /usr/include/SDL2 + /usr/local/Cellar/sdl2 # Brew Intel /sw # Fink + /opt/homebrew/Cellar/sdl2 # Brew Apple Silicon /opt/local # DarwinPorts /opt/csw # Blastwave /opt + ${SDL2_SEARCH_PATHS} # Brew Intel and Apple Silicon with versions ) #MESSAGE("SDL2_INCLUDE_DIR is ${SDL2_INCLUDE_DIR}") @@ -92,18 +97,20 @@ FIND_LIBRARY(SDL2_LIBRARY_TEMP $ENV{SDL2DIR} PATH_SUFFIXES lib64 lib PATHS + /usr/local/Cellar/sdl2 /sw + /opt/homebrew/Cellar/sdl2 /opt/local /opt/csw /opt + ${SDL2_SEARCH_PATHS} ) - #MESSAGE("SDL2_LIBRARY_TEMP is ${SDL2_LIBRARY_TEMP}") IF(NOT SDL2_BUILDING_LIBRARY) IF(NOT ${SDL2_INCLUDE_DIR} MATCHES ".framework") - # Non-OS X framework versions expect you to also dynamically link to - # SDL2main. This is mainly for Windows and OS X. Other (Unix) platforms + # Non-macOS framework versions expect you to also dynamically link to + # SDL2main. This is mainly for Windows and macOS. Other (Unix) platforms # seem to provide SDL2main for compatibility even though they don't # necessarily need it. FIND_LIBRARY(SDL2MAIN_LIBRARY @@ -112,10 +119,13 @@ IF(NOT SDL2_BUILDING_LIBRARY) $ENV{SDL2DIR} PATH_SUFFIXES lib64 lib PATHS + /usr/local/Cellar/sdl2 /sw + /opt/homebrew/Cellar/sdl2 /opt/local /opt/csw /opt + ${SDL2_SEARCH_PATHS} ) ENDIF(NOT ${SDL2_INCLUDE_DIR} MATCHES ".framework") ENDIF(NOT SDL2_BUILDING_LIBRARY) diff --git a/pyproject.toml b/pyproject.toml index 9d6205c2d..afd3457b7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -39,6 +39,7 @@ build = "cp{38,39,310,311,312}-*" [tool.cibuildwheel.linux] # Only manylinux is supported (no musl) build = "cp{38,39,310,311,312}-manylinux*" +repair-wheel-command = "auditwheel show {wheel} && auditwheel repair -w {dest_dir} {wheel}" # For manylinux_2_28 we need to install the following dependencies using yum: before-all = "yum install -y cmake git boost-devel SDL2-devel openal-soft-devel" @@ -50,3 +51,7 @@ manylinux-aarch64-image = "manylinux_2_28" [tool.cibuildwheel.macos] before-all = "brew install cmake boost sdl2 openal-soft" +repair-wheel-command = "delocate-wheel --require-archs {delocate_archs} -w {dest_dir} -v {wheel}" + +# In addition, MACOSX_DEPLOYMENT_TARGET maybe needed to be set depending on the version of macOS +environment = {"HOMEBREW_NO_AUTO_UPDATE" = "1", "HOMEBREW_NO_INSTALL_CLEANUP" = "1"} diff --git a/setup.py b/setup.py index 017746a0b..72a5d51d7 100644 --- a/setup.py +++ b/setup.py @@ -131,6 +131,14 @@ def run(self): f"VIZDOOM_CMAKE_ARGS is set, the following arguments will be added to cmake command: {env_cmake_args}" ) + # MacOS specific flag for specifying the architecture of the binary + if platform.startswith("darwin"): + macos_arch = os.getenv("VIZDOOM_MACOS_ARCH") + if macos_arch is not None: + cmake_arg_list.append(f"-DCMAKE_APPLE_SILICON_PROCESSOR={macos_arch}") + # else: + # cmake_arg_list.append(f"-DCMAKE_APPLE_SILICON_PROCESSOR={os.uname().machine}") + # Windows specific version of the libraries if platform.startswith("win"): generator = os.getenv("VIZDOOM_BUILD_GENERATOR_NAME") @@ -182,7 +190,7 @@ def run(self): os.remove("CMakeCache.txt") cmake_arg_list.append(".") - print(f"Running cmake with arguments: {cmake_arg_list}", file=sys.stderr) + sys.stderr.write(f"Running cmake with arguments: {cmake_arg_list}") try: if platform.startswith("win"):