diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 61b4a0ac4a..2d6560c1f8 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -8,22 +8,38 @@ jobs: fail-fast: false matrix: include: + # CPython builds - target: x86_64-pc-windows-msvc os: windows-2022 arch: x64 - + python-impl: cpython + python-version: "3.12" - target: i686-pc-windows-msvc os: windows-2022 arch: x86 - + python-impl: cpython + python-version: "3.12" - target: x86_64-apple-darwin os: macos-13 arch: x64 - + python-impl: cpython + python-version: "3.12" - target: aarch64-apple-darwin os: macos-13 arch: x64 - + python-impl: cpython + python-version: "3.12" + # PyPy builds + - target: x86_64-pc-windows-msvc + os: windows-2022 + arch: x64 + python-impl: pypy + python-version: "pypy3.10" + - target: x86_64-apple-darwin + os: macos-13 + arch: x64 + python-impl: pypy + python-version: "pypy3.10" runs-on: ${{ matrix.os }} steps: - name: Check out repository @@ -39,23 +55,22 @@ jobs: with: toolchain: nightly components: rustfmt - + - name: Install Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: - python-version: "3.12" + python-version: ${{ matrix.python-version }} architecture: ${{ matrix.arch }} - name: Install Python packages run: pip install -r python/requirements.txt - name: Build wheel - run: make TARGET=${{ matrix.target }} - + run: make TARGET=${{ matrix.target }} PYTHON_IMPL=${{ matrix.python-impl }} - name: Upload wheel uses: actions/upload-artifact@v4 with: - name: pyxel-${{ matrix.target }} + name: pyxel-${{ matrix.python-impl }}-${{ matrix.target }} path: dist/* build-linux: @@ -63,17 +78,37 @@ jobs: fail-fast: false matrix: include: + # CPython builds - target: x86_64-unknown-linux-gnu image: messense/manylinux2014-cross:x86_64 + python-impl: cpython + python-version: "3.12" - target: i686-unknown-linux-gnu image: messense/manylinux2014-cross:i686 + python-impl: cpython + python-version: "3.12" - target: aarch64-unknown-linux-gnu image: messense/manylinux2014-cross:aarch64 + python-impl: cpython + python-version: "3.12" - target: armv7-unknown-linux-gnueabihf image: messense/manylinux2014-cross:armv7l + python-impl: cpython + python-version: "3.12" + + # PyPy builds + - target: x86_64-unknown-linux-gnu + image: messense/manylinux2014-cross:x86_64 + python-impl: pypy + python-version: "pypy3.10" + + - target: armv7-unknown-linux-gnueabihf + image: messense/manylinux2014-cross:armv7l + python-impl: pypy + python-version: "pypy3.10" runs-on: ubuntu-22.04 container: ${{ matrix.image }} @@ -94,13 +129,12 @@ jobs: components: rustfmt - name: Install Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: - python-version: "3.12" + python-version: ${{ matrix.python-version }} - name: Install Python packages run: pip install -r python/requirements.txt - - name: Build and install SDL2 run: | SDL2_VERSION=2.0.10 @@ -123,10 +157,10 @@ jobs: run: | export BINDGENFLAGS="-I/usr/${{ matrix.target }}/include/SDL2 -I/usr/${{ matrix.target }}/${{ matrix.target }}/sysroot/usr/include" export RUSTFLAGS="-L/usr/${{ matrix.target }}/lib" - make TARGET=${{ matrix.target }} + make TARGET=${{ matrix.target }} PYTHON_IMPL=${{ matrix.python-impl }} - name: Upload wheel uses: actions/upload-artifact@v4 with: - name: pyxel-${{ matrix.target }} + name: pyxel-${{ matrix.python-impl }}-${{ matrix.target }} path: dist/* diff --git a/Makefile b/Makefile index 17150ca488..4f59bb379e 100644 --- a/Makefile +++ b/Makefile @@ -61,13 +61,26 @@ WASM_TARGET = wasm32-unknown-emscripten RUSTUP_TOOLCHAIN=nightly-2025-02-01 CLIPPY_OPTS = -q --all-targets --all-features -- --no-deps MATURIN_OPTS = --manylinux 2014 --auditwheel skip +PYTHON_BIN = $(if $(filter pypy,$(PYTHON_IMPL)),pypy3,python3) + +# Set Python implementation (cpython or pypy) +PYTHON_IMPL ?= cpython + +# Add Python implementation to wheel filename for easier identification +ifeq ($(PYTHON_IMPL),pypy) + MATURIN_OPTS += --interpreter pypy3 + WHEEL_PREFIX = pypy +else + WHEEL_PREFIX = cpython +endif + ifeq ($(TARGET),) -ENSURE_TARGET = -BUILD_OPTS = --release + ENSURE_TARGET = + BUILD_OPTS = --release else -ENSURE_TARGET = rustup target add $(TARGET) --toolchain $(RUSTUP_TOOLCHAIN) -BUILD_OPTS = --release --target $(TARGET) + ENSURE_TARGET = rustup target add $(TARGET) --toolchain $(RUSTUP_TOOLCHAIN) + BUILD_OPTS = --release --target $(TARGET) endif .PHONY: \ @@ -103,43 +116,48 @@ build: format @$(ENSURE_TARGET) @$(SCRIPTS_DIR)/generate_readme_abspath @cp LICENSE $(PYTHON_DIR)/pyxel - @cd $(PYTHON_DIR); RUSTUP_TOOLCHAIN=$(RUSTUP_TOOLCHAIN) maturin build -o ../$(DIST_DIR) $(BUILD_OPTS) $(MATURIN_OPTS) + @cd $(PYTHON_DIR); RUSTUP_TOOLCHAIN=$(RUSTUP_TOOLCHAIN) PYTHON_IMPL=$(PYTHON_IMPL) maturin build -o ../$(DIST_DIR) $(BUILD_OPTS) $(MATURIN_OPTS) install: build +ifeq ($(PYTHON_IMPL),pypy) + @pypy3 -m pip install --force-reinstall `ls -rt $(DIST_DIR)/*-$(WHEEL_PREFIX)-*.whl | tail -n 1 || ls -rt $(DIST_DIR)/*.whl | tail -n 1` +else @pip3 install --force-reinstall `ls -rt $(DIST_DIR)/*.whl | tail -n 1` +endif test: install #@cd $(RUST_DIR); cargo test $(BUILD_OPTS) - @python3 -m unittest discover $(RUST_DIR)/pyxel-wrapper/tests - @pyxel run $(EXAMPLES_DIR)/01_hello_pyxel.py - @pyxel run $(EXAMPLES_DIR)/02_jump_game.py - @pyxel run $(EXAMPLES_DIR)/03_draw_api.py - @pyxel run $(EXAMPLES_DIR)/04_sound_api.py - @pyxel run $(EXAMPLES_DIR)/05_color_palette.py - @pyxel run $(EXAMPLES_DIR)/06_click_game.py - @pyxel run $(EXAMPLES_DIR)/07_snake.py - @pyxel run $(EXAMPLES_DIR)/08_triangle_api.py - @pyxel run $(EXAMPLES_DIR)/09_shooter.py - @pyxel run $(EXAMPLES_DIR)/10_platformer.py - @pyxel run $(EXAMPLES_DIR)/11_offscreen.py - @pyxel run $(EXAMPLES_DIR)/12_perlin_noise.py - @pyxel run $(EXAMPLES_DIR)/13_bitmap_font.py - @pyxel run $(EXAMPLES_DIR)/14_synthesizer.py - @pyxel run $(EXAMPLES_DIR)/15_tiled_map_file.py - @pyxel run $(EXAMPLES_DIR)/16_transform.py - @pyxel run $(EXAMPLES_DIR)/99_flip_animation.py - @pyxel play $(EXAMPLES_DIR)/30sec_of_daylight.pyxapp - @pyxel play $(EXAMPLES_DIR)/megaball.pyxapp - @pyxel play $(EXAMPLES_DIR)/8bit-bgm-gen.pyxapp - @pyxel edit $(EXAMPLES_DIR)/assets/sample.pyxres + @$(PYTHON_BIN) -m unittest discover $(RUST_DIR)/pyxel-wrapper/tests + @$(PYTHON_BIN) -m pyxel run $(EXAMPLES_DIR)/01_hello_pyxel.py + @$(PYTHON_BIN) -m pyxel run $(EXAMPLES_DIR)/02_jump_game.py + @$(PYTHON_BIN) -m pyxel run $(EXAMPLES_DIR)/03_draw_api.py + @$(PYTHON_BIN) -m pyxel run $(EXAMPLES_DIR)/04_sound_api.py + @$(PYTHON_BIN) -m pyxel run $(EXAMPLES_DIR)/05_color_palette.py + @$(PYTHON_BIN) -m pyxel run $(EXAMPLES_DIR)/06_click_game.py + @$(PYTHON_BIN) -m pyxel run $(EXAMPLES_DIR)/07_snake.py + @$(PYTHON_BIN) -m pyxel run $(EXAMPLES_DIR)/08_triangle_api.py + @$(PYTHON_BIN) -m pyxel run $(EXAMPLES_DIR)/09_shooter.py + @$(PYTHON_BIN) -m pyxel run $(EXAMPLES_DIR)/10_platformer.py + @$(PYTHON_BIN) -m pyxel run $(EXAMPLES_DIR)/11_offscreen.py + @$(PYTHON_BIN) -m pyxel run $(EXAMPLES_DIR)/12_perlin_noise.py + @$(PYTHON_BIN) -m pyxel run $(EXAMPLES_DIR)/13_bitmap_font.py + @$(PYTHON_BIN) -m pyxel run $(EXAMPLES_DIR)/14_synthesizer.py + @$(PYTHON_BIN) -m pyxel run $(EXAMPLES_DIR)/15_tiled_map_file.py + @$(PYTHON_BIN) -m pyxel run $(EXAMPLES_DIR)/16_transform.py + @$(PYTHON_BIN) -m pyxel run $(EXAMPLES_DIR)/99_flip_animation.py + @$(PYTHON_BIN) -m pyxel play $(EXAMPLES_DIR)/30sec_of_daylight.pyxapp + @$(PYTHON_BIN) -m pyxel play $(EXAMPLES_DIR)/megaball.pyxapp + @$(PYTHON_BIN) -m pyxel play $(EXAMPLES_DIR)/8bit-bgm-gen.pyxapp + @$(PYTHON_BIN) -m pyxel edit $(EXAMPLES_DIR)/assets/sample.pyxres @rm -rf testapp testapp.pyxapp @mkdir -p testapp/assets @cp $(EXAMPLES_DIR)/10_platformer.py testapp @cp $(EXAMPLES_DIR)/assets/platformer.pyxres testapp/assets - @pyxel package testapp testapp/10_platformer.py - @pyxel play testapp.pyxapp + @$(PYTHON_BIN) -m pyxel package testapp testapp/10_platformer.py + @$(PYTHON_BIN) -m pyxel play testapp.pyxapp @rm -rf testapp testapp.pyxapp - @pyxel watch $(EXAMPLES_DIR) $(EXAMPLES_DIR)/01_hello_pyxel.py + @$(PYTHON_BIN) -m pyxel watch $(EXAMPLES_DIR) $(EXAMPLES_DIR)/01_hello_pyxel.py + clean-wasm: @make clean TARGET=$(WASM_TARGET)