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

ENH: support shared libraries inside packages #257

Open
wants to merge 2 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
20 changes: 18 additions & 2 deletions example_pkg/example_pkg/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,20 @@
from ._core import echo
import os
import sys

__all__ = ["echo"]
__all__ = ["echo", "example_sum"]
__version__ = "0.0.0dev0"


def _enable_sharedlib_loading():
basedir = os.path.dirname(__file__)
subdir = os.path.join(basedir, "submodule")
if os.name == "nt":
os.add_dll_directory(subdir)
elif sys.platform == "cygwin":
os.environ["PATH"] = f'os.environ["PATH"]{os.pathsep}{subdir}'


_enable_sharedlib_loading()


from ._core import echo, example_sum # noqa: E402
1 change: 1 addition & 0 deletions example_pkg/example_pkg/_core.pyi
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
def echo(str) -> None: ...
def example_sum(a: int, b: int) -> int: ...
15 changes: 15 additions & 0 deletions example_pkg/example_pkg/coremodule.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#define PY_SSIZE_T_CLEAN
#include <Python.h>

#include "shlib.h"

static PyObject *
core_echo(PyObject *self, PyObject *args)
{
Expand All @@ -17,8 +19,21 @@ core_echo(PyObject *self, PyObject *args)
return ret;
}

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 CoreMethods[] = {
{"echo", core_echo, METH_VARARGS, "Echo a string and return 42"},
{"example_sum", example_sum, METH_VARARGS, "Sum up two integers"},
{NULL, NULL, 0, NULL} /* Sentinel */
};

Expand Down
8 changes: 6 additions & 2 deletions example_pkg/example_pkg/meson.build
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
subdir('submodule')

py.extension_module(
'_core',
'coremodule.c',
include_directories: 'submodule',
dependencies: shlib_dep,
install: true,
subdir: 'example_pkg'
subdir: 'example_pkg',
install_rpath: '$ORIGIN/submodule',
)

python_sources = [
Expand All @@ -15,5 +20,4 @@ py.install_sources(
subdir: 'example_pkg'
)

install_subdir('submodule', install_dir: py.get_install_dir() / 'example_pkg')
install_subdir('tests', install_dir: py.get_install_dir() / 'example_pkg')
28 changes: 28 additions & 0 deletions example_pkg/example_pkg/submodule/meson.build
Original file line number Diff line number Diff line change
@@ -1 +1,29 @@
# Add a basic shared library, used from the Python extension module
# in ../coremodule.c
if meson.get_compiler('c').get_id() in ['msvc', 'clang-cl', 'intel-cl']
export_dll_args = ['-DSHLIB_DLL_EXPORTS']
import_dll_args = ['-DSHLIB_DLL_IMPORTS']
else
export_dll_args = []
import_dll_args = []
endif

shlib = shared_library(
'shlib',
'shlib.c',
c_args: export_dll_args,
install: true,
install_dir: py.get_install_dir() / 'example_pkg/submodule',
)

shlib_dep = declare_dependency(
compile_args: import_dll_args,
link_with: shlib,
)

py.install_sources(
['__init__.py'],
subdir: 'example_pkg/submodule',
)

install_subdir('tests', install_dir: py.get_install_dir() / 'example_pkg/submodule')
5 changes: 5 additions & 0 deletions example_pkg/example_pkg/submodule/shlib.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#include "shlib_dll.h"

SHLIB_DLL int sum(int a, int b) {
return a + b;
}
3 changes: 3 additions & 0 deletions example_pkg/example_pkg/submodule/shlib.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#include "shlib_dll.h"

SHLIB_DLL int sum(int a, int b);
14 changes: 14 additions & 0 deletions example_pkg/example_pkg/submodule/shlib_dll.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#pragma once

// Windows support. When building the `shlib` 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.
#if defined(SHLIB_DLL_EXPORTS)
#define SHLIB_DLL __declspec(dllexport)
#elif defined(SHLIB_DLL_IMPORTS)
#define SHLIB_DLL __declspec(dllimport)
#else
#define SHLIB_DLL
#endif
3 changes: 1 addition & 2 deletions example_pkg/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@ project(

cc = meson.get_compiler('c')

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

subdir('example_pkg')
17 changes: 5 additions & 12 deletions spin/cmds/meson.py
Original file line number Diff line number Diff line change
Expand Up @@ -231,11 +231,6 @@ def _check_coverage_tool_installation(coverage_type: GcovReportFormat, build_dir
)


if sys.platform.startswith("win"):
DEFAULT_PREFIX = "C:/"
else:
DEFAULT_PREFIX = "/usr"

build_dir_option = click.option(
"-C",
"--build-dir",
Expand Down Expand Up @@ -266,10 +261,10 @@ def _check_coverage_tool_installation(coverage_type: GcovReportFormat, build_dir
)
@click.option(
"--prefix",
help="The build prefix, passed directly to meson.",
help="The build prefix as an absolute path, passed directly to meson.",
type=str,
metavar="PREFIX",
default=DEFAULT_PREFIX,
default="",
)
@click.argument("meson_args", nargs=-1)
@build_dir_option
Expand Down Expand Up @@ -316,10 +311,12 @@ def build(
Which can then be used to build (`spin-clang build`), to test (`spin-clang test ...`), etc.

"""
abs_build_dir = os.path.abspath(build_dir)
install_dir = _get_install_dir(build_dir)
abs_install_dir = os.path.abspath(install_dir)

if not prefix:
prefix = abs_install_dir

cfg = get_config()
distname = cfg.get("project.name", None)
if distname and _is_editable_install_of_same_source(distname):
Expand Down Expand Up @@ -385,10 +382,6 @@ def build(
"--only-changed",
"-C",
build_dir,
"--destdir",
install_dir
if os.path.isabs(install_dir)
else os.path.relpath(abs_install_dir, abs_build_dir),
]
+ list(meson_install_args),
output=(not quiet) and verbose,
Expand Down
3 changes: 2 additions & 1 deletion spin/tests/test_build_cmds.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ def test_debug_builds(example_pkg):

def test_prefix_builds(example_pkg):
"""does spin build --prefix create a build-install directory with the correct structure?"""
spin("build", "--prefix=/foobar/")
prefix = Path.cwd() / "build-install" / "foobar"
spin("build", f"--prefix={prefix}")
assert (Path("build-install") / Path("foobar")).exists()


Expand Down
Loading