Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
25 changes: 24 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,29 @@ jobs:
name: ${{ matrix.py }}-${{ matrix.platform.wheel_tag }}
path: ./wheelhouse/*.whl

build_pyodide:
name: Build Pyodide wheel
needs: build_sdist
runs-on: ubuntu-latest
steps:
- name: Download source distribution
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: source
- name: Unpack source distribution
run: tar --strip-components 1 -xvf *.tar.gz
- name: Build and test wheel
uses: pypa/cibuildwheel@294735312765b09d24a2fbec22660ce817587d55 # v4.1.0
env:
CIBW_PLATFORM: pyodide
CIBW_BUILD: cp314-pyodide_wasm32
CIBW_TEST_COMMAND: >-
python -c "import pypcode; assert pypcode.Context('x86:LE:64:default').translate(b'\xc3').ops"
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: cp314-pyodide_wasm32
path: ./wheelhouse/*.whl

build_docs:
name: Build docs
runs-on: ubuntu-latest
Expand Down Expand Up @@ -152,7 +175,7 @@ jobs:

upload_pypi:
name: Upload wheels to PyPI
needs: [lint, build_docs, build_sdist, build_wheels, upload_coverage]
needs: [lint, build_docs, build_sdist, build_wheels, build_pyodide, upload_coverage]
environment:
name: pypi
url: https://pypi.org/p/pypcode
Expand Down
64 changes: 37 additions & 27 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,21 +1,27 @@
cmake_minimum_required(VERSION 3.18...3.22)
project(pypcode)
find_package(Python COMPONENTS Interpreter Development.Module REQUIRED)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.14)

option(PYPCODE_BUILD_EXTENSION "Build the Python extension" ON)
option(PYPCODE_BUILD_SLEIGH "Build the SLEIGH compiler" ON)

if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build." FORCE)
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo")
endif()

# Detect the installed nanobind package and import it into CMake
execute_process(
COMMAND "${Python_EXECUTABLE}" -c "import nanobind; print(nanobind.cmake_dir())"
OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE NB_DIR)
list(APPEND CMAKE_PREFIX_PATH "${NB_DIR}")
find_package(nanobind CONFIG REQUIRED)
if(PYPCODE_BUILD_EXTENSION)
find_package(Python COMPONENTS Interpreter Development.Module REQUIRED)

# Detect the installed nanobind package and import it into CMake
execute_process(
COMMAND "${Python_EXECUTABLE}" -c "import nanobind; print(nanobind.cmake_dir())"
OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE NB_DIR)
list(APPEND CMAKE_PREFIX_PATH "${NB_DIR}")
find_package(nanobind CONFIG REQUIRED)
endif()

if(MSVC)
add_compile_options(/O2 /D_HAS_STD_BYTE=0 /DLOCAL_ZLIB=1 /DNO_GZIP=1)
Expand Down Expand Up @@ -58,27 +64,31 @@ set(SLEIGH_COMMON
pypcode/sleigh/xml.cc
)

add_executable(sleigh
pypcode/sleigh/filemanage.cc
pypcode/sleigh/slgh_compile.cc
pypcode/sleigh/slghparse.cc
pypcode/sleigh/slghscan.cc
${SLEIGH_COMMON}
${ZLIB}
)
install(TARGETS sleigh DESTINATION bin)
if(PYPCODE_BUILD_SLEIGH)
add_executable(sleigh
pypcode/sleigh/filemanage.cc
pypcode/sleigh/slgh_compile.cc
pypcode/sleigh/slghparse.cc
pypcode/sleigh/slghscan.cc
${SLEIGH_COMMON}
${ZLIB}
)
install(TARGETS sleigh DESTINATION bin)
endif()

nanobind_add_module(pypcode_native
pypcode/pypcode_native.cpp
${SLEIGH_COMMON}
${ZLIB}
)
if(PYPCODE_BUILD_EXTENSION)
nanobind_add_module(pypcode_native
pypcode/pypcode_native.cpp
${SLEIGH_COMMON}
${ZLIB}
)

if(DEFINED ENV{COVERAGE} AND NOT "$ENV{COVERAGE}" STREQUAL "")
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
target_compile_options(pypcode_native PRIVATE --coverage -O0 -g)
target_link_options(pypcode_native PRIVATE --coverage -O0 -g)
if(DEFINED ENV{COVERAGE} AND NOT "$ENV{COVERAGE}" STREQUAL "")
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
target_compile_options(pypcode_native PRIVATE --coverage -O0 -g)
target_link_options(pypcode_native PRIVATE --coverage -O0 -g)
endif()
endif()
endif()

install(TARGETS pypcode_native DESTINATION .)
install(TARGETS pypcode_native DESTINATION .)
endif()
59 changes: 52 additions & 7 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
#!/usr/bin/env python3
import json
import os
from pathlib import Path
import platform
import shutil
import struct
import subprocess
import sys

from setuptools import setup
from setuptools.command.build_ext import build_ext

Expand All @@ -27,7 +29,10 @@ def run(self):
cross_compiling_for_macos_amd64 = (
platform.system() == "Darwin" and platform.machine() != "x86_64" and "x86_64" in os.getenv("ARCHFLAGS", "")
)
cross_compiling = cross_compiling_for_macos_arm64 or cross_compiling_for_macos_amd64
cross_compiling_for_emscripten = os.getenv("_PYTHON_HOST_PLATFORM", "").startswith("emscripten")
cross_compiling = (
cross_compiling_for_macos_arm64 or cross_compiling_for_macos_amd64 or cross_compiling_for_emscripten
)

root_dir = Path(__file__).parent.absolute()
target_build_dir = root_dir / "build" / "native"
Expand All @@ -51,7 +56,16 @@ def run(self):
cmake_build_args += ["--config", "Release"]

target_cmake_config_args = cmake_config_args[::]
if cross_compiling:
if cross_compiling_for_emscripten:
import nanobind # pylint: disable=import-error,import-outside-toplevel

pywasmcross_args = json.loads(os.environ["PYWASMCROSS_ARGS"])
target_cmake_config_args += [
f"-DPython_INCLUDE_DIR={pywasmcross_args['pythoninclude']}",
f"-Dnanobind_DIR={nanobind.cmake_dir()}",
"-DPYPCODE_BUILD_SLEIGH=OFF",
]
if cross_compiling_for_macos_arm64 or cross_compiling_for_macos_amd64:
target_cmake_config_args += [
"-DCMAKE_OSX_DEPLOYMENT_TARGET=10.14",
"-DCMAKE_OSX_ARCHITECTURES=" + os.getenv("ARCHFLAGS"),
Expand All @@ -64,20 +78,51 @@ def run(self):

if cross_compiling:
# Also build a host version of sleigh to process .sla files
host_cmake_config_args = cmake_config_args
subprocess.check_call(["cmake", "-S", ".", "-B", host_build_dir] + host_cmake_config_args, cwd=root_dir)
host_cmake_config_args = ["-DPYPCODE_BUILD_EXTENSION=OFF"]
host_cmake = "cmake"
host_env = None
if cross_compiling_for_emscripten:
wrapper_dir = os.environ["COMPILER_WRAPPER_DIR"]
host_path = os.pathsep.join(
path for path in os.environ["PATH"].split(os.pathsep) if path != wrapper_dir
)
host_cmake = shutil.which("cmake", path=host_path)
if host_cmake is None:
raise RuntimeError("Could not find the host CMake executable")
host_env = os.environ.copy()
host_env["PATH"] = host_path
for name in (
"AR",
"CC",
"CFLAGS",
"CMAKE_CROSSCOMPILING_EMULATOR",
"CMAKE_TOOLCHAIN_FILE",
"CXX",
"CXXFLAGS",
"LD",
"LDFLAGS",
"RANLIB",
):
host_env.pop(name, None)
subprocess.check_call(
[host_cmake, "-S", ".", "-B", host_build_dir] + host_cmake_config_args,
cwd=root_dir,
env=host_env,
)
subprocess.check_call(
["cmake", "--build", host_build_dir, "--parallel", "--verbose", "--target", "sleigh"]
[host_cmake, "--build", host_build_dir, "--parallel", "--verbose", "--target", "sleigh"]
+ cmake_build_args,
cwd=root_dir,
env=host_env,
)

# Install extension and sleigh binary into target package
if cross_compiling:
# Note: Manually install because cmake install step may refuse to install binaries for foreign architectures
install_pkg_bin_dir.mkdir(exist_ok=True)
ext_path = next(target_build_dir.glob("pypcode_native.*"))
shutil.copy(target_build_dir / sleigh_filename, install_pkg_bin_dir / sleigh_filename)
if not cross_compiling_for_emscripten:
install_pkg_bin_dir.mkdir(exist_ok=True)
shutil.copy(target_build_dir / sleigh_filename, install_pkg_bin_dir / sleigh_filename)
shutil.copy(ext_path, install_pkg_root_dir / ext_path.name)
else:
subprocess.check_call(["cmake", "--install", target_build_dir], cwd=root_dir)
Expand Down
Loading