Skip to content

Commit ef5d9ef

Browse files
committed
Kill the PkgConfig singleton in setupext.
PkgConfig.setup_extension works just fine as a free-standing function.
1 parent dce1dc3 commit ef5d9ef

File tree

1 file changed

+62
-71
lines changed

1 file changed

+62
-71
lines changed

setupext.py

Lines changed: 62 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@
22
import configparser
33
from distutils import sysconfig, version
44
from distutils.core import Extension
5-
from io import BytesIO
5+
import functools
66
import glob
77
import hashlib
88
import importlib
9+
from io import BytesIO
910
import logging
1011
import os
1112
import pathlib
@@ -214,83 +215,73 @@ def get_buffer_hash(fd):
214215
return hasher.hexdigest()
215216

216217

217-
class PkgConfig(object):
218-
"""This is a class for communicating with pkg-config."""
219-
220-
def __init__(self):
221-
"""Determines whether pkg-config exists on this machine."""
222-
self.pkg_config = None
223-
if sys.platform != 'win32':
224-
pkg_config = os.environ.get('PKG_CONFIG', 'pkg-config')
225-
if shutil.which(pkg_config) is not None:
226-
self.pkg_config = pkg_config
227-
self.set_pkgconfig_path()
228-
else:
229-
print("IMPORTANT WARNING:\n"
230-
" pkg-config is not installed.\n"
231-
" matplotlib may not be able to find some of its dependencies")
232-
233-
def set_pkgconfig_path(self):
234-
pkgconfig_path = sysconfig.get_config_var('LIBDIR')
235-
if pkgconfig_path is None:
236-
return
237-
238-
pkgconfig_path = os.path.join(pkgconfig_path, 'pkgconfig')
239-
if not os.path.isdir(pkgconfig_path):
240-
return
241-
218+
@functools.lru_cache(1) # We only need to compute this once.
219+
def get_pkg_config():
220+
"""
221+
Get path to pkg-config and set up the PKG_CONFIG environment variable.
222+
"""
223+
if sys.platform == 'win32':
224+
return None
225+
pkg_config = os.environ.get('PKG_CONFIG', 'pkg-config')
226+
if shutil.which(pkg_config) is None:
227+
print("IMPORTANT WARNING:\n"
228+
" pkg-config is not installed.\n"
229+
" matplotlib may not be able to find some of its dependencies.")
230+
return None
231+
pkg_config_path = sysconfig.get_config_var('LIBDIR')
232+
if pkg_config_path is not None:
233+
pkg_config_path = os.path.join(pkg_config_path, 'pkgconfig')
242234
try:
243-
os.environ['PKG_CONFIG_PATH'] += ':' + pkgconfig_path
235+
os.environ['PKG_CONFIG_PATH'] += ':' + pkg_config_path
244236
except KeyError:
245-
os.environ['PKG_CONFIG_PATH'] = pkgconfig_path
237+
os.environ['PKG_CONFIG_PATH'] = pkg_config_path
238+
return pkg_config
246239

247-
def setup_extension(
248-
self, ext, package,
249-
atleast_version=None, alt_exec=None, default_libraries=()):
250-
"""Add parameters to the given *ext* for the given *package*."""
251240

252-
# First, try to get the flags from pkg-config.
253-
254-
cmd = ([self.pkg_config, package] if self.pkg_config else alt_exec)
255-
if cmd is not None:
256-
try:
257-
if self.pkg_config and atleast_version:
258-
subprocess.check_call(
259-
[*cmd, f"--atleast-version={atleast_version}"])
260-
# Use sys.getfilesystemencoding() to allow round-tripping
261-
# when passed back to later subprocess calls; do not use
262-
# locale.getpreferredencoding() which universal_newlines=True
263-
# would do.
264-
cflags = shlex.split(
265-
os.fsdecode(subprocess.check_output([*cmd, "--cflags"])))
266-
libs = shlex.split(
267-
os.fsdecode(subprocess.check_output([*cmd, "--libs"])))
268-
except (OSError, subprocess.CalledProcessError):
269-
pass
270-
else:
271-
ext.extra_compile_args.extend(cflags)
272-
ext.extra_link_args.extend(libs)
273-
return
241+
def pkg_config_setup_extension(
242+
ext, package,
243+
atleast_version=None, alt_exec=None, default_libraries=()):
244+
"""Add parameters to the given *ext* for the given *package*."""
274245

275-
# If that fails, fall back on the defaults.
246+
# First, try to get the flags from pkg-config.
276247

277-
# conda Windows header and library paths.
278-
# https://github.com/conda/conda/issues/2312 re: getting the env dir.
279-
if sys.platform == 'win32':
280-
conda_env_path = (os.getenv('CONDA_PREFIX') # conda >= 4.1
281-
or os.getenv('CONDA_DEFAULT_ENV')) # conda < 4.1
282-
if conda_env_path and os.path.isdir(conda_env_path):
283-
ext.include_dirs.append(os.fspath(
284-
pathlib.Path(conda_env_path, "Library/include")))
285-
ext.library_dirs.append(os.fspath(
286-
pathlib.Path(conda_env_path, "Library/lib")))
248+
pkg_config = get_pkg_config()
249+
cmd = [pkg_config, package] if pkg_config else alt_exec
250+
if cmd is not None:
251+
try:
252+
if pkg_config and atleast_version:
253+
subprocess.check_call(
254+
[*cmd, f"--atleast-version={atleast_version}"])
255+
# Use sys.getfilesystemencoding() to allow round-tripping
256+
# when passed back to later subprocess calls; do not use
257+
# locale.getpreferredencoding() which universal_newlines=True
258+
# would do.
259+
cflags = shlex.split(
260+
os.fsdecode(subprocess.check_output([*cmd, "--cflags"])))
261+
libs = shlex.split(
262+
os.fsdecode(subprocess.check_output([*cmd, "--libs"])))
263+
except (OSError, subprocess.CalledProcessError):
264+
pass
265+
else:
266+
ext.extra_compile_args.extend(cflags)
267+
ext.extra_link_args.extend(libs)
268+
return
287269

288-
# Default linked libs.
289-
ext.libraries.extend(default_libraries)
270+
# If that fails, fall back on the defaults.
290271

272+
# conda Windows header and library paths.
273+
# https://github.com/conda/conda/issues/2312 re: getting the env dir.
274+
if sys.platform == 'win32':
275+
conda_env_path = (os.getenv('CONDA_PREFIX') # conda >= 4.1
276+
or os.getenv('CONDA_DEFAULT_ENV')) # conda < 4.1
277+
if conda_env_path and os.path.isdir(conda_env_path):
278+
ext.include_dirs.append(os.fspath(
279+
pathlib.Path(conda_env_path, "Library/include")))
280+
ext.library_dirs.append(os.fspath(
281+
pathlib.Path(conda_env_path, "Library/lib")))
291282

292-
# The PkgConfig class should be used through this singleton
293-
pkg_config = PkgConfig()
283+
# Default linked libs.
284+
ext.libraries.extend(default_libraries)
294285

295286

296287
class CheckFailed(Exception):
@@ -679,7 +670,7 @@ def add_flags(self, ext):
679670
0, os.path.join(src_path, 'objs', '.libs', libfreetype))
680671
ext.define_macros.append(('FREETYPE_BUILD_TYPE', 'local'))
681672
else:
682-
pkg_config.setup_extension(
673+
pkg_config_setup_extension(
683674
# FreeType 2.3 has libtool version 9.11.3 as can be checked
684675
# from the tarball. For FreeType>=2.4, there is a conversion
685676
# table in docs/VERSIONS.txt in the FreeType source tree.
@@ -826,7 +817,7 @@ def get_extension(self):
826817
'src/mplutils.cpp',
827818
]
828819
ext = Extension('matplotlib._png', sources)
829-
pkg_config.setup_extension(
820+
pkg_config_setup_extension(
830821
ext, 'libpng',
831822
atleast_version='1.2',
832823
alt_exec=['libpng-config', '--ldflags'],

0 commit comments

Comments
 (0)