Skip to content

Commit c455425

Browse files
rgommersdnicolodi
authored andcommitted
TST: add test package with internal shared libraries, installed in site-packages
1 parent 077e3bc commit c455425

File tree

12 files changed

+238
-0
lines changed

12 files changed

+238
-0
lines changed
Lines changed: 9 additions & 0 deletions
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')
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# SPDX-FileCopyrightText: 2024 The meson-python developers
2+
#
3+
# SPDX-License-Identifier: MIT
4+
5+
import os
6+
import sys
7+
8+
9+
# start-literalinclude
10+
def _enable_sharedlib_loading():
11+
"""
12+
Ensure the shared libraries in this dir and the ``sub`` subdir can be
13+
loaded on Windows.
14+
15+
One shared library is installed alongside this ``__init__.py`` file.
16+
Windows can load it because it searches for DLLs in the directory where a
17+
``.pyd`` (Python extension module) is located in. Cygwin does not though.
18+
For a shared library in another directory inside the package, Windows also
19+
needs a hint.
20+
21+
This function is Windows-specific due to lack of RPATH support on Windows.
22+
It cannot find shared libraries installed within wheels unless we either
23+
amend the DLL search path or pre-load the DLL.
24+
25+
Note that ``delvewheel`` inserts a similar snippet into the main
26+
``__init__.py`` of a package when it vendors external shared libraries.
27+
28+
.. note::
29+
30+
`os.add_dll_directory` is only available for Python >=3.8, and with
31+
the Conda ``python`` packages only works as advertised for >=3.10.
32+
If you require support for older versions, pre-loading the DLL
33+
with `ctypes.WinDLL` may be preferred (the SciPy code base has an
34+
example of this).
35+
"""
36+
basedir = os.path.dirname(__file__)
37+
subdir = os.path.join(basedir, 'sub')
38+
if os.name == 'nt':
39+
os.add_dll_directory(subdir)
40+
elif sys.platform == 'cygwin':
41+
os.environ['PATH'] = f'os.environ["PATH"]:{basedir}:{subdir}'
42+
43+
44+
_enable_sharedlib_loading()
45+
# end-literalinclude
46+
47+
48+
from ._example import example_prod, example_sum #noqa: E402
49+
50+
51+
__all__ = ['example_prod', 'example_sum']
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
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+
#include "examplelib2.h"
9+
10+
static PyObject* example_sum(PyObject* self, PyObject *args)
11+
{
12+
int a, b;
13+
if (!PyArg_ParseTuple(args, "ii", &a, &b)) {
14+
return NULL;
15+
}
16+
17+
long result = sum(a, b);
18+
19+
return PyLong_FromLong(result);
20+
}
21+
22+
static PyObject* example_prod(PyObject* self, PyObject *args)
23+
{
24+
int a, b;
25+
if (!PyArg_ParseTuple(args, "ii", &a, &b)) {
26+
return NULL;
27+
}
28+
29+
long result = prod(a, b);
30+
31+
return PyLong_FromLong(result);
32+
}
33+
34+
static PyMethodDef methods[] = {
35+
{"example_prod", (PyCFunction)example_prod, METH_VARARGS, NULL},
36+
{"example_sum", (PyCFunction)example_sum, METH_VARARGS, NULL},
37+
{NULL, NULL, 0, NULL},
38+
};
39+
40+
static struct PyModuleDef module = {
41+
PyModuleDef_HEAD_INIT,
42+
"_example",
43+
NULL,
44+
-1,
45+
methods,
46+
};
47+
48+
PyMODINIT_FUNC PyInit__example(void)
49+
{
50+
return PyModule_Create(&module);
51+
}
Lines changed: 9 additions & 0 deletions
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 "sub/mypkg_dll.h"
6+
7+
MYPKG_DLL int sum(int a, int b) {
8+
return a + b;
9+
}
Lines changed: 7 additions & 0 deletions
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 "sub/mypkg_dll.h"
6+
7+
MYPKG_DLL int sum(int a, int b);
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
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+
subdir('sub')
27+
28+
py.extension_module(
29+
'_example',
30+
'_examplemod.c',
31+
dependencies: [example_lib_dep, example_lib2_dep],
32+
include_directories: 'sub',
33+
install: true,
34+
subdir: 'mypkg',
35+
install_rpath: '$ORIGIN',
36+
)
37+
38+
py.install_sources(
39+
['__init__.py'],
40+
subdir: 'mypkg',
41+
)
Lines changed: 9 additions & 0 deletions
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 prod(int a, int b) {
8+
return a * b;
9+
}
Lines changed: 7 additions & 0 deletions
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 prod(int a, int b);
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# SPDX-FileCopyrightText: 2022 The meson-python developers
2+
#
3+
# SPDX-License-Identifier: MIT
4+
5+
example_lib2 = shared_library(
6+
'examplelib2',
7+
'examplelib2.c',
8+
c_args: export_dll_args,
9+
install: true,
10+
install_dir: py.get_install_dir() / 'mypkg/sub',
11+
)
12+
13+
example_lib2_dep = declare_dependency(
14+
compile_args: import_dll_args,
15+
link_with: example_lib2,
16+
)
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// SPDX-FileCopyrightText: 2022 The meson-python developers
2+
//
3+
// SPDX-License-Identifier: MIT
4+
5+
#pragma once
6+
7+
// MYPKG_DLL
8+
// inspired by https://github.com/abseil/abseil-cpp/blob/20240116.2/absl/base/config.h#L736-L753
9+
// and https://github.com/scipy/scipy/blob/9ded83b51099eee745418ccbb30196db96c81f3f/scipy/_build_utils/src/scipy_dll.h
10+
//
11+
// When building the `examplelib` DLL, this macro expands to `__declspec(dllexport)`
12+
// so we can annotate symbols appropriately as being exported. When used in
13+
// headers consuming a DLL, this macro expands to `__declspec(dllimport)` so
14+
// that consumers know the symbol is defined inside the DLL. In all other cases,
15+
// the macro expands to nothing.
16+
// Note: MYPKG_DLL_{EX,IM}PORTS are set in mypkg/meson.build
17+
#if defined(MYPKG_DLL_EXPORTS)
18+
#define MYPKG_DLL __declspec(dllexport)
19+
#elif defined(MYPKG_DLL_IMPORTS)
20+
#define MYPKG_DLL __declspec(dllimport)
21+
#else
22+
#define MYPKG_DLL
23+
#endif

0 commit comments

Comments
 (0)