From 2ff37ae41a70631a2c7a857b53384799cff7cdb7 Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Wed, 13 Dec 2017 16:51:10 -0500 Subject: pkgconfig: Early abort tests if pkg-config is not present --- test cases/common/51 pkgconfig-gen/meson.build | 30 +++++++++++++++----------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/test cases/common/51 pkgconfig-gen/meson.build b/test cases/common/51 pkgconfig-gen/meson.build index 68ee812..e02f127 100644 --- a/test cases/common/51 pkgconfig-gen/meson.build +++ b/test cases/common/51 pkgconfig-gen/meson.build @@ -1,5 +1,17 @@ project('pkgconfig-gen', 'c') +# First check we have pkg-config >= 0.29 + +pkgconfig = find_program('pkg-config', required: false) +if not pkgconfig.found() + error('MESON_SKIP_TEST: pkg-config not found') +endif + +v = run_command(pkgconfig, '--version').stdout().strip() +if v.version_compare('<0.29') + error('MESON_SKIP_TEST: pkg-config version \'' + v + '\' too old') +endif + pkgg = import('pkgconfig') lib = shared_library('simple', 'simple.c') @@ -18,19 +30,11 @@ pkgg.generate( libraries_private : [lib, '-lz'], ) -pkgconfig = find_program('pkg-config', required: false) -if pkgconfig.found() - v = run_command(pkgconfig, '--version').stdout().strip() - if v.version_compare('>=0.29') - test('pkgconfig-validation', pkgconfig, - args: ['--validate', 'simple'], - env: ['PKG_CONFIG_PATH=' + meson.current_build_dir() + '/meson-private' ]) - else - message('pkg-config version \'' + v + '\' too old, skipping validate test') - endif -else - message('pkg-config not found, skipping validate test') -endif +pkgconfig_env = 'PKG_CONFIG_PATH=' + meson.current_build_dir() + '/meson-private' + +test('pkgconfig-validation', pkgconfig, + args: ['--validate', 'simple'], + env: [ pkgconfig_env ]) # Test that name_prefix='' and name='libfoo' results in '-lfoo' lib2 = shared_library('libfoo', 'simple.c', -- cgit v1.1 From 1c0570906c644df619ce463b9c3715dd492e1c8f Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Sun, 10 Dec 2017 17:54:28 -0500 Subject: pkgconfig: Allow passing Dependency objects to library(_private) Special case ThreadDependency by taking compiler's flags and PkgConfigDependency by adding them in requires(.private) instead. For other Dependency objects just take their link_args and compile_args. Closes #2725 --- mesonbuild/dependencies/misc.py | 5 + mesonbuild/dependencies/ui.py | 5 + mesonbuild/modules/pkgconfig.py | 127 ++++++++++++++++++------- test cases/common/51 pkgconfig-gen/meson.build | 62 ++++++++++++ 4 files changed, 167 insertions(+), 32 deletions(-) diff --git a/mesonbuild/dependencies/misc.py b/mesonbuild/dependencies/misc.py index 6ffa42a..e7eac1b 100644 --- a/mesonbuild/dependencies/misc.py +++ b/mesonbuild/dependencies/misc.py @@ -416,6 +416,7 @@ class MPIDependency(ExternalDependency): self.link_args = pkgdep.get_link_args() self.version = pkgdep.get_version() self.is_found = True + self.pcdep = pkgdep break except Exception: pass @@ -617,6 +618,7 @@ class Python3Dependency(ExternalDependency): self.link_args = self.pkgdep.get_link_args() self.version = self.pkgdep.get_version() self.is_found = True + self.pcdep = self.pkgdep return else: self.pkgdep = None @@ -750,6 +752,7 @@ class PcapDependency(ExternalDependency): self.compile_args = pcdep.get_compile_args() self.link_args = pcdep.get_link_args() self.version = pcdep.get_version() + self.pcdep = pcdep return except Exception as e: mlog.debug('Pcap not found via pkgconfig. Trying next, error was:', str(e)) @@ -792,6 +795,7 @@ class CupsDependency(ExternalDependency): self.compile_args = pcdep.get_compile_args() self.link_args = pcdep.get_link_args() self.version = pcdep.get_version() + self.pcdep = pcdep return except Exception as e: mlog.debug('cups not found via pkgconfig. Trying next, error was:', str(e)) @@ -841,6 +845,7 @@ class LibWmfDependency(ExternalDependency): self.compile_args = pcdep.get_compile_args() self.link_args = pcdep.get_link_args() self.version = pcdep.get_version() + self.pcdep = pcdep return except Exception as e: mlog.debug('LibWmf not found via pkgconfig. Trying next, error was:', str(e)) diff --git a/mesonbuild/dependencies/ui.py b/mesonbuild/dependencies/ui.py index 1db518c..c066c31 100644 --- a/mesonbuild/dependencies/ui.py +++ b/mesonbuild/dependencies/ui.py @@ -47,6 +47,7 @@ class GLDependency(ExternalDependency): self.compile_args = pcdep.get_compile_args() self.link_args = pcdep.get_link_args() self.version = pcdep.get_version() + self.pcdep = pcdep return except Exception: pass @@ -228,6 +229,7 @@ class QtBaseDependency(ExternalDependency): self.link_args += m.get_link_args() self.is_found = True self.version = m.version + self.pcdep = list(modules.values()) # Try to detect moc, uic, rcc if 'Core' in modules: core = modules['Core'] @@ -235,6 +237,7 @@ class QtBaseDependency(ExternalDependency): corekwargs = {'required': 'false', 'silent': 'true'} core = PkgConfigDependency(self.qtpkgname + 'Core', self.env, corekwargs, language=self.language) + self.pcdep.append(core) # Used by self.compilers_detect() self.bindir = self.get_pkgconfig_host_bins(core) if not self.bindir: @@ -387,6 +390,7 @@ class SDL2Dependency(ExternalDependency): self.compile_args = pcdep.get_compile_args() self.link_args = pcdep.get_link_args() self.version = pcdep.get_version() + self.pcdep = pcdep return except Exception as e: mlog.debug('SDL 2 not found via pkgconfig. Trying next, error was:', str(e)) @@ -461,6 +465,7 @@ class VulkanDependency(ExternalDependency): self.compile_args = pcdep.get_compile_args() self.link_args = pcdep.get_link_args() self.version = pcdep.get_version() + self.pcdep = pcdep return except Exception: pass diff --git a/mesonbuild/modules/pkgconfig.py b/mesonbuild/modules/pkgconfig.py index f963323..7a54a84 100644 --- a/mesonbuild/modules/pkgconfig.py +++ b/mesonbuild/modules/pkgconfig.py @@ -16,12 +16,82 @@ import os from pathlib import PurePath from .. import build +from .. import dependencies from .. import mesonlib from .. import mlog from . import ModuleReturnValue from . import ExtensionModule from ..interpreterbase import permittedKwargs +class DepsHolder: + def __init__(self): + self.pub_libs = [] + self.pub_reqs = [] + self.priv_libs = [] + self.priv_reqs = [] + self.cflags = [] + + def add_pub_libs(self, libs): + libs, reqs, cflags = self._process_libs(libs, True) + self.pub_libs += libs + self.pub_reqs += reqs + self.cflags += cflags + + def add_priv_libs(self, libs): + libs, reqs, _ = self._process_libs(libs, False) + self.priv_libs += libs + self.priv_reqs += reqs + + def add_pub_reqs(self, reqs): + self.pub_reqs += mesonlib.stringlistify(reqs) + + def add_priv_reqs(self, reqs): + self.priv_reqs += mesonlib.stringlistify(reqs) + + def add_cflags(self, cflags): + self.cflags += mesonlib.stringlistify(cflags) + + def _process_libs(self, libs, public): + libs = mesonlib.listify(libs) + processed_libs = [] + processed_reqs = [] + processed_cflags = [] + for obj in libs: + if hasattr(obj, 'held_object'): + obj = obj.held_object + if hasattr(obj, 'pcdep'): + pcdeps = mesonlib.listify(obj.pcdep) + processed_reqs += [i.name for i in pcdeps] + elif isinstance(obj, dependencies.PkgConfigDependency): + processed_reqs.append(obj.name) + elif isinstance(obj, dependencies.ThreadDependency): + processed_libs += obj.get_compiler().thread_link_flags(obj.env) + processed_cflags += obj.get_compiler().thread_flags(obj.env) + elif isinstance(obj, dependencies.Dependency): + processed_libs += obj.get_link_args() + processed_cflags += obj.get_compile_args() + elif isinstance(obj, (build.SharedLibrary, build.StaticLibrary)): + processed_libs.append(obj) + if public: + self.add_priv_libs(obj.get_dependencies()) + self.add_priv_libs(obj.get_external_deps()) + elif isinstance(obj, str): + processed_libs.append(obj) + else: + raise mesonlib.MesonException('library argument not a string, library or dependency object.') + + return processed_libs, processed_reqs, processed_cflags + + def remove_dups(self): + self.pub_libs = list(set(self.pub_libs)) + self.pub_reqs = list(set(self.pub_reqs)) + self.priv_libs = list(set(self.priv_libs)) + self.priv_reqs = list(set(self.priv_reqs)) + self.cflags = list(set(self.cflags)) + + # Remove from pivate libs/reqs if they are in public already + self.priv_libs = [i for i in self.priv_libs if i not in self.pub_libs] + self.priv_reqs = [i for i in self.priv_reqs if i not in self.pub_reqs] class PkgConfigModule(ExtensionModule): @@ -64,9 +134,9 @@ class PkgConfigModule(ExtensionModule): subdir = subdir.replace(prefix, '') return subdir - def generate_pkgconfig_file(self, state, libraries, subdirs, name, description, - url, version, pcfile, pub_reqs, priv_reqs, - conflicts, priv_libs, extra_cflags, variables): + def generate_pkgconfig_file(self, state, deps, subdirs, name, description, + url, version, pcfile, conflicts, variables): + deps.remove_dups() coredata = state.environment.get_coredata() outdir = state.environment.scratch_dir fname = os.path.join(outdir, pcfile) @@ -78,6 +148,8 @@ class PkgConfigModule(ExtensionModule): ofile.write('prefix={}\n'.format(self._escape(prefix))) ofile.write('libdir={}\n'.format(self._escape('${prefix}' / libdir))) ofile.write('includedir={}\n'.format(self._escape('${prefix}' / incdir))) + if variables: + ofile.write('\n') for k, v in variables: ofile.write('{}={}\n'.format(k, self._escape(v))) ofile.write('\n') @@ -87,11 +159,11 @@ class PkgConfigModule(ExtensionModule): if len(url) > 0: ofile.write('URL: %s\n' % url) ofile.write('Version: %s\n' % version) - if len(pub_reqs) > 0: - ofile.write('Requires: {}\n'.format(' '.join(pub_reqs))) - if len(priv_reqs) > 0: + if len(deps.pub_reqs) > 0: + ofile.write('Requires: {}\n'.format(' '.join(deps.pub_reqs))) + if len(deps.priv_reqs) > 0: ofile.write( - 'Requires.private: {}\n'.format(' '.join(priv_reqs))) + 'Requires.private: {}\n'.format(' '.join(deps.priv_reqs))) if len(conflicts) > 0: ofile.write('Conflicts: {}\n'.format(' '.join(conflicts))) @@ -117,10 +189,10 @@ class PkgConfigModule(ExtensionModule): mlog.warning(msg.format(l.name, 'name_suffix', lname, pcfile)) yield '-l%s' % lname - if len(libraries) > 0: - ofile.write('Libs: {}\n'.format(' '.join(generate_libs_flags(libraries)))) - if len(priv_libs) > 0: - ofile.write('Libs.private: {}\n'.format(' '.join(generate_libs_flags(priv_libs)))) + if len(deps.pub_libs) > 0: + ofile.write('Libs: {}\n'.format(' '.join(generate_libs_flags(deps.pub_libs)))) + if len(deps.priv_libs) > 0: + ofile.write('Libs.private: {}\n'.format(' '.join(generate_libs_flags(deps.priv_libs)))) ofile.write('Cflags:') for h in subdirs: ofile.write(' ') @@ -128,30 +200,25 @@ class PkgConfigModule(ExtensionModule): ofile.write('-I${includedir}') else: ofile.write(self._escape(PurePath('-I${includedir}') / h)) - for f in extra_cflags: + for f in deps.cflags: ofile.write(' ') ofile.write(self._escape(f)) ofile.write('\n') - def process_libs(self, libs): - libs = mesonlib.listify(libs) - processed_libs = [] - for l in libs: - if hasattr(l, 'held_object'): - l = l.held_object - if not isinstance(l, (build.SharedLibrary, build.StaticLibrary, str)): - raise mesonlib.MesonException('Library argument not a library object nor a string.') - processed_libs.append(l) - return processed_libs - @permittedKwargs({'libraries', 'version', 'name', 'description', 'filebase', 'subdirs', 'requires', 'requires_private', 'libraries_private', 'install_dir', 'extra_cflags', 'variables', 'url', 'd_module_versions'}) def generate(self, state, args, kwargs): if len(args) > 0: raise mesonlib.MesonException('Pkgconfig_gen takes no positional arguments.') - libs = self.process_libs(kwargs.get('libraries', [])) - priv_libs = self.process_libs(kwargs.get('libraries_private', [])) + + deps = DepsHolder() + deps.add_pub_libs(kwargs.get('libraries', [])) + deps.add_priv_libs(kwargs.get('libraries_private', [])) + deps.add_pub_reqs(kwargs.get('requires', [])) + deps.add_priv_reqs(kwargs.get('requires_private', [])) + deps.add_cflags(kwargs.get('extra_cflags', [])) + subdirs = mesonlib.stringlistify(kwargs.get('subdirs', ['.'])) version = kwargs.get('version', None) if not isinstance(version, str): @@ -168,16 +235,13 @@ class PkgConfigModule(ExtensionModule): url = kwargs.get('url', '') if not isinstance(url, str): raise mesonlib.MesonException('URL is not a string.') - pub_reqs = mesonlib.stringlistify(kwargs.get('requires', [])) - priv_reqs = mesonlib.stringlistify(kwargs.get('requires_private', [])) conflicts = mesonlib.stringlistify(kwargs.get('conflicts', [])) - extra_cflags = mesonlib.stringlistify(kwargs.get('extra_cflags', [])) dversions = kwargs.get('d_module_versions', None) if dversions: compiler = state.environment.coredata.compilers.get('d') if compiler: - extra_cflags.extend(compiler.get_feature_args({'versions': dversions})) + deps.add_cflags(compiler.get_feature_args({'versions': dversions})) def parse_variable_list(stringlist): reserved = ['prefix', 'libdir', 'includedir'] @@ -211,9 +275,8 @@ class PkgConfigModule(ExtensionModule): pkgroot = os.path.join(state.environment.coredata.get_builtin_option('libdir'), 'pkgconfig') if not isinstance(pkgroot, str): raise mesonlib.MesonException('Install_dir must be a string.') - self.generate_pkgconfig_file(state, libs, subdirs, name, description, url, - version, pcfile, pub_reqs, priv_reqs, - conflicts, priv_libs, extra_cflags, variables) + self.generate_pkgconfig_file(state, deps, subdirs, name, description, url, + version, pcfile, conflicts, variables) res = build.Data(mesonlib.File(True, state.environment.get_scratch_dir(), pcfile), pkgroot) return ModuleReturnValue(res, [res]) diff --git a/test cases/common/51 pkgconfig-gen/meson.build b/test cases/common/51 pkgconfig-gen/meson.build index e02f127..dbe9100 100644 --- a/test cases/common/51 pkgconfig-gen/meson.build +++ b/test cases/common/51 pkgconfig-gen/meson.build @@ -12,6 +12,11 @@ if v.version_compare('<0.29') error('MESON_SKIP_TEST: pkg-config version \'' + v + '\' too old') endif +envcmd = find_program('env', required: false) +if not envcmd.found() + error('MESON_SKIP_TEST: env command not found') +endif + pkgg = import('pkgconfig') lib = shared_library('simple', 'simple.c') @@ -48,3 +53,60 @@ pkgg.generate( description : 'A foo library.', variables : ['foo=bar', 'datadir=${prefix}/data'] ) + +# libmain internally use libinternal and expose libexpose in its API +exposed_lib = shared_library('libexposed', 'simple.c') +internal_lib = shared_library('libinternal', 'simple.c') +main_lib = shared_library('libmain', link_with : [exposed_lib, internal_lib]) + +# Declare a few different Dependency objects +pc_dep = dependency('libfoo', required : false) +threads_dep = dependency('threads', required : false) +custom_dep = declare_dependency(link_args : ['-lcustom'], compile_args : ['-DCUSTOM']) +custom2_dep = declare_dependency(link_args : ['-lcustom2'], compile_args : ['-DCUSTOM2']) + +# Generate a PC file: +# - Having libmain in libraries should pull implicitely libexposed and libinternal in Libs.private +# - Having libexposed in libraries should remove it from Libs.private +# - Having threads_dep in libraries should add '-pthread' in both Libs and Cflags +# - Having custom_dep in libraries and libraries_private should only add it in Libs +# - Having custom2_dep in libraries_private should not add its Cflags +# - Having pc_dep in libraries_private should add it in Requires.private +pkgg.generate(libraries : [main_lib, exposed_lib, threads_dep , custom_dep], + libraries_private : [custom_dep, custom2_dep, pc_dep], + version : libver, + name : 'dependency-test', + filebase : 'dependency-test', + description : 'A dependency test.' +) + +msg = 'Generated pc file doesn\'t have expected @0@: @1@' + +out = run_command(envcmd, '-', pkgconfig_env, pkgconfig, 'dependency-test', '--print-requires').stdout().strip().split() +assert(out.length() == 0, msg.format('requires', out)) + +out = run_command(envcmd, '-', pkgconfig_env, pkgconfig, 'dependency-test', '--print-requires-private').stdout().strip().split() +assert(out.contains('libfoo'), msg.format('requires.private', out)) +assert(out.length() == 1, msg.format('requires.private', out)) + +out = run_command(envcmd, '-', pkgconfig_env, pkgconfig, 'dependency-test', '--cflags-only-other').stdout().strip().split() +assert(out.contains('-pthread'), msg.format('cflags', out)) +assert(out.contains('-DCUSTOM'), msg.format('cflags', out)) +assert(out.length() == 2, msg.format('cflags', out)) + +out = run_command(envcmd, '-', pkgconfig_env, pkgconfig, 'dependency-test', '--libs-only-l', '--libs-only-other').stdout().strip().split() +assert(out.contains('-llibexposed'), msg.format('libs', out)) +assert(out.contains('-pthread'), msg.format('libs', out)) +assert(out.contains('-lcustom'), msg.format('libs', out)) +assert(out.contains('-llibmain'), msg.format('libs', out)) +assert(out.length() == 4, msg.format('libs', out)) + +out = run_command(envcmd, '-', pkgconfig_env, pkgconfig, 'dependency-test', '--libs-only-l', '--libs-only-other', '--static').stdout().strip().split() +assert(out.contains('-llibexposed'), msg.format('libs.private', out)) +assert(out.contains('-pthread'), msg.format('libs.private', out)) +assert(out.contains('-lcustom'), msg.format('libs.private', out)) +assert(out.contains('-llibmain'), msg.format('libs.private', out)) +assert(out.contains('-llibinternal'), msg.format('libs.private', out)) +assert(out.contains('-lcustom2'), msg.format('libs.private', out)) +assert(out.contains('-lfoo'), msg.format('libs.private', out)) +assert(out.length() == 7, msg.format('libs.private', out)) -- cgit v1.1 From 9e541a0fff9b2f345fc76d807a2c99555394930f Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Thu, 14 Dec 2017 09:49:23 -0500 Subject: pkgconfig: Avoid duplicated -L flags --- mesonbuild/modules/pkgconfig.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/mesonbuild/modules/pkgconfig.py b/mesonbuild/modules/pkgconfig.py index 7a54a84..44add61 100644 --- a/mesonbuild/modules/pkgconfig.py +++ b/mesonbuild/modules/pkgconfig.py @@ -171,6 +171,7 @@ class PkgConfigModule(ExtensionModule): msg = 'Library target {0!r} has {1!r} set. Compilers ' \ 'may not find it from its \'-l{2}\' linker flag in the ' \ '{3!r} pkg-config file.' + Lflags = [] for l in libs: if isinstance(l, str): yield l @@ -179,9 +180,12 @@ class PkgConfigModule(ExtensionModule): if install_dir is False: continue if isinstance(install_dir, str): - yield '-L${prefix}/%s ' % self._escape(self._make_relative(prefix, install_dir)) + Lflag = '-L${prefix}/%s ' % self._escape(self._make_relative(prefix, install_dir)) else: # install_dir is True - yield '-L${libdir}' + Lflag = '-L${libdir}' + if Lflag not in Lflags: + Lflags.append(Lflag) + yield Lflag lname = self._get_lname(l, msg, pcfile) # If using a custom suffix, the compiler may not be able to # find the library -- cgit v1.1 From 49977686b57685decfeda726958c33610710eb2e Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Thu, 14 Dec 2017 11:13:37 -0500 Subject: pkgconfig: Use the pc file we generated for libraries --- mesonbuild/modules/pkgconfig.py | 21 +++++++++++++-------- test cases/common/51 pkgconfig-gen/meson.build | 12 +++++++++--- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/mesonbuild/modules/pkgconfig.py b/mesonbuild/modules/pkgconfig.py index 44add61..c938d42 100644 --- a/mesonbuild/modules/pkgconfig.py +++ b/mesonbuild/modules/pkgconfig.py @@ -24,7 +24,8 @@ from . import ExtensionModule from ..interpreterbase import permittedKwargs class DepsHolder: - def __init__(self): + def __init__(self, name): + self.name = name self.pub_libs = [] self.pub_reqs = [] self.priv_libs = [] @@ -62,6 +63,8 @@ class DepsHolder: if hasattr(obj, 'pcdep'): pcdeps = mesonlib.listify(obj.pcdep) processed_reqs += [i.name for i in pcdeps] + elif hasattr(obj, 'generated_pc'): + processed_reqs.append(obj.generated_pc) elif isinstance(obj, dependencies.PkgConfigDependency): processed_reqs.append(obj.name) elif isinstance(obj, dependencies.ThreadDependency): @@ -73,6 +76,8 @@ class DepsHolder: elif isinstance(obj, (build.SharedLibrary, build.StaticLibrary)): processed_libs.append(obj) if public: + if not hasattr(obj, 'generated_pc'): + obj.generated_pc = self.name self.add_priv_libs(obj.get_dependencies()) self.add_priv_libs(obj.get_external_deps()) elif isinstance(obj, str): @@ -216,13 +221,6 @@ class PkgConfigModule(ExtensionModule): if len(args) > 0: raise mesonlib.MesonException('Pkgconfig_gen takes no positional arguments.') - deps = DepsHolder() - deps.add_pub_libs(kwargs.get('libraries', [])) - deps.add_priv_libs(kwargs.get('libraries_private', [])) - deps.add_pub_reqs(kwargs.get('requires', [])) - deps.add_priv_reqs(kwargs.get('requires_private', [])) - deps.add_cflags(kwargs.get('extra_cflags', [])) - subdirs = mesonlib.stringlistify(kwargs.get('subdirs', ['.'])) version = kwargs.get('version', None) if not isinstance(version, str): @@ -241,6 +239,13 @@ class PkgConfigModule(ExtensionModule): raise mesonlib.MesonException('URL is not a string.') conflicts = mesonlib.stringlistify(kwargs.get('conflicts', [])) + deps = DepsHolder(filebase) + deps.add_pub_libs(kwargs.get('libraries', [])) + deps.add_priv_libs(kwargs.get('libraries_private', [])) + deps.add_pub_reqs(kwargs.get('requires', [])) + deps.add_priv_reqs(kwargs.get('requires_private', [])) + deps.add_cflags(kwargs.get('extra_cflags', [])) + dversions = kwargs.get('d_module_versions', None) if dversions: compiler = state.environment.coredata.compilers.get('d') diff --git a/test cases/common/51 pkgconfig-gen/meson.build b/test cases/common/51 pkgconfig-gen/meson.build index dbe9100..45e3ed7 100644 --- a/test cases/common/51 pkgconfig-gen/meson.build +++ b/test cases/common/51 pkgconfig-gen/meson.build @@ -59,6 +59,12 @@ exposed_lib = shared_library('libexposed', 'simple.c') internal_lib = shared_library('libinternal', 'simple.c') main_lib = shared_library('libmain', link_with : [exposed_lib, internal_lib]) +pkgg.generate(libraries : exposed_lib, + version : libver, + name : 'libexposed', + description : 'An exposed library in dependency test.' +) + # Declare a few different Dependency objects pc_dep = dependency('libfoo', required : false) threads_dep = dependency('threads', required : false) @@ -68,6 +74,7 @@ custom2_dep = declare_dependency(link_args : ['-lcustom2'], compile_args : ['-DC # Generate a PC file: # - Having libmain in libraries should pull implicitely libexposed and libinternal in Libs.private # - Having libexposed in libraries should remove it from Libs.private +# - We generated a pc file for libexposed so it should be in Requires instead of Libs # - Having threads_dep in libraries should add '-pthread' in both Libs and Cflags # - Having custom_dep in libraries and libraries_private should only add it in Libs # - Having custom2_dep in libraries_private should not add its Cflags @@ -83,7 +90,8 @@ pkgg.generate(libraries : [main_lib, exposed_lib, threads_dep , custom_dep], msg = 'Generated pc file doesn\'t have expected @0@: @1@' out = run_command(envcmd, '-', pkgconfig_env, pkgconfig, 'dependency-test', '--print-requires').stdout().strip().split() -assert(out.length() == 0, msg.format('requires', out)) +assert(out.contains('libexposed'), msg.format('requires', out)) +assert(out.length() == 1, msg.format('requires', out)) out = run_command(envcmd, '-', pkgconfig_env, pkgconfig, 'dependency-test', '--print-requires-private').stdout().strip().split() assert(out.contains('libfoo'), msg.format('requires.private', out)) @@ -95,14 +103,12 @@ assert(out.contains('-DCUSTOM'), msg.format('cflags', out)) assert(out.length() == 2, msg.format('cflags', out)) out = run_command(envcmd, '-', pkgconfig_env, pkgconfig, 'dependency-test', '--libs-only-l', '--libs-only-other').stdout().strip().split() -assert(out.contains('-llibexposed'), msg.format('libs', out)) assert(out.contains('-pthread'), msg.format('libs', out)) assert(out.contains('-lcustom'), msg.format('libs', out)) assert(out.contains('-llibmain'), msg.format('libs', out)) assert(out.length() == 4, msg.format('libs', out)) out = run_command(envcmd, '-', pkgconfig_env, pkgconfig, 'dependency-test', '--libs-only-l', '--libs-only-other', '--static').stdout().strip().split() -assert(out.contains('-llibexposed'), msg.format('libs.private', out)) assert(out.contains('-pthread'), msg.format('libs.private', out)) assert(out.contains('-lcustom'), msg.format('libs.private', out)) assert(out.contains('-llibmain'), msg.format('libs.private', out)) -- cgit v1.1 From f9c9e80d4a1b351985a6c6d5e2a56e0686a98592 Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Thu, 14 Dec 2017 14:33:28 -0500 Subject: pkgconfig: Update documentation --- docs/markdown/Pkgconfig-module.md | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/docs/markdown/Pkgconfig-module.md b/docs/markdown/Pkgconfig-module.md index 7f767f1..cbe01b4 100644 --- a/docs/markdown/Pkgconfig-module.md +++ b/docs/markdown/Pkgconfig-module.md @@ -23,9 +23,16 @@ keyword arguments. - `install_dir` the directory to install to, defaults to the value of option `libdir` followed by `/pkgconfig` - `libraries` a list of built libraries (usually results of - shared_library) that the user needs to link against -- `libraries_private` list of strings to put in the - `Libraries.private` field + shared_library) that the user needs to link against. Arbitraty strings can + also be provided and they will be added into the `Libs` field. Since 0.45.0 + dependencies of built libraries will be automatically added to `Libs.private` + field. If a dependency is provided by pkg-config then it will be added in + `Requires.private` instead. Other type of dependency objects can also be passed + and will result in their `link_args` and `compile_args` to be added to `Libs` + and `Cflags` fields. +- `libraries_private` list of built libraries or strings to put in the + `Libs.private` field. Since 0.45.0 it can also contain dependency objects, + their `link_args` will be added to `Libs.private`. - `name` the name of this library - `subdirs` which subdirs of `include` should be added to the header search path, for example if you install headers into -- cgit v1.1 From 2881db7379506efbd110363cf9d77c94c4c6426a Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Sat, 16 Dec 2017 09:50:11 -0500 Subject: pkgconfig: Move pc file checks to run_unittests.py --- run_unittests.py | 30 ++++++++++++++++++++ test cases/common/51 pkgconfig-gen/meson.build | 39 +------------------------- 2 files changed, 31 insertions(+), 38 deletions(-) diff --git a/run_unittests.py b/run_unittests.py index d7d5ed0..acf029f 100755 --- a/run_unittests.py +++ b/run_unittests.py @@ -1912,6 +1912,36 @@ class LinuxlikeTests(BasePlatformTests): self.assertEqual(foo_dep.get_pkgconfig_variable('foo', {}), 'bar') self.assertPathEqual(foo_dep.get_pkgconfig_variable('datadir', {}), '/usr/data') + def test_pkgconfig_gen_deps(self): + ''' + Test that generated pkg-config files correctly handle dependencies + ''' + + testdir = os.path.join(self.common_test_dir, '51 pkgconfig-gen') + self.init(testdir) + + os.environ['PKG_CONFIG_LIBDIR'] = self.privatedir + cmd = ['pkg-config', 'dependency-test'] + + out = self._run(cmd + ['--print-requires']).strip().split() + self.assertEqual(sorted(out), sorted(['libexposed'])) + + out = self._run(cmd + ['--print-requires-private']).strip().split() + self.assertEqual(sorted(out), sorted(['libfoo'])) + + out = self._run(cmd + ['--cflags-only-other']).strip().split() + self.assertEqual(sorted(out), sorted(['-pthread', '-DCUSTOM'])) + + out = self._run(cmd + ['--libs-only-l', '--libs-only-other']).strip().split() + self.assertEqual(sorted(out), sorted(['-pthread', '-lcustom', + '-llibmain', '-llibexposed'])) + + out = self._run(cmd + ['--libs-only-l', '--libs-only-other', '--static']).strip().split() + self.assertEqual(sorted(out), sorted(['-pthread', '-lcustom', + '-llibmain', '-llibexposed', + '-llibinternal', '-lcustom2', + '-lfoo'])) + def test_vala_c_warnings(self): ''' Test that no warnings are emitted for C code generated by Vala. This diff --git a/test cases/common/51 pkgconfig-gen/meson.build b/test cases/common/51 pkgconfig-gen/meson.build index 45e3ed7..a8dd092 100644 --- a/test cases/common/51 pkgconfig-gen/meson.build +++ b/test cases/common/51 pkgconfig-gen/meson.build @@ -12,11 +12,6 @@ if v.version_compare('<0.29') error('MESON_SKIP_TEST: pkg-config version \'' + v + '\' too old') endif -envcmd = find_program('env', required: false) -if not envcmd.found() - error('MESON_SKIP_TEST: env command not found') -endif - pkgg = import('pkgconfig') lib = shared_library('simple', 'simple.c') @@ -35,11 +30,9 @@ pkgg.generate( libraries_private : [lib, '-lz'], ) -pkgconfig_env = 'PKG_CONFIG_PATH=' + meson.current_build_dir() + '/meson-private' - test('pkgconfig-validation', pkgconfig, args: ['--validate', 'simple'], - env: [ pkgconfig_env ]) + env: [ 'PKG_CONFIG_PATH=' + meson.current_build_dir() + '/meson-private' ]) # Test that name_prefix='' and name='libfoo' results in '-lfoo' lib2 = shared_library('libfoo', 'simple.c', @@ -86,33 +79,3 @@ pkgg.generate(libraries : [main_lib, exposed_lib, threads_dep , custom_dep], filebase : 'dependency-test', description : 'A dependency test.' ) - -msg = 'Generated pc file doesn\'t have expected @0@: @1@' - -out = run_command(envcmd, '-', pkgconfig_env, pkgconfig, 'dependency-test', '--print-requires').stdout().strip().split() -assert(out.contains('libexposed'), msg.format('requires', out)) -assert(out.length() == 1, msg.format('requires', out)) - -out = run_command(envcmd, '-', pkgconfig_env, pkgconfig, 'dependency-test', '--print-requires-private').stdout().strip().split() -assert(out.contains('libfoo'), msg.format('requires.private', out)) -assert(out.length() == 1, msg.format('requires.private', out)) - -out = run_command(envcmd, '-', pkgconfig_env, pkgconfig, 'dependency-test', '--cflags-only-other').stdout().strip().split() -assert(out.contains('-pthread'), msg.format('cflags', out)) -assert(out.contains('-DCUSTOM'), msg.format('cflags', out)) -assert(out.length() == 2, msg.format('cflags', out)) - -out = run_command(envcmd, '-', pkgconfig_env, pkgconfig, 'dependency-test', '--libs-only-l', '--libs-only-other').stdout().strip().split() -assert(out.contains('-pthread'), msg.format('libs', out)) -assert(out.contains('-lcustom'), msg.format('libs', out)) -assert(out.contains('-llibmain'), msg.format('libs', out)) -assert(out.length() == 4, msg.format('libs', out)) - -out = run_command(envcmd, '-', pkgconfig_env, pkgconfig, 'dependency-test', '--libs-only-l', '--libs-only-other', '--static').stdout().strip().split() -assert(out.contains('-pthread'), msg.format('libs.private', out)) -assert(out.contains('-lcustom'), msg.format('libs.private', out)) -assert(out.contains('-llibmain'), msg.format('libs.private', out)) -assert(out.contains('-llibinternal'), msg.format('libs.private', out)) -assert(out.contains('-lcustom2'), msg.format('libs.private', out)) -assert(out.contains('-lfoo'), msg.format('libs.private', out)) -assert(out.length() == 7, msg.format('libs.private', out)) -- cgit v1.1 From 68eedc8b7157190a010d31bea81f13f91144ea75 Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Thu, 21 Dec 2017 16:44:42 -0500 Subject: pkgconfig: Rename DepsHolder to DependenciesHelper --- mesonbuild/modules/pkgconfig.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mesonbuild/modules/pkgconfig.py b/mesonbuild/modules/pkgconfig.py index c938d42..54c2126 100644 --- a/mesonbuild/modules/pkgconfig.py +++ b/mesonbuild/modules/pkgconfig.py @@ -23,7 +23,7 @@ from . import ModuleReturnValue from . import ExtensionModule from ..interpreterbase import permittedKwargs -class DepsHolder: +class DependenciesHelper: def __init__(self, name): self.name = name self.pub_libs = [] @@ -239,7 +239,7 @@ class PkgConfigModule(ExtensionModule): raise mesonlib.MesonException('URL is not a string.') conflicts = mesonlib.stringlistify(kwargs.get('conflicts', [])) - deps = DepsHolder(filebase) + deps = DependenciesHelper(filebase) deps.add_pub_libs(kwargs.get('libraries', [])) deps.add_priv_libs(kwargs.get('libraries_private', [])) deps.add_pub_reqs(kwargs.get('requires', [])) -- cgit v1.1