diff --git a/.github/workflows/build_wheels.yml b/.github/workflows/build_wheels.yml index b9ca769..e62fa26 100644 --- a/.github/workflows/build_wheels.yml +++ b/.github/workflows/build_wheels.yml @@ -44,6 +44,12 @@ jobs: with: python-version: "3.11" + - name: Vendor pelfy + run: | + git clone --depth 1 https://github.com/Nonannet/pelfy.git /tmp/pelfy + mkdir -p src/${{ github.event.repository.name }}/_vendor + cp -r /tmp/pelfy/pelfy src/${{ github.event.repository.name }}/_vendor/ + # Only needed for Linux ARM builds - name: Set up QEMU if: runner.os == 'Linux' diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0fd9d89..438baae 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,6 +30,42 @@ jobs: name: musl-object-files path: /object_files/musl_objects_*.*o + build-package-test: + needs: [build_stencils] + runs-on: ubuntu-latest + + strategy: + matrix: + python-version: ["3.12"] + + steps: + - name: Check out code + uses: actions/checkout@v4 + + - uses: actions/download-artifact@v4 + with: + name: stencil-object-files + path: src/copapy/obj + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + + - name: Install Python dependencies + run: | + python -m pip install -e . + python -m pip install pytest + + - name: Vendor pelfy + run: | + git clone --depth 1 https://github.com/Nonannet/pelfy.git /tmp/pelfy + mkdir -p src/${{ github.event.repository.name }}/_vendor + cp -r /tmp/pelfy/pelfy src/${{ github.event.repository.name }}/_vendor/ + + - name: Run tests with pytest + run: pytest -m "not runner" + build-ubuntu: needs: [build_stencils] runs-on: ubuntu-latest diff --git a/pyproject.toml b/pyproject.toml index ac0d2b9..37612d2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -13,7 +13,6 @@ classifiers = [ "Operating System :: OS Independent", ] dependencies = [ - "pelfy>=1.0.7" ] [project.urls] @@ -34,13 +33,15 @@ copapy = ["obj/*.o", "py.typed"] dev = [ "ruff", "mypy", - "pytest" + "pytest", + "pelfy>=1.0.7" ] doc_build = [ "sphinx", "pydata_sphinx_theme", "sphinx-autodoc-typehints", - "myst-parser" + "myst-parser", + "pelfy>=1.0.7" ] [tool.mypy] diff --git a/src/copapy/_stencils.py b/src/copapy/_stencils.py index 1c57374..3d78e83 100644 --- a/src/copapy/_stencils.py +++ b/src/copapy/_stencils.py @@ -1,10 +1,17 @@ from dataclasses import dataclass -from pelfy import open_elf_file, elf_file, elf_symbol -from typing import Generator, Literal, Iterable -import pelfy +from typing import Generator, Literal, Iterable, TYPE_CHECKING import struct import platform +if TYPE_CHECKING: + import pelfy +else: + try: + from ._vendor import pelfy + except ImportError: + import pelfy + + ByteOrder = Literal['little', 'big'] @@ -62,7 +69,7 @@ def detect_process_arch() -> str: return arch_family -def get_return_function_type(symbol: elf_symbol) -> str: +def get_return_function_type(symbol: pelfy.elf_symbol) -> str: if symbol.relocations: for reloc in reversed(symbol.relocations): func_name = reloc.symbol.name @@ -71,7 +78,7 @@ def get_return_function_type(symbol: elf_symbol) -> str: return 'void' -def get_stencil_position(func: elf_symbol) -> tuple[int, int]: +def get_stencil_position(func: pelfy.elf_symbol) -> tuple[int, int]: start_index = 0 # There must be no prolog # Find last relocation in function last_instr = get_last_call_in_function(func) @@ -84,7 +91,7 @@ def get_stencil_position(func: elf_symbol) -> tuple[int, int]: return start_index, end_index -def get_last_call_in_function(func: elf_symbol) -> int: +def get_last_call_in_function(func: pelfy.elf_symbol) -> int: # Find last relocation in function assert func.relocations, f'No call function in stencil function {func.name}.' reloc = func.relocations[-1] @@ -95,7 +102,7 @@ def get_last_call_in_function(func: elf_symbol) -> int: return reloc.fields['r_offset'] - func.fields['st_value'] + address_field_length - instruction_lengths -def get_op_after_last_call_in_function(func: elf_symbol) -> int: +def get_op_after_last_call_in_function(func: pelfy.elf_symbol) -> int: # Find last relocation in function assert func.relocations, f'No call function in stencil function {func.name}.' reloc = func.relocations[-1] @@ -120,9 +127,9 @@ class stencil_database(): obj_file: path to the ELF object file or bytes of the ELF object file """ if isinstance(obj_file, str): - self.elf = open_elf_file(obj_file) + self.elf = pelfy.open_elf_file(obj_file) else: - self.elf = elf_file(obj_file) + self.elf = pelfy.elf_file(obj_file) self.stencil_definitions = {s.name: get_return_function_type(s) for s in self.elf.symbols