From 7e2390f3558d05b3168dc57f2c2fe923b8ed12af Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 4 Oct 2016 09:45:41 -0300 Subject: [PATCH 1/3] interpreter: Add a type_name method to DependencyHolder And remove the InternalDependencyHolder class. In some cases we need to know the type of dependency we are dealing with. For example in GStreamer if the dependency is not an internal one, then we need to get some env var from pkg-config to know where to find some plugins necessary to run some tests. --- mesonbuild/dependencies.py | 40 +++++++++++-------- mesonbuild/interpreter.py | 24 +++++------ .../5 dependency versions/meson.build | 2 + 3 files changed, 34 insertions(+), 32 deletions(-) diff --git a/mesonbuild/dependencies.py b/mesonbuild/dependencies.py index 6a4c32c7a..d0c76632d 100644 --- a/mesonbuild/dependencies.py +++ b/mesonbuild/dependencies.py @@ -32,9 +32,10 @@ class DependencyException(MesonException): MesonException.__init__(self, *args, **kwargs) class Dependency(): - def __init__(self): + def __init__(self, type_name='unknown'): self.name = "null" self.is_found = False + self.type_name = type_name def get_compile_args(self): return [] @@ -59,9 +60,12 @@ class Dependency(): def need_threads(self): return False + def type_name(self): + return self.type_name + class InternalDependency(Dependency): def __init__(self, version, incdirs, compile_args, link_args, libraries, sources, ext_deps): - super().__init__() + super().__init__('internal') self.version = version self.include_directories = incdirs self.compile_args = compile_args @@ -83,7 +87,7 @@ class PkgConfigDependency(Dependency): pkgconfig_found = None def __init__(self, name, environment, kwargs): - Dependency.__init__(self) + Dependency.__init__(self, 'pkgconfig') self.is_libtool = False self.required = kwargs.get('required', True) self.static = kwargs.get('static', False) @@ -270,7 +274,7 @@ class WxDependency(Dependency): wx_found = None def __init__(self, environment, kwargs): - Dependency.__init__(self) + Dependency.__init__(self, 'wx') self.is_found = False if WxDependency.wx_found is None: self.check_wxconfig() @@ -445,7 +449,7 @@ class ExternalProgram(): class ExternalLibrary(Dependency): def __init__(self, name, link_args=None, silent=False): - super().__init__() + super().__init__('external') self.name = name # Rename fullpath to link_args once standalone find_library() gets removed. if link_args is not None: @@ -476,7 +480,7 @@ class BoostDependency(Dependency): name2lib = {'test' : 'unit_test_framework'} def __init__(self, environment, kwargs): - Dependency.__init__(self) + Dependency.__init__(self, 'boost') self.name = 'boost' self.environment = environment self.libdir = '' @@ -677,7 +681,7 @@ class BoostDependency(Dependency): class GTestDependency(Dependency): def __init__(self, environment, kwargs): - Dependency.__init__(self) + Dependency.__init__(self, 'gtest') self.main = kwargs.get('main', False) self.name = 'gtest' self.libname = 'libgtest.so' @@ -744,7 +748,7 @@ class GTestDependency(Dependency): class GMockDependency(Dependency): def __init__(self, environment, kwargs): - Dependency.__init__(self) + Dependency.__init__(self, 'gmock') # GMock may be a library or just source. # Work with both. self.name = 'gmock' @@ -798,7 +802,7 @@ class GMockDependency(Dependency): class Qt5Dependency(Dependency): def __init__(self, environment, kwargs): - Dependency.__init__(self) + Dependency.__init__(self, 'qt5') self.name = 'qt5' self.root = '/usr' mods = kwargs.get('modules', []) @@ -909,7 +913,7 @@ class Qt5Dependency(Dependency): class Qt4Dependency(Dependency): def __init__(self, environment, kwargs): - Dependency.__init__(self) + Dependency.__init__(self, 'qt4') self.name = 'qt4' self.root = '/usr' self.modules = [] @@ -947,7 +951,7 @@ class Qt4Dependency(Dependency): class GnuStepDependency(Dependency): def __init__(self, environment, kwargs): - Dependency.__init__(self) + Dependency.__init__(self, 'gnustep') self.modules = kwargs.get('modules', []) self.detect() @@ -1019,7 +1023,7 @@ why. As a hack filter out everything that is not a flag.""" class AppleFrameworks(Dependency): def __init__(self, environment, kwargs): - Dependency.__init__(self) + Dependency.__init__(self, 'appleframeworks') modules = kwargs.get('modules', []) if isinstance(modules, str): modules = [modules] @@ -1039,13 +1043,14 @@ class AppleFrameworks(Dependency): class GLDependency(Dependency): def __init__(self, environment, kwargs): - Dependency.__init__(self) + Dependency.__init__(self, 'gl') self.is_found = False self.cargs = [] self.linkargs = [] 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() @@ -1068,13 +1073,14 @@ class GLDependency(Dependency): # sdl2-config, pkg-config and OSX framework class SDL2Dependency(Dependency): def __init__(self, environment, kwargs): - Dependency.__init__(self) + Dependency.__init__(self, 'sdl2') self.is_found = False self.cargs = [] self.linkargs = [] try: 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() @@ -1124,7 +1130,7 @@ class SDL2Dependency(Dependency): class ExtraFrameworkDependency(Dependency): def __init__(self, name, required, path=None): - Dependency.__init__(self) + Dependency.__init__(self, 'extraframeworks') self.name = None self.detect(name, path) if self.found(): @@ -1165,7 +1171,7 @@ class ExtraFrameworkDependency(Dependency): class ThreadDependency(Dependency): def __init__(self, environment, kwargs): - super().__init__() + super().__init__('threads') self.name = 'threads' self.is_found = True mlog.log('Dependency', mlog.bold(self.name), 'found:', mlog.green('YES')) @@ -1175,7 +1181,7 @@ class ThreadDependency(Dependency): class Python3Dependency(Dependency): def __init__(self, environment, kwargs): - super().__init__() + super().__init__('python3') self.name = 'python3' self.is_found = False self.version = "3.something_maybe" diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index e486ee980..2a7ad6e77 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -278,27 +278,21 @@ class DependencyHolder(InterpreterObject): InterpreterObject.__init__(self) self.held_object = dep self.methods.update({'found' : self.found_method, + 'type_name': self.type_name_method, 'version': self.version_method}) + def type_name_method(self, args, kwargs): + return self.held_object.type_name + def found_method(self, args, kwargs): + if self.held_object.type_name == 'internal': + return True + return self.held_object.found() def version_method(self, args, kwargs): return self.held_object.get_version() -class InternalDependencyHolder(InterpreterObject): - def __init__(self, dep): - InterpreterObject.__init__(self) - self.held_object = dep - self.methods.update({'found' : self.found_method, - 'version': self.version_method, - }) - - def found_method(self, args, kwargs): - return True - - def version_method(self, args, kwargs): - return self.held_object.get_version() class ExternalProgramHolder(InterpreterObject): def __init__(self, ep): @@ -1394,7 +1388,7 @@ class Interpreter(): raise InterpreterException('Dependencies must be external deps') final_deps.append(d) dep = dependencies.InternalDependency(version, incs, compile_args, link_args, libs, sources, final_deps) - return InternalDependencyHolder(dep) + return DependencyHolder(dep) @noKwargs def func_assert(self, node, args, kwargs): @@ -1873,7 +1867,7 @@ class Interpreter(): dep = self.subprojects[dirname].get_variable_method([varname], {}) except KeyError: raise InterpreterException('Fallback variable {!r} in the subproject {!r} does not exist'.format(varname, dirname)) - if not isinstance(dep, (DependencyHolder, InternalDependencyHolder)): + if not isinstance(dep, DependencyHolder): raise InterpreterException('Fallback variable {!r} in the subproject {!r} is not a dependency object.'.format(varname, dirname)) # Check if the version of the declared dependency matches what we want if 'version' in kwargs: diff --git a/test cases/linuxlike/5 dependency versions/meson.build b/test cases/linuxlike/5 dependency versions/meson.build index a3ee33598..9bc264cf1 100644 --- a/test cases/linuxlike/5 dependency versions/meson.build +++ b/test cases/linuxlike/5 dependency versions/meson.build @@ -6,6 +6,7 @@ zlib = dependency('zlib') zlibver = dependency('zlib', version : '>1.0') assert(zlib.version() == zlibver.version(), 'zlib versions did not match!') # Find external dependency with conflicting version +assert(zlib.type_name() == 'pkgconfig', 'zlib should be of type "pkgconfig" not ' + zlib.type_name()) zlibver = dependency('zlib', version : '<1.0', required : false) assert(zlibver.found() == false, 'zlib <1.0 should not be found!') @@ -16,6 +17,7 @@ dependency('somebrokenlib', version : '>=1.0', required : false) # Find internal dependency without version somelibver = dependency('somelib', fallback : ['somelibnover', 'some_dep']) +assert(somelibver.type_name() == 'internal', 'somelibver should be of type "internal", not ' + somelibver.type_name()) # Find an internal dependency again with the same name and a specific version somelib = dependency('somelib', version : '== 0.1', From fcaf319e49aaaf548a814977c4c5e864fa5a4f77 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 4 Oct 2016 17:16:24 -0300 Subject: [PATCH 2/3] interpreter: Add a way to copy and environment object It is really usefull when you have common variables defined for all tests and then need to set some extra ones for each test --- mesonbuild/interpreter.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index 2a7ad6e77..28f56c8f1 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -27,6 +27,7 @@ import os, sys, subprocess, shutil, uuid, re from functools import wraps import importlib +import copy run_depr_printed = False @@ -188,6 +189,7 @@ class EnvironmentVariablesHolder(InterpreterObject): self.methods.update({'set': self.set_method, 'append': self.append_method, 'prepend' : self.prepend_method, + 'copy' : self.copy_method, }) @stringArgs @@ -210,6 +212,9 @@ class EnvironmentVariablesHolder(InterpreterObject): def prepend_method(self, args, kwargs): self.add_var(self.held_object.prepend, args, kwargs) + def copy_method(self, args, kwargs): + return copy.deepcopy(self) + class ConfigurationDataHolder(InterpreterObject): def __init__(self): From 77b379f5cf5f395257fdbbc56775dd906c5f2a3e Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 14 Oct 2016 11:06:56 +0200 Subject: [PATCH 3/3] Try using already setup fallback subprojects before using native dependency In the case the main project set a subproject for a dependency another subprojects uses, that other subproject should rather use the first subproject rather that using native dependency. For example in gst-all we set all GStreamer modules as subprojects and, gst-plugins-base is set after gstreamer core, and we want gst-plugins-base to always use GStreamer core from the subproject and not the possibly avalaible native one. --- mesonbuild/interpreter.py | 29 ++++++++++++++----- .../5 dependency versions/meson.build | 4 +++ .../subprojects/somelib/meson.build | 3 ++ 3 files changed, 29 insertions(+), 7 deletions(-) diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index 28f56c8f1..da96eb366 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -1834,11 +1834,23 @@ class Interpreter(): # We need to actually search for this dep exception = None dep = None - try: - dep = dependencies.find_external_dependency(name, self.environment, kwargs) - except dependencies.DependencyException as e: - exception = e - pass + # If the fallback has already been configured (possibly by a higher level project) + # try to use it before using the native version + if 'fallback' in kwargs: + dirname, varname = self.get_subproject_infos(kwargs) + if dirname in self.subprojects: + try: + dep = self.subprojects[dirname].get_variable_method([varname], {}) + dep = dep.held_object + except KeyError: + pass + + if not dep: + try: + dep = dependencies.find_external_dependency(name, self.environment, kwargs) + except dependencies.DependencyException as e: + exception = e + pass if not dep or not dep.found(): if 'fallback' in kwargs: @@ -1852,12 +1864,15 @@ class Interpreter(): self.coredata.deps[identifier] = dep return DependencyHolder(dep) - def dependency_fallback(self, name, kwargs): + def get_subproject_infos(self, kwargs): fbinfo = kwargs['fallback'] check_stringlist(fbinfo) if len(fbinfo) != 2: raise InterpreterException('Fallback info must have exactly two items.') - dirname, varname = fbinfo + return fbinfo + + def dependency_fallback(self, name, kwargs): + dirname, varname = self.get_subproject_infos(kwargs) try: self.do_subproject(dirname, {}) except: diff --git a/test cases/linuxlike/5 dependency versions/meson.build b/test cases/linuxlike/5 dependency versions/meson.build index 9bc264cf1..1de87c80a 100644 --- a/test cases/linuxlike/5 dependency versions/meson.build +++ b/test cases/linuxlike/5 dependency versions/meson.build @@ -32,3 +32,7 @@ somelibfail = dependency('somelib', required : false, fallback : ['somelibfail', 'some_dep']) assert(somelibfail.found() == false, 'somelibfail found via wrong fallback') + +fakezlib_dep = dependency('zlib', + fallback : ['somelib', 'fakezlib_dep']) +assert(fakezlib_dep.type_name() == 'internal', 'fakezlib_dep should be of type "internal", not ' + fakezlib_dep.type_name()) diff --git a/test cases/linuxlike/5 dependency versions/subprojects/somelib/meson.build b/test cases/linuxlike/5 dependency versions/subprojects/somelib/meson.build index 049c58b2d..086e514b9 100644 --- a/test cases/linuxlike/5 dependency versions/subprojects/somelib/meson.build +++ b/test cases/linuxlike/5 dependency versions/subprojects/somelib/meson.build @@ -6,3 +6,6 @@ someinc = include_directories('.') some_dep = declare_dependency(link_with : somelib, include_directories : someinc) + +fakezlib_dep = declare_dependency(link_with : somelib, + include_directories : someinc)