Skip to content

Commit b4ec8b4

Browse files
committed
Move the Windows PATH update logic into the WindowsImportWrapper
1 parent 4a8c0d2 commit b4ec8b4

File tree

2 files changed

+53
-48
lines changed

2 files changed

+53
-48
lines changed

build_scripts/pypi/package_files/setup.py

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -59,28 +59,6 @@ def windows():
5959
for f in dll_files:
6060
shutil.move(f, os.path.join(BUILD_DIR, "lib/python/pxr"))
6161

62-
# Because there are no RPATHS, patch __init__.py
63-
# See this thread and related conversations
64-
# https://mail.python.org/pipermail/distutils-sig/2014-September/024962.html
65-
with open(os.path.join(BUILD_DIR, 'lib/python/pxr/__init__.py'), 'a+') as init_file:
66-
init_file.write('''
67-
68-
# appended to this file for the windows PyPI package
69-
import os, sys
70-
dllPath = os.path.split(os.path.realpath(__file__))[0]
71-
if sys.version_info >= (3, 8, 0):
72-
os.environ['PXR_USD_WINDOWS_DLL_PATH'] = dllPath
73-
# Note that we ALWAYS modify the PATH, even for python-3.8+. This is because:
74-
# - Anaconda python interpreters are modified to use the old, pre-3.8, PATH-
75-
# based method of loading dlls
76-
# - extra calls to os.add_dll_directory won't hurt these anaconda
77-
# interpreters
78-
# - similarly, adding the extra PATH entry shouldn't hurt standard python
79-
# interpreters
80-
# - there's no canonical/bulletproof way to check for an anaconda interpreter
81-
os.environ['PATH'] = dllPath + os.pathsep + os.environ['PATH']
82-
''')
83-
8462
# Get the readme text
8563
with open("README.md", "r") as fh:
8664
long_description = fh.read()

pxr/base/tf/__init__.py

Lines changed: 53 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -12,53 +12,80 @@
1212
# and newer. These interpreters don't search for DLLs in the path anymore, you
1313
# have to provide a path explicitly. This re-enables path searching for USD
1414
# dependency libraries
15-
import platform, sys
16-
if sys.version_info >= (3, 8) and platform.system() == "Windows":
15+
16+
import platform
17+
if platform.system() == "Windows":
1718
import contextlib
1819

20+
_WINDOWS_IMPORT_WRAPPER_DEPTH = 0
21+
1922
@contextlib.contextmanager
2023
def WindowsImportWrapper():
21-
import os
24+
import os, sys
25+
26+
global _WINDOWS_IMPORT_WRAPPER_DEPTH
2227
dirs = []
28+
29+
path_updated = False
2330
import_paths = os.getenv('PXR_USD_WINDOWS_DLL_PATH')
2431
if import_paths is None:
25-
import_paths = os.getenv('PATH', '')
26-
# the underlying windows API call, AddDllDirectory, states that:
27-
#
28-
# > If AddDllDirectory is used to add more than one directory to the
29-
# > process DLL search path, the order in which those directories are
30-
# > searched is unspecified.
31-
#
32-
# https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-adddlldirectory
33-
#
34-
# However, in practice, it seems that the most-recently-added ones
35-
# take precedence - so, reverse the order of entries in PATH to give
36-
# it the same precedence
37-
#
38-
# Note that we have a test (testTfPyDllLink) to alert us if this
39-
# undefined behavior changes.
40-
for path in reversed(import_paths.split(os.pathsep)):
41-
# Calling add_dll_directory raises an exception if paths don't
42-
# exist, or if you pass in dot
43-
if os.path.exists(path) and path != '.':
44-
abs_path = os.path.abspath(path)
45-
dirs.append(os.add_dll_directory(abs_path))
32+
33+
import_paths = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
34+
os.environ['PXR_USD_WINDOWS_DLL_PATH'] = import_paths
35+
36+
# For python version <3.8 and Anaconda, os.envion['PATH'] is used to
37+
# populate the DLL search paths. Because there's no bulletproof way to
38+
# detect an Anaconda environment, we must always update PATH if the
39+
# PXR_USD_WINDOWS_DLL_PATH is set
40+
if _WINDOWS_IMPORT_WRAPPER_DEPTH == 0: # but only do it once
41+
path_updated = True
42+
os.environ['PATH'] = import_paths + os.pathsep + os.getenv('PATH', '')
43+
44+
if sys.version_info >= (3, 8):
45+
# the underlying windows API call, AddDllDirectory, states that:
46+
#
47+
# > If AddDllDirectory is used to add more than one directory to the
48+
# > process DLL search path, the order in which those directories are
49+
# > searched is unspecified.
50+
#
51+
# https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-adddlldirectory
52+
#
53+
# However, in practice, it seems that the most-recently-added ones
54+
# take precedence - so, reverse the order of entries in PATH to give
55+
# it the same precedence
56+
#
57+
# Note that we have a test (testTfPyDllLink) to alert us if this
58+
# undefined behavior changes.
59+
for path in reversed(import_paths.split(os.pathsep)):
60+
# Calling add_dll_directory raises an exception if paths don't
61+
# exist, or if you pass in dot
62+
if os.path.exists(path) and path != '.':
63+
abs_path = os.path.abspath(path)
64+
dirs.append(os.add_dll_directory(abs_path))
65+
4666
# This block guarantees we clear the dll directories if an exception
4767
# is raised in the with block.
68+
69+
_WINDOWS_IMPORT_WRAPPER_DEPTH += 1
4870
try:
4971
yield
5072
finally:
73+
_WINDOWS_IMPORT_WRAPPER_DEPTH -= 1
5174
for dll_dir in dirs:
5275
dll_dir.close()
53-
del os
76+
77+
if _WINDOWS_IMPORT_WRAPPER_DEPTH == 0 and path_updated:
78+
os.environ['PATH'] = os.environ['PATH'][:len(import_paths) + 1]
79+
80+
del os, sys
5481
del contextlib
5582
else:
5683
class WindowsImportWrapper(object):
5784
def __enter__(self):
5885
pass
5986
def __exit__(self, exc_type, ex_val, exc_tb):
6087
pass
61-
del platform, sys
88+
del platform
6289

6390

6491
def PreparePythonModule(moduleName=None):

0 commit comments

Comments
 (0)