aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/markdown/Dependencies.md28
-rw-r--r--docs/markdown/Reference-manual.md4
-rw-r--r--docs/markdown/snippets/config-tool-variable-method.md11
-rw-r--r--mesonbuild/dependencies/base.py156
-rw-r--r--mesonbuild/dependencies/dev.py105
-rw-r--r--mesonbuild/dependencies/misc.py109
-rw-r--r--mesonbuild/dependencies/ui.py182
-rw-r--r--mesonbuild/interpreter.py10
-rwxr-xr-xrun_unittests.py2
-rw-r--r--test cases/common/165 config tool variable/meson.build31
-rw-r--r--test cases/frameworks/16 sdl2/meson.build5
-rw-r--r--test cases/frameworks/19 pcap/meson.build4
-rw-r--r--test cases/frameworks/20 cups/meson.build5
-rw-r--r--test cases/frameworks/21 libwmf/meson.build7
14 files changed, 376 insertions, 283 deletions
diff --git a/docs/markdown/Dependencies.md b/docs/markdown/Dependencies.md
index 8e780d6..dbd21aa 100644
--- a/docs/markdown/Dependencies.md
+++ b/docs/markdown/Dependencies.md
@@ -178,32 +178,22 @@ the list of sources for the target. The `modules` keyword of
`dependency` works just like it does with Boost. It tells which
subparts of Qt the program uses.
-## Pcap
+## Dependencies using config tools
-The pcap library does not ship with pkg-config at the time or writing
-but instead it has its own `pcap-config` util. Meson will use it
-automatically:
+CUPS, LLVM, PCAP, WxWidgets, libwmf, and GnuStep either do not provide
+pkg-config modules or additionally can be detected via a config tool
+(cups-config, llvm-config, etc). Meson has native support for these tools, and
+then can be found like other dependencies:
```meson
pcap_dep = dependency('pcap', version : '>=1.0')
-```
-
-## CUPS
-
-The cups library does not ship with pkg-config at the time or writing
-but instead it has its own `cups-config` util. Meson will use it
-automatically:
-
-```meson
cups_dep = dependency('cups', version : '>=1.4')
+llvm_dep = dependency('llvm', version : '>=4.0')
```
-## LibWMF
-
-The libwmf library does not ship with pkg-config at the time or writing
-but instead it has its own `libwmf-config` util. Meson will use it
-automatically:
+Some of these tools (like wmf and cups) provide both pkg-config and config
+tools support. You can force one or another via the method keyword:
```meson
-libwmf_dep = dependency('libwmf', version : '>=0.2.8')
+wmf_dep = dependency('wmf', method : 'config-tool')
```
diff --git a/docs/markdown/Reference-manual.md b/docs/markdown/Reference-manual.md
index 0f00203..424ab58 100644
--- a/docs/markdown/Reference-manual.md
+++ b/docs/markdown/Reference-manual.md
@@ -1614,6 +1614,10 @@ an external dependency with the following methods:
pkg-config variable specified, or, if invoked on a non pkg-config
dependency, error out
+ - `get_configtool_variable(varname)` (*Added 0.44.0*) will get the
+ command line argument from the config tool (with `--` prepended), or,
+ if invoked on a non config-tool dependency, error out.
+
- `type_name()` which returns a string describing the type of the
dependency, the most common values are `internal` for deps created
with `declare_dependencies` and `pkgconfig` for system dependencies
diff --git a/docs/markdown/snippets/config-tool-variable-method.md b/docs/markdown/snippets/config-tool-variable-method.md
new file mode 100644
index 0000000..7725982
--- /dev/null
+++ b/docs/markdown/snippets/config-tool-variable-method.md
@@ -0,0 +1,11 @@
+# Config-Tool based dependencies gained a method to get arbitrary options
+
+A number of dependencies (CUPS, LLVM, pcap, WxWidgets, GnuStep) use a config
+tool instead of pkg-config. As of this version they now have a
+`get_configtool_variable` method, which is analogous to the
+`get_pkgconfig_variable` for pkg config.
+
+```meson
+dep_llvm = dependency('LLVM')
+llvm_inc_dir = dep_llvm.get_configtool_variable('includedir')
+```
diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py
index 15b47bc..682182c 100644
--- a/mesonbuild/dependencies/base.py
+++ b/mesonbuild/dependencies/base.py
@@ -20,11 +20,14 @@ import sys
import stat
import shlex
import shutil
+import textwrap
from enum import Enum
from .. import mlog
from .. import mesonlib
-from ..mesonlib import MesonException, Popen_safe, version_compare_many, listify
+from ..mesonlib import (
+ MesonException, Popen_safe, version_compare_many, version_compare, listify
+)
# These must be defined in this file to avoid cyclical references.
@@ -43,18 +46,17 @@ class DependencyMethods(Enum):
QMAKE = 'qmake'
# Just specify the standard link arguments, assuming the operating system provides the library.
SYSTEM = 'system'
- # Detect using sdl2-config
- SDLCONFIG = 'sdlconfig'
- # Detect using pcap-config
- PCAPCONFIG = 'pcap-config'
- # Detect using cups-config
- CUPSCONFIG = 'cups-config'
- # Detect using libwmf-config
- LIBWMFCONFIG = 'libwmf-config'
# This is only supported on OSX - search the frameworks directory by name.
EXTRAFRAMEWORK = 'extraframework'
# Detect using the sysconfig module.
SYSCONFIG = 'sysconfig'
+ # Specify using a "program"-config style tool
+ CONFIG_TOOL = 'config-tool'
+ # For backewards compatibility
+ SDLCONFIG = 'sdlconfig'
+ CUPSCONFIG = 'cups-config'
+ PCAPCONFIG = 'pcap-config'
+ LIBWMFCONFIG = 'libwmf-config'
class Dependency:
@@ -72,6 +74,16 @@ class Dependency:
raise DependencyException('method {!r} is invalid'.format(method))
method = DependencyMethods(method)
+ # This sets per-too config methods which are deprecated to to the new
+ # generic CONFIG_TOOL value.
+ if method in [DependencyMethods.SDLCONFIG, DependencyMethods.CUPSCONFIG,
+ DependencyMethods.PCAPCONFIG, DependencyMethods.LIBWMFCONFIG]:
+ mlog.warning(textwrap.dedent("""\
+ Configuration method {} has been deprecated in favor of
+ 'config-tool'. This will be removed in a future version of
+ meson.""".format(method)))
+ method = DependencyMethods.CONFIG_TOOL
+
# Set the detection method. If the method is set to auto, use any available method.
# If method is set to a specific string, allow only that detection method.
if method == DependencyMethods.AUTO:
@@ -82,7 +94,7 @@ class Dependency:
raise DependencyException(
'Unsupported detection method: {}, allowed methods are {}'.format(
method.value,
- mlog.format_list(map(lambda x: x.value, [DependencyMethods.AUTO] + self.get_methods()))))
+ mlog.format_list([x.value for x in [DependencyMethods.AUTO] + self.get_methods()])))
def __repr__(self):
s = '<{0} {1}: {2}>'
@@ -120,6 +132,9 @@ class Dependency:
def get_pkgconfig_variable(self, variable_name):
raise NotImplementedError('{!r} is not a pkgconfig dependency'.format(self.name))
+ def get_configtool_variable(self, variable_name):
+ raise NotImplementedError('{!r} is not a config-tool dependency'.format(self.name))
+
class InternalDependency(Dependency):
def __init__(self, version, incdirs, compile_args, link_args, libraries, sources, ext_deps):
@@ -167,6 +182,127 @@ class ExternalDependency(Dependency):
return self.compiler
+class ConfigToolDependency(ExternalDependency):
+
+ """Class representing dependencies found using a config tool."""
+
+ tools = None
+ tool_name = None
+
+ def __init__(self, name, environment, language, kwargs):
+ super().__init__('config-tool', environment, language, kwargs)
+ self.name = name
+ self.tools = listify(kwargs.get('tools', self.tools))
+
+ req_version = kwargs.get('version', None)
+ tool, version = self.find_config(req_version)
+ self.config = tool
+ self.is_found = self.report_config(version, req_version)
+ if not self.is_found:
+ self.config = None
+ return
+ self.version = version
+
+ @classmethod
+ def factory(cls, name, environment, language, kwargs, tools, tool_name):
+ """Constructor for use in dependencies that can be found multiple ways.
+
+ In addition to the standard constructor values, this constructor sets
+ the tool_name and tools values of the instance.
+ """
+ # This deserves some explanation, because metaprogramming is hard.
+ # This uses type() to create a dynamic subclass of ConfigToolDependency
+ # with the tools and tool_name class attributes set, this class is then
+ # instantiated and returned. The reduce function (method) is also
+ # attached, since python's pickle module won't be able to do anything
+ # with this dynamically generated class otherwise.
+ def reduce(_):
+ return (cls.factory,
+ (name, environment, language, kwargs, tools, tool_name))
+ sub = type('{}Dependency'.format(name.capitalize()), (cls, ),
+ {'tools': tools, 'tool_name': tool_name, '__reduce__': reduce})
+
+ return sub(name, environment, language, kwargs)
+
+ def find_config(self, versions=None):
+ """Helper method that searchs for config tool binaries in PATH and
+ returns the one that best matches the given version requirements.
+ """
+ if not isinstance(versions, list) and versions is not None:
+ versions = listify(versions)
+
+ best_match = (None, None)
+ for tool in self.tools:
+ try:
+ p, out = Popen_safe([tool, '--version'])[:2]
+ except (FileNotFoundError, PermissionError):
+ continue
+ if p.returncode != 0:
+ continue
+
+ out = out.strip()
+ # Some tools, like pcap-config don't supply a version, but also
+ # dont fail with --version, in that case just assume that there is
+ # only one verison and return it.
+ if not out:
+ return (tool, 'none')
+ if versions:
+ is_found = version_compare_many(out, versions)[0]
+ # This allows returning a found version without a config tool,
+ # which is useful to inform the user that you found version x,
+ # but y was required.
+ if not is_found:
+ tool = None
+ if best_match[1]:
+ if version_compare(out, '> {}'.format(best_match[1])):
+ best_match = (tool, out)
+ else:
+ best_match = (tool, out)
+
+ return best_match
+
+ def report_config(self, version, req_version):
+ """Helper method to print messages about the tool."""
+ if self.config is None:
+ if version is not None:
+ mlog.log('found {} {!r} but need:'.format(self.tool_name, version),
+ req_version)
+ else:
+ mlog.log("No {} found; can't detect dependency".format(self.tool_name))
+ mlog.log('Dependency {} found:'.format(self.name), mlog.red('NO'))
+ if self.required:
+ raise DependencyException('Dependency {} not found'.format(self.name))
+ return False
+ mlog.log('Found {}:'.format(self.tool_name), mlog.bold(shutil.which(self.config)),
+ '({})'.format(version))
+ mlog.log('Dependency {} found:'.format(self.name), mlog.green('YES'))
+ return True
+
+ def get_config_value(self, args, stage):
+ p, out, err = Popen_safe([self.config] + args)
+ if p.returncode != 0:
+ if self.required:
+ raise DependencyException(
+ 'Could not generate {} for {}.\n{}'.format(
+ stage, self.name, err))
+ return []
+ return shlex.split(out)
+
+ def get_methods(self):
+ return [DependencyMethods.AUTO, DependencyMethods.CONFIG_TOOL]
+
+ def get_configtool_variable(self, variable_name):
+ p, out, _ = Popen_safe([self.config, '--{}'.format(variable_name)])
+ if p.returncode != 0:
+ if self.required:
+ raise DependencyException(
+ 'Could not get variable "{}" for dependency {}'.format(
+ variable_name, self.name))
+ variable = out.strip()
+ mlog.debug('Got config-tool variable {} : {}'.format(variable_name, variable))
+ return variable
+
+
class PkgConfigDependency(ExternalDependency):
# The class's copy of the pkg-config path. Avoids having to search for it
# multiple times in the same Meson invocation.
diff --git a/mesonbuild/dependencies/dev.py b/mesonbuild/dependencies/dev.py
index a161495..d15d5da 100644
--- a/mesonbuild/dependencies/dev.py
+++ b/mesonbuild/dependencies/dev.py
@@ -17,14 +17,16 @@
import os
import re
-import shlex
import shutil
from .. import mlog
from .. import mesonlib
from ..mesonlib import version_compare, Popen_safe, stringlistify, extract_as_list
-from .base import DependencyException, ExternalDependency, PkgConfigDependency
-from .base import strip_system_libdirs
+from .base import (
+ DependencyException, ExternalDependency, PkgConfigDependency,
+ strip_system_libdirs, ConfigToolDependency,
+)
+
class GTestDependency(ExternalDependency):
def __init__(self, environment, kwargs):
@@ -109,7 +111,7 @@ class GMockDependency(ExternalDependency):
self.is_found = False
-class LLVMDependency(ExternalDependency):
+class LLVMDependency(ConfigToolDependency):
"""
LLVM uses a special tool, llvm-config, which has arguments for getting
c args, cxx args, and ldargs as well as version.
@@ -121,7 +123,7 @@ class LLVMDependency(ExternalDependency):
# not be moved to the beginning of the list. The only difference between
# llvm-config-6.0 and llvm-config-devel is that the former is used by
# Debian and the latter is used by FreeBSD.
- llvm_config_bins = [
+ tools = [
'llvm-config', # base
'llvm-config-5.0', 'llvm-config50', # latest stable release
'llvm-config-4.0', 'llvm-config40', # old stable releases
@@ -132,61 +134,31 @@ class LLVMDependency(ExternalDependency):
'llvm-config-3.5', 'llvm-config35',
'llvm-config-6.0', 'llvm-config-devel', # development snapshot
]
+ tool_name = 'llvm-config'
__cpp_blacklist = {'-DNDEBUG'}
def __init__(self, environment, kwargs):
# It's necessary for LLVM <= 3.8 to use the C++ linker. For 3.9 and 4.0
# the C linker works fine if only using the C API.
- super().__init__('llvm-config', environment, 'cpp', kwargs)
+ super().__init__('config-tool', environment, 'cpp', kwargs)
self.provided_modules = []
self.required_modules = set()
- self.llvmconfig = None
- self.static = kwargs.get('static', False)
- self.__best_found = None
- # FIXME: Support multiple version requirements ala PkgConfigDependency
- req_version = kwargs.get('version', None)
- self.check_llvmconfig(req_version)
- if self.llvmconfig is None:
- if self.__best_found is not None:
- mlog.log('found {!r} but need:'.format(self.__best_found),
- req_version)
- else:
- mlog.log("No llvm-config found; can't detect dependency")
- mlog.log('Dependency LLVM found:', mlog.red('NO'))
- if self.required:
- raise DependencyException('Dependency LLVM not found')
+ if not self.is_found:
return
-
- p, out, err = Popen_safe([self.llvmconfig, '--version'])
- if p.returncode != 0:
- mlog.debug('stdout: {}\nstderr: {}'.format(out, err))
- if self.required:
- raise DependencyException('Dependency LLVM not found')
- mlog.log('Dependency LLVM found:', mlog.red('NO'))
- return
-
- mlog.log('Dependency LLVM found:', mlog.green('YES'))
- self.is_found = True
+ self.static = kwargs.get('static', False)
# Currently meson doesn't really attempt to handle pre-release versions,
# so strip the 'svn' off the end, since it will probably cuase problems
# for users who want the patch version.
- self.version = out.strip().rstrip('svn')
-
- p, out, err = Popen_safe([self.llvmconfig, '--components'])
- if p.returncode != 0:
- raise DependencyException('Could not generate modules for LLVM:\n' + err)
- self.provided_modules = shlex.split(out)
+ self.version = self.version.rstrip('svn')
+ self.provided_modules = self.get_config_value(['--components'], 'modules')
modules = stringlistify(extract_as_list(kwargs, 'modules'))
self.check_components(modules)
opt_modules = stringlistify(extract_as_list(kwargs, 'optional_modules'))
self.check_components(opt_modules, required=False)
- p, out, err = Popen_safe([self.llvmconfig, '--cppflags'])
- if p.returncode != 0:
- raise DependencyException('Could not generate includedir for LLVM:\n' + err)
- cargs = mesonlib.OrderedSet(shlex.split(out))
+ cargs = set(self.get_config_value(['--cppflags'], 'compile_args'))
self.compile_args = list(cargs.difference(self.__cpp_blacklist))
if version_compare(self.version, '>= 3.9'):
@@ -198,11 +170,9 @@ class LLVMDependency(ExternalDependency):
def _set_new_link_args(self):
"""How to set linker args for LLVM versions >= 3.9"""
link_args = ['--link-static', '--system-libs'] if self.static else ['--link-shared']
- p, out, err = Popen_safe(
- [self.llvmconfig, '--libs', '--ldflags'] + link_args + list(self.required_modules))
- if p.returncode != 0:
- raise DependencyException('Could not generate libs for LLVM:\n' + err)
- self.link_args = shlex.split(out)
+ self.link_args = self.get_config_value(
+ ['--libs', '--ldflags'] + link_args + list(self.required_modules),
+ 'link_args')
def _set_old_link_args(self):
"""Setting linker args for older versions of llvm.
@@ -213,20 +183,15 @@ class LLVMDependency(ExternalDependency):
of course we do.
"""
if self.static:
- p, out, err = Popen_safe(
- [self.llvmconfig, '--libs', '--ldflags', '--system-libs'] + list(self.required_modules))
- if p.returncode != 0:
- raise DependencyException('Could not generate libs for LLVM:\n' + err)
- self.link_args = shlex.split(out)
+ self.link_args = self.get_config_value(
+ ['--libs', '--ldflags', '--system-libs'] + list(self.required_modules),
+ 'link_args')
else:
# llvm-config will provide arguments for static linking, so we get
# to figure out for ourselves what to link with. We'll do that by
# checking in the directory provided by --libdir for a library
# called libLLVM-<ver>.(so|dylib|dll)
- p, out, err = Popen_safe([self.llvmconfig, '--libdir'])
- if p.returncode != 0:
- raise DependencyException('Could not generate libs for LLVM:\n' + err)
- libdir = out.strip()
+ libdir = self.get_config_value(['--libdir'], 'link_args')[0]
expected_name = 'libLLVM-{}'.format(self.version)
re_name = re.compile(r'{}.(so|dll|dylib)'.format(expected_name))
@@ -259,34 +224,6 @@ class LLVMDependency(ExternalDependency):
self.required_modules.add(mod)
mlog.log('LLVM module', mod, 'found:', mlog.green('YES'))
- def check_llvmconfig(self, version_req):
- """Try to find the highest version of llvm-config."""
- for llvmconfig in self.llvm_config_bins:
- try:
- p, out = Popen_safe([llvmconfig, '--version'])[0:2]
- out = out.strip()
- if p.returncode != 0:
- continue
- if version_req:
- if version_compare(out, version_req, strict=True):
- if self.__best_found and version_compare(
- out, '<={}'.format(self.__best_found), strict=True):
- continue
- self.__best_found = out
- self.llvmconfig = llvmconfig
- else:
- # If no specific version is requested use the first version
- # found, since that should be the best.
- self.__best_found = out
- self.llvmconfig = llvmconfig
- break
- except (FileNotFoundError, PermissionError):
- pass
- if self.__best_found:
- mlog.log('Found llvm-config:',
- mlog.bold(shutil.which(self.llvmconfig)),
- '({})'.format(out.strip()))
-
def need_threads(self):
return True
diff --git a/mesonbuild/dependencies/misc.py b/mesonbuild/dependencies/misc.py
index 4a023e4..e966597 100644
--- a/mesonbuild/dependencies/misc.py
+++ b/mesonbuild/dependencies/misc.py
@@ -1,4 +1,4 @@
-# Copyright 2013-2017 The Meson development team
+# Copyright 2013-2017 The Meson development team
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -26,8 +26,11 @@ from .. import mesonlib
from ..mesonlib import Popen_safe, extract_as_list
from ..environment import detect_cpu_family
-from .base import DependencyException, DependencyMethods
-from .base import ExternalDependency, ExternalProgram, ExtraFrameworkDependency, PkgConfigDependency
+from .base import (
+ DependencyException, DependencyMethods, ExternalDependency,
+ ExternalProgram, ExtraFrameworkDependency, PkgConfigDependency,
+ ConfigToolDependency,
+)
# On windows 3 directory layouts are supported:
# * The default layout (versioned) installed:
@@ -687,9 +690,9 @@ class Python3Dependency(ExternalDependency):
class PcapDependency(ExternalDependency):
def __init__(self, environment, kwargs):
super().__init__('pcap', environment, None, kwargs)
+ kwargs['required'] = False
if DependencyMethods.PKGCONFIG in self.methods:
try:
- kwargs['required'] = False
pcdep = PkgConfigDependency('pcap', environment, kwargs)
if pcdep.found():
self.type_name = 'pkgconfig'
@@ -700,25 +703,26 @@ class PcapDependency(ExternalDependency):
return
except Exception as e:
mlog.debug('Pcap not found via pkgconfig. Trying next, error was:', str(e))
- if DependencyMethods.PCAPCONFIG in self.methods:
- pcapconf = shutil.which('pcap-config')
- if pcapconf:
- stdo = Popen_safe(['pcap-config', '--cflags'])[1]
- self.compile_args = stdo.strip().split()
- stdo = Popen_safe(['pcap-config', '--libs'])[1]
- self.link_args = stdo.strip().split()
- self.version = self.get_pcap_lib_version()
- self.is_found = True
- mlog.log('Dependency', mlog.bold('pcap'), 'found:',
- mlog.green('YES'), '(%s)' % pcapconf)
- return
- mlog.debug('Could not find pcap-config binary, trying next.')
+ if DependencyMethods.CONFIG_TOOL in self.methods:
+ try:
+ ctdep = ConfigToolDependency.factory(
+ 'pcap', environment, None, kwargs, ['pcap-config'], 'pcap-config')
+ if ctdep.found():
+ self.config = ctdep.config
+ self.type_name = 'config-tool'
+ self.compile_args = ctdep.get_config_value(['--cflags'], 'compile_args')
+ self.link_args = ctdep.get_config_value(['--libs'], 'link_args')
+ self.version = self.get_pcap_lib_version()
+ self.is_found = True
+ return
+ except Exception as e:
+ mlog.debug('Pcap not found via pcap-config. Trying next, error was:', str(e))
def get_methods(self):
if mesonlib.is_osx():
- return [DependencyMethods.PKGCONFIG, DependencyMethods.PCAPCONFIG, DependencyMethods.EXTRAFRAMEWORK]
+ return [DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL, DependencyMethods.EXTRAFRAMEWORK]
else:
- return [DependencyMethods.PKGCONFIG, DependencyMethods.PCAPCONFIG]
+ return [DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL]
def get_pcap_lib_version(self):
return self.compiler.get_return_value('pcap_lib_version', 'string',
@@ -728,9 +732,9 @@ class PcapDependency(ExternalDependency):
class CupsDependency(ExternalDependency):
def __init__(self, environment, kwargs):
super().__init__('cups', environment, None, kwargs)
+ kwargs['required'] = False
if DependencyMethods.PKGCONFIG in self.methods:
try:
- kwargs['required'] = False
pcdep = PkgConfigDependency('cups', environment, kwargs)
if pcdep.found():
self.type_name = 'pkgconfig'
@@ -741,20 +745,20 @@ class CupsDependency(ExternalDependency):
return
except Exception as e:
mlog.debug('cups not found via pkgconfig. Trying next, error was:', str(e))
- if DependencyMethods.CUPSCONFIG in self.methods:
- cupsconf = shutil.which('cups-config')
- if cupsconf:
- stdo = Popen_safe(['cups-config', '--cflags'])[1]
- self.compile_args = stdo.strip().split()
- stdo = Popen_safe(['cups-config', '--libs'])[1]
- self.link_args = stdo.strip().split()
- stdo = Popen_safe(['cups-config', '--version'])[1]
- self.version = stdo.strip().split()
- self.is_found = True
- mlog.log('Dependency', mlog.bold('cups'), 'found:',
- mlog.green('YES'), '(%s)' % cupsconf)
- return
- mlog.debug('Could not find cups-config binary, trying next.')
+ if DependencyMethods.CONFIG_TOOL in self.methods:
+ try:
+ ctdep = ConfigToolDependency.factory(
+ 'cups', environment, None, kwargs, ['cups-config'], 'cups-config')
+ if ctdep.found():
+ self.config = ctdep.config
+ self.type_name = 'config-tool'
+ self.version = ctdep.version
+ self.compile_args = ctdep.get_config_value(['--cflags'], 'compile_args')
+ self.link_args = ctdep.get_config_value(['--libs'], 'link_args')
+ self.is_found = True
+ return
+ except Exception as e:
+ mlog.debug('cups not found via cups-config. Trying next, error was:', str(e))
if DependencyMethods.EXTRAFRAMEWORK in self.methods:
if mesonlib.is_osx():
fwdep = ExtraFrameworkDependency('cups', False, None, self.env,
@@ -769,9 +773,9 @@ class CupsDependency(ExternalDependency):
def get_methods(self):
if mesonlib.is_osx():
- return [DependencyMethods.PKGCONFIG, DependencyMethods.CUPSCONFIG, DependencyMethods.EXTRAFRAMEWORK]
+ return [DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL, DependencyMethods.EXTRAFRAMEWORK]
else:
- return [DependencyMethods.PKGCONFIG, DependencyMethods.CUPSCONFIG]
+ return [DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL]
class LibWmfDependency(ExternalDependency):
@@ -790,26 +794,27 @@ class LibWmfDependency(ExternalDependency):
return
except Exception as e:
mlog.debug('LibWmf not found via pkgconfig. Trying next, error was:', str(e))
- if DependencyMethods.LIBWMFCONFIG in self.methods:
- libwmfconf = shutil.which('libwmf-config')
- if libwmfconf:
- stdo = Popen_safe(['libwmf-config', '--cflags'])[1]
- self.compile_args = stdo.strip().split()
- stdo = Popen_safe(['libwmf-config', '--libs'])[1]
- self.link_args = stdo.strip().split()
- stdo = Popen_safe(['libwmf-config', '--version'])[1]
- self.version = stdo.strip()
- self.is_found = True
- mlog.log('Dependency', mlog.bold('libwmf'), 'found:',
- mlog.green('YES'), '(%s)' % libwmfconf)
- return
- mlog.debug('Could not find libwmf-config binary, trying next.')
+ if DependencyMethods.CONFIG_TOOL in self.methods:
+ try:
+ ctdep = ConfigToolDependency.factory(
+ 'libwmf', environment, None, kwargs, ['libwmf-config'], 'libwmf-config')
+ if ctdep.found():
+ self.config = ctdep.config
+ self.type_name = 'config-too'
+ self.version = ctdep.version
+ self.compile_args = ctdep.get_config_value(['--cflags'], 'compile_args')
+ self.link_args = ctdep.get_config_value(['--libs'], 'link_args')
+ self.is_found = True
+ return
+ except Exception as e:
+ mlog.debug('cups not found via libwmf-config. Trying next, error was:', str(e))
def get_methods(self):
if mesonlib.is_osx():
- return [DependencyMethods.PKGCONFIG, DependencyMethods.LIBWMFCONFIG, DependencyMethods.EXTRAFRAMEWORK]
+ return [DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL, DependencyMethods.EXTRAFRAMEWORK]
else:
- return [DependencyMethods.PKGCONFIG, DependencyMethods.LIBWMFCONFIG]
+ return [DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL]
+
# Generated with boost_names.py
BOOST_LIBS = [
diff --git a/mesonbuild/dependencies/ui.py b/mesonbuild/dependencies/ui.py
index 837149c..dd04580 100644
--- a/mesonbuild/dependencies/ui.py
+++ b/mesonbuild/dependencies/ui.py
@@ -23,13 +23,16 @@ from collections import OrderedDict
from .. import mlog
from .. import mesonlib
-from ..mesonlib import MesonException, Popen_safe, version_compare
-from ..mesonlib import extract_as_list, for_windows
+from ..mesonlib import (
+ MesonException, Popen_safe, extract_as_list, for_windows,
+ version_compare_many
+)
from ..environment import detect_cpu
from .base import DependencyException, DependencyMethods
from .base import ExternalDependency, ExternalProgram
from .base import ExtraFrameworkDependency, PkgConfigDependency
+from .base import ConfigToolDependency
class GLDependency(ExternalDependency):
@@ -70,49 +73,48 @@ class GLDependency(ExternalDependency):
return [DependencyMethods.PKGCONFIG]
-class GnuStepDependency(ExternalDependency):
+class GnuStepDependency(ConfigToolDependency):
+
+ tools = ['gnustep-config']
+ tool_name = 'gnustep-config'
+
def __init__(self, environment, kwargs):
super().__init__('gnustep', environment, 'objc', kwargs)
+ if not self.is_found:
+ return
self.modules = kwargs.get('modules', [])
- self.detect()
-
- def detect(self):
- self.confprog = 'gnustep-config'
+ self.compile_args = self.filter_args(
+ self.get_config_value(['--objc-flags'], 'compile_args'))
+ self.link_args = self.weird_filter(self.get_config_value(
+ ['--gui-libs' if 'gui' in self.modules else '--base-libs'],
+ 'link_args'))
+
+ def find_config(self, versions=None):
+ tool = self.tools[0]
try:
- gp = Popen_safe([self.confprog, '--help'])[0]
+ p, out = Popen_safe([tool, '--help'])[:2]
except (FileNotFoundError, PermissionError):
- mlog.log('Dependency GnuStep found:', mlog.red('NO'), '(no gnustep-config)')
- return
- if gp.returncode != 0:
- mlog.log('Dependency GnuStep found:', mlog.red('NO'))
- return
- if 'gui' in self.modules:
- arg = '--gui-libs'
- else:
- arg = '--base-libs'
- fp, flagtxt, flagerr = Popen_safe([self.confprog, '--objc-flags'])
- if fp.returncode != 0:
- raise DependencyException('Error getting objc-args: %s %s' % (flagtxt, flagerr))
- args = flagtxt.split()
- self.compile_args = self.filter_args(args)
- fp, libtxt, liberr = Popen_safe([self.confprog, arg])
- if fp.returncode != 0:
- raise DependencyException('Error getting objc-lib args: %s %s' % (libtxt, liberr))
- self.link_args = self.weird_filter(libtxt.split())
- self.version = self.detect_version()
- self.is_found = True
- mlog.log('Dependency', mlog.bold('GnuStep'), 'found:',
- mlog.green('YES'), self.version)
+ return (None, None)
+ if p.returncode != 0:
+ return (None, None)
+ self.config = tool
+ found_version = self.detect_version()
+ if versions and not version_compare_many(found_version, versions)[0]:
+ return (None, found_version)
+
+ return (tool, found_version)
def weird_filter(self, elems):
- """When building packages, the output of the enclosing Make
-is sometimes mixed among the subprocess output. I have no idea
-why. As a hack filter out everything that is not a flag."""
+ """When building packages, the output of the enclosing Make is
+ sometimes mixed among the subprocess output. I have no idea why. As a
+ hack filter out everything that is not a flag.
+ """
return [e for e in elems if e.startswith('-')]
def filter_args(self, args):
- """gnustep-config returns a bunch of garbage args such
- as -O2 and so on. Drop everything that is not needed."""
+ """gnustep-config returns a bunch of garbage args such as -O2 and so
+ on. Drop everything that is not needed.
+ """
result = []
for f in args:
if f.startswith('-D') \
@@ -124,8 +126,8 @@ why. As a hack filter out everything that is not a flag."""
return result
def detect_version(self):
- gmake = self.get_variable('GNUMAKE')
- makefile_dir = self.get_variable('GNUSTEP_MAKEFILES')
+ gmake = self.get_config_value(['--variable=GNUMAKE'], 'variable')[0]
+ makefile_dir = self.get_config_value(['--variable=GNUSTEP_MAKEFILES'], 'variable')[0]
# This Makefile has the GNUStep version set
base_make = os.path.join(makefile_dir, 'Additional', 'base.make')
# Print the Makefile variable passed as the argument. For instance, if
@@ -145,13 +147,6 @@ why. As a hack filter out everything that is not a flag."""
version = '1'
return version
- def get_variable(self, var):
- p, o, e = Popen_safe([self.confprog, '--variable=' + var])
- if p.returncode != 0 and self.required:
- raise DependencyException('{!r} for variable {!r} failed to run'
- ''.format(self.confprog, var))
- return o.strip()
-
class QtBaseDependency(ExternalDependency):
def __init__(self, name, env, kwargs):
@@ -380,9 +375,9 @@ class Qt5Dependency(QtBaseDependency):
class SDL2Dependency(ExternalDependency):
def __init__(self, environment, kwargs):
super().__init__('sdl2', environment, None, kwargs)
+ kwargs['required'] = False
if DependencyMethods.PKGCONFIG in self.methods:
try:
- kwargs['required'] = False
pcdep = PkgConfigDependency('sdl2', environment, kwargs)
if pcdep.found():
self.type_name = 'pkgconfig'
@@ -393,20 +388,20 @@ class SDL2Dependency(ExternalDependency):
return
except Exception as e:
mlog.debug('SDL 2 not found via pkgconfig. Trying next, error was:', str(e))
- if DependencyMethods.SDLCONFIG in self.methods:
- sdlconf = shutil.which('sdl2-config')
- if sdlconf:
- stdo = Popen_safe(['sdl2-config', '--cflags'])[1]
- self.compile_args = stdo.strip().split()
- stdo = Popen_safe(['sdl2-config', '--libs'])[1]
- self.link_args = stdo.strip().split()
- stdo = Popen_safe(['sdl2-config', '--version'])[1]
- self.version = stdo.strip()
- self.is_found = True
- mlog.log('Dependency', mlog.bold('sdl2'), 'found:', mlog.green('YES'),
- self.version, '(%s)' % sdlconf)
- return
- mlog.debug('Could not find sdl2-config binary, trying next.')
+ if DependencyMethods.CONFIG_TOOL in self.methods:
+ try:
+ ctdep = ConfigToolDependency.factory(
+ 'sdl2', environment, None, kwargs, ['sdl2-config'], 'sdl2-config')
+ if ctdep.found():
+ self.type_name = 'config-tool'
+ self.config = ctdep.config
+ self.version = ctdep.version
+ self.compile_args = ctdep.get_config_value(['--cflags'], 'compile_args')
+ self.links_args = ctdep.get_config_value(['--libs'], 'link_args')
+ self.is_found = True
+ return
+ except Exception as e:
+ mlog.debug('SDL 2 not found via sdl2-config. Trying next, error was:', str(e))
if DependencyMethods.EXTRAFRAMEWORK in self.methods:
if mesonlib.is_osx():
fwdep = ExtraFrameworkDependency('sdl2', False, None, self.env,
@@ -421,54 +416,25 @@ class SDL2Dependency(ExternalDependency):
def get_methods(self):
if mesonlib.is_osx():
- return [DependencyMethods.PKGCONFIG, DependencyMethods.SDLCONFIG, DependencyMethods.EXTRAFRAMEWORK]
+ return [DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL, DependencyMethods.EXTRAFRAMEWORK]
else:
- return [DependencyMethods.PKGCONFIG, DependencyMethods.SDLCONFIG]
+ return [DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL]
-class WxDependency(ExternalDependency):
- wx_found = None
+class WxDependency(ConfigToolDependency):
+
+ tools = ['wx-config-3.0', 'wx-config']
+ tool_name = 'wx-config'
def __init__(self, environment, kwargs):
- super().__init__('wx', environment, None, kwargs)
- self.version = 'none'
- if WxDependency.wx_found is None:
- self.check_wxconfig()
- else:
- self.wxc = WxDependency.wx_found
- if not WxDependency.wx_found:
- mlog.log("Neither wx-config-3.0 nor wx-config found; can't detect dependency")
+ super().__init__('WxWidgets', environment, None, kwargs)
+ if not self.is_found:
return
-
- # FIXME: This should print stdout and stderr using mlog.debug
- p, out = Popen_safe([self.wxc, '--version'])[0:2]
- if p.returncode != 0:
- mlog.log('Dependency wxwidgets found:', mlog.red('NO'))
- else:
- self.version = out.strip()
- # FIXME: Support multiple version reqs like PkgConfigDependency
- version_req = kwargs.get('version', None)
- if version_req is not None:
- if not version_compare(self.version, version_req, strict=True):
- mlog.log('Wxwidgets version %s does not fullfill requirement %s' %
- (self.version, version_req))
- return
- mlog.log('Dependency wxwidgets found:', mlog.green('YES'))
- self.is_found = True
- self.requested_modules = self.get_requested(kwargs)
- # wx-config seems to have a cflags as well but since it requires C++,
- # this should be good, at least for now.
- p, out = Popen_safe([self.wxc, '--cxxflags'])[0:2]
- # FIXME: this error should only be raised if required is true
- if p.returncode != 0:
- raise DependencyException('Could not generate cargs for wxwidgets.')
- self.compile_args = out.split()
-
- # FIXME: this error should only be raised if required is true
- p, out = Popen_safe([self.wxc, '--libs'] + self.requested_modules)[0:2]
- if p.returncode != 0:
- raise DependencyException('Could not generate libs for wxwidgets.')
- self.link_args = out.split()
+ self.requested_modules = self.get_requested(kwargs)
+ # wx-config seems to have a cflags as well but since it requires C++,
+ # this should be good, at least for now.
+ self.compile_args = self.get_config_value(['--cxxflags'], 'compile_args')
+ self.link_args = self.get_config_value(['--libs'], 'link_args')
def get_requested(self, kwargs):
if 'modules' not in kwargs:
@@ -479,20 +445,6 @@ class WxDependency(ExternalDependency):
raise DependencyException('wxwidgets module argument is not a string')
return candidates
- def check_wxconfig(self):
- for wxc in ['wx-config-3.0', 'wx-config']:
- try:
- p, out = Popen_safe([wxc, '--version'])[0:2]
- if p.returncode == 0:
- mlog.log('Found wx-config:', mlog.bold(shutil.which(wxc)),
- '(%s)' % out.strip())
- self.wxc = wxc
- WxDependency.wx_found = wxc
- return
- except (FileNotFoundError, PermissionError):
- pass
- WxDependency.wxconfig_found = False
- mlog.log('Found wx-config:', mlog.red('NO'))
class VulkanDependency(ExternalDependency):
def __init__(self, environment, kwargs):
diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py
index 77f3105..b301fee 100644
--- a/mesonbuild/interpreter.py
+++ b/mesonbuild/interpreter.py
@@ -274,6 +274,7 @@ class DependencyHolder(InterpreterObject, ObjectHolder):
'type_name': self.type_name_method,
'version': self.version_method,
'get_pkgconfig_variable': self.pkgconfig_method,
+ 'get_configtool_variable': self.configtool_method,
})
def type_name_method(self, args, kwargs):
@@ -296,6 +297,15 @@ class DependencyHolder(InterpreterObject, ObjectHolder):
raise InterpreterException('Variable name must be a string.')
return self.held_object.get_pkgconfig_variable(varname)
+ def configtool_method(self, args, kwargs):
+ args = listify(args)
+ if len(args) != 1:
+ raise InterpreterException('get_configtool_variable takes exactly one argument.')
+ varname = args[0]
+ if not isinstance(varname, str):
+ raise InterpreterException('Variable name must be a string.')
+ return self.held_object.get_configtool_variable(varname)
+
class InternalDependencyHolder(InterpreterObject, ObjectHolder):
def __init__(self, dep):
InterpreterObject.__init__(self)
diff --git a/run_unittests.py b/run_unittests.py
index be5ce47..8af872e 100755
--- a/run_unittests.py
+++ b/run_unittests.py
@@ -1661,7 +1661,7 @@ class FailureTests(BasePlatformTests):
raise unittest.SkipTest('wx-config or wx-config-3.0 found')
self.assertMesonRaises("dependency('wxwidgets')", self.dnf)
self.assertMesonOutputs("dependency('wxwidgets', required : false)",
- "nor wx-config found")
+ "No wx-config found;")
def test_wx_dependency(self):
if not shutil.which('wx-config-3.0') and not shutil.which('wx-config'):
diff --git a/test cases/common/165 config tool variable/meson.build b/test cases/common/165 config tool variable/meson.build
new file mode 100644
index 0000000..0643042
--- /dev/null
+++ b/test cases/common/165 config tool variable/meson.build
@@ -0,0 +1,31 @@
+# Copyright © 2017 Intel Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+project('config tool variable', 'cpp')
+
+
+dep_llvm = dependency('llvm', required : false)
+if not dep_llvm.found()
+ error('MESON_SKIP_TEST LLVM not installed.')
+endif
+
+includedir = dep_llvm.get_configtool_variable('includedir')
+includedir = join_paths(includedir, 'llvm')
+if host_machine.system() == 'windows'
+ cmd = run_command(['dir', includedir])
+else
+ cmd = run_command(['ls', includedir])
+endif
+
+assert(cmd.returncode() == 0, 'did not run successfully')
diff --git a/test cases/frameworks/16 sdl2/meson.build b/test cases/frameworks/16 sdl2/meson.build
index c79bd46..61a34ef 100644
--- a/test cases/frameworks/16 sdl2/meson.build
+++ b/test cases/frameworks/16 sdl2/meson.build
@@ -6,5 +6,8 @@ e = executable('sdl2prog', 'sdl2prog.c', dependencies : sdl2_dep)
test('sdl2test', e)
-# Ensure that we can find it with sdl2-config too
+# Ensure that we can find it with sdl2-config too, using the legacy method name
configdep = dependency('sdl2', method : 'sdlconfig')
+
+# And the modern method name
+configdep = dependency('sdl2', method : 'config-tool')
diff --git a/test cases/frameworks/19 pcap/meson.build b/test cases/frameworks/19 pcap/meson.build
index c505960..f02f411 100644
--- a/test cases/frameworks/19 pcap/meson.build
+++ b/test cases/frameworks/19 pcap/meson.build
@@ -8,3 +8,7 @@ assert(pcap_ver.split('.').length() > 1, 'pcap version is "@0@"'.format(pcap_ver
e = executable('pcap_prog', 'pcap_prog.c', dependencies : pcap_dep)
test('pcaptest', e)
+
+# Ensure discovery bia the configuration tools work also
+pcap_dep = dependency('pcap', version : '>=1.0', method : 'pcap-config')
+pcap_dep = dependency('pcap', version : '>=1.0', method : 'config-tool')
diff --git a/test cases/frameworks/20 cups/meson.build b/test cases/frameworks/20 cups/meson.build
index 6c9b6fe..11f6f63 100644
--- a/test cases/frameworks/20 cups/meson.build
+++ b/test cases/frameworks/20 cups/meson.build
@@ -5,3 +5,8 @@ cups_dep = dependency('cups', version : '>=1.4')
e = executable('cups_prog', 'cups_prog.c', dependencies : cups_dep)
test('cupstest', e)
+
+# ensure we can find the cups dependency via the legacy and modern config-tool
+# options
+dep = dependency('cups', version : '>=1.4', method : 'cups-config')
+dep = dependency('cups', version : '>=1.4', method : 'config-tool')
diff --git a/test cases/frameworks/21 libwmf/meson.build b/test cases/frameworks/21 libwmf/meson.build
index a7d9263..b39d8f4 100644
--- a/test cases/frameworks/21 libwmf/meson.build
+++ b/test cases/frameworks/21 libwmf/meson.build
@@ -1,9 +1,14 @@
project('libwmf test', 'c')
-libwmf_dep = dependency('libwmf', version : '>=3.0')
+libwmf_dep = dependency('libwmf', version : '>= 0.2.8')
libwmf_ver = libwmf_dep.version()
assert(libwmf_ver.split('.').length() > 1, 'libwmf version is "@0@"'.format(libwmf_ver))
message('libwmf version is "@0@"'.format(libwmf_ver))
e = executable('libwmf_prog', 'libwmf_prog.c', dependencies : libwmf_dep)
test('libwmftest', e)
+
+# Test using the method keyword:
+
+dependency('libwmf', method : 'config-tool')
+dependency('libwmf', method : 'libwmf-config')