From 3c64ecaf866ca611b40287c78f622e370f90f272 Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Tue, 6 Apr 2021 14:29:23 -0400 Subject: [PATCH] pkgconfig: Add support for CustomTarget objects in generator Fixes: #8618. --- docs/markdown/Pkgconfig-module.md | 7 ++++-- docs/markdown/snippets/pkgconfig_gen_ct.md | 5 ++++ mesonbuild/build.py | 3 +++ mesonbuild/modules/pkgconfig.py | 24 ++++++++++++++----- run_unittests.py | 7 ++++++ .../common/45 pkgconfig-gen/meson.build | 19 +++++++++++++++ test cases/common/45 pkgconfig-gen/test.json | 4 +++- 7 files changed, 60 insertions(+), 9 deletions(-) create mode 100644 docs/markdown/snippets/pkgconfig_gen_ct.md diff --git a/docs/markdown/Pkgconfig-module.md b/docs/markdown/Pkgconfig-module.md index 35396d616..9c66b338f 100644 --- a/docs/markdown/Pkgconfig-module.md +++ b/docs/markdown/Pkgconfig-module.md @@ -30,11 +30,14 @@ keyword arguments. also be provided and they will be added into the `Libs` field. Since 0.45.0 dependencies of built libraries will be automatically added, see the [Implicit dependencies](#implicit-dependencies) section below for the exact - rules. + rules. Since 0.58.0 custom_target() objects are supported as long as they are + linkable (has known extension such as `.a`, `.so`, etc). - `libraries_private` list of built libraries or strings to put in the `Libs.private` field. Since 0.45.0 dependencies of built libraries will be automatically added, see the [Implicit dependencies](#implicit-dependencies) - section below for the exact rules. + section below for the exact rules. Since 0.58.0 custom_target() objects are + supported as long as they are linkable (has known extension such as `.a`, + `.so`, etc). - `name` the name of this library, used to set the `Name:` field - `subdirs` which subdirs of `include` should be added to the header search path, for example if you install headers into diff --git a/docs/markdown/snippets/pkgconfig_gen_ct.md b/docs/markdown/snippets/pkgconfig_gen_ct.md new file mode 100644 index 000000000..ccf941531 --- /dev/null +++ b/docs/markdown/snippets/pkgconfig_gen_ct.md @@ -0,0 +1,5 @@ +## Passing `custom_target()` output to `pkg.generate()` + +It is now allowed to pass libraries generated by a `custom_target()` to +pkg-config file generator. The output filename must have a known library extension +such as `.a`, `.so`, etc. diff --git a/mesonbuild/build.py b/mesonbuild/build.py index 69e853fc5..06e40f571 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -2601,6 +2601,9 @@ class CustomTargetIndex: def extract_all_objects_recurse(self): return self.target.extract_all_objects_recurse() + def get_custom_install_dir(self): + return self.target.get_custom_install_dir() + class ConfigurationData: def __init__(self) -> None: super().__init__() diff --git a/mesonbuild/modules/pkgconfig.py b/mesonbuild/modules/pkgconfig.py index 3f06ed0d3..18815f663 100644 --- a/mesonbuild/modules/pkgconfig.py +++ b/mesonbuild/modules/pkgconfig.py @@ -153,6 +153,11 @@ class DependenciesHelper: obj.link_whole_targets, obj.external_deps, isinstance(obj, build.StaticLibrary) and public) + elif isinstance(obj, (build.CustomTarget, build.CustomTargetIndex)): + if not obj.is_linkable_target(): + raise mesonlib.MesonException('library argument contains a not linkable custom_target.') + FeatureNew.single_use('custom_target in pkgconfig.generate libraries', '0.58.0', self.state.subproject) + processed_libs.append(obj) elif isinstance(obj, str): processed_libs.append(obj) else: @@ -276,7 +281,13 @@ class DependenciesHelper: class PkgConfigModule(ExtensionModule): - def _get_lname(self, l, msg, pcfile): + def _get_lname(self, l, msg, pcfile, is_custom_target): + if is_custom_target: + basename = os.path.basename(l.get_filename()) + name = os.path.splitext(basename)[0] + if name.startswith('lib'): + name = name[3:] + return name # Nothing special if not l.name_prefix_set: return l.name @@ -373,7 +384,8 @@ class PkgConfigModule(ExtensionModule): install_dir = l.get_custom_install_dir()[0] if install_dir is False: continue - if 'cs' in l.compilers: + is_custom_target = isinstance(l, (build.CustomTarget, build.CustomTargetIndex)) + if not is_custom_target and 'cs' in l.compilers: if isinstance(install_dir, str): Lflag = '-r${{prefix}}/{}/{}'.format(self._escape(self._make_relative(prefix, install_dir)), l.filename) else: # install_dir is True @@ -386,18 +398,18 @@ class PkgConfigModule(ExtensionModule): if Lflag not in Lflags: Lflags.append(Lflag) yield Lflag - lname = self._get_lname(l, msg, pcfile) + lname = self._get_lname(l, msg, pcfile, is_custom_target) # If using a custom suffix, the compiler may not be able to # find the library - if l.name_suffix_set: + if not is_custom_target and l.name_suffix_set: mlog.warning(msg.format(l.name, 'name_suffix', lname, pcfile)) - if 'cs' not in l.compilers: + if is_custom_target or 'cs' not in l.compilers: yield '-l%s' % lname def get_uninstalled_include_dirs(libs): result = [] for l in libs: - if isinstance(l, str): + if isinstance(l, (str, build.CustomTarget, build.CustomTargetIndex)): continue if l.get_subdir() not in result: result.append(l.get_subdir()) diff --git a/run_unittests.py b/run_unittests.py index 2a2fb4c95..b6e349d32 100755 --- a/run_unittests.py +++ b/run_unittests.py @@ -6486,6 +6486,13 @@ class LinuxlikeTests(BasePlatformTests): self.assertEqual(libhello_nolib.get_pkgconfig_variable('foo', {}), 'bar') self.assertEqual(libhello_nolib.get_pkgconfig_variable('prefix', {}), self.prefix) + cc = env.detect_c_compiler(MachineChoice.HOST) + if cc.get_id() in {'gcc', 'clang'}: + for name in {'ct', 'ct0'}: + ct_dep = PkgConfigDependency(name, env, kwargs) + self.assertTrue(ct_dep.found()) + self.assertIn('-lct', ct_dep.get_link_args()) + def test_pkgconfig_gen_deps(self): ''' Test that generated pkg-config files correctly handle dependencies diff --git a/test cases/common/45 pkgconfig-gen/meson.build b/test cases/common/45 pkgconfig-gen/meson.build index 6a3b788ec..788539161 100644 --- a/test cases/common/45 pkgconfig-gen/meson.build +++ b/test cases/common/45 pkgconfig-gen/meson.build @@ -101,3 +101,22 @@ stat2 = static_library('stat2', 'simple.c', install: true) simple4 = library('simple4', 'simple.c', link_with: stat2) simple5 = library('simple5', 'simple5.c', link_with: simple4, link_whole: stat2) pkgg.generate(simple5) + +# Test passing a linkable CustomTarget and CustomTargetIndex to generator. +# Do this only with gcc/clang to not have to deal with other compiler command +# line specificities. +if cc.get_id() in ['gcc', 'clang'] + ct = custom_target('ct', + input: 'simple.c', + output: 'libct.so', + command: [cc.cmd_array(), '@INPUT@', '-shared', '-o', '@OUTPUT@'], + ) + pkgg.generate(libraries: ct, + name: 'ct', + description: 'custom target' + ) + pkgg.generate(libraries: ct[0], + name: 'ct0', + description: 'custom target index' + ) +endif diff --git a/test cases/common/45 pkgconfig-gen/test.json b/test cases/common/45 pkgconfig-gen/test.json index 702e7fee4..e741a6251 100644 --- a/test cases/common/45 pkgconfig-gen/test.json +++ b/test cases/common/45 pkgconfig-gen/test.json @@ -8,6 +8,8 @@ {"type": "file", "file": "usr/lib/pkgconfig/libhello_nolib.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/simple5.pc"}, + {"type": "file", "file": "usr/lib/pkgconfig/ct.pc"}, + {"type": "file", "file": "usr/lib/pkgconfig/ct0.pc"} ] }