aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mesonbuild/dependencies/misc.py5
-rw-r--r--mesonbuild/dependencies/ui.py5
-rw-r--r--mesonbuild/modules/pkgconfig.py127
-rw-r--r--test cases/common/51 pkgconfig-gen/meson.build62
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))