Skip to content

TST: rework the sharedlib-in-package test package #783

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

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
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
2 changes: 1 addition & 1 deletion mesonpy/_rpath.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ def fix_rpath(filepath: Path, libs_relative_path: str) -> None:

def _get_rpath(filepath: Path) -> List[str]:
r = subprocess.run(['patchelf', '--print-rpath', os.fspath(filepath)], capture_output=True, text=True)
return r.stdout.strip().split(':')
return [x for x in r.stdout.strip().split(':') if x]

def _set_rpath(filepath: Path, rpath: Iterable[str]) -> None:
subprocess.run(['patchelf','--set-rpath', ':'.join(rpath), os.fspath(filepath)], check=True)
Expand Down
3 changes: 3 additions & 0 deletions tests/packages/sharedlib-in-package/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,7 @@ project('sharedlib-in-package', 'c', version: '1.0.0')

py = import('python').find_installation(pure: false)

origin = build_machine.system() == 'darwin' ? '@loader_path' : '$ORIGIN'

subdir('src')
subdir('mypkg')
4 changes: 2 additions & 2 deletions tests/packages/sharedlib-in-package/mypkg/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ def _append_to_sharedlib_load_path():
# end-literalinclude


from ._example import example_prod, example_sum #noqa: E402
from ._example import prodsum # noqa: E402


__all__ = ['example_prod', 'example_sum']
__all__ = ['prodsum']
25 changes: 6 additions & 19 deletions tests/packages/sharedlib-in-package/mypkg/_examplemod.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,36 +4,23 @@

#include <Python.h>

#include "examplelib.h"
#include "examplelib2.h"
#include "lib.h"

static PyObject* example_sum(PyObject* self, PyObject *args)
static PyObject* example_prodsum(PyObject* self, PyObject *args)
{
int a, b;
if (!PyArg_ParseTuple(args, "ii", &a, &b)) {
return NULL;
}
int a, b, x;

long result = sum(a, b);

return PyLong_FromLong(result);
}

static PyObject* example_prod(PyObject* self, PyObject *args)
{
int a, b;
if (!PyArg_ParseTuple(args, "ii", &a, &b)) {
if (!PyArg_ParseTuple(args, "iii", &a, &b, &x)) {
return NULL;
}

long result = prod(a, b);
long result = prodsum(a, b, x);

return PyLong_FromLong(result);
}

static PyMethodDef methods[] = {
{"example_prod", (PyCFunction)example_prod, METH_VARARGS, NULL},
{"example_sum", (PyCFunction)example_sum, METH_VARARGS, NULL},
{"prodsum", (PyCFunction)example_prodsum, METH_VARARGS, NULL},
{NULL, NULL, 0, NULL},
};

Expand Down
9 changes: 0 additions & 9 deletions tests/packages/sharedlib-in-package/mypkg/examplelib.c

This file was deleted.

7 changes: 0 additions & 7 deletions tests/packages/sharedlib-in-package/mypkg/examplelib.h

This file was deleted.

32 changes: 6 additions & 26 deletions tests/packages/sharedlib-in-package/mypkg/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -2,37 +2,17 @@
#
# SPDX-License-Identifier: MIT

if meson.get_compiler('c').get_id() in ['msvc', 'clang-cl', 'intel-cl']
export_dll_args = ['-DMYPKG_DLL_EXPORTS']
import_dll_args = ['-DMYPKG_DLL_IMPORTS']
else
export_dll_args = []
import_dll_args = []
endif

example_lib = shared_library(
'examplelib',
'examplelib.c',
c_args: export_dll_args,
install: true,
install_dir: py.get_install_dir() / 'mypkg',
)

example_lib_dep = declare_dependency(
compile_args: import_dll_args,
link_with: example_lib,
)

subdir('sub')

py.extension_module(
'_example',
'_examplemod.c',
dependencies: [example_lib_dep, example_lib2_dep],
include_directories: 'sub',
dependencies: lib_dep,
install: true,
subdir: 'mypkg',
install_rpath: '$ORIGIN',
# install_rpath is not exposed in the Meson introspection data in Meson
# versions prior to 1.6.0 and thus cannot be set by meson-python when
# building the Python wheel. Use link_args to set the RPATH.
# install_rpath: f'@origin@',
link_args: f'-Wl,-rpath,@origin@',
)

py.install_sources(
Expand Down
7 changes: 0 additions & 7 deletions tests/packages/sharedlib-in-package/mypkg/sub/examplelib2.h

This file was deleted.

10 changes: 10 additions & 0 deletions tests/packages/sharedlib-in-package/src/lib.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// SPDX-FileCopyrightText: 2022 The meson-python developers
//
// SPDX-License-Identifier: MIT

#include "lib.h"
#include "sublib.h"

int prodsum(int a, int b, int x) {
return prod(a, x) + b;
}
13 changes: 13 additions & 0 deletions tests/packages/sharedlib-in-package/src/lib.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// SPDX-FileCopyrightText: 2022 The meson-python developers
//
// SPDX-License-Identifier: MIT

#if defined(MYPKG_DLL_EXPORTS)
#define EXPORT __declspec(dllexport)
#elif defined(MYPKG_DLL_IMPORTS)
#define EXPORT __declspec(dllimport)
#else
#define EXPORT
#endif

EXPORT int prodsum(int a, int b, int x);
44 changes: 44 additions & 0 deletions tests/packages/sharedlib-in-package/src/meson.build
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# SPDX-FileCopyrightText: 2022 The meson-python developers
#
# SPDX-License-Identifier: MIT

if meson.get_compiler('c').get_id() in ['msvc', 'clang-cl', 'intel-cl']
export_dll_args = ['-DMYPKG_DLL_EXPORTS']
import_dll_args = ['-DMYPKG_DLL_IMPORTS']
else
export_dll_args = []
import_dll_args = []
endif

sublib = shared_library(
'sublib',
'sublib.c',
c_args: export_dll_args,
install: true,
install_dir: py.get_install_dir() / 'mypkg/sub',
)

sublib_dep = declare_dependency(
compile_args: import_dll_args,
link_with: sublib,
)

lib = shared_library(
'lib',
'lib.c',
dependencies: sublib_dep,
c_args: export_dll_args,
install: true,
install_dir: py.get_install_dir() / 'mypkg',
# install_rpath is not exposed in the Meson introspection data in Meson
# versions prior to 1.6.0 and thus cannot be set by meson-python when
# building the Python wheel. Use link_args to set the RPATH.
# install_rpath: f'@origin@/sub',
link_args: f'-Wl,-rpath,@origin@/sub',
)

lib_dep = declare_dependency(
compile_args: import_dll_args,
link_with: lib,
include_directories: include_directories('.'),
)
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
//
// SPDX-License-Identifier: MIT

#include "mypkg_dll.h"
#include "sublib.h"

MYPKG_DLL int prod(int a, int b) {
int prod(int a, int b) {
return a * b;
}
13 changes: 13 additions & 0 deletions tests/packages/sharedlib-in-package/src/sublib.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// SPDX-FileCopyrightText: 2022 The meson-python developers
//
// SPDX-License-Identifier: MIT

#if defined(MYPKG_DLL_EXPORTS)
#define EXPORT __declspec(dllexport)
#elif defined(MYPKG_DLL_IMPORTS)
#define EXPORT __declspec(dllimport)
#else
#define EXPORT
#endif

EXPORT int prod(int a, int b);
70 changes: 61 additions & 9 deletions tests/test_wheel.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,33 +178,85 @@ def test_local_lib(venv, wheel_link_against_local_lib):
assert int(output) == 3


@pytest.mark.skipif(sys.platform in {'win32', 'cygwin'}, reason='requires RPATH support')
def test_sharedlib_in_package_rpath(wheel_sharedlib_in_package, tmp_path):
artifact = wheel.wheelfile.WheelFile(wheel_sharedlib_in_package)
artifact.extractall(tmp_path)

origin = '@loader_path' if sys.platform == 'darwin' else '$ORIGIN'

rpath = set(mesonpy._rpath._get_rpath(tmp_path / 'mypkg' / f'_example{EXT_SUFFIX}'))
# This RPATH entry should be removed by meson-python but it is not.
build_rpath = {f'{origin}/../src'}
assert rpath == {origin, *build_rpath}

rpath = set(mesonpy._rpath._get_rpath(tmp_path / 'mypkg' / f'liblib{LIB_SUFFIX}'))
# This RPATH entry should be removed by meson-python but it is not.
build_rpath = {f'{origin}/'}
assert rpath == {f'{origin}/sub', *build_rpath}

rpath = set(mesonpy._rpath._get_rpath(tmp_path / 'mypkg' / 'sub' / f'libsublib{LIB_SUFFIX}'))
assert rpath == set()


@pytest.mark.skipif(sys.platform in {'win32', 'cygwin'}, reason='requires RPATH support')
def test_sharedlib_in_package_rpath_ldflags(package_sharedlib_in_package, tmp_path, monkeypatch):
origin = '@loader_path' if sys.platform == 'darwin' else '$ORIGIN'
extra_rpath = {f'{origin}/test-ldflags', '/usr/lib/test-ldflags'}
ldflags = ' '.join(f'-Wl,-rpath,{p}' for p in extra_rpath)
monkeypatch.setenv('LDFLAGS', ldflags)

filename = mesonpy.build_wheel(tmp_path)
artifact = wheel.wheelfile.WheelFile(tmp_path / filename)
artifact.extractall(tmp_path)

for path in f'_example{EXT_SUFFIX}', f'liblib{LIB_SUFFIX}', f'sub/libsublib{LIB_SUFFIX}':
rpath = set(mesonpy._rpath._get_rpath(tmp_path / 'mypkg' / path))
assert extra_rpath <= rpath


def test_sharedlib_in_package(venv, wheel_sharedlib_in_package):
venv.pip('install', wheel_sharedlib_in_package)
output = venv.python('-c', 'import mypkg; print(mypkg.example_sum(2, 5))')
assert int(output) == 7
output = venv.python('-c', 'import mypkg; print(mypkg.example_prod(6, 7))')
assert int(output) == 42
output = venv.python('-c', 'import mypkg; print(mypkg.prodsum(2, 3, 4))')
assert int(output) == 11


@pytest.mark.skipif(MESON_VERSION < (1, 3, 0), reason='Meson version too old')
@pytest.mark.skipif(MESON_VERSION < (1, 3, 0), reason='meson too old')
def test_link_library_in_subproject(venv, wheel_link_library_in_subproject):
venv.pip('install', wheel_link_library_in_subproject)
output = venv.python('-c', 'import foo; print(foo.example_sum(3, 6))')
assert int(output) == 9


@pytest.mark.skipif(sys.platform in {'win32', 'cygwin'}, reason='requires RPATH support')
def test_rpath(wheel_link_against_local_lib, tmp_path):
def test_link_against_local_lib_rpath(wheel_link_against_local_lib, tmp_path):
artifact = wheel.wheelfile.WheelFile(wheel_link_against_local_lib)
artifact.extractall(tmp_path)

origin = '@loader_path' if sys.platform == 'darwin' else '$ORIGIN'
expected = {f'{origin}/../.link_against_local_lib.mesonpy.libs', 'custom-rpath',}

rpath = set(mesonpy._rpath._get_rpath(tmp_path / 'example' / f'_example{EXT_SUFFIX}'))
# Verify that rpath is a superset of the expected one: linking to
# the Python runtime may require additional rpath entries.
assert rpath >= expected
assert rpath == expected


@pytest.mark.skipif(sys.platform in {'win32', 'cygwin'}, reason='requires RPATH support')
def test_link_against_local_lib_rpath_ldflags(package_link_against_local_lib, tmp_path, monkeypatch):
origin = '@loader_path' if sys.platform == 'darwin' else '$ORIGIN'
extra_rpath = {f'{origin}/test-ldflags', '/usr/lib/test-ldflags'}
ldflags = ' '.join(f'-Wl,-rpath,{p}' for p in extra_rpath)
monkeypatch.setenv('LDFLAGS', ldflags)

filename = mesonpy.build_wheel(tmp_path)
artifact = wheel.wheelfile.WheelFile(tmp_path / filename)
artifact.extractall(tmp_path)

# The RPATH entry relative to $ORIGIN added via $LDFLAGS is
# erroneusly stripped by meson-python.
extra_rpath = {'/usr/lib/test-ldflags',}

rpath = set(mesonpy._rpath._get_rpath(tmp_path / 'example' / f'_example{EXT_SUFFIX}'))
assert extra_rpath <= rpath


@pytest.mark.skipif(sys.platform in {'win32', 'cygwin'}, reason='requires RPATH support')
Expand Down
Loading