Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added cross platform support #1

Merged
merged 27 commits into from
Mar 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions .gitattributes

This file was deleted.

95 changes: 78 additions & 17 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
@@ -1,36 +1,97 @@
name: Build

on: [push, pull_request]
env:
# WARNING: If you update this also update it in the pyproject.toml
BINARYEN_VERSION: 117
# WARNING: If you update this also update it in the pyproject.toml

# env:
# CIBW_PROJECT_REQUIRES_PYTHON: ">=3.12"
# CIBW_ARCHS_MACOS:
# CIBW_ARCHS_WINDOWS:
# CIBW_ARCHS_LINUX:
# CIBW_ARCHS: auto
on:
workflow_dispatch:
pull_request:
push:
branches:
- main
release:
types:
- published

jobs:
build_wheels:
name: Build wheels on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-20.04, windows-2019, macos-11]
# macos-13 is an intel runner, macos-14 is apple silicon
os: [ubuntu-latest, windows-latest, macos-13, macos-14]

steps:
- uses: actions/checkout@v4

- name: Install macOS Dependencies
if: runner.os == 'macOS'
run: 'brew install ninja'

- name: Install Windows Dependencies
if: runner.os == 'Windows'
run: 'choco install wget -y'

- name: Restore cached libbinaryen
if: runner.os != 'Linux'
id: cache-libbinaryen-restore
uses: actions/cache/restore@v4
with:
path: ./binaryen/libbinaryen
key: ${{ matrix.os }}-${{ runner.os }}-${{ runner.arch }}-v${{env.BINARYEN_VERSION}}-libbinaryen

- name: Build wheels
uses: pypa/cibuildwheel@v2.16.5
# env:
# CIBW_SOME_OPTION: value
# ...
# with:
# package-dir: .
# output-dir: wheelhouse
# config-file: "{package}/pyproject.toml"

- name: Cache libbinaryen
id: cache-libbinaryen-save
uses: actions/cache/save@v4
if: ${{steps.cache-libbinaryen-restore.outputs.cache-hit != 'true' && runner.os != 'Linux'}}
with:
path: ./binaryen/libbinaryen
key: ${{steps.cache-libbinaryen-restore.outputs.cache-primary-key}}

- uses: actions/upload-artifact@v4
with:
name: binaryen-py-${{ matrix.os }}-${{ strategy.job-index }}
path: ./wheelhouse/*.whl

build_sdist:
name: Build source distribution
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Link Binaryen
run: bash ./scripts/build_libbinaryen.sh

- name: Build sdist
run: pipx run build --sdist

- uses: actions/upload-artifact@v4
with:
name: cibw-wheels-${{ matrix.os }}-${{ strategy.job-index }}
path: ./wheelhouse/*.whl
name: binaryen-py-sdist
path: dist/*.tar.gz

create_release:
name: Create Release
needs: [build_wheels, build_sdist]
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/download-artifact@v4
with:
pattern: binaryen-py-*
path: dist
merge-multiple: true
- name: Create Release
uses: softprops/action-gh-release@v1
if: startsWith(github.ref, 'refs/tags/')
with:
draft: true
files: dist/*
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
.vscode
.DS_Store

binaryen/TODO.h
dist/
wheelhouse/
binaryen/libbinaryen/*
binaryen/_binaryen.*

Expand Down
47 changes: 0 additions & 47 deletions BUILD.md

This file was deleted.

9 changes: 0 additions & 9 deletions CHANGELOG.md

This file was deleted.

65 changes: 64 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,72 @@ Install through PyPI.
pip install binaryen.py
```

Windows, Mac (Intel & ARM) and Linux (manylinux, musllinux) are supported.

### Build from source

1. (If upgrading binaryen version) Update `BINARYEN_VERSION` in `pyproject.toml` and `.github/workflows/build.yaml`
2. Run `bash scripts/build_libbinaryen.sh`
3. Run `python -m pip install -e .`, `cibuildwheel`, `python -m pip wheel .`, or whichever supported build command you would prefer

## How To Use

Reference the [Binaryen header file](https://github.com/WebAssembly/binaryen/blob/main/src/binaryen-c.h) to understand how to use Binaryen. This package makes no significant changes to the Binaryen API, apart from creating more pythonic objects for Modules, Expressions and Functions.
```py

# Equivalent python function
def add(x, y):
return x + y

func_inputs = binaryen.type.create([Int32, Int32])

mod = binaryen.Module()
mod.add_function(
b"add",
func_inputs,
Int32,
[Int32],
mod.block(
None,
[
mod.local_set(
2,
mod.binary(
binaryen.operations.AddInt32(),
mod.local_get(0, Int32),
mod.local_get(1, Int32),
),
),
mod.Return(mod.local_get(2, Int32)),
],
TypeNone,
),
)

mod.add_function_export(b"add", b"add")

mod.optimize()

mod.print()
```

Results in the following Wasm

```wasm
(module
(type $0 (func (param i32 i32) (result i32)))
(export "add" (func $add))
(func $add (; has Stack IR ;) (param $0 i32) (param $1 i32) (result i32)
(i32.add
(local.get $0)
(local.get $1)
)
)
)
```

Reference the [Binaryen header file](https://github.com/WebAssembly/binaryen/blob/main/src/binaryen-c.h) to understand how to use Binaryen. This package makes no significant changes to how Binaryen is used. The majority of the work this module does is interoperating between C and Python and creating more pythonic classes for Modules, Expressions and Functions.

For more examples see [examples](examples/).

## Missing Functions

Expand Down
6 changes: 3 additions & 3 deletions binaryen/__type_builder.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
from ._binaryen import lib, ffi
from ._binaryen import ffi, lib
from .internals import (
BinaryenExpressionId,
BinaryenType,
BinaryenPackedType,
BinaryenHeapType,
BinaryenPackedType,
BinaryenType,
)

type_builder_errors = {
Expand Down
55 changes: 43 additions & 12 deletions binaryen/binaryen_build.py
Original file line number Diff line number Diff line change
@@ -1,27 +1,58 @@
import cffi
import os
import platform
from pathlib import Path

root_path = os.environ["BINARYEN_PY_ROOT"]
import cffi

host_platform = platform.system().lower()
if host_platform == "darwin":
host_platform = "macos"

host_machine = platform.machine().lower()

if host_platform == "windows" and host_machine == "amd64":
host_machine = "x86_64"

root_path_override = os.environ.get("BINARYEN_PY_ROOT")

print("==== BUILD ====")
print(f"Building binaryen.py for {host_machine}-{host_platform}")

file_path = Path(__file__).resolve().parent.parent
root_path = Path(file_path) / f"binaryen/libbinaryen/{host_machine}-{host_platform}/"

if root_path_override is not None:
root_path = Path(root_path_override).resolve()
print(f"INFO: Overriding root path to {root_path.absolute()}")

if root_path is None:
raise RuntimeError("Set BINARYEN_PY_ROOT environment variable to the root folder of binaryen.py")

def valid(path):
return "valid" if path else "INVALID!"

lib_path = (Path(root_path)/"binaryen/libbinaryen")
cdef_path = (Path(root_path)/"binaryen/libbinaryen/binaryen-c.c")

if not lib_path.is_dir():
raise RuntimeError("Cannot find libbinaryen folder, is BINARYEN_PY_ROOT set correctly?")
include_path = root_path / "include"
cdef_path = include_path / "binaryen-c.c"
header_path = include_path / "binaryen-c.h"
wasm_path = include_path / "wasm-delegations.def"
lib_path = root_path / "lib"

if not cdef_path.is_file():
raise RuntimeError("Cannot find binaryen-c.c, have you run create_cdef.py?")
print("== Paths ==")
print(f"include {valid(include_path.is_dir())} {include_path.absolute()}")
print(f"binaryen-c.h {valid(header_path.is_file())} {header_path.absolute()}")
print(f"delegations {valid(wasm_path.is_file())} {wasm_path.absolute()}")
print(f"binaryen-c.c {valid(cdef_path.is_file())} {cdef_path.absolute()}")

lib_path = str(lib_path)
print(f"lib {valid(lib_path.is_dir())} {lib_path.absolute()}")

ffibuilder = cffi.FFI()
ffibuilder.set_source("binaryen._binaryen", "#include \"binaryen-c.h\"", libraries=["binaryen"], library_dirs=[lib_path], include_dirs=[lib_path], language="c++")
ffibuilder.set_source(
"binaryen._binaryen",
'#include "binaryen-c.h"',
libraries=["binaryen"],
library_dirs=[str(lib_path.absolute())],
include_dirs=[str(include_path.absolute())],
language="c++",
)

with open(cdef_path, "r", encoding="utf-8") as file:
cdef = file.read()
Expand Down
2 changes: 1 addition & 1 deletion binaryen/internals.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,4 @@ class __BaseType:
BinaryenExternalKind = __NewType("BinaryenExternalKind", __BaseType)
BinaryenOp = __NewType("BinaryenOp", __BaseType)
BinaryenLiteral = __NewType("BinaryenLiteral", __BaseType)
BinaryenGlobalRef = __NewType("BinaryenGlobalRef", __BaseType)
BinaryenGlobalRef = __NewType("BinaryenGlobalRef", __BaseType)
2 changes: 1 addition & 1 deletion binaryen/type/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from .. import internals as __internals
from .._binaryen import ffi as __ffi
from .._binaryen import lib as __lib
from . import array_type, heap_type, struct_type, signature_type
from . import array_type, heap_type, signature_type, struct_type

# These "types" are actually integers representing the type
# e.g. none = 0, i32 = 2 etc.
Expand Down
Binary file removed dist/binaryen.py-117.0.0a1-LINUXX8664.tar.gz
Binary file not shown.
Binary file removed dist/binaryen.py-117.0.0a1-MACARM.tar.gz
Binary file not shown.
Binary file removed dist/binaryen.py-117.0.0a1-WINDOWSX8664.tar.gz
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
33 changes: 0 additions & 33 deletions examples/add.c

This file was deleted.

Loading
Loading