-
Notifications
You must be signed in to change notification settings - Fork 234
Improve how PyGMT finds the GMT library #440
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
Changes from all commits
8f51190
628b061
9273528
c783bff
1fe4305
1d121f7
9251d7c
4bc0bd7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,24 +7,19 @@ | |
| import os | ||
| import sys | ||
| import ctypes | ||
| from ctypes.util import find_library | ||
|
|
||
| from ..exceptions import GMTOSError, GMTCLibError, GMTCLibNotFoundError | ||
|
|
||
|
|
||
| def load_libgmt(env=None): | ||
| 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. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| env : dict or None | ||
| A dictionary containing the environment variables. If ``None``, will | ||
| default to ``os.environ``. | ||
|
|
||
| Returns | ||
| ------- | ||
| :py:class:`ctypes.CDLL` object | ||
|
|
@@ -37,27 +32,26 @@ def load_libgmt(env=None): | |
| couldn't access the functions). | ||
|
|
||
| """ | ||
| if env is None: | ||
| env = os.environ | ||
| libnames = clib_name(os_name=sys.platform) | ||
| libpath = env.get("GMT_LIBRARY_PATH", "") | ||
| lib_fullnames = clib_full_names() | ||
| error = True | ||
| for libname in libnames: | ||
| for libname in lib_fullnames: | ||
| try: | ||
| libgmt = ctypes.CDLL(os.path.join(libpath, libname)) | ||
| 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(libnames)) | ||
| "Error loading the GMT shared library '{}':".format( | ||
| ", ".join(lib_fullnames) | ||
| ) | ||
| ) | ||
| return libgmt | ||
|
|
||
|
|
||
| def clib_name(os_name): | ||
| def clib_names(os_name): | ||
| """ | ||
| Return the name of GMT's shared library for the current OS. | ||
|
|
||
|
|
@@ -68,20 +62,51 @@ def clib_name(os_name): | |
|
|
||
| Returns | ||
| ------- | ||
| libname : list of str | ||
| libnames : list of str | ||
| List of possible names of GMT's shared library. | ||
|
|
||
| """ | ||
| if os_name.startswith("linux"): | ||
| libname = ["libgmt.so"] | ||
| libnames = ["libgmt.so"] | ||
| elif os_name == "darwin": | ||
| # Darwin is macOS | ||
| libname = ["libgmt.dylib"] | ||
| libnames = ["libgmt.dylib"] | ||
| elif os_name == "win32": | ||
| libname = ["gmt.dll", "gmt_w64.dll", "gmt_w32.dll"] | ||
| libnames = ["gmt.dll", "gmt_w64.dll", "gmt_w32.dll"] | ||
| else: | ||
| raise GMTOSError('Operating system "{}" not supported.'.format(sys.platform)) | ||
| return libname | ||
| 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) | ||
|
Comment on lines
+105
to
+108
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These lines were missing on my test coverage (since I'm on Linux) so I can't check this properly. But looking at the Azure Pipelines test on Windows, it seems okay.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it OK to add a Windows-only test?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure if In [1]: import pygmt
In [2]: from ctypes.util import find_library
In [3]: find_library("gmt")
In [4]: find_library("libgmt")
In [5]: find_library("libgmt.dylib")
In [6]: find_library("m")
Out[6]: '/usr/lib/libm.dylib'
In [7]: find_library("libm")
Out[7]: '/usr/lib/libm.dylib'
In [8]: find_library("libm.dylib")
Out[8]: '/usr/lib/libm.dylib'
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could have sworn someone mentioned this before, but a quick scan through the old issues turn up nothing. Should be good to go then, but will keep it in the back of my mind 😄 |
||
| return lib_fullnames | ||
|
|
||
|
|
||
| def check_libgmt(libgmt): | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.