diff options
author | Tomasz Miąsko <tomasz.miasko@gmail.com> | 2018-02-15 00:00:00 +0000 |
---|---|---|
committer | Christoph Reiter <reiter.christoph@gmail.com> | 2018-07-28 19:00:55 +0200 |
commit | b80fff2e5a8f327c3128378c12c290dd8e4f7c01 (patch) | |
tree | bdf8e8dd62436a99513e35645245e4641a93245f /giscanner | |
parent | 8bf05589bba98a13dacce1312075af9f04145b82 (diff) | |
download | gobject-introspection-b80fff2e5a8f327c3128378c12c290dd8e4f7c01.tar.gz |
Factor out pkg-config functionality to a separate module.
Functional changes:
* Consistently check that return code from pkg-config is zero.
* Use shell word splitting rules to process pkg-config output to match
behaviour obtained by running `cc program.cc $(pkg-config --cflags ...)`.
Fixes issue #171 .
* Use user preferred encoding to process output from pkg-config on
Python 3. Python 2 behaviour defaults to using ascii encoding as before.
edit creiter: still ignore pkg-config errors by default for now as we
depend on it when glib is a subproject.
Diffstat (limited to 'giscanner')
-rw-r--r-- | giscanner/dumper.py | 24 | ||||
-rw-r--r-- | giscanner/meson.build | 1 | ||||
-rw-r--r-- | giscanner/pkgconfig.py | 58 | ||||
-rw-r--r--[-rwxr-xr-x] | giscanner/scannermain.py | 23 |
4 files changed, 73 insertions, 33 deletions
diff --git a/giscanner/dumper.py b/giscanner/dumper.py index bb97bc81..494c7ff7 100644 --- a/giscanner/dumper.py +++ b/giscanner/dumper.py @@ -32,7 +32,7 @@ import tempfile from distutils.errors import LinkError from .gdumpparser import IntrospectionBinary -from . import utils +from . import pkgconfig, utils from .ccompiler import CCompiler # bugzilla.gnome.org/558436 @@ -94,9 +94,8 @@ class DumpCompiler(object): # Acquire the compiler (and linker) commands via the CCompiler class in ccompiler.py self._compiler = CCompiler() - self._pkgconfig_cmd = os.environ.get('PKG_CONFIG', 'pkg-config') self._uninst_srcdir = os.environ.get('UNINSTALLED_INTROSPECTION_SRCDIR') - self._packages = ['gio-2.0 gmodule-2.0'] + self._packages = ['gio-2.0', 'gmodule-2.0'] self._packages.extend(options.packages) if self._compiler.check_is_msvc(): self._linker_cmd = ['link.exe'] @@ -189,21 +188,9 @@ class DumpCompiler(object): self._options.namespace_version, suffix) return os.path.join(tmpdir, tmpl) - def _run_pkgconfig(self, flag): - # Enable the --msvc-syntax pkg-config flag when - # the Microsoft compiler is used - if self._compiler.check_is_msvc(): - cmd = [self._pkgconfig_cmd, '--msvc-syntax', flag] - else: - cmd = [self._pkgconfig_cmd, flag] - proc = subprocess.Popen( - cmd + self._packages, - stdout=subprocess.PIPE) - out, err = proc.communicate() - return out.decode('ascii').split() - def _compile(self, *sources): - cflags = self._run_pkgconfig('--cflags') + cflags = pkgconfig.cflags(self._packages, + msvc_syntax=self._compiler.check_is_msvc()) cflags.extend(self._options.cflags) return self._compiler.compile(cflags, self._options.cpp_includes, @@ -255,7 +242,8 @@ class DumpCompiler(object): args.extend(sources) - pkg_config_libs = self._run_pkgconfig('--libs') + pkg_config_libs = pkgconfig.libs(self._packages, + msvc_syntax=self._compiler.check_is_msvc()) if not self._options.external_library: self._compiler.get_internal_link_flags(args, diff --git a/giscanner/meson.build b/giscanner/meson.build index b4ec3796..7b4b0d9d 100644 --- a/giscanner/meson.build +++ b/giscanner/meson.build @@ -17,6 +17,7 @@ giscanner_files = [ 'maintransformer.py', 'message.py', 'msvccompiler.py', + 'pkgconfig.py', 'shlibs.py', 'scannermain.py', 'sectionparser.py', diff --git a/giscanner/pkgconfig.py b/giscanner/pkgconfig.py new file mode 100644 index 00000000..6f0b2d57 --- /dev/null +++ b/giscanner/pkgconfig.py @@ -0,0 +1,58 @@ +# GObject-Introspection - a framework for introspecting GObject libraries +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. +# + +import os +import shlex +import subprocess + + +class PkgConfigError(Exception): + pass + + +def check_output(flags, ignore_errors, command=None): + if command is None: + command = [os.environ.get('PKG_CONFIG', 'pkg-config')] + argv = command[:] + argv.extend(flags) + try: + return subprocess.check_output(argv, universal_newlines=True, stderr=subprocess.STDOUT) + except subprocess.CalledProcessError as e: + output = e.output or '' + if ignore_errors: + print(output) + return '' + raise PkgConfigError('pkg-config: %s\n%s' % (e, output)) + except OSError as e: + raise PkgConfigError('pkg-config: error executing command %s: %s' % (argv, e)) + + +def cflags(packages, msvc_syntax=False, ignore_errors=True, command=None): + flags = ['--msvc-syntax'] if msvc_syntax else [] + flags.append('--cflags') + flags.extend(packages) + out = check_output(flags, ignore_errors, command) + return shlex.split(out) + + +def libs(packages, msvc_syntax=False, ignore_errors=True, command=None): + flags = ['--msvc-syntax'] if msvc_syntax else [] + flags.append('--libs') + flags.extend(packages) + out = check_output(flags, ignore_errors, command) + return shlex.split(out) diff --git a/giscanner/scannermain.py b/giscanner/scannermain.py index 2f1d9095..e0af993a 100755..100644 --- a/giscanner/scannermain.py +++ b/giscanner/scannermain.py @@ -37,7 +37,7 @@ import platform import shlex import giscanner -from giscanner import message +from giscanner import message, pkgconfig from giscanner.annotationparser import GtkDocCommentBlockParser from giscanner.ast import Include, Namespace from giscanner.dumper import compile_introspection_binary @@ -288,7 +288,7 @@ def test_codegen(optstring, def process_options(output, allowed_flags): - for option in output.split(): + for option in output: for flag in allowed_flags: if not option.startswith(flag): continue @@ -297,19 +297,11 @@ def process_options(output, allowed_flags): def process_packages(options, packages): - args = [os.environ.get('PKG_CONFIG', 'pkg-config'), '--cflags'] - args.extend(packages) - output = subprocess.Popen(args, - stdout=subprocess.PIPE).communicate()[0] - if output is None: - # the error output should have already appeared on our stderr, - # so we just exit - return 1 - output = output.decode('ascii') + flags = pkgconfig.cflags(packages) # Some pkg-config files on Windows have options we don't understand, # so we explicitly filter to only the ones we need. options_whitelist = ['-I', '-D', '-U', '-l', '-L'] - filtered_output = list(process_options(output, options_whitelist)) + filtered_output = list(process_options(flags, options_whitelist)) parser = _get_option_parser() pkg_options, unused = parser.parse_args(filtered_output) options.cpp_includes.extend([os.path.realpath(f) for f in pkg_options.cpp_includes]) @@ -539,9 +531,10 @@ def scanner_main(args): packages = set(options.packages) packages.update(transformer.get_pkgconfig_packages()) if packages: - exit_code = process_packages(options, packages) - if exit_code: - return exit_code + try: + process_packages(options, packages) + except pkgconfig.PkgConfigError as e: + _error(str(e)) ss = create_source_scanner(options, args) |