Skip to content

Commit fdae0da

Browse files
committed
Fix DLL preload for the libdynd default install location.
1 parent f462ffb commit fdae0da

4 files changed

Lines changed: 67 additions & 125 deletions

File tree

dynd/__init__.py

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,24 +6,17 @@
66
import pkgutil
77
__path__ = pkgutil.extend_path(__path__, __name__)
88

9-
try: # Only the import from dynd.ndt is expected to succeed.
9+
# The 'common' import is only supposed to work from the dynd.ndt sub-package.
10+
# If dynd.nd/dynd/__init__.py and dynd.ndt/dynd/__init__.py are the same file,
11+
# this ImportError must be ignored. The alternative is to ship two different
12+
# __init__.py files and remove the import from dynd.nd/dynd/__init__.py.
13+
try:
1014
from .common import *
1115
except ImportError:
1216
pass
1317

1418
__all__ = [
15-
'__libdynd_version__', '__version__', '__libdynd_git_sha1__', ' __git_sha1__',
19+
'__libdynd_version__', '__version__', '__libdynd_git_sha1__', '__git_sha1__',
1620
'annotate', 'test', 'load'
1721
]
1822

19-
20-
try: del common
21-
except: pass
22-
23-
try: del pkgutil
24-
except: pass
25-
26-
try: del pkg_resources
27-
except: pass
28-
29-

dynd/common/__init__.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,60 @@
1+
2+
def _load_win_dll(dirname, dll):
3+
# Manually load dlls before loading the extension modules.
4+
# This is handled via rpaths on Unix based systems.
5+
import ctypes
6+
import sys
7+
import os.path
8+
def load_dynd_dll(rootpath):
9+
try:
10+
ctypes.cdll.LoadLibrary(os.path.join(rootpath, dll))
11+
return True
12+
except OSError:
13+
return False
14+
# If the dll has been placed in the dynd-python installation, use that
15+
loaded = load_dynd_dll(dirname)
16+
# Next, try the default DLL search path
17+
loaded = loaded or load_dynd_dll('')
18+
if not loaded:
19+
# Try to load it from the Program Files directories where libdynd
20+
# installs by default. This matches the search path for libdynd used
21+
# in the CMake build for dynd-python.
22+
is_64_bit = sys.maxsize > 2**32
23+
processor_arch = os.environ.get('PROCESSOR_ARCHITECTURE')
24+
err_str = ('Fallback search for %s failed because the "{}" '
25+
'environment variable was not set. Please make sure that '
26+
'either %s is on the DLL search path or that it is '
27+
'in the default install directory and the runtime '
28+
'environment has the necessary system-specified '
29+
'environment variables properly set. On 64 bit Windows '
30+
'with 64 bit Python the needed variables are '
31+
'"PROCESSOR_ARCHITECTURE" and "ProgramFiles". On 64 bit '
32+
'Windows with 32 bit Python the needed variables are '
33+
'"PROCESSOR_ARCHITECTURE" and "ProgramFiles(x86)". On 32 '
34+
'bit Windows the needed variables are '
35+
'"PROCESSOR_ARCHITECTURE" and "ProgramFiles".' % (dll, dll))
36+
if processor_arch is None:
37+
raise RuntimeError(err_str.format('PROCESSOR_ARCHITECTURE'))
38+
is_32_on_64_bit = (is_64_bit and not processor_arch.endswith('64'))
39+
if not is_32_on_64_bit:
40+
prog_files = os.environ.get('ProgramFiles')
41+
if prog_files is None:
42+
raise RuntimeError(err_str.format('ProgramFiles'))
43+
else:
44+
prog_files = os.environ.get('ProgramFiles(x86)')
45+
if prog_files is None:
46+
raise RuntimeError(err_str.format('ProgramFiles(x86)'))
47+
dynd_lib_dir = os.path.join(prog_files, 'libdynd', 'lib')
48+
if os.path.isdir(dynd_lib_dir):
49+
loaded = load_dynd_dll(dynd_lib_dir)
50+
if not loaded:
51+
raise ctypes.WinError(126, 'Could not load %s' % dll)
52+
53+
import os, os.path
54+
if os.name == 'nt':
55+
_load_win_dll(os.path.dirname(os.path.dirname(__file__)), 'libdyndt.dll')
56+
57+
158
from ..config import _dynd_version_string as __libdynd_version__, \
259
_dynd_python_version_string as __version__, \
360
_dynd_git_sha1 as __libdynd_git_sha1__, \

dynd/nd/__init__.py

Lines changed: 3 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,9 @@
1-
from .. import ndt # ensure that the module is loaded first
1+
from ..common import _load_win_dll # this also ensures that libdyndt is loaded first
2+
import os, os.path
23
import sys
3-
import os
44

55
if os.name == 'nt':
6-
# Manually load dlls before loading the extension modules.
7-
# This is handled via rpaths on Unix based systems.
8-
import ctypes
9-
import os.path
10-
def load_dynd_dll(rootpath):
11-
try:
12-
ctypes.cdll.LoadLibrary(os.path.join(rootpath, 'libdynd.dll'))
13-
return True
14-
except OSError:
15-
return False
16-
# If libdynd.dll has been placed in the dynd-python installation, use that
17-
nddir = os.path.dirname(os.path.dirname(__file__))
18-
loaded = load_dynd_dll(nddir)
19-
# Next, try the default DLL search path
20-
loaded = loaded or load_dynd_dll('')
21-
if not loaded:
22-
# Try to load it from the Program Files directories where libdynd
23-
# installs by default. This matches the search path for libdynd used
24-
# in the CMake build for dynd-python.
25-
is_64_bit = sys.maxsize > 2**32
26-
processor_arch = os.environ.get('PROCESSOR_ARCHITECTURE')
27-
err_str = ('Fallback search for libdynd.dll failed because the "{}" '
28-
'environment variable was not set. Please make sure that '
29-
'either libdynd is on the DLL search path or that it is '
30-
'in the default install directory and the runtime '
31-
'environment has the necessary system-specified '
32-
'environment variables properly set. On 64 bit Windows '
33-
'with 64 bit Python the needed variables are '
34-
'"PROCESSOR_ARCHITECTURE" and "ProgramFiles". On 64 bit '
35-
'Windows with 32 bit Python the needed variables are '
36-
'"PROCESSOR_ARCHITECTURE" and "ProgramFiles(x86)". On 32 '
37-
'bit Windows the needed variables are '
38-
'"PROCESSOR_ARCHITECTURE" and "ProgramFiles".')
39-
if processor_arch is None:
40-
raise RuntimeError(err_str.format('PROCESSOR_ARCHITECTURE'))
41-
is_32_on_64_bit = (is_64_bit and not processor_arch.endswith('64'))
42-
if not is_32_on_64_bit:
43-
prog_files = os.environ.get('ProgramFiles')
44-
if prog_files is None:
45-
raise RuntimeError(err_str.format('ProgramFiles'))
46-
else:
47-
prog_files = os.environ.get('ProgramFiles(x86)')
48-
if prog_files is None:
49-
raise RuntimeError(err_str.format('ProgramFiles(x86)'))
50-
dynd_lib_dir = os.path.join(prog_files, 'libdynd', 'lib')
51-
if os.path.isdir(dynd_lib_dir):
52-
loaded = load_dynd_dll(dynd_lib_dir)
53-
if not loaded:
54-
raise ctypes.WinError(126, 'Could not load libdynd.dll')
55-
6+
_load_win_dll(os.path.dirname(os.path.dirname(__file__)), 'libdynd.dll')
567

578
from dynd.config import *
589

@@ -74,7 +25,3 @@ def load_dynd_dll(rootpath):
7425
# return _parse(tp, obj)
7526

7627
publish_callables(sys.modules[__name__])
77-
78-
del os
79-
del sys
80-
del ndt

dynd/ndt/__init__.py

Lines changed: 1 addition & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,4 @@
1-
import sys
2-
import os
3-
4-
if os.name == 'nt':
5-
# Manually load dlls before loading the extension modules.
6-
# This is handled via rpaths on Unix based systems.
7-
import ctypes
8-
import os.path
9-
def load_dynd_dll(rootpath):
10-
try:
11-
ctypes.cdll.LoadLibrary(os.path.join(rootpath, 'libdyndt.dll'))
12-
return True
13-
except OSError:
14-
return False
15-
# If libdyndt.dll has been placed in the dynd-python installation, use that
16-
ndtdir = os.path.dirname(os.path.dirname(__file__))
17-
loaded = load_dynd_dll(ndtdir)
18-
# Next, try the default DLL search path
19-
loaded = loaded or load_dynd_dll('')
20-
if not loaded:
21-
# Try to load it from the Program Files directories where libdynd
22-
# installs by default. This matches the search path for libdynd used
23-
# in the CMake build for dynd-python.
24-
is_64_bit = sys.maxsize > 2**32
25-
processor_arch = os.environ.get('PROCESSOR_ARCHITECTURE')
26-
err_str = ('Fallback search for libdyndt.dll failed because the "{}" '
27-
'environment variable was not set. Please make sure that '
28-
'either libdyndt is on the DLL search path or that it is '
29-
'in the default install directory and the runtime '
30-
'environment has the necessary system-specified '
31-
'environment variables properly set. On 64 bit Windows '
32-
'with 64 bit Python the needed variables are '
33-
'"PROCESSOR_ARCHITECTURE" and "ProgramFiles". On 64 bit '
34-
'Windows with 32 bit Python the needed variables are '
35-
'"PROCESSOR_ARCHITECTURE" and "ProgramFiles(x86)". On 32 '
36-
'bit Windows the needed variables are '
37-
'"PROCESSOR_ARCHITECTURE" and "ProgramFiles".')
38-
if processor_arch is None:
39-
raise RuntimeError(err_str.format('PROCESSOR_ARCHITECTURE'))
40-
is_32_on_64_bit = (is_64_bit and not processor_arch.endswith('64'))
41-
if not is_32_on_64_bit:
42-
prog_files = os.environ.get('ProgramFiles')
43-
if prog_files is None:
44-
raise RuntimeError(err_str.format('ProgramFiles'))
45-
else:
46-
prog_files = os.environ.get('ProgramFiles(x86)')
47-
if prog_files is None:
48-
raise RuntimeError(err_str.format('ProgramFiles(x86)'))
49-
dynd_lib_dir = os.path.join(prog_files, 'libdynd', 'lib')
50-
if os.path.isdir(dynd_lib_dir):
51-
loaded = load_dynd_dll(dynd_lib_dir)
52-
if not loaded:
53-
raise ctypes.WinError(126, 'Could not load libdyndt.dll')
1+
from .. import common # ensure that libdyndt is loaded
542

553
from .type import make_fixed_bytes, make_fixed_string, make_struct, \
564
make_fixed_dim, make_string, make_var_dim, make_fixed_dim_kind, \
@@ -63,6 +11,3 @@ def load_dynd_dll(rootpath):
6311
from . import dynd_ctypes as ctypes
6412

6513
from . import json
66-
67-
del os
68-
del sys

0 commit comments

Comments
 (0)