-
Notifications
You must be signed in to change notification settings - Fork 213
/
loading.py
142 lines (116 loc) · 3.89 KB
/
loading.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
"""
Utility functions to load libgmt as ctypes.CDLL.
The path to the shared library can be found automatically by ctypes or set
through the GMT_LIBRARY_PATH environment variable.
"""
import os
import sys
import ctypes
from ctypes.util import find_library
from pygmt.exceptions import GMTOSError, GMTCLibError, GMTCLibNotFoundError
def load_libgmt():
"""
Find and load ``libgmt`` as a :py:class:`ctypes.CDLL`.
By default, will look for the shared library in the directory specified by
the environment variable ``GMT_LIBRARY_PATH``. If it's not set, will let
ctypes try to find the library.
Returns
-------
:py:class:`ctypes.CDLL` object
The loaded shared library.
Raises
------
GMTCLibNotFoundError
If there was any problem loading the library (couldn't find it or
couldn't access the functions).
"""
lib_fullnames = clib_full_names()
error = True
for libname in lib_fullnames:
try:
libgmt = ctypes.CDLL(libname)
check_libgmt(libgmt)
error = False
break
except OSError as err:
error = err
if error:
raise GMTCLibNotFoundError(
"Error loading the GMT shared library '{}':".format(
", ".join(lib_fullnames)
)
)
return libgmt
def clib_names(os_name):
"""
Return the name of GMT's shared library for the current OS.
Parameters
----------
os_name : str
The operating system name as given by ``sys.platform``.
Returns
-------
libnames : list of str
List of possible names of GMT's shared library.
"""
if os_name.startswith("linux"):
libnames = ["libgmt.so"]
elif os_name == "darwin": # Darwin is macOS
libnames = ["libgmt.dylib"]
elif os_name == "win32":
libnames = ["gmt.dll", "gmt_w64.dll", "gmt_w32.dll"]
elif os_name.startswith("freebsd"): # FreeBSD
libnames = ["libgmt.so"]
else:
raise GMTOSError(f'Operating system "{sys.platform}" not supported.')
return libnames
def clib_full_names(env=None):
"""
Return the full path of GMT's shared library for the current OS.
Parameters
----------
env : dict or None
A dictionary containing the environment variables. If ``None``, will
default to ``os.environ``.
Returns
-------
lib_fullnames: list of str
List of possible full names of GMT's shared library.
"""
if env is None:
env = os.environ
libnames = clib_names(os_name=sys.platform) # e.g. libgmt.so, libgmt.dylib, gmt.dll
libpath = env.get("GMT_LIBRARY_PATH", "") # e.g. $HOME/miniconda/envs/pygmt/lib
lib_fullnames = [os.path.join(libpath, libname) for libname in libnames]
# Search for DLLs in PATH if GMT_LIBRARY_PATH is not defined [Windows only]
if not libpath and sys.platform == "win32":
for libname in libnames:
libfullpath = find_library(libname)
if libfullpath:
lib_fullnames.append(libfullpath)
return lib_fullnames
def check_libgmt(libgmt):
"""
Make sure that libgmt was loaded correctly.
Checks if it defines some common required functions.
Does nothing if everything is fine. Raises an exception if any of the
functions are missing.
Parameters
----------
libgmt : :py:class:`ctypes.CDLL`
A shared library loaded using ctypes.
Raises
------
GMTCLibError
"""
# Check if a few of the functions we need are in the library
functions = ["Create_Session", "Get_Enum", "Call_Module", "Destroy_Session"]
for func in functions:
if not hasattr(libgmt, "GMT_" + func):
msg = " ".join(
[
"Error loading libgmt.",
"Couldn't access function GMT_{}.".format(func),
]
)
raise GMTCLibError(msg)