diff options
| -rw-r--r-- | docs/markdown/Pkgconfig-module.md | 57 | ||||
| -rw-r--r-- | docs/markdown/snippets/pkgconfig_break.md | 34 | ||||
| -rw-r--r-- | mesonbuild/modules/pkgconfig.py | 48 | ||||
| -rw-r--r-- | test cases/common/48 pkgconfig-gen/dependencies/custom.c | 3 | ||||
| -rw-r--r-- | test cases/common/48 pkgconfig-gen/dependencies/meson.build | 3 | 
5 files changed, 126 insertions, 19 deletions
diff --git a/docs/markdown/Pkgconfig-module.md b/docs/markdown/Pkgconfig-module.md index 9a34e1478..6aee0c70f 100644 --- a/docs/markdown/Pkgconfig-module.md +++ b/docs/markdown/Pkgconfig-module.md @@ -5,9 +5,12 @@ This module is a simple generator for  ## Usage -To use this module, just do: **`pkg = import('pkgconfig')`**. The -following function will then be available as `pkg.generate()`. You -can, of course, replace the name `pkg` with anything else. +```meson +pkg = import('pkgconfig') +bar_dep = dependency('bar') +lib = library('foo', dependencies : [bar]) +pkg.generate(lib) +```  ### pkg.generate() @@ -25,14 +28,13 @@ keyword arguments.  - `libraries` a list of built libraries (usually results of    shared_library) that the user needs to link against. Arbitrary 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. +  dependencies of built libraries will be automatically added, see the +  [Implicit dependencies](#Implicit_dependencies) section below for the exact +  rules.  - `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`. +  `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.  - `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 @@ -59,3 +61,38 @@ provided for all required fields of the pc file:  - `install_dir` is set to `pkgconfig` folder in the same location than the provided library.  - `description` is set to the project's name followed by the library's name.  - `name` is set to the library's name. + +### Implicit dependencies + +The exact rules followed to find dependencies that are implicitly added into the +pkg-config file have evolved over time. Here are the rules as of Meson *0.49.0*, +previous versions might have slightly different behaviour. + +- Not found libraries or dependencies are ignored. +- Libraries and dependencies are private by default (i.e. added into +  `Requires.private:` or `Libs.private:`) unless they are explicitly added in +  `libraries` or `requires` keyword arguments, or is the main library (first +  positional argument). +- Libraries and dependencies will be de-duplicated, if they are added in both +  public and private (e.g `Requires:` and `Requires.private:`) it will be removed +  from the private list. +- Shared libraries (i.e. `shared_library()` and **NOT** `library()`) add only +  `-lfoo` into `Libs:` or `Libs.private:` but their dependencies are not pulled. +  This is because dependencies are only needed for static link. +- Other libraries (i.e. `static_library()` or `library()`) add `-lfoo` into `Libs:` +  or `Libs.private:` and recursively add their dependencies into `Libs.private:` or +  `Requires.private:`. +- Dependencies provided by pkg-config are added into `Requires:` or +  `Requires.private:`. If a version was specified when declaring that dependency +  it will be written into the generated file too. +- The thread dependency (i.e. `dependency('thread')`) adds `-pthread` into +  `Libs:` or `Libs.private:`. +- Internal dependencies (i.e. +  `declare_dependency(compiler_args : '-DFOO', link_args : '-Wl,something', link_with : foo)`) +  add `compiler_args` into `Cflags:` if public, `link_args` and `link_with` into +  `Libs:` if public or `Libs.private:` if private. +- Other dependency types add their compiler arguments into `Cflags:` if public, +  and linker arguments into `Libs:` if public or `Libs.private:` if private. +- Once a pkg-config file is generated for a library using `pkg.generate(mylib)`, +  any subsequent call to `pkg.generate()` where mylib appears, will generate a +  `Requires:` or `Requires.private` instead of a `Libs:` or `Libs.private:`. diff --git a/docs/markdown/snippets/pkgconfig_break.md b/docs/markdown/snippets/pkgconfig_break.md new file mode 100644 index 000000000..49c908dd7 --- /dev/null +++ b/docs/markdown/snippets/pkgconfig_break.md @@ -0,0 +1,34 @@ +## Deprecation warning in pkg-config generator + +All libraries passed to the `libraries` keyword argument of the `generate()` +method used to be associated with that generated pkg-config file. That means +that any subsequent call to `generate()` where those libraries appear would add +the filebase of the `generate()` that first contained them into `Requires:` or +`Requires.private:` field instead of adding an `-l` to `Libs:` or `Libs.private:`. + +This behaviour is now deprecated. The library that should be associated with +the generated pkg-config file should be passed as first positional argument +instead of in the `libraries` keyword argument. The previous behaviour is +maintained but prints a deprecation warning and support for this will be removed +in a future Meson release. If you can not create the needed pkg-config file +without this warning, please file an issue with as much details as possible +about the situation. + +For example this sample will write `Requires: liba` into `libb.pc` but print a +deprecation warning: +```meson +liba = library(...) +pkg.generate(libraries : liba) + +libb = library(...) +pkg.generate(libraries : [liba, libb]) +``` + +It can be fixed by passing `liba` as first positional argument:: +```meson +liba = library(...) +pkg.generate(liba) + +libb = library(...) +pkg.generate(libb, libraries : [liba]) +``` diff --git a/mesonbuild/modules/pkgconfig.py b/mesonbuild/modules/pkgconfig.py index 708695af0..eee3783cf 100644 --- a/mesonbuild/modules/pkgconfig.py +++ b/mesonbuild/modules/pkgconfig.py @@ -12,7 +12,7 @@  # See the License for the specific language governing permissions and  # limitations under the License. -import os +import os, types  from pathlib import PurePath  from .. import build @@ -50,11 +50,24 @@ class DependenciesHelper:      def add_priv_reqs(self, reqs):          self.priv_reqs += self._process_reqs(reqs) +    def _check_generated_pc_deprecation(self, obj): +        if hasattr(obj, 'generated_pc_warn'): +            mlog.deprecation('Library', mlog.bold(obj.name), 'was passed to the ' +                             '"libraries" keyword argument of a previous call ' +                             'to generate() method instead of first positional ' +                             'argument.', 'Adding', mlog.bold(obj.generated_pc), +                             'to "Requires" field, but this is a deprecated ' +                             'behaviour that will change in a future version ' +                             'of Meson. Please report the issue if this ' +                             'warning cannot be avoided in your case.', +                             location=obj.generated_pc_warn) +      def _process_reqs(self, reqs):          '''Returns string names of requirements'''          processed_reqs = []          for obj in mesonlib.listify(reqs, unholder=True):              if hasattr(obj, 'generated_pc'): +                self._check_generated_pc_deprecation(obj)                  processed_reqs.append(obj.generated_pc)              elif hasattr(obj, 'pcdep'):                  pcdeps = mesonlib.listify(obj.pcdep) @@ -93,7 +106,8 @@ class DependenciesHelper:                  for d in pcdeps:                      processed_reqs.append(d.name)                      self.add_version_reqs(d.name, obj.version_reqs) -            elif hasattr(obj, 'generated_pc') and obj.generated_pc != self.name: +            elif hasattr(obj, 'generated_pc'): +                self._check_generated_pc_deprecation(obj)                  processed_reqs.append(obj.generated_pc)              elif isinstance(obj, dependencies.PkgConfigDependency):                  if obj.found(): @@ -102,6 +116,14 @@ class DependenciesHelper:              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.InternalDependency): +                if obj.found(): +                    processed_libs += obj.get_link_args() +                    processed_cflags += obj.get_compile_args() +                    if public: +                        self.add_pub_libs(obj.libraries) +                    else: +                        self.add_priv_libs(obj.libraries)              elif isinstance(obj, dependencies.Dependency):                  if obj.found():                      processed_libs += obj.get_link_args() @@ -114,14 +136,8 @@ class DependenciesHelper:                  # than needed build deps.                  # See https://bugs.freedesktop.org/show_bug.cgi?id=105572                  processed_libs.append(obj) -                if public: -                    if not hasattr(obj, 'generated_pc'): -                        obj.generated_pc = self.name              elif isinstance(obj, (build.SharedLibrary, build.StaticLibrary)):                  processed_libs.append(obj) -                if public: -                    if not hasattr(obj, 'generated_pc'): -                        obj.generated_pc = self.name                  if isinstance(obj, build.StaticLibrary) and public:                      self.add_pub_libs(obj.get_dependencies(internal=False))                      self.add_pub_libs(obj.get_external_deps()) @@ -407,6 +423,22 @@ class PkgConfigModule(ExtensionModule):          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) +        # Associate the main library with this generated pc file. If the library +        # is used in any subsequent call to the generated, it will generate a +        # 'Requires:' or 'Requires.private:'. +        # Backward compatibility: We used to set 'generated_pc' on all public +        # libraries instead of just the main one. Keep doing that but warn if +        # anyone is relying on that deprecated behaviour. +        if mainlib: +            if not hasattr(mainlib, 'generated_pc'): +                mainlib.generated_pc = filebase +            else: +                mlog.warning('Already generated a pkg-config file for', mlog.bold(mainlib.name)) +        for lib in deps.pub_libs: +            if not isinstance(lib, str) and not hasattr(lib, 'generated_pc'): +                lib.generated_pc = filebase +                lib.generated_pc_warn = types.SimpleNamespace(subdir=state.subdir, +                                                              lineno=state.current_lineno)          return ModuleReturnValue(res, [res])  def initialize(*args, **kwargs): diff --git a/test cases/common/48 pkgconfig-gen/dependencies/custom.c b/test cases/common/48 pkgconfig-gen/dependencies/custom.c new file mode 100644 index 000000000..2cc5651dd --- /dev/null +++ b/test cases/common/48 pkgconfig-gen/dependencies/custom.c @@ -0,0 +1,3 @@ +int custom_function() { +    return 42; +} diff --git a/test cases/common/48 pkgconfig-gen/dependencies/meson.build b/test cases/common/48 pkgconfig-gen/dependencies/meson.build index 047e7e7eb..2dad3932a 100644 --- a/test cases/common/48 pkgconfig-gen/dependencies/meson.build +++ b/test cases/common/48 pkgconfig-gen/dependencies/meson.build @@ -6,6 +6,7 @@ pkgg = import('pkgconfig')  exposed_lib = shared_library('libexposed', 'exposed.c')  internal_lib = shared_library('libinternal', 'internal.c')  main_lib = both_libraries('libmain', link_with : [exposed_lib, internal_lib]) +custom_lib = shared_library('custom', 'custom.c')  pkgg.generate(exposed_lib) @@ -14,7 +15,7 @@ pc_dep = dependency('libfoo', version : '>=1.0')  pc_dep_dup = dependency('libfoo', version : '>= 1.0')  notfound_dep = dependency('notfound', required : false)  threads_dep = dependency('threads') -custom_dep = declare_dependency(link_args : ['-lcustom'], compile_args : ['-DCUSTOM']) +custom_dep = declare_dependency(link_with : custom_lib, compile_args : ['-DCUSTOM'])  custom2_dep = declare_dependency(link_args : ['-lcustom2'], compile_args : ['-DCUSTOM2'])  # Generate a PC file:  | 
