Updating to capnproto v0.8.0

- Includes some test stabilization
- Fixes manylinux2010 build issues (linker flag order due to old gcc)
- More rigorous python setup.py clean
- Requires capnproto v0.8.0 or greater
- Including system libcapnp include path for import (e.g. import
  stream_capnp)
- Bundle libcapnp .capnp files when not using system libcapnp
- Removing more distutils usage. Now using pkg-config to determine the
  system version of libcapnp (mainly for Linux, but should work on macOS
  with brew)
- Removed dead code

Resolves issues #215 #216 #217
Lots of fixes for Issue #218 (all sorts of retry methods needed for
GitHub Actions)
This commit is contained in:
Jacob Alexander
2020-06-03 22:49:52 -07:00
parent 7bfd5b962b
commit 255119b838
28 changed files with 206 additions and 834 deletions

View File

@@ -5,9 +5,5 @@ Largely adapted from h5py
# flake8: noqa F401 F403
from .msg import *
from .config import *
from .detect import *
from .bundle import *
from .misc import *
from .patch import *
from .build import *

View File

@@ -22,7 +22,9 @@ def build_libcapnp(bundle_dir, build_dir):
os.mkdir(tmp_dir)
cxxflags = os.environ.get('CXXFLAGS', None)
ldflags = os.environ.get('LDFLAGS', None)
os.environ['CXXFLAGS'] = (cxxflags or '') + ' -O2 -DNDEBUG'
os.environ['LDFLAGS'] = (ldflags or '')
# Enable ninja for compilation if available
build_type = []
@@ -77,5 +79,9 @@ def build_libcapnp(bundle_dir, build_dir):
del os.environ['CXXFLAGS']
else:
os.environ['CXXFLAGS'] = cxxflags
if ldflags is None:
del os.environ['LDFLAGS']
else:
os.environ['LDFLAGS'] = ldflags
if returncode != 0:
raise RuntimeError('capnproto compilation failed: {}'.format(returncode))

View File

@@ -27,7 +27,7 @@ pjoin = os.path.join
#
bundled_version = (0, 7, 0)
bundled_version = (0, 8, 0)
libcapnp_name = "capnproto-c++-%i.%i.%i.tar.gz" % (bundled_version)
libcapnp_url = "https://capnproto.org/" + libcapnp_name
@@ -92,14 +92,3 @@ def fetch_libcapnp(savedir, url=None):
else:
cpp_dir = os.path.join(with_version, 'c++')
shutil.move(cpp_dir, dest)
# XXX (HaaTa): There's a bug in capnproto-0.7.0 on CentOS 6 (or any glibc older than 2.16)
# This patches the issue
with fileinput.FileInput(os.path.join(dest, 'src', 'kj', 'table.c++'), inplace=True, backup='.bak') as f:
for line in f:
print(
line.replace(
'__APPLE__ || __BIONIC__', '__APPLE__ || __BIONIC__ || (defined(__GLIBC__) && (__GLIBC__ == 2) && (__GLIBC_MINOR__ < 16))'
),
end=''
)

View File

@@ -1,21 +0,0 @@
"""Config functions"""
#
# Copyright (C) PyZMQ Developers
#
# This file is part of pyzmq, copied and adapted from h5py.
# h5py source used under the New BSD license
#
# h5py: <http://code.google.com/p/h5py/>
#
# Distributed under the terms of the New BSD License. The full license is in
# the file COPYING.BSD, distributed as part of this software.
#
#
# Utility functions (adapted from h5py: http://h5py.googlecode.com)
#
def v_str(v_tuple):
"""turn (2,0,1) into '2.0.1'."""
return ".".join(str(x) for x in v_tuple)

View File

@@ -1,154 +0,0 @@
"""Detect zmq version"""
#
# Copyright (C) PyZMQ Developers
#
# This file is part of pyzmq, copied and adapted from h5py.
# h5py source used under the New BSD license
#
# h5py: <http://code.google.com/p/h5py/>
#
# Distributed under the terms of the New BSD License. The full license is in
# the file COPYING.BSD, distributed as part of this software.
#
#
# Adapted for use in pycapnp from pyzmq. See https://github.com/zeromq/pyzmq
# for original project.
import shutil
import sys
import os
import logging
import platform
from distutils import ccompiler
from distutils.ccompiler import get_default_compiler
import tempfile
from .misc import get_compiler, get_output_error
from .patch import patch_lib_paths
pjoin = os.path.join
#
# Utility functions (adapted from h5py: http://h5py.googlecode.com)
#
def test_compilation(cfile, compiler=None, **compiler_attrs):
"""Test simple compilation with given settings"""
cc = get_compiler(compiler, **compiler_attrs)
efile, _ = os.path.splitext(cfile)
cpreargs = lpreargs = []
if sys.platform == 'darwin':
# use appropriate arch for compiler
if platform.architecture()[0] == '32bit':
if platform.processor() == 'powerpc':
cpu = 'ppc'
else:
cpu = 'i386'
cpreargs = ['-arch', cpu]
lpreargs = ['-arch', cpu, '-undefined', 'dynamic_lookup']
else:
# allow for missing UB arch, since it will still work:
lpreargs = ['-undefined', 'dynamic_lookup']
if sys.platform == 'sunos5':
if platform.architecture()[0] == '32bit':
lpreargs = ['-m32']
else:
lpreargs = ['-m64']
extra_compile_args = compiler_attrs.get('extra_compile_args', [])
if os.name != 'nt':
extra_compile_args += ['--std=c++14']
extra_link_args = compiler_attrs.get('extra_link_args', [])
if cc.compiler_type == 'msvc':
extra_link_args += ['/MANIFEST']
objs = cc.compile([cfile], extra_preargs=cpreargs, extra_postargs=extra_compile_args)
cc.link_executable(objs, efile, extra_preargs=lpreargs, extra_postargs=extra_link_args)
return efile
def detect_version(basedir, compiler=None, **compiler_attrs):
"""Compile, link & execute a test program, in empty directory `basedir`.
The C compiler will be updated with any keywords given via setattr.
Parameters
----------
basedir : path
The location where the test program will be compiled and run
compiler : str
The distutils compiler key (e.g. 'unix', 'msvc', or 'mingw32')
**compiler_attrs : dict
Any extra compiler attributes, which will be set via ``setattr(cc)``.
Returns
-------
A dict of properties for zmq compilation, with the following two keys:
vers : tuple
The ZMQ version as a tuple of ints, e.g. (2,2,0)
settings : dict
The compiler options used to compile the test function, e.g. `include_dirs`,
`library_dirs`, `libs`, etc.
"""
if compiler is None:
compiler = get_default_compiler()
cfile = pjoin(basedir, 'vers.cpp')
shutil.copy(pjoin(os.path.dirname(__file__), 'vers.cpp'), cfile)
# check if we need to link against Realtime Extensions library
if sys.platform.startswith('linux'):
cc = ccompiler.new_compiler(compiler=compiler)
cc.output_dir = basedir
if not cc.has_function('timer_create'):
if 'libraries' not in compiler_attrs:
compiler_attrs['libraries'] = []
compiler_attrs['libraries'].append('rt')
cc = get_compiler(compiler=compiler, **compiler_attrs)
efile = test_compilation(cfile, compiler=cc)
patch_lib_paths(efile, cc.library_dirs)
rc, so, se = get_output_error([efile])
if rc:
msg = "Error running version detection script:\n%s\n%s" % (so, se)
logging.error(msg)
raise IOError(msg)
handlers = {'vers': lambda val: tuple(int(v) for v in val.split('.'))}
props = {}
for line in (x for x in so.split('\n') if x):
key, val = line.split(':')
props[key] = handlers[key](val)
return props
def test_build(**compiler_attrs):
"""do a test build of libcapnp"""
tmp_dir = tempfile.mkdtemp()
# line()
# info("Configure: Autodetecting Cap'n Proto settings...")
# info(" Custom Cap'n Proto dir: %s" % prefix)
try:
detected = detect_version(tmp_dir, None, **compiler_attrs)
finally:
erase_dir(tmp_dir)
# info(" Cap'n Proto version detected: %s" % v_str(detected['vers']))
return detected
def erase_dir(path):
"""Erase directory"""
try:
shutil.rmtree(path)
except Exception:
pass

View File

@@ -1,64 +0,0 @@
"""misc build utility functions"""
# Copyright (c) PyZMQ Developers
# Distributed under the terms of the Modified BSD License.
import os
import logging
from distutils import ccompiler
from distutils.sysconfig import customize_compiler
from pipes import quote
from subprocess import Popen, PIPE
pjoin = os.path.join
def customize_mingw(cc):
"""customize mingw"""
# strip -mno-cygwin from mingw32 (Python Issue #12641)
for cmd in [cc.compiler, cc.compiler_cxx, cc.compiler_so, cc.linker_exe, cc.linker_so]:
if '-mno-cygwin' in cmd:
cmd.remove('-mno-cygwin')
# remove problematic msvcr90
if 'msvcr90' in cc.dll_libraries:
cc.dll_libraries.remove('msvcr90')
def customize_msvc(cc):
pass
def get_compiler(compiler, **compiler_attrs):
"""get and customize a compiler"""
if compiler is None or isinstance(compiler, str):
cc = ccompiler.new_compiler(compiler=compiler)
customize_compiler(cc)
if cc.compiler_type == 'mingw32':
customize_mingw(cc)
elif cc.compiler_type == 'msvc':
customize_msvc(cc)
else:
cc = compiler
for name, val in compiler_attrs.items():
setattr(cc, name, val)
return cc
def get_output_error(cmd):
"""Return the exit status, stdout, stderr of a command"""
if not isinstance(cmd, list):
cmd = [cmd]
logging.debug("Running: %s", ' '.join(map(quote, cmd)))
try:
result = Popen(cmd, stdout=PIPE, stderr=PIPE)
except IOError as e:
return -1, '', 'Failed to run %r: %r' % (cmd, e)
so, se = result.communicate()
# unicode:
so = so.decode('utf8', 'replace')
se = se.decode('utf8', 'replace')
return result.returncode, so, se

View File

@@ -1,67 +0,0 @@
"""utils for patching libraries"""
# Copyright (c) PyZMQ Developers.
# Distributed under the terms of the Modified BSD License.
import re
import sys
import os
import logging
from .misc import get_output_error
pjoin = os.path.join
# LIB_PAT from delocate
LIB_PAT = re.compile(
r"\s*(.*) \(compatibility version (\d+\.\d+\.\d+), current version (\d+\.\d+\.\d+)\)"
)
def _get_libs(fname):
rc, so, se = get_output_error(['otool', '-L', fname])
if rc:
logging.error("otool -L %s failed: %r", fname, se)
return
for line in so.splitlines()[1:]:
m = LIB_PAT.match(line)
if m:
yield m.group(1)
def _find_library(lib, path):
"""Find a library"""
for d in path[::-1]:
real_lib = os.path.join(d, lib)
if os.path.exists(real_lib):
return real_lib
return None
def _install_name_change(fname, lib, real_lib):
rc, so, se = get_output_error(['install_name_tool', '-change', lib, real_lib, fname])
if rc:
logging.error("Couldn't update load path: %s", se)
def patch_lib_paths(fname, library_dirs):
"""Load any weakly-defined libraries from their real location
(only on OS X)
- Find libraries with `otool -L`
- Update with `install_name_tool -change`
"""
if sys.platform != 'darwin':
return
libs = _get_libs(fname)
for lib in libs:
if not lib.startswith(('@', '/')):
real_lib = _find_library(lib, library_dirs)
if real_lib:
_install_name_change(fname, lib, real_lib)
__all__ = ['patch_lib_paths']

View File

@@ -1,9 +0,0 @@
// check libcapnp version
#include <stdio.h>
#include "capnp/common.h"
int main(int argc, char **argv){
fprintf(stdout, "vers: %d.%d.%d\n", CAPNP_VERSION_MAJOR, CAPNP_VERSION_MINOR, CAPNP_VERSION_MICRO);
return 0;
}