* Use cibuildwheel in ci `cibuildwheel` is a system that automatically compiles and repairs wheels for many python versions and architectures at once. This has some advantages vs the old situation: - Macosx wheels had inconsistent minimum versions ranging between 10.9 and 11.0. I'm not sure why this happens, but for some users this means they have to build from source on macosx. With cibuildwheel, the build is consistent, with 10.9 as the minimum for x86 and 11.0 for arm64. - Consolidation between the packaging tests and manylinux tests. - Addition of musllinux targets and additional cross-compilation to ppc64le and s390x. - With cibuildwheel, new python versions should be automatically picked up. - Separation of the sdist build and lint checks. There is not reason to run that many times. All possible build targets succeed, except for ARM64 on Windows. The upstream capnp build fails. I've disabled it. The cross-compilation builds on linux are pretty slow. This could potentially be sped up by separating the builds of manylinux and musllinux, but I'm not sure if it's worth the extra complexity. (One can also contemplate disabling these targets.) Tests for macosx arm64 cannot be run (but also couldn't be run in the previous system. This should be remedied once apple silicon becomes available on the CI. I've also added some commented-out code that can automatically take care of uploading a build to PyPi when a release is created. One might contemplate using this. * Set CMAKE_OSX_ARCHITECTURES for arm64 and disable universal2
263 lines
8.2 KiB
Python
263 lines
8.2 KiB
Python
#!/usr/bin/env python
|
|
"""
|
|
pycapnp distutils setup.py
|
|
"""
|
|
|
|
import glob
|
|
import os
|
|
import shutil
|
|
import struct
|
|
import sys
|
|
|
|
import pkgconfig
|
|
|
|
from distutils.command.clean import clean as _clean
|
|
|
|
from setuptools import setup, Extension
|
|
|
|
from buildutils.build import build_libcapnp
|
|
from buildutils.bundle import fetch_libcapnp
|
|
|
|
_this_dir = os.path.dirname(__file__)
|
|
|
|
MAJOR = 1
|
|
MINOR = 3
|
|
MICRO = 0
|
|
TAG = ""
|
|
VERSION = "%d.%d.%d%s" % (MAJOR, MINOR, MICRO, TAG)
|
|
|
|
|
|
# Write version info
|
|
def write_version_py(filename=None):
|
|
"""
|
|
Generate pycapnp version
|
|
"""
|
|
cnt = """\
|
|
from .lib.capnp import _CAPNP_VERSION_MAJOR as LIBCAPNP_VERSION_MAJOR # noqa: F401
|
|
from .lib.capnp import _CAPNP_VERSION_MINOR as LIBCAPNP_VERSION_MINOR # noqa: F401
|
|
from .lib.capnp import _CAPNP_VERSION_MICRO as LIBCAPNP_VERSION_MICRO # noqa: F401
|
|
from .lib.capnp import _CAPNP_VERSION as LIBCAPNP_VERSION # noqa: F401
|
|
|
|
version = '%s'
|
|
short_version = '%s'
|
|
"""
|
|
if not filename:
|
|
filename = os.path.join(os.path.dirname(__file__), "capnp", "version.py")
|
|
|
|
a = open(filename, "w")
|
|
try:
|
|
a.write(cnt % (VERSION, VERSION))
|
|
finally:
|
|
a.close()
|
|
|
|
|
|
write_version_py()
|
|
|
|
# Try to use README.md and CHANGELOG.md as description and changelog
|
|
with open("README.md", encoding="utf-8") as f:
|
|
long_description = f.read()
|
|
with open("CHANGELOG.md", encoding="utf-8") as f:
|
|
changelog = f.read()
|
|
changelog = "\nChangelog\n=============\n" + changelog
|
|
long_description += changelog
|
|
|
|
|
|
class clean(_clean):
|
|
"""
|
|
Clean command, invoked with `python setup.py clean`
|
|
"""
|
|
|
|
def run(self):
|
|
_clean.run(self)
|
|
for x in [
|
|
os.path.join("capnp", "lib", "capnp.cpp"),
|
|
os.path.join("capnp", "lib", "capnp.h"),
|
|
os.path.join("capnp", "version.py"),
|
|
"build",
|
|
"build32",
|
|
"build64",
|
|
"bundled",
|
|
] + glob.glob(os.path.join("capnp", "*.capnp")):
|
|
print("removing %s" % x)
|
|
try:
|
|
os.remove(x)
|
|
except OSError:
|
|
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
|
|
|
|
|
|
class build_libcapnp_ext(build_ext_c):
|
|
"""
|
|
Build capnproto library
|
|
"""
|
|
|
|
def build_extension(self, ext):
|
|
build_ext_c.build_extension(self, ext)
|
|
|
|
def run(self): # noqa: C901
|
|
if force_bundled_libcapnp:
|
|
need_build = True
|
|
elif force_system_libcapnp:
|
|
need_build = False
|
|
else:
|
|
# Try to use capnp executable to find include and lib path
|
|
capnp_executable = shutil.which("capnp")
|
|
if capnp_executable:
|
|
capnp_dir = os.path.dirname(capnp_executable)
|
|
self.include_dirs += [os.path.join(capnp_dir, "..", "include")]
|
|
self.library_dirs += [
|
|
os.path.join(
|
|
capnp_dir, "..", "lib{}".format(8 * struct.calcsize("P"))
|
|
)
|
|
]
|
|
self.library_dirs += [os.path.join(capnp_dir, "..", "lib")]
|
|
|
|
# Look for capnproto using pkg-config (and minimum version)
|
|
try:
|
|
if pkgconfig.installed("capnp", ">= 0.7.0"):
|
|
need_build = False
|
|
else:
|
|
need_build = True
|
|
except EnvironmentError:
|
|
# pkg-config not available in path
|
|
need_build = True
|
|
|
|
if need_build:
|
|
print(
|
|
"*WARNING* no libcapnp detected or rebuild forced. "
|
|
"Attempting to build it from source now. "
|
|
"If you have C++ Cap'n Proto installed, it may be out of date or is not being detected. "
|
|
"This may take a while..."
|
|
)
|
|
bundle_dir = os.path.join(_this_dir, "bundled")
|
|
if not os.path.exists(bundle_dir):
|
|
os.mkdir(bundle_dir)
|
|
build_dir = os.path.join(
|
|
_this_dir, "build{}".format(8 * struct.calcsize("P"))
|
|
)
|
|
if not os.path.exists(build_dir):
|
|
os.mkdir(build_dir)
|
|
|
|
# Check if we've already built capnproto
|
|
capnp_bin = os.path.join(build_dir, "bin", "capnp")
|
|
if os.name == "nt":
|
|
capnp_bin = os.path.join(build_dir, "bin", "capnp.exe")
|
|
|
|
if not os.path.exists(capnp_bin):
|
|
# Not built, fetch and build
|
|
fetch_libcapnp(bundle_dir, libcapnp_url)
|
|
build_libcapnp(bundle_dir, build_dir)
|
|
else:
|
|
print("capnproto already built at {}".format(build_dir))
|
|
|
|
self.include_dirs += [os.path.join(build_dir, "include")]
|
|
self.library_dirs += [
|
|
os.path.join(build_dir, "lib{}".format(8 * struct.calcsize("P")))
|
|
]
|
|
self.library_dirs += [os.path.join(build_dir, "lib")]
|
|
|
|
# Copy .capnp files from source
|
|
src_glob = glob.glob(os.path.join(build_dir, "include", "capnp", "*.capnp"))
|
|
dst_dir = os.path.join(self.build_lib, "capnp")
|
|
for file in src_glob:
|
|
print("copying {} -> {}".format(file, dst_dir))
|
|
shutil.copy(file, dst_dir)
|
|
|
|
return build_ext_c.run(self)
|
|
|
|
|
|
extra_compile_args = ["--std=c++14"]
|
|
extra_link_args = []
|
|
if os.name == "nt":
|
|
extra_compile_args = ["/std:c++14", "/MD"]
|
|
extra_link_args = ["/MANIFEST"]
|
|
|
|
import Cython.Build # noqa: E402
|
|
import Cython # noqa: E402
|
|
|
|
extensions = [
|
|
Extension(
|
|
"*",
|
|
["capnp/helpers/capabilityHelper.cpp", "capnp/lib/*.pyx"],
|
|
extra_compile_args=extra_compile_args,
|
|
extra_link_args=extra_link_args,
|
|
language="c++",
|
|
)
|
|
]
|
|
|
|
setup(
|
|
python_requires=">=3.7",
|
|
name="pycapnp",
|
|
packages=["capnp"],
|
|
version=VERSION,
|
|
package_data={
|
|
"capnp": [
|
|
"*.pxd",
|
|
"*.h",
|
|
"*.capnp",
|
|
"helpers/*.pxd",
|
|
"helpers/*.h",
|
|
"helpers/*.cpp",
|
|
"includes/*.pxd",
|
|
"lib/*.pxd",
|
|
"lib/*.py",
|
|
"lib/*.pyx",
|
|
"lib/*.h",
|
|
"templates/*",
|
|
]
|
|
},
|
|
ext_modules=Cython.Build.cythonize(extensions),
|
|
cmdclass={"clean": clean, "build_ext": build_libcapnp_ext},
|
|
install_requires=[],
|
|
entry_points={"console_scripts": ["capnpc-cython = capnp._gen:main"]},
|
|
# PyPi info
|
|
description="A cython wrapping of the C++ Cap'n Proto library",
|
|
long_description=long_description,
|
|
long_description_content_type="text/markdown",
|
|
license="BSD",
|
|
# (setup.py only supports 1 author...)
|
|
author="Jacob Alexander", # <- Current maintainer; Original author -> Jason Paryani
|
|
author_email="haata@kiibohd.com",
|
|
url="https://github.com/capnproto/pycapnp",
|
|
download_url="https://github.com/haata/pycapnp/archive/v%s.zip" % VERSION,
|
|
keywords=["capnp", "capnproto", "Cap'n Proto", "pycapnp"],
|
|
classifiers=[
|
|
"Development Status :: 5 - Production/Stable",
|
|
"Intended Audience :: Developers",
|
|
"License :: OSI Approved :: BSD License",
|
|
"Operating System :: MacOS :: MacOS X",
|
|
"Operating System :: Microsoft :: Windows :: Windows 10",
|
|
"Operating System :: POSIX",
|
|
"Programming Language :: C++",
|
|
"Programming Language :: Cython",
|
|
"Programming Language :: Python :: 3.7",
|
|
"Programming Language :: Python :: 3.8",
|
|
"Programming Language :: Python :: 3.9",
|
|
"Programming Language :: Python :: 3.10",
|
|
"Programming Language :: Python :: Implementation :: PyPy",
|
|
"Topic :: Communications",
|
|
],
|
|
)
|