Skip to content

Commit

Permalink
pkgconfig: Generate -uninstalled.pc files
Browse files Browse the repository at this point in the history
  • Loading branch information
xclaesse committed Oct 28, 2018
1 parent 198d4b8 commit cc12f30
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 17 deletions.
9 changes: 9 additions & 0 deletions docs/markdown/Pkgconfig-module.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,19 @@ keyword arguments.
- `version` a string describing the version of this library
- `d_module_versions` a list of module version flags used when compiling
D sources referred to by this pkg-config file
- `uninstalled_variables` used instead of the `variables` keyword argument, when
generating the uninstalled pkg-config file. Since *0.49.0*

Since 0.46 a `StaticLibrary` or `SharedLibrary` object can optionally be passed
as first positional argument. If one is provided a default value will be
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.

Since 0.49.0 uninstalled pkg-config files are generated as well. They are
located in `<build dir>/pkgconfig-uninstalled/*-uninstalled.pc`. It is useful to
build projects against libraries built by meson without having to install them
into a prefix. In order to do so, just set `PKG_CONFIG_PATH=<builddir>/pkgconfig-uninstalled`
before building your application. That will cause pkg-config to use those pc files
in priority and find libraries and headers from the meson builddir.
7 changes: 7 additions & 0 deletions docs/markdown/snippets/uninstalled-pkgconfig.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
## Uninstalled pkg-config files

The `pkgconfig` module now generates uninstalled pc files as well. For any generated
`foo.pc` file, an extra `foo-uninstalled.pc` file is placed into
`<builddir>/pkgconfig-uninstalled`. They can be used to build applications against
libraries built by meson without installing them, by pointing `PKG_CONFIG_PATH`
to that directory.
75 changes: 58 additions & 17 deletions mesonbuild/modules/pkgconfig.py
Original file line number Diff line number Diff line change
Expand Up @@ -231,19 +231,30 @@ def _make_relative(self, prefix, subdir):
return subdir

def generate_pkgconfig_file(self, state, deps, subdirs, name, description,
url, version, pcfile, conflicts, variables):
url, version, pcfile, conflicts, variables,
uninstalled=False):
deps.remove_dups()
coredata = state.environment.get_coredata()
outdir = state.environment.scratch_dir
fname = os.path.join(outdir, pcfile)
prefix = PurePath(coredata.get_builtin_option('prefix'))
# These always return paths relative to prefix
libdir = PurePath(coredata.get_builtin_option('libdir'))
incdir = PurePath(coredata.get_builtin_option('includedir'))
if not uninstalled:
fname = os.path.join(state.environment.scratch_dir, pcfile)
else:
outdir = os.path.join(state.environment.build_dir, 'pkgconfig-uninstalled')
if not os.path.exists(outdir):
os.mkdir(outdir)
fname = os.path.join(outdir, pcfile)
with open(fname, 'w') as ofile:
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 not uninstalled:
prefix = PurePath(coredata.get_builtin_option('prefix'))
# These always return paths relative to prefix
libdir = PurePath(coredata.get_builtin_option('libdir'))
incdir = PurePath(coredata.get_builtin_option('includedir'))
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)))
else:
ofile.write('prefix=\n')
ofile.write('libdir=\n')
ofile.write('includedir=\n')
if variables:
ofile.write('\n')
for k, v in variables:
Expand Down Expand Up @@ -276,7 +287,10 @@ def generate_libs_flags(libs):
install_dir = l.get_custom_install_dir()[0]
if install_dir is False:
continue
if isinstance(install_dir, str):
if uninstalled:
path = os.path.dirname(state.backend.get_target_filename_abs(l))
Lflag = '-L%s' % self._escape(path)
elif isinstance(install_dir, str):
Lflag = '-L${prefix}/%s ' % self._escape(self._make_relative(prefix, install_dir))
else: # install_dir is True
Lflag = '-L${libdir}'
Expand All @@ -290,22 +304,42 @@ def generate_libs_flags(libs):
mlog.warning(msg.format(l.name, 'name_suffix', lname, pcfile))
yield '-l%s' % lname

def generate_include_flags(libs):
Iflags = []
for l in libs:
if isinstance(l, str):
continue
for i in l.get_include_dirs():
curdir = i.get_curdir()
for d in i.get_incdirs():
for basedir in [state.environment.get_source_dir(),
state.environment.get_build_dir()]:
path = os.path.join(basedir, curdir, d)
Iflag = '-I%s' % path
if Iflag not in Iflags:
Iflags.append(Iflag)
yield Iflag

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(' ')
if h == '.':
ofile.write('-I${includedir}')
else:
ofile.write(self._escape(PurePath('-I${includedir}') / h))
if uninstalled:
ofile.write(' '.join(generate_include_flags(deps.pub_libs + deps.priv_libs)))
else:
for h in subdirs:
ofile.write(' ')
if h == '.':
ofile.write('-I${includedir}')
else:
ofile.write(self._escape(PurePath('-I${includedir}') / h))
for f in deps.cflags:
ofile.write(' ')
ofile.write(self._escape(f))
ofile.write('\n')

@FeatureNewKwargs('pkgconfig.generate', '0.49.0', ['uninstalled_variables'])
@FeatureNewKwargs('pkgconfig.generate', '0.42.0', ['extra_cflags'])
@FeatureNewKwargs('pkgconfig.generate', '0.41.0', ['variables'])
@permittedKwargs({'libraries', 'version', 'name', 'description', 'filebase',
Expand Down Expand Up @@ -400,6 +434,13 @@ def parse_variable_list(stringlist):
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)

variables = parse_variable_list(mesonlib.stringlistify(kwargs.get('uninstalled_variables', [])))
pcfile = filebase + '-uninstalled.pc'
self.generate_pkgconfig_file(state, deps, subdirs, name, description, url,
version, pcfile, conflicts, variables,
uninstalled=True)

return ModuleReturnValue(res, [res])

def initialize(*args, **kwargs):
Expand Down

0 comments on commit cc12f30

Please sign in to comment.