From bc63103ae02d8cca96ed9f4f130f0eca2d2abd4f Mon Sep 17 00:00:00 2001 From: Nirbheek Chauhan Date: Thu, 28 Jul 2016 21:01:49 +0530 Subject: [PATCH 1/4] pkg-config: Short-circuit when there's no pkg-config file found Just exit immediately when there's no pkg-config file found instead of putting everything else in a huge 'else:'. Much clearer and avoids one level of indentation. No code changes accompany this. --- mesonbuild/dependencies.py | 98 +++++++++++++++++++------------------- 1 file changed, 49 insertions(+), 49 deletions(-) diff --git a/mesonbuild/dependencies.py b/mesonbuild/dependencies.py index 2b777066d..a62973e96 100644 --- a/mesonbuild/dependencies.py +++ b/mesonbuild/dependencies.py @@ -122,56 +122,56 @@ class PkgConfigDependency(Dependency): if self.required: raise DependencyException('%s dependency %s not found.' % (self.type_string, name)) self.modversion = 'none' + return + self.modversion = out.decode().strip() + mlog.log('%s dependency' % self.type_string, mlog.bold(name), 'found:', + mlog.green('YES'), self.modversion) + self.version_requirement = kwargs.get('version', None) + if self.version_requirement is None: + self.is_found = True else: - self.modversion = out.decode().strip() - mlog.log('%s dependency' % self.type_string, mlog.bold(name), 'found:', - mlog.green('YES'), self.modversion) - self.version_requirement = kwargs.get('version', None) - if self.version_requirement is None: - self.is_found = True - else: - if not isinstance(self.version_requirement, str): - raise DependencyException('Version argument must be string.') - self.is_found = mesonlib.version_compare(self.modversion, self.version_requirement) - if not self.is_found and self.required: - raise DependencyException( - 'Invalid version of a dependency, needed %s %s found %s.' % - (name, self.version_requirement, self.modversion)) - if not self.is_found: - return - p = subprocess.Popen([pkgbin, '--cflags', name], stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - out = p.communicate()[0] - if p.returncode != 0: - raise DependencyException('Could not generate cargs for %s:\n\n%s' % \ - (name, out.decode(errors='ignore'))) - self.cargs = out.decode().split() - - libcmd = [pkgbin, '--libs'] - if self.static: - libcmd.append('--static') - p = subprocess.Popen(libcmd + [name], stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - out = p.communicate()[0] - if p.returncode != 0: - raise DependencyException('Could not generate libs for %s:\n\n%s' % \ - (name, out.decode(errors='ignore'))) - self.libs = [] - for lib in out.decode().split(): - if lib.endswith(".la"): - shared_libname = self.extract_libtool_shlib(lib) - shared_lib = os.path.join(os.path.dirname(lib), shared_libname) - if not os.path.exists(shared_lib): - shared_lib = os.path.join(os.path.dirname(lib), ".libs", shared_libname) - - if not os.path.exists(shared_lib): - raise DependencyException('Got a libtools specific "%s" dependencies' - 'but we could not compute the actual shared' - 'library path' % lib) - lib = shared_lib - self.is_libtool = True - - self.libs.append(lib) + if not isinstance(self.version_requirement, str): + raise DependencyException('Version argument must be string.') + self.is_found = mesonlib.version_compare(self.modversion, self.version_requirement) + if not self.is_found and self.required: + raise DependencyException( + 'Invalid version of a dependency, needed %s %s found %s.' % + (name, self.version_requirement, self.modversion)) + if not self.is_found: + return + p = subprocess.Popen([pkgbin, '--cflags', name], stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + out = p.communicate()[0] + if p.returncode != 0: + raise DependencyException('Could not generate cargs for %s:\n\n%s' % \ + (name, out.decode(errors='ignore'))) + self.cargs = out.decode().split() + + libcmd = [pkgbin, '--libs'] + if self.static: + libcmd.append('--static') + p = subprocess.Popen(libcmd + [name], stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + out = p.communicate()[0] + if p.returncode != 0: + raise DependencyException('Could not generate libs for %s:\n\n%s' % \ + (name, out.decode(errors='ignore'))) + self.libs = [] + for lib in out.decode().split(): + if lib.endswith(".la"): + shared_libname = self.extract_libtool_shlib(lib) + shared_lib = os.path.join(os.path.dirname(lib), shared_libname) + if not os.path.exists(shared_lib): + shared_lib = os.path.join(os.path.dirname(lib), ".libs", shared_libname) + + if not os.path.exists(shared_lib): + raise DependencyException('Got a libtools specific "%s" dependencies' + 'but we could not compute the actual shared' + 'library path' % lib) + lib = shared_lib + self.is_libtool = True + + self.libs.append(lib) def get_variable(self, variable_name): p = subprocess.Popen([self.pkgbin, '--variable=%s' % variable_name, self.name], From 48b4defa3781dac7bd9bf7988664c9de4f576a07 Mon Sep 17 00:00:00 2001 From: Nirbheek Chauhan Date: Thu, 28 Jul 2016 21:06:00 +0530 Subject: [PATCH 2/4] pkg-config: Move setting of cargs and libs to functions Much cleaner this way. It's completely clear what each block of code does. --- mesonbuild/dependencies.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/mesonbuild/dependencies.py b/mesonbuild/dependencies.py index a62973e96..bfcc42099 100644 --- a/mesonbuild/dependencies.py +++ b/mesonbuild/dependencies.py @@ -139,19 +139,26 @@ class PkgConfigDependency(Dependency): (name, self.version_requirement, self.modversion)) if not self.is_found: return - p = subprocess.Popen([pkgbin, '--cflags', name], stdout=subprocess.PIPE, - stderr=subprocess.PIPE) + # Fetch cargs to be used while using this dependency + self._set_cargs() + # Fetch the libraries and library paths needed for using this + self._set_libs() + + def _set_cargs(self): + p = subprocess.Popen([self.pkgbin, '--cflags', self.name], + stdout=subprocess.PIPE, stderr=subprocess.PIPE) out = p.communicate()[0] if p.returncode != 0: raise DependencyException('Could not generate cargs for %s:\n\n%s' % \ (name, out.decode(errors='ignore'))) self.cargs = out.decode().split() - libcmd = [pkgbin, '--libs'] + def _set_libs(self): + libcmd = [self.pkgbin, '--libs'] if self.static: libcmd.append('--static') - p = subprocess.Popen(libcmd + [name], stdout=subprocess.PIPE, - stderr=subprocess.PIPE) + p = subprocess.Popen(libcmd + [self.name], + stdout=subprocess.PIPE, stderr=subprocess.PIPE) out = p.communicate()[0] if p.returncode != 0: raise DependencyException('Could not generate libs for %s:\n\n%s' % \ @@ -170,7 +177,6 @@ class PkgConfigDependency(Dependency): 'library path' % lib) lib = shared_lib self.is_libtool = True - self.libs.append(lib) def get_variable(self, variable_name): From baf8481c4f8835b9c9bdaa6e82946ee123127394 Mon Sep 17 00:00:00 2001 From: Nirbheek Chauhan Date: Thu, 28 Jul 2016 21:11:34 +0530 Subject: [PATCH 3/4] pkg-config: Print 'NO' when version is too old This gives a clearer output when the dependency is not required or has a fallback subproject otherwise the user is left wondering why the optional dependency wasn't used or why the fallback subproject is being used. --- mesonbuild/dependencies.py | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/mesonbuild/dependencies.py b/mesonbuild/dependencies.py index bfcc42099..3f1e214df 100644 --- a/mesonbuild/dependencies.py +++ b/mesonbuild/dependencies.py @@ -124,8 +124,7 @@ class PkgConfigDependency(Dependency): self.modversion = 'none' return self.modversion = out.decode().strip() - mlog.log('%s dependency' % self.type_string, mlog.bold(name), 'found:', - mlog.green('YES'), self.modversion) + found_msg = ['%s dependency' % self.type_string, mlog.bold(name), 'found:'] self.version_requirement = kwargs.get('version', None) if self.version_requirement is None: self.is_found = True @@ -133,12 +132,17 @@ class PkgConfigDependency(Dependency): if not isinstance(self.version_requirement, str): raise DependencyException('Version argument must be string.') self.is_found = mesonlib.version_compare(self.modversion, self.version_requirement) - if not self.is_found and self.required: - raise DependencyException( - 'Invalid version of a dependency, needed %s %s found %s.' % - (name, self.version_requirement, self.modversion)) - if not self.is_found: - return + if not self.is_found: + found_msg += [mlog.red('NO'), 'found {!r}'.format(self.modversion), + 'but need {!r}'.format(self.version_requirement)] + mlog.log(*found_msg) + if self.required: + raise DependencyException( + 'Invalid version of a dependency, needed %s %s found %s.' % + (name, self.version_requirement, self.modversion)) + return + found_msg += [mlog.green('YES'), self.modversion] + mlog.log(*found_msg) # Fetch cargs to be used while using this dependency self._set_cargs() # Fetch the libraries and library paths needed for using this From 1459d186432e88e96d4fc959fa2ac36b756d82c9 Mon Sep 17 00:00:00 2001 From: Nirbheek Chauhan Date: Thu, 28 Jul 2016 21:45:45 +0530 Subject: [PATCH 4/4] dependency: Better errors when fallbacks are not found Otherwise the message is very cryptic and no one can figure out what Meson actually wants --- mesonbuild/interpreter.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index 51c40c900..72eebe7c8 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -1683,20 +1683,26 @@ class Interpreter(): dep = dependencies.find_external_dependency(name, self.environment, kwargs) except dependencies.DependencyException: if 'fallback' in kwargs: - dep = self.dependency_fallback(kwargs) + dep = self.dependency_fallback(name, kwargs) self.coredata.deps[identifier] = dep.held_object return dep raise self.coredata.deps[identifier] = dep return DependencyHolder(dep) - def dependency_fallback(self, kwargs): + def dependency_fallback(self, name, kwargs): fbinfo = kwargs['fallback'] check_stringlist(fbinfo) if len(fbinfo) != 2: raise InterpreterException('Fallback info must have exactly two items.') dirname, varname = fbinfo - self.do_subproject(dirname, {}) + try: + self.do_subproject(dirname, {}) + except: + mlog.log('Also couldn\'t find a fallback subproject in', + mlog.bold(os.path.join(self.subproject_dir, dirname)), + 'for the dependency', mlog.bold(name)) + raise dep = self.subprojects[dirname].get_variable_method([varname], {}) # Check if the version of the declared dependency matches what we want if 'version' in kwargs: @@ -1705,6 +1711,9 @@ class Interpreter(): if found == 'undefined' or not mesonlib.version_compare(found, wanted): m = 'Subproject "{0}" dependency "{1}" version is "{2}" but "{3}" is required.' raise InterpreterException(m.format(dirname, varname, found, wanted)) + mlog.log('Found a', mlog.green('fallback'), 'subproject', + mlog.bold(os.path.join(self.subproject_dir, dirname)), 'for', + mlog.bold(name)) return dep def func_executable(self, node, args, kwargs):