diff --git a/README.md b/README.md index a0362ed..63982a4 100644 --- a/README.md +++ b/README.md @@ -38,25 +38,27 @@ cd pycapnp pip install . ``` -If you wish to install using the latest upstream C++ Cap'n Proto: +By default, the setup script will automatically use the locally installed Cap'n Proto. +If Cap'n Proto is not installed, it will bundle and build the matching Cap'n Proto library. + +To enforce bundling, the Cap'n Proto library: ```bash -pip install \ - --install-option "--libcapnp-url" \ - --install-option "https://github.com/capnproto/capnproto/archive/master.tar.gz" \ - --install-option "--force-bundled-libcapnp" . +pip install . -C force-bundled-libcapnp=True ``` -To force bundled python: +If you wish to install using the latest upstream C++ Cap'n Proto: ```bash -pip install --install-option "--force-bundled-libcapnp" . +pip install . \ + -C force-bundled-libcapnp=True \ + -C libcapnp-url="https://github.com/capnproto/capnproto/archive/master.tar.gz" ``` -Slightly more prompt error messages using distutils rather than pip. +To enforce using the installed Cap'n Proto from the system: ```bash -python setup.py install --force-bundled-libcapnp +pip install . -C force-system-libcapnp=True ``` The bundling system isn't that smart so it might be necessary to clean up the bundled build when changing versions: @@ -92,19 +94,12 @@ pipenv run pytest ### Binary Packages -Building a dumb binary distribution: - -```bash -python setup.py bdist_dumb -``` - -Building a Python wheel distributiion: +Building a Python wheel distributiion ```bash -python setup.py bdist_wheel +pip wheel . ``` - ## Documentation/Example There is some basic documentation [here](http://capnproto.github.io/pycapnp/). diff --git a/_custom_build/backend.py b/_custom_build/backend.py new file mode 100644 index 0000000..768bdb4 --- /dev/null +++ b/_custom_build/backend.py @@ -0,0 +1,31 @@ +import sys + +from setuptools.build_meta import * # noqa: F401, F403 +from setuptools.build_meta import build_wheel + +backend_class = build_wheel.__self__.__class__ + + +class _CustomBuildMetaBackend(backend_class): + def run_setup(self, setup_script="setup.py"): + if self.config_settings: + flags = [] + if self.config_settings.get("force-bundled-libcapnp"): + flags.append("--force-bundled-libcapnp") + if self.config_settings.get("force-system-libcapnp"): + flags.append("--force-system-libcapnp") + if self.config_settings.get("libcapnp-url"): + flags.append("--libcapnp-url") + flags.append(self.config_settings["libcapnp-url"]) + if flags: + sys.argv = sys.argv[:1] + ["build_ext"] + flags + sys.argv[1:] + return super().run_setup(setup_script) + + def build_wheel( + self, wheel_directory, config_settings=None, metadata_directory=None + ): + self.config_settings = config_settings + return super().build_wheel(wheel_directory, config_settings, metadata_directory) + + +build_wheel = _CustomBuildMetaBackend().build_wheel diff --git a/docs/install.rst b/docs/install.rst index 656a8dd..abb81c0 100644 --- a/docs/install.rst +++ b/docs/install.rst @@ -15,8 +15,8 @@ To force rebuilding the pip package from source (you'll need requirments.txt or To force bundling libcapnp (or force system libcapnp), just in case setup.py isn't doing the right thing:: - pip install --no-binary :all: --install-option "--force-bundled-libcapnp" - pip install --no-binary :all: --install-option "--force-system-libcapnp" + pip install --no-binary :all: -C force-bundled-libcapnp=True + pip install --no-binary :all: -C force-system-libcapnp=True If you're using an older Linux distro (e.g. CentOS 6) you many need to set `LDFLAGS="-Wl,--no-as-needed -lrt"`:: @@ -24,7 +24,7 @@ If you're using an older Linux distro (e.g. CentOS 6) you many need to set `LDFL It's also possible to specify the libcapnp url when bundling (this may not work, there be dragons):: - pip install --no-binary :all: --install-option "--force-bundled-libcapnp" --install-option "--libcapnp-url" --install-option "https://github.com/capnproto/capnproto/archive/master.tar.gz" + pip install --no-binary :all: -C force-bundled-libcapnp=True -C libcapnp-url="https://github.com/capnproto/capnproto/archive/master.tar.gz" From Source ----------- diff --git a/pyproject.toml b/pyproject.toml index c829d6d..1551bd2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,7 @@ [build-system] requires = ["setuptools", "wheel", "pkgconfig", "cython<3"] +build-backend = "backend" +backend-path = ["_custom_build"] [tool.pytest.ini_options] asyncio_mode = "auto" diff --git a/setup.cfg b/setup.cfg index 8e5df73..04ef73c 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,3 +1,3 @@ [metadata] -description-file = README.md +description_file = README.md license_files = LICENSE.md diff --git a/setup.py b/setup.py index ef29917..8ba020f 100644 --- a/setup.py +++ b/setup.py @@ -15,10 +15,12 @@ from setuptools import setup, Extension +_this_dir = os.path.dirname(__file__) +sys.path.insert(1, _this_dir) + from buildutils.build import build_libcapnp from buildutils.bundle import fetch_libcapnp -_this_dir = os.path.dirname(__file__) MAJOR = 1 MINOR = 3 @@ -85,26 +87,6 @@ def run(self): shutil.rmtree(x, ignore_errors=True) -# hack to parse commandline arguments -force_bundled_libcapnp = "--force-bundled-libcapnp" in sys.argv -if force_bundled_libcapnp: - sys.argv.remove("--force-bundled-libcapnp") -force_system_libcapnp = "--force-system-libcapnp" in sys.argv -if force_system_libcapnp: - sys.argv.remove("--force-system-libcapnp") -force_cython = "--force-cython" in sys.argv -if force_cython: - sys.argv.remove("--force-cython") - # Always use cython, ignoring option -libcapnp_url = None -try: - libcapnp_url_index = sys.argv.index("--libcapnp-url") - libcapnp_url = sys.argv[libcapnp_url_index + 1] - sys.argv.remove("--libcapnp-url") - sys.argv.remove(libcapnp_url) -except Exception: - pass - from Cython.Distutils import build_ext as build_ext_c # noqa: E402 @@ -113,13 +95,29 @@ class build_libcapnp_ext(build_ext_c): Build capnproto library """ + user_options = build_ext_c.user_options + [ + ("force-bundled-libcapnp", None, "Bundle capnp library into the installer"), + ("force-system-libcapnp", None, "Use system capnp library"), + ("libcapnp-url=", "u", "URL to download libcapnp from (only if bundled)"), + ] + + def initialize_options(self): + build_ext_c.initialize_options(self) + self.force_bundled_libcapnp = None + self.force_system_libcapnp = None + self.libcapnp_url = None + + def finalize_options(self): + # print('The custom option for install is ', self.custom_option) + build_ext_c.finalize_options(self) + def build_extension(self, ext): build_ext_c.build_extension(self, ext) def run(self): # noqa: C901 - if force_bundled_libcapnp: + if self.force_bundled_libcapnp: need_build = True - elif force_system_libcapnp: + elif self.force_system_libcapnp: need_build = False else: # Try to use capnp executable to find include and lib path @@ -167,7 +165,7 @@ def run(self): # noqa: C901 if not os.path.exists(capnp_bin): # Not built, fetch and build - fetch_libcapnp(bundle_dir, libcapnp_url) + fetch_libcapnp(bundle_dir, self.libcapnp_url) build_libcapnp(bundle_dir, build_dir) else: print("capnproto already built at {}".format(build_dir)) diff --git a/tox.ini b/tox.ini index de20c96..2aea657 100644 --- a/tox.ini +++ b/tox.ini @@ -7,10 +7,11 @@ deps= pkgconfig Jinja2 pytest + pytest-asyncio cython<3 commands = - python setup.py install + pip install . py.test {posargs} setenv =