Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Put libraries in $WHEELNAME.libs #90

Merged
merged 1 commit into from
Jan 23, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 12 additions & 15 deletions auditwheel/repair.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@
logger = logging.getLogger(__name__)


# Copied from wheel 0.31.1
WHEEL_INFO_RE = re.compile(
r"""^(?P<namever>(?P<name>.+?)-(?P<ver>\d.*?))(-(?P<build>\d.*?))?
-(?P<pyver>[a-z].+?)-(?P<abi>.+?)-(?P<plat>.+?)(\.whl|\.dist-info)$""",
re.VERBOSE).match


@functools.lru_cache()
def verify_patchelf():
"""This function looks for the ``patchelf`` external binary in the PATH,
Expand Down Expand Up @@ -59,24 +66,14 @@ def repair_wheel(wheel_path: str, abi: str, lib_sdir: str, out_dir: str,
with InWheelCtx(wheel_path) as ctx:
ctx.out_wheel = pjoin(out_dir, wheel_fname)

dest_dir = WHEEL_INFO_RE(wheel_fname).group('name') + lib_sdir

if not exists(dest_dir):
os.mkdir(dest_dir)

# here, fn is a path to a python extension library in
# the wheel, and v['libs'] contains its required libs
for fn, v in external_refs_by_fn.items():
# pkg_root should resolve to like numpy/ or scipy/
# note that it's possible for the wheel to contain
# more than one pkg, which is why we detect the pkg root
# for each fn.
pkg_root = fn.split(os.sep)[0]

if pkg_root == fn:
# this file is an extension that's not contained in a
# directory -- just supposed to be directly in site-packages
dest_dir = lib_sdir + pkg_root.split('.')[0]
else:
dest_dir = pjoin(pkg_root, lib_sdir)

if not exists(dest_dir):
os.mkdir(dest_dir)

ext_libs = v[abi]['libs'] # type: Dict[str, str]
for soname, src_path in ext_libs.items():
Expand Down
2 changes: 2 additions & 0 deletions tests/integration/multiple_top_level/MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
include pyproject.toml
graft lib
9 changes: 9 additions & 0 deletions tests/integration/multiple_top_level/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
all: lib-src/b/libb.so lib-src/a/liba.so


lib-src/b/libb.so: lib-src/b/b.c
gcc -fPIC -shared -o lib-src/b/libb.so lib-src/b/b.c


lib-src/a/liba.so: lib-src/b/libb.so lib-src/a/a.c
gcc -fPIC -shared -o lib-src/a/liba.so -Ilib-src/b -Llib-src/b -lb lib-src/a/a.c
6 changes: 6 additions & 0 deletions tests/integration/multiple_top_level/lib-src/a/a.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#include "b.h"


int fa(void) {
return 1 + fb();
}
1 change: 1 addition & 0 deletions tests/integration/multiple_top_level/lib-src/a/a.h
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
int fa(void);
3 changes: 3 additions & 0 deletions tests/integration/multiple_top_level/lib-src/b/b.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
int fb(void) {
return 10;
}
1 change: 1 addition & 0 deletions tests/integration/multiple_top_level/lib-src/b/b.h
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
int fb(void);
3 changes: 3 additions & 0 deletions tests/integration/multiple_top_level/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[build-system]
build-backend = "setuptools.build_meta"
requires = ["cython", "setuptools", "wheel"]
2 changes: 2 additions & 0 deletions tests/integration/multiple_top_level/setup.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[build_ext]
cython_c_in_temp = 1
25 changes: 25 additions & 0 deletions tests/integration/multiple_top_level/setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
from setuptools import setup, Extension, find_packages


setup(
name='multiple_top_level',
version='1.0',
description='Auditwheel multiple top-level extensions example',
packages=find_packages(where='src'),
ext_modules=[
Extension(
'example_a',
['src/example_a.pyx'],
include_dirs=['lib-src/a'],
library_dirs=['lib-src/a', 'lib-src/b'],
libraries=['a'],
),
Extension(
'example_b',
['src/example_b.pyx'],
include_dirs=['lib-src/a'],
library_dirs=['lib-src/a', 'lib-src/b'],
libraries=['a'],
),
],
)
6 changes: 6 additions & 0 deletions tests/integration/multiple_top_level/src/example_a.pyx
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
cdef extern from "a.h":
int fa();


cpdef int example_a():
return fa()
6 changes: 6 additions & 0 deletions tests/integration/multiple_top_level/src/example_b.pyx
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
cdef extern from "a.h":
int fa();


cpdef int example_b():
return fa() * 10
85 changes: 85 additions & 0 deletions tests/integration/test_manylinux.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import io
import os
import os.path as op
import re
import shutil
import sys
import logging
Expand Down Expand Up @@ -487,3 +488,87 @@ def test_build_wheel_depending_on_library_with_rpath(any_manylinux_container, do
rpath_tags = [t for t in dynamic.iter_tags() if t.entry.d_tag == 'DT_RPATH']
assert len(rpath_tags) == 1
assert rpath_tags[0].rpath == '$ORIGIN/.'


def test_build_repair_multiple_top_level_modules_wheel(any_manylinux_container, docker_python, io_folder):

policy, manylinux_ctr = any_manylinux_container

docker_exec(
manylinux_ctr,
[
'bash',
'-c',
'cd /auditwheel_src/tests/integration/multiple_top_level '
'&& make '
'&& pip wheel . -w /io',
]
)

filenames = os.listdir(io_folder)
assert filenames == [
'multiple_top_level-1.0-{abi}-linux_{platform}.whl'.format(
abi=PYTHON_ABI, platform=PLATFORM)]
orig_wheel = filenames[0]
assert 'manylinux' not in orig_wheel

# Repair the wheel using the appropriate manylinux container
repair_command = (
'auditwheel repair --plat {policy} -w /io /io/{orig_wheel}'
).format(policy=policy, orig_wheel=orig_wheel)
docker_exec(
manylinux_ctr,
[
'bash',
'-c',
(
'LD_LIBRARY_PATH='
'/auditwheel_src/tests/integration/multiple_top_level/lib-src/a:'
'/auditwheel_src/tests/integration/multiple_top_level/lib-src/b:'
'$LD_LIBRARY_PATH '
)
+ repair_command,
],
)
filenames = os.listdir(io_folder)
repaired_wheels = [fn for fn in filenames if policy in fn]
# Wheel picks up newer symbols when built in manylinux2010
expected_wheel_name = (
'multiple_top_level-1.0-{abi}-{policy}.whl'
).format(abi=PYTHON_ABI, policy=policy)
assert repaired_wheels == [expected_wheel_name]
repaired_wheel = expected_wheel_name
output = docker_exec(manylinux_ctr, 'auditwheel show /io/' + repaired_wheel)
if PLATFORM in {'x86_64', 'i686'}:
expect = 'manylinux1_{}'.format(PLATFORM)
else:
expect = 'manylinux2014_{}'.format(PLATFORM)
assert (
'{wheel} is consistent'
' with the following platform tag: "{expect}"'
).format(wheel=repaired_wheel, expect=expect) in output.replace('\n', ' ')

docker_exec(docker_python, 'pip install /io/' + repaired_wheel)
for mod, func, expected in [
('example_a', 'example_a', '11'),
('example_b', 'example_b', '110'),
]:
output = docker_exec(
docker_python,
[
'python',
'-c',
'from {mod} import {func}; print({func}())'.format(
mod=mod, func=func
),
],
).strip()
assert output.strip() == expected
with zipfile.ZipFile(os.path.join(io_folder, repaired_wheel)) as w:
for lib_name in ['liba', 'libb']:
assert any(
re.match(
r'multiple_top_level.libs/{}.*\.so'.format(lib_name), name
)
for name in w.namelist()
)