summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristoph Reiter <reiter.christoph@gmail.com>2022-04-09 11:46:58 +0200
committerChristoph Reiter <reiter.christoph@gmail.com>2022-04-13 21:59:09 +0000
commit5f614b36b8f61caab581a56ccf320fee3177051b (patch)
treebee89a994fa2243f603814cbbc27352cfb25ab51
parent0f3ba012512acfd74e5942ff6858c22611c4a79a (diff)
downloadpygobject-5f614b36b8f61caab581a56ccf320fee3177051b.tar.gz
setup.py: look up pycairo headers without importing the module
Up until now pycairo provided a cairo.get_include() helper which could be used to find the required include directory matching the module, considering various scenarios. Starting with 3.8 this leads to problems on Windows since CPython on Windows will no longer use PATH for the DLL lookup and expects the library user to explicitely pass the directory where the cairo DLL can be found. In a build environment the user has no control over this though, so we have to find the include directory without loading/importing pycairo again. This now uses a combination of importlib.util.find_spec() for finding the module and importlib.metadata.distribution() for finding the package version. Hopefully this covers all cases.
-rwxr-xr-xsetup.py78
1 files changed, 31 insertions, 47 deletions
diff --git a/setup.py b/setup.py
index 5f801607..f50c3052 100755
--- a/setup.py
+++ b/setup.py
@@ -22,7 +22,6 @@ import sys
import errno
import subprocess
import tarfile
-import sysconfig
import tempfile
import posixpath
@@ -827,7 +826,9 @@ def get_pycairo_include_dir():
pkg_config_name = "py3cairo"
min_version = get_version_requirement(pkg_config_name)
- min_version_info = tuple(int(p) for p in min_version.split("."))
+
+ def parse_version(string):
+ return tuple(int(p) for p in string.split("."))
def check_path(include_dir):
log.info("pycairo: trying include directory: %r" % include_dir)
@@ -843,61 +844,44 @@ def get_pycairo_include_dir():
if check_path(p):
return p
- def find_new_api():
- log.info("pycairo: new API")
- import cairo
-
- if cairo.version_info < min_version_info:
- raise DistutilsSetupError(
- "pycairo >= %s required, %s found." % (
- min_version, ".".join(map(str, cairo.version_info))))
-
- if hasattr(cairo, "get_include"):
- return [cairo.get_include()]
- log.info("pycairo: no get_include()")
- return []
+ def find_python():
+ """This tries to find the pycairo module without importing it"""
- def find_old_api():
- log.info("pycairo: old API")
+ from importlib.util import find_spec
- import cairo
+ # Find the module path
+ spec = find_spec("cairo")
+ if spec is None:
+ log.info("pycairo: cairo module not found via importlib")
+ return []
+ package_path = os.path.dirname(spec.origin)
- if cairo.version_info < min_version_info:
- raise DistutilsSetupError(
- "pycairo >= %s required, %s found." % (
- min_version, ".".join(map(str, cairo.version_info))))
-
- location = os.path.dirname(os.path.abspath(cairo.__path__[0]))
- log.info("pycairo: found %r" % location)
-
- def get_sys_path(location, name):
- # Returns the sysconfig path for a distribution, or None
- for scheme in sysconfig.get_scheme_names():
- for path_type in ["platlib", "purelib"]:
- path = sysconfig.get_path(path_type, scheme)
- try:
- if os.path.samefile(path, location):
- return sysconfig.get_path(name, scheme)
- except EnvironmentError:
- pass
+ # With Python 3.8 we can also check the package version
+ try:
+ from importlib.metadata import distribution, PackageNotFoundError
+ except ImportError:
+ # Python <3.8
+ pass
+ else:
+ try:
+ d = distribution("pycairo")
+ except PackageNotFoundError:
+ log.info("pycairo: pycairo distribution not found via importlib")
+ else:
+ if parse_version(d.version) < parse_version(min_version):
+ raise DistutilsSetupError(
+ "pycairo >= %s required, %s found (%s)." % (
+ min_version, d.version, package_path))
- data_path = get_sys_path(location, "data") or sys.prefix
- return [os.path.join(data_path, "include", "pycairo")]
+ return [os.path.join(package_path, 'include')]
def find_pkg_config():
log.info("pycairo: pkg-config")
pkg_config_version_check(pkg_config_name, min_version)
return pkg_config_parse("--cflags-only-I", pkg_config_name)
- # First the new get_include() API added in >1.15.6
- include_dir = find_path(find_new_api())
- if include_dir is not None:
- return include_dir
-
- # Then try to find it in the data prefix based on the module path.
- # This works with many virtualenv/userdir setups, but not all apparently,
- # see https://gitlab.gnome.org/GNOME/pygobject/issues/150
- include_dir = find_path(find_old_api())
+ # First look in the current Python installation/venv
+ include_dir = find_path(find_python())
if include_dir is not None:
return include_dir