Skip to content

Commit

Permalink
Fix external DLL loading on wheels (#2811)
Browse files Browse the repository at this point in the history
* Fix external DLL loading on wheels

* Use SetDefaultDllDirectoriess and AddDllDirectory

* Add previous paths

* Trigger debug

* Do not call SetDefaultDllDirectories.

* Do not call loadlibrary if the extensions were not compiled

* Fix lint issues
  • Loading branch information
andfoy authored Oct 15, 2020
1 parent 16ef312 commit 072d8b2
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 2 deletions.
6 changes: 6 additions & 0 deletions packaging/wheel/relocate.py
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,12 @@ def relocate_elf_library(patchelf, output_dir, output_library, binary):


def relocate_dll_library(dumpbin, output_dir, output_library, binary):
"""
Relocate a DLL/PE shared library to be packaged on a wheel.
Given a shared library, find the transitive closure of its dependencies,
rename and copy them into the wheel.
"""
print('Relocating {0}'.format(binary))
binary_path = osp.join(output_library, binary)

Expand Down
23 changes: 23 additions & 0 deletions torchvision/extension.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,29 @@ def _register_extensions():

# load the custom_op_library and register the custom ops
lib_dir = os.path.dirname(__file__)
if os.name == 'nt':
# Register the main torchvision library location on the default DLL path
import ctypes
import sys

kernel32 = ctypes.WinDLL('kernel32.dll', use_last_error=True)
with_load_library_flags = hasattr(kernel32, 'AddDllDirectory')
prev_error_mode = kernel32.SetErrorMode(0x0001)

if with_load_library_flags:
kernel32.AddDllDirectory.restype = ctypes.c_void_p

if sys.version_info >= (3, 8):
os.add_dll_directory(lib_dir)
elif with_load_library_flags:
res = kernel32.AddDllDirectory(lib_dir)
if res is None:
err = ctypes.WinError(ctypes.get_last_error())
err.strerror += f' Error adding "{lib_dir}" to the DLL directories.'
raise err

kernel32.SetErrorMode(prev_error_mode)

loader_details = (
importlib.machinery.ExtensionFileLoader,
importlib.machinery.EXTENSION_SUFFIXES
Expand Down
25 changes: 24 additions & 1 deletion torchvision/io/_video_opt.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
_HAS_VIDEO_OPT = False

try:
lib_dir = os.path.join(os.path.dirname(__file__), "..")
lib_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))

loader_details = (
importlib.machinery.ExtensionFileLoader,
Expand All @@ -22,6 +22,29 @@

extfinder = importlib.machinery.FileFinder(lib_dir, loader_details)
ext_specs = extfinder.find_spec("video_reader")

if os.name == 'nt':
# Load the video_reader extension using LoadLibraryExW
import ctypes
import sys

kernel32 = ctypes.WinDLL('kernel32.dll', use_last_error=True)
with_load_library_flags = hasattr(kernel32, 'AddDllDirectory')
prev_error_mode = kernel32.SetErrorMode(0x0001)

if with_load_library_flags:
kernel32.LoadLibraryExW.restype = ctypes.c_void_p

if ext_specs is not None:
res = kernel32.LoadLibraryExW(ext_specs.origin, None, 0x00001100)
if res is None:
err = ctypes.WinError(ctypes.get_last_error())
err.strerror += (f' Error loading "{ext_specs.origin}" or any or '
'its dependencies.')
raise err

kernel32.SetErrorMode(prev_error_mode)

if ext_specs is not None:
torch.ops.load_library(ext_specs.origin)
_HAS_VIDEO_OPT = True
Expand Down
26 changes: 25 additions & 1 deletion torchvision/io/image.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
_HAS_IMAGE_OPT = False

try:
lib_dir = osp.join(osp.dirname(__file__), "..")
lib_dir = osp.abspath(osp.join(osp.dirname(__file__), ".."))

loader_details = (
importlib.machinery.ExtensionFileLoader,
Expand All @@ -16,6 +16,30 @@

extfinder = importlib.machinery.FileFinder(lib_dir, loader_details) # type: ignore[arg-type]
ext_specs = extfinder.find_spec("image")

if os.name == 'nt':
# Load the image extension using LoadLibraryExW
import ctypes
import sys

kernel32 = ctypes.WinDLL('kernel32.dll', use_last_error=True)
with_load_library_flags = hasattr(kernel32, 'AddDllDirectory')
prev_error_mode = kernel32.SetErrorMode(0x0001)

kernel32.LoadLibraryW.restype = ctypes.c_void_p
if with_load_library_flags:
kernel32.LoadLibraryExW.restype = ctypes.c_void_p

if ext_specs is not None:
res = kernel32.LoadLibraryExW(ext_specs.origin, None, 0x00001100)
if res is None:
err = ctypes.WinError(ctypes.get_last_error())
err.strerror += (f' Error loading "{ext_specs.origin}" or any or '
'its dependencies.')
raise err

kernel32.SetErrorMode(prev_error_mode)

if ext_specs is not None:
torch.ops.load_library(ext_specs.origin)
_HAS_IMAGE_OPT = True
Expand Down

0 comments on commit 072d8b2

Please sign in to comment.