Skip to content
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
6 changes: 5 additions & 1 deletion cmake/nanobind-config.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -590,7 +590,7 @@ endfunction()
# ---------------------------------------------------------------------------

function (nanobind_add_stub name)
cmake_parse_arguments(PARSE_ARGV 1 ARG "VERBOSE;INCLUDE_PRIVATE;EXCLUDE_DOCSTRINGS;INSTALL_TIME;RECURSIVE;EXCLUDE_FROM_ALL" "MODULE;COMPONENT;PATTERN_FILE;OUTPUT_PATH" "PYTHON_PATH;DEPENDS;MARKER_FILE;OUTPUT")
cmake_parse_arguments(PARSE_ARGV 1 ARG "VERBOSE;INCLUDE_PRIVATE;EXCLUDE_DOCSTRINGS;INSTALL_TIME;RECURSIVE;EXCLUDE_FROM_ALL" "MODULE;COMPONENT;PATTERN_FILE;OUTPUT_PATH" "PYTHON_PATH;LIB_PATH;DEPENDS;MARKER_FILE;OUTPUT")

if (EXISTS ${NB_DIR}/src/stubgen.py)
set(NB_STUBGEN "${NB_DIR}/src/stubgen.py")
Expand Down Expand Up @@ -622,6 +622,10 @@ function (nanobind_add_stub name)
list(APPEND NB_STUBGEN_ARGS -i "${PYTHON_PATH}")
endforeach()

foreach (LIB_PATH IN LISTS ARG_LIB_PATH)
list(APPEND NB_STUBGEN_ARGS -L "${LIB_PATH}")
endforeach()

if (ARG_PATTERN_FILE)
list(APPEND NB_STUBGEN_ARGS -p "${ARG_PATTERN_FILE}")
endif()
Expand Down
8 changes: 8 additions & 0 deletions docs/api_cmake.rst
Original file line number Diff line number Diff line change
Expand Up @@ -492,6 +492,14 @@ Nanobind's CMake tooling includes a convenience command to interface with the
generation. Otherwise, generator expressions should not be used.
Optional.

* - ``LIB_PATH``
- List of search paths that should be considered when searching for
shared libraries. This can be useful when the python module being
imported depends on shared libraries that are not in the default
search path. The paths are relative to ``CMAKE_CURRENT_BINARY_DIR``
for build-time stub generation and relative to
``CMAKE_INSTALL_PREFIX`` for install-time stub generation. Optional.

* - ``DEPENDS``
- Any targets listed here will be marked as a dependencies. This should
generally be used to list the target names of one or more prior
Expand Down
7 changes: 5 additions & 2 deletions docs/typing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -539,8 +539,9 @@ The program has the following command line options:

.. code-block:: text

usage: python -m nanobind.stubgen [-h] [-o FILE] [-O PATH] [-i PATH] [-m MODULE]
[-r] [-M FILE] [-P] [-D] [-q]
usage: python -m nanobind.stubgen [-h] [-o FILE] [-O PATH] [-i PATH]
[-L PATH] [-m MODULE] [-r] [-M FILE] [-P]
[-D] [-q]

Generate stubs for nanobind-based extensions.

Expand All @@ -550,6 +551,8 @@ The program has the following command line options:
-O PATH, --output-dir PATH write generated stubs to the specified directory
-i PATH, --import PATH add the directory to the Python import path (can
specify multiple times)
-L PATH, --lib-path PATH add directory to shared library search path (can
specify multiple times)
-m MODULE, --module MODULE generate a stub for the specified module (can
specify multiple times)
-r, --recursive recursively process submodules
Expand Down
21 changes: 21 additions & 0 deletions src/stubgen.py
Original file line number Diff line number Diff line change
Expand Up @@ -1263,6 +1263,16 @@ def parse_options(args: List[str]) -> argparse.Namespace:
help="add the directory to the Python import path (can specify multiple times)",
)

parser.add_argument(
"-L",
"--lib-path",
action="append",
metavar="PATH",
dest="lib_paths",
default=[],
help="add directory to shared library search path (can specify multiple times)"
)

parser.add_argument(
"-m",
"--module",
Expand Down Expand Up @@ -1396,6 +1406,7 @@ def add_pattern(query: str, lines: List[str]):

def main(args: Optional[List[str]] = None) -> None:
import sys
import os

# Ensure that the current directory is on the path
if "" not in sys.path and "." not in sys.path:
Expand All @@ -1416,6 +1427,16 @@ def main(args: Optional[List[str]] = None) -> None:
for i in opt.imports:
sys.path.insert(0, i)

if os.name == 'nt':
for lib_path in opt.lib_paths:
os.add_dll_directory(lib_path)
else:
lib_env = "DYLD_LIBRARY_PATH" if sys.platform == "darwin" else "LD_LIBRARY_PATH"
old_value = os.environ.get(lib_env, "")
paths_str = ":".join(opt.lib_paths)
if paths_str:
os.environ[lib_env] = f"{paths_str}:{old_value}" if old_value else paths_str

for i, mod in enumerate(opt.modules):
if not opt.quiet:
if i > 0:
Expand Down