From b0a446851ea603844e0972080cb87bd9a9aa1aae Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Mon, 28 Oct 2024 18:02:11 +0100 Subject: [PATCH] TST: add package linking a library from a subproject Note that for Meson versions older than 1.2.0, CI failed with: ``` mesonpy.BuildError: Could not map installation path to an equivalent wheel directory: '{libdir_static}/libexamplelib.a' ``` because the `--skip-subprojects` install option isn't honored. Hence the test skip on older versions. In addition, the `c_shared_libs` usage requires Meson 1.3.0 --- .../foo/__init__.py | 8 ++++ .../foo/_examplemod.c | 37 +++++++++++++++++++ .../foo/meson.build | 16 ++++++++ .../link-library-in-subproject/meson.build | 17 +++++++++ .../link-library-in-subproject/pyproject.toml | 15 ++++++++ .../subprojects/bar/bar_dll.h | 19 ++++++++++ .../subprojects/bar/examplelib.c | 9 +++++ .../subprojects/bar/examplelib.h | 7 ++++ .../subprojects/bar/meson.build | 36 ++++++++++++++++++ tests/test_wheel.py | 7 ++++ 10 files changed, 171 insertions(+) create mode 100644 tests/packages/link-library-in-subproject/foo/__init__.py create mode 100644 tests/packages/link-library-in-subproject/foo/_examplemod.c create mode 100644 tests/packages/link-library-in-subproject/foo/meson.build create mode 100644 tests/packages/link-library-in-subproject/meson.build create mode 100644 tests/packages/link-library-in-subproject/pyproject.toml create mode 100644 tests/packages/link-library-in-subproject/subprojects/bar/bar_dll.h create mode 100644 tests/packages/link-library-in-subproject/subprojects/bar/examplelib.c create mode 100644 tests/packages/link-library-in-subproject/subprojects/bar/examplelib.h create mode 100644 tests/packages/link-library-in-subproject/subprojects/bar/meson.build diff --git a/tests/packages/link-library-in-subproject/foo/__init__.py b/tests/packages/link-library-in-subproject/foo/__init__.py new file mode 100644 index 00000000..58482491 --- /dev/null +++ b/tests/packages/link-library-in-subproject/foo/__init__.py @@ -0,0 +1,8 @@ +# SPDX-FileCopyrightText: 2024 The meson-python developers +# +# SPDX-License-Identifier: MIT + +from ._example import example_sum + + +__all__ = ['example_sum'] diff --git a/tests/packages/link-library-in-subproject/foo/_examplemod.c b/tests/packages/link-library-in-subproject/foo/_examplemod.c new file mode 100644 index 00000000..d6955699 --- /dev/null +++ b/tests/packages/link-library-in-subproject/foo/_examplemod.c @@ -0,0 +1,37 @@ +// SPDX-FileCopyrightText: 2022 The meson-python developers +// +// SPDX-License-Identifier: MIT + +#include + +#include "examplelib.h" + +static PyObject* example_sum(PyObject* self, PyObject *args) +{ + int a, b; + if (!PyArg_ParseTuple(args, "ii", &a, &b)) { + return NULL; + } + + long result = sum(a, b); + + return PyLong_FromLong(result); +} + +static PyMethodDef methods[] = { + {"example_sum", (PyCFunction)example_sum, METH_VARARGS, NULL}, + {NULL, NULL, 0, NULL}, +}; + +static struct PyModuleDef module = { + PyModuleDef_HEAD_INIT, + "_example", + NULL, + -1, + methods, +}; + +PyMODINIT_FUNC PyInit__example(void) +{ + return PyModule_Create(&module); +} diff --git a/tests/packages/link-library-in-subproject/foo/meson.build b/tests/packages/link-library-in-subproject/foo/meson.build new file mode 100644 index 00000000..a171be52 --- /dev/null +++ b/tests/packages/link-library-in-subproject/foo/meson.build @@ -0,0 +1,16 @@ +# SPDX-FileCopyrightText: 2022 The meson-python developers +# +# SPDX-License-Identifier: MIT + +py.extension_module( + '_example', + '_examplemod.c', + dependencies: bar_dep, + install: true, + subdir: 'foo', +) + +py.install_sources( + ['__init__.py'], + subdir: 'foo', +) diff --git a/tests/packages/link-library-in-subproject/meson.build b/tests/packages/link-library-in-subproject/meson.build new file mode 100644 index 00000000..eaa82951 --- /dev/null +++ b/tests/packages/link-library-in-subproject/meson.build @@ -0,0 +1,17 @@ +# SPDX-FileCopyrightText: 2022 The meson-python developers +# +# SPDX-License-Identifier: MIT + +project( + 'link-library-in-subproject', + 'c', + version: '1.0.0', + meson_version: '>=1.2.0', +) + +py = import('python').find_installation(pure: false) + +bar_proj = subproject('bar') +bar_dep = bar_proj.get_variable('bar_dep') + +subdir('foo') diff --git a/tests/packages/link-library-in-subproject/pyproject.toml b/tests/packages/link-library-in-subproject/pyproject.toml new file mode 100644 index 00000000..212bb3d1 --- /dev/null +++ b/tests/packages/link-library-in-subproject/pyproject.toml @@ -0,0 +1,15 @@ +# SPDX-FileCopyrightText: 2022 The meson-python developers +# +# SPDX-License-Identifier: MIT + +[build-system] +build-backend = 'mesonpy' +requires = ['meson-python'] + +[project] +name = 'link-library-in-subproject' +version = '1.2.3' + +[tool.meson-python.args] +setup = ['--default-library=static'] +install = ['--skip-subprojects'] diff --git a/tests/packages/link-library-in-subproject/subprojects/bar/bar_dll.h b/tests/packages/link-library-in-subproject/subprojects/bar/bar_dll.h new file mode 100644 index 00000000..61a6d7bc --- /dev/null +++ b/tests/packages/link-library-in-subproject/subprojects/bar/bar_dll.h @@ -0,0 +1,19 @@ +// SPDX-FileCopyrightText: 2024 The meson-python developers +// +// SPDX-License-Identifier: MIT + +#pragma once + +// When building the `examplelib` DLL, this macro expands to `__declspec(dllexport)` +// so we can annotate symbols appropriately as being exported. When used in +// headers consuming a DLL, this macro expands to `__declspec(dllimport)` so +// that consumers know the symbol is defined inside the DLL. In all other cases, +// the macro expands to nothing. +// Note: BAR_DLL_{EX,IM}PORTS are set in meson.build +#if defined(BAR_DLL_EXPORTS) + #define BAR_DLL __declspec(dllexport) +#elif defined(BAR_DLL_IMPORTS) + #define BAR_DLL __declspec(dllimport) +#else + #define BAR_DLL +#endif diff --git a/tests/packages/link-library-in-subproject/subprojects/bar/examplelib.c b/tests/packages/link-library-in-subproject/subprojects/bar/examplelib.c new file mode 100644 index 00000000..7efb3667 --- /dev/null +++ b/tests/packages/link-library-in-subproject/subprojects/bar/examplelib.c @@ -0,0 +1,9 @@ +// SPDX-FileCopyrightText: 2022 The meson-python developers +// +// SPDX-License-Identifier: MIT + +#include "bar_dll.h" + +BAR_DLL int sum(int a, int b) { + return a + b; +} diff --git a/tests/packages/link-library-in-subproject/subprojects/bar/examplelib.h b/tests/packages/link-library-in-subproject/subprojects/bar/examplelib.h new file mode 100644 index 00000000..c0f9e5ec --- /dev/null +++ b/tests/packages/link-library-in-subproject/subprojects/bar/examplelib.h @@ -0,0 +1,7 @@ +// SPDX-FileCopyrightText: 2022 The meson-python developers +// +// SPDX-License-Identifier: MIT + +#include "bar_dll.h" + +BAR_DLL int sum(int a, int b); diff --git a/tests/packages/link-library-in-subproject/subprojects/bar/meson.build b/tests/packages/link-library-in-subproject/subprojects/bar/meson.build new file mode 100644 index 00000000..503257bc --- /dev/null +++ b/tests/packages/link-library-in-subproject/subprojects/bar/meson.build @@ -0,0 +1,36 @@ +# SPDX-FileCopyrightText: 2022 The meson-python developers +# +# SPDX-License-Identifier: MIT + +project('bar', 'c', version: '1.2.3', meson_version: '>= 1.3.0') + +if get_option('default_library') == 'shared' and meson.get_compiler('c').get_id() in ['msvc', 'clang-cl', 'intel-cl'] + export_dll_args = ['-DBAR_DLL_EXPORTS'] + import_dll_args = ['-DBAR_DLL_IMPORTS'] +else + export_dll_args = [] + import_dll_args = [] +endif + +example_lib = library( + 'examplelib', + 'examplelib.c', + c_shared_args: export_dll_args, + install: true, +) + +# A second library that we don't link from `foo`. If we install the subproject, +# this second library also ends up in the wheel. To prevent that, we need to +# skip installing this `bar` subproject, and statically link `example_lib`. +unwanted_lib = library( + 'unwantedlib', + 'examplelib.c', + c_shared_args: export_dll_args, + install: true, +) + +bar_dep = declare_dependency( + compile_args: import_dll_args, + link_with: example_lib, + include_directories: '.', +) diff --git a/tests/test_wheel.py b/tests/test_wheel.py index a663d15b..5b3f679d 100644 --- a/tests/test_wheel.py +++ b/tests/test_wheel.py @@ -169,6 +169,13 @@ def test_sharedlib_in_package(venv, wheel_sharedlib_in_package): assert int(output) == 42 +@pytest.mark.skipif(MESON_VERSION < (1, 3, 0), reason='Meson version 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 not in {'linux', 'darwin', 'sunos5'}, reason='Not supported on this platform') def test_rpath(wheel_link_against_local_lib, tmp_path): artifact = wheel.wheelfile.WheelFile(wheel_link_against_local_lib)