Skip to content

Commit

Permalink
python: fix windows build
Browse files Browse the repository at this point in the history
  • Loading branch information
lmontaut committed Jun 24, 2024
1 parent 5a7a374 commit 1696fba
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 2 deletions.
3 changes: 3 additions & 0 deletions python/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,8 @@ SET_TARGET_PROPERTIES(${PYTHON_LIB_NAME} PROPERTIES
SUFFIX "${PYTHON_EXT_SUFFIX}"
OUTPUT_NAME "${PYTHON_LIB_NAME}"
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/python/${PROJECT_NAME}"
# On Windows, shared library are treat as binary
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/python/${PROJECT_NAME}"
)

IF(IS_ABSOLUTE ${PYTHON_SITELIB})
Expand Down Expand Up @@ -169,6 +171,7 @@ ENDIF(GENERATE_PYTHON_STUBS)
SET(PYTHON_FILES
__init__.py
viewer.py
windows_dll_manager.py
)

FOREACH(python ${PYTHON_FILES})
Expand Down
29 changes: 27 additions & 2 deletions python/coal/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,30 @@
# POSSIBILITY OF SUCH DAMAGE.

# ruff: noqa: F401, F403
from .coal_pywrap import *
from .coal_pywrap import __raw_version__, __version__

# On Windows, if coal.dll is not in the same directory than
# the .pyd, it will not be loaded.
# We first try to load coal, then, if it fail and we are on Windows:
# 1. We add all paths inside COAL_WINDOWS_DLL_PATH to DllDirectory
# 2. If COAL_WINDOWS_DLL_PATH we add the relative path from the
# package directory to the bin directory to DllDirectory
# This solution is inspired from:
# - https://github.com/PixarAnimationStudios/OpenUSD/pull/1511/files
# - https://stackoverflow.com/questions/65334494/python-c-extension-packaging-dll-along-with-pyd
# More resources on https://github.com/diffpy/pyobjcryst/issues/33
try:
from .coal_pywrap import * # noqa
from .coal_pywrap import __raw_version__, __version__
except ImportError:
import platform

if platform.system() == "Windows":
from .windows_dll_manager import build_directory_manager, get_dll_paths

with build_directory_manager() as dll_dir_manager:
for p in get_dll_paths():
dll_dir_manager.add_dll_directory(p)
from .coal_pywrap import * # noqa
from .coal_pywrap import __raw_version__, __version__ # noqa
else:
raise
65 changes: 65 additions & 0 deletions python/coal/windows_dll_manager.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import contextlib
import os
import sys


def get_dll_paths():
coal_paths = os.getenv("COAL_WINDOWS_DLL_PATH")
if coal_paths is None:
# From https://peps.python.org/pep-0250/#implementation
# lib/python-version/site-packages/package
RELATIVE_DLL_PATH1 = "..\\..\\..\\..\\bin"
# lib/site-packages/package
RELATIVE_DLL_PATH2 = "..\\..\\..\\bin"
# For unit test
RELATIVE_DLL_PATH3 = "..\\..\\bin"
return [
os.path.join(os.path.dirname(__file__), RELATIVE_DLL_PATH1),
os.path.join(os.path.dirname(__file__), RELATIVE_DLL_PATH2),
os.path.join(os.path.dirname(__file__), RELATIVE_DLL_PATH3),
]
else:
return coal_paths.split(os.pathsep)


class PathManager(contextlib.AbstractContextManager):
"""Restore PATH state after importing Python module"""

def add_dll_directory(self, dll_dir: str):
os.environ["PATH"] += os.pathsep + dll_dir

def __enter__(self):
self.old_path = os.environ["PATH"]
return self

def __exit__(self, *exc_details):
os.environ["PATH"] = self.old_path


class DllDirectoryManager(contextlib.AbstractContextManager):
"""Restore DllDirectory state after importing Python module"""

def add_dll_directory(self, dll_dir: str):
# add_dll_directory can fail on relative path and non
# existing path.
# Since we don't know all the fail criterion we just ignore
# thrown exception
try:
self.dll_dirs.append(os.add_dll_directory(dll_dir))
except OSError:
pass

def __enter__(self):
self.dll_dirs = []
return self

def __exit__(self, *exc_details):
for d in self.dll_dirs:
d.close()


def build_directory_manager():
if sys.version_info >= (3, 8):
return DllDirectoryManager()
else:
return PathManager()

0 comments on commit 1696fba

Please sign in to comment.