aboutsummaryrefslogtreecommitdiff
path: root/mesonbuild/dependencies
diff options
context:
space:
mode:
authorNirbheek Chauhan <nirbheek@centricular.com>2017-06-05 03:29:40 +0530
committerNirbheek Chauhan <nirbheek@centricular.com>2017-06-09 20:21:01 +0530
commit0c83f8352d288134ede8f4b8854e455007ce02b7 (patch)
tree61044ab368b3e57540f2b43fba1418f4d2652a78 /mesonbuild/dependencies
parent22cfd44221ada3219d9096e15dc8b00d32e0f9f6 (diff)
downloadmeson-0c83f8352d288134ede8f4b8854e455007ce02b7.zip
meson-0c83f8352d288134ede8f4b8854e455007ce02b7.tar.gz
meson-0c83f8352d288134ede8f4b8854e455007ce02b7.tar.bz2
dependencies: Add a new class ExternalDependency
This class now consolidates a lot of the logic that each external dependency was duplicating in its class definition. All external dependencies now set: * self.version * self.compile_args and self.link_args * self.is_found (if found) * self.sources * etc And the abstract ExternalDependency class defines the methods that will fetch those properties. Some classes still override that for various reasons, but those should also be migrated to properties as far as possible. Next step is to consolidate and standardize the way in which we call 'configuration binaries' such as sdl2-config, llvm-config, pkg-config, etc. Currently each class has to duplicate code involved with that even though the format is very similar. Currently only pkg-config supports multiple version requirements, and some classes don't even properly check the version requirement. That will also become easier now.
Diffstat (limited to 'mesonbuild/dependencies')
-rw-r--r--mesonbuild/dependencies/__init__.py5
-rw-r--r--mesonbuild/dependencies/base.py176
-rw-r--r--mesonbuild/dependencies/dev.py109
-rw-r--r--mesonbuild/dependencies/misc.py73
-rw-r--r--mesonbuild/dependencies/platform.py16
-rw-r--r--mesonbuild/dependencies/ui.py209
6 files changed, 203 insertions, 385 deletions
diff --git a/mesonbuild/dependencies/__init__.py b/mesonbuild/dependencies/__init__.py
index ec11152..3d41a2b 100644
--- a/mesonbuild/dependencies/__init__.py
+++ b/mesonbuild/dependencies/__init__.py
@@ -13,8 +13,9 @@
# limitations under the License.
from .base import ( # noqa: F401
- Dependency, DependencyException, DependencyMethods, ExternalProgram, ExternalLibrary, ExtraFrameworkDependency,
- InternalDependency, PkgConfigDependency, find_external_dependency, get_dep_identifier, packages)
+ Dependency, DependencyException, DependencyMethods, ExternalProgram,
+ ExternalDependency, ExternalLibrary, ExtraFrameworkDependency, InternalDependency,
+ PkgConfigDependency, find_external_dependency, get_dep_identifier, packages)
from .dev import GMockDependency, GTestDependency, LLVMDependency, ValgrindDependency
from .misc import BoostDependency, Python3Dependency, ThreadDependency
from .platform import AppleFrameworks
diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py
index 139ff39..d727021 100644
--- a/mesonbuild/dependencies/base.py
+++ b/mesonbuild/dependencies/base.py
@@ -52,9 +52,13 @@ class DependencyMethods(Enum):
class Dependency:
def __init__(self, type_name, kwargs):
self.name = "null"
- self.language = None
+ self.version = 'none'
+ self.language = None # None means C-like
self.is_found = False
self.type_name = type_name
+ self.compile_args = []
+ self.link_args = []
+ self.sources = []
method = DependencyMethods(kwargs.get('method', 'auto'))
# Set the detection method. If the method is set to auto, use any available method.
@@ -74,10 +78,10 @@ class Dependency:
return s.format(self.__class__.__name__, self.name, self.is_found)
def get_compile_args(self):
- return []
+ return self.compile_args
def get_link_args(self):
- return []
+ return self.link_args
def found(self):
return self.is_found
@@ -85,7 +89,7 @@ class Dependency:
def get_sources(self):
"""Source files that need to be added to the target.
As an example, gtest-all.cc when using GTest."""
- return []
+ return self.sources
def get_methods(self):
return [DependencyMethods.AUTO]
@@ -93,6 +97,9 @@ class Dependency:
def get_name(self):
return self.name
+ def get_version(self):
+ return self.version
+
def get_exe_args(self, compiler):
return []
@@ -100,7 +107,7 @@ class Dependency:
return False
def get_pkgconfig_variable(self, variable_name):
- raise MesonException('Tried to get a pkg-config variable from a non-pkgconfig dependency.')
+ raise NotImplementedError('{!r} is not a pkgconfig dependency'.format(self.name))
class InternalDependency(Dependency):
@@ -115,41 +122,52 @@ class InternalDependency(Dependency):
self.sources = sources
self.ext_deps = ext_deps
- def get_compile_args(self):
- return self.compile_args
- def get_link_args(self):
- return self.link_args
+class ExternalDependency(Dependency):
+ def __init__(self, type_name, environment, language, kwargs):
+ super().__init__(type_name, kwargs)
+ self.env = environment
+ self.name = type_name # default
+ self.is_found = False
+ self.language = language
+ if language and language not in self.env.coredata.compilers:
+ m = self.name.capitalize() + ' requires a {} compiler'
+ raise DependencyException(m.format(language.capitalize()))
+ self.version_reqs = kwargs.get('version', None)
+ self.required = kwargs.get('required', True)
+ self.silent = kwargs.get('silent', False)
+ self.static = kwargs.get('static', False)
+ if not isinstance(self.static, bool):
+ raise DependencyException('Static keyword must be boolean')
+ # Is this dependency for cross-com,pilation?
+ if 'native' in kwargs and self.env.is_cross_build():
+ self.want_cross = not kwargs['native']
+ else:
+ self.want_cross = self.env.is_cross_build()
+ # Set the compiler that will be used by this dependency
+ # This is only used for configuration checks
+ if self.want_cross:
+ compilers = self.env.coredata.cross_compilers
+ else:
+ compilers = self.env.coredata.compilers
+ self.compiler = compilers.get(self.language or 'c', None)
- def get_version(self):
- return self.version
+ def get_compiler(self):
+ return self.compiler
-class PkgConfigDependency(Dependency):
+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.
class_pkgbin = None
def __init__(self, name, environment, kwargs):
- Dependency.__init__(self, 'pkgconfig', kwargs)
+ super().__init__('pkgconfig', environment, None, kwargs)
+ self.name = name
self.is_libtool = False
- self.version_reqs = kwargs.get('version', None)
- self.required = kwargs.get('required', True)
- self.static = kwargs.get('static', False)
- self.silent = kwargs.get('silent', False)
- if not isinstance(self.static, bool):
- raise DependencyException('Static keyword must be boolean')
# Store a copy of the pkg-config path on the object itself so it is
# stored in the pickled coredata and recovered.
self.pkgbin = None
- self.cargs = []
- self.libs = []
- if 'native' in kwargs and environment.is_cross_build():
- self.want_cross = not kwargs['native']
- else:
- self.want_cross = environment.is_cross_build()
- self.name = name
- self.modversion = 'none'
# When finding dependencies for cross-compiling, we don't care about
# the 'native' pkg-config
@@ -175,7 +193,6 @@ class PkgConfigDependency(Dependency):
else:
self.pkgbin = PkgConfigDependency.class_pkgbin
- self.is_found = False
if not self.pkgbin:
if self.required:
raise DependencyException('Pkg-config not found.')
@@ -187,7 +204,7 @@ class PkgConfigDependency(Dependency):
mlog.debug('Determining dependency {!r} with pkg-config executable '
'{!r}'.format(name, self.pkgbin))
- ret, self.modversion = self._call_pkgbin(['--modversion', name])
+ ret, self.version = self._call_pkgbin(['--modversion', name])
if ret != 0:
if self.required:
raise DependencyException('{} dependency {!r} not found'
@@ -202,10 +219,10 @@ class PkgConfigDependency(Dependency):
if isinstance(self.version_reqs, str):
self.version_reqs = [self.version_reqs]
(self.is_found, not_found, found) = \
- version_compare_many(self.modversion, self.version_reqs)
+ version_compare_many(self.version, self.version_reqs)
if not self.is_found:
found_msg += [mlog.red('NO'),
- 'found {!r} but need:'.format(self.modversion),
+ 'found {!r} but need:'.format(self.version),
', '.join(["'{}'".format(e) for e in not_found])]
if found:
found_msg += ['; matched:',
@@ -214,9 +231,9 @@ class PkgConfigDependency(Dependency):
mlog.log(*found_msg)
if self.required:
m = 'Invalid version of dependency, need {!r} {!r} found {!r}.'
- raise DependencyException(m.format(name, not_found, self.modversion))
+ raise DependencyException(m.format(name, not_found, self.version))
return
- found_msg += [mlog.green('YES'), self.modversion]
+ found_msg += [mlog.green('YES'), self.version]
# Fetch cargs to be used while using this dependency
self._set_cargs()
# Fetch the libraries and library paths needed for using this
@@ -240,7 +257,7 @@ class PkgConfigDependency(Dependency):
if ret != 0:
raise DependencyException('Could not generate cargs for %s:\n\n%s' %
(self.name, out))
- self.cargs = out.split()
+ self.compile_args = out.split()
def _set_libs(self):
libcmd = [self.name, '--libs']
@@ -250,7 +267,7 @@ class PkgConfigDependency(Dependency):
if ret != 0:
raise DependencyException('Could not generate libs for %s:\n\n%s' %
(self.name, out))
- self.libs = []
+ self.link_args = []
for lib in out.split():
if lib.endswith(".la"):
shared_libname = self.extract_libtool_shlib(lib)
@@ -264,7 +281,7 @@ class PkgConfigDependency(Dependency):
'library path' % lib)
lib = shared_lib
self.is_libtool = True
- self.libs.append(lib)
+ self.link_args.append(lib)
def get_pkgconfig_variable(self, variable_name):
ret, out = self._call_pkgbin(['--variable=' + variable_name, self.name])
@@ -278,18 +295,6 @@ class PkgConfigDependency(Dependency):
mlog.debug('Got pkgconfig variable %s : %s' % (variable_name, variable))
return variable
- def get_modversion(self):
- return self.modversion
-
- def get_version(self):
- return self.modversion
-
- def get_compile_args(self):
- return self.cargs
-
- def get_link_args(self):
- return self.libs
-
def get_methods(self):
return [DependencyMethods.PKGCONFIG]
@@ -319,9 +324,6 @@ class PkgConfigDependency(Dependency):
mlog.log('Found Pkg-config:', mlog.red('NO'))
return pkgbin
- def found(self):
- return self.is_found
-
def extract_field(self, la_file, fieldname):
with open(la_file) as f:
for line in f:
@@ -500,52 +502,39 @@ class ExternalProgram:
return self.name
-class ExternalLibrary(Dependency):
- # TODO: Add `language` support to all Dependency objects so that languages
- # can be exposed for dependencies that support that (i.e., not pkg-config)
- def __init__(self, name, link_args, language, silent=False):
- super().__init__('external', {})
+class ExternalLibrary(ExternalDependency):
+ def __init__(self, name, link_args, environment, language, silent=False):
+ super().__init__('external', environment, language, {})
self.name = name
self.language = language
self.is_found = False
- self.link_args = []
- self.lang_args = []
if link_args:
self.is_found = True
if not isinstance(link_args, list):
link_args = [link_args]
- self.lang_args = {language: link_args}
- # We special-case Vala for now till the Dependency object gets
- # proper support for exposing the language it was written in.
- # Without this, vala-specific link args will end up in the C link
- # args list if you link to a Vala library.
- # This hack use to be in CompilerHolder.find_library().
- if language != 'vala':
- self.link_args = link_args
+ self.link_args = link_args
if not silent:
if self.is_found:
mlog.log('Library', mlog.bold(name), 'found:', mlog.green('YES'))
else:
mlog.log('Library', mlog.bold(name), 'found:', mlog.red('NO'))
- def found(self):
- return self.is_found
-
- def get_name(self):
- return self.name
-
- def get_link_args(self):
+ def get_link_args(self, language=None):
+ '''
+ External libraries detected using a compiler must only be used with
+ compatible code. For instance, Vala libraries (.vapi files) cannot be
+ used with C code, and not all Rust library types can be linked with
+ C-like code. Note that C++ libraries *can* be linked with C code with
+ a C++ linker (and vice-versa).
+ '''
+ if self.language == 'vala' and language != 'vala':
+ return []
return self.link_args
- def get_lang_args(self, lang):
- if lang in self.lang_args:
- return self.lang_args[lang]
- return []
-
-class ExtraFrameworkDependency(Dependency):
- def __init__(self, name, required, path, kwargs):
- Dependency.__init__(self, 'extraframeworks', kwargs)
+class ExtraFrameworkDependency(ExternalDependency):
+ def __init__(self, name, required, path, env, lang, kwargs):
+ super().__init__('extraframeworks', env, lang, kwargs)
self.name = None
self.required = required
self.detect(name, path)
@@ -570,6 +559,7 @@ class ExtraFrameworkDependency(Dependency):
continue
self.path = p
self.name = d
+ self.is_found = True
return
if not self.found() and self.required:
raise DependencyException('Framework dependency %s not found.' % (name, ))
@@ -584,9 +574,6 @@ class ExtraFrameworkDependency(Dependency):
return ['-F' + self.path, '-framework', self.name.split('.')[0]]
return []
- def found(self):
- return self.name is not None
-
def get_version(self):
return 'unknown'
@@ -611,7 +598,7 @@ def get_dep_identifier(name, kwargs, want_cross):
return identifier
-def find_external_dependency(name, environment, kwargs):
+def find_external_dependency(name, env, kwargs):
required = kwargs.get('required', True)
if not isinstance(required, bool):
raise DependencyException('Keyword "required" must be a boolean.')
@@ -619,20 +606,20 @@ def find_external_dependency(name, environment, kwargs):
raise DependencyException('Keyword "method" must be a string.')
lname = name.lower()
if lname in packages:
- dep = packages[lname](environment, kwargs)
+ dep = packages[lname](env, kwargs)
if required and not dep.found():
raise DependencyException('Dependency "%s" not found' % name)
return dep
pkg_exc = None
pkgdep = None
try:
- pkgdep = PkgConfigDependency(name, environment, kwargs)
+ pkgdep = PkgConfigDependency(name, env, kwargs)
if pkgdep.found():
return pkgdep
except Exception as e:
pkg_exc = e
if mesonlib.is_osx():
- fwdep = ExtraFrameworkDependency(name, required, None, kwargs)
+ fwdep = ExtraFrameworkDependency(name, required, None, env, kwargs)
if required and not fwdep.found():
m = 'Dependency {!r} not found, tried Extra Frameworks ' \
'and Pkg-Config:\n\n' + str(pkg_exc)
@@ -642,16 +629,3 @@ def find_external_dependency(name, environment, kwargs):
raise pkg_exc
mlog.log('Dependency', mlog.bold(name), 'found:', mlog.red('NO'))
return pkgdep
-
-def dependency_get_compiler(language, environment, kwargs):
- if 'native' in kwargs and environment.is_cross_build():
- want_cross = not kwargs['native']
- else:
- want_cross = environment.is_cross_build()
-
- if want_cross:
- compilers = environment.coredata.cross_compilers
- else:
- compilers = environment.coredata.compilers
-
- return compilers.get(language, None)
diff --git a/mesonbuild/dependencies/dev.py b/mesonbuild/dependencies/dev.py
index 76d6691..8d64379 100644
--- a/mesonbuild/dependencies/dev.py
+++ b/mesonbuild/dependencies/dev.py
@@ -22,29 +22,20 @@ import shutil
from .. import mlog
from .. import mesonlib
from ..mesonlib import version_compare, Popen_safe
-from .base import Dependency, DependencyException, PkgConfigDependency, dependency_get_compiler
+from .base import DependencyException, ExternalDependency, PkgConfigDependency
-class GTestDependency(Dependency):
+class GTestDependency(ExternalDependency):
def __init__(self, environment, kwargs):
- Dependency.__init__(self, 'gtest', kwargs)
- self.env = environment
+ super().__init__('gtest', environment, 'cpp', kwargs)
self.main = kwargs.get('main', False)
- self.name = 'gtest'
- self.include_dir = '/usr/include'
self.src_dirs = ['/usr/src/gtest/src', '/usr/src/googletest/googletest/src']
-
- self.cpp_compiler = dependency_get_compiler('cpp', environment, kwargs)
- if self.cpp_compiler is None:
- raise DependencyException('Tried to use gtest but a C++ compiler is not defined.')
self.detect()
- def found(self):
- return self.is_found
-
def detect(self):
- gtest_detect = self.cpp_compiler.find_library("gtest", self.env, [])
- gtest_main_detect = self.cpp_compiler.find_library("gtest_main", self.env, [])
- if gtest_detect and gtest_main_detect:
+ self.version = '1.something_maybe'
+ gtest_detect = self.compiler.find_library("gtest", self.env, [])
+ gtest_main_detect = self.compiler.find_library("gtest_main", self.env, [])
+ if gtest_detect and (not self.main or gtest_main_detect):
self.is_found = True
self.compile_args = []
self.link_args = gtest_detect
@@ -64,7 +55,6 @@ class GTestDependency(Dependency):
else:
mlog.log('Dependency GTest found:', mlog.red('NO'))
self.is_found = False
- return self.is_found
def detect_srcdir(self):
for s in self.src_dirs:
@@ -78,37 +68,17 @@ class GTestDependency(Dependency):
return True
return False
- def get_compile_args(self):
- arr = []
- if self.include_dir != '/usr/include':
- arr.append('-I' + self.include_dir)
- if hasattr(self, 'src_include_dir'):
- arr.append('-I' + self.src_include_dir)
- return arr
-
- def get_link_args(self):
- return self.link_args
-
- def get_version(self):
- return '1.something_maybe'
-
- def get_sources(self):
- return self.sources
-
def need_threads(self):
return True
-class GMockDependency(Dependency):
+class GMockDependency(ExternalDependency):
def __init__(self, environment, kwargs):
- Dependency.__init__(self, 'gmock', kwargs)
+ super().__init__('gmock', environment, 'cpp', kwargs)
+ self.version = '1.something_maybe'
# GMock may be a library or just source.
# Work with both.
- self.name = 'gmock'
- cpp_compiler = dependency_get_compiler('cpp', environment, kwargs)
- if cpp_compiler is None:
- raise DependencyException('Tried to use gmock but a C++ compiler is not defined.')
- gmock_detect = cpp_compiler.find_library("gmock", environment, [])
+ gmock_detect = self.compiler.find_library("gmock", self.env, [])
if gmock_detect:
self.is_found = True
self.compile_args = []
@@ -133,29 +103,12 @@ class GMockDependency(Dependency):
self.sources = [all_src]
mlog.log('Dependency GMock found:', mlog.green('YES'), '(building self)')
return
-
mlog.log('Dependency GMock found:', mlog.red('NO'))
self.is_found = False
- def get_version(self):
- return '1.something_maybe'
-
- def get_compile_args(self):
- return self.compile_args
-
- def get_sources(self):
- return self.sources
-
- def get_link_args(self):
- return self.link_args
-
- def found(self):
- return self.is_found
-
-
-class LLVMDependency(Dependency):
- """LLVM dependency.
+class LLVMDependency(ExternalDependency):
+ """
LLVM uses a special tool, llvm-config, which has arguments for getting
c args, cxx args, and ldargs as well as version.
"""
@@ -182,15 +135,11 @@ class LLVMDependency(Dependency):
__cpp_blacklist = {'-DNDEBUG'}
def __init__(self, environment, kwargs):
- super().__init__('llvm-config', 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.
- self.language = 'cpp'
- self.cargs = []
- self.libs = []
+ super().__init__('llvm-config', environment, 'cpp', kwargs)
self.modules = []
-
- required = kwargs.get('required', True)
+ # FIXME: Support multiple version requirements ala PkgConfigDependency
req_version = kwargs.get('version', None)
if self.llvmconfig is None:
self.check_llvmconfig(req_version)
@@ -201,14 +150,14 @@ class LLVMDependency(Dependency):
else:
mlog.log("No llvm-config found; can't detect dependency")
mlog.log('Dependency LLVM found:', mlog.red('NO'))
- if required:
+ if self.required:
raise DependencyException('Dependency LLVM not found')
return
p, out, err = Popen_safe([self.llvmconfig, '--version'])
if p.returncode != 0:
mlog.debug('stdout: {}\nstderr: {}'.format(out, err))
- if required:
+ if self.required:
raise DependencyException('Dependency LLVM not found')
return
else:
@@ -220,12 +169,13 @@ class LLVMDependency(Dependency):
[self.llvmconfig, '--libs', '--ldflags', '--system-libs'])[:2]
if p.returncode != 0:
raise DependencyException('Could not generate libs for LLVM.')
- self.libs = shlex.split(out)
+ self.link_args = shlex.split(out)
p, out = Popen_safe([self.llvmconfig, '--cppflags'])[:2]
if p.returncode != 0:
raise DependencyException('Could not generate includedir for LLVM.')
- self.cargs = list(mesonlib.OrderedSet(shlex.split(out)).difference(self.__cpp_blacklist))
+ cargs = mesonlib.OrderedSet(shlex.split(out))
+ self.compile_args = list(cargs.difference(self.__cpp_blacklist))
p, out = Popen_safe([self.llvmconfig, '--components'])[:2]
if p.returncode != 0:
@@ -237,21 +187,12 @@ class LLVMDependency(Dependency):
if mod not in self.modules:
mlog.log('LLVM module', mod, 'found:', mlog.red('NO'))
self.is_found = False
- if required:
+ if self.required:
raise DependencyException(
'Could not find required LLVM Component: {}'.format(mod))
else:
mlog.log('LLVM module', mod, 'found:', mlog.green('YES'))
- def get_version(self):
- return self.version
-
- def get_compile_args(self):
- return self.cargs
-
- def get_link_args(self):
- return self.libs
-
@classmethod
def check_llvmconfig(cls, version_req):
"""Try to find the highest version of llvm-config."""
@@ -288,8 +229,12 @@ class LLVMDependency(Dependency):
class ValgrindDependency(PkgConfigDependency):
- def __init__(self, environment, kwargs):
- PkgConfigDependency.__init__(self, 'valgrind', environment, kwargs)
+ '''
+ Consumers of Valgrind usually only need the compile args and do not want to
+ link to its (static) libraries.
+ '''
+ def __init__(self, env, kwargs):
+ super().__init__('valgrind', env, None, kwargs)
def get_link_args(self):
return []
diff --git a/mesonbuild/dependencies/misc.py b/mesonbuild/dependencies/misc.py
index 6a76ba6..1356ec8 100644
--- a/mesonbuild/dependencies/misc.py
+++ b/mesonbuild/dependencies/misc.py
@@ -23,25 +23,19 @@ from .. import mlog
from .. import mesonlib
from ..environment import detect_cpu_family
-from .base import Dependency, DependencyException, DependencyMethods, ExtraFrameworkDependency, PkgConfigDependency
+from .base import DependencyException, DependencyMethods
+from .base import ExternalDependency, ExtraFrameworkDependency, PkgConfigDependency
-class BoostDependency(Dependency):
+class BoostDependency(ExternalDependency):
# Some boost libraries have different names for
# their sources and libraries. This dict maps
# between the two.
name2lib = {'test': 'unit_test_framework'}
def __init__(self, environment, kwargs):
- Dependency.__init__(self, 'boost', kwargs)
- self.name = 'boost'
- self.environment = environment
+ super().__init__('boost', environment, 'cpp', kwargs)
self.libdir = ''
- self.static = kwargs.get('static', False)
- if 'native' in kwargs and environment.is_cross_build():
- self.want_cross = not kwargs['native']
- else:
- self.want_cross = environment.is_cross_build()
try:
self.boost_root = os.environ['BOOST_ROOT']
if not os.path.isabs(self.boost_root):
@@ -72,7 +66,7 @@ class BoostDependency(Dependency):
self.detect_version()
self.requested_modules = self.get_requested(kwargs)
module_str = ', '.join(self.requested_modules)
- if self.version is not None:
+ if self.is_found:
self.detect_src_modules()
self.detect_lib_modules()
self.validate_requested()
@@ -83,9 +77,6 @@ class BoostDependency(Dependency):
mlog.log('Dependency Boost (%s) found:' % module_str, mlog.green('YES'), info)
else:
mlog.log("Dependency Boost (%s) found:" % module_str, mlog.red('NO'))
- if 'cpp' not in self.environment.coredata.compilers:
- raise DependencyException('Tried to use Boost but a C++ compiler is not defined.')
- self.cpp_compiler = self.environment.coredata.compilers['cpp']
def detect_win_root(self):
globtext = 'c:\\local\\boost_*'
@@ -130,7 +121,7 @@ class BoostDependency(Dependency):
# names in order to handle cases like cross-compiling where we
# might have a different sysroot.
if not include_dir.endswith(('/usr/include', '/usr/local/include')):
- args.append("".join(self.cpp_compiler.get_include_args(include_dir, True)))
+ args.append("".join(self.compiler.get_include_args(include_dir, True)))
return args
def get_requested(self, kwargs):
@@ -147,17 +138,10 @@ class BoostDependency(Dependency):
if m not in self.src_modules:
raise DependencyException('Requested Boost module "%s" not found.' % m)
- def found(self):
- return self.version is not None
-
- def get_version(self):
- return self.version
-
def detect_version(self):
try:
ifile = open(os.path.join(self.boost_inc_subdir, 'version.hpp'))
except FileNotFoundError:
- self.version = None
return
with ifile:
for line in ifile:
@@ -165,8 +149,8 @@ class BoostDependency(Dependency):
ver = line.split()[-1]
ver = ver[1:-1]
self.version = ver.replace('_', '.')
+ self.is_found = True
return
- self.version = None
def detect_src_modules(self):
for entry in os.listdir(self.boost_inc_subdir):
@@ -180,7 +164,7 @@ class BoostDependency(Dependency):
return self.detect_lib_modules_nix()
def detect_lib_modules_win(self):
- arch = detect_cpu_family(self.environment.coredata.compilers)
+ arch = detect_cpu_family(self.env.coredata.compilers)
# Guess the libdir
if arch == 'x86':
gl = 'lib32*'
@@ -254,10 +238,10 @@ class BoostDependency(Dependency):
module = BoostDependency.name2lib.get(module, module)
libname = 'boost_' + module
# The compiler's library detector is the most reliable so use that first.
- default_detect = self.cpp_compiler.find_library(libname, self.environment, [])
+ default_detect = self.compiler.find_library(libname, self.env, [])
if default_detect is not None:
if module == 'unit_testing_framework':
- emon_args = self.cpp_compiler.find_library('boost_test_exec_monitor')
+ emon_args = self.compiler.find_library('boost_test_exec_monitor')
else:
emon_args = None
args += default_detect
@@ -286,9 +270,9 @@ class BoostDependency(Dependency):
return 'thread' in self.requested_modules
-class ThreadDependency(Dependency):
+class ThreadDependency(ExternalDependency):
def __init__(self, environment, kwargs):
- super().__init__('threads', {})
+ super().__init__('threads', environment, None, {})
self.name = 'threads'
self.is_found = True
mlog.log('Dependency', mlog.bold(self.name), 'found:', mlog.green('YES'))
@@ -300,19 +284,18 @@ class ThreadDependency(Dependency):
return 'unknown'
-class Python3Dependency(Dependency):
+class Python3Dependency(ExternalDependency):
def __init__(self, environment, kwargs):
- super().__init__('python3', kwargs)
+ super().__init__('python3', environment, None, kwargs)
self.name = 'python3'
- self.is_found = False
# We can only be sure that it is Python 3 at this point
self.version = '3'
if DependencyMethods.PKGCONFIG in self.methods:
try:
pkgdep = PkgConfigDependency('python3', environment, kwargs)
if pkgdep.found():
- self.cargs = pkgdep.cargs
- self.libs = pkgdep.libs
+ self.compile_args = pkgdep.get_compile_args()
+ self.link_args = pkgdep.get_link_args()
self.version = pkgdep.get_version()
self.is_found = True
return
@@ -324,10 +307,11 @@ class Python3Dependency(Dependency):
elif mesonlib.is_osx() and DependencyMethods.EXTRAFRAMEWORK in self.methods:
# In OSX the Python 3 framework does not have a version
# number in its name.
- fw = ExtraFrameworkDependency('python', False, None, kwargs)
+ fw = ExtraFrameworkDependency('python', False, None, self.env,
+ self.language, kwargs)
if fw.found():
- self.cargs = fw.get_compile_args()
- self.libs = fw.get_link_args()
+ self.compile_args = fw.get_compile_args()
+ self.link_args = fw.get_link_args()
self.is_found = True
if self.is_found:
mlog.log('Dependency', mlog.bold(self.name), 'found:', mlog.green('YES'))
@@ -359,23 +343,17 @@ class Python3Dependency(Dependency):
return
inc = sysconfig.get_path('include')
platinc = sysconfig.get_path('platinclude')
- self.cargs = ['-I' + inc]
+ self.compile_args = ['-I' + inc]
if inc != platinc:
- self.cargs.append('-I' + platinc)
+ self.compile_args.append('-I' + platinc)
# Nothing exposes this directly that I coulf find
basedir = sysconfig.get_config_var('base')
vernum = sysconfig.get_config_var('py_version_nodot')
- self.libs = ['-L{}/libs'.format(basedir),
- '-lpython{}'.format(vernum)]
+ self.link_args = ['-L{}/libs'.format(basedir),
+ '-lpython{}'.format(vernum)]
self.version = sysconfig.get_config_var('py_version_short')
self.is_found = True
- def get_compile_args(self):
- return self.cargs
-
- def get_link_args(self):
- return self.libs
-
def get_methods(self):
if mesonlib.is_windows():
return [DependencyMethods.PKGCONFIG, DependencyMethods.SYSCONFIG]
@@ -383,6 +361,3 @@ class Python3Dependency(Dependency):
return [DependencyMethods.PKGCONFIG, DependencyMethods.EXTRAFRAMEWORK]
else:
return [DependencyMethods.PKGCONFIG]
-
- def get_version(self):
- return self.version
diff --git a/mesonbuild/dependencies/platform.py b/mesonbuild/dependencies/platform.py
index cd46412..95ab727 100644
--- a/mesonbuild/dependencies/platform.py
+++ b/mesonbuild/dependencies/platform.py
@@ -17,25 +17,21 @@
from .. import mesonlib
-from .base import Dependency, DependencyException
+from .base import ExternalDependency, DependencyException
-class AppleFrameworks(Dependency):
- def __init__(self, environment, kwargs):
- Dependency.__init__(self, 'appleframeworks', kwargs)
+class AppleFrameworks(ExternalDependency):
+ def __init__(self, env, kwargs):
+ super().__init__('appleframeworks', env, None, kwargs)
modules = kwargs.get('modules', [])
if isinstance(modules, str):
modules = [modules]
if not modules:
raise DependencyException("AppleFrameworks dependency requires at least one module.")
self.frameworks = modules
-
- def get_link_args(self):
- args = []
+ # FIXME: Use self.compiler to check if the frameworks are available
for f in self.frameworks:
- args.append('-framework')
- args.append(f)
- return args
+ self.link_args += ['-framework', f]
def found(self):
return mesonlib.is_osx()
diff --git a/mesonbuild/dependencies/ui.py b/mesonbuild/dependencies/ui.py
index 3174176..7b276cc 100644
--- a/mesonbuild/dependencies/ui.py
+++ b/mesonbuild/dependencies/ui.py
@@ -26,24 +26,22 @@ from .. import mesonlib
from ..mesonlib import MesonException, Popen_safe, version_compare
from ..environment import for_windows
-from .base import (Dependency, DependencyException, DependencyMethods,
- ExternalProgram, ExtraFrameworkDependency, PkgConfigDependency)
+from .base import DependencyException, DependencyMethods
+from .base import ExternalDependency, ExternalProgram
+from .base import ExtraFrameworkDependency, PkgConfigDependency
-class GLDependency(Dependency):
+class GLDependency(ExternalDependency):
def __init__(self, environment, kwargs):
- Dependency.__init__(self, 'gl', kwargs)
- self.is_found = False
- self.cargs = []
- self.linkargs = []
+ super().__init__('gl', environment, None, kwargs)
if DependencyMethods.PKGCONFIG in self.methods:
try:
pcdep = PkgConfigDependency('gl', environment, kwargs)
if pcdep.found():
self.type_name = 'pkgconfig'
self.is_found = True
- self.cargs = pcdep.get_compile_args()
- self.linkargs = pcdep.get_link_args()
+ self.compile_args = pcdep.get_compile_args()
+ self.link_args = pcdep.get_link_args()
self.version = pcdep.get_version()
return
except Exception:
@@ -51,21 +49,19 @@ class GLDependency(Dependency):
if DependencyMethods.SYSTEM in self.methods:
if mesonlib.is_osx():
self.is_found = True
- self.linkargs = ['-framework', 'OpenGL']
- self.version = '1' # FIXME
+ # FIXME: Use AppleFrameworks dependency
+ self.link_args = ['-framework', 'OpenGL']
+ # FIXME: Detect version using self.compiler
+ self.version = '1'
return
if mesonlib.is_windows():
self.is_found = True
- self.linkargs = ['-lopengl32']
- self.version = '1' # FIXME: unfixable?
+ # FIXME: Use self.compiler.find_library()
+ self.link_args = ['-lopengl32']
+ # FIXME: Detect version using self.compiler
+ self.version = '1'
return
- def get_link_args(self):
- return self.linkargs
-
- def get_version(self):
- return self.version
-
def get_methods(self):
if mesonlib.is_osx() or mesonlib.is_windows():
return [DependencyMethods.PKGCONFIG, DependencyMethods.SYSTEM]
@@ -73,10 +69,9 @@ class GLDependency(Dependency):
return [DependencyMethods.PKGCONFIG]
-class GnuStepDependency(Dependency):
+class GnuStepDependency(ExternalDependency):
def __init__(self, environment, kwargs):
- Dependency.__init__(self, 'gnustep', kwargs)
- self.required = kwargs.get('required', True)
+ super().__init__('gnustep', environment, 'objc', kwargs)
self.modules = kwargs.get('modules', [])
self.detect()
@@ -85,11 +80,9 @@ class GnuStepDependency(Dependency):
try:
gp = Popen_safe([self.confprog, '--help'])[0]
except (FileNotFoundError, PermissionError):
- self.args = None
mlog.log('Dependency GnuStep found:', mlog.red('NO'), '(no gnustep-config)')
return
if gp.returncode != 0:
- self.args = None
mlog.log('Dependency GnuStep found:', mlog.red('NO'))
return
if 'gui' in self.modules:
@@ -100,12 +93,13 @@ class GnuStepDependency(Dependency):
if fp.returncode != 0:
raise DependencyException('Error getting objc-args: %s %s' % (flagtxt, flagerr))
args = flagtxt.split()
- self.args = self.filter_arsg(args)
+ 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.libs = self.weird_filter(libtxt.split())
+ 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)
@@ -115,7 +109,7 @@ 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_arsg(self, args):
+ 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."""
result = []
@@ -157,25 +151,10 @@ why. As a hack filter out everything that is not a flag."""
''.format(self.confprog, var))
return o.strip()
- def found(self):
- return self.args is not None
-
- def get_version(self):
- return self.version
-
- def get_compile_args(self):
- if self.args is None:
- return []
- return self.args
-
- def get_link_args(self):
- return self.libs
-
-class QtBaseDependency(Dependency):
+class QtBaseDependency(ExternalDependency):
def __init__(self, name, env, kwargs):
- Dependency.__init__(self, name, kwargs)
- self.name = name
+ super().__init__(name, env, 'cpp', kwargs)
self.qtname = name.capitalize()
self.qtver = name[-1]
if self.qtver == "4":
@@ -184,16 +163,7 @@ class QtBaseDependency(Dependency):
self.qtpkgname = self.qtname
self.root = '/usr'
self.bindir = None
- self.silent = kwargs.get('silent', False)
- # We store the value of required here instead of passing it on to
- # PkgConfigDependency etc because we want to try the qmake-based
- # fallback as well.
- self.required = kwargs.pop('required', True)
- kwargs['required'] = False
mods = kwargs.get('modules', [])
- self.cargs = []
- self.largs = []
- self.is_found = False
if isinstance(mods, str):
mods = [mods]
if not mods:
@@ -207,16 +177,16 @@ class QtBaseDependency(Dependency):
methods = []
# Prefer pkg-config, then fallback to `qmake -query`
if DependencyMethods.PKGCONFIG in self.methods:
- self._pkgconfig_detect(mods, env, kwargs)
+ self._pkgconfig_detect(mods, kwargs)
methods.append('pkgconfig')
if not self.is_found and DependencyMethods.QMAKE in self.methods:
- from_text = self._qmake_detect(mods, env, kwargs)
+ from_text = self._qmake_detect(mods, kwargs)
methods.append('qmake-' + self.name)
methods.append('qmake')
if not self.is_found:
# Reset compile args and link args
- self.cargs = []
- self.largs = []
+ self.compile_args = []
+ self.link_args = []
from_text = '(checked {})'.format(mlog.format_list(methods))
self.version = 'none'
if self.required:
@@ -244,24 +214,27 @@ class QtBaseDependency(Dependency):
rcc = ExternalProgram('rcc-' + self.name, silent=True)
return moc, uic, rcc
- def _pkgconfig_detect(self, mods, env, kwargs):
+ def _pkgconfig_detect(self, mods, kwargs):
+ # We set the value of required to False so that we can try the
+ # qmake-based fallback if pkg-config fails.
+ kwargs['required'] = False
modules = OrderedDict()
for module in mods:
- modules[module] = PkgConfigDependency(self.qtpkgname + module, env, kwargs)
- self.is_found = True
+ modules[module] = PkgConfigDependency(self.qtpkgname + module, self.env, kwargs)
for m in modules.values():
if not m.found():
self.is_found = False
return
- self.cargs += m.get_compile_args()
- self.largs += m.get_link_args()
- self.version = m.modversion
+ self.compile_args += m.get_compile_args()
+ self.link_args += m.get_link_args()
+ self.is_found = True
+ self.version = m.version
# Try to detect moc, uic, rcc
if 'Core' in modules:
core = modules['Core']
else:
corekwargs = {'required': 'false', 'silent': 'true'}
- core = PkgConfigDependency(self.qtpkgname + 'Core', env, corekwargs)
+ core = PkgConfigDependency(self.qtpkgname + 'Core', self.env, corekwargs)
# Used by self.compilers_detect()
self.bindir = self.get_pkgconfig_host_bins(core)
if not self.bindir:
@@ -270,16 +243,16 @@ class QtBaseDependency(Dependency):
if prefix:
self.bindir = os.path.join(prefix, 'bin')
- def _find_qmake(self, qmake, env):
+ def _find_qmake(self, qmake):
# Even when cross-compiling, if we don't get a cross-info qmake, we
# fallback to using the qmake in PATH because that's what we used to do
- if env.is_cross_build():
- qmake = env.cross_info.config['binaries'].get('qmake', qmake)
+ if self.env.is_cross_build():
+ qmake = self.env.cross_info.config['binaries'].get('qmake', qmake)
return ExternalProgram(qmake, silent=True)
- def _qmake_detect(self, mods, env, kwargs):
+ def _qmake_detect(self, mods, kwargs):
for qmake in ('qmake-' + self.name, 'qmake'):
- self.qmake = self._find_qmake(qmake, env)
+ self.qmake = self._find_qmake(qmake)
if not self.qmake.found():
continue
# Check that the qmake is for qt5
@@ -293,6 +266,7 @@ class QtBaseDependency(Dependency):
break
else:
# Didn't find qmake :(
+ self.is_found = False
return
self.version = re.search(self.qtver + '(\.\d+)+', stdo).group(0)
# Query library path, header path, and binary path
@@ -308,15 +282,15 @@ class QtBaseDependency(Dependency):
if mesonlib.is_osx():
return self._framework_detect(qvars, mods, kwargs)
incdir = qvars['QT_INSTALL_HEADERS']
- self.cargs.append('-I' + incdir)
+ self.compile_args.append('-I' + incdir)
libdir = qvars['QT_INSTALL_LIBS']
# Used by self.compilers_detect()
self.bindir = self.get_qmake_host_bins(qvars)
self.is_found = True
for module in mods:
mincdir = os.path.join(incdir, 'Qt' + module)
- self.cargs.append('-I' + mincdir)
- if for_windows(env.is_cross_build(), env):
+ self.compile_args.append('-I' + mincdir)
+ if for_windows(self.env.is_cross_build(), self.env):
libfile = os.path.join(libdir, self.qtpkgname + module + '.lib')
if not os.path.isfile(libfile):
# MinGW can link directly to .dll
@@ -329,7 +303,7 @@ class QtBaseDependency(Dependency):
if not os.path.isfile(libfile):
self.is_found = False
break
- self.largs.append(libfile)
+ self.link_args.append(libfile)
return qmake
def _framework_detect(self, qvars, modules, kwargs):
@@ -340,8 +314,8 @@ class QtBaseDependency(Dependency):
self.cargs.append('-F' + libdir)
if fwdep.found():
self.is_found = True
- self.cargs += fwdep.get_compile_args()
- self.largs += fwdep.get_link_args()
+ self.compile_args += fwdep.get_compile_args()
+ self.link_args += fwdep.get_link_args()
# Used by self.compilers_detect()
self.bindir = self.get_qmake_host_bins(qvars)
@@ -353,24 +327,9 @@ class QtBaseDependency(Dependency):
else:
return qvars['QT_INSTALL_BINS']
- def get_version(self):
- return self.version
-
- def get_compile_args(self):
- return self.cargs
-
- def get_sources(self):
- return []
-
- def get_link_args(self):
- return self.largs
-
def get_methods(self):
return [DependencyMethods.PKGCONFIG, DependencyMethods.QMAKE]
- def found(self):
- return self.is_found
-
def get_exe_args(self, compiler):
# Originally this was -fPIE but nowadays the default
# for upstream and distros seems to be -reduce-relocations
@@ -408,20 +367,18 @@ class Qt5Dependency(QtBaseDependency):
# There are three different ways of depending on SDL2:
# sdl2-config, pkg-config and OSX framework
-class SDL2Dependency(Dependency):
+class SDL2Dependency(ExternalDependency):
def __init__(self, environment, kwargs):
- Dependency.__init__(self, 'sdl2', kwargs)
- self.is_found = False
- self.cargs = []
- self.linkargs = []
+ super().__init__('sdl2', environment, None, kwargs)
if DependencyMethods.PKGCONFIG in self.methods:
try:
+ kwargs['required'] = False
pcdep = PkgConfigDependency('sdl2', environment, kwargs)
if pcdep.found():
self.type_name = 'pkgconfig'
self.is_found = True
- self.cargs = pcdep.get_compile_args()
- self.linkargs = pcdep.get_link_args()
+ self.compile_args = pcdep.get_compile_args()
+ self.link_args = pcdep.get_link_args()
self.version = pcdep.get_version()
return
except Exception as e:
@@ -431,9 +388,9 @@ class SDL2Dependency(Dependency):
sdlconf = shutil.which('sdl2-config')
if sdlconf:
stdo = Popen_safe(['sdl2-config', '--cflags'])[1]
- self.cargs = stdo.strip().split()
+ self.compile_args = stdo.strip().split()
stdo = Popen_safe(['sdl2-config', '--libs'])[1]
- self.linkargs = stdo.strip().split()
+ self.link_args = stdo.strip().split()
stdo = Popen_safe(['sdl2-config', '--version'])[1]
self.version = stdo.strip()
self.is_found = True
@@ -443,27 +400,15 @@ class SDL2Dependency(Dependency):
mlog.debug('Could not find sdl2-config binary, trying next.')
if DependencyMethods.EXTRAFRAMEWORK in self.methods:
if mesonlib.is_osx():
- fwdep = ExtraFrameworkDependency('sdl2', kwargs.get('required', True), None, kwargs)
+ fwdep = ExtraFrameworkDependency('sdl2', False, None, kwargs)
if fwdep.found():
self.is_found = True
- self.cargs = fwdep.get_compile_args()
- self.linkargs = fwdep.get_link_args()
+ self.compile_args = fwdep.get_compile_args()
+ self.link_args = fwdep.get_link_args()
self.version = '2' # FIXME
return
mlog.log('Dependency', mlog.bold('sdl2'), 'found:', mlog.red('NO'))
- def get_compile_args(self):
- return self.cargs
-
- def get_link_args(self):
- return self.linkargs
-
- def found(self):
- return self.is_found
-
- def get_version(self):
- return self.version
-
def get_methods(self):
if mesonlib.is_osx():
return [DependencyMethods.PKGCONFIG, DependencyMethods.SDLCONFIG, DependencyMethods.EXTRAFRAMEWORK]
@@ -471,14 +416,12 @@ class SDL2Dependency(Dependency):
return [DependencyMethods.PKGCONFIG, DependencyMethods.SDLCONFIG]
-class WxDependency(Dependency):
+class WxDependency(ExternalDependency):
wx_found = None
def __init__(self, environment, kwargs):
- Dependency.__init__(self, 'wx', kwargs)
- self.is_found = False
- # FIXME: use version instead of modversion
- self.modversion = 'none'
+ super().__init__('wx', environment, None, kwargs)
+ self.version = 'none'
if WxDependency.wx_found is None:
self.check_wxconfig()
if not WxDependency.wx_found:
@@ -490,15 +433,14 @@ class WxDependency(Dependency):
p, out = Popen_safe([self.wxc, '--version'])[0:2]
if p.returncode != 0:
mlog.log('Dependency wxwidgets found:', mlog.red('NO'))
- self.cargs = []
- self.libs = []
else:
- self.modversion = out.strip()
+ 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.modversion, version_req, strict=True):
+ if not version_compare(self.version, version_req, strict=True):
mlog.log('Wxwidgets version %s does not fullfill requirement %s' %
- (self.modversion, version_req))
+ (self.version, version_req))
return
mlog.log('Dependency wxwidgets found:', mlog.green('YES'))
self.is_found = True
@@ -509,13 +451,13 @@ class WxDependency(Dependency):
# FIXME: this error should only be raised if required is true
if p.returncode != 0:
raise DependencyException('Could not generate cargs for wxwidgets.')
- self.cargs = out.split()
+ 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.libs = out.split()
+ self.link_args = out.split()
def get_requested(self, kwargs):
modules = 'modules'
@@ -529,18 +471,6 @@ class WxDependency(Dependency):
raise DependencyException('wxwidgets module argument is not a string.')
return candidates
- def get_modversion(self):
- return self.modversion
-
- def get_version(self):
- return self.modversion
-
- def get_compile_args(self):
- return self.cargs
-
- def get_link_args(self):
- return self.libs
-
def check_wxconfig(self):
for wxc in ['wx-config-3.0', 'wx-config']:
try:
@@ -555,6 +485,3 @@ class WxDependency(Dependency):
pass
WxDependency.wxconfig_found = False
mlog.log('Found wx-config:', mlog.red('NO'))
-
- def found(self):
- return self.is_found