Skip to content

Commit b7ef032

Browse files
committed
TST: add test package with internal shared library, installed in site-packages
1 parent d52a81b commit b7ef032

File tree

9 files changed

+165
-0
lines changed

9 files changed

+165
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# SPDX-FileCopyrightText: 2022 The meson-python developers
2+
#
3+
# SPDX-License-Identifier: MIT
4+
5+
project('sharedlib-in-package', 'c', version: '1.0.0')
6+
7+
py = import('python').find_installation(pure: false)
8+
9+
subdir('mypkg')
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# SPDX-FileCopyrightText: 2024 The meson-python developers
2+
#
3+
# SPDX-License-Identifier: MIT
4+
5+
import os
6+
7+
8+
def _enable_sharedlib_loading():
9+
"""Ensure the `examplelib` shared library on Windows can be loaded
10+
11+
This shared library is installed alongside this __init__.py file. Due to
12+
lack of RPATH support, Windows cannot find shared libraries installed
13+
within wheels unless we either amend the DLL search path or pre-load the
14+
DLL.
15+
16+
.. note::
17+
18+
`os.add_dll_directory` is only available for Python >=3.8, and with
19+
the Conda `python` packages only works as advertised for >=3.10.
20+
If you require support for older versions, pre-loading the DLL
21+
with `ctypes.WinDLL` may be preferred (the SciPy code base has an
22+
example of this).
23+
"""
24+
if os.name == "nt":
25+
basedir = os.path.dirname(__file__)
26+
os.add_dll_directory(basedir)
27+
28+
29+
_enable_sharedlib_loading()
30+
31+
32+
from ._example import example_sum
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// SPDX-FileCopyrightText: 2022 The meson-python developers
2+
//
3+
// SPDX-License-Identifier: MIT
4+
5+
#include <Python.h>
6+
7+
#include "examplelib.h"
8+
9+
static PyObject* example_sum(PyObject* self, PyObject *args)
10+
{
11+
int a, b;
12+
if (!PyArg_ParseTuple(args, "ii", &a, &b)) {
13+
return NULL;
14+
}
15+
16+
long result = sum(a, b);
17+
18+
return PyLong_FromLong(result);
19+
}
20+
21+
static PyMethodDef methods[] = {
22+
{"example_sum", (PyCFunction)example_sum, METH_VARARGS, NULL},
23+
{NULL, NULL, 0, NULL},
24+
};
25+
26+
static struct PyModuleDef module = {
27+
PyModuleDef_HEAD_INIT,
28+
"_example",
29+
NULL,
30+
-1,
31+
methods,
32+
};
33+
34+
PyMODINIT_FUNC PyInit__example(void)
35+
{
36+
return PyModule_Create(&module);
37+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// SPDX-FileCopyrightText: 2022 The meson-python developers
2+
//
3+
// SPDX-License-Identifier: MIT
4+
5+
#include "mypkg_dll.h"
6+
7+
MYPKG_DLL int sum(int a, int b) {
8+
return a + b;
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// SPDX-FileCopyrightText: 2022 The meson-python developers
2+
//
3+
// SPDX-License-Identifier: MIT
4+
5+
#include "mypkg_dll.h"
6+
7+
MYPKG_DLL int sum(int a, int b);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# SPDX-FileCopyrightText: 2022 The meson-python developers
2+
#
3+
# SPDX-License-Identifier: MIT
4+
5+
if meson.get_compiler('c').get_id() in ['msvc', 'clang-cl', 'intel-cl']
6+
export_dll_args = ['-DMYPKG_DLL_EXPORTS']
7+
import_dll_args = ['-DMYPKG_DLL_IMPORTS']
8+
else
9+
export_dll_args = []
10+
import_dll_args = []
11+
endif
12+
13+
example_lib = shared_library(
14+
'examplelib',
15+
'examplelib.c',
16+
c_args: export_dll_args,
17+
install: true,
18+
install_dir: py.get_install_dir() / 'mypkg',
19+
)
20+
21+
example_lib_dep = declare_dependency(
22+
compile_args: import_dll_args,
23+
link_with: example_lib,
24+
)
25+
26+
py.extension_module(
27+
'_example',
28+
'_examplemod.c',
29+
dependencies: example_lib_dep,
30+
install: true,
31+
subdir: 'mypkg',
32+
install_rpath: '$ORIGIN',
33+
)
34+
35+
py.install_sources(
36+
['__init__.py'],
37+
subdir: 'mypkg',
38+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#pragma once
2+
3+
// MYPKG_DLL
4+
// inspired by https://github.com/abseil/abseil-cpp/blob/20240116.2/absl/base/config.h#L736-L753
5+
// and https://github.com/scipy/scipy/blob/9ded83b51099eee745418ccbb30196db96c81f3f/scipy/_build_utils/src/scipy_dll.h
6+
//
7+
// When building the `examplelib` DLL, this macro expands to `__declspec(dllexport)`
8+
// so we can annotate symbols appropriately as being exported. When used in
9+
// headers consuming a DLL, this macro expands to `__declspec(dllimport)` so
10+
// that consumers know the symbol is defined inside the DLL. In all other cases,
11+
// the macro expands to nothing.
12+
// Note: MYPKG_DLL_{EX,IM}PORTS are set in mypkg/meson.build
13+
#if defined(MYPKG_DLL_EXPORTS)
14+
#define MYPKG_DLL __declspec(dllexport)
15+
#elif defined(MYPKG_DLL_IMPORTS)
16+
#define MYPKG_DLL __declspec(dllimport)
17+
#else
18+
#define MYPKG_DLL
19+
#endif
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# SPDX-FileCopyrightText: 2022 The meson-python developers
2+
#
3+
# SPDX-License-Identifier: MIT
4+
5+
[build-system]
6+
build-backend = 'mesonpy'
7+
requires = ['meson-python']

tests/test_wheel.py

+7
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,13 @@ def test_local_lib(venv, wheel_link_against_local_lib):
161161
assert int(output) == 3
162162

163163

164+
@pytest.mark.skipif(MESON_VERSION < (0, 64, 0), reason='Meson version too old')
165+
def test_sharedlib_in_package(venv, wheel_sharedlib_in_package):
166+
venv.pip('install', wheel_sharedlib_in_package)
167+
output = venv.python('-c', 'import mypkg; print(mypkg.example_sum(2, 5))')
168+
assert int(output) == 7
169+
170+
164171
@pytest.mark.skipif(sys.platform not in {'linux', 'darwin'}, reason='Not supported on this platform')
165172
def test_rpath(wheel_link_against_local_lib, tmp_path):
166173
artifact = wheel.wheelfile.WheelFile(wheel_link_against_local_lib)

0 commit comments

Comments
 (0)