diff --git a/docs/markdown/snippets/pkgconfig_directory_variables.md b/docs/markdown/snippets/pkgconfig_directory_variables.md new file mode 100644 index 000000000..27a406900 --- /dev/null +++ b/docs/markdown/snippets/pkgconfig_directory_variables.md @@ -0,0 +1,31 @@ +## pkgconfig.generate will now include variables for builtin directories when referenced + +When using the `variables:` family of kwargs to `pkgconfig.generate` to refer +to installed paths, traditionally only `prefix`, `includedir`, and `libdir` +were available by default, and generating a correct (relocatable) pkg-config +file required manually constructing variables for e.g. `datadir`. + +Meson now checks each variable to see if it begins with a reference to a +standard directory, and if so, adds it to the list of directories for which a +builtin variable is created. + +For example, before it was necessary to do this: +```meson +pkgconfig.generate( + name: 'bash-completion', + description: 'programmable completion for the bash shell', + dataonly: true, + variables: { + 'prefix': get_option('prefix'), + 'datadir': join_paths('${prefix}', get_option('datadir')), + 'sysconfdir': join_paths('${prefix}', get_option('sysconfdir')), + + 'compatdir': '${sysconfdir}/bash_completion.d', + 'completionsdir': '${datadir}/bash-completion/completions', + 'helpersdir': '${datadir}/bash-completion/helpers', + }, + install_dir: join_paths(get_option('datadir'), 'pkgconfig'), +) +``` + +Now the first three variables are not needed. diff --git a/mesonbuild/modules/pkgconfig.py b/mesonbuild/modules/pkgconfig.py index 2e985cf03..f67e6eb41 100644 --- a/mesonbuild/modules/pkgconfig.py +++ b/mesonbuild/modules/pkgconfig.py @@ -22,8 +22,9 @@ from .. import build from .. import dependencies from .. import mesonlib from .. import mlog +from ..coredata import BUILTIN_DIR_OPTIONS from ..dependencies import ThreadDependency -from ..interpreterbase import permittedKwargs, FeatureNew, FeatureNewKwargs +from ..interpreterbase import permittedKwargs, FeatureNew, FeatureDeprecated, FeatureNewKwargs if T.TYPE_CHECKING: from . import ModuleState @@ -329,6 +330,41 @@ class PkgConfigModule(ExtensionModule): url, version, pcfile, conflicts, variables, unescaped_variables, uninstalled=False, dataonly=False): coredata = state.environment.get_coredata() + referenced_vars = set() + optnames = [x.name for x in BUILTIN_DIR_OPTIONS.keys()] + + if not dataonly: + # includedir is always implied, although libdir may not be + # needed for header-only libraries + referenced_vars |= {'prefix', 'includedir'} + if deps.pub_libs or deps.priv_libs: + referenced_vars |= {'libdir'} + # also automatically infer variables referenced in other variables + implicit_vars_warning = False + redundant_vars_warning = False + varnames = set() + varstrings = set() + for k, v in variables + unescaped_variables: + varnames |= {k} + varstrings |= {v} + for optname in optnames: + optvar = f'${{{optname}}}' + if any(x.startswith(optvar) for x in varstrings): + if optname in varnames: + redundant_vars_warning = True + else: + # these 3 vars were always "implicit" + if dataonly or optname not in {'prefix', 'includedir', 'libdir'}: + implicit_vars_warning = True + referenced_vars |= {'prefix', optname} + if redundant_vars_warning: + FeatureDeprecated.single_use('pkgconfig.generate variable for builtin directories', '0.62.0', + state.subproject, 'They will be automatically included when referenced', + state.current_node) + if implicit_vars_warning: + FeatureNew.single_use('pkgconfig.generate implicit variable for builtin directories', '0.62.0', + state.subproject, location=state.current_node) + if uninstalled: outdir = os.path.join(state.environment.build_dir, 'meson-uninstalled') if not os.path.exists(outdir): @@ -338,18 +374,17 @@ class PkgConfigModule(ExtensionModule): else: outdir = state.environment.scratch_dir prefix = PurePath(coredata.get_option(mesonlib.OptionKey('prefix'))) - # These always return paths relative to prefix - libdir = PurePath(coredata.get_option(mesonlib.OptionKey('libdir'))) - incdir = PurePath(coredata.get_option(mesonlib.OptionKey('includedir'))) fname = os.path.join(outdir, pcfile) with open(fname, 'w', encoding='utf-8') as ofile: - if not dataonly: - ofile.write('prefix={}\n'.format(self._escape(prefix))) - if uninstalled: - ofile.write('srcdir={}\n'.format(self._escape(srcdir))) - if deps.pub_libs or deps.priv_libs: - ofile.write('libdir={}\n'.format(self._escape('${prefix}' / libdir))) - ofile.write('includedir={}\n'.format(self._escape('${prefix}' / incdir))) + for optname in optnames: + if optname in referenced_vars - varnames: + if optname == 'prefix': + ofile.write('prefix={}\n'.format(self._escape(prefix))) + else: + dirpath = PurePath(coredata.get_option(mesonlib.OptionKey(optname))) + ofile.write('{}={}\n'.format(optname, self._escape('${prefix}' / dirpath))) + if uninstalled and not dataonly: + ofile.write('srcdir={}\n'.format(self._escape(srcdir))) if variables or unescaped_variables: ofile.write('\n') for k, v in variables: diff --git a/test cases/common/44 pkgconfig-gen/meson.build b/test cases/common/44 pkgconfig-gen/meson.build index 128205a96..a24c23989 100644 --- a/test cases/common/44 pkgconfig-gen/meson.build +++ b/test cases/common/44 pkgconfig-gen/meson.build @@ -1,4 +1,4 @@ -project('pkgconfig-gen', 'c') +project('pkgconfig-gen', 'c', meson_version: '>=0.60.0') # Some CI runners does not have zlib, just skip them as we need some common # external dependency. @@ -149,3 +149,17 @@ ct = custom_target('stat3', ) simple6 = library('simple6', link_with: ct) pkgg.generate(simple6) + +# implicit variables +pkgg.generate( + name : 'libvartest', + description : 'Check that implicit vars are created', + version : libver, + variables: ['datadir=${prefix}/data', 'foo=${datadir}/foo', 'bar=${bindir}/bar'] +) +pkgg.generate( + name : 'libvartest2', + description : 'Check that libdir is not an implicit var', + version : libver, + variables: ['bar=${libdir}/bar'] +) diff --git a/test cases/common/44 pkgconfig-gen/test.json b/test cases/common/44 pkgconfig-gen/test.json index c7bdd43f4..118fecdd4 100644 --- a/test cases/common/44 pkgconfig-gen/test.json +++ b/test cases/common/44 pkgconfig-gen/test.json @@ -7,11 +7,26 @@ {"type": "file", "file": "usr/lib/pkgconfig/libfoo.pc"}, {"type": "file", "file": "usr/lib/pkgconfig/libhello.pc"}, {"type": "file", "file": "usr/lib/pkgconfig/libhello_nolib.pc"}, + {"type": "file", "file": "usr/lib/pkgconfig/libvartest.pc"}, + {"type": "file", "file": "usr/lib/pkgconfig/libvartest2.pc"}, {"type": "file", "file": "usr/lib/pkgconfig/simple2.pc"}, {"type": "file", "file": "usr/lib/pkgconfig/simple3.pc"}, {"type": "file", "file": "usr/lib/pkgconfig/simple5.pc"}, {"type": "file", "file": "usr/lib/pkgconfig/simple6.pc"}, {"type": "file", "file": "usr/lib/pkgconfig/ct.pc"}, {"type": "file", "file": "usr/lib/pkgconfig/ct0.pc"} + ], + "stdout": [ + { + "line": "test cases/common/44 pkgconfig-gen/meson.build:158: WARNING: Project targeting '>=0.60.0' but tried to use feature introduced in '0.62.0': pkgconfig.generate implicit variable for builtin directories." + }, + { + "line": "test cases/common/44 pkgconfig-gen/meson.build:164: WARNING: Project targeting '>=0.60.0' but tried to use feature introduced in '0.62.0': pkgconfig.generate implicit variable for builtin directories.", + "count": 0 + }, + { + "comment": "This will either match in the future-deprecated notice summary, or match the warning summary", + "line": " * 0.62.0: {'pkgconfig.generate variable for builtin directories'}" + } ] }