7

I have a simple package that includes a C extension. I'm managing my dependencies and build process with Poetry.

When I run poetry build, the extension is compiled and included in the .tar.gz archive but not in the .whl and I don't understand why. Pip installing from the tar.gz archive works as expected but since the wheel is lacking the .so, pip installing the wheel results in an unusable package.

I've lifted the build machinery from here: https://github.com/python-poetry/poetry/issues/2740

pyproject.toml

[tool.poetry]
name = "python_ctypes"
version = "0.1.0"
description = ""
authors = ["Me"]
include = [
    {path = "_extensions/*.so", format = "wheel"}
]

[tool.poetry.dependencies]
python = "^3.9"
numpy = "^1.22.1"

[tool.poetry.dev-dependencies]

[tool.poetry.build]
generate-setup-file = false
script = "build.py"

[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"

build.py

"""Poetry build script for python_ctypes"""
import os
import shutil

from distutils.command.build_ext import build_ext
from distutils.core import Distribution
from distutils.core import Extension
from distutils.errors import CCompilerError
from distutils.errors import DistutilsExecError
from distutils.errors import DistutilsPlatformError


extensions = [
    Extension("python_ctypes._extensions.arraysum", ["python_ctypes/_extensions/arraysum.c"]),
]


class ExtBuilder(build_ext):
    # This class allows C extension building to fail.

    built_extensions = []

    def run(self):
        try:
            build_ext.run(self)
        except (DistutilsPlatformError, FileNotFoundError):
            print("Unable to build the C extensions")

    def build_extension(self, ext):
        try:
            build_ext.build_extension(self, ext)
        except (CCompilerError, DistutilsExecError, DistutilsPlatformError, ValueError):
            print('Unable to build the "{}" C extension, '
                  "python_ctypes will use the pure python version of the extension.".format(ext.name))


def build(setup_kwargs):
    """
    This function is mandatory in order to build the extensions.
    """
    print(setup_kwargs)
    distribution = Distribution({"name": "python_ctypes", "ext_modules": extensions})
    distribution.package_dir = "python_ctypes"

    cmd = ExtBuilder(distribution)
    cmd.ensure_finalized()
    cmd.run()

    # Copy built extensions back to the project
    for output in cmd.get_outputs():
        relative_extension = os.path.relpath(output, cmd.build_lib)
        if not os.path.exists(output):
            continue

        shutil.copyfile(output, relative_extension)
        mode = os.stat(relative_extension).st_mode
        mode |= (mode & 0o444) >> 2
        os.chmod(relative_extension, mode)

    return setup_kwargs


if __name__ == "__main__":
    build({})
medley56
  • 1,181
  • 1
  • 14
  • 29
  • 1
    I'm an idiot. I had the wrong path in my `include` in my pyproject.toml. It works. I wish this stuff was documented in the Poetry docs though. – medley56 Mar 01 '22 at 23:50

0 Answers0