Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

api: Cygwin compatibility #365

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
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
85 changes: 67 additions & 18 deletions wand/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,38 @@
import platform
import sys
import traceback
if platform.system() == "Windows":
try:
import winreg
except ImportError:
import _winreg as winreg

def _is_windows():
"""Python on Windows hatch in different nests. Some are more Unix
than others.

:returns: A pair of ``<Bool, Maybe<str>>`` type. The first element
indicates Windows-ness; the second gives a string for
replacement "lib" prefix when the platform is Unix-y.
:rtype: :class:`tuple`
"""
system = platform.system()
if system == "Windows":
return (True, False)
if system.startswith('CYGWIN_NT-'):
return (True, "cyg")
if system.startswith('MSYS_NT-'):
return (True, "msys-")
else:
return (False, False)

is_windows = _is_windows()

if is_windows[0]:
for winregmod in ['winreg', '_winreg', 'cygwinreg']:
try:
winreg = __import__(winregmod)
except ImportError:
pass
else:
winreg = None
else:
winreg = None

__all__ = ('MagickPixelPacket', 'PointInfo', 'AffineMatrix', 'c_magick_char_p',
'library', 'libc', 'libmagick', 'load_library')
Expand Down Expand Up @@ -60,26 +87,31 @@ def library_paths():
system = platform.system()
magick_home = os.environ.get('MAGICK_HOME')

if system == 'Windows':
if winreg:
# ImageMagick installers normally install coder and filter DLLs in
# subfolders, we need to add those folders to PATH, otherwise loading
# the DLL later will fail.
#
# We prepend those paths to PATH so that ImageMagick will be sure to
# use those DLLs. Since ctype looks in PATH, we can save magick_home
# for the actual environment variable.
try:
with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE,
r"SOFTWARE\ImageMagick\Current") as reg_key:
libPath = winreg.QueryValueEx(reg_key, "LibPath")
coderPath = winreg.QueryValueEx(reg_key, "CoderModulesPath")
filterPath = winreg.QueryValueEx(reg_key, "FilterModulesPath")
magick_home = libPath[0]
os.environ['PATH'] += (';' + libPath[0] + ";" +
coderPath[0] + ";" + filterPath[0])
pathSep = ';' if is_windows[1] == False else ':'
os.environ['PATH'] = (pathSep.join((libPath[0], coderPath[0], filterPath[0])) +
os.environ['PATH'])
except OSError:
# otherwise use MAGICK_HOME, and we assume the coder and
# otherwise do nothing; we assume the coder and
# filter DLLs are in the same directory
pass

def magick_path(path):
return os.path.join(magick_home, *path)

combinations = itertools.product(versions, options)
suffixes = (version + option for version, option in combinations)
if magick_home:
Expand All @@ -92,9 +124,20 @@ def magick_path(path):
libwand = 'CORE_RL_wand_{0}.dll'.format(suffix),
libmagick = 'CORE_RL_magick_{0}.dll'.format(suffix),
yield magick_path(libwand), magick_path(libmagick)
libwand = 'libMagickWand{0}.dll'.format(suffix),
libmagick = 'libMagickCore{0}.dll'.format(suffix),
yield magick_path(libwand), magick_path(libmagick)

# Prioritize the Unix-y instance
if is_windows[1] != False:
prefixes = (is_windows[1], 'lib')
else:
prefixes = ('lib',)

for prefix in prefixes:
libwand = '{1}MagickWand{0}.dll'.format(suffix, prefix),
libmagick = '{1}MagickCore{0}.dll'.format(suffix, prefix),
# "lib" (or other prefixes) are used for MinGW/Cygwin/MSYS
# builds, which may have a "bin" hierarchy over the DLLs. Add twice.
yield magick_path(libwand), magick_path(libmagick)
yield magick_path('bin', libwand), magick_path('bin', libmagick)
elif system == 'Darwin':
libwand = 'lib', 'libMagickWand{0}.dylib'.format(suffix),
yield magick_path(libwand), magick_path(libwand)
Expand All @@ -107,11 +150,14 @@ def magick_path(path):
libmagick = ctypes.util.find_library('CORE_RL_magick_' + suffix)
yield libwand, libmagick
libwand = ctypes.util.find_library('libMagickWand' + suffix)
libmagick = ctypes.util.find_library('libMagickCore' + suffix)
libmagick = ctypes.util.find_library('libMagickCore' + suffix) or libwand
yield libwand, libmagick
# On Cygwin-like systems, find_library function normally with the prefixes.
# But libmagick is split (totally legit), so let's do a "or" fallback instead:
else:
libwand = ctypes.util.find_library('MagickWand' + suffix)
yield libwand, libwand
libmagick = ctypes.util.find_library('MagickCore' + suffix) or libwand
yield libwand, libmagick


def load_library():
Expand Down Expand Up @@ -1422,10 +1468,13 @@ class AffineMatrix(ctypes.Structure):
except OSError:
# In case of El Capitan SIP
libc = ctypes.cdll.LoadLibrary('/usr/lib/libc.dylib')
elif sys.platform.startswith(('dragonfly', 'freebsd')):
libc = ctypes.cdll.LoadLibrary(ctypes.util.find_library('c'))
else:
libc = ctypes.cdll.LoadLibrary('libc.so.6')
try:
# Theoretically correct for all *nix, including Darwin
libc = ctypes.cdll.LoadLibrary(ctypes.util.find_library('c'))
except OSError:
# Hardcode a Linux case
libc = ctypes.cdll.LoadLibrary('libc.so.6')
libc.fdopen.argtypes = [ctypes.c_int, ctypes.c_char_p]
libc.fdopen.restype = ctypes.c_void_p
libc.fflush.argtypes = [ctypes.c_void_p]