Skip to content
Merged
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
11 changes: 10 additions & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,16 @@ jobs:
env:
CIBW_BUILD_VERBOSITY: 3
CIBW_BEFORE_BUILD_WINDOWS: "pip install delvewheel"
CIBW_REPAIR_WHEEL_COMMAND_WINDOWS: "delvewheel repair --add-path ${{ github.workspace }}/vcpkg/installed/x64-windows-release/bin -w {dest_dir} {wheel}"
# --no-mangle-all + --add-dll icuin<ver>.dll are required so a *compiled*
# NLP++ analyzer (bin/run.dll / bin/kb.dll, dlopened at analyze time)
# can resolve its ICU imports. It imports icuin<ver>.dll + icuuc<ver>.dll
# by their real names; the default delvewheel run mangles those names and
# only vendors icuuc/icudt (what our extension itself imports), so the
# analyzer's icuin import goes unresolved and kb.dll fails to load. Keep
# real names (--no-mangle-all) and force-vendor icuin (--add-dll); the
# package then preloads them by name at import (NLPPlus._preload_icu).
# NOTE: bump "78" if the vcpkg ICU major version changes.
CIBW_REPAIR_WHEEL_COMMAND_WINDOWS: "delvewheel repair --no-mangle-all --add-dll icuin78.dll --add-path ${{ github.workspace }}/vcpkg/installed/x64-windows-release/bin -w {dest_dir} {wheel}"
CIBW_CONFIG_SETTINGS: "cmake.args='-A x64;-DCMAKE_BUILD_TYPE=Release;-DCMAKE_TOOLCHAIN_FILE=${{ github.workspace }}/vcpkg/scripts/buildsystems/vcpkg.cmake'"

- uses: actions/upload-artifact@v4
Expand Down
58 changes: 56 additions & 2 deletions NLPPlus/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,65 @@
import os
import glob

from .bindings import NLP_ENGINE # type: ignore

LOGGER = logging.getLogger("NLPPlus")


def _preload_icu() -> None:
"""Load the vendored ICU (and MSVC runtime) DLLs by their real names.

A *compiled* NLP++ analyzer ships as a self-contained shared library
(``bin/run.<ext>`` / ``bin/kb.<ext>``) that imports ``icuin<ver>.dll``
and ``icuuc<ver>.dll`` **by name**. The engine loads that library at
analyze time with a plain ``LoadLibrary(full_path)``, whose dependency
resolution only consults modules already loaded in the process (matched
by base name), the library's own directory, and the system path — it
does *not* consult ``os.add_dll_directory`` entries.

Our own extension only pulls in ``icuuc`` (+ its ``icudt`` data), so
without help ``icuin`` is never loaded and the compiled KB library fails
with ``[Couldn't load library: ...\\bin\\kb.dll]``. Pre-loading every
vendored ``icu*``/``msvcp*`` DLL here, in dependency order and under
their real (un-mangled) names, makes them memory-resident so a compiled
analyzer binds them straight from memory. Requires the wheel to have
been repaired with ``--no-mangle-all`` (real names) and ``icuin`` force
added via ``--add-dll`` since it is not a dependency of our extension.

No-op off Windows (Linux/macOS resolve ``.so``/``.dylib`` deps via
``RPATH``/``@loader_path`` set by ``auditwheel``/``delocate``).
"""
if os.name != "nt":
return
import ctypes

here = Path(__file__).resolve().parent
# delvewheel vendors DLLs into a sibling ``<distribution>.libs`` folder.
libdirs = [
here.parent / "nlpplus.libs",
here.parent / "NLPPlus.libs",
]
for libs in libdirs:
if not libs.is_dir():
continue
try:
os.add_dll_directory(str(libs))
except (OSError, AttributeError):
pass
# Dependency order: data (icudt) -> common (icuuc) -> i18n (icuin).
# msvcp is pulled first as the C++ runtime the analyzer also imports.
for stem in ("msvcp", "vcruntime", "icudt", "icuuc", "icuin"):
for dll in sorted(libs.glob(stem + "*.dll")):
try:
ctypes.WinDLL(str(dll))
except OSError:
pass
break


_preload_icu()

from .bindings import NLP_ENGINE # type: ignore # noqa: E402


def maybe_readfile(path: Path) -> Optional[str]:
"""Bogus utility function to maybe read a file."""
if not path.exists():
Expand Down
Loading