Add 'contrib/pkgconf/' from commit '6294b6ab217a2d5f1d2bc23a64505a228294c508'

git-subtree-dir: contrib/pkgconf
git-subtree-mainline: 45827f9ad2
git-subtree-split: 6294b6ab21
This commit is contained in:
Pierre Pronchery
2026-04-22 15:13:42 +02:00
184 changed files with 19696 additions and 0 deletions
+41
View File
@@ -0,0 +1,41 @@
A. Wilcox <AWilcox@Wilcox-Tech.com>
Alexander Tsoy <alexander@tsoy.me>
Alexpux <alexey.pawlow@gmail.com>
Alon Bar-Lev <alon.barlev@gmail.com>
Alyx <alyx@malkier.net>
Ariadne Conill <ariadne@dereferenced.org>
Baptiste Daroussin <bapt@FreeBSD.org>
Baptiste Daroussin <bapt@gandi.net>
Bryan Drewery <bryan@shatow.net>
Dag-Erling Smørgrav <des@des.no>
Dan Kegel <dank@kegel.com>
Dan Kegel <dank@oblong.com>
Dan Nicholson <dbn.lists@gmail.com>
David Michael <fedora.dm0@gmail.com>
Emil Renner Berthing <esmil@mailme.dk>
Fabian Groffen <grobian@gentoo.org>
Graham Ollis <plicease@cpan.org>
Gregor Richards <Richards@codu.org>
Ignacio Casal Quinteiro <qignacio@amazon.com>
Igor Gnatenko <ignatenko@redhat.com>
Issam Maghni <concatime@users.noreply.github.com>
JD Horelick <jdhore1@gmail.com>
Jason Dusek <jason.dusek@gmail.com>
Javier Viguera <javier.viguera@digi.com>
Jean-Sébastien Pédron <dumbbell@FreeBSD.org>
John Hein <jhgit@users.github.com>
Jussi Pakkanen <jpakkane@gmail.com>
Leorize <alaviss@users.noreply.github.com>
Luca Barbato <lu_zero@gentoo.org>
Marcin Wojdyr <wojdyr@gmail.com>
Maxin B. John <maxinbjohn@users.noreply.github.com>
Michał Górny <mgorny@gentoo.org>
Mike Frysinger <vapier@gentoo.org>
Seungha Yang <seungha.yang@navercorp.com>
TingPing <tingping@tingping.se>
Tobias Kortkamp <t6@users.noreply.github.com>
Tony Theodore <tonyt@logyst.com>
Volker Braun <vbraun.name@gmail.com>
Yu Kobayashi <yukoba@accelart.jp>
orbea <orbea@fredslev.dk>
✈ Graham ✈ <plicease@cpan.org>
+27
View File
@@ -0,0 +1,27 @@
# pkgconf Code of Conduct
We invite and encourage everybody to express their opinions on relevant
topics. All participants should at all times feel at ease to do so without
fearing any form of attack, reprisal or harassment. We ask everybody to be
respectful and considerate towards each other, especially when attempting
to provide constructive criticism.
To foster tolerance, respect and hospitality in our community, we agree not
to engage in discriminatory, disparaging or offensive speech or actions,
including as to (but not limited to) gender, sexuality, race, nationality,
religion or profession. We are a community of many different nationalities
and backgrounds, and we cherish our strength in diversity.
## Reporting incidents
Please report any incidents which may be perceived as violations to
`ariadne+conduct@dereferenced.org`. Incidents will be investigated and,
if warranted, acted upon.
## Credits
This CoC is derived from the [FSFE Code of Conduct][fsfe-coc].
[fsfe-coc]: https://fsfe.org/about/codeofconduct.en.html
+10
View File
@@ -0,0 +1,10 @@
Copyright (c) 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018
pkgconf authors (see AUTHORS file in source directory).
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
This software is provided 'as is' and without any warranty, express or
implied. In no event shall the authors be liable for any damages arising
from the use of this software.
+5
View File
@@ -0,0 +1,5 @@
syntax(2)
test_suite('pkgconf')
include('tests/Kyuafile')
+217
View File
@@ -0,0 +1,217 @@
libdir = @libdir@
datarootdir = @datarootdir@
datadir = @datadir@
includedir = @includedir@
system_includedir = @SYSTEM_INCLUDEDIR@
system_libdir = @SYSTEM_LIBDIR@
pkg_default_dir = @PKG_DEFAULT_PATH@
personality_dir = @PERSONALITY_PATH@
pkgconfigdir = $(libdir)/pkgconfig
nodist_pkgconfig_DATA = libpkgconf.pc
ACLOCAL_AMFLAGS = -I m4
AM_CFLAGS = -DPERSONALITY_PATH=\"$(personality_dir)\" -DPKG_DEFAULT_PATH=\"$(pkg_default_dir)\" -DSYSTEM_INCLUDEDIR=\"$(system_includedir)\" -DSYSTEM_LIBDIR=\"$(system_libdir)\"
bin_PROGRAMS = pkgconf bomtool
lib_LTLIBRARIES = libpkgconf.la
EXTRA_DIST = pkg.m4 \
meson.build \
meson_options.txt \
pkgconf.wxs.in \
txt2rtf.py \
libpkgconf/meson.build \
libpkgconf/config.h.meson \
libpkgconf/win-dirent.h \
tests/lib-relocatable/lib/pkgconfig/foo.pc \
tests/lib1/argv-parse-2.pc \
tests/lib1/billion-laughs.pc \
tests/lib1/dos-lineendings.pc \
tests/lib1/paren-quoting.pc \
tests/lib1/argv-parse-3.pc \
tests/lib1/foo.pc \
tests/lib1/foobar.pc \
tests/lib1/unavailable-provider.pc \
tests/lib1/prefix-foo1.pc \
tests/lib1/argv-parse.pc \
tests/lib1/framework-1.pc \
tests/lib1/prefix-foo2.pc \
tests/lib1/bar.pc \
tests/lib1/framework-2.pc \
tests/lib1/private-libs-duplication.pc \
tests/lib1/baz.pc \
tests/lib1/incomplete.pc \
tests/lib1/quotes.pc \
tests/lib1/case-sensitivity.pc \
tests/lib1/intermediary-1.pc \
tests/lib1/static-archive-libs.pc \
tests/lib1/cflags-libs-only.pc \
tests/lib1/intermediary-2.pc \
tests/lib1/static-libs.pc \
tests/lib1/circular-1.pc \
tests/lib1/missing-require.pc \
tests/lib1/sysroot-dir.pc \
tests/lib1/circular-2.pc \
tests/lib1/multiline.pc \
tests/lib1/multiline-bogus.pc \
tests/lib1/tilde-quoting.pc \
tests/lib1/circular-3.pc \
tests/lib1/no-trailing-newline.pc \
tests/lib1/tilde.pc \
tests/lib1/comments-in-fields.pc \
tests/lib1/nocflag.pc \
tests/lib1/typelibdir.pc \
tests/lib2/foo.pc \
tests/lib1/comments.pc \
tests/lib1/nolib.pc \
tests/lib3/bar.pc \
tests/lib1/conflicts.pc \
tests/lib1/omg-uninstalled.pc \
tests/lib1/omg-sysroot-uninstalled.pc \
tests/lib1/isystem.pc \
tests/lib1/idirafter.pc \
tests/lib1/idirafter-ordering.pc \
tests/lib1/depgraph-break.pc \
tests/lib1/cflags-whitespace.pc \
tests/lib1/cflags-whitespace-trailing.pc \
tests/lib1/provides.pc \
tests/lib1/provides-request-simple.pc \
tests/lib1/flag-order-1.pc \
tests/lib1/flag-order-3.pc \
tests/lib1/variable-whitespace.pc \
tests/lib1/fragment-collision.pc \
tests/lib1/fragment-collision-intermediary.pc \
tests/lib1/fragment-collision-1.pc \
tests/lib1/fragment-collision-2.pc \
tests/lib1/fragment-comment.pc \
tests/lib1/fragment-escaping-1.pc \
tests/lib1/fragment-escaping-2.pc \
tests/lib1/fragment-escaping-3.pc \
tests/lib1/fragment-quoting.pc \
tests/lib1/fragment-quoting-2.pc \
tests/lib1/fragment-quoting-3.pc \
tests/lib1/fragment-quoting-5.pc \
tests/lib1/fragment-quoting-7.pc \
tests/lib1/fragment-groups.pc \
tests/lib1/fragment-groups-2.pc \
tests/lib1/fragment-group-a.pc \
tests/lib1/fragment-group-b.pc \
tests/lib1/fragment-group-c.pc \
tests/lib1/malformed-1.pc \
tests/lib1/malformed-quoting.pc \
tests/lib1/malformed-version.pc \
tests/lib1/metapackage.pc \
tests/lib1/metapackage-1.pc \
tests/lib1/metapackage-2.pc \
tests/lib1/metapackage-3.pc \
tests/lib1/explicit-sysroot.pc \
tests/lib1/escaped-backslash.pc \
tests/lib1/cflags-internal.pc \
tests/lib1/requires-internal.pc \
tests/lib1/requires-internal-2.pc \
tests/lib1/requires-internal-missing.pc \
tests/lib1/requires-internal-collision.pc \
tests/lib1/tuple-quoting.pc \
tests/lib1/empty-tuple.pc \
tests/lib1/orphaned-requires-private.pc \
tests/lib1/pcfiledir.pc \
tests/lib1/sysroot-dir-2.pc \
tests/lib1/sysroot-dir-3.pc \
tests/lib1/sysroot-dir-4.pc \
tests/lib1/sysroot-dir-5.pc \
tests/lib1/child-prefix/pkgconfig/child-prefix-1.pc \
tests/lib1/cflags-libs-private-a.pc \
tests/lib1/cflags-libs-private-b.pc \
tests/lib1/cflags-libs-private-c.pc \
tests/lib1/truncated.pc \
tests/lib1/c-comment.pc \
tests/meson.build \
$(test_scripts) \
doc/conf.py \
doc/extract.py \
doc/index.rst \
doc/libpkgconf.rst \
doc/libpkgconf-argvsplit.rst \
doc/libpkgconf-audit.rst \
doc/libpkgconf-cache.rst \
doc/libpkgconf-client.rst \
doc/libpkgconf-dependency.rst \
doc/libpkgconf-fragment.rst \
doc/libpkgconf-path.rst \
doc/libpkgconf-pkg.rst \
doc/libpkgconf-queue.rst \
doc/libpkgconf-tuple.rst
test_scripts= tests/basic.sh \
tests/builtins.sh \
tests/conflicts.sh \
tests/framework.sh \
tests/parser.sh \
tests/provides.sh \
tests/regress.sh \
tests/requires.sh \
tests/symlink.sh \
tests/sysroot.sh \
tests/version.sh
test_sh = $(test_scripts)
check_SCRIPTS = ${test_sh:.sh=}
SUFFIXES= .sh
nobase_pkginclude_HEADERS = libpkgconf/bsdstubs.h libpkgconf/iter.h libpkgconf/libpkgconf.h libpkgconf/stdinc.h libpkgconf/libpkgconf-api.h
libpkgconf_la_SOURCES = \
libpkgconf/audit.c \
libpkgconf/buffer.c \
libpkgconf/cache.c \
libpkgconf/client.c \
libpkgconf/pkg.c \
libpkgconf/bsdstubs.c \
libpkgconf/fragment.c \
libpkgconf/argvsplit.c \
libpkgconf/fileio.c \
libpkgconf/tuple.c \
libpkgconf/dependency.c \
libpkgconf/queue.c \
libpkgconf/path.c \
libpkgconf/personality.c \
libpkgconf/parser.c
libpkgconf_la_LDFLAGS = -no-undefined -version-info 7:0:0 -export-symbols-regex '^pkgconf_'
dist_man_MANS = \
man/bomtool.1 \
man/pkgconf.1 \
man/pkg.m4.7 \
man/pc.5 \
man/pkgconf-personality.5
pkgconf_LDADD = libpkgconf.la
pkgconf_SOURCES = \
cli/main.c \
cli/getopt_long.c \
cli/renderer-msvc.c
pkgconf_CPPFLAGS = -I$(top_srcdir)/libpkgconf -I$(top_srcdir)/cli
noinst_HEADERS = \
cli/getopt_long.h \
cli/renderer-msvc.h
bomtool_LDADD = libpkgconf.la
bomtool_SOURCES = \
cli/bomtool/main.c \
cli/getopt_long.c
bomtool_CPPFLAGS = -I$(top_srcdir)/libpkgconf -I$(top_srcdir)/cli -I$(top_srcdir)/cli/bomtool
dist_doc_DATA = README.md AUTHORS
m4datadir = $(datadir)/aclocal
m4data_DATA = pkg.m4
CLEANFILES = $(EXTRA_PROGRAMS) \
$(check_SCRIPTS)
check: pkgconf $(check_SCRIPTS)
kyua --config=none test --kyuafile='$(top_builddir)/Kyuafile' \
--build-root='$(top_builddir)'
.sh:
install -m 755 $< $@
+77
View File
@@ -0,0 +1,77 @@
# Copyright (c) 2019 William Pitcock <nenolod@dereferenced.org>
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# This software is provided 'as is' and without any warranty, express or
# implied. In no event shall the authors be liable for any damages arising
# from the use of this software.
# pkgconf-lite is a staticly-linked version of pkgconf that does not include
# all features, notably it does not include cross-compile support and MSVC
# support. It does not include the libpkgconf library.
SRCS = \
libpkgconf/argvsplit.c \
libpkgconf/audit.c \
libpkgconf/bsdstubs.c \
libpkgconf/cache.c \
libpkgconf/client.c \
libpkgconf/dependency.c \
libpkgconf/fileio.c \
libpkgconf/fragment.c \
libpkgconf/parser.c \
libpkgconf/path.c \
libpkgconf/personality.c \
libpkgconf/pkg.c \
libpkgconf/queue.c \
libpkgconf/tuple.c \
cli/getopt_long.c \
cli/main.c
OBJS = ${SRCS:.c=.o}
CFLAGS = ${STATIC} -DPKGCONF_LITE -I. -Ilibpkgconf -Icli -DSYSTEM_LIBDIR=\"${SYSTEM_LIBDIR}\" -DSYSTEM_INCLUDEDIR=\"${SYSTEM_INCLUDEDIR}\" -DPKG_DEFAULT_PATH=\"${PKG_DEFAULT_PATH}\"
STATIC =
STRIP = strip
all: pkgconf-lite
libpkgconf/config.h:
@echo '#define PACKAGE_NAME "pkgconf-lite"' >> $@
@echo '#define PACKAGE_BUGREPORT "https://git.dereferenced.org/pkgconf/pkgconf/issues"' >> $@
@echo '#define PACKAGE_VERSION "2.5.1"' >> $@
@echo '#define PACKAGE PACKAGE_NAME " " PACKAGE_VERSION' >> $@
@echo '#define HAVE_STRLCPY' >> $@
@echo '#define HAVE_STRLCAT' >> $@
@echo '#define HAVE_STRNDUP' >> $@
pkgconf-lite: preflight libpkgconf/config.h ${OBJS}
${CC} ${STATIC} -o $@ ${OBJS}
${STRIP} $@
clean:
rm -f libpkgconf/config.h
rm -f ${OBJS}
rm -f pkgconf-lite
preflight: preflight-system-libdir preflight-system-includedir preflight-pkg-default-path
preflight-system-libdir:
@if test -z "${SYSTEM_LIBDIR}"; then \
echo "SYSTEM_LIBDIR not set."; \
exit 1; \
fi
preflight-system-includedir:
@if test -z "${SYSTEM_INCLUDEDIR}"; then \
echo "SYSTEM_INCLUDEDIR not set."; \
exit 1; \
fi
preflight-pkg-default-path:
@if test -z "${PKG_DEFAULT_PATH}"; then \
echo "PKG_DEFAULT_PATH not set."; \
exit 1; \
fi
.PHONY: preflight preflight-system-libdir preflight-system-includedir preflight-pkg-default-path clean
+943
View File
@@ -0,0 +1,943 @@
Changes from previous version of pkgconf
========================================
Changes from 2.5.0 to 2.5.1:
----------------------------
* Fix processing of empty dependency lists.
Changes from 2.4.3 to 2.5.0:
----------------------------
* Added a manual page for bomtool.
* Add support for preloaded packages.
These are modules which are preloaded into the package database
and preferred over searching the module search path when present.
* Refactor Windows registry PKG_CONFIG_PATH support so that it
augments the main directory search list instead of being treated
as a special case.
* Processing of `--with-path` arguments by the pkgconf CLI is
now deferred until libpkgconf is fully initialized, effectively
aligning behavior with PKG_CONFIG_PATH processing.
* Fix several minor memory safety bugs which were identified by
the GCC 15 static analyzer.
* Added support for pledge(2) and unveil(2) on systems where
this functionality is available.
* Significant improvements to pkgconf's manual pages.
Patches by Ingo Schwarze and Jonathan Gray (OpenBSD).
* Remove questionable default-static assumption on Windows that
was inherited from the original pkg-config. Most distributions
of pkgconf on Windows were already patching this out.
Patch by Kai Pastor.
* Add -D_POSIX_C_SOURCE=200809L to the build definitions, which
is needed for readlinkat on glibc.
Patch by Filipe Laíns.
Changes from 2.4.2 to 2.4.3:
----------------------------
* Fix additional logic errors relating to the new fragment trees
functionality.
Changes from 2.4.1 to 2.4.2:
----------------------------
* Fix several logic errors in the pkg-config file parser that were
surfaced by recent refactoring work.
* Fix BSD make compatibility so that it generates the test data
before running kyua on BSD make implementations.
Changes from 2.4.0 to 2.4.1:
----------------------------
* Ensure the full DAG is solved for all query types.
Changes from 2.3.0 to 2.4.0:
----------------------------
* Allow multiple package names in solution-based queries such as
`--print-requires`, `--print-requires-private` and `--print-provides`.
* Use `_DEFAULT_SOURCE` where appropriate on Meson.
* Add an abstract buffer type and use it when loading files from disk
instead of a 64KB buffer. This ensures large pkg-config files are
not truncated.
* Disable graph recursion in `--variable` queries as it was generating
duplicate output.
* Add infrastructure for tracking fragment group relations and convert
storage of fragments to use a tree-like structure instead of string
concatenation.
* Add support for tracking linker groups, e.g.
-Wl,--start-group -la -lb -lc -Wl,--end-group
as fragment groups.
* Properly contextualize the sysroot directory when processing package
information, ensuring packages where ${pc_sysrootdir} does not match
the default are properly processed.
Changes from 2.2.0 to 2.3.0:
----------------------------
* Fix compile with Meson on Solaris by defining __EXTENSIONS__.
* Add support for the PKG_CONFIG_RELOCATE_PATHS environmental variable.
When set, the program will act as if --define-prefix is always enabled.
* Color solution nodes that were part of the original query, and use
that coloring to skip over dependencies when generating DocumentNames
in bomtool.
* Enhance --env option to support variables with both --variable=varname
and --print-variables.
* Add --exists-cflags option which creates synthetic preprocessor
definition flags for every queried dependency when found.
* Document that Requires.private is always used for header paths.
Patch by Petr Písař.
* Fix minor documentation typos.
Patch by Pierce.
* Ensure string comparisons using <ctype.h> functions are done with
unsigned bytes to avoid undefined behavior.
Patch by Taylor R Campbell.
* Fix parsing edge-case bugs with dependency versions.
Patch by Kai Pastor.
* Change PKG_PROG_PKG_CONFIG autoconf macro to add a customizable
failure handler if pkg-config is not found.
Patch by Ismael Luceno.
Changes from 2.1.1 to 2.2.0:
----------------------------
* libpkgconf SOVERSION is now 5.
* Significant solver rework to flatten both requires and requires.private
dependencies in a single pass. Improves performance slightly and ensures
proper dependency order.
Patches by Kai Pastor.
* Improve `--digraph` output to reflect more of the solver's state in the
rendered dependency graph.
Patches by Kai Pastor.
* Do not reference the graph root by name when presenting error messages about
directly requested dependency nodes.
Patch by Kai Pastor.
Changes from 2.1.0 to 2.1.1:
----------------------------
* Documentation fixes from Sam James and Stefan Weil.
* Fix --modversion with constraints.
Patch by Kai Pastor.
* Reintroduce an optimization to the dependency graph walker which avoids
revisiting already visited nodes.
Patch by Yi Chou with some modifications.
* Add a regression test to check that the dependency flattener is working
as expected.
Patch by Kai Pastor.
Changes from 2.0.3 to 2.1.0:
----------------------------
* Do not flatten the solver solution into the original world used as
input to the solver.
Patches by Kai Pastor.
* Fix warnings with GCC 14 -Walloc-size.
Patch by Sam James.
* Add --solution to the pkgconf CLI to dump the solver state.
* Improve the --digraph output to clarify cancelled edges in a given
solution.
* Demote requires dependencies to requires.private when a parent
dependency is pulled in via requires.private.
* Trim trailing whitespace when processing package arguments.
Patch by Colin Gillespie.
* Avoid strncmp() in --modversion version comparison.
Patch by Colin Gillespie.
* Update autoconf compile flag checking macro.
Patch by Peter Kokot.
* Add system default path configuration to Meson.
Patch by L. E. Segovia.
* Fix order of PKG_CONFIG_LIBDIR and PKG_CONFIG_PATH element processing.
Changes from 2.0.2 to 2.0.3:
----------------------------
* Fix some edge-cases with the new `--modversion` implementation
and add additional regression tests.
Patch by Colin Gillespie.
* Fix some format specifiers to use PRIu64 in debug tracing.
Changes from 2.0.1 to 2.0.2:
----------------------------
* Fix long-standing bug where package identifiers for "uninstalled"
packages incorrectly included the "-uninstalled" suffix.
This was exposed by the recent change to `--modversion` in 2.0.1.
Changes from 2.0.0 to 2.0.1:
----------------------------
* The behavior of --modversion was largely reverted back to the traditional
pkg-config behavior, but still operates on a solved dependency graph.
The order of --modversion output is based on the dependency resolution
queue which is passed to the solver, which itself generally maps to the
order of the constrants provided on the command line.
* A new flag, --verbose, has been added. When used with `--modversion`, it
is possible to disambiguate which version belongs to which module:
% pkgconf --modversion --verbose foo bar
foo: 1.2.3
bar: 1.3
Changes from 1.9.5 to 2.0.0:
----------------------------
* When flattening the dependency graph, retain the latest seen edges
rather than the earliest.
* Fix a long-standing bug where the dependency resolution queue was
evaluated in reverse. This bug masked the aforementioned dependency
flattening bug in many cases.
* Fix handling of --with-path, which was appending paths to the search
list rather than prepending them as intended.
* Error when --modversion is requested with more than one package, as
the output is ambiguous.
Changes from 1.9.4 to 1.9.5:
----------------------------
* Fix incorrect assumptions involving the use of ctype(3) functions.
Patch by Taylor R Campbell.
* Fix detection of provided functions on autoconf.
Patches by Harmen Stoppels.
* Fix deletion of tests/meson.build by the autoconf build system.
Patch by h30032433.
* Fix quoting rules in argvsplit.c.
Patch by huyubiao.
* Update libpkgconf documentation and documentation building scripts.
Patches by Andrew Shadura.
* Enforce maximum package count correctly for --modversion.
Changes from 1.9.3 to 1.9.4:
----------------------------
* Fix a buffer overflow vulnerability involving very large variable expansions.
CVE-2023-24056
* Fix a bunch of minor regressions with the solver.
* Create separate solutions for `--cflags` and `--libs` when `--static` is not
used.
* Remove final trailing whitespace in pkgconf_fragment_render_buf().
* Revert broken pkg.m4 change involving querying module versions in
PKG_CHECK_MODULES.
* Fix handling of tildes in version strings.
* Various C99 formatting string fixes involving SIZE_FMT_SPECIFIER.
Changes from 1.9.2 to 1.9.3:
----------------------------
* Fix a bunch of minor code issues pointed out using Clang static analyzer.
* New API: pkgconf_solution_free(), which frees a compiled solution graph.
* Fix behavior when overriding global variables with `--define-variable`.
Changes from 1.9.1 to 1.9.2:
----------------------------
* Do not try to break dependency cycles across dependency lists. This causes
the solved graph to sometimes miss required dependency nodes because the
solver detected an incorrect dependency cycle.
* New API: pkgconf_queue_solve(), which replaces pkgconf_queue_apply().
pkgconf_queue_apply is now deprecated and should not be used in new code.
Changes from 1.9.0 to 1.9.1:
----------------------------
* Skip graph flattening and traversal for query types which only make sense
for a single pkg-config module.
The old solver walked these graphs with --maximum-traverse-depth=1 in
these cases, but this is no longer helpful because the graph is flattened
by the new solver.
Changes from 1.8.0 to 1.9.0:
----------------------------
* pkgconf 1.9.0 is the first testing release in the pkgconf 2.0 development
series. While it is believed to be suitable for production, there may be
bugs due to the overall redesign of the solver and other initiatives.
Additionally, a future release of pkgconf plans will have additional ABI
breaks for the libpkgconf library before the pkgconf 2.0 release is cut.
* There is now a new solver that is designed to provide higher performance
with complicated graphs, which works by flattening the dependency graph
into a smaller set of dependencies. This graph can then be evaluated
instead of the original dependency graph without having to visit every
edge in the graph.
NOTE: This solver, while providing significant performance improvements,
does so, at the cost of changed behavior for some edge cases (such as
circular dependencies).
* Bug fixes:
- Resolved several memory leaks with edge cases when using libpkgconf
directly.
- pkgconf CLI now consistently frees libpkgconf resources under all
circumstances.
- SYSROOT rules are no longer applied to `-uninstalled` packages by
default. Use `PKG_CONFIG_PKGCONF1_SYSROOT_RULES` for legacy behavior.
* A new `--license` selector has been added to the pkgconf CLI. This uses
SPDX expressions which can be set as the `License` field in `.pc` files.
See the `pc(5)` manpage for more information.
* The canonical location for pkgconf maintenance going forward is
<https://gitea.treehouse.systems/ariadne/pkgconf>. This is presently
mirrored to GitHub for user convenience, but that mirroring will
be terminated at some point (due to GitHub Copilot).
Changes from 1.7.4 to 1.8.0:
----------------------------
* This is the last planned maintenance branch. I see pkgconf as basically
a finished tool at this point, and very few people were ultimately interested
in libpkgconf. So, from here on out, it will just be bug fixes only and
very minor enhancements.
* Bug fixes:
- Improved path handling on Windows to conform to what the MSYS2
and Cygwin teams were already modifying pkgconf to do.
Patches by Christoph Reiter.
- Fix a minor memory leak relating to cross-personalities.
Patch by Stone Tickle.
- Fix static builds for Windows on Meson.
Patch by Alexander Neumann.
- Fix some edge cases with --redefine-prefix.
Patch by midipix.
- Do not prepend sysroot_dir if the .pc file does not exist in the
sysroot.
Patch by Sandro Mani.
- Do not perform path filtering on default system include and library
path lists. This fixes consistency with other mechanisms that modify
these path lists.
* Enhancements:
- Document the --validate option in the manpage.
Patch by orbea.
Changes from 1.7.3 to 1.7.4:
----------------------------
* Bug fixes:
- Fix null-dereference crash when pulling a malformed 'uninstalled'
.pc file into a dependency tree. Patch by Tobias Stöckmann.
- Fix truncation of comment characters when quoted.
- Fix handling of .pc module names in --list-all on Windows.
Patch by Ryan Scott.
- Handle platforms where realpath(3) requires a pre-allocated buffer.
Patch by Fabian Groffen.
- Fix version whitespace warning.
Patch by Christoph Reiter.
* Enhancements:
- Rewrite DOS paths on native Windows builds that don't use
Cygwin/MSYS.
- Add WantDefaultPure cross-compiler personality option.
- Prefer --static --pure linking on Windows.
- Add PKG_CONFIG_DONT_DEFINE_PREFIX environment variable.
Patch by Jeff Moguillansky.
- Many improvements when building pkgconf with Meson.
Patches by Christoph Reiter.
Changes from 1.7.2 to 1.7.3:
----------------------------
* Bug fixes:
- Fix a possible out of boundary write when evaluating dependencies.
Patch by Tobias Stöckmann.
- Fix escaping logic on Windows. Patch by Vincent Torri.
- Fix out of boundary reads and writes with a malformed fragment.
Patches by Tobias Stöckmann.
- Fix a possible out of boundary write when evaluating tuples.
Patch by Tobias Stöckmann.
Changes from 1.7.1 to 1.7.2:
----------------------------
* Bug fixes:
- Fix a windows-specific crash relating to path fixups.
Changes from 1.7.0 to 1.7.1:
----------------------------
* Bug fixes:
- Fix a possible out of boundary access in the parser for the
cross-compile database. Patch by Tobias Stöckmann.
- Missing files for building with Meson are now included in the
tarball. Patch by Neal Gompa.
- Fix calculation of package atoms on Windows with paths that
use both directory separator characters.
Changes from 1.6.3 to 1.7.0:
----------------------------
* Bug fixes:
- Fix a possible buffer overflow involving newline escaping.
Patch by Tobias Stöckmann.
- Fix an out of boundary access in the parser.
Patch by Tobias Stöckmann.
- Fix leakage of strcmp() result value in pkgconf_compare_version()
responses.
- Return the default personality if loading a cross-compile
personality file failed.
- Do not complain about newlines when validating package versions.
- Properly detect strndup() on Windows when building with Meson.
* Enhancements:
- A new --shared option and WantDefaultStatic cross-compile
configuration option have been added. This allows for toolchains
to specify that static linking should be used by default.
- Support for the PKG_CONFIG_MSVC_SYNTAX environment variable has
been added. Patch by Dan Kegel.
- Support for the PKGCONF_PKG_PKGF_DONT_MERGE_SPECIAL_FRAGMENTS
client flag which disables emulation of freedesktop.org pkg-config
fragment merging semantics has been added.
Patch by Karen Arutyunov.
Changes from 1.6.2 to 1.6.3:
----------------------------
* Bug fixes:
- Properly tokenize versions. Versions cannot logically contain
whitespace, as dependency-lists would not properly tokenize if
they could. A diagnostic is generated for malformed version
strings containing whitespace when --validate is used.
* Enhancements:
- CMake support has been dropped. Use Meson to build on Windows.
Changes from 1.6.1 to 1.6.2:
----------------------------
* Bug fixes:
- Fixed a memory leak when deduplicating paths.
- Fixed strndup-related build regression on Windows.
* Enhancements:
- Added pkgconf-lite variant. pkgconf-lite is a stripped down
variant of pkgconf that only includes pkg-config features.
- Added --modversion description to pkgconf(1) man page.
Changes from 1.6.0 to 1.6.1:
----------------------------
* Bug fixes:
- Fixed an issue where a personality may not be properly selected
due to argv[0] containing a full path.
- Fixed a regression where having an empty PKG_CONFIG_LIBDIR
environment variable would not eliminate the default search
paths.
- Use POSIX realpath(3) instead of readlink() for deduplicating the
search path. Use _fullpath() on Windows for the same purpose.
- The dequoting logic for tuples has been improved to ensure that
quotes *inside* a value remain quoted when necessary.
Changes from 1.5.4 to 1.6.0:
----------------------------
* Bug fixes:
- Fixed issue where packages which referenced missing packages in
Requires.private may have crashed due to memory corruption issues
in some circumstances.
- Fixed warnings reported by GCC 8 diagnostics.
* Enhancements:
- Add LIBPKGCONF_VERSION and LIBPKGCONF_VERSION_STR macros for
determining libpkgconf version.
- Add pkgconf_fragment_copy_list() to copy a fragment list to
another fragment list.
Changes from 1.5.3 to 1.5.4:
----------------------------
* Bug fixes:
- fix build on Windows with Meson
- fix edge cases for path canonicalization (especially on Windows)
Changes from 1.5.2 to 1.5.3:
----------------------------
* Security fixes:
- Fix edge cases involving dequoting zero-length tuples that can lead to a
buffer overflow under the right circumstances. Thanks to A. Wilcox for
reporting and supplying a patch. (MR 3)
Changes from 1.5.1 to 1.5.2:
----------------------------
* Bug fixes:
- Ensure environment variables override values learned from personality files
or built-in defaults.
* Documentation enhancements:
- Add pkgconf-personality(5) manpage documenting the personality file format.
Changes from 1.5.0 to 1.5.1:
----------------------------
* Bug fixes:
- fixed a crash with some invalid multi-line .pc files
Changes from 1.4.2 to 1.5.0:
---------------------------
* Administrative:
- The git repository has moved to <https://git.dereferenced.org/pkgconf/pkgconf>,
due to the acquisition of GitHub by Microsoft.
* Overall enhancements:
- pkgconf now supports the proposed Requires.internal pkg-config extension,
by merging it with the Requires.private list (there is no functional difference
between the two in our resolver implementation)
- Support for cross-compilation personalities have been added. To make use of this
functionality, create a file in the new personality.d directory that sits inside
the pkgconfig directory. The personality file format is described in
pc-personality(5). (github #166)
- Support for Haiku has been added, including interpretation of BELIBRARIES and
other toolchain specifics. (github #180)
- Testsuite support can be disabled when building with Meson. (github #175)
* Bug fixes:
- tuples are now appropriately dequoted when added by the parser (github #186).
* Various Windows enhancements:
- CMake supports building with GCC on Windows. (github #179)
- Prefix rewriting has been improved. (github #177)
- PKGCONF_API support has been implemented when building with Meson,
allowing Meson to be used to build pkgconf on Windows. (github #174)
* Documentation fixes:
- The manpages have been linted and fixed. (github #181, #182, #183)
- The description of pkgconf --exists has been corrected. (github #173)
Changes from 1.4.1 to 1.4.2:
----------------------------
* Bug fixes:
- ensure pkgconf_dependency_t nodes have a solution marked when satisfied
by an indirect provider (github #172)
Changes from 1.4.0 to 1.4.1:
----------------------------
* Bug fixes:
- revert some quoting changes because they don't work well with certain
GCC edge cases (github #168)
* Enhancements:
- add limited support for --cflags with --msvc-syntax
Changes from 1.3.7 to 1.4.0:
----------------------------
* Notable libpkgconf API changes:
- pkgconf_pkg_t.requires has been renamed to pkgconf_pkg_t.required for
C++20 compatibility.
* Enhancements:
- pkgconf and libpkgconf has been ported to Windows as native binaries.
- improved compatibility with freedesktop.org pkg-config's ${pc_sysrootdir}
usage pattern.
- do not mention PKG_CONFIG_SKIP_CONFLICTS environmental variable when
simplified errors are requested, as with PKG_CONFIG_PATH.
- the dependency solver now stores solutions to dependency graph elements
it visits, allowing for the dependency graph to be incrementally solved.
this improves dependency solving time by an order of magnitude in most
cases.
- new --env option allows for exporting cflags/libs fragments as export
variables
- new support for building pkgconf with CMake and Meson
- improved compiler warning flag detection on autoconf and CMake
- removed PKGCONF_BUFSIZE allocations from the stack where possible
- allow for customizing the way fragment lists are rendered using a callback API
- new support for --msvc-syntax output using the new fragment rendering callbacks
- fragments are now quoted according to POSIX literal rules
- new variables on the pkg-config builtin:
- ${pc_system_includedirs}: the system includedir search path known by pkgconf
- ${pc_system_libdirs}: the system libdir search path known by pkgconf
- new manpages:
- pc(5) describing pkgconf's interpretation of pkg-config .pc files
- pkg.m4(7) describing the autotools macros bundled with pkgconf
* Bug fixes:
- fix pkgconf_pkg_t.id generation on native Windows where either \ or / are usable
as path separator.
- add missing --modversion to --help output
- do not evaluate module paths for modules that are not actually on disk
- ensure we work on a zeroed buffer prior to calling realpath(2) with it
- fix path deduplication edge case when cache-inodes feature is unavailable
- fix path rewriting regression with PKG_CONFIG_SYSROOT_DIR when
PKG_CONFIG_SYSROOT_DIR is set to /
- fix crash in edge case where a .pc file has misquoting in a fragment list.
- fix logic edge case when comparing relocated paths
Changes from 1.3.6 to 1.3.7:
----------------------------
* Enhancements:
- improved diagnostics for malformed packages.
* Bug fixes:
- reject packages which contain incomplete metadata in post-parse phase.
Changes from 1.3.5 to 1.3.6:
----------------------------
* Enhancements:
- add many cflags to the protected set: -Wa, -Wl, -Wp, -ansi, -std=, -stdlib=,
-pedantic, -pthread, -trigraphs, -nostdinc, -nostdlibinc, -nobuiltininc.
* Bug fixes:
- handle -include cflag fragments properly.
Changes from 1.3.4 to 1.3.5:
----------------------------
* Bug fixes:
- fix --variable output for compatibility some broken configure scripts when they
request the same variable from multiple packages
Changes from 1.3.3 to 1.3.4:
----------------------------
* Bug fixes:
- fix a quoting issue exposed by the Go testsuite
Changes from 1.3.2 to 1.3.3:
----------------------------
* Bug fixes:
- back out disabling the dependency resolver for single-package queries, it caused
too many regressions.
* Enhancements:
- allow explicitly disabling the dependency resolver via new environment variable,
PKG_CONFIG_MINIMUM_TRAVERSE_DEPTH=1. while pkgconf could already do this using
--minimum-traverse-depth=1, other pkg-config implementations do not have this
option, so adding an environment variable allows to make better use of this
feature (other implementations won't error due to unknown option this way)
Changes from 1.3.1 to 1.3.2:
----------------------------
* Bug fixes:
- rewrite handling of --modversion, --print-variables and --variable to not require
the dependency resolver
- ensure we disable the dependency resolver in all cases where it is a single-package
query (1.3.1 did not go far enough)
Changes from 1.3.0 to 1.3.1:
----------------------------
* Features:
- implement --short-errors
* Bug fixes:
- only consider a single package at a time with --print-requires, --print-requires-private,
--print-provides, --modversion, --print-variable and --print-variables
* Enhancements:
- synchronized latest freedesktop.org changes to pkg.m4
- improve error reporting with legacy --atleast-version and similar flags.
Changes from 1.2.0 to 1.3.0:
----------------------------
* Features:
- pkgconf --debug now provides a facility for tracing most relevant libpkgconf operations
- libpkgconf: add warn and trace handlers for warnings
- replace realpath() with faster, lighter weight path normalization function (github #112)
- pkgconf CLI now emulates pkg-config quoting rules precisely, while allowing direct access
to the actual fragments via libpkgconf
* Bug fixes:
- pkg: properly separate static and virtual packages so they are not inappropriately
optimized out of the dependency graph (github #108)
- argvsplit: do not consider ' and " to have similar rules to escape sequences (github #111)
- pkg: strip trailing whitespace when parsing .pc files
* Enhancements:
- argvsplit basically rewritten from scratch
- many code fixes spotted by coverity
- add PKG_CONFIG_DONT_RELOCATE_PATHS and --dont-relocate-paths environment variables to
disable path relocation feature if needed
- remove extra whitespace that was present for compatibility with older pkg-config releases
(github #113)
Changes from 1.1.0 to 1.2.0:
----------------------------
* Features:
- new --path option lists the .pc files which provided the requested dependencies
- new path relocation API: pkgconf_path_relocate(), which wraps functions such as
realpath() and cygwin_conv_path().
- new --with-path option adds a path to the search list
- new --define-prefix and --dont-define-prefix features enable automatic prefix
detection for relocatable SDKs. this is mostly useful on windows.
* Bug fixes:
- fragments: fix even more edge cases involving token concatenation
- path lists: don't attempt to collect path inodes if the filter is disabled
- path lists: explicitly avoid uninitialised data for the path inode cache
- client: properly handle --keep-system-cflags and --keep-system-libs
* Enhancements:
- windows: build libpkgconf as a DLL
- fragments: only munge fragments if sysroot_dir is actually set
- overall API: resolver flags have been moved to being a client-object setting
instead of used for every function invocation
Changes from 1.0.1 to 1.1.0:
----------------------------
* Features:
- new Provides system allows alternate .pc files to provide a dependency
- stable library API (with documentation): http://pkgconf.readthedocs.io/
* Enhancements:
- make it possible to programmatically declare dependencies instead of just using the parser
- testsuite migrated to run under kyua
- provide a libpkgconf.pc file for consumers to use
- pkgconf client: new --pure flag to enable dependency graph optimization in --static mode
- significant .pc parser speedups using bsearch(3).
- handle -idirafter in the same way as -isystem CFLAGS
- learn toolchain "system" paths from GCC environment variables, if present
- filter duplicate PKG_CONFIG_PATH (and other) entries by inode
* Bug fixes:
- fragments: fix another edge case involving empty tokens being concatenated onto previous tokens
(github #99)
- libpkgconf: remove dependencies on config.h in public headers
Changes from 1.0.0 to 1.0.1:
----------------------------
* Enhancements:
- new stub implementation of --print-provides (github #95)
* Bug fixes:
- fragments: fix an edge case involving path-only fragments and PKG_CONFIG_SYSROOT_DIR (github #94)
Changes from 0.9.12 to 1.0.0:
-----------------------------
* Features:
- new library: libpkgconf
* Enhancements:
- testsuite: use an explicit prefix on all tests
- build: switch to automake
* Bug fixes:
- cast all usage of ctype(3) functions
- do not expand variables passed via --define-variable for compatibility with pkg-config 0.29
- let the CFLAGS being user settable
Changes from 0.9.11 to 0.9.12:
------------------------------
* Features:
- add --list-package-names
* Enhancements:
- ensure -I and -L are never pushed back
* Bug fixes:
- fix implicit conversion warnings with variables over 31bits
Changes from 0.9.10 to 0.9.11:
------------------------------
* Features:
- add --validate
* Enhancements:
- add large file support checks in autoconf
* Bug fixes:
- fix private lib deduplication
- handle --static correctly in some more esoteric scenarios
Changes from 0.9.9 to 0.9.10:
-----------------------------
* Features:
* Enhancements:
* Bug fixes:
- Fix parser when dealing with commented lines
Changes from 0.9.8 to 0.9.9:
----------------------------
* Features:
- add a sub out --print-provides
* Enhancements:
* Bug fixes:
- Fix parser when dealing with comments in fields
Changes from 0.9.7 to 0.9.8:
----------------------------
* Features:
* Enhancements:
- Convert manpages to mdoc(7)
* Bug fixes:
- Fix parsing multiline fields
Changes from 0.9.6 to 0.9.7:
----------------------------
* Features:
* Enhancements:
- Convert manpages to mdoc(7)
* Bug fixes:
- Fix parsing multiline fields
Changes from 0.9.5 to 0.9.6:
----------------------------
* Features:
- add a sub --debug
* Enhancements:
- Do not hardcode non-posix install(1)
* Bug fixes:
- fix --with-system-includedir and --with-system-libdir behaviour
Changes from 0.9.4 to 0.9.5:
----------------------------
* Features:
* Enhancements:
- Make all variables but CFLAGS and LIBS case sensitive
* Bug fixes:
Changes from 0.9.3 to 0.9.4:
----------------------------
* Features:
- Add a pkgconf(1) manpage
* Enhancements:
- Improve support for MacOS -framework
* Bug fixes:
Changes from 0.9.2 to 0.9.3:
----------------------------
* Features:
- Add support for CFLAGS.private
* Enhancements:
- Support out of source build
- Improved private libs deduplication
* Bug fixes:
Changes from 0.9.1 to 0.9.2:
----------------------------
* Features:
* Enhancements:
* Bug fixes:
- Fix PKG_CONFIG_PATH being ignored when a .pc is directly supplied from
command line
Changes from 0.9.0 to 0.9.1:
----------------------------
* Features:
* Enhancements:
- --simulate: print depgraph operations
- --simulate: print bytecode program as a human-readable AST
* Bug fixes:
- reset parser state on new package atom
Changes from 0.8.12 to 0.9.0:
----------------------------
* Features:
* Enhancements:
- Rework the internal cache API
- Rework the internal code to use the new pkg_list_t framework
- Rework PKG_CONFIG_PATH handling code
* Bug fixes:
- fix multi-recursion with -framework
+130
View File
@@ -0,0 +1,130 @@
# pkgconf [![test](https://github.com/pkgconf/pkgconf/actions/workflows/test.yml/badge.svg)](https://github.com/pkgconf/pkgconf/actions/workflows/test.yml)
`pkgconf` is a program which helps to configure compiler and linker flags for
development libraries. It is a superset of the functionality provided by
pkg-config from freedesktop.org, but does not provide bug-compatibility with
the original pkg-config.
`libpkgconf` is a library which provides access to most of `pkgconf`'s functionality,
to allow other tooling such as compilers and IDEs to discover and use libraries
configured by pkgconf.
## release tarballs
Release tarballs are available on [distfiles.ariadne.space][distfiles].
[distfiles]: https://distfiles.ariadne.space/pkgconf/
## build system setup
If you would like to use the git sources directly, or a snapshot of the
sources from GitHub, you will need to regenerate the autotools build
system artifacts yourself, or use Meson instead. For example, on Alpine:
$ apk add autoconf automake libtool build-base
$ sh ./autogen.sh
## pkgconf-lite
If you only need the original pkg-config functionality, there is also pkgconf-lite,
which builds the `pkgconf` frontend and relevant portions of `libpkgconf` functionality
into a single binary:
$ make -f Makefile.lite
## why `pkgconf` over original `pkg-config`?
pkgconf builds a flattened directed dependency graph, which allows for more insight
into relationships between dependencies, allowing for some link-time dependency
optimization, which allows for the user to more conservatively link their binaries,
which may be helpful in some environments, such as when prelink(1) is being used.
The solver is also optimized to handle large dependency graphs with hundreds of
thousands of edges, which can be seen in any project using the Abseil frameworks
for example.
In addition, pkgconf has full support for virtual packages, while the original
pkg-config does not, as well as fully supporting `Conflicts` at dependency
resolution time, which is more efficient than checking for `Conflicts` while
walking the dependency graph.
## linker flags optimization
pkgconf, when used effectively, can make optimizations to avoid overlinking binaries.
This functionality depends on the pkg-config module properly declaring its dependency
tree instead of using `Libs` and `Cflags` fields to directly link against other modules
which have pkg-config metadata files installed.
The practice of using `Libs` and `Cflags` to describe unrelated dependencies is
not recommended in [Dan Nicholson's pkg-config tutorial][fd-tut] for this reason.
[fd-tut]: http://people.freedesktop.org/~dbn/pkg-config-guide.html
## bug compatibility with original pkg-config
In general, we do not provide bug-level compatibility with pkg-config.
What that means is, if you feel that there is a legitimate regression versus pkg-config,
do let us know, but also make sure that the .pc files are valid and follow the rules of
the [pkg-config tutorial][fd-tut], as most likely fixing them to follow the specified
rules will solve the problem.
## debug output
Please use only the stable interfaces to query pkg-config. Do not screen-scrape the
output from `--debug`: this is sent to `stderr` for a reason, it is not intended to be
scraped. The `--debug` output is **not** a stable interface, and should **never** be
depended on as a source of information. If you need a stable interface to query pkg-config
which is not covered, please get in touch.
## compiling `pkgconf` and `libpkgconf` on UNIX
pkgconf is basically compiled the same way any other autotools-based project is
compiled:
$ ./configure
$ make
$ sudo make install
If you are installing pkgconf into a custom prefix, such as `/opt/pkgconf`, you will
likely want to define the default system includedir and libdir for your toolchain.
To do this, use the `--with-system-includedir` and `--with-system-libdir` configure
flags like so:
$ ./configure \
--prefix=/opt/pkgconf \
--with-system-libdir=/lib:/usr/lib \
--with-system-includedir=/usr/include
$ make
$ sudo make install
## compiling `pkgconf` and `libpkgconf` with Meson (usually for Windows)
pkgconf is compiled using [Meson](https://mesonbuild.com) on Windows. In theory, you could also use
Meson to build on UNIX, but this is not recommended at this time as pkgconf is typically built
much earlier than Meson.
$ meson setup build -Dtests=disabled
$ meson compile -C build
$ meson install -C build
There are a few defines such as `SYSTEM_LIBDIR`, `PKGCONFIGDIR` and `SYSTEM_INCLUDEDIR`.
However, on Windows, the default `PKGCONFIGDIR` value is usually overridden at runtime based
on path relocation.
## pkg-config symlink
If you want pkgconf to be used when you invoke `pkg-config`, you should install a
symlink for this. We do not do this for you, as we believe it is better for vendors
to make this determination themselves.
$ ln -sf pkgconf /usr/bin/pkg-config
## contacts
You can report bugs at <https://github.com/pkgconf/pkgconf/issues>.
There is a mailing list at <https://lists.sr.ht/~kaniini/pkgconf>.
You can contact us via IRC at `#pkgconf` at `irc.oftc.net`.
+87
View File
@@ -0,0 +1,87 @@
#! /bin/sh
TOP_DIR=$(dirname $0)
LAST_DIR=$PWD
if test ! -f $TOP_DIR/configure.ac ; then
echo "You must execute this script from the top level directory."
exit 1
fi
AUTOCONF=${AUTOCONF:-autoconf}
ACLOCAL=${ACLOCAL:-aclocal}
AUTOHEADER=${AUTOHEADER:-autoheader}
AUTOMAKE=${AUTOMAKE:-automake}
LIBTOOLIZE=${LIBTOOLIZE:-libtoolize}
dump_help_screen ()
{
echo "Usage: $0 [options]"
echo
echo "options:"
echo " -n skip CVS changelog creation"
echo " -h,--help show this help screen"
echo
exit 0
}
parse_options ()
{
while test "$1" != "" ; do
case $1 in
-h|--help)
dump_help_screen
;;
-n)
SKIP_CVS_CHANGELOG=yes
;;
*)
echo Invalid argument - $1
dump_help_screen
;;
esac
shift
done
}
run_or_die ()
{
COMMAND=$1
# check for empty commands
if test -z "$COMMAND" ; then
echo "*warning* no command specified"
return 1
fi
shift;
OPTIONS="$@"
# print a message
echo -n "*info* running $COMMAND"
if test -n "$OPTIONS" ; then
echo " ($OPTIONS)"
else
echo
fi
# run or die
$COMMAND $OPTIONS ; RESULT=$?
if test $RESULT -ne 0 ; then
echo "*error* $COMMAND failed. (exit code = $RESULT)"
exit 1
fi
return 0
}
parse_options "$@"
cd $TOP_DIR
run_or_die $ACLOCAL
run_or_die $AUTOHEADER
run_or_die $AUTOCONF
run_or_die $LIBTOOLIZE --install
run_or_die $AUTOMAKE --add-missing
+368
View File
@@ -0,0 +1,368 @@
/*
* bomtool/main.c
* main() routine, printer functions
*
* Copyright (c) 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019
* pkgconf authors (see AUTHORS).
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* This software is provided 'as is' and without any warranty, express or
* implied. In no event shall the authors be liable for any damages arising
* from the use of this software.
*/
#include "libpkgconf/config.h"
#include <libpkgconf/stdinc.h>
#include <libpkgconf/libpkgconf.h>
#include "getopt_long.h"
#define PKG_VERSION (((uint64_t) 1) << 1)
#define PKG_ABOUT (((uint64_t) 1) << 2)
#define PKG_HELP (((uint64_t) 1) << 3)
static const char *spdx_version = "SPDX-2.2";
static const char *bom_license = "CC0-1.0";
static const char *document_ref = "SPDXRef-DOCUMENT";
static pkgconf_client_t pkg_client;
static uint64_t want_flags;
static size_t maximum_package_count = 0;
static int maximum_traverse_depth = 2000;
FILE *error_msgout = NULL;
static bool
error_handler(const char *msg, const pkgconf_client_t *client, void *data)
{
(void) client;
(void) data;
fprintf(error_msgout, "%s", msg);
return true;
}
static const char *
sbom_spdx_identity(pkgconf_pkg_t *pkg)
{
static char buf[PKGCONF_ITEM_SIZE];
snprintf(buf, sizeof buf, "%sC64%s", pkg->id, pkg->version);
return buf;
}
static const char *
sbom_name(pkgconf_pkg_t *world)
{
static char buf[PKGCONF_BUFSIZE];
pkgconf_node_t *node;
pkgconf_strlcpy(buf, "SBOM-SPDX", sizeof buf);
PKGCONF_FOREACH_LIST_ENTRY(world->required.head, node)
{
pkgconf_dependency_t *dep = node->data;
pkgconf_pkg_t *match = dep->match;
if ((dep->flags & PKGCONF_PKG_DEPF_QUERY) != PKGCONF_PKG_DEPF_QUERY)
continue;
if (!dep->match)
continue;
pkgconf_strlcat(buf, "-", sizeof buf);
pkgconf_strlcat(buf, sbom_spdx_identity(match), sizeof buf);
}
return buf;
}
static void
write_sbom_header(pkgconf_client_t *client, pkgconf_pkg_t *world)
{
(void) client;
(void) world;
printf("SPDXVersion: %s\n", spdx_version);
printf("DataLicense: %s\n", bom_license);
printf("SPDXID: %s\n", document_ref);
printf("DocumentName: %s\n", sbom_name(world));
printf("DocumentNamespace: https://spdx.org/spdxdocs/bomtool-%s\n", PACKAGE_VERSION);
printf("Creator: Tool: bomtool %s\n", PACKAGE_VERSION);
printf("\n\n");
}
static const char *
sbom_identity(pkgconf_pkg_t *pkg)
{
static char buf[PKGCONF_ITEM_SIZE];
snprintf(buf, sizeof buf, "%s@%s", pkg->id, pkg->version);
return buf;
}
static void
write_sbom_package(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *unused)
{
(void) client;
(void) unused;
if (pkg->flags & PKGCONF_PKG_PROPF_VIRTUAL)
return;
printf("##### Package: %s\n\n", sbom_identity(pkg));
printf("PackageName: %s\n", sbom_identity(pkg));
printf("SPDXID: SPDXRef-Package-%s\n", sbom_spdx_identity(pkg));
printf("PackageVersion: %s\n", pkg->version);
printf("PackageDownloadLocation: NOASSERTION\n");
printf("PackageVerificationCode: NOASSERTION\n");
/* XXX: What about projects? */
if (pkg->maintainer != NULL)
printf("PackageSupplier: Person: %s\n", pkg->maintainer);
if (pkg->url != NULL)
printf("PackageHomePage: %s\n", pkg->url);
printf("PackageLicenseDeclared: %s\n", pkg->license != NULL ? pkg->license : "NOASSERTION");
if (pkg->copyright != NULL)
printf("PackageCopyrightText: <text>%s</text>\n", pkg->copyright);
if (pkg->description != NULL)
printf("PackageSummary: <text>%s</text>\n", pkg->description);
printf("\n\n");
}
static void
write_sbom_relationships(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *unused)
{
(void) client;
(void) unused;
char baseref[PKGCONF_ITEM_SIZE];
pkgconf_node_t *node;
if (pkg->flags & PKGCONF_PKG_PROPF_VIRTUAL)
return;
snprintf(baseref, sizeof baseref, "SPDXRef-Package-%sC64%s", pkg->id, pkg->version);
PKGCONF_FOREACH_LIST_ENTRY(pkg->required.head, node)
{
pkgconf_dependency_t *dep = node->data;
pkgconf_pkg_t *match = dep->match;
if (!dep->match)
continue;
printf("Relationship: %s DEPENDS_ON SPDXRef-Package-%s\n", baseref, sbom_spdx_identity(match));
printf("Relationship: SPDXRef-Package-%s DEPENDENCY_OF %s\n", sbom_spdx_identity(match), baseref);
}
PKGCONF_FOREACH_LIST_ENTRY(pkg->requires_private.head, node)
{
pkgconf_dependency_t *dep = node->data;
pkgconf_pkg_t *match = dep->match;
if (!dep->match)
continue;
printf("Relationship: %s DEPENDS_ON SPDXRef-Package-%s\n", baseref, sbom_spdx_identity(match));
printf("Relationship: SPDXRef-Package-%s DEV_DEPENDENCY_OF %s\n", sbom_spdx_identity(match), baseref);
}
if (pkg->required.head != NULL || pkg->requires_private.head != NULL)
printf("\n\n");
}
static bool
generate_sbom_from_world(pkgconf_client_t *client, pkgconf_pkg_t *world)
{
int eflag;
pkgconf_node_t *node;
write_sbom_header(client, world);
eflag = pkgconf_pkg_traverse(client, world, write_sbom_package, NULL, maximum_traverse_depth, 0);
if (eflag != PKGCONF_PKG_ERRF_OK)
return false;
eflag = pkgconf_pkg_traverse(client, world, write_sbom_relationships, NULL, maximum_traverse_depth, 0);
if (eflag != PKGCONF_PKG_ERRF_OK)
return false;
PKGCONF_FOREACH_LIST_ENTRY(world->required.head, node)
{
pkgconf_dependency_t *dep = node->data;
pkgconf_pkg_t *match = dep->match;
if (!dep->match)
continue;
printf("Relationship: %s DESCRIBES SPDXRef-Package-%s\n", document_ref, sbom_spdx_identity(match));
}
return true;
}
static int
version(void)
{
printf("bomtool %s\n", PACKAGE_VERSION);
return EXIT_SUCCESS;
}
static int
about(void)
{
printf("bomtool (%s %s)\n", PACKAGE_NAME, PACKAGE_VERSION);
printf("Copyright (c) 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021\n");
printf(" pkgconf authors (see AUTHORS in documentation directory).\n\n");
printf("Permission to use, copy, modify, and/or distribute this software for any\n");
printf("purpose with or without fee is hereby granted, provided that the above\n");
printf("copyright notice and this permission notice appear in all copies.\n\n");
printf("This software is provided 'as is' and without any warranty, express or\n");
printf("implied. In no event shall the authors be liable for any damages arising\n");
printf("from the use of this software.\n\n");
printf("Report bugs at <%s>.\n", PACKAGE_BUGREPORT);
return EXIT_SUCCESS;
}
static int
usage(void)
{
printf("usage: bomtool [--flags] [modules]\n");
printf("\nbasic options:\n\n");
printf(" --help this message\n");
printf(" --about print bomtool version and license to stdout\n");
printf(" --version print bomtool version to stdout\n");
return EXIT_SUCCESS;
}
int
main(int argc, char *argv[])
{
int ret = EXIT_SUCCESS;
pkgconf_list_t pkgq = PKGCONF_LIST_INITIALIZER;
unsigned int want_client_flags = PKGCONF_PKG_PKGF_SEARCH_PRIVATE;
pkgconf_cross_personality_t *personality = pkgconf_cross_personality_default();
pkgconf_pkg_t world = {
.id = "virtual:world",
.realname = "virtual world package",
.flags = PKGCONF_PKG_PROPF_STATIC | PKGCONF_PKG_PROPF_VIRTUAL,
};
error_msgout = stderr;
struct pkg_option options[] = {
{ "version", no_argument, &want_flags, PKG_VERSION, },
{ "about", no_argument, &want_flags, PKG_ABOUT, },
{ "help", no_argument, &want_flags, PKG_HELP, },
{ NULL, 0, NULL, 0 }
};
while ((ret = pkg_getopt_long_only(argc, argv, "", options, NULL)) != -1)
{
switch (ret)
{
case '?':
case ':':
return EXIT_FAILURE;
default:
break;
}
}
pkgconf_client_init(&pkg_client, error_handler, NULL, personality);
/* we have determined what features we want most likely. in some cases, we override later. */
pkgconf_client_set_flags(&pkg_client, want_client_flags);
/* at this point, want_client_flags should be set, so build the dir list */
pkgconf_client_dir_list_build(&pkg_client, personality);
if ((want_flags & PKG_ABOUT) == PKG_ABOUT)
return about();
if ((want_flags & PKG_VERSION) == PKG_VERSION)
return version();
if ((want_flags & PKG_HELP) == PKG_HELP)
return usage();
while (1)
{
const char *package = argv[pkg_optind];
if (package == NULL)
break;
/* check if there is a limit to the number of packages allowed to be included, if so and we have hit
* the limit, stop adding packages to the queue.
*/
if (maximum_package_count > 0 && pkgq.length > maximum_package_count)
break;
while (isspace((unsigned char)package[0]))
package++;
/* skip empty packages */
if (package[0] == '\0') {
pkg_optind++;
continue;
}
if (argv[pkg_optind + 1] == NULL || !PKGCONF_IS_OPERATOR_CHAR(*(argv[pkg_optind + 1])))
{
pkgconf_queue_push(&pkgq, package);
pkg_optind++;
}
else
{
char packagebuf[PKGCONF_BUFSIZE];
snprintf(packagebuf, sizeof packagebuf, "%s %s %s", package, argv[pkg_optind + 1], argv[pkg_optind + 2]);
pkg_optind += 3;
pkgconf_queue_push(&pkgq, packagebuf);
}
}
if (pkgq.head == NULL)
{
fprintf(stderr, "Please specify at least one package name on the command line.\n");
ret = EXIT_FAILURE;
goto out;
}
ret = EXIT_SUCCESS;
if (!pkgconf_queue_solve(&pkg_client, &pkgq, &world, maximum_traverse_depth))
{
ret = EXIT_FAILURE;
goto out;
}
if (!generate_sbom_from_world(&pkg_client, &world))
{
ret = EXIT_FAILURE;
goto out;
}
out:
pkgconf_solution_free(&pkg_client, &world);
pkgconf_queue_free(&pkgq);
pkgconf_cross_personality_deinit(personality);
pkgconf_client_deinit(&pkg_client);
return ret;
}
+643
View File
@@ -0,0 +1,643 @@
/* $OpenBSD: getopt_long.c,v 1.21 2006/09/22 17:22:05 millert Exp $ */
/* $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $ */
/*
* Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Sponsored in part by the Defense Advanced Research Projects
* Agency (DARPA) and Air Force Research Laboratory, Air Force
* Materiel Command, USAF, under agreement number F39502-99-1-0512.
*/
/*-
* Copyright (c) 2000 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Dieter Baron and Thomas Klausner.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "getopt_long.h"
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef _WIN32
#include <unistd.h>
#endif
#define PKGCONF_HACK_LOGICAL_OR_ALL_VALUES
int pkg_opterr = 1; /* if error message should be printed */
int pkg_optind = 1; /* index into parent argv vector */
int pkg_optopt = '?'; /* character checked for validity */
int pkg_optreset; /* reset getopt */
char *pkg_optarg; /* argument associated with option */
#define PRINT_ERROR ((pkg_opterr) && (*options != ':'))
#define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */
#define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */
#define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */
/* return values */
#define BADCH (int)'?'
#define BADARG ((*options == ':') ? (int)':' : (int)'?')
#define INORDER (int)1
/* add some padding to EMSG to avoid overrun */
#define EMSG "\0\0\0\0"
#ifdef GNU_COMPATIBLE
#define NO_PREFIX (-1)
#define D_PREFIX 0
#define DD_PREFIX 1
#define W_PREFIX 2
#endif
static int getopt_internal(int, char * const *, const char *,
const struct pkg_option *, int *, int);
static int parse_long_options(char * const *, const char *,
const struct pkg_option *, int *, int, int);
static int gcd(int, int);
static void permute_args(int, int, int, char * const *);
static char *place = EMSG; /* option letter processing */
/* XXX: set pkg_optreset to 1 rather than these two */
static int nonopt_start = -1; /* first non option argument (for permute) */
static int nonopt_end = -1; /* first option after non options (for permute) */
/* Error messages */
static const char recargchar[] = "option requires an argument -- %c";
static const char illoptchar[] = "illegal option -- %c"; /* From P1003.2 */
#ifdef GNU_COMPATIBLE
static int dash_prefix = NO_PREFIX;
static const char gnuoptchar[] = "invalid option -- %c";
static const char recargstring[] = "option `%s%s' requires an argument";
static const char ambig[] = "option `%s%.*s' is ambiguous";
static const char noarg[] = "option `%s%.*s' doesn't allow an argument";
static const char illoptstring[] = "unrecognized option `%s%s'";
#else
static const char recargstring[] = "option requires an argument -- %s";
static const char ambig[] = "ambiguous option -- %.*s";
static const char noarg[] = "option doesn't take an argument -- %.*s";
static const char illoptstring[] = "unknown option -- %s";
#endif
/*
* Compute the greatest common divisor of a and b.
*/
static int
gcd(int a, int b)
{
int c;
c = a % b;
while (c != 0) {
a = b;
b = c;
c = a % b;
}
return (b);
}
/*
* Exchange the block from nonopt_start to nonopt_end with the block
* from nonopt_end to opt_end (keeping the same order of arguments
* in each block).
*/
static void
permute_args(int panonopt_start, int panonopt_end, int opt_end,
char * const *nargv)
{
int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
char *swap;
/*
* compute lengths of blocks and number and size of cycles
*/
nnonopts = panonopt_end - panonopt_start;
nopts = opt_end - panonopt_end;
ncycle = gcd(nnonopts, nopts);
cyclelen = (opt_end - panonopt_start) / ncycle;
for (i = 0; i < ncycle; i++) {
cstart = panonopt_end+i;
pos = cstart;
for (j = 0; j < cyclelen; j++) {
if (pos >= panonopt_end)
pos -= nnonopts;
else
pos += nopts;
swap = nargv[pos];
/* LINTED const cast */
((char **) nargv)[pos] = nargv[cstart];
/* LINTED const cast */
((char **)nargv)[cstart] = swap;
}
}
}
/*
* parse_long_options --
* Parse long options in argc/argv argument vector.
* Returns -1 if short_too is set and the option does not match long_options.
*/
static int
parse_long_options(char * const *nargv, const char *options,
const struct pkg_option *long_options, int *idx, int short_too, int flags)
{
char *current_argv, *has_equal;
#ifdef GNU_COMPATIBLE
char *current_dash;
#endif
size_t current_argv_len;
int i, match, exact_match, second_partial_match;
current_argv = place;
#ifdef GNU_COMPATIBLE
switch (dash_prefix) {
case D_PREFIX:
current_dash = "-";
break;
case DD_PREFIX:
current_dash = "--";
break;
case W_PREFIX:
current_dash = "-W ";
break;
default:
current_dash = "";
break;
}
#endif
match = -1;
exact_match = 0;
second_partial_match = 0;
pkg_optind++;
if ((has_equal = strchr(current_argv, '=')) != NULL) {
/* argument found (--option=arg) */
current_argv_len = has_equal - current_argv;
has_equal++;
} else
current_argv_len = strlen(current_argv);
for (i = 0; long_options[i].name; i++) {
/* find matching long option */
if (strncmp(current_argv, long_options[i].name,
current_argv_len))
continue;
if (strlen(long_options[i].name) == current_argv_len) {
/* exact match */
match = i;
exact_match = 1;
break;
}
/*
* If this is a known short option, don't allow
* a partial match of a single character.
*/
if (short_too && current_argv_len == 1)
continue;
if (match == -1) /* first partial match */
match = i;
else if ((flags & FLAG_LONGONLY) ||
long_options[i].has_arg !=
long_options[match].has_arg ||
long_options[i].flag != long_options[match].flag ||
long_options[i].val != long_options[match].val)
second_partial_match = 1;
}
if (!exact_match && second_partial_match) {
/* ambiguous abbreviation */
if (PRINT_ERROR) {
fprintf(stderr, "pkgconf: ");
fprintf(stderr, ambig,
#ifdef GNU_COMPATIBLE
current_dash,
#endif
(int)current_argv_len,
current_argv);
fprintf(stderr, "\n");
}
pkg_optopt = 0;
return (BADCH);
}
if (match != -1) { /* option found */
if (long_options[match].has_arg == no_argument
&& has_equal) {
if (PRINT_ERROR) {
fprintf(stderr, "pkgconf: ");
fprintf(stderr, noarg,
#ifdef GNU_COMPATIBLE
current_dash,
#endif
(int)current_argv_len,
current_argv);
fprintf(stderr, "\n");
}
/*
* XXX: GNU sets pkg_optopt to val regardless of flag
*/
if (long_options[match].flag == NULL)
pkg_optopt = (int)long_options[match].val;
else
pkg_optopt = 0;
#ifdef GNU_COMPATIBLE
return (BADCH);
#else
return (BADARG);
#endif
}
if (long_options[match].has_arg == required_argument ||
long_options[match].has_arg == optional_argument) {
if (has_equal)
pkg_optarg = has_equal;
else if (long_options[match].has_arg ==
required_argument) {
/*
* optional argument doesn't use next nargv
*/
pkg_optarg = nargv[pkg_optind++];
}
}
if ((long_options[match].has_arg == required_argument)
&& (pkg_optarg == NULL)) {
/*
* Missing argument; leading ':' indicates no error
* should be generated.
*/
if (PRINT_ERROR) {
fprintf(stderr, "pkgconf: ");
fprintf(stderr, recargstring,
#ifdef GNU_COMPATIBLE
current_dash,
#endif
current_argv);
fprintf(stderr, "\n");
}
/*
* XXX: GNU sets pkg_optopt to val regardless of flag
*/
if (long_options[match].flag == NULL)
pkg_optopt = (int)long_options[match].val;
else
pkg_optopt = 0;
--pkg_optind;
return (BADARG);
}
} else { /* unknown option */
if (short_too) {
--pkg_optind;
return (-1);
}
if (PRINT_ERROR) {
fprintf(stderr, "pkgconf: ");
fprintf(stderr, illoptstring,
#ifdef GNU_COMPATIBLE
current_dash,
#endif
current_argv);
fprintf(stderr, "\n");
}
pkg_optopt = 0;
return (BADCH);
}
if (idx)
*idx = match;
if (long_options[match].flag) {
#ifdef PKGCONF_HACK_LOGICAL_OR_ALL_VALUES
*long_options[match].flag |= long_options[match].val;
#else
*long_options[match].flag = long_options[match].val;
#endif
return (0);
} else
return ((int)long_options[match].val);
}
/*
* getopt_internal --
* Parse argc/argv argument vector. Called by user level routines.
*/
static int
getopt_internal(int nargc, char * const *nargv, const char *options,
const struct pkg_option *long_options, int *idx, int flags)
{
char *oli; /* option letter list index */
int optchar, short_too;
int posixly_correct; /* no static, can be changed on the fly */
if (options == NULL)
return (-1);
/*
* Disable GNU extensions if POSIXLY_CORRECT is set or options
* string begins with a '+'.
*/
posixly_correct = (getenv("POSIXLY_CORRECT") != NULL);
#ifdef GNU_COMPATIBLE
if (*options == '-')
flags |= FLAG_ALLARGS;
else if (posixly_correct || *options == '+')
flags &= ~FLAG_PERMUTE;
#else
if (posixly_correct || *options == '+')
flags &= ~FLAG_PERMUTE;
else if (*options == '-')
flags |= FLAG_ALLARGS;
#endif
if (*options == '+' || *options == '-')
options++;
/*
* XXX Some GNU programs (like cvs) set pkg_optind to 0 instead of
* XXX using pkg_optreset. Work around this braindamage.
*/
if (pkg_optind == 0)
pkg_optind = pkg_optreset = 1;
pkg_optarg = NULL;
if (pkg_optreset)
nonopt_start = nonopt_end = -1;
start:
if (pkg_optreset || !*place) { /* update scanning pointer */
pkg_optreset = 0;
if (pkg_optind >= nargc) { /* end of argument vector */
place = EMSG;
if (nonopt_end != -1) {
/* do permutation, if we have to */
permute_args(nonopt_start, nonopt_end,
pkg_optind, nargv);
pkg_optind -= nonopt_end - nonopt_start;
}
else if (nonopt_start != -1) {
/*
* If we skipped non-options, set pkg_optind
* to the first of them.
*/
pkg_optind = nonopt_start;
}
nonopt_start = nonopt_end = -1;
return (-1);
}
if (*(place = nargv[pkg_optind]) != '-' ||
#ifdef GNU_COMPATIBLE
place[1] == '\0') {
#else
(place[1] == '\0' && strchr(options, '-') == NULL)) {
#endif
place = EMSG; /* found non-option */
if (flags & FLAG_ALLARGS) {
/*
* GNU extension:
* return non-option as argument to option 1
*/
pkg_optarg = nargv[pkg_optind++];
return (INORDER);
}
if (!(flags & FLAG_PERMUTE)) {
/*
* If no permutation wanted, stop parsing
* at first non-option.
*/
return (-1);
}
/* do permutation */
if (nonopt_start == -1)
nonopt_start = pkg_optind;
else if (nonopt_end != -1) {
permute_args(nonopt_start, nonopt_end,
pkg_optind, nargv);
nonopt_start = pkg_optind -
(nonopt_end - nonopt_start);
nonopt_end = -1;
}
pkg_optind++;
/* process next argument */
goto start;
}
if (nonopt_start != -1 && nonopt_end == -1)
nonopt_end = pkg_optind;
/*
* If we have "-" do nothing, if "--" we are done.
*/
if (place[1] != '\0' && *++place == '-' && place[1] == '\0') {
pkg_optind++;
place = EMSG;
/*
* We found an option (--), so if we skipped
* non-options, we have to permute.
*/
if (nonopt_end != -1) {
permute_args(nonopt_start, nonopt_end,
pkg_optind, nargv);
pkg_optind -= nonopt_end - nonopt_start;
}
nonopt_start = nonopt_end = -1;
return (-1);
}
}
/*
* Check long options if:
* 1) we were passed some
* 2) the arg is not just "-"
* 3) either the arg starts with -- we are getopt_long_only()
*/
if (long_options != NULL && place != nargv[pkg_optind] &&
(*place == '-' || (flags & FLAG_LONGONLY))) {
short_too = 0;
#ifdef GNU_COMPATIBLE
dash_prefix = D_PREFIX;
#endif
if (*place == '-') {
place++; /* --foo long option */
#ifdef GNU_COMPATIBLE
dash_prefix = DD_PREFIX;
#endif
} else if (*place != ':' && strchr(options, *place) != NULL)
short_too = 1; /* could be short option too */
optchar = parse_long_options(nargv, options, long_options,
idx, short_too, flags);
if (optchar != -1) {
place = EMSG;
return (optchar);
}
}
if ((optchar = (int)*place++) == (int)':' ||
(optchar == (int)'-' && *place != '\0') ||
(oli = strchr(options, optchar)) == NULL) {
/*
* If the user specified "-" and '-' isn't listed in
* options, return -1 (non-option) as per POSIX.
* Otherwise, it is an unknown option character (or ':').
*/
if (optchar == (int)'-' && *place == '\0')
return (-1);
if (!*place)
++pkg_optind;
#ifdef GNU_COMPATIBLE
if (PRINT_ERROR) {
fprintf(stderr, "pkgconf: ");
fprintf(stderr, posixly_correct ? illoptchar : gnuoptchar,
optchar);
fprintf(stderr, "\n");
}
#else
if (PRINT_ERROR) {
fprintf(stderr, "pkgconf: ");
fprintf(stderr, illoptchar, optchar);
fprintf(stderr, "\n");
}
#endif
pkg_optopt = optchar;
return (BADCH);
}
if (long_options != NULL && optchar == 'W' && oli[1] == ';') {
/* -W long-option */
if (*place) /* no space */
/* NOTHING */;
else if (++pkg_optind >= nargc) { /* no arg */
place = EMSG;
if (PRINT_ERROR) {
fprintf(stderr, "pkgconf: ");
fprintf(stderr, recargchar, optchar);
fprintf(stderr, "\n");
}
pkg_optopt = optchar;
return (BADARG);
} else /* white space */
place = nargv[pkg_optind];
#ifdef GNU_COMPATIBLE
dash_prefix = W_PREFIX;
#endif
optchar = parse_long_options(nargv, options, long_options,
idx, 0, flags);
place = EMSG;
return (optchar);
}
if (*++oli != ':') { /* doesn't take argument */
if (!*place)
++pkg_optind;
} else { /* takes (optional) argument */
pkg_optarg = NULL;
if (*place) /* no white space */
pkg_optarg = place;
else if (oli[1] != ':') { /* arg not optional */
if (++pkg_optind >= nargc) { /* no arg */
place = EMSG;
if (PRINT_ERROR) {
fprintf(stderr, "pkgconf: ");
fprintf(stderr, recargchar, optchar);
fprintf(stderr, "\n");
}
pkg_optopt = optchar;
return (BADARG);
} else
pkg_optarg = nargv[pkg_optind];
}
place = EMSG;
++pkg_optind;
}
/* dump back option letter */
return (optchar);
}
/*
* getopt --
* Parse argc/argv argument vector.
*
* [eventually this will replace the BSD getopt]
*/
int
pkg_getopt(int nargc, char * const *nargv, const char *options)
{
/*
* We don't pass FLAG_PERMUTE to getopt_internal() since
* the BSD getopt(3) (unlike GNU) has never done this.
*
* Furthermore, since many privileged programs call getopt()
* before dropping privileges it makes sense to keep things
* as simple (and bug-free) as possible.
*/
return (getopt_internal(nargc, nargv, options, NULL, NULL, 0));
}
/*
* getopt_long --
* Parse argc/argv argument vector.
*/
int
pkg_getopt_long(int nargc, char * const *nargv, const char *options,
const struct pkg_option *long_options, int *idx)
{
return (getopt_internal(nargc, nargv, options, long_options, idx,
FLAG_PERMUTE));
}
/*
* getopt_long_only --
* Parse argc/argv argument vector.
*/
int
pkg_getopt_long_only(int nargc, char * const *nargv, const char *options,
const struct pkg_option *long_options, int *idx)
{
return (getopt_internal(nargc, nargv, options, long_options, idx,
FLAG_PERMUTE|FLAG_LONGONLY));
}
+70
View File
@@ -0,0 +1,70 @@
/* $NetBSD: getopt.h,v 1.4 2000/07/07 10:43:54 ad Exp $ */
/* $FreeBSD$ */
/*-
* Copyright (c) 2000 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Dieter Baron and Thomas Klausner.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _GETOPT_LONG_H_
#define _GETOPT_LONG_H_
#include <stdint.h>
/*
* GNU-like getopt_long()/getopt_long_only() with 4.4BSD optreset extension.
* getopt() is declared here too for GNU programs.
*/
#define no_argument 0
#define required_argument 1
#define optional_argument 2
struct pkg_option {
/* name of long option */
const char *name;
/*
* one of no_argument, required_argument, and optional_argument:
* whether option takes an argument
*/
int has_arg;
/* if not NULL, set *flag to val when option found */
uint64_t *flag;
/* if flag not NULL, value to set *flag to; else return value */
uint64_t val;
};
int pkg_getopt_long(int, char * const *, const char *,
const struct pkg_option *, int *);
int pkg_getopt_long_only(int, char * const *, const char *,
const struct pkg_option *, int *);
int pkg_getopt(int, char * const [], const char *);
extern char *pkg_optarg; /* getopt(3) external variables */
extern int pkg_optind, pkg_opterr, pkg_optopt;
extern int pkg_optreset; /* getopt(3) external variable */
#endif
File diff suppressed because it is too large Load Diff
+172
View File
@@ -0,0 +1,172 @@
/*
* renderer-msvc.c
* MSVC library syntax renderer
*
* Copyright (c) 2017 pkgconf authors (see AUTHORS).
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* This software is provided 'as is' and without any warranty, express or
* implied. In no event shall the authors be liable for any damages arising
* from the use of this software.
*/
#include <string.h>
#include <stdlib.h>
#include <libpkgconf/libpkgconf.h>
#include "renderer-msvc.h"
static inline bool
fragment_should_quote(const pkgconf_fragment_t *frag)
{
const char *src;
if (frag->data == NULL)
return false;
for (src = frag->data; *src; src++)
{
if (((*src < ' ') ||
(*src >= (' ' + (frag->children.head != NULL ? 1 : 0)) && *src < '$') ||
(*src > '$' && *src < '(') ||
(*src > ')' && *src < '+') ||
(*src > ':' && *src < '=') ||
(*src > '=' && *src < '@') ||
(*src > 'Z' && *src < '^') ||
(*src == '`') ||
(*src > 'z' && *src < '~') ||
(*src > '~')))
return true;
}
return false;
}
static inline size_t
fragment_len(const pkgconf_fragment_t *frag)
{
size_t len = 1;
if (frag->type)
len += 2;
if (frag->data != NULL)
{
len += strlen(frag->data);
if (fragment_should_quote(frag))
len += 2;
}
return len;
}
static inline bool
allowed_fragment(const pkgconf_fragment_t *frag)
{
return !(!frag->type || frag->data == NULL || strchr("DILl", frag->type) == NULL);
}
static size_t
msvc_renderer_render_len(const pkgconf_list_t *list, bool escape)
{
(void) escape;
size_t out = 1; /* trailing nul */
pkgconf_node_t *node;
PKGCONF_FOREACH_LIST_ENTRY(list->head, node)
{
const pkgconf_fragment_t *frag = node->data;
if (!allowed_fragment(frag))
continue;
switch (frag->type)
{
case 'L':
out += 9; /* "/libpath:" */
break;
case 'l':
out += 4; /* ".lib" */
break;
default:
break;
}
out += fragment_len(frag);
}
return out;
}
static void
msvc_renderer_render_buf(const pkgconf_list_t *list, char *buf, size_t buflen, bool escape)
{
pkgconf_node_t *node;
char *bptr = buf;
memset(buf, 0, buflen);
PKGCONF_FOREACH_LIST_ENTRY(list->head, node)
{
const pkgconf_fragment_t *frag = node->data;
size_t buf_remaining = buflen - (bptr - buf);
size_t cnt;
if (!allowed_fragment(frag))
continue;
if (fragment_len(frag) > buf_remaining)
break;
switch(frag->type) {
case 'D':
case 'I':
*bptr++ = '/';
*bptr++ = frag->type;
break;
case 'L':
cnt = pkgconf_strlcpy(bptr, "/libpath:", buf_remaining);
bptr += cnt;
buf_remaining -= cnt;
break;
}
escape = fragment_should_quote(frag);
if (escape)
*bptr++ = '"';
cnt = pkgconf_strlcpy(bptr, frag->data, buf_remaining);
bptr += cnt;
buf_remaining -= cnt;
if (frag->type == 'l')
{
cnt = pkgconf_strlcpy(bptr, ".lib", buf_remaining);
bptr += cnt;
}
if (escape)
*bptr++ = '"';
*bptr++ = ' ';
}
*bptr = '\0';
}
static const pkgconf_fragment_render_ops_t msvc_renderer_ops = {
.render_len = msvc_renderer_render_len,
.render_buf = msvc_renderer_render_buf
};
const pkgconf_fragment_render_ops_t *
msvc_renderer_get(void)
{
return &msvc_renderer_ops;
}
+23
View File
@@ -0,0 +1,23 @@
/*
* renderer-msvc.h
* MSVC library syntax renderer header
*
* Copyright (c) 2017 pkgconf authors (see AUTHORS).
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* This software is provided 'as is' and without any warranty, express or
* implied. In no event shall the authors be liable for any damages arising
* from the use of this software.
*/
#ifndef RENDERER_MSVC_H
#define RENDERER_MSVC_H
#include <libpkgconf/libpkgconf.h>
const pkgconf_fragment_render_ops_t *msvc_renderer_get(void);
#endif
+66
View File
@@ -0,0 +1,66 @@
dnl configure.ac
dnl m4 preprocessor script for autotools
dnl
dnl Copyright (c) 2011, 2012, 2013, 2014 pkgconf authors (see AUTHORS).
dnl
dnl Permission to use, copy, modify, and/or distribute this software for any
dnl purpose with or without fee is hereby granted, provided that the above
dnl copyright notice and this permission notice appear in all copies.
dnl
dnl This software is provided 'as is' and without any warranty, express or
dnl implied. In no event shall the authors be liable for any damages arising
dnl from the use of this software.
AC_PREREQ([2.71])
AC_INIT([pkgconf],[2.5.1],[https://github.com/pkgconf/pkgconf/issues/new])
AC_CONFIG_SRCDIR([cli/main.c])
AC_CONFIG_MACRO_DIR([m4])
AX_CHECK_COMPILE_FLAG([-Wall], [CFLAGS="$CFLAGS -Wall"])
AX_CHECK_COMPILE_FLAG([-Wextra], [CFLAGS="$CFLAGS -Wextra"])
AX_CHECK_COMPILE_FLAG([-Wformat=2], [CFLAGS="$CFLAGS -Wformat=2"])
AX_CHECK_COMPILE_FLAG([-std=gnu99], [CFLAGS="$CFLAGS -std=gnu99"], [
AX_CHECK_COMPILE_FLAG([-std=c99], [CFLAGS="$CFLAGS -std=c99"])
])
AC_CONFIG_HEADERS([libpkgconf/config.h])
AC_CHECK_DECLS([strlcpy, strlcat, strndup], [], [], [[#include <string.h>]])
AC_CHECK_DECLS([pledge, unveil], [], [], [[#include <unistd.h>]])
AC_CHECK_DECLS([reallocarray])
AC_CHECK_HEADERS([sys/stat.h])
AM_INIT_AUTOMAKE([foreign dist-xz subdir-objects])
AM_SILENT_RULES([yes])
LT_INIT
AC_SYS_LARGEFILE
AC_ARG_WITH([personality-dir],[AS_HELP_STRING([--with-personality-dir],[specify
the place where cross-compile personality files will be found])],
PERSONALITY_PATH="$withval",
PERSONALITY_PATH="${datadir}/pkgconfig/personality.d:${sysconfdir}/pkgconfig/personality.d")
AC_SUBST([PERSONALITY_PATH])
AC_ARG_WITH([pkg-config-dir],[AS_HELP_STRING([--with-pkg-config-dir],[specify
the place where pc files will be found])],PKG_DEFAULT_PATH="$withval",
PKG_DEFAULT_PATH="${libdir}/pkgconfig:${datadir}/pkgconfig")
AC_SUBST([PKG_DEFAULT_PATH])
AC_ARG_WITH([system-libdir],[AS_HELP_STRING([--with-system-libdir],[specify the
system library directory (default LIBDIR)])],
SYSTEM_LIBDIR="$withval", SYSTEM_LIBDIR="${libdir}")
AC_SUBST([SYSTEM_LIBDIR])
AC_ARG_WITH([system-includedir],[AS_HELP_STRING([--with-system-includedir],[specify the
system include directory (default INCLUDEDIR)])],
SYSTEM_INCLUDEDIR="$withval", SYSTEM_INCLUDEDIR="${includedir}")
AC_SUBST([SYSTEM_INCLUDEDIR])
AC_PROG_CPP
AC_PROG_CC
AC_PROG_INSTALL
AC_PROG_LN_S
AC_CONFIG_FILES([Makefile Kyuafile libpkgconf.pc tests/Kyuafile tests/test_env.sh])
AC_OUTPUT
+339
View File
@@ -0,0 +1,339 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# pkgconf documentation build configuration file, created by
# sphinx-quickstart on Sat Dec 10 16:54:40 2016.
#
# This file is execfile()d with the current directory set to its
# containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
# import os
# import sys
# sys.path.insert(0, os.path.abspath('.'))
# -- General configuration ------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#
# needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = []
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
#
# source_suffix = ['.rst', '.md']
source_suffix = '.rst'
# The encoding of source files.
#
# source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = 'pkgconf'
copyright = '2016, pkgconf authors'
author = 'pkgconf authors'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = '1.1.0'
# The full version, including alpha/beta/rc tags.
release = '1.1.0'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = 'en'
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#
# today = ''
#
# Else, today_fmt is used as the format for a strftime call.
#
# today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This patterns also effect to html_static_path and html_extra_path
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
# The reST default role (used for this markup: `text`) to use for all
# documents.
#
# default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
#
# add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#
# add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#
# show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# A list of ignored prefixes for module index sorting.
# modindex_common_prefix = []
# If true, keep warnings as "system message" paragraphs in the built documents.
# keep_warnings = False
# If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = False
# -- Options for HTML output ----------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
html_theme = 'default'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#
# html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
# html_theme_path = []
# The name for this set of Sphinx documents.
# "<project> v<release> documentation" by default.
#
# html_title = 'pkgconf v1.1.0'
# A shorter title for the navigation bar. Default is the same as html_title.
#
# html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#
# html_logo = None
# The name of an image file (relative to this directory) to use as a favicon of
# the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#
# html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# Add any extra paths that contain custom files (such as robots.txt or
# .htaccess) here, relative to this directory. These files are copied
# directly to the root of the documentation.
#
# html_extra_path = []
# If not None, a 'Last updated on:' timestamp is inserted at every page
# bottom, using the given strftime format.
# The empty string is equivalent to '%b %d, %Y'.
#
# html_last_updated_fmt = None
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#
# html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
#
# html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
#
# html_additional_pages = {}
# If false, no module index is generated.
#
# html_domain_indices = True
# If false, no index is generated.
#
# html_use_index = True
# If true, the index is split into individual pages for each letter.
#
# html_split_index = False
# If true, links to the reST sources are added to the pages.
#
# html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
#
# html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
#
# html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
#
# html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
# html_file_suffix = None
# Language to be used for generating the HTML full-text search index.
# Sphinx supports the following languages:
# 'da', 'de', 'en', 'es', 'fi', 'fr', 'h', 'it', 'ja'
# 'nl', 'no', 'pt', 'ro', 'r', 'sv', 'tr', 'zh'
#
# html_search_language = 'en'
# A dictionary with options for the search language support, empty by default.
# 'ja' uses this config value.
# 'zh' user can custom change `jieba` dictionary path.
#
# html_search_options = {'type': 'default'}
# The name of a javascript file (relative to the configuration directory) that
# implements a search results scorer. If empty, the default will be used.
#
# html_search_scorer = 'scorer.js'
# Output file base name for HTML help builder.
htmlhelp_basename = 'pkgconfdoc'
# -- Options for LaTeX output ---------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#
# 'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#
# 'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#
# 'preamble': '',
# Latex figure (float) alignment
#
# 'figure_align': 'htbp',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
(master_doc, 'pkgconf.tex', 'pkgconf Documentation',
'pkgconf authors', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
#
# latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#
# latex_use_parts = False
# If true, show page references after internal links.
#
# latex_show_pagerefs = False
# If true, show URL addresses after external links.
#
# latex_show_urls = False
# Documents to append as an appendix to all manuals.
#
# latex_appendices = []
# It false, will not define \strong, \code, itleref, \crossref ... but only
# \sphinxstrong, ..., \sphinxtitleref, ... To help avoid clash with user added
# packages.
#
# latex_keep_old_macro_names = True
# If false, no module index is generated.
#
# latex_domain_indices = True
# -- Options for manual page output ---------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
(master_doc, 'pkgconf', 'pkgconf Documentation',
[author], 1)
]
# If true, show URL addresses after external links.
#
# man_show_urls = False
# -- Options for Texinfo output -------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
(master_doc, 'pkgconf', 'pkgconf Documentation',
author, 'pkgconf', 'One line description of project.',
'Miscellaneous'),
]
# Documents to append as an appendix to all manuals.
#
# texinfo_appendices = []
# If false, no module index is generated.
#
# texinfo_domain_indices = True
# How to display URL addresses: 'footnote', 'no', or 'inline'.
#
# texinfo_show_urls = 'footnote'
# If true, do not generate a @detailmenu in the "Top" node's menu.
#
# texinfo_no_detailmenu = False
+149
View File
@@ -0,0 +1,149 @@
# derived from https://github.com/jeanralphaviles/comment_parser/blob/master/comment_parser/parsers/c_parser.py
# MIT license - https://github.com/jeanralphaviles/comment_parser/blob/master/LICENSE
class Comment:
def __init__(self, comment, line, multiline):
self.comment = comment
self.line = line
self.multiline = multiline
def __repr__(self):
return "Comment(comment=%r, line=%r, multiline=%r)" % (self.comment, self.line, self.multiline)
@property
def clean_text(self):
if not self.multiline:
return self.comment.strip()
lines = self.comment.splitlines()
cleanlines = []
for line in lines:
if line[0:3] == ' * ':
cleanlines.append(line[3:])
elif len(line) == 2:
cleanlines.append('')
return '\n'.join(cleanlines)
@property
def doc_text(self):
text = self.clean_text
if '!doc' in text[0:4]:
return text[5:]
return None
class FileError(Exception):
pass
class UnterminatedCommentError(Exception):
pass
def extract_comments(filename):
"""Extracts a list of comments from the given C family source file.
Comments are represented with the Comment class found in the common module.
C family comments come in two forms, single and multi-line comments.
- Single-line comments begin with '//' and continue to the end of line.
- Multi-line comments begin with '/*' and end with '*/' and can span
multiple lines of code. If a multi-line comment does not terminate
before EOF is reached, then an exception is raised.
Note that this doesn't take language-specific preprocessor directives into
consideration.
Args:
filename: String name of the file to extract comments from.
Returns:
Python list of Comment objects in the order that they appear in the file.
Raises:
FileError: File was unable to be open or read.
UnterminatedCommentError: Encountered an unterminated multi-line
comment.
"""
try:
with open(filename, 'r') as source_file:
state = 0
current_comment = ''
comments = []
line_counter = 1
comment_start = 1
while True:
char = source_file.read(1)
if not char:
if state == 3 or state == 4:
raise UnterminatedCommentError()
if state == 2:
# Was in single line comment. Create comment.
comment = Comment(current_comment, line_counter, False)
comments.append(comment)
return comments
if state == 0:
# Waiting for comment start character or beginning of
# string.
if char == '/':
state = 1
elif char == '"':
state = 5
elif state == 1:
# Found comment start character, classify next character and
# determine if single or multiline comment.
if char == '/':
state = 2
elif char == '*':
comment_start = line_counter
state = 3
else:
state = 0
elif state == 2:
# In single line comment, read characters until EOL.
if char == '\n':
comment = Comment(current_comment, line_counter, False)
comments.append(comment)
current_comment = ''
state = 0
else:
current_comment += char
elif state == 3:
# In multi-line comment, add characters until '*'
# encountered.
if char == '*':
state = 4
else:
current_comment += char
elif state == 4:
# In multi-line comment with asterisk found. Determine if
# comment is ending.
if char == '/':
comment = Comment(
current_comment, comment_start, True)
comments.append(comment)
current_comment = ''
state = 0
else:
current_comment += '*'
# Care for multiple '*' in a row
if char != '*':
current_comment += char
state = 3
elif state == 5:
# In string literal, expect literal end or escape char.
if char == '"':
state = 0
elif char == '\\':
state = 6
elif state == 6:
# In string literal, escaping current char.
state = 5
if char == '\n':
line_counter += 1
except OSError as exception:
raise FileError(str(exception))
if __name__ == '__main__':
import sys
from pprint import pprint
comments = [comment for comment in extract_comments(sys.argv[1]) if comment.doc_text]
for comment in comments:
print(comment.doc_text)
+14
View File
@@ -0,0 +1,14 @@
pkgconf
=======
.. toctree::
:maxdepth: 2
libpkgconf
Indices and tables
==================
* :ref:`genindex`
* :ref:`search`
@@ -0,0 +1,23 @@
libpkgconf `argvsplit` module
=============================
This is a lowlevel module which provides parsing of strings into argument vectors,
similar to what a shell would do.
.. c:function:: void pkgconf_argv_free(char **argv)
Frees an argument vector.
:param char** argv: The argument vector to free.
:return: nothing
.. c:function:: int pkgconf_argv_split(const char *src, int *argc, char ***argv)
Splits a string into an argument vector.
:param char* src: The string to split.
:param int* argc: A pointer to an integer to store the argument count.
:param char*** argv: A pointer to a pointer for an argument vector.
:return: 0 on success, -1 on error.
:rtype: int
+35
View File
@@ -0,0 +1,35 @@
libpkgconf `audit` module
=========================
The libpkgconf `audit` module contains the functions related to attaching an audit log file
to a ``pkgconf_client_t`` object.
The audit log format is the same as the output generated by the ``PKG_CONFIG_LOG`` environment
variable.
.. c:function:: void pkgconf_audit_set_log(pkgconf_client_t *client, FILE *auditf)
Sets the audit log file pointer on `client` to `auditf`.
The callee is responsible for closing any previous log files.
:param pkgconf_client_t* client: The client object to modify.
:param FILE* auditf: The file pointer for the already open log file.
:return: nothing
.. c:function:: void pkgconf_audit_log(pkgconf_client_t *client, const char *format, ...)
Logs a message to the opened audit log (if any).
:param pkgconf_client_t* client: The client object the log message is for.
:param char* format: The format string to use for the log messages.
:return: nothing
.. c:function:: void pkgconf_audit_log_dependency(pkgconf_client_t *client, const pkgconf_pkg_t *dep, const pkgconf_dependency_t *depnode)
Convenience function which logs a dependency node to the opened audit log (if any).
:param pkgconf_client_t* client: The client object the log message is for.
:param pkgconf_pkg_t* dep: The dependency package object being logged.
:param pkgconf_dependency_t* depnode: The dependency object itself being logged.
:return: nothing
+45
View File
@@ -0,0 +1,45 @@
libpkgconf `cache` module
=========================
The libpkgconf `cache` module manages a package/module object cache, allowing it to
avoid loading duplicate copies of a package/module.
A cache is tied to a specific pkgconf client object, so package objects should not
be shared across threads.
.. c:function:: pkgconf_pkg_t *pkgconf_cache_lookup(const pkgconf_client_t *client, const char *id)
Looks up a package in the cache given an `id` atom,
such as ``gtk+-3.0`` and returns the already loaded version
if present.
:param pkgconf_client_t* client: The client object to access.
:param char* id: The package atom to look up in the client object's cache.
:return: A package object if present, else ``NULL``.
:rtype: pkgconf_pkg_t *
.. c:function:: void pkgconf_cache_add(pkgconf_client_t *client, pkgconf_pkg_t *pkg)
Adds an entry for the package to the package cache.
The cache entry must be removed if the package is freed.
:param pkgconf_client_t* client: The client object to modify.
:param pkgconf_pkg_t* pkg: The package object to add to the client object's cache.
:return: nothing
.. c:function:: void pkgconf_cache_remove(pkgconf_client_t *client, pkgconf_pkg_t *pkg)
Deletes a package from the client object's package cache.
:param pkgconf_client_t* client: The client object to modify.
:param pkgconf_pkg_t* pkg: The package object to remove from the client object's cache.
:return: nothing
.. c:function:: void pkgconf_cache_free(pkgconf_client_t *client)
Releases all resources related to a client object's package cache.
This function should only be called to clear a client object's package cache,
as it may release any package in the cache.
:param pkgconf_client_t* client: The client object to modify.
+212
View File
@@ -0,0 +1,212 @@
libpkgconf `client` module
==========================
The libpkgconf `client` module implements the `pkgconf_client_t` "client" object.
Client objects store all necessary state for libpkgconf allowing for multiple instances to run
in parallel.
Client objects are not thread safe, in other words, a client object should not be shared across
thread boundaries.
.. c:function:: void pkgconf_client_dir_list_build(pkgconf_client_t *client)
Bootstraps the package search paths. If the ``PKGCONF_PKG_PKGF_ENV_ONLY`` `flag` is set on the client,
then only the ``PKG_CONFIG_PATH`` environment variable will be used, otherwise both the
``PKG_CONFIG_PATH`` and ``PKG_CONFIG_LIBDIR`` environment variables will be used.
:param pkgconf_client_t* client: The pkgconf client object to bootstrap.
:return: nothing
.. c:function:: void pkgconf_client_init(pkgconf_client_t *client, pkgconf_error_handler_func_t error_handler, void *error_handler_data, const pkgconf_cross_personality_t *personality)
Initialise a pkgconf client object.
:param pkgconf_client_t* client: The client to initialise.
:param pkgconf_error_handler_func_t error_handler: An optional error handler to use for logging errors.
:param void* error_handler_data: user data passed to optional error handler
:param pkgconf_cross_personality_t* personality: the cross-compile personality to use for defaults
:return: nothing
.. c:function:: pkgconf_client_t* pkgconf_client_new(pkgconf_error_handler_func_t error_handler, void *error_handler_data, const pkgconf_cross_personality_t *personality)
Allocate and initialise a pkgconf client object.
:param pkgconf_error_handler_func_t error_handler: An optional error handler to use for logging errors.
:param void* error_handler_data: user data passed to optional error handler
:param pkgconf_cross_personality_t* personality: cross-compile personality to use
:return: A pkgconf client object.
:rtype: pkgconf_client_t*
.. c:function:: void pkgconf_client_deinit(pkgconf_client_t *client)
Release resources belonging to a pkgconf client object.
:param pkgconf_client_t* client: The client to deinitialise.
:return: nothing
.. c:function:: void pkgconf_client_free(pkgconf_client_t *client)
Release resources belonging to a pkgconf client object and then free the client object itself.
:param pkgconf_client_t* client: The client to deinitialise and free.
:return: nothing
.. c:function:: const char *pkgconf_client_get_sysroot_dir(const pkgconf_client_t *client)
Retrieves the client's sysroot directory (if any).
:param pkgconf_client_t* client: The client object being accessed.
:return: A string containing the sysroot directory or NULL.
:rtype: const char *
.. c:function:: void pkgconf_client_set_sysroot_dir(pkgconf_client_t *client, const char *sysroot_dir)
Sets or clears the sysroot directory on a client object. Any previous sysroot directory setting is
automatically released if one was previously set.
Additionally, the global tuple ``$(pc_sysrootdir)`` is set as appropriate based on the new setting.
:param pkgconf_client_t* client: The client object being modified.
:param char* sysroot_dir: The sysroot directory to set or NULL to unset.
:return: nothing
.. c:function:: const char *pkgconf_client_get_buildroot_dir(const pkgconf_client_t *client)
Retrieves the client's buildroot directory (if any).
:param pkgconf_client_t* client: The client object being accessed.
:return: A string containing the buildroot directory or NULL.
:rtype: const char *
.. c:function:: void pkgconf_client_set_buildroot_dir(pkgconf_client_t *client, const char *buildroot_dir)
Sets or clears the buildroot directory on a client object. Any previous buildroot directory setting is
automatically released if one was previously set.
Additionally, the global tuple ``$(pc_top_builddir)`` is set as appropriate based on the new setting.
:param pkgconf_client_t* client: The client object being modified.
:param char* buildroot_dir: The buildroot directory to set or NULL to unset.
:return: nothing
.. c:function:: bool pkgconf_error(const pkgconf_client_t *client, const char *format, ...)
Report an error to a client-registered error handler.
:param pkgconf_client_t* client: The pkgconf client object to report the error to.
:param char* format: A printf-style format string to use for formatting the error message.
:return: true if the error handler processed the message, else false.
:rtype: bool
.. c:function:: bool pkgconf_warn(const pkgconf_client_t *client, const char *format, ...)
Report an error to a client-registered warn handler.
:param pkgconf_client_t* client: The pkgconf client object to report the error to.
:param char* format: A printf-style format string to use for formatting the warning message.
:return: true if the warn handler processed the message, else false.
:rtype: bool
.. c:function:: bool pkgconf_trace(const pkgconf_client_t *client, const char *filename, size_t len, const char *funcname, const char *format, ...)
Report a message to a client-registered trace handler.
:param pkgconf_client_t* client: The pkgconf client object to report the trace message to.
:param char* filename: The file the function is in.
:param size_t lineno: The line number currently being executed.
:param char* funcname: The function name to use.
:param char* format: A printf-style format string to use for formatting the trace message.
:return: true if the trace handler processed the message, else false.
:rtype: bool
.. c:function:: bool pkgconf_default_error_handler(const char *msg, const pkgconf_client_t *client, const void *data)
The default pkgconf error handler.
:param char* msg: The error message to handle.
:param pkgconf_client_t* client: The client object the error originated from.
:param void* data: An opaque pointer to extra data associated with the client for error handling.
:return: true (the function does nothing to process the message)
:rtype: bool
.. c:function:: unsigned int pkgconf_client_get_flags(const pkgconf_client_t *client)
Retrieves resolver-specific flags associated with a client object.
:param pkgconf_client_t* client: The client object to retrieve the resolver-specific flags from.
:return: a bitfield of resolver-specific flags
:rtype: uint
.. c:function:: void pkgconf_client_set_flags(pkgconf_client_t *client, unsigned int flags)
Sets resolver-specific flags associated with a client object.
:param pkgconf_client_t* client: The client object to set the resolver-specific flags on.
:return: nothing
.. c:function:: const char *pkgconf_client_get_prefix_varname(const pkgconf_client_t *client)
Retrieves the name of the variable that should contain a module's prefix.
In some cases, it is necessary to override this variable to allow proper path relocation.
:param pkgconf_client_t* client: The client object to retrieve the prefix variable name from.
:return: the prefix variable name as a string
:rtype: const char *
.. c:function:: void pkgconf_client_set_prefix_varname(pkgconf_client_t *client, const char *prefix_varname)
Sets the name of the variable that should contain a module's prefix.
If the variable name is ``NULL``, then the default variable name (``prefix``) is used.
:param pkgconf_client_t* client: The client object to set the prefix variable name on.
:param char* prefix_varname: The prefix variable name to set.
:return: nothing
.. c:function:: pkgconf_client_get_warn_handler(const pkgconf_client_t *client)
Returns the warning handler if one is set, else ``NULL``.
:param pkgconf_client_t* client: The client object to get the warn handler from.
:return: a function pointer to the warn handler or ``NULL``
.. c:function:: pkgconf_client_set_warn_handler(pkgconf_client_t *client, pkgconf_error_handler_func_t warn_handler, void *warn_handler_data)
Sets a warn handler on a client object or uninstalls one if set to ``NULL``.
:param pkgconf_client_t* client: The client object to set the warn handler on.
:param pkgconf_error_handler_func_t warn_handler: The warn handler to set.
:param void* warn_handler_data: Optional data to associate with the warn handler.
:return: nothing
.. c:function:: pkgconf_client_get_error_handler(const pkgconf_client_t *client)
Returns the error handler if one is set, else ``NULL``.
:param pkgconf_client_t* client: The client object to get the error handler from.
:return: a function pointer to the error handler or ``NULL``
.. c:function:: pkgconf_client_set_error_handler(pkgconf_client_t *client, pkgconf_error_handler_func_t error_handler, void *error_handler_data)
Sets a warn handler on a client object or uninstalls one if set to ``NULL``.
:param pkgconf_client_t* client: The client object to set the error handler on.
:param pkgconf_error_handler_func_t error_handler: The error handler to set.
:param void* error_handler_data: Optional data to associate with the error handler.
:return: nothing
.. c:function:: pkgconf_client_get_trace_handler(const pkgconf_client_t *client)
Returns the error handler if one is set, else ``NULL``.
:param pkgconf_client_t* client: The client object to get the error handler from.
:return: a function pointer to the error handler or ``NULL``
.. c:function:: pkgconf_client_set_trace_handler(pkgconf_client_t *client, pkgconf_error_handler_func_t trace_handler, void *trace_handler_data)
Sets a warn handler on a client object or uninstalls one if set to ``NULL``.
:param pkgconf_client_t* client: The client object to set the error handler on.
:param pkgconf_error_handler_func_t trace_handler: The error handler to set.
:param void* trace_handler_data: Optional data to associate with the error handler.
:return: nothing
@@ -0,0 +1,90 @@
libpkgconf `dependency` module
==============================
The `dependency` module provides support for building `dependency lists` (the basic component of the overall `dependency graph`) and
`dependency nodes` which store dependency information.
.. c:function:: pkgconf_dependency_t *pkgconf_dependency_add(pkgconf_list_t *list, const char *package, const char *version, pkgconf_pkg_comparator_t compare)
Adds a parsed dependency to a dependency list as a dependency node.
:param pkgconf_client_t* client: The client object that owns the package this dependency list belongs to.
:param pkgconf_list_t* list: The dependency list to add a dependency node to.
:param char* package: The package `atom` to set on the dependency node.
:param char* version: The package `version` to set on the dependency node.
:param pkgconf_pkg_comparator_t compare: The comparison operator to set on the dependency node.
:param uint flags: Any flags to attach to the dependency node.
:return: A dependency node.
:rtype: pkgconf_dependency_t *
.. c:function:: void pkgconf_dependency_append(pkgconf_list_t *list, pkgconf_dependency_t *tail)
Adds a dependency node to a pre-existing dependency list.
:param pkgconf_list_t* list: The dependency list to add a dependency node to.
:param pkgconf_dependency_t* tail: The dependency node to add to the tail of the dependency list.
:return: nothing
.. c:function:: void pkgconf_dependency_free_one(pkgconf_dependency_t *dep)
Frees a dependency node.
:param pkgconf_dependency_t* dep: The dependency node to free.
:return: nothing
.. c:function:: pkgconf_dependency_t *pkgconf_dependency_ref(pkgconf_client_t *owner, pkgconf_dependency_t *dep)
Increases a dependency node's refcount.
:param pkgconf_client_t* owner: The client object which owns the memory of this dependency node.
:param pkgconf_dependency_t* dep: The dependency to increase the refcount of.
:return: the dependency node on success, else NULL
.. c:function:: void pkgconf_dependency_unref(pkgconf_client_t *owner, pkgconf_dependency_t *dep)
Decreases a dependency node's refcount and frees it if necessary.
:param pkgconf_client_t* owner: The client object which owns the memory of this dependency node.
:param pkgconf_dependency_t* dep: The dependency to decrease the refcount of.
:return: nothing
.. c:function:: void pkgconf_dependency_free(pkgconf_list_t *list)
Release a dependency list and its child dependency nodes.
:param pkgconf_list_t* list: The dependency list to release.
:return: nothing
.. c:function:: void pkgconf_dependency_parse_str(pkgconf_list_t *deplist_head, const char *depends)
Parse a dependency declaration into a dependency list.
Commas are counted as whitespace to allow for constructs such as ``@SUBSTVAR@, zlib`` being processed
into ``, zlib``.
:param pkgconf_client_t* client: The client object that owns the package this dependency list belongs to.
:param pkgconf_list_t* deplist_head: The dependency list to populate with dependency nodes.
:param char* depends: The dependency data to parse.
:param uint flags: Any flags to attach to the dependency nodes.
:return: nothing
.. c:function:: void pkgconf_dependency_parse(const pkgconf_client_t *client, pkgconf_pkg_t *pkg, pkgconf_list_t *deplist, const char *depends)
Preprocess dependency data and then process that dependency declaration into a dependency list.
Commas are counted as whitespace to allow for constructs such as ``@SUBSTVAR@, zlib`` being processed
into ``, zlib``.
:param pkgconf_client_t* client: The client object that owns the package this dependency list belongs to.
:param pkgconf_pkg_t* pkg: The package object that owns this dependency list.
:param pkgconf_list_t* deplist: The dependency list to populate with dependency nodes.
:param char* depends: The dependency data to parse.
:param uint flags: Any flags to attach to the dependency nodes.
:return: nothing
.. c:function:: pkgconf_dependency_t *pkgconf_dependency_copy(pkgconf_client_t *client, const pkgconf_dependency_t *dep)
Copies a dependency node to a new one.
:param pkgconf_client_t* client: The client object that will own this dependency.
:param pkgconf_dependency_t* dep: The dependency node to copy.
:return: a pointer to a new dependency node, else NULL
+116
View File
@@ -0,0 +1,116 @@
libpkgconf `fragment` module
============================
The `fragment` module provides low-level management and rendering of fragment lists. A
`fragment list` contains various `fragments` of text (such as ``-I /usr/include``) in a matter
which is composable, mergeable and reorderable.
.. c:function:: void pkgconf_fragment_add(const pkgconf_client_t *client, pkgconf_list_t *list, const char *string, unsigned int flags)
Adds a `fragment` of text to a `fragment list`, possibly modifying the fragment if a sysroot is set.
:param pkgconf_client_t* client: The pkgconf client being accessed.
:param pkgconf_list_t* list: The fragment list.
:param char* string: The string of text to add as a fragment to the fragment list.
:param uint flags: Parsing-related flags for the package.
:return: nothing
.. c:function:: bool pkgconf_fragment_has_system_dir(const pkgconf_client_t *client, const pkgconf_fragment_t *frag)
Checks if a `fragment` contains a `system path`. System paths are detected at compile time and optionally overridden by
the ``PKG_CONFIG_SYSTEM_INCLUDE_PATH`` and ``PKG_CONFIG_SYSTEM_LIBRARY_PATH`` environment variables.
:param pkgconf_client_t* client: The pkgconf client object the fragment belongs to.
:param pkgconf_fragment_t* frag: The fragment being checked.
:return: true if the fragment contains a system path, else false
:rtype: bool
.. c:function:: void pkgconf_fragment_copy(const pkgconf_client_t *client, pkgconf_list_t *list, const pkgconf_fragment_t *base, bool is_private)
Copies a `fragment` to another `fragment list`, possibly removing a previous copy of the `fragment`
in a process known as `mergeback`.
:param pkgconf_client_t* client: The pkgconf client being accessed.
:param pkgconf_list_t* list: The list the fragment is being added to.
:param pkgconf_fragment_t* base: The fragment being copied.
:param bool is_private: Whether the fragment list is a `private` fragment list (static linking).
:return: nothing
.. c:function:: void pkgconf_fragment_copy_list(const pkgconf_client_t *client, pkgconf_list_t *list, const pkgconf_list_t *base)
Copies a `fragment list` to another `fragment list`, possibly removing a previous copy of the fragments
in a process known as `mergeback`.
:param pkgconf_client_t* client: The pkgconf client being accessed.
:param pkgconf_list_t* list: The list the fragments are being added to.
:param pkgconf_list_t* base: The list the fragments are being copied from.
:return: nothing
.. c:function:: void pkgconf_fragment_filter(const pkgconf_client_t *client, pkgconf_list_t *dest, pkgconf_list_t *src, pkgconf_fragment_filter_func_t filter_func)
Copies a `fragment list` to another `fragment list` which match a user-specified filtering function.
:param pkgconf_client_t* client: The pkgconf client being accessed.
:param pkgconf_list_t* dest: The destination list.
:param pkgconf_list_t* src: The source list.
:param pkgconf_fragment_filter_func_t filter_func: The filter function to use.
:param void* data: Optional data to pass to the filter function.
:return: nothing
.. c:function:: size_t pkgconf_fragment_render_len(const pkgconf_list_t *list, bool escape, const pkgconf_fragment_render_ops_t *ops)
Calculates the required memory to store a `fragment list` when rendered as a string.
:param pkgconf_list_t* list: The `fragment list` being rendered.
:param bool escape: Whether or not to escape special shell characters (deprecated).
:param pkgconf_fragment_render_ops_t* ops: An optional ops structure to use for custom renderers, else ``NULL``.
:return: the amount of bytes required to represent the `fragment list` when rendered
:rtype: size_t
.. c:function:: void pkgconf_fragment_render_buf(const pkgconf_list_t *list, char *buf, size_t buflen, bool escape, const pkgconf_fragment_render_ops_t *ops)
Renders a `fragment list` into a buffer.
:param pkgconf_list_t* list: The `fragment list` being rendered.
:param char* buf: The buffer to render the fragment list into.
:param size_t buflen: The length of the buffer.
:param bool escape: Whether or not to escape special shell characters (deprecated).
:param pkgconf_fragment_render_ops_t* ops: An optional ops structure to use for custom renderers, else ``NULL``.
:return: nothing
.. c:function:: char *pkgconf_fragment_render(const pkgconf_list_t *list)
Allocate memory and render a `fragment list` into it.
:param pkgconf_list_t* list: The `fragment list` being rendered.
:param bool escape: Whether or not to escape special shell characters (deprecated).
:param pkgconf_fragment_render_ops_t* ops: An optional ops structure to use for custom renderers, else ``NULL``.
:return: An allocated string containing the rendered `fragment list`.
:rtype: char *
.. c:function:: void pkgconf_fragment_delete(pkgconf_list_t *list, pkgconf_fragment_t *node)
Delete a `fragment node` from a `fragment list`.
:param pkgconf_list_t* list: The `fragment list` to delete from.
:param pkgconf_fragment_t* node: The `fragment node` to delete.
:return: nothing
.. c:function:: void pkgconf_fragment_free(pkgconf_list_t *list)
Delete an entire `fragment list`.
:param pkgconf_list_t* list: The `fragment list` to delete.
:return: nothing
.. c:function:: bool pkgconf_fragment_parse(const pkgconf_client_t *client, pkgconf_list_t *list, pkgconf_list_t *vars, const char *value)
Parse a string into a `fragment list`.
:param pkgconf_client_t* client: The pkgconf client being accessed.
:param pkgconf_list_t* list: The `fragment list` to add the fragment entries to.
:param pkgconf_list_t* vars: A list of variables to use for variable substitution.
:param uint flags: Any parsing flags to be aware of.
:param char* value: The string to parse into fragments.
:return: true on success, false on parse error
+71
View File
@@ -0,0 +1,71 @@
libpkgconf `path` module
========================
The `path` module provides functions for manipulating lists of paths in a cross-platform manner. Notably,
it is used by the `pkgconf client` to parse the ``PKG_CONFIG_PATH``, ``PKG_CONFIG_LIBDIR`` and related environment
variables.
.. c:function:: void pkgconf_path_add(const char *text, pkgconf_list_t *dirlist)
Adds a path node to a path list. If the path is already in the list, do nothing.
:param char* text: The path text to add as a path node.
:param pkgconf_list_t* dirlist: The path list to add the path node to.
:param bool filter: Whether to perform duplicate filtering.
:return: nothing
.. c:function:: size_t pkgconf_path_split(const char *text, pkgconf_list_t *dirlist)
Splits a given text input and inserts paths into a path list.
:param char* text: The path text to split and add as path nodes.
:param pkgconf_list_t* dirlist: The path list to have the path nodes added to.
:param bool filter: Whether to perform duplicate filtering.
:return: number of path nodes added to the path list
:rtype: size_t
.. c:function:: size_t pkgconf_path_build_from_environ(const char *envvarname, const char *fallback, pkgconf_list_t *dirlist)
Adds the paths specified in an environment variable to a path list. If the environment variable is not set,
an optional default set of paths is added.
:param char* envvarname: The environment variable to look up.
:param char* fallback: The fallback paths to use if the environment variable is not set.
:param pkgconf_list_t* dirlist: The path list to add the path nodes to.
:param bool filter: Whether to perform duplicate filtering.
:return: number of path nodes added to the path list
:rtype: size_t
.. c:function:: bool pkgconf_path_match_list(const char *path, const pkgconf_list_t *dirlist)
Checks whether a path has a matching prefix in a path list.
:param char* path: The path to check against a path list.
:param pkgconf_list_t* dirlist: The path list to check the path against.
:return: true if the path list has a matching prefix, otherwise false
:rtype: bool
.. c:function:: void pkgconf_path_copy_list(pkgconf_list_t *dst, const pkgconf_list_t *src)
Copies a path list to another path list.
:param pkgconf_list_t* dst: The path list to copy to.
:param pkgconf_list_t* src: The path list to copy from.
:return: nothing
.. c:function:: void pkgconf_path_free(pkgconf_list_t *dirlist)
Releases any path nodes attached to the given path list.
:param pkgconf_list_t* dirlist: The path list to clean up.
:return: nothing
.. c:function:: bool pkgconf_path_relocate(char *buf, size_t buflen)
Relocates a path, possibly calling normpath() on it.
:param char* buf: The path to relocate.
:param size_t buflen: The buffer length the path is contained in.
:return: true on success, false on error
:rtype: bool
@@ -0,0 +1,27 @@
libpkgconf `personality` module
=========================
.. c:function:: const pkgconf_cross_personality_t *pkgconf_cross_personality_default(void)
Returns the default cross-compile personality.
Not thread safe.
:rtype: pkgconf_cross_personality_t*
:return: the default cross-compile personality
.. c:function:: void pkgconf_cross_personality_deinit(pkgconf_cross_personality_t *)
Decrements the count of default cross personality instances.
Not thread safe.
:rtype: void
.. c:function:: pkgconf_cross_personality_t *pkgconf_cross_personality_find(const char *triplet)
Attempts to find a cross-compile personality given a triplet.
:rtype: pkgconf_cross_personality_t*
:return: the default cross-compile personality
+154
View File
@@ -0,0 +1,154 @@
libpkgconf `pkg` module
=======================
The `pkg` module provides dependency resolution services and the overall `.pc` file parsing
routines.
.. c:function:: pkgconf_pkg_t *pkgconf_pkg_new_from_file(const pkgconf_client_t *client, const char *filename, FILE *f, unsigned int flags)
Parse a .pc file into a pkgconf_pkg_t object structure.
:param pkgconf_client_t* client: The pkgconf client object to use for dependency resolution.
:param char* filename: The filename of the package file (including full path).
:param FILE* f: The file object to read from.
:param uint flags: The flags to use when parsing.
:returns: A ``pkgconf_pkg_t`` object which contains the package data.
:rtype: pkgconf_pkg_t *
.. c:function:: void pkgconf_pkg_free(pkgconf_client_t *client, pkgconf_pkg_t *pkg)
Releases all releases for a given ``pkgconf_pkg_t`` object.
:param pkgconf_client_t* client: The client which owns the ``pkgconf_pkg_t`` object, `pkg`.
:param pkgconf_pkg_t* pkg: The package to free.
:return: nothing
.. c:function:: pkgconf_pkg_t *pkgconf_pkg_ref(const pkgconf_client_t *client, pkgconf_pkg_t *pkg)
Adds an additional reference to the package object.
:param pkgconf_client_t* client: The pkgconf client object which owns the package being referenced.
:param pkgconf_pkg_t* pkg: The package object being referenced.
:return: The package itself with an incremented reference count.
:rtype: pkgconf_pkg_t *
.. c:function:: void pkgconf_pkg_unref(pkgconf_client_t *client, pkgconf_pkg_t *pkg)
Releases a reference on the package object. If the reference count is 0, then also free the package.
:param pkgconf_client_t* client: The pkgconf client object which owns the package being dereferenced.
:param pkgconf_pkg_t* pkg: The package object being dereferenced.
:return: nothing
.. c:function:: pkgconf_pkg_t *pkgconf_scan_all(pkgconf_client_t *client, void *data, pkgconf_pkg_iteration_func_t func)
Iterates over all packages found in the `package directory list`, running ``func`` on them. If ``func`` returns true,
then stop iteration and return the last iterated package.
:param pkgconf_client_t* client: The pkgconf client object to use for dependency resolution.
:param void* data: An opaque pointer to data to provide the iteration function with.
:param pkgconf_pkg_iteration_func_t func: A function which is called for each package to determine if the package matches,
always return ``false`` to iterate over all packages.
:return: A package object reference if one is found by the scan function, else ``NULL``.
:rtype: pkgconf_pkg_t *
.. c:function:: pkgconf_pkg_t *pkgconf_pkg_find(pkgconf_client_t *client, const char *name)
Search for a package.
:param pkgconf_client_t* client: The pkgconf client object to use for dependency resolution.
:param char* name: The name of the package `atom` to use for searching.
:return: A package object reference if the package was found, else ``NULL``.
:rtype: pkgconf_pkg_t *
.. c:function:: int pkgconf_compare_version(const char *a, const char *b)
Compare versions using RPM version comparison rules as described in the LSB.
:param char* a: The first version to compare in the pair.
:param char* b: The second version to compare in the pair.
:return: -1 if the first version is less than, 0 if both versions are equal, 1 if the second version is less than.
:rtype: int
.. c:function:: pkgconf_pkg_t *pkgconf_builtin_pkg_get(const char *name)
Looks up a built-in package. The package should not be freed or dereferenced.
:param char* name: An atom corresponding to a built-in package to search for.
:return: the built-in package if present, else ``NULL``.
:rtype: pkgconf_pkg_t *
.. c:function:: const char *pkgconf_pkg_get_comparator(const pkgconf_dependency_t *pkgdep)
Returns the comparator used in a depgraph dependency node as a string.
:param pkgconf_dependency_t* pkgdep: The depgraph dependency node to return the comparator for.
:return: A string matching the comparator or ``"???"``.
:rtype: char *
.. c:function:: pkgconf_pkg_comparator_t pkgconf_pkg_comparator_lookup_by_name(const char *name)
Look up the appropriate comparator bytecode in the comparator set (defined
in ``pkg.c``, see ``pkgconf_pkg_comparator_names`` and ``pkgconf_pkg_comparator_impls``).
:param char* name: The comparator to look up by `name`.
:return: The comparator bytecode if found, else ``PKGCONF_CMP_ANY``.
:rtype: pkgconf_pkg_comparator_t
.. c:function:: pkgconf_pkg_t *pkgconf_pkg_verify_dependency(pkgconf_client_t *client, pkgconf_dependency_t *pkgdep, unsigned int *eflags)
Verify a pkgconf_dependency_t node in the depgraph. If the dependency is solvable,
return the appropriate ``pkgconf_pkg_t`` object, else ``NULL``.
:param pkgconf_client_t* client: The pkgconf client object to use for dependency resolution.
:param pkgconf_dependency_t* pkgdep: The dependency graph node to solve.
:param uint* eflags: An optional pointer that, if set, will be populated with an error code from the resolver.
:return: On success, the appropriate ``pkgconf_pkg_t`` object to solve the dependency, else ``NULL``.
:rtype: pkgconf_pkg_t *
.. c:function:: unsigned int pkgconf_pkg_verify_graph(pkgconf_client_t *client, pkgconf_pkg_t *root, int depth)
Verify the graph dependency nodes are satisfiable by walking the tree using
``pkgconf_pkg_traverse()``.
:param pkgconf_client_t* client: The pkgconf client object to use for dependency resolution.
:param pkgconf_pkg_t* root: The root entry in the package dependency graph which should contain the top-level dependencies to resolve.
:param int depth: The maximum allowed depth for dependency resolution.
:return: On success, ``PKGCONF_PKG_ERRF_OK`` (0), else an error code.
:rtype: unsigned int
.. c:function:: unsigned int pkgconf_pkg_traverse(pkgconf_client_t *client, pkgconf_pkg_t *root, pkgconf_pkg_traverse_func_t func, void *data, int maxdepth, unsigned int skip_flags)
Walk and resolve the dependency graph up to `maxdepth` levels.
:param pkgconf_client_t* client: The pkgconf client object to use for dependency resolution.
:param pkgconf_pkg_t* root: The root of the dependency graph.
:param pkgconf_pkg_traverse_func_t func: A traversal function to call for each resolved node in the dependency graph.
:param void* data: An opaque pointer to data to be passed to the traversal function.
:param int maxdepth: The maximum depth to walk the dependency graph for. -1 means infinite recursion.
:param uint skip_flags: Skip over dependency nodes containing the specified flags. A setting of 0 skips no dependency nodes.
:return: ``PKGCONF_PKG_ERRF_OK`` on success, else an error code.
:rtype: unsigned int
.. c:function:: int pkgconf_pkg_cflags(pkgconf_client_t *client, pkgconf_pkg_t *root, pkgconf_list_t *list, int maxdepth)
Walks a dependency graph and extracts relevant ``CFLAGS`` fragments.
:param pkgconf_client_t* client: The pkgconf client object to use for dependency resolution.
:param pkgconf_pkg_t* root: The root of the dependency graph.
:param pkgconf_list_t* list: The fragment list to add the extracted ``CFLAGS`` fragments to.
:param int maxdepth: The maximum allowed depth for dependency resolution. -1 means infinite recursion.
:return: ``PKGCONF_PKG_ERRF_OK`` if successful, otherwise an error code.
:rtype: unsigned int
.. c:function:: int pkgconf_pkg_libs(pkgconf_client_t *client, pkgconf_pkg_t *root, pkgconf_list_t *list, int maxdepth)
Walks a dependency graph and extracts relevant ``LIBS`` fragments.
:param pkgconf_client_t* client: The pkgconf client object to use for dependency resolution.
:param pkgconf_pkg_t* root: The root of the dependency graph.
:param pkgconf_list_t* list: The fragment list to add the extracted ``LIBS`` fragments to.
:param int maxdepth: The maximum allowed depth for dependency resolution. -1 means infinite recursion.
:return: ``PKGCONF_PKG_ERRF_OK`` if successful, otherwise an error code.
:rtype: unsigned int
+78
View File
@@ -0,0 +1,78 @@
libpkgconf `queue` module
=========================
The `queue` module provides an interface that allows easily building a dependency graph from an
arbitrary set of dependencies. It also provides support for doing "preflight" checks on the entire
dependency graph prior to working with it.
Using the `queue` module functions is the recommended way of working with dependency graphs.
.. c:function:: void pkgconf_queue_push(pkgconf_list_t *list, const char *package)
Pushes a requested dependency onto the dependency resolver's queue.
:param pkgconf_list_t* list: the dependency resolution queue to add the package request to.
:param char* package: the dependency atom requested
:return: nothing
.. c:function:: bool pkgconf_queue_compile(pkgconf_client_t *client, pkgconf_pkg_t *world, pkgconf_list_t *list)
Compile a dependency resolution queue into a dependency resolution problem if possible, otherwise report an error.
:param pkgconf_client_t* client: The pkgconf client object to use for dependency resolution.
:param pkgconf_pkg_t* world: The designated root of the dependency graph.
:param pkgconf_list_t* list: The list of dependency requests to consider.
:return: true if the built dependency resolution problem is consistent, else false
:rtype: bool
.. c:function:: void pkgconf_queue_free(pkgconf_list_t *list)
Release any memory related to a dependency resolution queue.
:param pkgconf_list_t* list: The dependency resolution queue to release.
:return: nothing
.. c:function:: void pkgconf_solution_free(pkgconf_client_t *client, pkgconf_pkg_t *world, int maxdepth)
Removes references to package nodes contained in a solution.
:param pkgconf_client_t* client: The pkgconf client object to use for dependency resolution.
:param pkgconf_pkg_t* world: The root for the generated dependency graph. Should have PKGCONF_PKG_PROPF_VIRTUAL flag.
:returns: nothing
.. c:function:: bool pkgconf_queue_solve(pkgconf_client_t *client, pkgconf_list_t *list, pkgconf_pkg_t *world, int maxdepth)
Solves and flattens the dependency graph for the supplied dependency list.
:param pkgconf_client_t* client: The pkgconf client object to use for dependency resolution.
:param pkgconf_list_t* list: The list of dependency requests to consider.
:param pkgconf_pkg_t* world: The root for the generated dependency graph, provided by the caller. Should have PKGCONF_PKG_PROPF_VIRTUAL flag.
:param int maxdepth: The maximum allowed depth for the dependency resolver. A depth of -1 means unlimited.
:returns: true if the dependency resolver found a solution, otherwise false.
:rtype: bool
.. c:function:: void pkgconf_queue_apply(pkgconf_client_t *client, pkgconf_list_t *list, pkgconf_queue_apply_func_t func, int maxdepth, void *data)
Attempt to compile a dependency resolution queue into a dependency resolution problem, then attempt to solve the problem and
feed the solution to a callback function if a complete dependency graph is found.
This function should not be used in new code. Use pkgconf_queue_solve instead.
:param pkgconf_client_t* client: The pkgconf client object to use for dependency resolution.
:param pkgconf_list_t* list: The list of dependency requests to consider.
:param pkgconf_queue_apply_func_t func: The callback function to call if a solution is found by the dependency resolver.
:param int maxdepth: The maximum allowed depth for the dependency resolver. A depth of -1 means unlimited.
:param void* data: An opaque pointer which is passed to the callback function.
:returns: true if the dependency resolver found a solution, otherwise false.
:rtype: bool
.. c:function:: void pkgconf_queue_validate(pkgconf_client_t *client, pkgconf_list_t *list, pkgconf_queue_apply_func_t func, int maxdepth, void *data)
Attempt to compile a dependency resolution queue into a dependency resolution problem, then attempt to solve the problem.
:param pkgconf_client_t* client: The pkgconf client object to use for dependency resolution.
:param pkgconf_list_t* list: The list of dependency requests to consider.
:param int maxdepth: The maximum allowed depth for the dependency resolver. A depth of -1 means unlimited.
:returns: true if the dependency resolver found a solution, otherwise false.
:rtype: bool
+92
View File
@@ -0,0 +1,92 @@
libpkgconf `tuple` module
=========================
The `tuple` module provides key-value mappings backed by a linked list. The key-value
mapping is mainly used for variable substitution when parsing .pc files.
There are two sets of mappings: a ``pkgconf_pkg_t`` specific mapping, and a `global` mapping.
The `tuple` module provides convenience wrappers for managing the `global` mapping, which is
attached to a given client object.
.. c:function:: void pkgconf_tuple_add_global(pkgconf_client_t *client, const char *key, const char *value)
Defines a global variable, replacing the previous declaration if one was set.
:param pkgconf_client_t* client: The pkgconf client object to modify.
:param char* key: The key for the mapping (variable name).
:param char* value: The value for the mapped entry.
:return: nothing
.. c:function:: void pkgconf_tuple_find_global(const pkgconf_client_t *client, const char *key)
Looks up a global variable.
:param pkgconf_client_t* client: The pkgconf client object to access.
:param char* key: The key or variable name to look up.
:return: the contents of the variable or ``NULL``
:rtype: char *
.. c:function:: void pkgconf_tuple_free_global(pkgconf_client_t *client)
Delete all global variables associated with a pkgconf client object.
:param pkgconf_client_t* client: The pkgconf client object to modify.
:return: nothing
.. c:function:: void pkgconf_tuple_define_global(pkgconf_client_t *client, const char *kv)
Parse and define a global variable.
:param pkgconf_client_t* client: The pkgconf client object to modify.
:param char* kv: The variable in the form of ``key=value``.
:return: nothing
.. c:function:: pkgconf_tuple_t *pkgconf_tuple_add(const pkgconf_client_t *client, pkgconf_list_t *list, const char *key, const char *value, bool parse)
Optionally parse and then define a variable.
:param pkgconf_client_t* client: The pkgconf client object to access.
:param pkgconf_list_t* list: The variable list to add the new variable to.
:param char* key: The name of the variable being added.
:param char* value: The value of the variable being added.
:param bool parse: Whether or not to parse the value for variable substitution.
:return: a variable object
:rtype: pkgconf_tuple_t *
.. c:function:: char *pkgconf_tuple_find(const pkgconf_client_t *client, pkgconf_list_t *list, const char *key)
Look up a variable in a variable list.
:param pkgconf_client_t* client: The pkgconf client object to access.
:param pkgconf_list_t* list: The variable list to search.
:param char* key: The variable name to search for.
:return: the value of the variable or ``NULL``
:rtype: char *
.. c:function:: char *pkgconf_tuple_parse(const pkgconf_client_t *client, pkgconf_list_t *vars, const char *value, unsigned int flags)
Parse an expression for variable substitution.
:param pkgconf_client_t* client: The pkgconf client object to access.
:param pkgconf_list_t* list: The variable list to search for variables (along side the global variable list).
:param char* value: The ``key=value`` string to parse.
:param uint flags: Any flags to consider while parsing.
:return: the variable data with any variables substituted
:rtype: char *
.. c:function:: void pkgconf_tuple_free_entry(pkgconf_tuple_t *tuple, pkgconf_list_t *list)
Deletes a variable object, removing it from any variable lists and releasing any memory associated
with it.
:param pkgconf_tuple_t* tuple: The variable object to release.
:param pkgconf_list_t* list: The variable list the variable object is attached to.
:return: nothing
.. c:function:: void pkgconf_tuple_free(pkgconf_list_t *list)
Deletes a variable list and any variables attached to it.
:param pkgconf_list_t* list: The variable list to delete.
:return: nothing
+17
View File
@@ -0,0 +1,17 @@
libpkgconf - an API for managing `pkg-config` modules
=====================================================
.. toctree::
:maxdepth: 2
libpkgconf-argvsplit
libpkgconf-audit
libpkgconf-cache
libpkgconf-client
libpkgconf-dependency
libpkgconf-fragment
libpkgconf-path
libpkgconf-personality
libpkgconf-pkg
libpkgconf-queue
libpkgconf-tuple
+12
View File
@@ -0,0 +1,12 @@
prefix=@prefix@
exec_prefix=${prefix}
includedir=@includedir@
libdir=@libdir@
Name: libpkgconf
Description: a library for accessing and manipulating development framework configuration
URL: https://gitea.treehouse.systems/ariadne/pkgconf
License: ISC
Version: @PACKAGE_VERSION@
CFlags: -I${includedir}/pkgconf
Libs: -L${libdir} -lpkgconf
+161
View File
@@ -0,0 +1,161 @@
/*
* argvsplit.c
* argv_split() routine
*
* Copyright (c) 2012, 2017 pkgconf authors (see AUTHORS).
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* This software is provided 'as is' and without any warranty, express or
* implied. In no event shall the authors be liable for any damages arising
* from the use of this software.
*/
#include <libpkgconf/stdinc.h>
#include <libpkgconf/libpkgconf.h>
/*
* !doc
*
* libpkgconf `argvsplit` module
* =============================
*
* This is a lowlevel module which provides parsing of strings into argument vectors,
* similar to what a shell would do.
*/
/*
* !doc
*
* .. c:function:: void pkgconf_argv_free(char **argv)
*
* Frees an argument vector.
*
* :param char** argv: The argument vector to free.
* :return: nothing
*/
void
pkgconf_argv_free(char **argv)
{
free(argv[0]);
free(argv);
}
/*
* !doc
*
* .. c:function:: int pkgconf_argv_split(const char *src, int *argc, char ***argv)
*
* Splits a string into an argument vector.
*
* :param char* src: The string to split.
* :param int* argc: A pointer to an integer to store the argument count.
* :param char*** argv: A pointer to a pointer for an argument vector.
* :return: 0 on success, -1 on error.
* :rtype: int
*/
int
pkgconf_argv_split(const char *src, int *argc, char ***argv)
{
char *buf = calloc(1, strlen(src) + 1);
if (buf == NULL)
return -1;
const char *src_iter;
char *dst_iter;
int argc_count = 0;
int argv_size = 5;
char quote = 0;
bool escaped = false;
src_iter = src;
dst_iter = buf;
*argv = calloc(argv_size, sizeof (void *));
if (*argv == NULL)
{
free(buf);
return -1;
}
(*argv)[argc_count] = dst_iter;
while (*src_iter)
{
if (escaped)
{
/* POSIX: only \CHAR is special inside a double quote if CHAR is {$, `, ", \, newline}. */
if (quote == '"')
{
if (!(*src_iter == '$' || *src_iter == '`' || *src_iter == '"' || *src_iter == '\\'))
*dst_iter++ = '\\';
*dst_iter++ = *src_iter;
}
else
{
*dst_iter++ = *src_iter;
}
escaped = false;
}
else if (quote)
{
if (*src_iter == quote)
quote = 0;
else if (*src_iter == '\\' && quote != '\'')
escaped = true;
else
*dst_iter++ = *src_iter;
}
else if (isspace((unsigned char)*src_iter))
{
if ((*argv)[argc_count] != NULL)
{
argc_count++, dst_iter++;
if (argc_count == argv_size)
{
argv_size += 5;
*argv = realloc(*argv, sizeof(void *) * argv_size);
}
(*argv)[argc_count] = dst_iter;
}
}
else switch(*src_iter)
{
case '\\':
escaped = true;
break;
case '\"':
case '\'':
quote = *src_iter;
break;
default:
*dst_iter++ = *src_iter;
break;
}
src_iter++;
}
if (escaped || quote)
{
free(*argv);
free(buf);
return -1;
}
if (strlen((*argv)[argc_count]))
{
argc_count++;
}
*argc = argc_count;
return 0;
}
+98
View File
@@ -0,0 +1,98 @@
/*
* audit.c
* package audit log functions
*
* Copyright (c) 2016 pkgconf authors (see AUTHORS).
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* This software is provided 'as is' and without any warranty, express or
* implied. In no event shall the authors be liable for any damages arising
* from the use of this software.
*/
#include <libpkgconf/libpkgconf.h>
/*
* !doc
*
* libpkgconf `audit` module
* =========================
*
* The libpkgconf `audit` module contains the functions related to attaching an audit log file
* to a ``pkgconf_client_t`` object.
*
* The audit log format is the same as the output generated by the ``PKG_CONFIG_LOG`` environment
* variable.
*/
/*
* !doc
*
* .. c:function:: void pkgconf_audit_set_log(pkgconf_client_t *client, FILE *auditf)
*
* Sets the audit log file pointer on `client` to `auditf`.
* The callee is responsible for closing any previous log files.
*
* :param pkgconf_client_t* client: The client object to modify.
* :param FILE* auditf: The file pointer for the already open log file.
* :return: nothing
*/
void
pkgconf_audit_set_log(pkgconf_client_t *client, FILE *auditf)
{
client->auditf = auditf;
}
/*
* !doc
*
* .. c:function:: void pkgconf_audit_log(pkgconf_client_t *client, const char *format, ...)
*
* Logs a message to the opened audit log (if any).
*
* :param pkgconf_client_t* client: The client object the log message is for.
* :param char* format: The format string to use for the log messages.
* :return: nothing
*/
void
pkgconf_audit_log(pkgconf_client_t *client, const char *format, ...)
{
va_list va;
if (client->auditf == NULL)
return;
va_start(va, format);
vfprintf(client->auditf, format, va);
va_end(va);
}
/*
* !doc
*
* .. c:function:: void pkgconf_audit_log_dependency(pkgconf_client_t *client, const pkgconf_pkg_t *dep, const pkgconf_dependency_t *depnode)
*
* Convenience function which logs a dependency node to the opened audit log (if any).
*
* :param pkgconf_client_t* client: The client object the log message is for.
* :param pkgconf_pkg_t* dep: The dependency package object being logged.
* :param pkgconf_dependency_t* depnode: The dependency object itself being logged.
* :return: nothing
*/
void
pkgconf_audit_log_dependency(pkgconf_client_t *client, const pkgconf_pkg_t *dep, const pkgconf_dependency_t *depnode)
{
if (client->auditf == NULL)
return;
fprintf(client->auditf, "%s ", dep->id);
if (depnode->version != NULL && depnode->compare != PKGCONF_CMP_ANY)
{
fprintf(client->auditf, "%s %s ", pkgconf_pkg_get_comparator(depnode), depnode->version);
}
fprintf(client->auditf, "[%s]\n", dep->version);
}
+197
View File
@@ -0,0 +1,197 @@
/* $OpenBSD: strlcpy.c,v 1.10 2005/08/08 08:05:37 espie Exp $ */
/* $OpenBSD: strlcat.c,v 1.12 2005/03/30 20:13:52 otto Exp $ */
/*
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <stdlib.h>
#include <sys/types.h>
#include <string.h>
#include <errno.h>
#ifndef _WIN32
#include <unistd.h>
#endif
#include <libpkgconf/bsdstubs.h>
#include <libpkgconf/config.h>
#if !HAVE_DECL_STRLCPY
/*
* Copy src to string dst of size siz. At most siz-1 characters
* will be copied. Always NUL terminates (unless siz == 0).
* Returns strlen(src); if retval >= siz, truncation occurred.
*/
static inline size_t
strlcpy(char *dst, const char *src, size_t siz)
{
char *d = dst;
const char *s = src;
size_t n = siz;
/* Copy as many bytes as will fit */
if (n != 0) {
while (--n != 0) {
if ((*d++ = *s++) == '\0')
break;
}
}
/* Not enough room in dst, add NUL and traverse rest of src */
if (n == 0) {
if (siz != 0)
*d = '\0'; /* NUL-terminate dst */
while (*s++)
;
}
return(s - src - 1); /* count does not include NUL */
}
#endif
#if !HAVE_DECL_STRLCAT
/*
* Appends src to string dst of size siz (unlike strncat, siz is the
* full size of dst, not space left). At most siz-1 characters
* will be copied. Always NUL terminates (unless siz <= strlen(dst)).
* Returns strlen(src) + MIN(siz, strlen(initial dst)).
* If retval >= siz, truncation occurred.
*/
static inline size_t
strlcat(char *dst, const char *src, size_t siz)
{
char *d = dst;
const char *s = src;
size_t n = siz;
size_t dlen;
/* Find the end of dst and adjust bytes left but don't go past end */
while (n-- != 0 && *d != '\0')
d++;
dlen = d - dst;
n = siz - dlen;
if (n == 0)
return(dlen + strlen(s));
while (*s != '\0') {
if (n != 1) {
*d++ = *s;
n--;
}
s++;
}
*d = '\0';
return(dlen + (s - src)); /* count does not include NUL */
}
#endif
/*
* Copyright (c) 2012 William Pitcock <nenolod@dereferenced.org>.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* This software is provided 'as is' and without any warranty, express or
* implied. In no event shall the authors be liable for any damages arising
* from the use of this software.
*/
#if !HAVE_DECL_STRNDUP
/*
* Creates a memory buffer and copies at most 'len' characters to it.
* If 'len' is less than the length of the source string, truncation occured.
*/
static inline char *
strndup(const char *src, size_t len)
{
char *out = malloc(len + 1);
pkgconf_strlcpy(out, src, len + 1);
return out;
}
#endif
#if !HAVE_DECL_PLEDGE
static inline int
pledge(const char *promises, const char *execpromises)
{
(void) promises;
(void) execpromises;
return 0;
}
#endif
#if !HAVE_DECL_UNVEIL
static inline int
unveil(const char *path, const char *permissions)
{
(void) path;
(void) permissions;
return 0;
}
#endif
size_t
pkgconf_strlcpy(char *dst, const char *src, size_t siz)
{
return strlcpy(dst, src, siz);
}
size_t
pkgconf_strlcat(char *dst, const char *src, size_t siz)
{
return strlcat(dst, src, siz);
}
char *
pkgconf_strndup(const char *src, size_t len)
{
return strndup(src, len);
}
#if !HAVE_DECL_REALLOCARRAY
void *
reallocarray(void *ptr, size_t m, size_t n)
{
if (n && m > -1 / n)
{
errno = ENOMEM;
return 0;
}
return realloc(ptr, m * n);
}
#endif
void *
pkgconf_reallocarray(void *ptr, size_t m, size_t n)
{
return reallocarray(ptr, m, n);
}
int
pkgconf_pledge(const char *promises, const char *execpromises)
{
return pledge(promises, execpromises);
}
int
pkgconf_unveil(const char *path, const char *permissions)
{
return unveil(path, permissions);
}
+36
View File
@@ -0,0 +1,36 @@
/*
* bsdstubs.h
* Header for stub BSD function prototypes if unavailable on a specific platform.
*
* Copyright (c) 2012 William Pitcock <nenolod@dereferenced.org>.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* This software is provided 'as is' and without any warranty, express or
* implied. In no event shall the authors be liable for any damages arising
* from the use of this software.
*/
#ifndef LIBPKGCONF_BSDSTUBS_H
#define LIBPKGCONF_BSDSTUBS_H
#include <libpkgconf/libpkgconf-api.h>
#ifdef __cplusplus
extern "C" {
#endif
PKGCONF_API extern size_t pkgconf_strlcpy(char *dst, const char *src, size_t siz);
PKGCONF_API extern size_t pkgconf_strlcat(char *dst, const char *src, size_t siz);
PKGCONF_API extern char *pkgconf_strndup(const char *src, size_t len);
PKGCONF_API extern void *pkgconf_reallocarray(void *ptr, size_t m, size_t n);
PKGCONF_API extern int pkgconf_pledge(const char *promises, const char *execpromises);
PKGCONF_API extern int pkgconf_unveil(const char *path, const char *permissions);
#ifdef __cplusplus
}
#endif
#endif
+87
View File
@@ -0,0 +1,87 @@
/*
* buffer.c
* dynamically-managed buffers
*
* Copyright (c) 2024 pkgconf authors (see AUTHORS).
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* This software is provided 'as is' and without any warranty, express or
* implied. In no event shall the authors be liable for any damages arising
* from the use of this software.
*/
#include <libpkgconf/stdinc.h>
#include <libpkgconf/libpkgconf.h>
/*
* !doc
*
* libpkgconf `buffer` module
* ==========================
*
* The libpkgconf `buffer` module contains the functions related to managing
* dynamically-allocated buffers.
*/
static inline size_t
target_allocation_size(size_t target_size)
{
return 4096 + (4096 * (target_size / 4096));
}
void
pkgconf_buffer_append(pkgconf_buffer_t *buffer, const char *text)
{
size_t needed = strlen(text) + 1;
size_t newsize = pkgconf_buffer_len(buffer) + needed;
char *newbase = realloc(buffer->base, target_allocation_size(newsize));
/* XXX: silently failing here is antisocial */
if (newbase == NULL)
return;
char *newend = newbase + pkgconf_buffer_len(buffer);
pkgconf_strlcpy(newend, text, needed);
buffer->base = newbase;
buffer->end = newend + needed;
}
void
pkgconf_buffer_push_byte(pkgconf_buffer_t *buffer, char byte)
{
size_t newsize = pkgconf_buffer_len(buffer) + 1;
char *newbase = realloc(buffer->base, target_allocation_size(newsize));
/* XXX: silently failing here remains antisocial */
if (newbase == NULL)
return;
char *newend = newbase + newsize;
*(newend - 1) = byte;
*newend = '\0';
buffer->base = newbase;
buffer->end = newend;
}
void
pkgconf_buffer_trim_byte(pkgconf_buffer_t *buffer)
{
size_t newsize = pkgconf_buffer_len(buffer) - 1;
char *newbase = realloc(buffer->base, target_allocation_size(newsize));
buffer->base = newbase;
buffer->end = newbase + newsize;
*(buffer->end) = '\0';
}
void
pkgconf_buffer_finalize(pkgconf_buffer_t *buffer)
{
free(buffer->base);
}
+231
View File
@@ -0,0 +1,231 @@
/*
* cache.c
* package object cache
*
* Copyright (c) 2013 pkgconf authors (see AUTHORS).
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* This software is provided 'as is' and without any warranty, express or
* implied. In no event shall the authors be liable for any damages arising
* from the use of this software.
*/
#include <libpkgconf/stdinc.h>
#include <libpkgconf/libpkgconf.h>
#include <assert.h>
/*
* !doc
*
* libpkgconf `cache` module
* =========================
*
* The libpkgconf `cache` module manages a package/module object cache, allowing it to
* avoid loading duplicate copies of a package/module.
*
* A cache is tied to a specific pkgconf client object, so package objects should not
* be shared across threads.
*/
static int
cache_member_cmp(const void *a, const void *b)
{
const char *key = a;
const pkgconf_pkg_t *pkg = *(void **) b;
return strcmp(key, pkg->id);
}
static int
cache_member_sort_cmp(const void *a, const void *b)
{
const pkgconf_pkg_t *pkgA = *(void **) a;
const pkgconf_pkg_t *pkgB = *(void **) b;
if (pkgA == NULL)
return 1;
if (pkgB == NULL)
return -1;
return strcmp(pkgA->id, pkgB->id);
}
static void
cache_dump(const pkgconf_client_t *client)
{
size_t i;
PKGCONF_TRACE(client, "dumping package cache contents");
for (i = 0; i < client->cache_count; i++)
{
const pkgconf_pkg_t *pkg = client->cache_table[i];
PKGCONF_TRACE(client, SIZE_FMT_SPECIFIER": %p(%s)",
i, pkg, pkg == NULL ? "NULL" : pkg->id);
}
}
/*
* !doc
*
* .. c:function:: pkgconf_pkg_t *pkgconf_cache_lookup(const pkgconf_client_t *client, const char *id)
*
* Looks up a package in the cache given an `id` atom,
* such as ``gtk+-3.0`` and returns the already loaded version
* if present.
*
* :param pkgconf_client_t* client: The client object to access.
* :param char* id: The package atom to look up in the client object's cache.
* :return: A package object if present, else ``NULL``.
* :rtype: pkgconf_pkg_t *
*/
pkgconf_pkg_t *
pkgconf_cache_lookup(pkgconf_client_t *client, const char *id)
{
if (client->cache_table == NULL)
return NULL;
pkgconf_pkg_t **pkg;
pkg = bsearch(id, client->cache_table,
client->cache_count, sizeof (void *),
cache_member_cmp);
if (pkg != NULL)
{
PKGCONF_TRACE(client, "found: %s @%p", id, *pkg);
return pkgconf_pkg_ref(client, *pkg);
}
PKGCONF_TRACE(client, "miss: %s", id);
return NULL;
}
/*
* !doc
*
* .. c:function:: void pkgconf_cache_add(pkgconf_client_t *client, pkgconf_pkg_t *pkg)
*
* Adds an entry for the package to the package cache.
* The cache entry must be removed if the package is freed.
*
* :param pkgconf_client_t* client: The client object to modify.
* :param pkgconf_pkg_t* pkg: The package object to add to the client object's cache.
* :return: nothing
*/
void
pkgconf_cache_add(pkgconf_client_t *client, pkgconf_pkg_t *pkg)
{
if (pkg == NULL)
return;
pkgconf_pkg_ref(client, pkg);
PKGCONF_TRACE(client, "added @%p to cache", pkg);
/* mark package as cached */
pkg->flags |= PKGCONF_PKG_PROPF_CACHED;
++client->cache_count;
client->cache_table = pkgconf_reallocarray(client->cache_table,
client->cache_count, sizeof (void *));
client->cache_table[client->cache_count - 1] = pkg;
qsort(client->cache_table, client->cache_count,
sizeof(void *), cache_member_sort_cmp);
}
/*
* !doc
*
* .. c:function:: void pkgconf_cache_remove(pkgconf_client_t *client, pkgconf_pkg_t *pkg)
*
* Deletes a package from the client object's package cache.
*
* :param pkgconf_client_t* client: The client object to modify.
* :param pkgconf_pkg_t* pkg: The package object to remove from the client object's cache.
* :return: nothing
*/
void
pkgconf_cache_remove(pkgconf_client_t *client, pkgconf_pkg_t *pkg)
{
if (client->cache_table == NULL)
return;
if (pkg == NULL)
return;
if (!(pkg->flags & PKGCONF_PKG_PROPF_CACHED))
return;
PKGCONF_TRACE(client, "removed @%p from cache", pkg);
pkgconf_pkg_t **slot;
slot = bsearch(pkg->id, client->cache_table,
client->cache_count, sizeof (void *),
cache_member_cmp);
if (slot == NULL)
return;
(*slot)->flags &= ~PKGCONF_PKG_PROPF_CACHED;
pkgconf_pkg_unref(client, *slot);
*slot = NULL;
qsort(client->cache_table, client->cache_count,
sizeof(void *), cache_member_sort_cmp);
if (client->cache_table[client->cache_count - 1] != NULL)
{
PKGCONF_TRACE(client, "end of cache table refers to %p, not NULL",
client->cache_table[client->cache_count - 1]);
cache_dump(client);
abort();
}
client->cache_count--;
if (client->cache_count > 0)
{
client->cache_table = pkgconf_reallocarray(client->cache_table,
client->cache_count, sizeof(void *));
}
else
{
free(client->cache_table);
client->cache_table = NULL;
}
}
/*
* !doc
*
* .. c:function:: void pkgconf_cache_free(pkgconf_client_t *client)
*
* Releases all resources related to a client object's package cache.
* This function should only be called to clear a client object's package cache,
* as it may release any package in the cache.
*
* :param pkgconf_client_t* client: The client object to modify.
*/
void
pkgconf_cache_free(pkgconf_client_t *client)
{
if (client->cache_table == NULL)
return;
while (client->cache_count > 0)
pkgconf_cache_remove(client, client->cache_table[0]);
free(client->cache_table);
client->cache_table = NULL;
client->cache_count = 0;
PKGCONF_TRACE(client, "cleared package cache");
}
+817
View File
@@ -0,0 +1,817 @@
/*
* client.c
* libpkgconf consumer lifecycle management
*
* Copyright (c) 2016 pkgconf authors (see AUTHORS).
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* This software is provided 'as is' and without any warranty, express or
* implied. In no event shall the authors be liable for any damages arising
* from the use of this software.
*/
#include <libpkgconf/config.h>
#include <libpkgconf/stdinc.h>
#include <libpkgconf/libpkgconf.h>
/*
* !doc
*
* libpkgconf `client` module
* ==========================
*
* The libpkgconf `client` module implements the `pkgconf_client_t` "client" object.
* Client objects store all necessary state for libpkgconf allowing for multiple instances to run
* in parallel.
*
* Client objects are not thread safe, in other words, a client object should not be shared across
* thread boundaries.
*/
static void
trace_path_list(const pkgconf_client_t *client, const char *desc, pkgconf_list_t *list)
{
const pkgconf_node_t *n;
PKGCONF_TRACE(client, "%s:", desc);
PKGCONF_FOREACH_LIST_ENTRY(list->head, n)
{
const pkgconf_path_t *p = n->data;
PKGCONF_TRACE(client, " - '%s'", p->path);
}
}
/*
* !doc
*
* .. c:function:: void pkgconf_client_dir_list_build(pkgconf_client_t *client)
*
* Bootstraps the package search paths. If the ``PKGCONF_PKG_PKGF_ENV_ONLY`` `flag` is set on the client,
* then only the ``PKG_CONFIG_PATH`` environment variable will be used, otherwise both the
* ``PKG_CONFIG_PATH`` and ``PKG_CONFIG_LIBDIR`` environment variables will be used.
*
* :param pkgconf_client_t* client: The pkgconf client object to bootstrap.
* :return: nothing
*/
void
pkgconf_client_dir_list_build(pkgconf_client_t *client, const pkgconf_cross_personality_t *personality)
{
pkgconf_path_build_from_environ("PKG_CONFIG_PATH", NULL, &client->dir_list, true);
if (!(client->flags & PKGCONF_PKG_PKGF_ENV_ONLY))
{
pkgconf_list_t dir_list = PKGCONF_LIST_INITIALIZER;
const pkgconf_list_t *prepend_list = &personality->dir_list;
#ifdef _WIN32
(void) pkgconf_path_build_from_registry(HKEY_CURRENT_USER, &client->dir_list, true);
(void) pkgconf_path_build_from_registry(HKEY_LOCAL_MACHINE, &client->dir_list, true);
#endif
if (getenv("PKG_CONFIG_LIBDIR") != NULL)
{
/* PKG_CONFIG_LIBDIR= should empty the search path entirely. */
(void) pkgconf_path_build_from_environ("PKG_CONFIG_LIBDIR", NULL, &dir_list, true);
prepend_list = &dir_list;
}
pkgconf_path_copy_list(&client->dir_list, prepend_list);
pkgconf_path_free(&dir_list);
}
}
/*
* !doc
*
* .. c:function:: void pkgconf_client_init(pkgconf_client_t *client, pkgconf_error_handler_func_t error_handler, void *error_handler_data, const pkgconf_cross_personality_t *personality)
*
* Initialise a pkgconf client object.
*
* :param pkgconf_client_t* client: The client to initialise.
* :param pkgconf_error_handler_func_t error_handler: An optional error handler to use for logging errors.
* :param void* error_handler_data: user data passed to optional error handler
* :param pkgconf_cross_personality_t* personality: the cross-compile personality to use for defaults
* :return: nothing
*/
void
pkgconf_client_init(pkgconf_client_t *client, pkgconf_error_handler_func_t error_handler, void *error_handler_data, const pkgconf_cross_personality_t *personality)
{
client->error_handler_data = error_handler_data;
client->error_handler = error_handler;
client->auditf = NULL;
client->cache_table = NULL;
client->cache_count = 0;
#ifndef PKGCONF_LITE
if (client->trace_handler == NULL)
pkgconf_client_set_trace_handler(client, NULL, NULL);
#endif
if (client->unveil_handler == NULL)
pkgconf_client_set_unveil_handler(client, NULL);
pkgconf_client_set_error_handler(client, error_handler, error_handler_data);
pkgconf_client_set_warn_handler(client, NULL, NULL);
pkgconf_client_set_sysroot_dir(client, personality->sysroot_dir);
pkgconf_client_set_buildroot_dir(client, NULL);
pkgconf_client_set_prefix_varname(client, NULL);
if(getenv("PKG_CONFIG_SYSTEM_LIBRARY_PATH") == NULL)
pkgconf_path_copy_list(&client->filter_libdirs, &personality->filter_libdirs);
else
pkgconf_path_build_from_environ("PKG_CONFIG_SYSTEM_LIBRARY_PATH", NULL, &client->filter_libdirs, false);
if(getenv("PKG_CONFIG_SYSTEM_INCLUDE_PATH") == NULL)
pkgconf_path_copy_list(&client->filter_includedirs, &personality->filter_includedirs);
else
pkgconf_path_build_from_environ("PKG_CONFIG_SYSTEM_INCLUDE_PATH", NULL, &client->filter_includedirs, false);
/* GCC uses these environment variables to define system include paths, so we should check them. */
#ifdef __HAIKU__
pkgconf_path_build_from_environ("BELIBRARIES", NULL, &client->filter_libdirs, false);
#else
pkgconf_path_build_from_environ("LIBRARY_PATH", NULL, &client->filter_libdirs, false);
#endif
pkgconf_path_build_from_environ("CPATH", NULL, &client->filter_includedirs, false);
pkgconf_path_build_from_environ("C_INCLUDE_PATH", NULL, &client->filter_includedirs, false);
pkgconf_path_build_from_environ("CPLUS_INCLUDE_PATH", NULL, &client->filter_includedirs, false);
pkgconf_path_build_from_environ("OBJC_INCLUDE_PATH", NULL, &client->filter_includedirs, false);
#ifdef _WIN32
/* also use the path lists that MSVC uses on windows */
pkgconf_path_build_from_environ("INCLUDE", NULL, &client->filter_includedirs, false);
#endif
PKGCONF_TRACE(client, "initialized client @%p", client);
trace_path_list(client, "filtered library paths", &client->filter_libdirs);
trace_path_list(client, "filtered include paths", &client->filter_includedirs);
}
/*
* !doc
*
* .. c:function:: pkgconf_client_t* pkgconf_client_new(pkgconf_error_handler_func_t error_handler, void *error_handler_data, const pkgconf_cross_personality_t *personality)
*
* Allocate and initialise a pkgconf client object.
*
* :param pkgconf_error_handler_func_t error_handler: An optional error handler to use for logging errors.
* :param void* error_handler_data: user data passed to optional error handler
* :param pkgconf_cross_personality_t* personality: cross-compile personality to use
* :return: A pkgconf client object.
* :rtype: pkgconf_client_t*
*/
pkgconf_client_t *
pkgconf_client_new(pkgconf_error_handler_func_t error_handler, void *error_handler_data, const pkgconf_cross_personality_t *personality)
{
pkgconf_client_t *out = calloc(1, sizeof(pkgconf_client_t));
if (out == NULL)
return NULL;
pkgconf_client_init(out, error_handler, error_handler_data, personality);
return out;
}
static void
unref_preload_list(pkgconf_client_t *client)
{
pkgconf_node_t *n, *tn;
PKGCONF_FOREACH_LIST_ENTRY_SAFE(client->preloaded_pkgs.head, n, tn)
{
pkgconf_pkg_t *pkg = n->data;
pkgconf_pkg_unref(client, pkg);
}
}
/*
* !doc
*
* .. c:function:: void pkgconf_client_deinit(pkgconf_client_t *client)
*
* Release resources belonging to a pkgconf client object.
*
* :param pkgconf_client_t* client: The client to deinitialise.
* :return: nothing
*/
void
pkgconf_client_deinit(pkgconf_client_t *client)
{
PKGCONF_TRACE(client, "deinit @%p", client);
unref_preload_list(client);
if (client->prefix_varname != NULL)
free(client->prefix_varname);
if (client->sysroot_dir != NULL)
free(client->sysroot_dir);
if (client->buildroot_dir != NULL)
free(client->buildroot_dir);
pkgconf_path_free(&client->filter_libdirs);
pkgconf_path_free(&client->filter_includedirs);
pkgconf_tuple_free_global(client);
pkgconf_path_free(&client->dir_list);
pkgconf_cache_free(client);
}
/*
* !doc
*
* .. c:function:: void pkgconf_client_free(pkgconf_client_t *client)
*
* Release resources belonging to a pkgconf client object and then free the client object itself.
*
* :param pkgconf_client_t* client: The client to deinitialise and free.
* :return: nothing
*/
void
pkgconf_client_free(pkgconf_client_t *client)
{
pkgconf_client_deinit(client);
free(client);
}
/*
* !doc
*
* .. c:function:: const char *pkgconf_client_get_sysroot_dir(const pkgconf_client_t *client)
*
* Retrieves the client's sysroot directory (if any).
*
* :param pkgconf_client_t* client: The client object being accessed.
* :return: A string containing the sysroot directory or NULL.
* :rtype: const char *
*/
const char *
pkgconf_client_get_sysroot_dir(const pkgconf_client_t *client)
{
return client->sysroot_dir;
}
/*
* !doc
*
* .. c:function:: void pkgconf_client_set_sysroot_dir(pkgconf_client_t *client, const char *sysroot_dir)
*
* Sets or clears the sysroot directory on a client object. Any previous sysroot directory setting is
* automatically released if one was previously set.
*
* Additionally, the global tuple ``$(pc_sysrootdir)`` is set as appropriate based on the new setting.
*
* :param pkgconf_client_t* client: The client object being modified.
* :param char* sysroot_dir: The sysroot directory to set or NULL to unset.
* :return: nothing
*/
void
pkgconf_client_set_sysroot_dir(pkgconf_client_t *client, const char *sysroot_dir)
{
if (client->sysroot_dir != NULL)
free(client->sysroot_dir);
client->sysroot_dir = sysroot_dir != NULL ? strdup(sysroot_dir) : NULL;
PKGCONF_TRACE(client, "set sysroot_dir to: %s", client->sysroot_dir != NULL ? client->sysroot_dir : "<default>");
pkgconf_tuple_add_global(client, "pc_sysrootdir", client->sysroot_dir != NULL ? client->sysroot_dir : "/");
}
/*
* !doc
*
* .. c:function:: const char *pkgconf_client_get_buildroot_dir(const pkgconf_client_t *client)
*
* Retrieves the client's buildroot directory (if any).
*
* :param pkgconf_client_t* client: The client object being accessed.
* :return: A string containing the buildroot directory or NULL.
* :rtype: const char *
*/
const char *
pkgconf_client_get_buildroot_dir(const pkgconf_client_t *client)
{
return client->buildroot_dir;
}
/*
* !doc
*
* .. c:function:: void pkgconf_client_set_buildroot_dir(pkgconf_client_t *client, const char *buildroot_dir)
*
* Sets or clears the buildroot directory on a client object. Any previous buildroot directory setting is
* automatically released if one was previously set.
*
* Additionally, the global tuple ``$(pc_top_builddir)`` is set as appropriate based on the new setting.
*
* :param pkgconf_client_t* client: The client object being modified.
* :param char* buildroot_dir: The buildroot directory to set or NULL to unset.
* :return: nothing
*/
void
pkgconf_client_set_buildroot_dir(pkgconf_client_t *client, const char *buildroot_dir)
{
if (client->buildroot_dir != NULL)
free(client->buildroot_dir);
client->buildroot_dir = buildroot_dir != NULL ? strdup(buildroot_dir) : NULL;
PKGCONF_TRACE(client, "set buildroot_dir to: %s", client->buildroot_dir != NULL ? client->buildroot_dir : "<default>");
pkgconf_tuple_add_global(client, "pc_top_builddir", client->buildroot_dir != NULL ? client->buildroot_dir : "$(top_builddir)");
}
/*
* !doc
*
* .. c:function:: bool pkgconf_error(const pkgconf_client_t *client, const char *format, ...)
*
* Report an error to a client-registered error handler.
*
* :param pkgconf_client_t* client: The pkgconf client object to report the error to.
* :param char* format: A printf-style format string to use for formatting the error message.
* :return: true if the error handler processed the message, else false.
* :rtype: bool
*/
bool
pkgconf_error(const pkgconf_client_t *client, const char *format, ...)
{
char *errbuf;
ssize_t msgsize = 0;
bool ret;
va_list va;
va_start(va, format);
msgsize = vsnprintf(NULL, 0, format, va);
va_end(va);
if (msgsize < 0)
return false;
msgsize++;
errbuf = calloc(1, msgsize);
if (errbuf == NULL)
return false;
va_start(va, format);
vsnprintf(errbuf, msgsize, format, va);
va_end(va);
ret = client->error_handler(errbuf, client, client->error_handler_data);
free(errbuf);
return ret;
}
/*
* !doc
*
* .. c:function:: bool pkgconf_warn(const pkgconf_client_t *client, const char *format, ...)
*
* Report an error to a client-registered warn handler.
*
* :param pkgconf_client_t* client: The pkgconf client object to report the error to.
* :param char* format: A printf-style format string to use for formatting the warning message.
* :return: true if the warn handler processed the message, else false.
* :rtype: bool
*/
bool
pkgconf_warn(const pkgconf_client_t *client, const char *format, ...)
{
char *errbuf;
ssize_t msgsize = 0;
bool ret;
va_list va;
va_start(va, format);
msgsize = vsnprintf(NULL, 0, format, va);
va_end(va);
if (msgsize < 0)
return false;
msgsize++;
errbuf = calloc(1, msgsize);
if (errbuf == NULL)
return false;
va_start(va, format);
vsnprintf(errbuf, msgsize, format, va);
va_end(va);
ret = client->warn_handler(errbuf, client, client->warn_handler_data);
free(errbuf);
return ret;
}
/*
* !doc
*
* .. c:function:: bool pkgconf_trace(const pkgconf_client_t *client, const char *filename, size_t len, const char *funcname, const char *format, ...)
*
* Report a message to a client-registered trace handler.
*
* :param pkgconf_client_t* client: The pkgconf client object to report the trace message to.
* :param char* filename: The file the function is in.
* :param size_t lineno: The line number currently being executed.
* :param char* funcname: The function name to use.
* :param char* format: A printf-style format string to use for formatting the trace message.
* :return: true if the trace handler processed the message, else false.
* :rtype: bool
*/
bool
pkgconf_trace(const pkgconf_client_t *client, const char *filename, size_t lineno, const char *funcname, const char *format, ...)
{
char prefix[PKGCONF_ITEM_SIZE];
char *errbuf = NULL;
ssize_t errlen;
char *finalbuf = NULL;
ssize_t finallen;
bool ret;
va_list va;
if (client == NULL || client->trace_handler == NULL)
return false;
snprintf(prefix, sizeof prefix, "%s:" SIZE_FMT_SPECIFIER " [%s]:", filename, lineno, funcname);
va_start(va, format);
errlen = vsnprintf(NULL, 0, format, va);
va_end(va);
if (errlen < 0)
return false;
errlen++;
errbuf = calloc(1, errlen);
if (errbuf == NULL)
return false;
va_start(va, format);
vsnprintf(errbuf, errlen, format, va);
va_end(va);
finallen = snprintf(NULL, 0, "%s %s\n", prefix, errbuf);
if (finallen < 0)
return false;
finallen++;
finalbuf = calloc(1, finallen);
if (finalbuf == NULL)
return false;
snprintf(finalbuf, finallen, "%s %s\n", prefix, errbuf);
ret = client->trace_handler(finalbuf, client, client->trace_handler_data);
free(errbuf);
free(finalbuf);
return ret;
}
/*
* !doc
*
* .. c:function:: bool pkgconf_default_error_handler(const char *msg, const pkgconf_client_t *client, const void *data)
*
* The default pkgconf error handler.
*
* :param char* msg: The error message to handle.
* :param pkgconf_client_t* client: The client object the error originated from.
* :param void* data: An opaque pointer to extra data associated with the client for error handling.
* :return: true (the function does nothing to process the message)
* :rtype: bool
*/
bool
pkgconf_default_error_handler(const char *msg, const pkgconf_client_t *client, void *data)
{
(void) msg;
(void) client;
(void) data;
return true;
}
static void
default_unveil_handler(const pkgconf_client_t *client, const char *path, const char *permissions)
{
(void) client;
(void) path;
(void) permissions;
}
/*
* !doc
*
* .. c:function:: unsigned int pkgconf_client_get_flags(const pkgconf_client_t *client)
*
* Retrieves resolver-specific flags associated with a client object.
*
* :param pkgconf_client_t* client: The client object to retrieve the resolver-specific flags from.
* :return: a bitfield of resolver-specific flags
* :rtype: uint
*/
unsigned int
pkgconf_client_get_flags(const pkgconf_client_t *client)
{
return client->flags;
}
/*
* !doc
*
* .. c:function:: void pkgconf_client_set_flags(pkgconf_client_t *client, unsigned int flags)
*
* Sets resolver-specific flags associated with a client object.
*
* :param pkgconf_client_t* client: The client object to set the resolver-specific flags on.
* :return: nothing
*/
void
pkgconf_client_set_flags(pkgconf_client_t *client, unsigned int flags)
{
client->flags = flags;
}
/*
* !doc
*
* .. c:function:: const char *pkgconf_client_get_prefix_varname(const pkgconf_client_t *client)
*
* Retrieves the name of the variable that should contain a module's prefix.
* In some cases, it is necessary to override this variable to allow proper path relocation.
*
* :param pkgconf_client_t* client: The client object to retrieve the prefix variable name from.
* :return: the prefix variable name as a string
* :rtype: const char *
*/
const char *
pkgconf_client_get_prefix_varname(const pkgconf_client_t *client)
{
return client->prefix_varname;
}
/*
* !doc
*
* .. c:function:: void pkgconf_client_set_prefix_varname(pkgconf_client_t *client, const char *prefix_varname)
*
* Sets the name of the variable that should contain a module's prefix.
* If the variable name is ``NULL``, then the default variable name (``prefix``) is used.
*
* :param pkgconf_client_t* client: The client object to set the prefix variable name on.
* :param char* prefix_varname: The prefix variable name to set.
* :return: nothing
*/
void
pkgconf_client_set_prefix_varname(pkgconf_client_t *client, const char *prefix_varname)
{
if (prefix_varname == NULL)
prefix_varname = "prefix";
if (client->prefix_varname != NULL)
free(client->prefix_varname);
client->prefix_varname = strdup(prefix_varname);
PKGCONF_TRACE(client, "set prefix_varname to: %s", client->prefix_varname);
}
/*
* !doc
*
* .. c:function:: pkgconf_client_get_warn_handler(const pkgconf_client_t *client)
*
* Returns the warning handler if one is set, else ``NULL``.
*
* :param pkgconf_client_t* client: The client object to get the warn handler from.
* :return: a function pointer to the warn handler or ``NULL``
*/
pkgconf_error_handler_func_t
pkgconf_client_get_warn_handler(const pkgconf_client_t *client)
{
return client->warn_handler;
}
/*
* !doc
*
* .. c:function:: pkgconf_client_set_warn_handler(pkgconf_client_t *client, pkgconf_error_handler_func_t warn_handler, void *warn_handler_data)
*
* Sets a warn handler on a client object or uninstalls one if set to ``NULL``.
*
* :param pkgconf_client_t* client: The client object to set the warn handler on.
* :param pkgconf_error_handler_func_t warn_handler: The warn handler to set.
* :param void* warn_handler_data: Optional data to associate with the warn handler.
* :return: nothing
*/
void
pkgconf_client_set_warn_handler(pkgconf_client_t *client, pkgconf_error_handler_func_t warn_handler, void *warn_handler_data)
{
client->warn_handler = warn_handler;
client->warn_handler_data = warn_handler_data;
if (client->warn_handler == NULL)
{
PKGCONF_TRACE(client, "installing default warn handler");
client->warn_handler = pkgconf_default_error_handler;
}
}
/*
* !doc
*
* .. c:function:: pkgconf_client_get_error_handler(const pkgconf_client_t *client)
*
* Returns the error handler if one is set, else ``NULL``.
*
* :param pkgconf_client_t* client: The client object to get the error handler from.
* :return: a function pointer to the error handler or ``NULL``
*/
pkgconf_error_handler_func_t
pkgconf_client_get_error_handler(const pkgconf_client_t *client)
{
return client->error_handler;
}
/*
* !doc
*
* .. c:function:: pkgconf_client_set_error_handler(pkgconf_client_t *client, pkgconf_error_handler_func_t error_handler, void *error_handler_data)
*
* Sets a warn handler on a client object or uninstalls one if set to ``NULL``.
*
* :param pkgconf_client_t* client: The client object to set the error handler on.
* :param pkgconf_error_handler_func_t error_handler: The error handler to set.
* :param void* error_handler_data: Optional data to associate with the error handler.
* :return: nothing
*/
void
pkgconf_client_set_error_handler(pkgconf_client_t *client, pkgconf_error_handler_func_t error_handler, void *error_handler_data)
{
client->error_handler = error_handler;
client->error_handler_data = error_handler_data;
if (client->error_handler == NULL)
{
PKGCONF_TRACE(client, "installing default error handler");
client->error_handler = pkgconf_default_error_handler;
}
}
/*
* !doc
*
* .. c:function:: pkgconf_client_get_unveil_handler(const pkgconf_client_t *client)
*
* Returns the unveil handler if one is set, else ``NULL``.
*
* :param pkgconf_client_t* client: The client object to get the unveil handler from.
* :return: a function pointer to the error handler or ``NULL``
*/
pkgconf_unveil_handler_func_t
pkgconf_client_get_unveil_handler(const pkgconf_client_t *client)
{
return client->unveil_handler;
}
/*
* !doc
*
* .. c:function:: pkgconf_client_set_unveil_handler(pkgconf_client_t *client, pkgconf_unveil_handler_func_t unveil_handler)
*
* Sets an unveil handler on a client object or uninstalls one if set to ``NULL``.
*
* :param pkgconf_client_t* client: The client object to set the error handler on.
* :param pkgconf_unveil_handler_func_t unveil_handler: The unveil handler to set.
* :return: nothing
*/
void
pkgconf_client_set_unveil_handler(pkgconf_client_t *client, pkgconf_unveil_handler_func_t unveil_handler)
{
client->unveil_handler = unveil_handler;
if (client->unveil_handler == NULL)
{
PKGCONF_TRACE(client, "installing default unveil handler");
client->unveil_handler = default_unveil_handler;
}
}
#ifndef PKGCONF_LITE
/*
* !doc
*
* .. c:function:: pkgconf_client_get_trace_handler(const pkgconf_client_t *client)
*
* Returns the error handler if one is set, else ``NULL``.
*
* :param pkgconf_client_t* client: The client object to get the error handler from.
* :return: a function pointer to the error handler or ``NULL``
*/
pkgconf_error_handler_func_t
pkgconf_client_get_trace_handler(const pkgconf_client_t *client)
{
return client->trace_handler;
}
/*
* !doc
*
* .. c:function:: pkgconf_client_set_trace_handler(pkgconf_client_t *client, pkgconf_error_handler_func_t trace_handler, void *trace_handler_data)
*
* Sets a warn handler on a client object or uninstalls one if set to ``NULL``.
*
* :param pkgconf_client_t* client: The client object to set the error handler on.
* :param pkgconf_error_handler_func_t trace_handler: The error handler to set.
* :param void* trace_handler_data: Optional data to associate with the error handler.
* :return: nothing
*/
void
pkgconf_client_set_trace_handler(pkgconf_client_t *client, pkgconf_error_handler_func_t trace_handler, void *trace_handler_data)
{
client->trace_handler = trace_handler;
client->trace_handler_data = trace_handler_data;
if (client->trace_handler == NULL)
{
client->trace_handler = pkgconf_default_error_handler;
PKGCONF_TRACE(client, "installing default trace handler");
}
}
#endif
/*
* !doc
*
* .. c:function:: bool pkgconf_client_preload_path(pkgconf_client_t *client, const char *path)
*
* Loads a pkg-config file into the preloaded packages set.
*
* :param pkgconf_client_t* client: The client object for preloading.
* :param char* path: The path to the pkg-config file to preload.
* :return: true on success, false on error
* :rtype: bool
*/
bool
pkgconf_client_preload_path(pkgconf_client_t *client, const char *path)
{
pkgconf_pkg_t *pkg = pkgconf_pkg_new_from_path(client, path, PKGCONF_PKG_PROPF_PRELOADED);
if (pkg == NULL)
return false;
pkgconf_pkg_ref(client, pkg);
pkgconf_node_insert_tail(&pkg->preload_node, pkg, &client->preloaded_pkgs);
return true;
}
/*
* !doc
*
* .. c:function:: bool pkgconf_client_preload_from_environ(pkgconf_client_t *client, const char *env)
*
* Loads zero or more pkg-config files specified in the given environmental
* variable.
*
* :param pkgconf_client_t* client: The client object for preloading.
* :param char* environ: The environment variable to use for preloading.
* :return: true on success, false on error
* :rtype: bool
*/
bool
pkgconf_client_preload_from_environ(pkgconf_client_t *client, const char *env)
{
const char *data;
pkgconf_list_t pathlist = PKGCONF_LIST_INITIALIZER;
pkgconf_node_t *n;
bool ret;
data = getenv(env);
if (data == NULL)
return true;
pkgconf_path_split(data, &pathlist, true);
PKGCONF_FOREACH_LIST_ENTRY(pathlist.head, n)
{
pkgconf_path_t *pn = n->data;
ret = pkgconf_client_preload_path(client, pn->path);
if (!ret)
break;
}
pkgconf_path_free(&pathlist);
return ret;
}
+79
View File
@@ -0,0 +1,79 @@
/* libpkgconf/config.h.in. Generated from configure.ac by autoheader. */
/* Define to 1 if you have the `strlcat' function. */
#mesondefine HAVE_STRLCAT
/* Define to 1 if you have the `strlcpy' function. */
#mesondefine HAVE_STRLCPY
/* Define to 1 if you have the `strndup' function. */
#mesondefine HAVE_STRNDUP
/* Define to 1 if you have the `reallocarray' function. */
#mesondefine HAVE_REALLOCARRAY
/* Define to 1 if you have the `strlcat' function. */
#mesondefine HAVE_DECL_STRLCAT
/* Define to 1 if you have the `strlcpy' function. */
#mesondefine HAVE_DECL_STRLCPY
/* Define to 1 if you have the `strndup' function. */
#mesondefine HAVE_DECL_STRNDUP
/* Define to 1 if you have the `reallocarray' function. */
#mesondefine HAVE_DECL_REALLOCARRAY
/* Define to 1 if you have the `pledge' function. */
#mesondefine HAVE_DECL_PLEDGE
/* Define to 1 if you have the `unveil' function. */
#mesondefine HAVE_DECL_UNVEIL
/* Name of package */
#mesondefine PACKAGE
/* Define to the address where bug reports for this package should be sent. */
#mesondefine PACKAGE_BUGREPORT
/* Define to the full name of this package. */
#mesondefine PACKAGE_NAME
/* Define to the full name and version of this package. */
#mesondefine PACKAGE_STRING
/* Define to the one symbol short name of this package. */
#mesondefine PACKAGE_TARNAME
/* Define to the home page for this package. */
#mesondefine PACKAGE_URL
/* Define to the version of this package. */
#mesondefine PACKAGE_VERSION
/* Define to 1 if you have the ANSI C header files. */
#mesondefine STDC_HEADERS
/* Version number of package */
#mesondefine VERSION
/* Enable large inode numbers on Mac OS X 10.5. */
#ifndef _DARWIN_USE_64_BIT_INODE
# define _DARWIN_USE_64_BIT_INODE 1
#endif
/* Number of bits in a file offset, on hosts where this is settable. */
#mesondefine _FILE_OFFSET_BITS
/* Define for large files, on AIX-style hosts. */
#mesondefine _LARGE_FILES
#mesondefine PKG_DEFAULT_PATH
#mesondefine SYSTEM_INCLUDEDIR
#mesondefine SYSTEM_LIBDIR
#mesondefine PERSONALITY_PATH
/* Enable Solaris extensions. */
#ifndef __EXTENSIONS__
# define __EXTENSIONS__ 1
#endif
+506
View File
@@ -0,0 +1,506 @@
/*
* dependency.c
* dependency parsing and management
*
* Copyright (c) 2011, 2012, 2013 pkgconf authors (see AUTHORS).
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* This software is provided 'as is' and without any warranty, express or
* implied. In no event shall the authors be liable for any damages arising
* from the use of this software.
*/
#include <libpkgconf/stdinc.h>
#include <libpkgconf/libpkgconf.h>
/*
* !doc
*
* libpkgconf `dependency` module
* ==============================
*
* The `dependency` module provides support for building `dependency lists` (the basic component of the overall `dependency graph`) and
* `dependency nodes` which store dependency information.
*/
typedef enum {
OUTSIDE_MODULE = 0,
INSIDE_MODULE_NAME = 1,
BEFORE_OPERATOR = 2,
INSIDE_OPERATOR = 3,
AFTER_OPERATOR = 4,
INSIDE_VERSION = 5
} parse_state_t;
#define DEBUG_PARSE 0
static const char *
dependency_to_str(const pkgconf_dependency_t *dep, char *buf, size_t buflen)
{
pkgconf_strlcpy(buf, dep->package, buflen);
if (dep->version != NULL)
{
pkgconf_strlcat(buf, " ", buflen);
pkgconf_strlcat(buf, pkgconf_pkg_get_comparator(dep), buflen);
pkgconf_strlcat(buf, " ", buflen);
pkgconf_strlcat(buf, dep->version, buflen);
}
return buf;
}
/* find a colliding dependency that is coloured differently */
static inline pkgconf_dependency_t *
find_colliding_dependency(const pkgconf_dependency_t *dep, const pkgconf_list_t *list)
{
const pkgconf_node_t *n;
PKGCONF_FOREACH_LIST_ENTRY(list->head, n)
{
pkgconf_dependency_t *dep2 = n->data;
if (strcmp(dep->package, dep2->package))
continue;
if (dep->flags != dep2->flags)
return dep2;
}
return NULL;
}
static inline pkgconf_dependency_t *
add_or_replace_dependency_node(pkgconf_client_t *client, pkgconf_dependency_t *dep, pkgconf_list_t *list)
{
char depbuf[PKGCONF_ITEM_SIZE];
pkgconf_dependency_t *dep2 = find_colliding_dependency(dep, list);
/* there is already a node in the graph which describes this dependency */
if (dep2 != NULL)
{
char depbuf2[PKGCONF_ITEM_SIZE];
PKGCONF_TRACE(client, "dependency collision: [%s/%x] -- [%s/%x]",
dependency_to_str(dep, depbuf, sizeof depbuf), dep->flags,
dependency_to_str(dep2, depbuf2, sizeof depbuf2), dep2->flags);
/* prefer the uncoloured node, either dep or dep2 */
if (dep->flags && dep2->flags == 0)
{
PKGCONF_TRACE(client, "dropping dependency [%s]@%p because of collision", depbuf, dep);
pkgconf_dependency_unref(dep->owner, dep);
return NULL;
}
else if (dep2->flags && dep->flags == 0)
{
PKGCONF_TRACE(client, "dropping dependency [%s]@%p because of collision", depbuf2, dep2);
pkgconf_node_delete(&dep2->iter, list);
pkgconf_dependency_unref(dep2->owner, dep2);
}
else
/* If both dependencies have equal strength, we keep both, because of situations like:
* Requires: foo > 1, foo < 3
*
* If the situation is that both dependencies are literally equal, it is still harmless because
* fragment deduplication will handle the excessive fragments.
*/
PKGCONF_TRACE(client, "keeping both dependencies (harmless)");
}
PKGCONF_TRACE(client, "added dependency [%s] to list @%p; flags=%x", dependency_to_str(dep, depbuf, sizeof depbuf), list, dep->flags);
pkgconf_node_insert_tail(&dep->iter, pkgconf_dependency_ref(dep->owner, dep), list);
/* This dependency is intentionally unowned.
*
* Internally we have no use for the returned type, and usually just
* discard it. However, there is a publig pkgconf_dependency_add
* function, which references this return value before returning it,
* giving ownership at that point.
*/
return dep;
}
static inline pkgconf_dependency_t *
pkgconf_dependency_addraw(pkgconf_client_t *client, pkgconf_list_t *list, const char *package, size_t package_sz, const char *version, size_t version_sz, pkgconf_pkg_comparator_t compare, unsigned int flags)
{
pkgconf_dependency_t *dep;
dep = calloc(1, sizeof(pkgconf_dependency_t));
if (dep == NULL)
return NULL;
dep->package = pkgconf_strndup(package, package_sz);
if (version_sz != 0)
dep->version = pkgconf_strndup(version, version_sz);
dep->compare = compare;
dep->flags = flags;
dep->owner = client;
dep->refcount = 0;
return add_or_replace_dependency_node(client, dep, list);
}
/*
* !doc
*
* .. c:function:: pkgconf_dependency_t *pkgconf_dependency_add(pkgconf_list_t *list, const char *package, const char *version, pkgconf_pkg_comparator_t compare)
*
* Adds a parsed dependency to a dependency list as a dependency node.
*
* :param pkgconf_client_t* client: The client object that owns the package this dependency list belongs to.
* :param pkgconf_list_t* list: The dependency list to add a dependency node to.
* :param char* package: The package `atom` to set on the dependency node.
* :param char* version: The package `version` to set on the dependency node.
* :param pkgconf_pkg_comparator_t compare: The comparison operator to set on the dependency node.
* :param uint flags: Any flags to attach to the dependency node.
* :return: A dependency node.
* :rtype: pkgconf_dependency_t *
*/
pkgconf_dependency_t *
pkgconf_dependency_add(pkgconf_client_t *client, pkgconf_list_t *list, const char *package, const char *version, pkgconf_pkg_comparator_t compare, unsigned int flags)
{
pkgconf_dependency_t *dep;
dep = pkgconf_dependency_addraw(client, list, package, strlen(package), version,
version != NULL ? strlen(version) : 0, compare, flags);
return pkgconf_dependency_ref(dep->owner, dep);
}
/*
* !doc
*
* .. c:function:: void pkgconf_dependency_append(pkgconf_list_t *list, pkgconf_dependency_t *tail)
*
* Adds a dependency node to a pre-existing dependency list.
*
* :param pkgconf_list_t* list: The dependency list to add a dependency node to.
* :param pkgconf_dependency_t* tail: The dependency node to add to the tail of the dependency list.
* :return: nothing
*/
void
pkgconf_dependency_append(pkgconf_list_t *list, pkgconf_dependency_t *tail)
{
pkgconf_node_insert_tail(&tail->iter, tail, list);
}
/*
* !doc
*
* .. c:function:: void pkgconf_dependency_free_one(pkgconf_dependency_t *dep)
*
* Frees a dependency node.
*
* :param pkgconf_dependency_t* dep: The dependency node to free.
* :return: nothing
*/
void
pkgconf_dependency_free_one(pkgconf_dependency_t *dep)
{
if (dep->match != NULL)
pkgconf_pkg_unref(dep->match->owner, dep->match);
if (dep->package != NULL)
free(dep->package);
if (dep->version != NULL)
free(dep->version);
free(dep);
}
/*
* !doc
*
* .. c:function:: pkgconf_dependency_t *pkgconf_dependency_ref(pkgconf_client_t *owner, pkgconf_dependency_t *dep)
*
* Increases a dependency node's refcount.
*
* :param pkgconf_client_t* owner: The client object which owns the memory of this dependency node.
* :param pkgconf_dependency_t* dep: The dependency to increase the refcount of.
* :return: the dependency node on success, else NULL
*/
pkgconf_dependency_t *
pkgconf_dependency_ref(pkgconf_client_t *client, pkgconf_dependency_t *dep)
{
if (client != dep->owner)
return NULL;
dep->refcount++;
PKGCONF_TRACE(client, "%s refcount@%p: %d", dep->package, dep, dep->refcount);
return dep;
}
/*
* !doc
*
* .. c:function:: void pkgconf_dependency_unref(pkgconf_client_t *owner, pkgconf_dependency_t *dep)
*
* Decreases a dependency node's refcount and frees it if necessary.
*
* :param pkgconf_client_t* owner: The client object which owns the memory of this dependency node.
* :param pkgconf_dependency_t* dep: The dependency to decrease the refcount of.
* :return: nothing
*/
void
pkgconf_dependency_unref(pkgconf_client_t *client, pkgconf_dependency_t *dep)
{
if (client != dep->owner)
return;
--dep->refcount;
PKGCONF_TRACE(client, "%s refcount@%p: %d", dep->package, dep, dep->refcount);
if (dep->refcount <= 0)
pkgconf_dependency_free_one(dep);
}
/*
* !doc
*
* .. c:function:: void pkgconf_dependency_free(pkgconf_list_t *list)
*
* Release a dependency list and its child dependency nodes.
*
* :param pkgconf_list_t* list: The dependency list to release.
* :return: nothing
*/
void
pkgconf_dependency_free(pkgconf_list_t *list)
{
pkgconf_node_t *node, *next;
PKGCONF_FOREACH_LIST_ENTRY_SAFE(list->head, next, node)
{
pkgconf_dependency_t *dep = node->data;
pkgconf_node_delete(&dep->iter, list);
pkgconf_dependency_unref(dep->owner, dep);
}
pkgconf_list_zero(list);
}
/*
* !doc
*
* .. c:function:: void pkgconf_dependency_parse_str(pkgconf_list_t *deplist_head, const char *depends)
*
* Parse a dependency declaration into a dependency list.
* Commas are counted as whitespace to allow for constructs such as ``@SUBSTVAR@, zlib`` being processed
* into ``, zlib``.
*
* :param pkgconf_client_t* client: The client object that owns the package this dependency list belongs to.
* :param pkgconf_list_t* deplist_head: The dependency list to populate with dependency nodes.
* :param char* depends: The dependency data to parse.
* :param uint flags: Any flags to attach to the dependency nodes.
* :return: nothing
*/
void
pkgconf_dependency_parse_str(pkgconf_client_t *client, pkgconf_list_t *deplist_head, const char *depends, unsigned int flags)
{
parse_state_t state = OUTSIDE_MODULE;
pkgconf_pkg_comparator_t compare = PKGCONF_CMP_ANY;
char cmpname[PKGCONF_ITEM_SIZE];
size_t package_sz = 0, version_sz = 0, buf_sz = 0;
char *buf;
char *start = NULL;
char *ptr = NULL;
char *vstart = NULL;
char *package = NULL, *version = NULL;
char *cnameptr = cmpname;
char *cnameend = cmpname + PKGCONF_ITEM_SIZE - 1;
if (!*depends)
return;
memset(cmpname, '\0', sizeof cmpname);
buf_sz = strlen(depends) * 2;
buf = calloc(1, buf_sz);
if (buf == NULL)
return;
pkgconf_strlcpy(buf, depends, buf_sz);
pkgconf_strlcat(buf, " ", buf_sz);
start = ptr = buf;
while (*ptr)
{
switch (state)
{
case OUTSIDE_MODULE:
if (!PKGCONF_IS_MODULE_SEPARATOR(*ptr))
state = INSIDE_MODULE_NAME;
break;
case INSIDE_MODULE_NAME:
if (isspace((unsigned char)*ptr))
{
const char *sptr = ptr;
while (*sptr && isspace((unsigned char)*sptr))
sptr++;
if (*sptr == '\0')
state = OUTSIDE_MODULE;
else if (PKGCONF_IS_MODULE_SEPARATOR(*sptr))
state = OUTSIDE_MODULE;
else if (PKGCONF_IS_OPERATOR_CHAR(*sptr))
state = BEFORE_OPERATOR;
else
state = OUTSIDE_MODULE;
}
else if (PKGCONF_IS_MODULE_SEPARATOR(*ptr))
state = OUTSIDE_MODULE;
else if (*(ptr + 1) == '\0')
{
ptr++;
state = OUTSIDE_MODULE;
}
if (state != INSIDE_MODULE_NAME && start != ptr)
{
char *iter = start;
while (PKGCONF_IS_MODULE_SEPARATOR(*iter))
iter++;
package = iter;
package_sz = ptr - iter;
start = ptr;
}
if (state == OUTSIDE_MODULE)
{
pkgconf_dependency_addraw(client, deplist_head, package, package_sz, NULL, 0, compare, flags);
compare = PKGCONF_CMP_ANY;
package_sz = 0;
}
break;
case BEFORE_OPERATOR:
if (PKGCONF_IS_OPERATOR_CHAR(*ptr))
{
state = INSIDE_OPERATOR;
if (cnameptr < cnameend)
*cnameptr++ = *ptr;
}
break;
case INSIDE_OPERATOR:
if (PKGCONF_IS_OPERATOR_CHAR(*ptr))
{
if (cnameptr < cnameend)
*cnameptr++ = *ptr;
break;
}
state = AFTER_OPERATOR;
compare = pkgconf_pkg_comparator_lookup_by_name(cmpname);
// fallthrough
case AFTER_OPERATOR:
if (!isspace((unsigned char)*ptr))
{
vstart = ptr;
state = INSIDE_VERSION;
}
break;
case INSIDE_VERSION:
if (PKGCONF_IS_MODULE_SEPARATOR(*ptr) || *(ptr + 1) == '\0')
{
version = vstart;
version_sz = ptr - vstart;
state = OUTSIDE_MODULE;
pkgconf_dependency_addraw(client, deplist_head, package, package_sz, version, version_sz, compare, flags);
compare = PKGCONF_CMP_ANY;
cnameptr = cmpname;
memset(cmpname, 0, sizeof cmpname);
package_sz = 0;
}
if (state == OUTSIDE_MODULE)
start = ptr;
break;
}
ptr++;
}
free(buf);
}
/*
* !doc
*
* .. c:function:: void pkgconf_dependency_parse(const pkgconf_client_t *client, pkgconf_pkg_t *pkg, pkgconf_list_t *deplist, const char *depends)
*
* Preprocess dependency data and then process that dependency declaration into a dependency list.
* Commas are counted as whitespace to allow for constructs such as ``@SUBSTVAR@, zlib`` being processed
* into ``, zlib``.
*
* :param pkgconf_client_t* client: The client object that owns the package this dependency list belongs to.
* :param pkgconf_pkg_t* pkg: The package object that owns this dependency list.
* :param pkgconf_list_t* deplist: The dependency list to populate with dependency nodes.
* :param char* depends: The dependency data to parse.
* :param uint flags: Any flags to attach to the dependency nodes.
* :return: nothing
*/
void
pkgconf_dependency_parse(pkgconf_client_t *client, pkgconf_pkg_t *pkg, pkgconf_list_t *deplist, const char *depends, unsigned int flags)
{
char *kvdepends = pkgconf_tuple_parse(client, &pkg->vars, depends, pkg->flags);
pkgconf_dependency_parse_str(client, deplist, kvdepends, flags);
free(kvdepends);
}
/*
* !doc
*
* .. c:function:: pkgconf_dependency_t *pkgconf_dependency_copy(pkgconf_client_t *client, const pkgconf_dependency_t *dep)
*
* Copies a dependency node to a new one.
*
* :param pkgconf_client_t* client: The client object that will own this dependency.
* :param pkgconf_dependency_t* dep: The dependency node to copy.
* :return: a pointer to a new dependency node, else NULL
*/
pkgconf_dependency_t *
pkgconf_dependency_copy(pkgconf_client_t *client, const pkgconf_dependency_t *dep)
{
pkgconf_dependency_t *new_dep;
new_dep = calloc(1, sizeof(pkgconf_dependency_t));
if (new_dep == NULL)
return NULL;
new_dep->package = strdup(dep->package);
if (dep->version != NULL)
new_dep->version = strdup(dep->version);
new_dep->compare = dep->compare;
new_dep->flags = dep->flags;
new_dep->owner = client;
new_dep->refcount = 0;
if (dep->match != NULL)
new_dep->match = pkgconf_pkg_ref(client, dep->match);
return pkgconf_dependency_ref(client, new_dep);
}
+113
View File
@@ -0,0 +1,113 @@
/*
* fileio.c
* File reading utilities
*
* Copyright (c) 2012, 2025 pkgconf authors (see AUTHORS).
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* This software is provided 'as is' and without any warranty, express or
* implied. In no event shall the authors be liable for any damages arising
* from the use of this software.
*/
#include <libpkgconf/stdinc.h>
#include <libpkgconf/libpkgconf.h>
bool
pkgconf_fgetline(pkgconf_buffer_t *buffer, FILE *stream)
{
bool quoted = false;
int c = '\0', c2;
while ((c = getc(stream)) != EOF)
{
if (c == '\\' && !quoted)
{
quoted = true;
continue;
}
else if (c == '#')
{
if (!quoted) {
/* Skip the rest of the line */
do {
c = getc(stream);
} while (c != '\n' && c != EOF);
pkgconf_buffer_push_byte(buffer, c);
break;
}
else
pkgconf_buffer_push_byte(buffer, c);
quoted = false;
continue;
}
else if (c == '\n')
{
if (quoted)
{
/* Trim spaces */
do {
c2 = getc(stream);
} while (c2 == '\t' || c2 == ' ');
ungetc(c2, stream);
quoted = false;
continue;
}
else
{
pkgconf_buffer_push_byte(buffer, c);
}
break;
}
else if (c == '\r')
{
pkgconf_buffer_push_byte(buffer, '\n');
if ((c2 = getc(stream)) == '\n')
{
if (quoted)
{
quoted = false;
continue;
}
break;
}
ungetc(c2, stream);
if (quoted)
{
quoted = false;
continue;
}
break;
}
else
{
if (quoted) {
pkgconf_buffer_push_byte(buffer, '\\');
quoted = false;
}
pkgconf_buffer_push_byte(buffer, c);
}
}
/* Remove newline character. */
if (pkgconf_buffer_lastc(buffer) == '\n')
pkgconf_buffer_trim_byte(buffer);
if (pkgconf_buffer_lastc(buffer) == '\r')
pkgconf_buffer_trim_byte(buffer);
return !(c == EOF || ferror(stream));
}
+803
View File
@@ -0,0 +1,803 @@
/*
* fragment.c
* Management of fragment lists.
*
* Copyright (c) 2012, 2013, 2014 pkgconf authors (see AUTHORS).
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* This software is provided 'as is' and without any warranty, express or
* implied. In no event shall the authors be liable for any damages arising
* from the use of this software.
*/
#include <libpkgconf/stdinc.h>
#include <libpkgconf/libpkgconf.h>
/*
* !doc
*
* libpkgconf `fragment` module
* ============================
*
* The `fragment` module provides low-level management and rendering of fragment lists. A
* `fragment list` contains various `fragments` of text (such as ``-I /usr/include``) in a matter
* which is composable, mergeable and reorderable.
*/
struct pkgconf_fragment_check {
char *token;
size_t len;
};
static inline bool
pkgconf_fragment_is_unmergeable(const char *string)
{
static const struct pkgconf_fragment_check check_fragments[] = {
{"-framework", 10},
{"-isystem", 8},
{"-idirafter", 10},
{"-pthread", 8},
{"-Wa,", 4},
{"-Wl,", 4},
{"-Wp,", 4},
{"-trigraphs", 10},
{"-pedantic", 9},
{"-ansi", 5},
{"-std=", 5},
{"-stdlib=", 8},
{"-include", 8},
{"-nostdinc", 9},
{"-nostdlibinc", 12},
{"-nobuiltininc", 13},
{"-nodefaultlibs", 14},
};
if (*string != '-')
return true;
for (size_t i = 0; i < PKGCONF_ARRAY_SIZE(check_fragments); i++)
if (!strncmp(string, check_fragments[i].token, check_fragments[i].len))
return true;
/* only one pair of {-flag, arg} may be merged together */
if (strchr(string, ' ') != NULL)
return false;
return false;
}
static inline bool
pkgconf_fragment_should_munge(const char *string, const char *sysroot_dir)
{
if (*string != '/')
return false;
if (sysroot_dir != NULL && strncmp(sysroot_dir, string, strlen(sysroot_dir)))
return true;
return false;
}
static inline bool
pkgconf_fragment_is_groupable(const char *string)
{
static const struct pkgconf_fragment_check check_fragments[] = {
{"-Wl,--start-group", 17},
{"-framework", 10},
{"-isystem", 8},
{"-idirafter", 10},
{"-include", 8},
};
for (size_t i = 0; i < PKGCONF_ARRAY_SIZE(check_fragments); i++)
if (!strncmp(string, check_fragments[i].token, check_fragments[i].len))
return true;
return false;
}
static inline bool
pkgconf_fragment_is_terminus(const char *string)
{
static const struct pkgconf_fragment_check check_fragments[] = {
{"-Wl,--end-group", 15},
};
for (size_t i = 0; i < PKGCONF_ARRAY_SIZE(check_fragments); i++)
if (!strncmp(string, check_fragments[i].token, check_fragments[i].len))
return true;
return false;
}
static inline bool
pkgconf_fragment_is_special(const char *string)
{
if (*string != '-')
return true;
if (!strncmp(string, "-lib:", 5))
return true;
return pkgconf_fragment_is_unmergeable(string);
}
static inline void
pkgconf_fragment_munge(const pkgconf_client_t *client, char *buf, size_t buflen, const char *source, const char *sysroot_dir, unsigned int flags)
{
*buf = '\0';
if (!(flags & PKGCONF_PKG_PROPF_UNINSTALLED) || (client->flags & PKGCONF_PKG_PKGF_PKGCONF1_SYSROOT_RULES))
{
if (sysroot_dir == NULL)
sysroot_dir = pkgconf_tuple_find_global(client, "pc_sysrootdir");
if (sysroot_dir != NULL && pkgconf_fragment_should_munge(source, sysroot_dir))
pkgconf_strlcat(buf, sysroot_dir, buflen);
}
pkgconf_strlcat(buf, source, buflen);
if (*buf == '/' && !(client->flags & PKGCONF_PKG_PKGF_DONT_RELOCATE_PATHS))
pkgconf_path_relocate(buf, buflen);
}
static inline char *
pkgconf_fragment_copy_munged(const pkgconf_client_t *client, const char *source, unsigned int flags)
{
char mungebuf[PKGCONF_ITEM_SIZE];
pkgconf_fragment_munge(client, mungebuf, sizeof mungebuf, source, client->sysroot_dir, flags);
return strdup(mungebuf);
}
/*
* !doc
*
* .. c:function:: void pkgconf_fragment_insert(const pkgconf_client_t *client, pkgconf_list_t *list, char type, const char *data, bool tail)
*
* Adds a `fragment` of text to a `fragment list` directly without interpreting it.
*
* :param pkgconf_client_t* client: The pkgconf client being accessed.
* :param pkgconf_list_t* list: The fragment list.
* :param char type: The type of the fragment.
* :param char* data: The data of the fragment.
* :param bool tail: Whether to place the fragment at the beginning of the list or the end.
* :return: nothing
*/
void
pkgconf_fragment_insert(const pkgconf_client_t *client, pkgconf_list_t *list, char type, const char *data, bool tail)
{
pkgconf_fragment_t *frag;
frag = calloc(1, sizeof(pkgconf_fragment_t));
frag->type = type;
frag->data = pkgconf_fragment_copy_munged(client, data, 0);
if (tail)
{
pkgconf_node_insert_tail(&frag->iter, frag, list);
return;
}
pkgconf_node_insert(&frag->iter, frag, list);
}
/*
* !doc
*
* .. c:function:: void pkgconf_fragment_add(const pkgconf_client_t *client, pkgconf_list_t *list, const char *string, unsigned int flags)
*
* Adds a `fragment` of text to a `fragment list`, possibly modifying the fragment if a sysroot is set.
*
* :param pkgconf_client_t* client: The pkgconf client being accessed.
* :param pkgconf_list_t* list: The fragment list.
* :param char* string: The string of text to add as a fragment to the fragment list.
* :param uint flags: Parsing-related flags for the package.
* :return: nothing
*/
void
pkgconf_fragment_add(const pkgconf_client_t *client, pkgconf_list_t *list, const char *string, unsigned int flags)
{
pkgconf_list_t *target = list;
pkgconf_fragment_t *frag;
if (*string == '\0')
return;
if (list->tail != NULL && list->tail->data != NULL &&
!(client->flags & PKGCONF_PKG_PKGF_DONT_MERGE_SPECIAL_FRAGMENTS))
{
pkgconf_fragment_t *parent = list->tail->data;
/* only attempt to merge 'special' fragments together */
if (!parent->type && parent->data != NULL &&
pkgconf_fragment_is_unmergeable(parent->data) &&
!(parent->flags & PKGCONF_PKG_FRAGF_TERMINATED))
{
if (pkgconf_fragment_is_groupable(parent->data))
target = &parent->children;
if (pkgconf_fragment_is_terminus(string))
parent->flags |= PKGCONF_PKG_FRAGF_TERMINATED;
PKGCONF_TRACE(client, "adding fragment as child to list @%p", target);
}
}
frag = calloc(1, sizeof(pkgconf_fragment_t));
if (frag == NULL)
{
PKGCONF_TRACE(client, "failed to add new fragment due to allocation failure to list @%p", target);
return;
}
if (strlen(string) > 1 && !pkgconf_fragment_is_special(string))
{
frag->type = *(string + 1);
frag->data = pkgconf_fragment_copy_munged(client, string + 2, flags);
PKGCONF_TRACE(client, "added fragment {%c, '%s'} to list @%p", frag->type, frag->data, list);
}
else
{
frag->type = 0;
frag->data = pkgconf_fragment_copy_munged(client, string, flags);
PKGCONF_TRACE(client, "created special fragment {'%s'} in list @%p", frag->data, target);
}
pkgconf_node_insert_tail(&frag->iter, frag, target);
}
static inline pkgconf_fragment_t *
pkgconf_fragment_lookup(pkgconf_list_t *list, const pkgconf_fragment_t *base)
{
pkgconf_node_t *node;
PKGCONF_FOREACH_LIST_ENTRY_REVERSE(list->tail, node)
{
pkgconf_fragment_t *frag = node->data;
if (base->type != frag->type)
continue;
if (!strcmp(base->data, frag->data))
return frag;
}
return NULL;
}
static inline bool
pkgconf_fragment_can_merge_back(const pkgconf_fragment_t *base, unsigned int flags, bool is_private)
{
(void) flags;
if (base->type == 'l')
{
if (is_private)
return false;
return true;
}
if (base->type == 'F')
return false;
if (base->type == 'L')
return false;
if (base->type == 'I')
return false;
return true;
}
static inline bool
pkgconf_fragment_can_merge(const pkgconf_fragment_t *base, unsigned int flags, bool is_private)
{
(void) flags;
if (is_private)
return false;
if (base->children.head != NULL)
return false;
return pkgconf_fragment_is_unmergeable(base->data);
}
static inline pkgconf_fragment_t *
pkgconf_fragment_exists(pkgconf_list_t *list, const pkgconf_fragment_t *base, unsigned int flags, bool is_private)
{
if (!pkgconf_fragment_can_merge_back(base, flags, is_private))
return NULL;
if (!pkgconf_fragment_can_merge(base, flags, is_private))
return NULL;
return pkgconf_fragment_lookup(list, base);
}
static inline bool
pkgconf_fragment_should_merge(const pkgconf_fragment_t *base)
{
const pkgconf_fragment_t *parent;
/* if we are the first fragment, that means the next fragment is the same, so it's always safe. */
if (base->iter.prev == NULL)
return true;
/* this really shouldn't ever happen, but handle it */
parent = base->iter.prev->data;
if (parent == NULL)
return true;
switch (parent->type)
{
case 'l':
case 'L':
case 'I':
return true;
default:
return !base->type || parent->type == base->type;
}
}
/*
* !doc
*
* .. c:function:: bool pkgconf_fragment_has_system_dir(const pkgconf_client_t *client, const pkgconf_fragment_t *frag)
*
* Checks if a `fragment` contains a `system path`. System paths are detected at compile time and optionally overridden by
* the ``PKG_CONFIG_SYSTEM_INCLUDE_PATH`` and ``PKG_CONFIG_SYSTEM_LIBRARY_PATH`` environment variables.
*
* :param pkgconf_client_t* client: The pkgconf client object the fragment belongs to.
* :param pkgconf_fragment_t* frag: The fragment being checked.
* :return: true if the fragment contains a system path, else false
* :rtype: bool
*/
bool
pkgconf_fragment_has_system_dir(const pkgconf_client_t *client, const pkgconf_fragment_t *frag)
{
const pkgconf_list_t *check_paths = NULL;
switch (frag->type)
{
case 'L':
check_paths = &client->filter_libdirs;
break;
case 'I':
check_paths = &client->filter_includedirs;
break;
default:
return false;
}
return pkgconf_path_match_list(frag->data, check_paths);
}
/*
* !doc
*
* .. c:function:: void pkgconf_fragment_copy(const pkgconf_client_t *client, pkgconf_list_t *list, const pkgconf_fragment_t *base, bool is_private)
*
* Copies a `fragment` to another `fragment list`, possibly removing a previous copy of the `fragment`
* in a process known as `mergeback`.
*
* :param pkgconf_client_t* client: The pkgconf client being accessed.
* :param pkgconf_list_t* list: The list the fragment is being added to.
* :param pkgconf_fragment_t* base: The fragment being copied.
* :param bool is_private: Whether the fragment list is a `private` fragment list (static linking).
* :return: nothing
*/
void
pkgconf_fragment_copy(const pkgconf_client_t *client, pkgconf_list_t *list, const pkgconf_fragment_t *base, bool is_private)
{
pkgconf_fragment_t *frag;
if ((frag = pkgconf_fragment_exists(list, base, client->flags, is_private)) != NULL)
{
if (pkgconf_fragment_should_merge(frag))
pkgconf_fragment_delete(list, frag);
}
else if (!is_private && !pkgconf_fragment_can_merge_back(base, client->flags, is_private) && (pkgconf_fragment_lookup(list, base) != NULL))
return;
frag = calloc(1, sizeof(pkgconf_fragment_t));
frag->type = base->type;
pkgconf_fragment_copy_list(client, &frag->children, &base->children);
if (base->data != NULL)
frag->data = strdup(base->data);
pkgconf_node_insert_tail(&frag->iter, frag, list);
}
/*
* !doc
*
* .. c:function:: void pkgconf_fragment_copy_list(const pkgconf_client_t *client, pkgconf_list_t *list, const pkgconf_list_t *base)
*
* Copies a `fragment list` to another `fragment list`, possibly removing a previous copy of the fragments
* in a process known as `mergeback`.
*
* :param pkgconf_client_t* client: The pkgconf client being accessed.
* :param pkgconf_list_t* list: The list the fragments are being added to.
* :param pkgconf_list_t* base: The list the fragments are being copied from.
* :return: nothing
*/
void
pkgconf_fragment_copy_list(const pkgconf_client_t *client, pkgconf_list_t *list, const pkgconf_list_t *base)
{
pkgconf_node_t *node;
PKGCONF_FOREACH_LIST_ENTRY(base->head, node)
{
pkgconf_fragment_t *frag = node->data;
pkgconf_fragment_copy(client, list, frag, true);
}
}
/*
* !doc
*
* .. c:function:: void pkgconf_fragment_filter(const pkgconf_client_t *client, pkgconf_list_t *dest, pkgconf_list_t *src, pkgconf_fragment_filter_func_t filter_func)
*
* Copies a `fragment list` to another `fragment list` which match a user-specified filtering function.
*
* :param pkgconf_client_t* client: The pkgconf client being accessed.
* :param pkgconf_list_t* dest: The destination list.
* :param pkgconf_list_t* src: The source list.
* :param pkgconf_fragment_filter_func_t filter_func: The filter function to use.
* :param void* data: Optional data to pass to the filter function.
* :return: nothing
*/
void
pkgconf_fragment_filter(const pkgconf_client_t *client, pkgconf_list_t *dest, pkgconf_list_t *src, pkgconf_fragment_filter_func_t filter_func, void *data)
{
pkgconf_node_t *node;
PKGCONF_FOREACH_LIST_ENTRY(src->head, node)
{
pkgconf_fragment_t *frag = node->data;
if (filter_func(client, frag, data))
pkgconf_fragment_copy(client, dest, frag, true);
}
}
static inline char *
fragment_quote(const pkgconf_fragment_t *frag)
{
const char *src = frag->data;
ssize_t outlen = strlen(src) + 10;
char *out, *dst;
if (frag->data == NULL)
return NULL;
out = dst = calloc(1, outlen);
if (out == NULL)
return NULL;
for (; *src; src++)
{
if (((*src < ' ') ||
(*src >= (' ' + (frag->children.head != NULL ? 1 : 0)) && *src < '$') ||
(*src > '$' && *src < '(') ||
(*src > ')' && *src < '+') ||
(*src > ':' && *src < '=') ||
(*src > '=' && *src < '@') ||
(*src > 'Z' && *src < '\\') ||
#ifndef _WIN32
(*src == '\\') ||
#endif
(*src > '\\' && *src < '^') ||
(*src == '`') ||
(*src > 'z' && *src < '~') ||
(*src > '~')))
*dst++ = '\\';
*dst++ = *src;
if ((ptrdiff_t)(dst - out) + 2 > outlen)
{
ptrdiff_t offset = dst - out;
outlen *= 2;
char *newout = realloc(out, outlen);
if (newout == NULL)
{
free(out);
return NULL;
}
out = newout;
dst = out + offset;
}
}
*dst = 0;
return out;
}
static inline size_t
pkgconf_fragment_len(const pkgconf_fragment_t *frag)
{
size_t len = 1;
if (frag->type)
len += 2;
if (frag->data != NULL)
{
pkgconf_node_t *iter;
char *quoted = fragment_quote(frag);
len += strlen(quoted);
free(quoted);
PKGCONF_FOREACH_LIST_ENTRY(frag->children.head, iter)
{
const pkgconf_fragment_t *child_frag = iter->data;
len += pkgconf_fragment_len(child_frag) + 1;
}
}
return len;
}
static size_t
fragment_render_len(const pkgconf_list_t *list, bool escape)
{
(void) escape;
size_t out = 1; /* trailing nul */
pkgconf_node_t *node;
PKGCONF_FOREACH_LIST_ENTRY(list->head, node)
{
const pkgconf_fragment_t *frag = node->data;
out += pkgconf_fragment_len(frag);
}
return out;
}
static inline size_t
fragment_render_item(const pkgconf_fragment_t *frag, char *bptr, size_t bufremain)
{
const pkgconf_node_t *iter;
char *base = bptr;
char *quoted = fragment_quote(frag);
if (quoted == NULL)
return 0;
if (strlen(quoted) > bufremain)
{
free(quoted);
return 0;
}
if (frag->type)
{
*bptr++ = '-';
*bptr++ = frag->type;
}
if (quoted != NULL)
{
bptr += pkgconf_strlcpy(bptr, quoted, bufremain - (bptr - base));
free(quoted);
}
PKGCONF_FOREACH_LIST_ENTRY(frag->children.head, iter)
{
const pkgconf_fragment_t *child_frag = iter->data;
*bptr++ = ' ';
bptr += fragment_render_item(child_frag, bptr, bufremain - (bptr - base));
}
return bptr - base;
}
static void
fragment_render_buf(const pkgconf_list_t *list, char *buf, size_t buflen, bool escape)
{
(void) escape;
pkgconf_node_t *node;
char *bptr = buf;
memset(buf, 0, buflen);
PKGCONF_FOREACH_LIST_ENTRY(list->head, node)
{
const pkgconf_fragment_t *frag = node->data;
size_t buf_remaining = buflen - (bptr - buf);
size_t written = fragment_render_item(frag, bptr, buf_remaining);
bptr += written;
if (node->next != NULL)
*bptr++ = ' ';
}
}
static const pkgconf_fragment_render_ops_t default_render_ops = {
.render_len = fragment_render_len,
.render_buf = fragment_render_buf
};
/*
* !doc
*
* .. c:function:: size_t pkgconf_fragment_render_len(const pkgconf_list_t *list, bool escape, const pkgconf_fragment_render_ops_t *ops)
*
* Calculates the required memory to store a `fragment list` when rendered as a string.
*
* :param pkgconf_list_t* list: The `fragment list` being rendered.
* :param bool escape: Whether or not to escape special shell characters (deprecated).
* :param pkgconf_fragment_render_ops_t* ops: An optional ops structure to use for custom renderers, else ``NULL``.
* :return: the amount of bytes required to represent the `fragment list` when rendered
* :rtype: size_t
*/
size_t
pkgconf_fragment_render_len(const pkgconf_list_t *list, bool escape, const pkgconf_fragment_render_ops_t *ops)
{
(void) escape;
ops = ops != NULL ? ops : &default_render_ops;
return ops->render_len(list, true);
}
/*
* !doc
*
* .. c:function:: void pkgconf_fragment_render_buf(const pkgconf_list_t *list, char *buf, size_t buflen, bool escape, const pkgconf_fragment_render_ops_t *ops)
*
* Renders a `fragment list` into a buffer.
*
* :param pkgconf_list_t* list: The `fragment list` being rendered.
* :param char* buf: The buffer to render the fragment list into.
* :param size_t buflen: The length of the buffer.
* :param bool escape: Whether or not to escape special shell characters (deprecated).
* :param pkgconf_fragment_render_ops_t* ops: An optional ops structure to use for custom renderers, else ``NULL``.
* :return: nothing
*/
void
pkgconf_fragment_render_buf(const pkgconf_list_t *list, char *buf, size_t buflen, bool escape, const pkgconf_fragment_render_ops_t *ops)
{
(void) escape;
ops = ops != NULL ? ops : &default_render_ops;
ops->render_buf(list, buf, buflen, true);
}
/*
* !doc
*
* .. c:function:: char *pkgconf_fragment_render(const pkgconf_list_t *list)
*
* Allocate memory and render a `fragment list` into it.
*
* :param pkgconf_list_t* list: The `fragment list` being rendered.
* :param bool escape: Whether or not to escape special shell characters (deprecated).
* :param pkgconf_fragment_render_ops_t* ops: An optional ops structure to use for custom renderers, else ``NULL``.
* :return: An allocated string containing the rendered `fragment list`.
* :rtype: char *
*/
char *
pkgconf_fragment_render(const pkgconf_list_t *list, bool escape, const pkgconf_fragment_render_ops_t *ops)
{
(void) escape;
size_t buflen = pkgconf_fragment_render_len(list, true, ops);
char *buf = calloc(1, buflen);
pkgconf_fragment_render_buf(list, buf, buflen, true, ops);
return buf;
}
/*
* !doc
*
* .. c:function:: void pkgconf_fragment_delete(pkgconf_list_t *list, pkgconf_fragment_t *node)
*
* Delete a `fragment node` from a `fragment list`.
*
* :param pkgconf_list_t* list: The `fragment list` to delete from.
* :param pkgconf_fragment_t* node: The `fragment node` to delete.
* :return: nothing
*/
void
pkgconf_fragment_delete(pkgconf_list_t *list, pkgconf_fragment_t *node)
{
pkgconf_node_delete(&node->iter, list);
free(node->data);
free(node);
}
/*
* !doc
*
* .. c:function:: void pkgconf_fragment_free(pkgconf_list_t *list)
*
* Delete an entire `fragment list`.
*
* :param pkgconf_list_t* list: The `fragment list` to delete.
* :return: nothing
*/
void
pkgconf_fragment_free(pkgconf_list_t *list)
{
pkgconf_node_t *node, *next;
PKGCONF_FOREACH_LIST_ENTRY_SAFE(list->head, next, node)
{
pkgconf_fragment_t *frag = node->data;
pkgconf_fragment_free(&frag->children);
free(frag->data);
free(frag);
}
}
/*
* !doc
*
* .. c:function:: bool pkgconf_fragment_parse(const pkgconf_client_t *client, pkgconf_list_t *list, pkgconf_list_t *vars, const char *value)
*
* Parse a string into a `fragment list`.
*
* :param pkgconf_client_t* client: The pkgconf client being accessed.
* :param pkgconf_list_t* list: The `fragment list` to add the fragment entries to.
* :param pkgconf_list_t* vars: A list of variables to use for variable substitution.
* :param uint flags: Any parsing flags to be aware of.
* :param char* value: The string to parse into fragments.
* :return: true on success, false on parse error
*/
bool
pkgconf_fragment_parse(const pkgconf_client_t *client, pkgconf_list_t *list, pkgconf_list_t *vars, const char *value, unsigned int flags)
{
int i, ret, argc;
char **argv;
char *repstr = pkgconf_tuple_parse(client, vars, value, flags);
PKGCONF_TRACE(client, "post-subst: [%s] -> [%s]", value, repstr);
ret = pkgconf_argv_split(repstr, &argc, &argv);
if (ret < 0)
{
PKGCONF_TRACE(client, "unable to parse fragment string [%s]", repstr);
free(repstr);
return false;
}
for (i = 0; i < argc; i++)
{
PKGCONF_TRACE(client, "processing %s", argv[i]);
if (argv[i] == NULL)
{
PKGCONF_TRACE(client, "parsed fragment string is inconsistent: argc = %d while argv[%d] == NULL", argc, i);
pkgconf_argv_free(argv);
free(repstr);
return false;
}
pkgconf_fragment_add(client, list, argv[i], flags);
}
pkgconf_argv_free(argv);
free(repstr);
return true;
}
+113
View File
@@ -0,0 +1,113 @@
/*
* iter.h
* Linked lists and iterators.
*
* Copyright (c) 2013 pkgconf authors (see AUTHORS).
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* This software is provided 'as is' and without any warranty, express or
* implied. In no event shall the authors be liable for any damages arising
* from the use of this software.
*/
#ifndef LIBPKGCONF_ITER_H
#define LIBPKGCONF_ITER_H
#ifdef __cplusplus
extern "C" {
#endif
typedef struct pkgconf_node_ pkgconf_node_t;
struct pkgconf_node_ {
pkgconf_node_t *prev, *next;
void *data;
};
typedef struct {
pkgconf_node_t *head, *tail;
size_t length;
} pkgconf_list_t;
#define PKGCONF_LIST_INITIALIZER { NULL, NULL, 0 }
static inline void
pkgconf_list_zero(pkgconf_list_t *list)
{
list->head = NULL;
list->tail = NULL;
list->length = 0;
}
static inline void
pkgconf_node_insert(pkgconf_node_t *node, void *data, pkgconf_list_t *list)
{
pkgconf_node_t *tnode;
node->data = data;
if (list->head == NULL)
{
list->head = node;
list->tail = node;
list->length = 1;
return;
}
tnode = list->head;
node->next = tnode;
tnode->prev = node;
list->head = node;
list->length++;
}
static inline void
pkgconf_node_insert_tail(pkgconf_node_t *node, void *data, pkgconf_list_t *list)
{
pkgconf_node_t *tnode;
node->data = data;
if (list->tail == NULL)
{
list->head = node;
list->tail = node;
list->length = 1;
return;
}
tnode = list->tail;
node->prev = tnode;
tnode->next = node;
list->tail = node;
list->length++;
}
static inline void
pkgconf_node_delete(pkgconf_node_t *node, pkgconf_list_t *list)
{
list->length--;
if (node->prev == NULL)
list->head = node->next;
else
node->prev->next = node->next;
if (node->next == NULL)
list->tail = node->prev;
else
node->next->prev = node->prev;
}
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,19 @@
#ifndef LIBPKGCONF_LIBPKGCONF_API_H
#define LIBPKGCONF_LIBPKGCONF_API_H
/* Makefile.am specifies visibility using the libtool option -export-symbols-regex '^pkgconf_'
* Unfortunately, that is not available when building with meson, so use attributes instead.
*/
#if defined(PKGCONFIG_IS_STATIC)
# define PKGCONF_API
#elif defined(_WIN32) || defined(_WIN64)
# if defined(LIBPKGCONF_EXPORT) || defined(DLL_EXPORT)
# define PKGCONF_API __declspec(dllexport)
# else
# define PKGCONF_API __declspec(dllimport)
# endif
#else
# define PKGCONF_API __attribute__((visibility("default")))
#endif
#endif
+493
View File
@@ -0,0 +1,493 @@
/*
* libpkgconf.h
* Global include file for everything in libpkgconf.
*
* Copyright (c) 2011, 2015 pkgconf authors (see AUTHORS).
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* This software is provided 'as is' and without any warranty, express or
* implied. In no event shall the authors be liable for any damages arising
* from the use of this software.
*/
#ifndef LIBPKGCONF__LIBPKGCONF_H
#define LIBPKGCONF__LIBPKGCONF_H
#include <inttypes.h>
#include <stdio.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdbool.h>
#include <stdint.h>
#include <libpkgconf/libpkgconf-api.h>
#include <libpkgconf/iter.h>
#include <libpkgconf/bsdstubs.h>
#ifdef __cplusplus
extern "C" {
#endif
/* pkg-config uses ';' on win32 as ':' is part of path */
#ifdef _WIN32
#define PKG_CONFIG_PATH_SEP_S ";"
#else
#define PKG_CONFIG_PATH_SEP_S ":"
#endif
#ifdef _WIN32
#define PKG_DIR_SEP_S '\\'
#else
#define PKG_DIR_SEP_S '/'
#endif
#ifdef _WIN32
#define realpath(N,R) _fullpath((R),(N),_MAX_PATH)
#endif
#define PKGCONF_BUFSIZE (65535)
typedef enum {
PKGCONF_CMP_NOT_EQUAL,
PKGCONF_CMP_ANY,
PKGCONF_CMP_LESS_THAN,
PKGCONF_CMP_LESS_THAN_EQUAL,
PKGCONF_CMP_EQUAL,
PKGCONF_CMP_GREATER_THAN,
PKGCONF_CMP_GREATER_THAN_EQUAL
} pkgconf_pkg_comparator_t;
#define PKGCONF_CMP_COUNT 7
typedef struct pkgconf_pkg_ pkgconf_pkg_t;
typedef struct pkgconf_dependency_ pkgconf_dependency_t;
typedef struct pkgconf_tuple_ pkgconf_tuple_t;
typedef struct pkgconf_fragment_ pkgconf_fragment_t;
typedef struct pkgconf_path_ pkgconf_path_t;
typedef struct pkgconf_client_ pkgconf_client_t;
typedef struct pkgconf_cross_personality_ pkgconf_cross_personality_t;
typedef struct pkgconf_queue_ pkgconf_queue_t;
#define PKGCONF_ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))
#define PKGCONF_FOREACH_LIST_ENTRY(head, value) \
for ((value) = (head); (value) != NULL; (value) = (value)->next)
#define PKGCONF_FOREACH_LIST_ENTRY_SAFE(head, nextiter, value) \
for ((value) = (head), (nextiter) = (head) != NULL ? (head)->next : NULL; (value) != NULL; (value) = (nextiter), (nextiter) = (nextiter) != NULL ? (nextiter)->next : NULL)
#define PKGCONF_FOREACH_LIST_ENTRY_REVERSE(tail, value) \
for ((value) = (tail); (value) != NULL; (value) = (value)->prev)
#define LIBPKGCONF_VERSION 20501
#define LIBPKGCONF_VERSION_STR "2.5.1"
struct pkgconf_queue_ {
pkgconf_node_t iter;
char *package;
unsigned int flags;
};
struct pkgconf_fragment_ {
pkgconf_node_t iter;
char type;
char *data;
pkgconf_list_t children;
unsigned int flags;
};
#define PKGCONF_PKG_FRAGF_TERMINATED 0x1
struct pkgconf_dependency_ {
pkgconf_node_t iter;
char *package;
pkgconf_pkg_comparator_t compare;
char *version;
pkgconf_pkg_t *parent;
pkgconf_pkg_t *match;
unsigned int flags;
int refcount;
pkgconf_client_t *owner;
};
struct pkgconf_tuple_ {
pkgconf_node_t iter;
char *key;
char *value;
unsigned int flags;
};
#define PKGCONF_PKG_TUPLEF_OVERRIDE 0x1
struct pkgconf_path_ {
pkgconf_node_t lnode;
char *path;
void *handle_path;
void *handle_device;
unsigned int flags;
};
#define PKGCONF_PKG_PROPF_NONE 0x00
#define PKGCONF_PKG_PROPF_STATIC 0x01
#define PKGCONF_PKG_PROPF_CACHED 0x02
#define PKGCONF_PKG_PROPF_UNINSTALLED 0x08
#define PKGCONF_PKG_PROPF_VIRTUAL 0x10
#define PKGCONF_PKG_PROPF_ANCESTOR 0x20
#define PKGCONF_PKG_PROPF_VISITED_PRIVATE 0x40
#define PKGCONF_PKG_PROPF_PRELOADED 0x80
struct pkgconf_pkg_ {
int refcount;
char *id;
char *filename;
char *realname;
char *version;
char *description;
char *url;
char *pc_filedir;
char *license;
char *maintainer;
char *copyright;
char *why;
pkgconf_list_t libs;
pkgconf_list_t libs_private;
pkgconf_list_t cflags;
pkgconf_list_t cflags_private;
pkgconf_list_t required; /* this used to be requires but that is now a reserved keyword */
pkgconf_list_t requires_private;
pkgconf_list_t conflicts;
pkgconf_list_t provides;
pkgconf_list_t vars;
unsigned int flags;
pkgconf_client_t *owner;
/* these resources are owned by the package and do not need special management,
* under no circumstance attempt to allocate or free objects belonging to these pointers
*/
pkgconf_tuple_t *orig_prefix;
pkgconf_tuple_t *prefix;
uint64_t serial;
uint64_t identifier;
pkgconf_node_t preload_node;
};
typedef bool (*pkgconf_pkg_iteration_func_t)(const pkgconf_pkg_t *pkg, void *data);
typedef void (*pkgconf_pkg_traverse_func_t)(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data);
typedef bool (*pkgconf_queue_apply_func_t)(pkgconf_client_t *client, pkgconf_pkg_t *world, void *data, int maxdepth);
typedef bool (*pkgconf_error_handler_func_t)(const char *msg, const pkgconf_client_t *client, void *data);
typedef void (*pkgconf_unveil_handler_func_t)(const pkgconf_client_t *client, const char *path, const char *permissions);
struct pkgconf_client_ {
pkgconf_list_t dir_list;
pkgconf_list_t filter_libdirs;
pkgconf_list_t filter_includedirs;
pkgconf_list_t global_vars;
void *error_handler_data;
void *warn_handler_data;
void *trace_handler_data;
pkgconf_error_handler_func_t error_handler;
pkgconf_error_handler_func_t warn_handler;
pkgconf_error_handler_func_t trace_handler;
FILE *auditf;
char *sysroot_dir;
char *buildroot_dir;
unsigned int flags;
char *prefix_varname;
bool already_sent_notice;
uint64_t serial;
uint64_t identifier;
pkgconf_pkg_t **cache_table;
size_t cache_count;
pkgconf_unveil_handler_func_t unveil_handler;
pkgconf_list_t preloaded_pkgs;
};
struct pkgconf_cross_personality_ {
char *name;
pkgconf_list_t dir_list;
pkgconf_list_t filter_libdirs;
pkgconf_list_t filter_includedirs;
char *sysroot_dir;
bool want_default_static;
bool want_default_pure;
};
/* client.c */
PKGCONF_API void pkgconf_client_init(pkgconf_client_t *client, pkgconf_error_handler_func_t error_handler, void *error_handler_data, const pkgconf_cross_personality_t *personality);
PKGCONF_API pkgconf_client_t * pkgconf_client_new(pkgconf_error_handler_func_t error_handler, void *error_handler_data, const pkgconf_cross_personality_t *personality);
PKGCONF_API void pkgconf_client_deinit(pkgconf_client_t *client);
PKGCONF_API void pkgconf_client_free(pkgconf_client_t *client);
PKGCONF_API const char *pkgconf_client_get_sysroot_dir(const pkgconf_client_t *client);
PKGCONF_API void pkgconf_client_set_sysroot_dir(pkgconf_client_t *client, const char *sysroot_dir);
PKGCONF_API const char *pkgconf_client_get_buildroot_dir(const pkgconf_client_t *client);
PKGCONF_API void pkgconf_client_set_buildroot_dir(pkgconf_client_t *client, const char *buildroot_dir);
PKGCONF_API unsigned int pkgconf_client_get_flags(const pkgconf_client_t *client);
PKGCONF_API void pkgconf_client_set_flags(pkgconf_client_t *client, unsigned int flags);
PKGCONF_API const char *pkgconf_client_get_prefix_varname(const pkgconf_client_t *client);
PKGCONF_API void pkgconf_client_set_prefix_varname(pkgconf_client_t *client, const char *prefix_varname);
PKGCONF_API pkgconf_error_handler_func_t pkgconf_client_get_warn_handler(const pkgconf_client_t *client);
PKGCONF_API void pkgconf_client_set_warn_handler(pkgconf_client_t *client, pkgconf_error_handler_func_t warn_handler, void *warn_handler_data);
PKGCONF_API pkgconf_error_handler_func_t pkgconf_client_get_error_handler(const pkgconf_client_t *client);
PKGCONF_API void pkgconf_client_set_error_handler(pkgconf_client_t *client, pkgconf_error_handler_func_t error_handler, void *error_handler_data);
PKGCONF_API pkgconf_error_handler_func_t pkgconf_client_get_trace_handler(const pkgconf_client_t *client);
PKGCONF_API void pkgconf_client_set_trace_handler(pkgconf_client_t *client, pkgconf_error_handler_func_t trace_handler, void *trace_handler_data);
PKGCONF_API pkgconf_unveil_handler_func_t pkgconf_client_get_unveil_handler(const pkgconf_client_t *client);
PKGCONF_API void pkgconf_client_set_unveil_handler(pkgconf_client_t *client, pkgconf_unveil_handler_func_t unveil_handler);
PKGCONF_API void pkgconf_client_dir_list_build(pkgconf_client_t *client, const pkgconf_cross_personality_t *personality);
PKGCONF_API bool pkgconf_client_preload_path(pkgconf_client_t *client, const char *path);
PKGCONF_API bool pkgconf_client_preload_from_environ(pkgconf_client_t *client, const char *env);
/* personality.c */
PKGCONF_API pkgconf_cross_personality_t *pkgconf_cross_personality_default(void);
PKGCONF_API pkgconf_cross_personality_t *pkgconf_cross_personality_find(const char *triplet);
PKGCONF_API void pkgconf_cross_personality_deinit(pkgconf_cross_personality_t *personality);
#define PKGCONF_IS_MODULE_SEPARATOR(c) ((c) == ',' || isspace ((unsigned char)(c)))
#define PKGCONF_IS_OPERATOR_CHAR(c) ((c) == '<' || (c) == '>' || (c) == '!' || (c) == '=')
#define PKGCONF_PKG_PKGF_NONE 0x0000
#define PKGCONF_PKG_PKGF_SEARCH_PRIVATE 0x0001
#define PKGCONF_PKG_PKGF_ENV_ONLY 0x0002
#define PKGCONF_PKG_PKGF_NO_UNINSTALLED 0x0004
#define PKGCONF_PKG_PKGF_SKIP_ROOT_VIRTUAL 0x0008
#define PKGCONF_PKG_PKGF_MERGE_PRIVATE_FRAGMENTS 0x0010
#define PKGCONF_PKG_PKGF_SKIP_CONFLICTS 0x0020
#define PKGCONF_PKG_PKGF_NO_CACHE 0x0040
#define PKGCONF_PKG_PKGF_SKIP_ERRORS 0x0080
#define PKGCONF_PKG_PKGF_ITER_PKG_IS_PRIVATE 0x0100
#define PKGCONF_PKG_PKGF_SKIP_PROVIDES 0x0200
#define PKGCONF_PKG_PKGF_REDEFINE_PREFIX 0x0400
#define PKGCONF_PKG_PKGF_DONT_RELOCATE_PATHS 0x0800
#define PKGCONF_PKG_PKGF_SIMPLIFY_ERRORS 0x1000
#define PKGCONF_PKG_PKGF_DONT_FILTER_INTERNAL_CFLAGS 0x2000
#define PKGCONF_PKG_PKGF_DONT_MERGE_SPECIAL_FRAGMENTS 0x4000
#define PKGCONF_PKG_PKGF_FDO_SYSROOT_RULES 0x8000
#define PKGCONF_PKG_PKGF_PKGCONF1_SYSROOT_RULES 0x10000
#define PKGCONF_PKG_DEPF_INTERNAL 0x1
#define PKGCONF_PKG_DEPF_PRIVATE 0x2
#define PKGCONF_PKG_DEPF_QUERY 0x4
#define PKGCONF_PKG_ERRF_OK 0x0
#define PKGCONF_PKG_ERRF_PACKAGE_NOT_FOUND 0x1
#define PKGCONF_PKG_ERRF_PACKAGE_VER_MISMATCH 0x2
#define PKGCONF_PKG_ERRF_PACKAGE_CONFLICT 0x4
#define PKGCONF_PKG_ERRF_DEPGRAPH_BREAK 0x8
#if __GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4)
# define PRINTFLIKE(fmtarg, firstvararg) \
__attribute__((__format__ (gnu_printf, fmtarg, firstvararg)))
#elif defined(__clang__) || defined(__INTEL_COMPILER) || __GNUC__ > 2 || (_GNUC__ == 2 && __GNUC_MINOR__ >= 5)
# define PRINTFLIKE(fmtarg, firstvararg) \
__attribute__((__format__ (__printf__, fmtarg, firstvararg)))
#else
# define PRINTFLIKE(fmtarg, firstvararg)
#endif
#if defined(__clang__) || defined(__INTEL_COMPILER) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
# define DEPRECATED __attribute__((deprecated))
#elif defined(_MSC_VER)
# define DEPRECATED __declspec(deprecated)
#else
# define DEPRECATED
#endif
/* parser.c */
typedef void (*pkgconf_parser_operand_func_t)(void *data, const size_t lineno, const char *key, const char *value);
typedef void (*pkgconf_parser_warn_func_t)(void *data, const char *fmt, ...);
PKGCONF_API void pkgconf_parser_parse(FILE *f, void *data, const pkgconf_parser_operand_func_t *ops, const pkgconf_parser_warn_func_t warnfunc, const char *filename);
/* pkg.c */
PKGCONF_API bool pkgconf_error(const pkgconf_client_t *client, const char *format, ...) PRINTFLIKE(2, 3);
PKGCONF_API bool pkgconf_warn(const pkgconf_client_t *client, const char *format, ...) PRINTFLIKE(2, 3);
PKGCONF_API bool pkgconf_trace(const pkgconf_client_t *client, const char *filename, size_t lineno, const char *funcname, const char *format, ...) PRINTFLIKE(5, 6);
PKGCONF_API bool pkgconf_default_error_handler(const char *msg, const pkgconf_client_t *client, void *data);
#ifndef PKGCONF_LITE
#if defined(__GNUC__) || defined(__INTEL_COMPILER)
#define PKGCONF_TRACE(client, ...) do { \
pkgconf_trace(client, __FILE__, __LINE__, __PRETTY_FUNCTION__, __VA_ARGS__); \
} while (0)
#else
#define PKGCONF_TRACE(client, ...) do { \
pkgconf_trace(client, __FILE__, __LINE__, __func__, __VA_ARGS__); \
} while (0)
#endif
#else
#define PKGCONF_TRACE(client, ...)
#endif
PKGCONF_API pkgconf_pkg_t *pkgconf_pkg_ref(pkgconf_client_t *client, pkgconf_pkg_t *pkg);
PKGCONF_API void pkgconf_pkg_unref(pkgconf_client_t *client, pkgconf_pkg_t *pkg);
PKGCONF_API void pkgconf_pkg_free(pkgconf_client_t *client, pkgconf_pkg_t *pkg);
PKGCONF_API pkgconf_pkg_t *pkgconf_pkg_find(pkgconf_client_t *client, const char *name);
PKGCONF_API unsigned int pkgconf_pkg_traverse(pkgconf_client_t *client, pkgconf_pkg_t *root, pkgconf_pkg_traverse_func_t func, void *data, int maxdepth, unsigned int skip_flags);
PKGCONF_API unsigned int pkgconf_pkg_verify_graph(pkgconf_client_t *client, pkgconf_pkg_t *root, int depth);
PKGCONF_API pkgconf_pkg_t *pkgconf_pkg_verify_dependency(pkgconf_client_t *client, pkgconf_dependency_t *pkgdep, unsigned int *eflags);
PKGCONF_API const char *pkgconf_pkg_get_comparator(const pkgconf_dependency_t *pkgdep);
PKGCONF_API unsigned int pkgconf_pkg_cflags(pkgconf_client_t *client, pkgconf_pkg_t *root, pkgconf_list_t *list, int maxdepth);
PKGCONF_API unsigned int pkgconf_pkg_libs(pkgconf_client_t *client, pkgconf_pkg_t *root, pkgconf_list_t *list, int maxdepth);
PKGCONF_API pkgconf_pkg_comparator_t pkgconf_pkg_comparator_lookup_by_name(const char *name);
PKGCONF_API pkgconf_pkg_t *pkgconf_builtin_pkg_get(const char *name);
PKGCONF_API int pkgconf_compare_version(const char *a, const char *b);
PKGCONF_API pkgconf_pkg_t *pkgconf_scan_all(pkgconf_client_t *client, void *ptr, pkgconf_pkg_iteration_func_t func);
/* parse.c */
PKGCONF_API pkgconf_pkg_t *pkgconf_pkg_new_from_path(pkgconf_client_t *client, const char *path, unsigned int flags);
PKGCONF_API void pkgconf_dependency_parse_str(pkgconf_client_t *client, pkgconf_list_t *deplist_head, const char *depends, unsigned int flags);
PKGCONF_API void pkgconf_dependency_parse(pkgconf_client_t *client, pkgconf_pkg_t *pkg, pkgconf_list_t *deplist_head, const char *depends, unsigned int flags);
PKGCONF_API void pkgconf_dependency_append(pkgconf_list_t *list, pkgconf_dependency_t *tail);
PKGCONF_API void pkgconf_dependency_free(pkgconf_list_t *list);
PKGCONF_API void pkgconf_dependency_free_one(pkgconf_dependency_t *dep);
PKGCONF_API pkgconf_dependency_t *pkgconf_dependency_add(pkgconf_client_t *client, pkgconf_list_t *list, const char *package, const char *version, pkgconf_pkg_comparator_t compare, unsigned int flags);
PKGCONF_API pkgconf_dependency_t *pkgconf_dependency_ref(pkgconf_client_t *client, pkgconf_dependency_t *dep);
PKGCONF_API void pkgconf_dependency_unref(pkgconf_client_t *client, pkgconf_dependency_t *dep);
PKGCONF_API pkgconf_dependency_t *pkgconf_dependency_copy(pkgconf_client_t *client, const pkgconf_dependency_t *dep);
/* argvsplit.c */
PKGCONF_API int pkgconf_argv_split(const char *src, int *argc, char ***argv);
PKGCONF_API void pkgconf_argv_free(char **argv);
/* fragment.c */
typedef struct pkgconf_fragment_render_ops_ {
size_t (*render_len)(const pkgconf_list_t *list, bool escape);
void (*render_buf)(const pkgconf_list_t *list, char *buf, size_t len, bool escape);
} pkgconf_fragment_render_ops_t;
typedef bool (*pkgconf_fragment_filter_func_t)(const pkgconf_client_t *client, const pkgconf_fragment_t *frag, void *data);
PKGCONF_API bool pkgconf_fragment_parse(const pkgconf_client_t *client, pkgconf_list_t *list, pkgconf_list_t *vars, const char *value, unsigned int flags);
PKGCONF_API void pkgconf_fragment_insert(const pkgconf_client_t *client, pkgconf_list_t *list, char type, const char *data, bool tail);
PKGCONF_API void pkgconf_fragment_add(const pkgconf_client_t *client, pkgconf_list_t *list, const char *string, unsigned int flags);
PKGCONF_API void pkgconf_fragment_copy(const pkgconf_client_t *client, pkgconf_list_t *list, const pkgconf_fragment_t *base, bool is_private);
PKGCONF_API void pkgconf_fragment_copy_list(const pkgconf_client_t *client, pkgconf_list_t *list, const pkgconf_list_t *base);
PKGCONF_API void pkgconf_fragment_delete(pkgconf_list_t *list, pkgconf_fragment_t *node);
PKGCONF_API void pkgconf_fragment_free(pkgconf_list_t *list);
PKGCONF_API void pkgconf_fragment_filter(const pkgconf_client_t *client, pkgconf_list_t *dest, pkgconf_list_t *src, pkgconf_fragment_filter_func_t filter_func, void *data);
PKGCONF_API size_t pkgconf_fragment_render_len(const pkgconf_list_t *list, bool escape, const pkgconf_fragment_render_ops_t *ops);
PKGCONF_API void pkgconf_fragment_render_buf(const pkgconf_list_t *list, char *buf, size_t len, bool escape, const pkgconf_fragment_render_ops_t *ops);
PKGCONF_API char *pkgconf_fragment_render(const pkgconf_list_t *list, bool escape, const pkgconf_fragment_render_ops_t *ops);
PKGCONF_API bool pkgconf_fragment_has_system_dir(const pkgconf_client_t *client, const pkgconf_fragment_t *frag);
/* tuple.c */
PKGCONF_API pkgconf_tuple_t *pkgconf_tuple_add(const pkgconf_client_t *client, pkgconf_list_t *parent, const char *key, const char *value, bool parse, unsigned int flags);
PKGCONF_API char *pkgconf_tuple_find(const pkgconf_client_t *client, pkgconf_list_t *list, const char *key);
PKGCONF_API char *pkgconf_tuple_parse(const pkgconf_client_t *client, pkgconf_list_t *list, const char *value, unsigned int flags);
PKGCONF_API void pkgconf_tuple_free(pkgconf_list_t *list);
PKGCONF_API void pkgconf_tuple_free_entry(pkgconf_tuple_t *tuple, pkgconf_list_t *list);
PKGCONF_API void pkgconf_tuple_add_global(pkgconf_client_t *client, const char *key, const char *value);
PKGCONF_API char *pkgconf_tuple_find_global(const pkgconf_client_t *client, const char *key);
PKGCONF_API void pkgconf_tuple_free_global(pkgconf_client_t *client);
PKGCONF_API void pkgconf_tuple_define_global(pkgconf_client_t *client, const char *kv);
/* queue.c */
PKGCONF_API void pkgconf_queue_push(pkgconf_list_t *list, const char *package);
PKGCONF_API bool pkgconf_queue_compile(pkgconf_client_t *client, pkgconf_pkg_t *world, pkgconf_list_t *list);
PKGCONF_API bool pkgconf_queue_solve(pkgconf_client_t *client, pkgconf_list_t *list, pkgconf_pkg_t *world, int maxdepth);
PKGCONF_API void pkgconf_queue_free(pkgconf_list_t *list);
PKGCONF_API bool pkgconf_queue_apply(pkgconf_client_t *client, pkgconf_list_t *list, pkgconf_queue_apply_func_t func, int maxdepth, void *data);
PKGCONF_API bool pkgconf_queue_validate(pkgconf_client_t *client, pkgconf_list_t *list, int maxdepth);
PKGCONF_API void pkgconf_solution_free(pkgconf_client_t *client, pkgconf_pkg_t *world);
/* cache.c */
PKGCONF_API pkgconf_pkg_t *pkgconf_cache_lookup(pkgconf_client_t *client, const char *id);
PKGCONF_API void pkgconf_cache_add(pkgconf_client_t *client, pkgconf_pkg_t *pkg);
PKGCONF_API void pkgconf_cache_remove(pkgconf_client_t *client, pkgconf_pkg_t *pkg);
PKGCONF_API void pkgconf_cache_free(pkgconf_client_t *client);
/* audit.c */
PKGCONF_API void pkgconf_audit_set_log(pkgconf_client_t *client, FILE *auditf);
PKGCONF_API void pkgconf_audit_log(pkgconf_client_t *client, const char *format, ...) PRINTFLIKE(2, 3);
PKGCONF_API void pkgconf_audit_log_dependency(pkgconf_client_t *client, const pkgconf_pkg_t *dep, const pkgconf_dependency_t *depnode);
/* path.c */
PKGCONF_API void pkgconf_path_add(const char *text, pkgconf_list_t *dirlist, bool filter);
PKGCONF_API void pkgconf_path_prepend(const char *text, pkgconf_list_t *dirlist, bool filter);
PKGCONF_API size_t pkgconf_path_split(const char *text, pkgconf_list_t *dirlist, bool filter);
PKGCONF_API size_t pkgconf_path_build_from_environ(const char *envvarname, const char *fallback, pkgconf_list_t *dirlist, bool filter);
#ifdef _WIN32
PKGCONF_API size_t pkgconf_path_build_from_registry(/* HKEY -> HANDLE -> PVOID */ void *hKey, pkgconf_list_t *dirlist, bool filter);
#endif
PKGCONF_API bool pkgconf_path_match_list(const char *path, const pkgconf_list_t *dirlist);
PKGCONF_API void pkgconf_path_free(pkgconf_list_t *dirlist);
PKGCONF_API bool pkgconf_path_relocate(char *buf, size_t buflen);
PKGCONF_API void pkgconf_path_copy_list(pkgconf_list_t *dst, const pkgconf_list_t *src);
PKGCONF_API void pkgconf_path_prepend_list(pkgconf_list_t *dst, const pkgconf_list_t *src);
/* buffer.c */
typedef struct pkgconf_buffer_ {
char *base;
char *end;
} pkgconf_buffer_t;
PKGCONF_API void pkgconf_buffer_append(pkgconf_buffer_t *buffer, const char *text);
PKGCONF_API void pkgconf_buffer_push_byte(pkgconf_buffer_t *buffer, char byte);
PKGCONF_API void pkgconf_buffer_trim_byte(pkgconf_buffer_t *buffer);
PKGCONF_API void pkgconf_buffer_finalize(pkgconf_buffer_t *buffer);
static inline const char *pkgconf_buffer_str(const pkgconf_buffer_t *buffer) {
return buffer->base;
}
static inline size_t pkgconf_buffer_len(const pkgconf_buffer_t *buffer) {
return (size_t)(ptrdiff_t)(buffer->end - buffer->base);
}
static inline char pkgconf_buffer_lastc(const pkgconf_buffer_t *buffer) {
if (buffer->base == buffer->end)
return '\0';
return *(buffer->end - 1);
}
#define PKGCONF_BUFFER_INITIALIZER { NULL, NULL }
static inline void pkgconf_buffer_reset(pkgconf_buffer_t *buffer) {
pkgconf_buffer_finalize(buffer);
buffer->base = buffer->end = NULL;
}
/* fileio.c */
PKGCONF_API bool pkgconf_fgetline(pkgconf_buffer_t *buffer, FILE *stream);
#ifdef __cplusplus
}
#endif
#endif
+12
View File
@@ -0,0 +1,12 @@
configure_file(input : 'config.h.meson',
output : 'config.h',
configuration : cdata)
install_headers('libpkgconf.h',
'stdinc.h',
'iter.h',
'bsdstubs.h',
'libpkgconf-api.h',
subdir : 'pkgconf/libpkgconf')
+115
View File
@@ -0,0 +1,115 @@
/*
* parser.c
* rfc822 message parser
*
* Copyright (c) 2018 pkgconf authors (see AUTHORS).
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* This software is provided 'as is' and without any warranty, express or
* implied. In no event shall the authors be liable for any damages arising
* from the use of this software.
*/
#include <libpkgconf/config.h>
#include <libpkgconf/stdinc.h>
#include <libpkgconf/libpkgconf.h>
/*
* !doc
*
* .. c:function:: pkgconf_pkg_t *pkgconf_pkg_new_from_file(const pkgconf_client_t *client, const char *filename, FILE *f)
*
* Parse a .pc file into a pkgconf_pkg_t object structure.
*
* :param pkgconf_client_t* client: The pkgconf client object to use for dependency resolution.
* :param char* filename: The filename of the package file (including full path).
* :param FILE* f: The file object to read from.
* :returns: A ``pkgconf_pkg_t`` object which contains the package data.
* :rtype: pkgconf_pkg_t *
*/
void
pkgconf_parser_parse(FILE *f, void *data, const pkgconf_parser_operand_func_t *ops, const pkgconf_parser_warn_func_t warnfunc, const char *filename)
{
pkgconf_buffer_t readbuf = PKGCONF_BUFFER_INITIALIZER;
size_t lineno = 0;
bool continue_reading = true;
while (continue_reading)
{
char op, *p, *key, *value;
bool warned_key_whitespace = false, warned_value_whitespace = false;
continue_reading = pkgconf_fgetline(&readbuf, f);
lineno++;
p = readbuf.base;
if (p == NULL)
continue;
while (*p && isspace((unsigned char)*p))
p++;
if (*p && p != readbuf.base)
{
warnfunc(data, "%s:" SIZE_FMT_SPECIFIER ": warning: whitespace encountered while parsing key section\n",
filename, lineno);
warned_key_whitespace = true;
}
key = p;
while (*p && (isalpha((unsigned char)*p) || isdigit((unsigned char)*p) || *p == '_' || *p == '.'))
p++;
if (!isalpha((unsigned char)*key) &&
!isdigit((unsigned char)*p))
{
pkgconf_buffer_reset(&readbuf);
continue;
}
while (*p && isspace((unsigned char)*p))
{
if (!warned_key_whitespace)
{
warnfunc(data, "%s:" SIZE_FMT_SPECIFIER ": warning: whitespace encountered while parsing key section\n",
filename, lineno);
warned_key_whitespace = true;
}
/* set to null to avoid trailing spaces in key */
*p = '\0';
p++;
}
op = *p;
if (*p != '\0')
{
*p = '\0';
p++;
}
while (*p && isspace((unsigned char)*p))
p++;
value = p;
p = value + (strlen(value) - 1);
while (*p && isspace((unsigned char) *p) && p > value)
{
if (!warned_value_whitespace && op == '=')
{
warnfunc(data, "%s:" SIZE_FMT_SPECIFIER ": warning: trailing whitespace encountered while parsing value section\n",
filename, lineno);
warned_value_whitespace = true;
}
*p = '\0';
p--;
}
if (ops[(unsigned char) op])
ops[(unsigned char) op](data, lineno, key, value);
pkgconf_buffer_reset(&readbuf);
}
pkgconf_buffer_finalize(&readbuf);
}
+459
View File
@@ -0,0 +1,459 @@
/*
* path.c
* filesystem path management
*
* Copyright (c) 2016 pkgconf authors (see AUTHORS).
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* This software is provided 'as is' and without any warranty, express or
* implied. In no event shall the authors be liable for any damages arising
* from the use of this software.
*/
#include <libpkgconf/config.h>
#include <libpkgconf/stdinc.h>
#include <libpkgconf/libpkgconf.h>
#if defined(HAVE_SYS_STAT_H) && ! defined(_WIN32)
# include <sys/stat.h>
# define PKGCONF_CACHE_INODES
#endif
#ifdef _WIN32
# define PKG_CONFIG_REG_KEY "Software\\pkgconfig\\PKG_CONFIG_PATH"
#endif
static bool
#ifdef PKGCONF_CACHE_INODES
path_list_contains_entry(const char *text, pkgconf_list_t *dirlist, struct stat *st)
#else
path_list_contains_entry(const char *text, pkgconf_list_t *dirlist)
#endif
{
pkgconf_node_t *n;
PKGCONF_FOREACH_LIST_ENTRY(dirlist->head, n)
{
pkgconf_path_t *pn = n->data;
#ifdef PKGCONF_CACHE_INODES
if (pn->handle_device == (void *)(intptr_t)st->st_dev && pn->handle_path == (void *)(intptr_t)st->st_ino)
return true;
#endif
if (!strcmp(text, pn->path))
return true;
}
return false;
}
/*
* !doc
*
* libpkgconf `path` module
* ========================
*
* The `path` module provides functions for manipulating lists of paths in a cross-platform manner. Notably,
* it is used by the `pkgconf client` to parse the ``PKG_CONFIG_PATH``, ``PKG_CONFIG_LIBDIR`` and related environment
* variables.
*/
static pkgconf_path_t *
prepare_path_node(const char *text, pkgconf_list_t *dirlist, bool filter)
{
pkgconf_path_t *node;
char path[PKGCONF_ITEM_SIZE];
pkgconf_strlcpy(path, text, sizeof path);
pkgconf_path_relocate(path, sizeof path);
#ifdef PKGCONF_CACHE_INODES
struct stat st;
if (filter)
{
if (lstat(path, &st) == -1)
return NULL;
if (S_ISLNK(st.st_mode))
{
char pathbuf[PKGCONF_ITEM_SIZE * 4];
char *linkdest = realpath(path, pathbuf);
if (linkdest != NULL && stat(linkdest, &st) == -1)
return NULL;
}
if (path_list_contains_entry(path, dirlist, &st))
return NULL;
}
#else
if (filter && path_list_contains_entry(path, dirlist))
return NULL;
#endif
node = calloc(1, sizeof(pkgconf_path_t));
if (node == NULL)
return NULL;
node->path = strdup(path);
#ifdef PKGCONF_CACHE_INODES
if (filter) {
node->handle_path = (void *)(intptr_t) st.st_ino;
node->handle_device = (void *)(intptr_t) st.st_dev;
}
#endif
return node;
}
/*
* !doc
*
* .. c:function:: void pkgconf_path_add(const char *text, pkgconf_list_t *dirlist)
*
* Adds a path node to a path list. If the path is already in the list, do nothing.
*
* :param char* text: The path text to add as a path node.
* :param pkgconf_list_t* dirlist: The path list to add the path node to.
* :param bool filter: Whether to perform duplicate filtering.
* :return: nothing
*/
void
pkgconf_path_add(const char *text, pkgconf_list_t *dirlist, bool filter)
{
pkgconf_path_t *node = prepare_path_node(text, dirlist, filter);
if (node == NULL)
return;
pkgconf_node_insert_tail(&node->lnode, node, dirlist);
}
/*
* !doc
*
* .. c:function:: void pkgconf_path_prepend(const char *text, pkgconf_list_t *dirlist)
*
* Prepends a path node to a path list. If the path is already in the list, do nothing.
*
* :param char* text: The path text to add as a path node.
* :param pkgconf_list_t* dirlist: The path list to add the path node to.
* :param bool filter: Whether to perform duplicate filtering.
* :return: nothing
*/
void
pkgconf_path_prepend(const char *text, pkgconf_list_t *dirlist, bool filter)
{
pkgconf_path_t *node = prepare_path_node(text, dirlist, filter);
if (node == NULL)
return;
pkgconf_node_insert(&node->lnode, node, dirlist);
}
/*
* !doc
*
* .. c:function:: size_t pkgconf_path_split(const char *text, pkgconf_list_t *dirlist)
*
* Splits a given text input and inserts paths into a path list.
*
* :param char* text: The path text to split and add as path nodes.
* :param pkgconf_list_t* dirlist: The path list to have the path nodes added to.
* :param bool filter: Whether to perform duplicate filtering.
* :return: number of path nodes added to the path list
* :rtype: size_t
*/
size_t
pkgconf_path_split(const char *text, pkgconf_list_t *dirlist, bool filter)
{
size_t count = 0;
char *workbuf, *p, *iter;
if (text == NULL)
return 0;
iter = workbuf = strdup(text);
while ((p = strtok(iter, PKG_CONFIG_PATH_SEP_S)) != NULL)
{
pkgconf_path_add(p, dirlist, filter);
count++, iter = NULL;
}
free(workbuf);
return count;
}
/*
* !doc
*
* .. c:function:: size_t pkgconf_path_build_from_environ(const char *envvarname, const char *fallback, pkgconf_list_t *dirlist)
*
* Adds the paths specified in an environment variable to a path list. If the environment variable is not set,
* an optional default set of paths is added.
*
* :param char* envvarname: The environment variable to look up.
* :param char* fallback: The fallback paths to use if the environment variable is not set.
* :param pkgconf_list_t* dirlist: The path list to add the path nodes to.
* :param bool filter: Whether to perform duplicate filtering.
* :return: number of path nodes added to the path list
* :rtype: size_t
*/
size_t
pkgconf_path_build_from_environ(const char *envvarname, const char *fallback, pkgconf_list_t *dirlist, bool filter)
{
const char *data;
data = getenv(envvarname);
if (data != NULL)
return pkgconf_path_split(data, dirlist, filter);
if (fallback != NULL)
return pkgconf_path_split(fallback, dirlist, filter);
/* no fallback and no environment variable, thusly no nodes added */
return 0;
}
/*
* !doc
*
* .. c:function:: bool pkgconf_path_match_list(const char *path, const pkgconf_list_t *dirlist)
*
* Checks whether a path has a matching prefix in a path list.
*
* :param char* path: The path to check against a path list.
* :param pkgconf_list_t* dirlist: The path list to check the path against.
* :return: true if the path list has a matching prefix, otherwise false
* :rtype: bool
*/
bool
pkgconf_path_match_list(const char *path, const pkgconf_list_t *dirlist)
{
pkgconf_node_t *n = NULL;
char relocated[PKGCONF_ITEM_SIZE];
const char *cpath = path;
pkgconf_strlcpy(relocated, path, sizeof relocated);
if (pkgconf_path_relocate(relocated, sizeof relocated))
cpath = relocated;
PKGCONF_FOREACH_LIST_ENTRY(dirlist->head, n)
{
pkgconf_path_t *pnode = n->data;
if (!strcmp(pnode->path, cpath))
return true;
}
return false;
}
/*
* !doc
*
* .. c:function:: void pkgconf_path_copy_list(pkgconf_list_t *dst, const pkgconf_list_t *src)
*
* Copies a path list to another path list.
*
* :param pkgconf_list_t* dst: The path list to copy to.
* :param pkgconf_list_t* src: The path list to copy from.
* :return: nothing
*/
void
pkgconf_path_copy_list(pkgconf_list_t *dst, const pkgconf_list_t *src)
{
pkgconf_node_t *n;
PKGCONF_FOREACH_LIST_ENTRY(src->head, n)
{
pkgconf_path_t *srcpath = n->data, *path;
path = calloc(1, sizeof(pkgconf_path_t));
if (path == NULL)
continue;
path->path = strdup(srcpath->path);
#ifdef PKGCONF_CACHE_INODES
path->handle_path = srcpath->handle_path;
path->handle_device = srcpath->handle_device;
#endif
pkgconf_node_insert_tail(&path->lnode, path, dst);
}
}
/*
* !doc
*
* .. c:function:: void pkgconf_path_prepend_list(pkgconf_list_t *dst, const pkgconf_list_t *src)
*
* Copies a path list to another path list.
*
* :param pkgconf_list_t* dst: The path list to copy to.
* :param pkgconf_list_t* src: The path list to copy from.
* :return: nothing
*/
void
pkgconf_path_prepend_list(pkgconf_list_t *dst, const pkgconf_list_t *src)
{
pkgconf_node_t *n;
PKGCONF_FOREACH_LIST_ENTRY(src->head, n)
{
pkgconf_path_t *srcpath = n->data, *path;
path = calloc(1, sizeof(pkgconf_path_t));
if (path == NULL)
continue;
path->path = strdup(srcpath->path);
#ifdef PKGCONF_CACHE_INODES
path->handle_path = srcpath->handle_path;
path->handle_device = srcpath->handle_device;
#endif
pkgconf_node_insert(&path->lnode, path, dst);
}
}
/*
* !doc
*
* .. c:function:: void pkgconf_path_free(pkgconf_list_t *dirlist)
*
* Releases any path nodes attached to the given path list.
*
* :param pkgconf_list_t* dirlist: The path list to clean up.
* :return: nothing
*/
void
pkgconf_path_free(pkgconf_list_t *dirlist)
{
pkgconf_node_t *n, *tn;
PKGCONF_FOREACH_LIST_ENTRY_SAFE(dirlist->head, tn, n)
{
pkgconf_path_t *pnode = n->data;
free(pnode->path);
free(pnode);
}
pkgconf_list_zero(dirlist);
}
static char *
normpath(const char *path)
{
if (!path)
return NULL;
char *copy = strdup(path);
if (NULL == copy)
return NULL;
char *ptr = copy;
for (int ii = 0; copy[ii]; ii++)
{
*ptr++ = path[ii];
if ('/' == path[ii])
{
ii++;
while ('/' == path[ii])
ii++;
ii--;
}
}
*ptr = '\0';
return copy;
}
/*
* !doc
*
* .. c:function:: bool pkgconf_path_relocate(char *buf, size_t buflen)
*
* Relocates a path, possibly calling normpath() on it.
*
* :param char* buf: The path to relocate.
* :param size_t buflen: The buffer length the path is contained in.
* :return: true on success, false on error
* :rtype: bool
*/
bool
pkgconf_path_relocate(char *buf, size_t buflen)
{
char *tmpbuf;
if ((tmpbuf = normpath(buf)) != NULL)
{
size_t tmpbuflen = strlen(tmpbuf);
if (tmpbuflen > buflen)
{
free(tmpbuf);
return false;
}
pkgconf_strlcpy(buf, tmpbuf, buflen);
free(tmpbuf);
}
return true;
}
#ifdef _WIN32
/*
* !doc
*
* .. c:function:: void pkgconf_path_build_from_registry(HKEY hKey, pkgconf_list_t *dir_list, bool filter)
*
* Adds paths to a directory list discovered from a given registry key.
*
* :param HKEY hKey: The registry key to enumerate.
* :param pkgconf_list_t* dir_list: The directory list to append enumerated paths to.
* :param bool filter: Whether duplicate paths should be filtered.
* :return: number of path nodes added to the list
* :rtype: size_t
*/
size_t
pkgconf_path_build_from_registry(void *hKey, pkgconf_list_t *dir_list, bool filter)
{
HKEY key;
int i = 0;
size_t added = 0;
char buf[16384]; /* per registry limits */
DWORD bufsize = sizeof buf;
if (RegOpenKeyEx(hKey, PKG_CONFIG_REG_KEY,
0, KEY_READ, &key) != ERROR_SUCCESS)
return 0;
while (RegEnumValue(key, i++, buf, &bufsize, NULL, NULL, NULL, NULL)
== ERROR_SUCCESS)
{
char pathbuf[PKGCONF_ITEM_SIZE];
DWORD type;
DWORD pathbuflen = sizeof pathbuf;
if (RegQueryValueEx(key, buf, NULL, &type, (LPBYTE) pathbuf, &pathbuflen)
== ERROR_SUCCESS && type == REG_SZ)
{
pkgconf_path_add(pathbuf, dir_list, filter);
added++;
}
bufsize = sizeof buf;
}
RegCloseKey(key);
return added;
}
#endif
+359
View File
@@ -0,0 +1,359 @@
/*
* personality.c
* libpkgconf cross-compile personality database
*
* Copyright (c) 2018 pkgconf authors (see AUTHORS).
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* This software is provided 'as is' and without any warranty, express or
* implied. In no event shall the authors be liable for any damages arising
* from the use of this software.
*/
#include <libpkgconf/config.h>
#include <libpkgconf/stdinc.h>
#include <libpkgconf/libpkgconf.h>
/*
* !doc
*
* libpkgconf `personality` module
* =========================
*/
#ifdef _WIN32
# define strcasecmp _stricmp
#endif
/*
* Increment each time the default personality is inited, decrement each time
* it's deinited. Whenever it is 0, then the deinit frees the personality. In
* that case an additional call to init will create it anew.
*/
static unsigned default_personality_init = 0;
static pkgconf_cross_personality_t default_personality = {
.name = "default",
};
static inline void
build_default_search_path(pkgconf_list_t* dirlist)
{
#ifdef _WIN32
char namebuf[MAX_PATH];
char outbuf[MAX_PATH];
char *p;
int sizepath = GetModuleFileName(NULL, namebuf, sizeof namebuf);
char * winslash;
namebuf[sizepath] = '\0';
while ((winslash = strchr (namebuf, '\\')) != NULL)
{
*winslash = '/';
}
p = strrchr(namebuf, '/');
if (p == NULL)
pkgconf_path_split(PKG_DEFAULT_PATH, dirlist, true);
*p = '\0';
pkgconf_strlcpy(outbuf, namebuf, sizeof outbuf);
pkgconf_strlcat(outbuf, "/", sizeof outbuf);
pkgconf_strlcat(outbuf, "../lib/pkgconfig", sizeof outbuf);
pkgconf_path_add(outbuf, dirlist, true);
pkgconf_strlcpy(outbuf, namebuf, sizeof outbuf);
pkgconf_strlcat(outbuf, "/", sizeof outbuf);
pkgconf_strlcat(outbuf, "../share/pkgconfig", sizeof outbuf);
pkgconf_path_add(outbuf, dirlist, true);
#elif __HAIKU__
char **paths;
size_t count;
if (find_paths(B_FIND_PATH_DEVELOP_LIB_DIRECTORY, "pkgconfig", &paths, &count) == B_OK) {
for (size_t i = 0; i < count; i++)
pkgconf_path_add(paths[i], dirlist, true);
free(paths);
paths = NULL;
}
if (find_paths(B_FIND_PATH_DATA_DIRECTORY, "pkgconfig", &paths, &count) == B_OK) {
for (size_t i = 0; i < count; i++)
pkgconf_path_add(paths[i], dirlist, true);
free(paths);
paths = NULL;
}
#else
pkgconf_path_split(PKG_DEFAULT_PATH, dirlist, true);
#endif
}
/*
* !doc
*
* .. c:function:: const pkgconf_cross_personality_t *pkgconf_cross_personality_default(void)
*
* Returns the default cross-compile personality.
*
* Not thread safe.
*
* :rtype: pkgconf_cross_personality_t*
* :return: the default cross-compile personality
*/
pkgconf_cross_personality_t *
pkgconf_cross_personality_default(void)
{
if (default_personality_init) {
++default_personality_init;
return &default_personality;
}
build_default_search_path(&default_personality.dir_list);
pkgconf_path_split(SYSTEM_LIBDIR, &default_personality.filter_libdirs, false);
pkgconf_path_split(SYSTEM_INCLUDEDIR, &default_personality.filter_includedirs, false);
++default_personality_init;
return &default_personality;
}
/*
* !doc
*
* .. c:function:: void pkgconf_cross_personality_deinit(pkgconf_cross_personality_t *)
*
* Destroys a cross personality object and/or decreases the reference count on the
* default cross personality object.
*
* Not thread safe.
*
* :rtype: void
*/
void
pkgconf_cross_personality_deinit(pkgconf_cross_personality_t *personality)
{
/* allow NULL parameter for API backwards compatibility */
if (personality == NULL)
return;
/* XXX: this hack is rather ugly, but it works for now... */
if (personality == &default_personality && --default_personality_init > 0)
return;
pkgconf_path_free(&personality->dir_list);
pkgconf_path_free(&personality->filter_libdirs);
pkgconf_path_free(&personality->filter_includedirs);
if (personality->sysroot_dir != NULL)
free(personality->sysroot_dir);
if (personality == &default_personality)
return;
if (personality->name != NULL)
free(personality->name);
free(personality);
}
#ifndef PKGCONF_LITE
static bool
valid_triplet(const char *triplet)
{
const char *c = triplet;
for (; *c; c++)
if (!isalnum((unsigned char)*c) && *c != '-' && *c != '_')
return false;
return true;
}
typedef void (*personality_keyword_func_t)(pkgconf_cross_personality_t *p, const char *keyword, const size_t lineno, const ptrdiff_t offset, char *value);
typedef struct {
const char *keyword;
const personality_keyword_func_t func;
const ptrdiff_t offset;
} personality_keyword_pair_t;
static void
personality_bool_func(pkgconf_cross_personality_t *p, const char *keyword, const size_t lineno, const ptrdiff_t offset, char *value)
{
(void) keyword;
(void) lineno;
bool *dest = (bool *)((char *) p + offset);
*dest = strcasecmp(value, "true") || strcasecmp(value, "yes") || *value == '1';
}
static void
personality_copy_func(pkgconf_cross_personality_t *p, const char *keyword, const size_t lineno, const ptrdiff_t offset, char *value)
{
(void) keyword;
(void) lineno;
char **dest = (char **)((char *) p + offset);
*dest = strdup(value);
}
static void
personality_fragment_func(pkgconf_cross_personality_t *p, const char *keyword, const size_t lineno, const ptrdiff_t offset, char *value)
{
(void) keyword;
(void) lineno;
pkgconf_list_t *dest = (pkgconf_list_t *)((char *) p + offset);
pkgconf_path_split(value, dest, false);
}
/* keep in alphabetical order! */
static const personality_keyword_pair_t personality_keyword_pairs[] = {
{"DefaultSearchPaths", personality_fragment_func, offsetof(pkgconf_cross_personality_t, dir_list)},
{"SysrootDir", personality_copy_func, offsetof(pkgconf_cross_personality_t, sysroot_dir)},
{"SystemIncludePaths", personality_fragment_func, offsetof(pkgconf_cross_personality_t, filter_includedirs)},
{"SystemLibraryPaths", personality_fragment_func, offsetof(pkgconf_cross_personality_t, filter_libdirs)},
{"Triplet", personality_copy_func, offsetof(pkgconf_cross_personality_t, name)},
{"WantDefaultPure", personality_bool_func, offsetof(pkgconf_cross_personality_t, want_default_pure)},
{"WantDefaultStatic", personality_bool_func, offsetof(pkgconf_cross_personality_t, want_default_static)},
};
static int
personality_keyword_pair_cmp(const void *key, const void *ptr)
{
const personality_keyword_pair_t *pair = ptr;
return strcasecmp(key, pair->keyword);
}
static void
personality_keyword_set(pkgconf_cross_personality_t *p, const size_t lineno, const char *keyword, char *value)
{
const personality_keyword_pair_t *pair = bsearch(keyword,
personality_keyword_pairs, PKGCONF_ARRAY_SIZE(personality_keyword_pairs),
sizeof(personality_keyword_pair_t), personality_keyword_pair_cmp);
if (pair == NULL || pair->func == NULL)
return;
pair->func(p, keyword, lineno, pair->offset, value);
}
static const pkgconf_parser_operand_func_t personality_parser_ops[256] = {
[':'] = (pkgconf_parser_operand_func_t) personality_keyword_set
};
static void personality_warn_func(void *p, const char *fmt, ...) PRINTFLIKE(2, 3);
static void
personality_warn_func(void *p, const char *fmt, ...)
{
va_list va;
(void) p;
va_start(va, fmt);
vfprintf(stderr, fmt, va);
va_end(va);
}
static pkgconf_cross_personality_t *
load_personality_with_path(const char *path, const char *triplet, bool datadir)
{
char pathbuf[PKGCONF_ITEM_SIZE];
FILE *f;
pkgconf_cross_personality_t *p;
/* if triplet is null, assume that path is a direct path to the personality file */
if (triplet == NULL)
pkgconf_strlcpy(pathbuf, path, sizeof pathbuf);
else if (datadir)
snprintf(pathbuf, sizeof pathbuf, "%s/pkgconfig/personality.d/%s.personality", path, triplet);
else
snprintf(pathbuf, sizeof pathbuf, "%s/%s.personality", path, triplet);
p = calloc(1, sizeof(pkgconf_cross_personality_t));
if (p == NULL)
return NULL;
if (triplet != NULL)
p->name = strdup(triplet);
f = fopen(pathbuf, "r");
if (f == NULL) {
pkgconf_cross_personality_deinit(p);
return NULL;
}
pkgconf_parser_parse(f, p, personality_parser_ops, personality_warn_func, pathbuf);
return p;
}
/*
* !doc
*
* .. c:function:: pkgconf_cross_personality_t *pkgconf_cross_personality_find(const char *triplet)
*
* Attempts to find a cross-compile personality given a triplet.
*
* :rtype: pkgconf_cross_personality_t*
* :return: the default cross-compile personality
*/
pkgconf_cross_personality_t *
pkgconf_cross_personality_find(const char *triplet)
{
pkgconf_list_t plist = PKGCONF_LIST_INITIALIZER;
pkgconf_node_t *n;
pkgconf_cross_personality_t *out = NULL;
#if ! defined(_WIN32) && ! defined(__HAIKU__)
char pathbuf[PKGCONF_ITEM_SIZE];
const char *envvar;
#endif
out = load_personality_with_path(triplet, NULL, false);
if (out != NULL)
return out;
if (!valid_triplet(triplet))
return NULL;
#if ! defined(_WIN32) && ! defined(__HAIKU__)
envvar = getenv("XDG_DATA_HOME");
if (envvar != NULL)
pkgconf_path_add(envvar, &plist, true);
else {
envvar = getenv("HOME");
if (envvar != NULL) {
pkgconf_strlcpy(pathbuf, envvar, sizeof pathbuf);
pkgconf_strlcat(pathbuf, "/.local/share", sizeof pathbuf);
pkgconf_path_add(pathbuf, &plist, true);
}
}
pkgconf_path_build_from_environ("XDG_DATA_DIRS", "/usr/local/share" PKG_CONFIG_PATH_SEP_S "/usr/share", &plist, true);
PKGCONF_FOREACH_LIST_ENTRY(plist.head, n)
{
pkgconf_path_t *pn = n->data;
out = load_personality_with_path(pn->path, triplet, true);
if (out != NULL)
goto finish;
}
pkgconf_path_free(&plist);
#endif
pkgconf_path_split(PERSONALITY_PATH, &plist, true);
PKGCONF_FOREACH_LIST_ENTRY(plist.head, n)
{
pkgconf_path_t *pn = n->data;
out = load_personality_with_path(pn->path, triplet, false);
if (out != NULL)
goto finish;
}
finish:
pkgconf_path_free(&plist);
return out != NULL ? out : pkgconf_cross_personality_default();
}
#endif
File diff suppressed because it is too large Load Diff
+408
View File
@@ -0,0 +1,408 @@
/*
* queue.c
* compilation of a list of packages into a world dependency set
*
* Copyright (c) 2012 pkgconf authors (see AUTHORS).
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* This software is provided 'as is' and without any warranty, express or
* implied. In no event shall the authors be liable for any damages arising
* from the use of this software.
*/
#include <libpkgconf/stdinc.h>
#include <libpkgconf/libpkgconf.h>
/*
* !doc
*
* libpkgconf `queue` module
* =========================
*
* The `queue` module provides an interface that allows easily building a dependency graph from an
* arbitrary set of dependencies. It also provides support for doing "preflight" checks on the entire
* dependency graph prior to working with it.
*
* Using the `queue` module functions is the recommended way of working with dependency graphs.
*/
/*
* !doc
*
* .. c:function:: void pkgconf_queue_push(pkgconf_list_t *list, const char *package)
*
* Pushes a requested dependency onto the dependency resolver's queue.
*
* :param pkgconf_list_t* list: the dependency resolution queue to add the package request to.
* :param char* package: the dependency atom requested
* :return: nothing
*/
void
pkgconf_queue_push(pkgconf_list_t *list, const char *package)
{
pkgconf_queue_t *pkgq = calloc(1, sizeof(pkgconf_queue_t));
pkgq->package = strdup(package);
pkgconf_node_insert_tail(&pkgq->iter, pkgq, list);
}
/*
* !doc
*
* .. c:function:: bool pkgconf_queue_compile(pkgconf_client_t *client, pkgconf_pkg_t *world, pkgconf_list_t *list)
*
* Compile a dependency resolution queue into a dependency resolution problem if possible, otherwise report an error.
*
* :param pkgconf_client_t* client: The pkgconf client object to use for dependency resolution.
* :param pkgconf_pkg_t* world: The designated root of the dependency graph.
* :param pkgconf_list_t* list: The list of dependency requests to consider.
* :return: true if the built dependency resolution problem is consistent, else false
* :rtype: bool
*/
bool
pkgconf_queue_compile(pkgconf_client_t *client, pkgconf_pkg_t *world, pkgconf_list_t *list)
{
pkgconf_node_t *iter;
PKGCONF_FOREACH_LIST_ENTRY(list->head, iter)
{
pkgconf_queue_t *pkgq;
pkgq = iter->data;
pkgconf_dependency_parse(client, world, &world->required, pkgq->package, PKGCONF_PKG_DEPF_QUERY);
}
return (world->required.head != NULL);
}
/*
* !doc
*
* .. c:function:: void pkgconf_queue_free(pkgconf_list_t *list)
*
* Release any memory related to a dependency resolution queue.
*
* :param pkgconf_list_t* list: The dependency resolution queue to release.
* :return: nothing
*/
void
pkgconf_queue_free(pkgconf_list_t *list)
{
pkgconf_node_t *node, *tnode;
PKGCONF_FOREACH_LIST_ENTRY_SAFE(list->head, tnode, node)
{
pkgconf_queue_t *pkgq = node->data;
free(pkgq->package);
free(pkgq);
}
}
static void
pkgconf_queue_mark_public(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data)
{
if (pkg->flags & PKGCONF_PKG_PROPF_VISITED_PRIVATE)
{
pkgconf_list_t *list = data;
pkgconf_node_t *node;
PKGCONF_FOREACH_LIST_ENTRY(list->head, node)
{
pkgconf_dependency_t *dep = node->data;
if (dep->match == pkg)
dep->flags &= ~PKGCONF_PKG_DEPF_PRIVATE;
}
pkg->flags &= ~PKGCONF_PKG_PROPF_VISITED_PRIVATE;
PKGCONF_TRACE(client, "%s: updated, public", pkg->id);
}
}
static unsigned int
pkgconf_queue_collect_dependencies_main(pkgconf_client_t *client,
pkgconf_pkg_t *root,
void *data,
int maxdepth);
static inline unsigned int
pkgconf_queue_collect_dependencies_walk(pkgconf_client_t *client,
pkgconf_list_t *deplist,
void *data,
int depth)
{
unsigned int eflags = PKGCONF_PKG_ERRF_OK;
pkgconf_node_t *node;
pkgconf_pkg_t *world = data;
PKGCONF_FOREACH_LIST_ENTRY_REVERSE(deplist->tail, node)
{
pkgconf_dependency_t *dep = node->data;
pkgconf_dependency_t *flattened_dep;
pkgconf_pkg_t *pkg = dep->match;
if (*dep->package == '\0')
continue;
if (pkg == NULL)
{
PKGCONF_TRACE(client, "WTF: unmatched dependency %p <%s>", dep, dep->package);
continue;
}
if (pkg->serial == client->serial)
continue;
if (client->flags & PKGCONF_PKG_PKGF_ITER_PKG_IS_PRIVATE)
pkg->flags |= PKGCONF_PKG_PROPF_VISITED_PRIVATE;
else
pkg->flags &= ~PKGCONF_PKG_PROPF_VISITED_PRIVATE;
eflags |= pkgconf_queue_collect_dependencies_main(client, pkg, data, depth - 1);
flattened_dep = pkgconf_dependency_copy(client, dep);
pkgconf_node_insert(&flattened_dep->iter, flattened_dep, &world->required);
}
return eflags;
}
static unsigned int
pkgconf_queue_collect_dependencies_main(pkgconf_client_t *client,
pkgconf_pkg_t *root,
void *data,
int maxdepth)
{
unsigned int eflags = PKGCONF_PKG_ERRF_OK;
if (maxdepth == 0)
return eflags;
/* Short-circuit if we have already visited this node.
*/
if (root->serial == client->serial)
return eflags;
root->serial = client->serial;
PKGCONF_TRACE(client, "%s: collecting private dependencies, level %d", root->id, maxdepth);
/* XXX: ugly */
const unsigned int saved_flags = client->flags;
client->flags |= PKGCONF_PKG_PKGF_ITER_PKG_IS_PRIVATE;
eflags = pkgconf_queue_collect_dependencies_walk(client, &root->requires_private, data, maxdepth);
client->flags = saved_flags;
if (eflags != PKGCONF_PKG_ERRF_OK)
return eflags;
PKGCONF_TRACE(client, "%s: collecting public dependencies, level %d", root->id, maxdepth);
eflags = pkgconf_queue_collect_dependencies_walk(client, &root->required, data, maxdepth);
if (eflags != PKGCONF_PKG_ERRF_OK)
return eflags;
PKGCONF_TRACE(client, "%s: finished, %s", root->id, (root->flags & PKGCONF_PKG_PROPF_VISITED_PRIVATE) ? "private" : "public");
return eflags;
}
static inline unsigned int
pkgconf_queue_collect_dependencies(pkgconf_client_t *client,
pkgconf_pkg_t *root,
void *data,
int maxdepth)
{
++client->serial;
return pkgconf_queue_collect_dependencies_main(client, root, data, maxdepth);
}
static inline unsigned int
pkgconf_queue_verify(pkgconf_client_t *client, pkgconf_pkg_t *world, pkgconf_list_t *list, int maxdepth)
{
unsigned int result;
const unsigned int saved_flags = client->flags;
pkgconf_pkg_t initial_world = {
.id = "user:request",
.realname = "virtual world package",
.flags = PKGCONF_PKG_PROPF_STATIC | PKGCONF_PKG_PROPF_VIRTUAL,
};
if (!pkgconf_queue_compile(client, &initial_world, list))
{
pkgconf_solution_free(client, &initial_world);
return PKGCONF_PKG_ERRF_DEPGRAPH_BREAK;
}
PKGCONF_TRACE(client, "solving");
result = pkgconf_pkg_traverse(client, &initial_world, NULL, NULL, maxdepth, 0);
if (result != PKGCONF_PKG_ERRF_OK)
{
pkgconf_solution_free(client, &initial_world);
return result;
}
PKGCONF_TRACE(client, "flattening");
result = pkgconf_queue_collect_dependencies(client, &initial_world, world, maxdepth);
if (result != PKGCONF_PKG_ERRF_OK)
{
pkgconf_solution_free(client, &initial_world);
return result;
}
if (client->flags & PKGCONF_PKG_PKGF_SEARCH_PRIVATE)
{
PKGCONF_TRACE(client, "marking public deps");
client->flags &= ~PKGCONF_PKG_PKGF_SEARCH_PRIVATE;
client->flags |= PKGCONF_PKG_PKGF_SKIP_CONFLICTS;
result = pkgconf_pkg_traverse(client, &initial_world, pkgconf_queue_mark_public, &world->required, maxdepth, 0);
client->flags = saved_flags;
if (result != PKGCONF_PKG_ERRF_OK)
{
pkgconf_solution_free(client, &initial_world);
return result;
}
}
/* free the initial solution */
pkgconf_solution_free(client, &initial_world);
return PKGCONF_PKG_ERRF_OK;
}
/*
* !doc
*
* .. c:function:: void pkgconf_solution_free(pkgconf_client_t *client, pkgconf_pkg_t *world, int maxdepth)
*
* Removes references to package nodes contained in a solution.
*
* :param pkgconf_client_t* client: The pkgconf client object to use for dependency resolution.
* :param pkgconf_pkg_t* world: The root for the generated dependency graph. Should have PKGCONF_PKG_PROPF_VIRTUAL flag.
* :returns: nothing
*/
void
pkgconf_solution_free(pkgconf_client_t *client, pkgconf_pkg_t *world)
{
(void) client;
if (world->flags & PKGCONF_PKG_PROPF_VIRTUAL)
{
pkgconf_dependency_free(&world->required);
pkgconf_dependency_free(&world->requires_private);
}
}
/*
* !doc
*
* .. c:function:: bool pkgconf_queue_solve(pkgconf_client_t *client, pkgconf_list_t *list, pkgconf_pkg_t *world, int maxdepth)
*
* Solves and flattens the dependency graph for the supplied dependency list.
*
* :param pkgconf_client_t* client: The pkgconf client object to use for dependency resolution.
* :param pkgconf_list_t* list: The list of dependency requests to consider.
* :param pkgconf_pkg_t* world: The root for the generated dependency graph, provided by the caller. Should have PKGCONF_PKG_PROPF_VIRTUAL flag.
* :param int maxdepth: The maximum allowed depth for the dependency resolver. A depth of -1 means unlimited.
* :returns: true if the dependency resolver found a solution, otherwise false.
* :rtype: bool
*/
bool
pkgconf_queue_solve(pkgconf_client_t *client, pkgconf_list_t *list, pkgconf_pkg_t *world, int maxdepth)
{
/* if maxdepth is one, then we will not traverse deeper than our virtual package. */
if (!maxdepth)
maxdepth = -1;
unsigned int flags = client->flags;
client->flags |= PKGCONF_PKG_PKGF_SEARCH_PRIVATE;
unsigned int ret = pkgconf_queue_verify(client, world, list, maxdepth);
client->flags = flags;
return ret == PKGCONF_PKG_ERRF_OK;
}
/*
* !doc
*
* .. c:function:: void pkgconf_queue_apply(pkgconf_client_t *client, pkgconf_list_t *list, pkgconf_queue_apply_func_t func, int maxdepth, void *data)
*
* Attempt to compile a dependency resolution queue into a dependency resolution problem, then attempt to solve the problem and
* feed the solution to a callback function if a complete dependency graph is found.
*
* This function should not be used in new code. Use pkgconf_queue_solve instead.
*
* :param pkgconf_client_t* client: The pkgconf client object to use for dependency resolution.
* :param pkgconf_list_t* list: The list of dependency requests to consider.
* :param pkgconf_queue_apply_func_t func: The callback function to call if a solution is found by the dependency resolver.
* :param int maxdepth: The maximum allowed depth for the dependency resolver. A depth of -1 means unlimited.
* :param void* data: An opaque pointer which is passed to the callback function.
* :returns: true if the dependency resolver found a solution, otherwise false.
* :rtype: bool
*/
bool
pkgconf_queue_apply(pkgconf_client_t *client, pkgconf_list_t *list, pkgconf_queue_apply_func_t func, int maxdepth, void *data)
{
bool ret = false;
pkgconf_pkg_t world = {
.id = "virtual:world",
.realname = "virtual world package",
.flags = PKGCONF_PKG_PROPF_STATIC | PKGCONF_PKG_PROPF_VIRTUAL,
};
/* if maxdepth is one, then we will not traverse deeper than our virtual package. */
if (!maxdepth)
maxdepth = -1;
if (!pkgconf_queue_solve(client, list, &world, maxdepth))
goto cleanup;
/* the world dependency set is flattened after it is returned from pkgconf_queue_verify */
if (!func(client, &world, data, maxdepth))
goto cleanup;
ret = true;
cleanup:
pkgconf_pkg_free(client, &world);
return ret;
}
/*
* !doc
*
* .. c:function:: void pkgconf_queue_validate(pkgconf_client_t *client, pkgconf_list_t *list, pkgconf_queue_apply_func_t func, int maxdepth, void *data)
*
* Attempt to compile a dependency resolution queue into a dependency resolution problem, then attempt to solve the problem.
*
* :param pkgconf_client_t* client: The pkgconf client object to use for dependency resolution.
* :param pkgconf_list_t* list: The list of dependency requests to consider.
* :param int maxdepth: The maximum allowed depth for the dependency resolver. A depth of -1 means unlimited.
* :returns: true if the dependency resolver found a solution, otherwise false.
* :rtype: bool
*/
bool
pkgconf_queue_validate(pkgconf_client_t *client, pkgconf_list_t *list, int maxdepth)
{
bool retval = true;
pkgconf_pkg_t world = {
.id = "virtual:world",
.realname = "virtual world package",
.flags = PKGCONF_PKG_PROPF_STATIC | PKGCONF_PKG_PROPF_VIRTUAL,
};
/* if maxdepth is one, then we will not traverse deeper than our virtual package. */
if (!maxdepth)
maxdepth = -1;
if (pkgconf_queue_verify(client, &world, list, maxdepth) != PKGCONF_PKG_ERRF_OK)
retval = false;
pkgconf_pkg_free(client, &world);
return retval;
}
+75
View File
@@ -0,0 +1,75 @@
/*
* stdinc.h
* pull in standard headers (including portability hacks)
*
* Copyright (c) 2012 pkgconf authors (see AUTHORS).
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* This software is provided 'as is' and without any warranty, express or
* implied. In no event shall the authors be liable for any damages arising
* from the use of this software.
*/
#ifndef LIBPKGCONF_STDINC_H
#define LIBPKGCONF_STDINC_H
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <stdbool.h>
#include <stdarg.h>
#include <string.h>
#include <sys/types.h>
#include <stdint.h>
#include <errno.h>
#ifdef _WIN32
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
# include <malloc.h>
# define PATH_DEV_NULL "nul"
# ifdef _WIN64
# ifndef __MINGW32__
# define SIZE_FMT_SPECIFIER "%I64u"
# else
# define SIZE_FMT_SPECIFIER "%llu"
# endif
# else
# define SIZE_FMT_SPECIFIER "%u"
# endif
# ifndef ssize_t
# ifndef __MINGW32__
# include <BaseTsd.h>
# else
# include <basetsd.h>
# endif
# define ssize_t SSIZE_T
# endif
# ifndef __MINGW32__
# include "win-dirent.h"
# else
# include <dirent.h>
# endif
# define PKGCONF_ITEM_SIZE (_MAX_PATH + 1024)
#else
# define PATH_DEV_NULL "/dev/null"
# define SIZE_FMT_SPECIFIER "%zu"
# ifdef __HAIKU__
# include <FindDirectory.h>
# endif
# include <dirent.h>
# include <unistd.h>
# include <limits.h>
# include <strings.h>
# ifdef PATH_MAX
# define PKGCONF_ITEM_SIZE (PATH_MAX + 1024)
# else
# define PKGCONF_ITEM_SIZE (4096 + 1024)
# endif
#endif
#endif
+476
View File
@@ -0,0 +1,476 @@
/*
* tuple.c
* management of key->value tuples
*
* Copyright (c) 2011, 2012 pkgconf authors (see AUTHORS).
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* This software is provided 'as is' and without any warranty, express or
* implied. In no event shall the authors be liable for any damages arising
* from the use of this software.
*/
#include <libpkgconf/stdinc.h>
#include <libpkgconf/libpkgconf.h>
/*
* !doc
*
* libpkgconf `tuple` module
* =========================
*
* The `tuple` module provides key-value mappings backed by a linked list. The key-value
* mapping is mainly used for variable substitution when parsing .pc files.
*
* There are two sets of mappings: a ``pkgconf_pkg_t`` specific mapping, and a `global` mapping.
* The `tuple` module provides convenience wrappers for managing the `global` mapping, which is
* attached to a given client object.
*/
/*
* !doc
*
* .. c:function:: void pkgconf_tuple_add_global(pkgconf_client_t *client, const char *key, const char *value)
*
* Defines a global variable, replacing the previous declaration if one was set.
*
* :param pkgconf_client_t* client: The pkgconf client object to modify.
* :param char* key: The key for the mapping (variable name).
* :param char* value: The value for the mapped entry.
* :return: nothing
*/
void
pkgconf_tuple_add_global(pkgconf_client_t *client, const char *key, const char *value)
{
pkgconf_tuple_add(client, &client->global_vars, key, value, false, 0);
}
static pkgconf_tuple_t *
lookup_global_tuple(const pkgconf_client_t *client, const char *key)
{
pkgconf_node_t *node;
PKGCONF_FOREACH_LIST_ENTRY(client->global_vars.head, node)
{
pkgconf_tuple_t *tuple = node->data;
if (!strcmp(tuple->key, key))
return tuple;
}
return NULL;
}
/*
* !doc
*
* .. c:function:: void pkgconf_tuple_find_global(const pkgconf_client_t *client, const char *key)
*
* Looks up a global variable.
*
* :param pkgconf_client_t* client: The pkgconf client object to access.
* :param char* key: The key or variable name to look up.
* :return: the contents of the variable or ``NULL``
* :rtype: char *
*/
char *
pkgconf_tuple_find_global(const pkgconf_client_t *client, const char *key)
{
pkgconf_tuple_t *tuple;
tuple = lookup_global_tuple(client, key);
if (tuple == NULL)
return NULL;
return tuple->value;
}
/*
* !doc
*
* .. c:function:: void pkgconf_tuple_free_global(pkgconf_client_t *client)
*
* Delete all global variables associated with a pkgconf client object.
*
* :param pkgconf_client_t* client: The pkgconf client object to modify.
* :return: nothing
*/
void
pkgconf_tuple_free_global(pkgconf_client_t *client)
{
pkgconf_tuple_free(&client->global_vars);
}
/*
* !doc
*
* .. c:function:: void pkgconf_tuple_define_global(pkgconf_client_t *client, const char *kv)
*
* Parse and define a global variable.
*
* :param pkgconf_client_t* client: The pkgconf client object to modify.
* :param char* kv: The variable in the form of ``key=value``.
* :return: nothing
*/
void
pkgconf_tuple_define_global(pkgconf_client_t *client, const char *kv)
{
char *workbuf = strdup(kv);
char *value;
pkgconf_tuple_t *tuple;
value = strchr(workbuf, '=');
if (value == NULL)
goto out;
*value++ = '\0';
tuple = pkgconf_tuple_add(client, &client->global_vars, workbuf, value, false, 0);
if (tuple != NULL)
tuple->flags = PKGCONF_PKG_TUPLEF_OVERRIDE;
out:
free(workbuf);
}
static void
pkgconf_tuple_find_delete(pkgconf_list_t *list, const char *key)
{
pkgconf_node_t *node, *next;
PKGCONF_FOREACH_LIST_ENTRY_SAFE(list->head, next, node)
{
pkgconf_tuple_t *tuple = node->data;
if (!strcmp(tuple->key, key))
{
pkgconf_tuple_free_entry(tuple, list);
return;
}
}
}
static char *
dequote(const char *value)
{
char *buf = calloc(1, (strlen(value) + 1) * 2);
char *bptr = buf;
const char *i;
char quote = 0;
if (*value == '\'' || *value == '"')
quote = *value;
for (i = value; *i != '\0'; i++)
{
if (*i == '\\' && quote && *(i + 1) == quote)
{
i++;
*bptr++ = *i;
}
else if (*i != quote)
*bptr++ = *i;
}
return buf;
}
static const char *
find_sysroot(const pkgconf_client_t *client, pkgconf_list_t *vars)
{
const char *sysroot_dir;
sysroot_dir = pkgconf_tuple_find(client, vars, "pc_sysrootdir");
if (sysroot_dir == NULL)
sysroot_dir = client->sysroot_dir;
return sysroot_dir;
}
static bool
should_rewrite_sysroot(const pkgconf_client_t *client, pkgconf_list_t *vars, const char *buf, unsigned int flags)
{
const char *sysroot_dir;
if (flags & PKGCONF_PKG_PROPF_UNINSTALLED && !(client->flags & PKGCONF_PKG_PKGF_FDO_SYSROOT_RULES))
return false;
sysroot_dir = find_sysroot(client, vars);
if (sysroot_dir == NULL)
return false;
if (*buf != '/')
return false;
if (!strcmp(sysroot_dir, "/"))
return false;
if (strlen(buf) <= strlen(sysroot_dir))
return false;
if (strstr(buf + strlen(sysroot_dir), sysroot_dir) == NULL)
return false;
return true;
}
/*
* !doc
*
* .. c:function:: pkgconf_tuple_t *pkgconf_tuple_add(const pkgconf_client_t *client, pkgconf_list_t *list, const char *key, const char *value, bool parse)
*
* Optionally parse and then define a variable.
*
* :param pkgconf_client_t* client: The pkgconf client object to access.
* :param pkgconf_list_t* list: The variable list to add the new variable to.
* :param char* key: The name of the variable being added.
* :param char* value: The value of the variable being added.
* :param bool parse: Whether or not to parse the value for variable substitution.
* :return: a variable object
* :rtype: pkgconf_tuple_t *
*/
pkgconf_tuple_t *
pkgconf_tuple_add(const pkgconf_client_t *client, pkgconf_list_t *list, const char *key, const char *value, bool parse, unsigned int flags)
{
char *dequote_value;
pkgconf_tuple_t *tuple = calloc(1, sizeof(pkgconf_tuple_t));
pkgconf_tuple_find_delete(list, key);
dequote_value = dequote(value);
tuple->key = strdup(key);
if (parse)
tuple->value = pkgconf_tuple_parse(client, list, dequote_value, flags);
else
tuple->value = strdup(dequote_value);
PKGCONF_TRACE(client, "adding tuple to @%p: %s => %s (parsed? %d)", list, key, tuple->value, parse);
pkgconf_node_insert(&tuple->iter, tuple, list);
free(dequote_value);
return tuple;
}
/*
* !doc
*
* .. c:function:: char *pkgconf_tuple_find(const pkgconf_client_t *client, pkgconf_list_t *list, const char *key)
*
* Look up a variable in a variable list.
*
* :param pkgconf_client_t* client: The pkgconf client object to access.
* :param pkgconf_list_t* list: The variable list to search.
* :param char* key: The variable name to search for.
* :return: the value of the variable or ``NULL``
* :rtype: char *
*/
char *
pkgconf_tuple_find(const pkgconf_client_t *client, pkgconf_list_t *list, const char *key)
{
pkgconf_node_t *node;
pkgconf_tuple_t *global_tuple;
global_tuple = lookup_global_tuple(client, key);
if (global_tuple != NULL && global_tuple->flags & PKGCONF_PKG_TUPLEF_OVERRIDE)
return global_tuple->value;
PKGCONF_FOREACH_LIST_ENTRY(list->head, node)
{
pkgconf_tuple_t *tuple = node->data;
if (!strcmp(tuple->key, key))
return tuple->value;
}
if (global_tuple != NULL)
return global_tuple->value;
return NULL;
}
/*
* !doc
*
* .. c:function:: char *pkgconf_tuple_parse(const pkgconf_client_t *client, pkgconf_list_t *vars, const char *value, unsigned int flags)
*
* Parse an expression for variable substitution.
*
* :param pkgconf_client_t* client: The pkgconf client object to access.
* :param pkgconf_list_t* list: The variable list to search for variables (along side the global variable list).
* :param char* value: The ``key=value`` string to parse.
* :param uint flags: Any flags to consider while parsing.
* :return: the variable data with any variables substituted
* :rtype: char *
*/
char *
pkgconf_tuple_parse(const pkgconf_client_t *client, pkgconf_list_t *vars, const char *value, unsigned int flags)
{
char buf[PKGCONF_BUFSIZE];
const char *ptr;
char *bptr = buf;
if (!(client->flags & PKGCONF_PKG_PKGF_FDO_SYSROOT_RULES) &&
(!(flags & PKGCONF_PKG_PROPF_UNINSTALLED) || (client->flags & PKGCONF_PKG_PKGF_PKGCONF1_SYSROOT_RULES)))
{
if (*value == '/' && client->sysroot_dir != NULL && strncmp(value, client->sysroot_dir, strlen(client->sysroot_dir)))
bptr += pkgconf_strlcpy(buf, client->sysroot_dir, sizeof buf);
}
for (ptr = value; *ptr != '\0' && bptr - buf < PKGCONF_BUFSIZE; ptr++)
{
if (*ptr != '$' || (*ptr == '$' && *(ptr + 1) != '{'))
*bptr++ = *ptr;
else if (*(ptr + 1) == '{')
{
char varname[PKGCONF_ITEM_SIZE];
char *vend = varname + PKGCONF_ITEM_SIZE - 1;
char *vptr = varname;
const char *pptr;
char *kv, *parsekv;
*vptr = '\0';
for (pptr = ptr + 2; *pptr != '\0'; pptr++)
{
if (*pptr != '}')
{
if (vptr < vend)
*vptr++ = *pptr;
else
{
*vptr = '\0';
break;
}
}
else
{
*vptr = '\0';
break;
}
}
PKGCONF_TRACE(client, "lookup tuple %s", varname);
size_t remain = PKGCONF_BUFSIZE - (bptr - buf);
ptr += (pptr - ptr);
kv = pkgconf_tuple_find_global(client, varname);
if (kv != NULL)
{
size_t nlen = pkgconf_strlcpy(bptr, kv, remain);
if (nlen > remain)
{
pkgconf_warn(client, "warning: truncating very long variable to 64KB\n");
bptr = buf + (PKGCONF_BUFSIZE - 1);
break;
}
bptr += nlen;
}
else
{
kv = pkgconf_tuple_find(client, vars, varname);
if (kv != NULL)
{
size_t nlen;
parsekv = pkgconf_tuple_parse(client, vars, kv, flags);
nlen = pkgconf_strlcpy(bptr, parsekv, remain);
free(parsekv);
if (nlen > remain)
{
pkgconf_warn(client, "warning: truncating very long variable to 64KB\n");
bptr = buf + (PKGCONF_BUFSIZE - 1);
break;
}
bptr += nlen;
}
}
}
}
*bptr = '\0';
/*
* Sigh. Somebody actually attempted to use freedesktop.org pkg-config's broken sysroot support,
* which was written by somebody who did not understand how sysroots are supposed to work. This
* results in an incorrect path being built as the sysroot will be prepended twice, once explicitly,
* and once by variable expansion (the pkgconf approach). We could simply make ${pc_sysrootdir} blank,
* but sometimes it is necessary to know the explicit sysroot path for other reasons, so we can't really
* do that.
*
* As a result, we check to see if ${pc_sysrootdir} is prepended as a duplicate, and if so, remove the
* prepend. This allows us to handle both our approach and the broken freedesktop.org implementation's
* approach. Because a path can be shorter than ${pc_sysrootdir}, we do some checks first to ensure it's
* safe to skip ahead in the string to scan for our sysroot dir.
*
* Finally, we call pkgconf_path_relocate() to clean the path of spurious elements.
*
* New in 1.9: Only attempt to rewrite the sysroot if we are not processing an uninstalled package.
*/
if (should_rewrite_sysroot(client, vars, buf, flags))
{
char cleanpath[PKGCONF_ITEM_SIZE];
const char *sysroot_dir = find_sysroot(client, vars);
pkgconf_strlcpy(cleanpath, buf + strlen(sysroot_dir), sizeof cleanpath);
pkgconf_path_relocate(cleanpath, sizeof cleanpath);
return strdup(cleanpath);
}
return strdup(buf);
}
/*
* !doc
*
* .. c:function:: void pkgconf_tuple_free_entry(pkgconf_tuple_t *tuple, pkgconf_list_t *list)
*
* Deletes a variable object, removing it from any variable lists and releasing any memory associated
* with it.
*
* :param pkgconf_tuple_t* tuple: The variable object to release.
* :param pkgconf_list_t* list: The variable list the variable object is attached to.
* :return: nothing
*/
void
pkgconf_tuple_free_entry(pkgconf_tuple_t *tuple, pkgconf_list_t *list)
{
pkgconf_node_delete(&tuple->iter, list);
free(tuple->key);
free(tuple->value);
free(tuple);
}
/*
* !doc
*
* .. c:function:: void pkgconf_tuple_free(pkgconf_list_t *list)
*
* Deletes a variable list and any variables attached to it.
*
* :param pkgconf_list_t* list: The variable list to delete.
* :return: nothing
*/
void
pkgconf_tuple_free(pkgconf_list_t *list)
{
pkgconf_node_t *node, *next;
PKGCONF_FOREACH_LIST_ENTRY_SAFE(list->head, next, node)
pkgconf_tuple_free_entry(node->data, list);
pkgconf_list_zero(list);
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,53 @@
# ===========================================================================
# https://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT])
#
# DESCRIPTION
#
# Check whether the given FLAG works with the current language's compiler
# or gives an error. (Warnings, however, are ignored)
#
# ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on
# success/failure.
#
# If EXTRA-FLAGS is defined, it is added to the current language's default
# flags (e.g. CFLAGS) when the check is done. The check is thus made with
# the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to
# force the compiler to issue an error when a bad flag is given.
#
# INPUT gives an alternative input source to AC_COMPILE_IFELSE.
#
# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this
# macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG.
#
# LICENSE
#
# Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de>
# Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com>
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 6
AC_DEFUN([AX_CHECK_COMPILE_FLAG],
[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF
AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl
AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [
ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS
_AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1"
AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])],
[AS_VAR_SET(CACHEVAR,[yes])],
[AS_VAR_SET(CACHEVAR,[no])])
_AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags])
AS_VAR_IF(CACHEVAR,yes,
[m4_default([$2], :)],
[m4_default([$3], :)])
AS_VAR_POPDEF([CACHEVAR])dnl
])dnl AX_CHECK_COMPILE_FLAGS
+100
View File
@@ -0,0 +1,100 @@
.\" Copyright (c) 2025 pkgconf authors (see AUTHORS).
.\"
.\" Permission to use, copy, modify, and/or distribute this software for any
.\" purpose with or without fee is hereby granted, provided that the above
.\" copyright notice and this permission notice appear in all copies.
.\"
.\" This software is provided 'as is' and without any warranty, express or
.\" implied. In no event shall the authors be liable for any damages arising
.\" from the use of this software.
.Dd June 4, 2025
.Dt BOMTOOL 1
.Os
.Sh NAME
.Nm bomtool
.Nd a tool for generating SPDX-based software bills of material
.Sh SYNOPSIS
.Nm
.Op Ar options
.Ar module ...
.Sh DESCRIPTION
.Nm
is a program which generates a textual SPDX 2.0 software bill of
materials (SBOM) for a given set of pkg-config modules.
The output of this tool can then be translated into other SBOM
formats as necessary.
.Pp
The
.Ar options
are as follows:
.Bl -tag -width indent
.It Fl -about
Print the version number, the Copyright notice, and the license of the
.Nm
program to standard output and exit.
Most other options and all command line arguments are ignored.
.It Fl -version
Print the version number of the
.Nm
program to standard output and exit.
Most other options and all command line arguments are ignored.
.El
.Sh ENVIRONMENT
.Bl -tag -width indent
.It Ev PKG_CONFIG_DEBUG_SPEW
If set, print debugging messages to stderr.
.It Ev PKG_CONFIG_IGNORE_CONFLICTS
If set, ignore
.Ic Conflicts
rules in modules.
Has the same effect as the
.Fl -ignore-conflicts
option in
.Xr pkgconf 1
.
.It Ev PKG_CONFIG_LIBDIR
A colon-separated list of low-priority directories where
.Xr pc 5
files are looked up.
The module search path is constructed by appending this list to
.Ev PKG_CONFIG_PATH ,
which enjoys higher priority.
If
.Ev PKG_CONFIG_LIBDIR
is not defined, the default list compiled into the
.Nm
program from the
.Dv PKG_DEFAULT_PATH
preprocessor macro is appended instead.
If
.Ev PKG_CONFIG_LIBDIR
is defined but empty, nothing is appended.
.It Ev PKG_CONFIG_MAXIMUM_TRAVERSE_DEPTH
Impose a limit on the allowed depth in the dependency graph.
.It Ev PKG_CONFIG_PATH
A colon-separated list of high-priority directories where
.Xr pc 5
files are looked up.
.It Ev PKG_CONFIG_PRELOADED_FILES
Colon-separated list of
.Xr pc 5
files which are loaded before any other pkg-config files.
These packages are given highest priority over any other
.Xr pc 5
files that would otherwise provide a given package.
.El
.Sh EXIT STATUS
.Ex -std
.Sh EXAMPLES
Generating an SBOM for the package named foo:
.Dl $ bomtool foo
.Dl SPDXVersion: SPDX-2.2
.Dl DataLicense: CC0-1.0
.Dl SPDXID: SPDXRef-DOCUMENT
.Dl DocumentName: SBOM-SPDX-fooC641.2.3
.Dl DocumentNamespace: https://spdx.org/spdxdocs/bomtool-2.4.3
.Dl Creator: Tool: bomtool 2.4.3
.Dl [...]
.Sh SEE ALSO
.Xr pc 5 ,
.Xr pkgconf 1
+178
View File
@@ -0,0 +1,178 @@
.\" Copyright (c) 2017 pkgconf authors (see AUTHORS).
.\"
.\" Permission to use, copy, modify, and/or distribute this software for any
.\" purpose with or without fee is hereby granted, provided that the above
.\" copyright notice and this permission notice appear in all copies.
.\"
.\" This software is provided 'as is' and without any warranty, express or
.\" implied. In no event shall the authors be liable for any damages arising
.\" from the use of this software.
.Dd December 15, 2017
.Dt PC 5
.Os
.Sh NAME
.Nm file.pc
.Nd pkg-config file format
.Sh DESCRIPTION
pkg-config files provide a useful mechanism for storing various information
about libraries and packages on a given system.
Information stored by
.Nm .pc
files include compiler and linker flags necessary to use a given library, as
well as any other relevant metadata.
.Pp
These
.Nm .pc
files are processed by a utility called
.Nm pkg-config ,
of which
.Nm pkgconf
is an implementation.
.\"
.Ss FILE SYNTAX
The
.Nm .pc
file follows a format inspired by RFC822.
Comments are prefixed by a pound sign, hash sign or octothorpe (#), and variable
assignment is similar to POSIX shell.
Properties are defined using RFC822-style stanzas.
.\"
.Ss VARIABLES
.\"
Variable definitions start with an alphanumeric string, followed by an equal sign,
and then the value the variable should contain.
.Pp
Variable references are always written as "${variable}".
It is possible to escape literal "${" as "$${".
.\"
.Ss PROPERTIES
.\"
Properties are set using RFC822-style stanzas which consist of a keyword, followed
by a colon (:) and then the value the property should be set to.
Variable substitution is always performed regardless of property type.
.Pp
There are three types of property:
.\"
.Bl -tag -width indent
.\"
.It Literal
The property will be set to the text of the value.
.\"
.It Dependency List
The property will be set to a list of dependencies parsed from the
text.
Dependency lists are defined by this ABNF syntax:
.Bd -literal
package-list = *WSP *( package-spec *( package-sep ) )
package-sep = WSP / ","
.\"
package-spec = package-key [ ver-op package-version ]
ver-op = "<" / "<=" / "=" / "!=" / ">=" / ">"
.Ed
.\"
.It Fragment List
The property will be set to a list of fragments parsed from the text.
The input text must be in a format that is suitable for passing to a POSIX
shell without any shell expansions after variable substitution has been done.
.\"
.El
.Ss PROPERTY KEYWORDS
.Bl -tag -width indent
.\"
.It Name
The displayed name of the package.
(mandatory; literal)
.It Version
The version of the package.
(mandatory; literal)
.It Description
A description of the package.
(mandatory; literal)
.It URL
A URL to a webpage for the package.
This is used to recommend where newer versions of the package can be acquired.
(mandatory; literal)
.It Cflags
Required compiler flags.
These flags are always used, regardless of whether static compilation is requested.
(optional; fragment list)
.It Cflags.private
Required compiler flags for static compilation.
(optional; fragment list; pkgconf extension)
.It Copyright
A copyright attestation statement.
(optional; literal; pkgconf extension)
.It Libs
Required linking flags for this package.
Libraries this package depends on for linking against it, which are not
described as dependencies should be specified here.
(optional; fragment list)
.It Libs.private
Required linking flags for this package that are only required when linking
statically.
Libraries this package depends on for linking against it statically, which are
not described as dependencies should be specified here.
(optional; fragment list)
.It License
The asserted SPDX license tag that should be applied to the given package.
(optional; literal; pkgconf extension)
.It Maintainer
The preferred contact for the maintainer. This should be in the format of a
name followed by an e-mail address or website.
(optional; literal; pkgconf extension)
.It Requires
Required dependencies that must be met for the package to be usable.
All dependencies must be satisfied or the pkg-config implementation must not use
the package.
(optional; dependency list)
.It Requires.private
Required dependencies that must be met for the package to be usable for header
inclusion and static linking.
All dependencies must be satisfied or the pkg-config implementation must not use
the package for header inclusion and static linking.
(optional; dependency list)
.It Conflicts
Dependencies that must not be met for the package to be usable.
If any package in the proposed dependency solution match any dependency in the
Conflicts list, the package being considered is not usable.
(optional; dependency list)
.It Provides
Dependencies that may be provided by an alternate package.
If a package cannot be found, the entire package collection is scanned for
providers which can match the requested dependency.
(optional; dependency list; pkgconf extension)
.El
.Ss EXTENSIONS
Features that have been marked as a pkgconf extension are only guaranteed to work
with the pkgconf implementation of pkg-config.
Other implementations may or may not support the extensions.
.Pp
Accordingly, it is suggested that
.Nm .pc
files which absolutely depend on these extensions declare a requirement on the
pkgconf virtual.
.Sh EXAMPLES
An example .pc file:
.Bd -literal
# This is a comment
prefix=/home/kaniini/pkg # this defines a variable
exec_prefix=${prefix} # defining another variable with a substitution
libdir=${exec_prefix}/lib
includedir=${prefix}/include
Name: libfoo # human-readable name
Description: an example library called libfoo # human-readable description
Copyright: Copyright (c) 2022 pkgconf project authors
License: Apache-2.0
Maintainer: the pkgconf project <http://www.pkgconf.org>
Version: 1.0
URL: http://www.pkgconf.org
Requires: libbar > 2.0.0
Conflicts: libbaz <= 3.0.0
Libs: -L${libdir} -lfoo
Libs.private: -lm
Cflags: -I${includedir}/libfoo
.Ed
.Sh SEE ALSO
.Xr pkgconf 1 ,
.Xr pkg.m4 7
+143
View File
@@ -0,0 +1,143 @@
.\" Copyright (c) 2017 pkgconf authors (see AUTHORS).
.\"
.\" Permission to use, copy, modify, and/or distribute this software for any
.\" purpose with or without fee is hereby granted, provided that the above
.\" copyright notice and this permission notice appear in all copies.
.\"
.\" This software is provided 'as is' and without any warranty, express or
.\" implied. In no event shall the authors be liable for any damages arising
.\" from the use of this software.
.Dd December 5, 2017
.Dt PKG.M4 7
.Os
.Sh NAME
.Nm pkg.m4
.Nd autoconf macros for using pkgconf
.Sh SYNOPSIS
.Nm PKG_PREREQ
.Nm PKG_PROG_PKG_CONFIG
.Nm PKG_CHECK_MODULES
.Nm PKG_CHECK_MODULES_STATIC
.Nm PKG_INSTALLDIR
.Nm PKG_NOARCH_INSTALLDIR
.Nm PKG_CHECK_VAR
.Nm PKG_WITH_MODULES
.Nm PKG_HAVE_WITH_MODULES
.Nm PKG_HAVE_DEFINE_WITH_MODULES
.Sh DESCRIPTION
.Nm
is a collection of autoconf macros which help to configure compiler and linker
flags for development libraries.
This allows build systems to detect other dependencies and use them with the
system toolchain.
.Sh "AUTOCONF MACROS"
.Ss "PKG_PREREQ(MIN-VERSION)"
Checks that the version of the
.Nm
autoconf macros in use is at least MIN-VERSION.
This can be used to ensure a particular
.Nm
macro will be available.
.Ss "PKG_PROG_PKG_CONFIG([MIN-VERSION])"
Checks for an implementation of
.Nm pkg-config
which is at least MIN-VERSION or newer.
.Ss "PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES [,ACTION-IF-FOUND [,ACTION-IF-NOT-FOUND]])"
.Ss "PKG_CHECK_MODULES_STATIC(VARIABLE-PREFIX, MODULES [,ACTION-IF-FOUND [,ACTION-IF-NOT-FOUND]])"
Checks whether a given module set exists, and if so, defines
.Nm CFLAGS
and
.Nm LIBS
variables prefixed by
.Nm VARIABLE-PREFIX
with the output from
.Fl -cflags
and
.Fl -libs
respectively.
.Pp
The optional
.Nm ACTION-IF-FOUND
and
.Nm ACTION-IF-NOT-FOUND
arguments are shell fragments that should be executed if the module set is
found or not found.
.Pp
If
.Nm $PKG_CONFIG
is not defined, the
.Nm PKG_PROG_PKG_CONFIG
macro will be executed to locate a
.Nm pkg-config
implementation.
.Pp
The
.Nm PKG_CHECK_MODULES_STATIC
macro provides the same behaviour as
.Nm PKG_CHECK_MODULES
with static linking enabled via the
.Fl -static
flag.
.Ss "PKG_INSTALLDIR(DIRECTORY)"
Defines the variable $pkgconfigdir as the location where a package
should install pkg-config .pc files.
.Pp
By default the directory is $libdir/pkgconfig, but the default can
be changed by passing the
.Nm DIRECTORY
parameter.
.Pp
This value can be overridden with the
.Fl -with-pkgconfigdir
configure parameter.
.Ss "PKG_NOARCH_INSTALLDIR(DIRECTORY)"
Defines the variable $noarch_pkgconfigdir as the location where a package
should install pkg-config .pc files.
.Pp
By default the directory is $datadir/pkgconfig, but the default can
be changed by passing the
.Nm DIRECTORY
parameter.
.Pp
This value can be overridden with the
.Fl -with-noarch-pkgconfigdir
configure parameter.
.Ss "PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])"
Retrieves the value of the
.Nm pkg-config
variable
.Nm CONFIG-VARIABLE
from
.Nm MODULE
and stores it in the
.Nm VARIABLE
variable.
.Pp
Note that repeated usage of
.Nm VARIABLE
is not recommended as the check will be skipped if the variable is
already set.
.Ss "PKG_WITH_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND], [DESCRIPTION], [DEFAULT])"
Prepares a "--with-" configure option using the lowercase
.Nm VARIABLE-PREFIX
name, merging the behaviour of
.Nm AC_ARG_WITH
and
.Nm PKG_CHECK_MODULES
in a single macro.
.Ss "PKG_HAVE_WITH_MODULES(VARIABLE-PREFIX, MODULES, [DESCRIPTION], [DEFAULT])"
Convenience macro to trigger
.Nm AM_CONDITIONAL
after a
.Nm PKG_WITH_MODULES check.\&
.Nm VARIABLE-PREFIX
is exported as a make variable.
.Ss "PKG_HAVE_DEFINE_WITH_MODULES(VARIABLE-PREFIX, MODULES, [DESCRIPTION], [DEFAULT])"
Convenience macro to trigger
.Nm AM_CONDITIONAL
and
.Nm AC_DEFINE
after a
.Nm PKG_WITH_MODULES check.\&
.Nm VARIABLE-PREFIX
is exported as a make variable.
+100
View File
@@ -0,0 +1,100 @@
.\" Copyright (c) 2018 pkgconf authors (see AUTHORS).
.\"
.\" Permission to use, copy, modify, and/or distribute this software for any
.\" purpose with or without fee is hereby granted, provided that the above
.\" copyright notice and this permission notice appear in all copies.
.\"
.\" This software is provided 'as is' and without any warranty, express or
.\" implied. In no event shall the authors be liable for any damages arising
.\" from the use of this software.
.Dd July 19, 2018
.Dt PKGCONF-PERSONALITY 5
.Os
.Sh NAME
.Nm file.personality
.Nd pkgconf cross-compile personality file format
.Sh DESCRIPTION
pkgconf cross-compile personality files provide a useful mechanism for storing
various information about system toolchains.
Information stored by
.Nm .personality
files include information about paths used by a cross-compile toolchain, such as
the sysroot directory and default include and library paths. pkgconf uses this
information to determine what information is necessary to use libraries.
.\"
.Ss FILE SYNTAX
The
.Nm .personality
file follows a format inspired by RFC822.
Comments are prefixed by a pound sign, hash sign or octothorpe (#), and variable
assignment is similar to POSIX shell.
Properties are defined using RFC822-style stanzas.
.\"
.Ss PROPERTIES
.\"
Properties are set using RFC822-style stanzas which consist of a keyword, followed
by a colon (:) and then the value the property should be set to.
Variable substitution is always performed regardless of property type.
.Pp
There are three types of property:
.\"
.Bl -tag -width indent
.\"
.It Literal
The property will be set to the text of the value.
.\"
.It Fragment List
The property will be set to a list of fragments parsed from the text.
The input text must be in a format that is suitable for passing to a POSIX
shell without any shell expansions after variable substitution has been done.
Elements are delimited with a colon.
.\"
.It Boolean
The property will be set to true if the value is one of: true, yes or 1.
Otherwise it will be set to false.
.\"
.El
.Ss PROPERTY KEYWORDS
.Bl -tag -width indent
.\"
.It Triplet
The triplet used by the cross-compile toolchain.
(mandatory; literal)
.It SysrootDir
The directory used by the system root of the cross-compile toolchain.
(mandatory; literal)
.It DefaultSearchPaths
A list of directories to look for
.Xr pc 5
files in.
(mandatory; fragment list)
.It SystemIncludePaths
A list of directories that are included by default in the search path for
include files.
(mandatory; fragment list)
.It SystemLibraryPaths
A list of directories that are included by default in the search path for
libraries.
(mandatory; fragment list)
.It WantDefaultPure
If true, pkgconf will default to preferring a pure dependency graph.
(optional; boolean; default is false)
.It WantDefaultStatic
If true, pkgconf will default to operating in static linking mode.
(optional; boolean; default is false)
.\"
.El
.Sh EXAMPLES
An example .personality file:
.Bd -literal
# This is a comment
Triplet: x86_64-pc-linux-gnu
SysrootDir: /home/kaniini/sysroot/x86_64-pc-linux-gnu
DefaultSearchPaths: /home/kaniini/sysroot/x86_64-pc-linux-gnu/lib/pkgconfig:/home/kaniini/sysroot/x86_64-pc-linux-gnu/share/pkgconfig
SystemIncludePaths: /home/kaniini/sysroot/x86_64-pc-linux-gnu/include
SystemLibraryPaths: /home/kaniini/sysroot/x86_64-pc-linux-gnu/lib
.Ed
.Sh SEE ALSO
.Xr pkgconf 1 ,
.Xr pc 5 ,
.Xr pkg.m4 7
+758
View File
@@ -0,0 +1,758 @@
.\" Copyright (c) 2011, 2012, 2013, 2014, 2015, 2016 pkgconf authors (see AUTHORS).
.\"
.\" Permission to use, copy, modify, and/or distribute this software for any
.\" purpose with or without fee is hereby granted, provided that the above
.\" copyright notice and this permission notice appear in all copies.
.\"
.\" This software is provided 'as is' and without any warranty, express or
.\" implied. In no event shall the authors be liable for any damages arising
.\" from the use of this software.
.Dd November 15, 2016
.Dt PKGCONF 1
.Os
.Sh NAME
.Nm pkgconf
.Nd a system for configuring build dependency information
.Sh SYNOPSIS
.Nm
.Op Ar options
.Ar module ...
.Sh DESCRIPTION
The
.Nm
program retrieves configuration information related to the
.Ar module
arguments from
.Xr pc 5
files installed on the system and prints parts of the retrieved
information depending on the specified
.Ar options .
The most common use is printing the compiler and linker flags needed
to build software that uses the libraries given by the
.Ar module
arguments.
.Pp
The
.Xr pc 5
files are searched for along a path constructed from the
.Fl -with-path
option, the
.Ev PKG_CONFIG_PATH
and
.Ev PKG_CONFIG_LIBDIR
environment variables, and some compiled-in default directories.
The
.Ar module
arguments correspond to the file names, but without the
.Pa .pc
filename extension.
.Pp
Several of the
.Ar options
cause immediate exit.
If multiple of these options are given, only the option with the
highest priority takes effect and those with lower priority are
silently ignored.
These options are, ordered by descending priority:
.Bl -enum
.It
No-module options:
.Fl -relocate ,
.Fl -dump-personality ,
.Fl -about ,
.Fl -version ,
.Fl -help ,
.Fl -atleast-pkgconfig-version ,
.Fl -list-all ,
and
.Fl -list-package-names :
These options cause all arguments to be ignored.
.It
Argument-only options:
.Fl -atleast-version ,
.Fl -exact-version ,
and
.Fl -max-version :
These options only inspect modules explicitly specified on the
command line and do not look at dependencies.
.It
Limited-output options:
.Fl -validate ,
.Fl -license ,
.Fl -uninstalled ,
and
.Fl -env :
These options perform dependency resolution, but exit after printing
the information requested by the highest-priority option,
ignoring other output options that may have been specified.
.El
.Pp
Several other options require at least one
.Ar module
argument, produce output, do not cause early exit, can be combined
with each other, but override and disable all
.Fl -cflags
and
.Fl -libs
options:
.Bl -enum
.It
Single-module output options:
.Fl -path ,
.Fl -print-variables ,
.Fl -variable :
If any of these options is specified, only the first
.Ar module
argument is used, all other arguments are silently ignored,
and no dependency resolution is attempted.
.It
Depth-one output options:
.Fl -print-provides ,
.Fl -modversion ,
.Fl -print-requires ,
and
.Fl -print-requires-private :
If any of these options is specified, only modules
explicitly specified on the command line are inspected
and no dependency resolution is attempted.
.It
General output options:
.Fl -simulate ,
.Fl -digraph ,
.Fl -solution ,
.Fl -fragment-tree :
These options do not limit dependency resolution.
.El
.Pp
The most important output options
.Fl -cflags
and
.Fl -libs
can be combined with each other, but are overridden and ignored if
any of the options listed above are specified.
.Pp
The complete list of
.Ar options
is as follows:
.Bl -tag -width indent
.It Fl -about
Print the version number, the Copyright notice, and the license of the
.Nm
program to standard output and exit.
Most other options and all command line arguments are ignored.
.It Fl -atleast-pkgconfig-version Ns = Ns Ar version
Exit with error if the requested
.Ar version
number is greater than the version number of the
.Nm
program, or with success otherwise.
Most other options and all command line arguments are ignored.
.It Fl -atleast-version Ns = Ns Ar version
Check the
.Ar module
arguments in the given order.
Exit with error as soon as a
.Ar module
does not exist, and exit with success as soon as the version number of a
.Ar module
is greater than or equal to the requested
.Ar version
number.
Exit with error if the version number of each
.Ar module
is less than the requested
.Ar version
number.
.It Fl -cflags , Fl -cflags-only-I , Fl -cflags-only-other
Print all compiler flags required to compile against the
.Ar module ,
or only the include path
.Pq Fl I
flags, or only the compiler flags that are not include path flags,
respectively.
These options imply
.Fl -print-errors .
.It Fl -debug
Print some non-fatal warning messages to standard error output
that would otherwise silently be ignored.
This option also implies
.Fl -print-errors .
If
.Nm
was compiled without defining the preprocessor macro
.Dv PKGCONF_LITE ,
this option also prints many debugging messages to standard error output.
.It Fl -define-prefix
Attempts to determine the prefix variable to use for CFLAGS and LIBS entry relocations.
This is mainly useful for platforms where framework SDKs are relocatable, such as Windows.
.It Fl -define-variable Ns = Ns Ar varname Ns = Ns Ar value
Define
.Ar varname
as
.Ar value .
Variables are used in query output, and some modules' results may change based
on the presence of a variable definition.
.It Fl -digraph
Dump the dependency resolver's solution as a graphviz
.Sq dot
file.
This can be used with graphviz to visualize module interdependencies.
This option is only available if the preprocessor macro
.Dv PKGCONF_LITE
was not defined during compilation.
.It Fl -dont-define-prefix
Disables the
.Sq define-prefix
feature.
.It Fl -dont-relocate-paths
Disables the path relocation feature.
.It Fl -dump-personality
Print some default settings to standard output, in particular
the default module search path that is used when
.Ev PKG_CONFIG_LIBDIR
is not defined, the default list of include paths that are filtered out when
.Ev PKG_CONFIG_SYSTEM_INCLUDE_PATH
is not defined,
and the default list of library paths that are filtered out when
.Ev PKG_CONFIG_SYSTEM_LIBRARY_PATH
is not defined, and exit.
Most other options and all command line arguments are ignored.
This option is only available if the preprocessor macro
.Dv PKGCONF_LITE
was not defined during compilation.
.It Fl -env Ns = Ns Ar varname
Print the requested values as variable declarations in a similar format as the
.Xr env 1
command.
.It Fl -env-only
Initialize the module search path from
.Fl -with-path
and
.Ev PKG_CONFIG_PATH
only, ignoring
.Ev PKG_CONFIG_LIBDIR
and the compiled-in default directories.
.It Fl -errors-to-stdout
Print all error, warning, and debugging messages to standard output
instead of to standard error output.
.It Fl -exact-version Ns = Ns Ar version
Check the
.Ar module
arguments in the given order.
Exit with error as soon as a
.Ar module
does not exist, and exit with success as soon as the version number of a
.Ar module
is exactly the requested
.Ar version
number.
Exit with error if the version number of each
.Ar module
differs from the requested
.Ar version
number.
.It Fl -exists
Exit with a non-zero exit status
if the dependency resolver is unable to find all of the requested
.Ar module Ns s .
This option is active by default and cannot be disabled.
However, various other options cause
.Nm
to exit and report success or failure before all arguments have been inspected.
.It Fl -fragment-filter Ns = Ns Ar types
Filter the fragment lists for the specified
.Ar types .
.It Fl -help
Print a usage summary on standard output and exit.
Most other options and all command line arguments are ignored.
.It Fl -ignore-conflicts
Ignore
.Sq Conflicts
rules in modules.
.It Fl -keep-system-cflags , Fl -keep-system-libs
Keep CFLAGS or linker flag fragments that would be filtered due to being
included by default in the compiler.
.It Fl -libs , Fl -libs-only-L , Fl -libs-only-l , Fl -libs-only-other
Print all linker flags required to link against the
.Ar module ,
or only the library path
.Pq Fl L
flags, or only the library
.Pq Fl l
flags, or only the linker flags that are neither library path
nor library flags, respectively.
These options imply
.Fl -print-errors .
.It Fl -list-all
Walk the module search path in the order of descending priority.
For each
.Xr pc 5
file found, print one line to standard output,
containing the basename of the file without the extension, the
.Ic Name
property, a dash
.Pq Sq \- ,
and the
.Ic Description
property.
This option implies
.Fl -print-errors .
All command line arguments are ignored.
.It Fl -list-package-names
Perform the same search as
.Fl -list-all ,
but only print the basename of each
.Xr pc 5
file without the extension, not the module name and the description.
This option implies
.Fl -print-errors .
All command line arguments are ignored.
.It Fl -log-file Ns = Ns Ar file
Set the name of the output
.Ar file
where information about selected modules is logged,
both about those selected by arguments and as dependencies.
For each selected module, one line is printed,
containing the basename of the
.Xr pc 5
file without the extension, optionally an operator and version number
describing the desired range of versions, and either the actual version
number in square brackets or the string
.Qq NOT-FOUND .
If this option is not provided, the name of the output file
is instead taken from the
.Ev PKG_CONFIG_LOG
environment variable, and if that is not provided either,
this kind of logging is disabled.
.It Fl -max-version Ns = Ns Ar version
Check the
.Ar module
arguments in the given order.
Exit with error as soon as a
.Ar module
does not exist, and exit with success as soon as the version number of a
.Ar module
is less than or equal to the requested
.Ar version
number.
Exit with error if the version number of each
.Ar module
is greater than the requested
.Ar version
number.
.It Fl -maximum-traverse-depth Ns = Ns Ar depth
Impose a limit on the allowed depth in the dependency graph.
For example, a
.Ar depth
of 2 restricts the resolver from acting on child
dependencies of modules added to the resolver's solution.
This option is overridden by the
.Ev PKG_CONFIG_MAXIMUM_TRAVERSE_DEPTH
environment variable and by the options
.Fl -modversion ,
.Fl -path ,
.Fl -print-provides ,
.Fl -print-requires ,
.Fl -print-requires-private ,
.Fl -print-variables ,
and
.Fl -variable .
.It Fl -modversion
For each specified
.Ar module ,
print the version number to standard output.
If the
.Fl -verbose
option is also specified, the name of the respective
.Ar module
and a colon is printed before each version number.
This option implies
.Fl -print-errors
and
.Fl -maximum-traverse-depth Ns =1
and overrides and disables all
.Fl -cflags
and
.Fl -libs
flags.
.It Fl -msvc-syntax
Use MSVC syntax for
.Fl -cflags ,
.Fl -env ,
and
.Fl -libs
output.
This option is only available if the preprocessor macro
.Dv PKGCONF_LITE
was not defined during compilation.
.It Fl -no-cache
Skip caching packages when they are loaded into the internal resolver.
This may result in an alternate dependency graph being computed.
.It Fl -no-provides
Ignore
.Sq Provides
rules in modules when resolving dependencies.
.It Fl -no-uninstalled
Forbids the dependency resolver from considering 'uninstalled' modules as part
of a solution.
.It Fl -path
For the first
.Ar module
given on the command line, let the dependency resolver find the
.Xr pc 5
file describing that module, print the absolute pathname of that file
to standard output, and exit immediately,
ignoring most other options and all other arguments.
.It Fl -prefix-variable Ns = Ns Ar variable
Sets the
.Sq prefix
variable used by the
.Sq define-prefix
feature.
.It Fl -print-errors
Print some messages about fatal errors to standard error output
that would otherwise be omitted.
This option is implied by many other options, but not by all.
It can be overridden with
.Fl -silence-errors .
.It Fl -print-provides
For each specified
.Ar module ,
print one line to standard output containing the
.Ic Name
property, an equal sign
.Pq Sq = ,
and the
.Ic Version
property.
If the
.Ar module
contains one or more
.Ic Provides
properties, print additional lines in dependency list format, one name
per line, each name optionally followed by an operator and a version.
This option implies
.Fl -maximum-traverse-depth Ns =1
and overrides and disables all
.Fl -cflags
and
.Fl -libs
flags.
.It Fl -print-requires , Fl -print-requires-private
For each specified
.Ar module ,
print the
.Ic Requires
or
.Ic Requires.private
properties, respectively, in dependency list format to standard output.
Both of these options imply
.Fl -maximum-traverse-depth Ns =1
and override and disable all
.Fl -cflags
and
.Fl -libs
flags.
.It Fl -print-variables
For the first
.Ar module
given on the command line, print the names of all seen variables
to standard output, one per line.
Any subsequent arguments are silently ignored.
This option implies
.Fl -print-errors
and
.Fl -maximum-traverse-depth Ns =1
and overrides and disables all
.Fl -cflags
and
.Fl -libs
flags.
.It Fl -pure
Treats the computed dependency graph as if it were pure.
This is mainly intended for use with the
.Fl -static
flag and has no effect if
.Fl -shared
is also specified.
.It Fl -relocate Ns = Ns Ar path
Relocates a path using the pkgconf_path_relocate API.
This is mainly used by the testsuite to provide a guaranteed interface
to the system's path relocation backend.
.It Fl -shared
Compute a simple dependency graph that is only suitable for shared linking.
This option overrides
.Fl -static .
.It Fl -short-errors
When printing error messages about modules that are not found
or conflict with each other, avoid printing additional, verbose
instructions explaining potential methods for solving the problem.
.It Fl -silence-errors
Do not print any error, warning, or debugging messages at all.
Overrides all of
.Fl -debug ,
.Fl -errors-to-stdout ,
and
.Fl -print-errors .
This option is overridden and disabled if the
.Ev PKG_CONFIG_DEBUG_SPEW
environment variable is set.
.It Fl -simulate
Simulates resolving a dependency graph based on the requested modules on the
command line.
Dumps a series of trees denoting pkgconf's resolver state.
This option is only available if the preprocessor macro
.Dv PKGCONF_LITE
was not defined during compilation.
.It Fl -solution
Print the names of the modules requested with
.Ar module
arguments and their dependencies to standard output.
This option is only available if the preprocessor macro
.Dv PKGCONF_LITE
was not defined during compilation.
.It Fl -static
Compute a deeper dependency graph and use compiler/linker flags intended for
static linking.
This option is overridden by
.Fl -shared .
.It Fl -uninstalled
Exit with a non-zero result if the dependency resolver uses an
.Sq uninstalled
module as part of its solution.
.It Fl -validate Ar package ...
Validate specific
.Sq .pc
files for correctness.
This option implies
.Fl -print-errors
and
.Fl -errors-to-stdout .
.It Fl -variable Ns = Ns Ar varname
For the first
.Ar module
given on the command line, print the value of the variable with the name
.Ar varname
to standard output.
Any subsequent arguments are silently ignored.
This option implies
.Fl -maximum-traverse-depth Ns =1
and overrides and disables all
.Fl -cflags
and
.Fl -libs
flags.
.It Fl -verbose
This option only has an effect if
.Fl -modversion
is also specified.
It prints the name of the respective
.Ar module
and a colon before each version number.
.It Fl -version
Print the version number of the
.Nm
program to standard output and exit.
Most other options and all command line arguments are ignored.
.It Fl -with-path Ns = Ns Ar path
Prepend the directory
.Ar path
to the module search path,
giving it priority over all other directories including those from
.Ev PKG_CONFIG_PATH
and
.Ev PKG_CONFIG_LIBDIR .
.El
.Sh ENVIRONMENT
.Bl -tag -width indent
.It Ev CPATH
First supplementary colon-separated list of include paths filtered out
in the same way as
.Ev PKG_CONFIG_SYSTEM_INCLUDE_PATH .
.It Ev CPLUS_INCLUDE_PATH
Third supplementary colon-separated list of include paths filtered out
in the same way as
.Ev PKG_CONFIG_SYSTEM_INCLUDE_PATH .
.It Ev C_INCLUDE_PATH
Second supplementary colon-separated list of include paths filtered out
in the same way as
.Ev PKG_CONFIG_SYSTEM_INCLUDE_PATH .
.It Ev DESTDIR
If set to the same value as
.Ev PKG_CONFIG_SYSROOT_DIR ,
behave in the same way as if
.Ev PKG_CONFIG_FDO_SYSROOT_RULES
is set.
If
.Ev PKG_CONFIG_SYSROOT_DIR
is not set or set to a different value,
.Ev DESTDIR
is ignored.
.It Ev LIBRARY_PATH
Supplementary colon-separated list of library paths filtered out
in the same way as
.Ev PKG_CONFIG_SYSTEM_LIBRARY_PATH .
.It Ev OBJC_INCLUDE_PATH
Fourth supplementary colon-separated list of include paths filtered out
in the same way as
.Ev PKG_CONFIG_SYSTEM_INCLUDE_PATH .
.It Ev PKG_CONFIG_ALLOW_SYSTEM_CFLAGS
If set, this variable has the same effect as the
.Fl -keep-system-cflags
option.
.It Ev PKG_CONFIG_ALLOW_SYSTEM_LIBS
If set, this variable has the same effect as the
.Fl -keep-system-libs
option.
.It Ev PKG_CONFIG_DEBUG_SPEW
If set, override and disable the
.Fl -silence-errors
option.
.It Ev PKG_CONFIG_DISABLE_UNINSTALLED
If set, enables the same behaviour as the
.Fl -no-uninstalled
flag.
.It Ev PKG_CONFIG_DONT_DEFINE_PREFIX
If set, this variable has the same effect as the
.Fl -dont-define-prefix
option.
.It Ev PKG_CONFIG_DONT_RELOCATE_PATHS
If set, disables the path relocation feature.
.It Ev PKG_CONFIG_FDO_SYSROOT_RULES
If set, follow the sysroot prefixing rules that freedesktop.org pkg-config uses.
.It Ev PKG_CONFIG_IGNORE_CONFLICTS
If set, ignore
.Ic Conflicts
rules in modules.
Has the same effect as the
.Fl -ignore-conflicts
option.
.It Ev PKG_CONFIG_LIBDIR
A colon-separated list of low-priority directories where
.Xr pc 5
files are looked up.
The module search path is constructed by appending this list to
.Ev PKG_CONFIG_PATH ,
which enjoys higher priority.
If
.Ev PKG_CONFIG_LIBDIR
is not defined, the default list compiled into the
.Nm
program from the
.Dv PKG_DEFAULT_PATH
preprocessor macro is appended instead.
If
.Ev PKG_CONFIG_LIBDIR
is defined but empty, nothing is appended.
.It Ev PKG_CONFIG_LOG
If set, log information about selected modules
to the file with the name stored in this variable.
For more details, see the
.Fl -log-file
command line option, which overrides this variable.
.It Ev PKG_CONFIG_MAXIMUM_TRAVERSE_DEPTH
Impose a limit on the allowed depth in the dependency graph.
This variable overrides the
.Fl -maximum-traverse-depth
option, but is overridden by the other options mentioned there.
.It Ev PKG_CONFIG_MSVC_SYNTAX
If set, use MSVC syntax for
.Fl -cflags ,
.Fl -env ,
and
.Fl -libs
output.
This variable has the same effect as the
.Fl -msvc-syntax
option.
If the preprocessor macro
.Dv PKGCONF_LITE
was defined during compilation, this variable is ignored.
.It Ev PKG_CONFIG_PATH
A colon-separated list of high-priority directories where
.Xr pc 5
files are looked up.
The module search path is constructed
by prepending the directory specified with
.Fl -with-path ,
if any, and unless
.Fl -env-only
is specified, by appending either
.Ev PKG_CONFIG_LIBDIR
or the compiled-in default directories with lower priority.
.It Ev PKG_CONFIG_PRELOADED_FILES
Colon-separated list of
.Xr pc 5
files which are loaded before any other pkg-config files.
These packages are given highest priority over any other
.Xr pc 5
files that would otherwise provide a given package.
.It Ev PKG_CONFIG_PURE_DEPGRAPH
If set, enables the same behaviour as the
.Fl -pure
flag.
.It Ev PKG_CONFIG_RELOCATE_PATHS
If set, this variable has the same effect as the
.Fl -define-prefix
option.
.It Ev PKG_CONFIG_SYSROOT_DIR
If set, this variable defines a
.Sq sysroot
directory, which will be prepended to every path variable
beginning with the prefix variable in a given
.Xr pc 5
file.
Useful for cross compilation.
The value of this environment variable is also copied into the global variable
.Va pc_sysrootdir .
.It Ev PKG_CONFIG_SYSTEM_INCLUDE_PATH
Colon-separated list of include paths that are filtered out
and not printed by the
.Fl -cflags
and
.Fl -cflags-only-I
options because they are considered system include paths.
If not defined, the default list compiled into the
.Nm
program from the
.Dv SYSTEM_INCLUDEDIR
preprocessor macro is used instead.
This variable is a pkgconf-specific extension.
Any directories listed in the environment variables
.Ev CPATH ,
.Ev C_INCLUDE_PATH ,
.Ev CPLUS_INCLUDE_PATH ,
and
.Ev OBJC_INCLUDE_PATH
are also filtered out.
.It Ev PKG_CONFIG_SYSTEM_LIBRARY_PATH
Colon-separated list of library paths that are filtered out
and not printed by the
.Fl -libs
and
.Fl -libs-only-L
options because they are considered system library paths.
If not defined, the default list compiled into the
.Nm
program from the
.Dv SYSTEM_LIBDIR
preprocessor macro is used instead.
This variable is a pkgconf-specific extension.
.It Ev PKG_CONFIG_TOP_BUILD_DIR
The value of the
.Va pc_top_builddir
global variable.
If this environment variable is not defined, the string
.Qq $(top_builddir)
is used as the value of
.Va pc_top_builddir .
.El
.Sh EXIT STATUS
.Ex -std
.Sh EXAMPLES
Displaying the CFLAGS of a package:
.Dl $ pkgconf --cflags foo
.Dl -fPIC -I/usr/include/foo
.Sh SEE ALSO
.Xr pc 5 ,
.Xr pkg.m4 7
+199
View File
@@ -0,0 +1,199 @@
project('pkgconf', 'c',
version : '2.5.1',
license : 'ISC',
default_options : ['c_std=c99'],
meson_version: '>=0.52',
)
cc = meson.get_compiler('c')
add_project_arguments(
'-D_BSD_SOURCE',
'-D_DEFAULT_SOURCE',
'-D_POSIX_C_SOURCE=200809L',
cc.get_supported_arguments(
'-Wimplicit-function-declaration',
'-Wmisleading-indentation',
),
language : 'c',
)
cdata = configuration_data()
check_functions = [
['strlcat', 'string.h'],
['strlcpy', 'string.h'],
['strndup', 'string.h'],
['strdup', 'string.h'],
['strncasecmp', 'strings.h'],
['strcasecmp', 'strings.h'],
['reallocarray', 'stdlib.h'],
['pledge', 'unistd.h'],
['unveil', 'unistd.h'],
]
foreach f : check_functions
name = f[0].to_upper().underscorify()
if cc.has_function(f[0], prefix : '#define _BSD_SOURCE\n#define _DEFAULT_SOURCE\n#define _POSIX_C_SOURCE 200809L\n#include <@0@>'.format(f[1])) and cc.has_header_symbol(f[1], f[0], prefix : '#define _BSD_SOURCE\n#define _DEFAULT_SOURCE\n#define _POSIX_C_SOURCE 200809L')
cdata.set('HAVE_@0@'.format(name), 1)
cdata.set('HAVE_DECL_@0@'.format(name), 1)
else
cdata.set('HAVE_DECL_@0@'.format(name), 0)
endif
endforeach
default_path = []
foreach f : ['libdir', 'datadir']
default_path += [join_paths(get_option('prefix'), get_option(f), 'pkgconfig')]
endforeach
personality_path = []
foreach f : ['libdir', 'datadir']
personality_path += [join_paths(get_option('prefix'), get_option(f), 'pkgconfig', 'personality.d')]
endforeach
SYSTEM_LIBDIR = get_option('with-system-libdir')
if SYSTEM_LIBDIR != ''
cdata.set_quoted('SYSTEM_LIBDIR', SYSTEM_LIBDIR)
else
cdata.set_quoted('SYSTEM_LIBDIR', join_paths(get_option('prefix'), get_option('libdir')))
endif
SYSTEM_INCLUDEDIR = get_option('with-system-includedir')
if SYSTEM_INCLUDEDIR != ''
cdata.set_quoted('SYSTEM_INCLUDEDIR', SYSTEM_INCLUDEDIR)
else
cdata.set_quoted('SYSTEM_INCLUDEDIR', join_paths(get_option('prefix'), get_option('includedir')))
endif
cdata.set_quoted('PKG_DEFAULT_PATH', ':'.join(default_path))
cdata.set_quoted('PERSONALITY_PATH', ':'.join(personality_path))
cdata.set_quoted('PACKAGE_NAME', meson.project_name())
cdata.set_quoted('PACKAGE_VERSION', meson.project_version())
cdata.set_quoted('PACKAGE_BUGREPORT', 'https://todo.sr.ht/~kaniini/pkgconf')
cdata.set('abs_top_srcdir', meson.current_source_dir())
cdata.set('abs_top_builddir', meson.current_build_dir())
subdir('libpkgconf')
libtype = get_option('default_library')
if libtype == 'static'
build_static = '-DPKGCONFIG_IS_STATIC'
else
build_static = '-DPKGCONFIG_IS_NOT_STATIC'
endif
libpkgconf = library('pkgconf',
'libpkgconf/argvsplit.c',
'libpkgconf/audit.c',
'libpkgconf/buffer.c',
'libpkgconf/bsdstubs.c',
'libpkgconf/cache.c',
'libpkgconf/client.c',
'libpkgconf/dependency.c',
'libpkgconf/fileio.c',
'libpkgconf/fragment.c',
'libpkgconf/parser.c',
'libpkgconf/path.c',
'libpkgconf/personality.c',
'libpkgconf/pkg.c',
'libpkgconf/queue.c',
'libpkgconf/tuple.c',
c_args: ['-DLIBPKGCONF_EXPORT', build_static],
install : true,
version : '7.0.0',
soversion : '7',
)
# For other projects using libpkgconfig as a subproject
dep_libpkgconf = declare_dependency(
link_with : libpkgconf,
include_directories : include_directories('.'),
)
# If we have a new enough meson override the dependency so that only
# `dependency('libpkgconf')` is required from the consumer
if meson.version().version_compare('>= 0.54.0')
meson.override_dependency('libpkgconf', dep_libpkgconf)
endif
pkg = import('pkgconfig')
pkg.generate(libpkgconf,
name : 'libpkgconf',
description : 'a library for accessing and manipulating development framework configuration',
url: 'http://github.com/pkgconf/pkgconf',
filebase : 'libpkgconf',
subdirs: ['pkgconf'],
extra_cflags : build_static
)
cli_include = include_directories('cli')
pkgconf_exe = executable('pkgconf',
'cli/main.c',
'cli/getopt_long.c',
'cli/renderer-msvc.c',
link_with : libpkgconf,
c_args : build_static,
include_directories : cli_include,
install : true)
bomtool_exe = executable('bomtool',
'cli/bomtool/main.c',
'cli/getopt_long.c',
link_with : libpkgconf,
c_args : build_static,
include_directories : cli_include,
install : true)
with_tests = get_option('tests')
kyua_exe = find_program('kyua', required : with_tests, disabler : true, native : true)
atf_sh_exe = find_program('atf-sh', required : with_tests, disabler : true, native : true)
kyuafile = configure_file(input : 'Kyuafile.in', output : 'Kyuafile', configuration : cdata)
test('kyua', kyua_exe, args : ['--config=none', 'test', '--kyuafile', kyuafile, '--build-root', meson.current_build_dir()])
subdir('tests')
install_man('man/bomtool.1')
install_man('man/pkgconf.1')
install_man('man/pkg.m4.7')
install_man('man/pc.5')
install_man('man/pkgconf-personality.5')
install_data('pkg.m4', install_dir: 'share/aclocal')
install_data('AUTHORS', install_dir: 'share/doc/pkgconf')
install_data('README.md', install_dir: 'share/doc/pkgconf')
if host_machine.system() == 'windows'
conf_data = configuration_data()
conf_data.set('VERSION', meson.project_version())
conf_data.set('EXE', pkgconf_exe.full_path())
conf_data.set('DLL', libpkgconf.full_path())
if host_machine.cpu() != 'x86_64'
wixl_arch = 'x86'
else
wixl_arch = 'x64'
endif
conf_data.set('WIXL_ARCH', wixl_arch)
python = find_program('python3')
wixl = find_program('wixl', required: false, version: '>= 0.105')
msi_filename = 'pkgconf-@0@-@1@.msi'.format(wixl_arch, meson.project_version())
wxsfile = configure_file(input: 'pkgconf.wxs.in', output: 'pkgconf.wxs', configuration: conf_data)
if wixl.found()
licensefile = custom_target(
'License.rtf',
input: 'COPYING',
output: 'License.rtf',
command: [python, files('txt2rtf.py'), '@INPUT@', '@OUTPUT@'],
)
msi = custom_target(
msi_filename,
input: [wxsfile, licensefile, pkgconf_exe],
output: msi_filename,
command: [wixl, '--arch', wixl_arch, '--ext', 'ui', '-o', msi_filename, wxsfile],
)
alias_target('msi', msi)
endif
endif
+19
View File
@@ -0,0 +1,19 @@
option(
'tests',
type: 'feature',
description: 'Build tests which depends upon the kyua framework',
)
option(
'with-system-libdir',
type: 'string',
value: '',
description: 'Specify the system library directory (default {prefix}/{libdir})'
)
option(
'with-system-includedir',
type: 'string',
value: '',
description: 'Specify the system include directory (default {prefix}/{includedir})'
)
+350
View File
@@ -0,0 +1,350 @@
# pkg.m4 - Macros to locate and use pkg-config. -*- Autoconf -*-
# serial 13 (pkgconf)
dnl Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
dnl Copyright © 2012-2015 Dan Nicholson <dbn.lists@gmail.com>
dnl
dnl This program is free software; you can redistribute it and/or modify
dnl it under the terms of the GNU General Public License as published by
dnl the Free Software Foundation; either version 2 of the License, or
dnl (at your option) any later version.
dnl
dnl This program is distributed in the hope that it will be useful, but
dnl WITHOUT ANY WARRANTY; without even the implied warranty of
dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
dnl General Public License for more details.
dnl
dnl You should have received a copy of the GNU General Public License
dnl along with this program; if not, see <https://www.gnu.org/licenses/>.
dnl
dnl As a special exception to the GNU General Public License, if you
dnl distribute this file as part of a program that contains a
dnl configuration script generated by Autoconf, you may include it under
dnl the same distribution terms that you use for the rest of that
dnl program.
dnl PKG_PREREQ(MIN-VERSION)
dnl -----------------------
dnl Since: 0.29
dnl
dnl Verify that the version of the pkg-config macros are at least
dnl MIN-VERSION. Unlike PKG_PROG_PKG_CONFIG, which checks the user's
dnl installed version of pkg-config, this checks the developer's version
dnl of pkg.m4 when generating configure.
dnl
dnl To ensure that this macro is defined, also add:
dnl m4_ifndef([PKG_PREREQ],
dnl [m4_fatal([must install pkg-config 0.29 or later before running autoconf/autogen])])
dnl
dnl See the "Since" comment for each macro you use to see what version
dnl of the macros you require.
m4_defun([PKG_PREREQ],
[m4_define([PKG_MACROS_VERSION], [0.29.2])
m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1,
[m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])])
])dnl PKG_PREREQ
dnl PKG_PROG_PKG_CONFIG([MIN-VERSION], [ACTION-IF-NOT-FOUND])
dnl ---------------------------------------------------------
dnl Since: 0.16
dnl
dnl Search for the pkg-config tool and set the PKG_CONFIG variable to
dnl first found in the path. Checks that the version of pkg-config found
dnl is at least MIN-VERSION. If MIN-VERSION is not specified, 0.9.0 is
dnl used since that's the first version where most current features of
dnl pkg-config existed.
dnl
dnl If pkg-config is not found or older than specified, it will result
dnl in an empty PKG_CONFIG variable. To avoid widespread issues with
dnl scripts not checking it, ACTION-IF-NOT-FOUND defaults to aborting.
dnl You can specify [PKG_CONFIG=false] as an action instead, which would
dnl result in pkg-config tests failing, but no bogus error messages.
AC_DEFUN([PKG_PROG_PKG_CONFIG],
[m4_pattern_forbid([^_?PKG_[A-Z_]+$])
m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$])
m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$])
AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility])
AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path])
AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path])
if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
AC_PATH_TOOL([PKG_CONFIG], [pkg-config])
fi
if test -n "$PKG_CONFIG"; then
_pkg_min_version=m4_default([$1], [0.9.0])
AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version])
if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
AC_MSG_RESULT([yes])
else
AC_MSG_RESULT([no])
PKG_CONFIG=""
fi
fi
if test -z "$PKG_CONFIG"; then
m4_default([$2], [AC_MSG_ERROR([pkg-config not found])])
fi[]dnl
])dnl PKG_PROG_PKG_CONFIG
dnl PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
dnl -------------------------------------------------------------------
dnl Since: 0.18
dnl
dnl Check to see whether a particular set of modules exists. Similar to
dnl PKG_CHECK_MODULES(), but does not set variables or print errors.
dnl
dnl Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG])
dnl only at the first occurrence in configure.ac, so if the first place
dnl it's called might be skipped (such as if it is within an "if", you
dnl have to call PKG_CHECK_EXISTS manually
AC_DEFUN([PKG_CHECK_EXISTS],
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
if test -n "$PKG_CONFIG" && \
AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then
m4_default([$2], [:])
m4_ifvaln([$3], [else
$3])dnl
fi])
dnl _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
dnl ---------------------------------------------
dnl Internal wrapper calling pkg-config via PKG_CONFIG and setting
dnl pkg_failed based on the result.
m4_define([_PKG_CONFIG],
[if test -n "$$1"; then
pkg_cv_[]$1="$$1"
elif test -n "$PKG_CONFIG"; then
PKG_CHECK_EXISTS([$3],
[pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes ],
[pkg_failed=yes])
else
pkg_failed=untried
fi[]dnl
])dnl _PKG_CONFIG
dnl _PKG_SHORT_ERRORS_SUPPORTED
dnl ---------------------------
dnl Internal check to see if pkg-config supports short errors.
AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED],
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])
if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
_pkg_short_errors_supported=yes
else
_pkg_short_errors_supported=no
fi[]dnl
])dnl _PKG_SHORT_ERRORS_SUPPORTED
dnl PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
dnl [ACTION-IF-NOT-FOUND])
dnl --------------------------------------------------------------
dnl Since: 0.4.0
dnl
dnl Note that if there is a possibility the first call to
dnl PKG_CHECK_MODULES might not happen, you should be sure to include an
dnl explicit call to PKG_PROG_PKG_CONFIG in your configure.ac
AC_DEFUN([PKG_CHECK_MODULES],
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl
AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl
pkg_failed=no
AC_MSG_CHECKING([for $2])
_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2])
_PKG_CONFIG([$1][_LIBS], [libs], [$2])
m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS
and $1[]_LIBS to avoid the need to call pkg-config.
See the pkg-config man page for more details.])
if test $pkg_failed = yes; then
AC_MSG_RESULT([no])
_PKG_SHORT_ERRORS_SUPPORTED
if test $_pkg_short_errors_supported = yes; then
$1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1`
else
$1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1`
fi
# Put the nasty error message in config.log where it belongs
echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD
m4_default([$4], [AC_MSG_ERROR(
[Package requirements ($2) were not met:
$$1_PKG_ERRORS
Consider adjusting the PKG_CONFIG_PATH environment variable if you
installed software in a non-standard prefix.
_PKG_TEXT])[]dnl
])
elif test $pkg_failed = untried; then
AC_MSG_RESULT([no])
m4_default([$4], [AC_MSG_FAILURE(
[The pkg-config script could not be found or is too old. Make sure it
is in your PATH or set the PKG_CONFIG environment variable to the full
path to pkg-config.
_PKG_TEXT
To get pkg-config, see <http://pkg-config.freedesktop.org/>.])[]dnl
])
else
$1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS
$1[]_LIBS=$pkg_cv_[]$1[]_LIBS
AC_MSG_RESULT([yes])
$3
fi[]dnl
])dnl PKG_CHECK_MODULES
dnl PKG_CHECK_MODULES_STATIC(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
dnl [ACTION-IF-NOT-FOUND])
dnl ---------------------------------------------------------------------
dnl Since: 0.29
dnl
dnl Checks for existence of MODULES and gathers its build flags with
dnl static libraries enabled. Sets VARIABLE-PREFIX_CFLAGS from --cflags
dnl and VARIABLE-PREFIX_LIBS from --libs.
dnl
dnl Note that if there is a possibility the first call to
dnl PKG_CHECK_MODULES_STATIC might not happen, you should be sure to
dnl include an explicit call to PKG_PROG_PKG_CONFIG in your
dnl configure.ac.
AC_DEFUN([PKG_CHECK_MODULES_STATIC],
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
_save_PKG_CONFIG=$PKG_CONFIG
PKG_CONFIG="$PKG_CONFIG --static"
PKG_CHECK_MODULES($@)
PKG_CONFIG=$_save_PKG_CONFIG[]dnl
])dnl PKG_CHECK_MODULES_STATIC
dnl PKG_INSTALLDIR([DIRECTORY])
dnl -------------------------
dnl Since: 0.27
dnl
dnl Substitutes the variable pkgconfigdir as the location where a module
dnl should install pkg-config .pc files. By default the directory is
dnl $libdir/pkgconfig, but the default can be changed by passing
dnl DIRECTORY. The user can override through the --with-pkgconfigdir
dnl parameter.
AC_DEFUN([PKG_INSTALLDIR],
[m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])])
m4_pushdef([pkg_description],
[pkg-config installation directory @<:@]pkg_default[@:>@])
AC_ARG_WITH([pkgconfigdir],
[AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],,
[with_pkgconfigdir=]pkg_default)
AC_SUBST([pkgconfigdir], [$with_pkgconfigdir])
m4_popdef([pkg_default])
m4_popdef([pkg_description])
])dnl PKG_INSTALLDIR
dnl PKG_NOARCH_INSTALLDIR([DIRECTORY])
dnl --------------------------------
dnl Since: 0.27
dnl
dnl Substitutes the variable noarch_pkgconfigdir as the location where a
dnl module should install arch-independent pkg-config .pc files. By
dnl default the directory is $datadir/pkgconfig, but the default can be
dnl changed by passing DIRECTORY. The user can override through the
dnl --with-noarch-pkgconfigdir parameter.
AC_DEFUN([PKG_NOARCH_INSTALLDIR],
[m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])])
m4_pushdef([pkg_description],
[pkg-config arch-independent installation directory @<:@]pkg_default[@:>@])
AC_ARG_WITH([noarch-pkgconfigdir],
[AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],,
[with_noarch_pkgconfigdir=]pkg_default)
AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir])
m4_popdef([pkg_default])
m4_popdef([pkg_description])
])dnl PKG_NOARCH_INSTALLDIR
dnl PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE,
dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
dnl -------------------------------------------
dnl Since: 0.28
dnl
dnl Retrieves the value of the pkg-config variable for the given module.
AC_DEFUN([PKG_CHECK_VAR],
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl
_PKG_CONFIG([$1], [variable="][$3]["], [$2])
AS_VAR_COPY([$1], [pkg_cv_][$1])
AS_VAR_IF([$1], [""], [$5], [$4])dnl
])dnl PKG_CHECK_VAR
dnl PKG_WITH_MODULES(VARIABLE-PREFIX, MODULES,
dnl [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND],
dnl [DESCRIPTION], [DEFAULT])
dnl ------------------------------------------
dnl
dnl Prepare a "--with-" configure option using the lowercase
dnl [VARIABLE-PREFIX] name, merging the behaviour of AC_ARG_WITH and
dnl PKG_CHECK_MODULES in a single macro.
AC_DEFUN([PKG_WITH_MODULES],
[
m4_pushdef([with_arg], m4_tolower([$1]))
m4_pushdef([description],
[m4_default([$5], [build with ]with_arg[ support])])
m4_pushdef([def_arg], [m4_default([$6], [auto])])
m4_pushdef([def_action_if_found], [AS_TR_SH([with_]with_arg)=yes])
m4_pushdef([def_action_if_not_found], [AS_TR_SH([with_]with_arg)=no])
m4_case(def_arg,
[yes],[m4_pushdef([with_without], [--without-]with_arg)],
[m4_pushdef([with_without],[--with-]with_arg)])
AC_ARG_WITH(with_arg,
AS_HELP_STRING(with_without, description[ @<:@default=]def_arg[@:>@]),,
[AS_TR_SH([with_]with_arg)=def_arg])
AS_CASE([$AS_TR_SH([with_]with_arg)],
[yes],[PKG_CHECK_MODULES([$1],[$2],$3,$4)],
[auto],[PKG_CHECK_MODULES([$1],[$2],
[m4_n([def_action_if_found]) $3],
[m4_n([def_action_if_not_found]) $4])])
m4_popdef([with_arg])
m4_popdef([description])
m4_popdef([def_arg])
])dnl PKG_WITH_MODULES
dnl PKG_HAVE_WITH_MODULES(VARIABLE-PREFIX, MODULES,
dnl [DESCRIPTION], [DEFAULT])
dnl -----------------------------------------------
dnl
dnl Convenience macro to trigger AM_CONDITIONAL after PKG_WITH_MODULES
dnl check._[VARIABLE-PREFIX] is exported as make variable.
AC_DEFUN([PKG_HAVE_WITH_MODULES],
[
PKG_WITH_MODULES([$1],[$2],,,[$3],[$4])
AM_CONDITIONAL([HAVE_][$1],
[test "$AS_TR_SH([with_]m4_tolower([$1]))" = "yes"])
])dnl PKG_HAVE_WITH_MODULES
dnl PKG_HAVE_DEFINE_WITH_MODULES(VARIABLE-PREFIX, MODULES,
dnl [DESCRIPTION], [DEFAULT])
dnl ------------------------------------------------------
dnl
dnl Convenience macro to run AM_CONDITIONAL and AC_DEFINE after
dnl PKG_WITH_MODULES check. HAVE_[VARIABLE-PREFIX] is exported as make
dnl and preprocessor variable.
AC_DEFUN([PKG_HAVE_DEFINE_WITH_MODULES],
[
PKG_HAVE_WITH_MODULES([$1],[$2],[$3],[$4])
AS_IF([test "$AS_TR_SH([with_]m4_tolower([$1]))" = "yes"],
[AC_DEFINE([HAVE_][$1], 1, [Enable ]m4_tolower([$1])[ support])])
])dnl PKG_HAVE_DEFINE_WITH_MODULES
+64
View File
@@ -0,0 +1,64 @@
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<?define Arch = "@WIXL_ARCH@"?>
<?if $(var.Arch) = "x64"?>
<?define GLIB_ARCH = "win64"?>
<?define ArchString = "64-bit"?>
<?define ArchProgramFilesFolder = "ProgramFiles64Folder"?>
<?define Win64 = "yes"?>
<?else?>
<?define GLIB_ARCH = "win32"?>
<?define ArchString = "32-bit"?>
<?define ArchProgramFilesFolder = "ProgramFilesFolder"?>
<?define Win64 = "no"?>
<?endif?>
<Product Id="*"
Name="pkgconf @VERSION@ ($(var.ArchString))"
Language="1033"
Version="@VERSION@"
Manufacturer="pkgconf"
UpgradeCode="4faedad2-3f9d-45cc-89a7-3732ad2db0f7">
<Package InstallerVersion="200"
Compressed="yes"
InstallScope="perMachine" />
<MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
<MediaTemplate EmbedCab="yes" />
<Feature Id="ProductFeature" Title="pkgconf" Level="1">
<ComponentGroupRef Id="ProductComponents" />
</Feature>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="$(var.ArchProgramFilesFolder)">
<Directory Id="INSTALLFOLDER" Name="pkgconf @VERSION@" />
</Directory>
</Directory>
<ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
<Component Id="PkgconfExe" Guid="*" Win64="$(var.Win64)">
<File Id="PkgconfExeFile"
Source="@EXE@"
KeyPath="yes" />
<File Id="PkgconfigExeFile"
Name="pkg-config.exe"
Source="@EXE@"/>
<File Id="PkgconfDllFile"
Source="@DLL@"/>
<Environment Id="PATH"
Name="PATH"
Value="[INSTALLFOLDER]"
Permanent="no"
Part="last"
Action="set"
System="yes" />
</Component>
</ComponentGroup>
<UIRef Id="WixUI_Minimal" />
</Product>
</Wix>
+14
View File
@@ -0,0 +1,14 @@
syntax(2)
test_suite('pkgconf')
atf_test_program{name='basic'}
atf_test_program{name='requires'}
atf_test_program{name='regress'}
atf_test_program{name='parser'}
atf_test_program{name='sysroot'}
atf_test_program{name='conflicts'}
atf_test_program{name='version'}
atf_test_program{name='framework'}
atf_test_program{name='provides'}
atf_test_program{name='symlink'}
+391
View File
@@ -0,0 +1,391 @@
#!/usr/bin/env atf-sh
. $(atf_get_srcdir)/test_env.sh
tests_init \
noargs \
libs \
libs_cflags \
libs_cflags_version \
libs_cflags_version_multiple \
libs_cflags_version_alt \
libs_cflags_version_different \
libs_cflags_version_different_bad \
libs_env \
exists_nonexitent \
nonexitent \
exists_version \
exists_version_bad \
exists_version_bad2 \
exists_version_bad3 \
exists \
exists2 \
exists3 \
exists_version_alt \
exists_cflags \
exists_cflags_env \
uninstalled_bad \
uninstalled \
libs_intermediary \
libs_circular1 \
libs_circular2 \
libs_circular_directpc \
libs_static \
libs_static_ordering \
libs_metapackage \
license_isc \
license_noassertion \
modversion_noflatten \
pkg_config_path \
nolibs \
nocflags \
arbitary_path \
with_path \
relocatable \
single_depth_selectors \
print_variables_env \
variable_env \
variable_no_recurse
noargs_body()
{
export PKG_CONFIG_PATH="${selfdir}/lib1"
atf_check -s exit:1 -e ignore pkgconf
}
libs_body()
{
export PKG_CONFIG_PATH="${selfdir}/lib1"
atf_check \
-o inline:"-L/test/lib -lfoo\n" \
pkgconf --libs foo
}
libs_cflags_body()
{
export PKG_CONFIG_PATH="${selfdir}/lib1"
atf_check \
-o inline:"-fPIC -I/test/include/foo -L/test/lib -lfoo\n" \
pkgconf --cflags --libs foo
}
atf_test_case basic_libs_cflags_version
libs_cflags_version_body()
{
export PKG_CONFIG_PATH="${selfdir}/lib1"
atf_check \
-o inline:"-fPIC -I/test/include/foo -L/test/lib -lfoo\n" \
pkgconf --cflags --libs 'foo > 1.2'
}
libs_cflags_version_multiple_body()
{
export PKG_CONFIG_PATH="${selfdir}/lib1"
atf_check \
-o inline:"-fPIC -I/test/include/foo -L/test/lib -lbar -lfoo\n" \
pkgconf --cflags --libs 'foo > 1.2 bar >= 1.3'
}
libs_cflags_version_multiple_coma_body()
{
export PKG_CONFIG_PATH="${selfdir}/lib1"
atf_check \
-o inline:"-fPIC -I/test/include/foo -L/test/lib -lbar -lfoo\n" \
pkgconf --cflags --libs 'foo > 1.2,bar >= 1.3'
}
libs_cflags_version_alt_body()
{
export PKG_CONFIG_PATH="${selfdir}/lib1"
atf_check \
-o inline:"-fPIC -I/test/include/foo -L/test/lib -lfoo\n" \
pkgconf --cflags --libs 'foo' '>' '1.2'
}
libs_cflags_version_different_body()
{
export PKG_CONFIG_PATH="${selfdir}/lib1"
atf_check \
-o inline:"-fPIC -I/test/include/foo -L/test/lib -lfoo\n" \
pkgconf --cflags --libs 'foo' '!=' '1.3.0'
}
atf_test_case basic_libs_cflags_version_different_bad
libs_cflags_version_different_bad_body()
{
export PKG_CONFIG_PATH="${selfdir}/lib1"
atf_check \
-s exit:1 \
-e inline:"Package dependency requirement 'foo != 1.2.3' could not be satisfied.\nPackage 'foo' has version '1.2.3', required version is '!= 1.2.3'\n" \
pkgconf --cflags --libs 'foo' '!=' '1.2.3'
}
exists_nonexitent_body()
{
export PKG_CONFIG_PATH="${selfdir}/lib1"
atf_check \
-s exit:1 \
pkgconf --exists nonexistant
}
nonexitent_body()
{
export PKG_CONFIG_PATH="${selfdir}/lib1"
atf_check \
-s exit:1 \
pkgconf nonexistant
}
exists_version_body()
{
export PKG_CONFIG_PATH="${selfdir}/lib1"
atf_check \
pkgconf --exists 'foo > 1.2'
}
exists_version_bad_body()
{
export PKG_CONFIG_PATH="${selfdir}/lib1"
atf_check \
-s exit:1 \
pkgconf --exists 'foo > 1.2.3'
}
exists_version_alt_body()
{
export PKG_CONFIG_PATH="${selfdir}/lib1"
atf_check \
pkgconf --exists 'foo' '>' '1.2'
}
uninstalled_bad_body()
{
export PKG_CONFIG_PATH="${selfdir}/lib1"
atf_check \
-s exit:1 \
pkgconf --uninstalled 'foo'
}
uninstalled_body()
{
export PKG_CONFIG_PATH="${selfdir}/lib1"
atf_check \
pkgconf --uninstalled 'omg'
}
exists_version_bad2_body()
{
export PKG_CONFIG_PATH="${selfdir}/lib1"
atf_check \
-s exit:1 \
pkgconf --exists 'foo >= '
}
exists_version_bad3_body()
{
export PKG_CONFIG_PATH="${selfdir}/lib1"
atf_check \
-s exit:1 \
pkgconf --exists 'tilde >= 1.0.0'
}
exists_body()
{
export PKG_CONFIG_PATH="${selfdir}/lib1"
atf_check \
pkgconf --exists 'tilde = 1.0.0~rc1'
}
exists2_body()
{
export PKG_CONFIG_PATH="${selfdir}/lib1"
atf_check \
pkgconf --exists 'tilde <= 1.0.0'
}
exists3_body()
{
export PKG_CONFIG_PATH="${selfdir}/lib1"
atf_check \
pkgconf --exists '' 'foo'
}
libs_intermediary_body()
{
export PKG_CONFIG_PATH="${selfdir}/lib1"
atf_check \
-o inline:"-lintermediary-1 -lintermediary-2 -lfoo -lbar -lbaz\n" \
pkgconf --libs intermediary-1 intermediary-2
}
libs_circular2_body()
{
export PKG_CONFIG_PATH="${selfdir}/lib1"
atf_check \
-o inline:"circular-1: breaking circular reference (circular-1 -> circular-2 -> circular-1)\n" \
pkgconf circular-2 --validate
}
libs_circular1_body()
{
export PKG_CONFIG_PATH="${selfdir}/lib1"
atf_check \
-o inline:"circular-3: breaking circular reference (circular-3 -> circular-1 -> circular-3)\n" \
pkgconf circular-1 --validate
}
libs_circular_directpc_body()
{
atf_check \
-o inline:"-lcircular-3 -lcircular-1 -lcircular-2\n" \
pkgconf --libs ${selfdir}/lib1/circular-3.pc
}
libs_static_body()
{
export PKG_CONFIG_PATH="${selfdir}/lib1"
atf_check \
-o inline:"/libfoo.a -pthread\n" \
pkgconf --libs static-archive-libs
}
libs_static_ordering_body()
{
export PKG_CONFIG_PATH="${selfdir}/lib1"
atf_check \
-o inline:"-L/test/lib -lbar -lfoo\n" \
pkgconf --libs foo bar
}
libs_metapackage_body()
{
export PKG_CONFIG_PATH="${selfdir}/lib1"
atf_check \
-o inline:"-L/test/lib -lbar -lfoo\n" \
pkgconf --static --libs metapackage-3
}
pkg_config_path_body()
{
export PKG_CONFIG_PATH="${selfdir}/lib1${PATH_SEP}${selfdir}/lib2"
atf_check \
-o inline:"-L/test/lib -lfoo\n" \
pkgconf --libs foo
atf_check \
-o inline:"-L/test/lib -lbar -lfoo\n" \
pkgconf --libs bar
}
with_path_body()
{
atf_check \
-o inline:"-L/test/lib -lfoo\n" \
pkgconf --with-path=${selfdir}/lib1 --with-path=${selfdir}/lib2 --libs foo
atf_check \
-o inline:"-L/test/lib -lbar -lfoo\n" \
pkgconf --with-path=${selfdir}/lib1 --with-path=${selfdir}/lib2 --libs bar
}
nolibs_body()
{
export PKG_CONFIG_PATH="${selfdir}/lib1"
atf_check \
-o inline:"\n" \
pkgconf --libs nolib
}
nocflags_body()
{
export PKG_CONFIG_PATH="${selfdir}/lib1"
atf_check \
-o inline:"\n" \
pkgconf --cflags nocflag
}
arbitary_path_body()
{
cp ${selfdir}/lib1/foo.pc .
atf_check \
-o inline:"-L/test/lib -lfoo\n" \
pkgconf --libs foo.pc
}
relocatable_body()
{
basedir=$(pkgconf --relocate ${selfdir})
atf_check \
-o inline:"${basedir}/lib-relocatable\n" \
pkgconf --define-prefix --variable=prefix ${basedir}/lib-relocatable/lib/pkgconfig/foo.pc
}
single_depth_selectors_body()
{
export PKG_CONFIG_MAXIMUM_TRAVERSE_DEPTH=1
atf_check \
-o inline:"foo\n" \
pkgconf --with-path=${selfdir}/lib3 --print-requires bar
}
license_isc_body()
{
atf_check \
-o inline:"foo: ISC\n" \
pkgconf --with-path=${selfdir}/lib1 --license foo
}
license_noassertion_body()
{
atf_check \
-o inline:"bar: NOASSERTION\nfoo: ISC\n" \
pkgconf --with-path=${selfdir}/lib1 --license bar
}
modversion_noflatten_body()
{
atf_check \
-o inline:"1.3\n" \
pkgconf --with-path=${selfdir}/lib1 --modversion bar
}
exists_cflags_body()
{
atf_check \
-o inline:"-DHAVE_FOO\n" \
pkgconf --with-path=${selfdir}/lib1 --cflags --exists-cflags --fragment-filter=D foo
}
exists_cflags_env_body()
{
atf_check \
-o inline:"FOO_CFLAGS='-DHAVE_FOO'\n" \
pkgconf --with-path=${selfdir}/lib1 --cflags --exists-cflags --fragment-filter=D --env=FOO foo
}
libs_env_body()
{
atf_check \
-o inline:"FOO_LIBS='-L/test/lib -lfoo'\n" \
pkgconf --with-path=${selfdir}/lib1 --libs --env=FOO foo
}
print_variables_env_body()
{
atf_check \
-o inline:"FOO_CFLAGS='-fPIC -I/test/include/foo'\nFOO_LIBS='-L/test/lib -lfoo'\nFOO_INCLUDEDIR='/test/include'\nFOO_LIBDIR='/test/lib'\nFOO_EXEC_PREFIX='/test'\nFOO_PREFIX='/test'\nFOO_PCFILEDIR='${selfdir}/lib1'\n" \
pkgconf --with-path=${selfdir}/lib1 --env=FOO --print-variables --cflags --libs foo
}
variable_env_body()
{
atf_check \
-o inline:"FOO_INCLUDEDIR='/test/include'\n" \
pkgconf --with-path=${selfdir}/lib1 --env=FOO --variable=includedir foo
}
variable_no_recurse_body()
{
atf_check \
-o inline:"/test/include\n" \
pkgconf --with-path=${selfdir}/lib1 --variable=includedir bar
}
+68
View File
@@ -0,0 +1,68 @@
#!/usr/bin/env atf-sh
. $(atf_get_srcdir)/test_env.sh
tests_init \
modversion \
variable \
define_variable \
global_variable
modversion_body()
{
export PKG_CONFIG_PATH="${selfdir}/lib1"
atf_check \
-o inline:"1.0.1 \n" \
pkgconf --modversion pkg-config
}
variable_body()
{
export PKG_CONFIG_PATH="${selfdir}/lib1"
atf_check \
-o inline:"/test \n" \
pkgconf --variable=prefix foo
}
define_variable_body()
{
export PKG_CONFIG_PATH="${selfdir}/lib1"
atf_check \
-o inline:"/test2 \n" \
pkgconf --define-variable=prefix=/test2 --variable=prefix foo
}
global_variable_body()
{
export PKG_CONFIG_PATH="${selfdir}/lib1"
atf_check \
-o inline:"${selfdir}/lib1 \n"
pkgconf --exists -foo
}
argv_parse_3_body()
{
export PKG_CONFIG_PATH="${selfdir}/lib1"
atf_check \
-o inline:"-llib-1 -pthread /test/lib/lib2.so \n" \
pkgconf --libs argv-parse-3
}
tilde_quoting_body()
{
export PKG_CONFIG_PATH="${selfdir}/lib1"
atf_check \
-o inline:"-L~ -ltilde \n" \
pkgconf --libs tilde-quoting
atf_check \
-o inline:"-I~ \n" \
pkgconf --cflags tilde-quoting
}
paren_quoting_body()
{
export PKG_CONFIG_PATH="${selfdir}/lib1"
atf_check \
-o inline:"-L\$(libdir) -ltilde \n" \
pkgconf --libs paren-quoting
}
+23
View File
@@ -0,0 +1,23 @@
#!/usr/bin/env atf-sh
. $(atf_get_srcdir)/test_env.sh
tests_init \
libs \
ignore
libs_body()
{
export PKG_CONFIG_PATH="${selfdir}/lib1"
atf_check \
-o inline:"-L/test/lib -lconflicts\n" \
pkgconf --libs conflicts
}
ignore_body()
{
export PKG_CONFIG_PATH="${selfdir}/lib1"
atf_check \
-o inline:"-L/test/lib -lconflicts\n" \
pkgconf --ignore-conflicts --libs conflicts
}
+20
View File
@@ -0,0 +1,20 @@
#!/usr/bin/env atf-sh
. $(atf_get_srcdir)/test_env.sh
tests_init \
libs
libs_body()
{
export PKG_CONFIG_PATH="${selfdir}/lib1"
atf_check \
-o inline:"-F/test/lib -framework framework-1\n" \
pkgconf --libs framework-1
atf_check \
-o inline:"-F/test/lib -framework framework-2 -framework framework-1\n" \
pkgconf --libs framework-2
atf_check \
-o inline:"-F/test/lib -framework framework-2 -framework framework-1\n" \
pkgconf --libs framework-1 framework-2
}
@@ -0,0 +1,11 @@
prefix=/test
exec_prefix=${prefix}
libdir=${prefix}/lib
includedir=${prefix}/include
Name: foo
Description: A testing pkg-config file
Version: 1.2.3
Libs: -L${libdir} -lfoo
Cflags: -fPIC -I${includedir}/foo
Cflags.private: -DFOO_STATIC
@@ -0,0 +1,10 @@
prefix=/test
exec_prefix=${prefix}
libdir=${prefix}/lib
includedir=${prefix}/include
Name: argv-parse-2
Description: A testing pkg-config file
Version: 1.2.3
Libs: -llib-1 -pthread ${libdir}/lib2.so
Cflags:
@@ -0,0 +1,11 @@
prefix=/test
exec_prefix=${prefix}
libdir=${prefix}/lib
includedir=${prefix}/include
Name: argv-parse-3
Description: A testing pkg-config file
Version: 1.2.3
Libs: -llib-1 \
-pthread ${libdir}/lib2.so
Cflags:
+10
View File
@@ -0,0 +1,10 @@
prefix=/test
exec_prefix=${prefix}
libdir=${prefix}/lib
includedir=${prefix}/include
Name: argv-parse
Description: A testing pkg-config file
Version: 1.2.3
Libs: -llib-3 -llib-1 -llib-2 -lpthread
Cflags:
+10
View File
@@ -0,0 +1,10 @@
prefix=/test
exec_prefix=${prefix}
libdir=${prefix}/lib
includedir=${prefix}/include
Name: bar
Description: Another pkg-config test
Version: 1.3
Libs: -L${libdir} -lbar
Requires: foo
+11
View File
@@ -0,0 +1,11 @@
prefix=/test
exec_prefix=${prefix}
libdir=${prefix}/lib
includedir=${prefix}/include
Name: bar
Description: Another pkg-config test (with private Requires, ha!)
Version: 1.3
Libs: -L${libdir} -lbaz
Libs.private: -L${libdir} -lzee
Requires.private: foo
@@ -0,0 +1,13 @@
v9=lol
v8=${v9}${v9}${v9}${v9}${v9}${v9}${v9}${v9}${v9}${v9}
v7=${v8}${v8}${v8}${v8}${v8}${v8}${v8}${v8}${v8}${v8}
v6=${v7}${v7}${v7}${v7}${v7}${v7}${v7}${v7}${v7}${v7}
v5=${v6}${v6}${v6}${v6}${v6}${v6}${v6}${v6}${v6}${v6}
v4=${v5}${v5}${v5}${v5}${v5}${v5}${v5}${v5}${v5}${v5}
v3=${v4}${v4}${v4}${v4}${v4}${v4}${v4}${v4}${v4}${v4}
v2=${v3}${v3}${v3}${v3}${v3}${v3}${v3}${v3}${v3}${v3}
v1=${v2}${v2}${v2}${v2}${v2}${v2}${v2}${v2}${v2}${v2}
v0=${v1}${v1}${v1}${v1}${v1}${v1}${v1}${v1}${v1}${v1}
Name: One Billion Laughs
Version: ${v0}
Description: Don't install this!
+17
View File
@@ -0,0 +1,17 @@
/*
This is a C-style comment, which technically isn't allowed, but
some pkg-config files use them.
*/
prefix=/test
exec_prefix=${prefix}
libdir=${prefix}/lib
includedir=${prefix}/include
Name: c-comment
Description: A testing pkg-config file
Version: 1.2.3
Libs: -L${libdir} -lfoo
Cflags: -fPIC -I${includedir}/foo
Cflags.private: -DFOO_STATIC
License: ISC
@@ -0,0 +1,7 @@
foo=3
Foo=4
Name: case-sensitivity
Description: Package for testing case-sensitivity
Version: 1
Requires: foo < ${foo}
@@ -0,0 +1,9 @@
prefix=/test/local
exec_prefix=${prefix}
libdir=${prefix}/lib
includedir=${prefix}/include
Name: cflags-internal
Description: A testing pkg-config file
Version: 1.2.3
Cflags: -I${includedir}/foo
@@ -0,0 +1,10 @@
prefix=/test/local
exec_prefix=${prefix}
libdir=${prefix}/lib
includedir=${prefix}/include
Name: cflags-libs-only
Description: A testing pkg-config file
Version: 1.2.3
Libs: -L${libdir} -lfoo
Cflags: -I${includedir}/foo
@@ -0,0 +1,7 @@
Name: cflags-libs-private-a
Version: 1
Description: test case for issue #370
Cflags:
Libs:
Requires.private: cflags-libs-private-b
@@ -0,0 +1,7 @@
Name: cflags-libs-private-b
Version: 1
Description: test case for issue #370
Cflags:
Libs:
Requires: cflags-libs-private-c
@@ -0,0 +1,6 @@
Name: cflags-libs-private-c
Version: 1
Description: test case for issue #370
Cflags:
Libs: -lc
@@ -0,0 +1,4 @@
Name: CFlags Trailing Whitespace Bug
Description: Demonstrates problems with -I with spaces
Version: 1
Cflags: -I/usr/include -I/usr/include/foo
@@ -0,0 +1,4 @@
Name: CFlags Whitespace Bug
Description: Demonstrates problems with -I with spaces and sysroot munging
Version: 1
Cflags: -I /opt/bad/include
@@ -0,0 +1,11 @@
prefix=/usr
exec_prefix=/usr
libdir=${prefix}/lib64
includedir=${prefix}/include
Name: child-prefix-1
Description: child prefix 1 test data
Requires:
Version: 1.0
Libs: -L${libdir} -lchild-prefix-1
Cflags: -I${includedir}/child-prefix-1
+11
View File
@@ -0,0 +1,11 @@
prefix=/test
exec_prefix=${prefix}
libdir=${prefix}/lib
includedir=${prefix}/include
Name: circular-1
Description: A testing pkg-config file
Version: 1.2.3
Libs: -lcircular-1
Requires: circular-2
Cflags:
+11
View File
@@ -0,0 +1,11 @@
prefix=/test
exec_prefix=${prefix}
libdir=${prefix}/lib
includedir=${prefix}/include
Name: circular-2
Description: A testing pkg-config file
Version: 1.2.3
Libs: -lcircular-2
Requires: circular-3
Cflags:
+11
View File
@@ -0,0 +1,11 @@
prefix=/test
exec_prefix=${prefix}
libdir=${prefix}/lib
includedir=${prefix}/include
Name: circular-3
Description: A testing pkg-config file
Version: 1.2.3
Libs: -lcircular-3
Requires: circular-1
Cflags:
@@ -0,0 +1,9 @@
Name: comments-in-fields
Description: Comments in fields test case
URL: http://pkgconf.org/
Version: 0
Requires: # foo
Requires.private: foo
Libs: -lfoo # -lbar
Libs.private: -lbar
Cflags: -I${includedir}
+6
View File
@@ -0,0 +1,6 @@
Name: comments
Description: Portable CD-ROM I/O library
Version: 0
#Requires: bar-2.0
Libs: -lfoo
Cflags: -I${includedir}
+11
View File
@@ -0,0 +1,11 @@
prefix=/test
exec_prefix=${prefix}
libdir=${prefix}/lib
includedir=${prefix}/include
Name: conflicts
Description: A testing pkg-config file
Conflicts: foo <= 1.3
Version: 1.2.3
Libs: -L${libdir} -lconflicts
Cflags: -fPIC -I${includedir}/conflicts
@@ -0,0 +1,12 @@
prefix=/test
exec_prefix=${prefix}
libdir=${prefix}/lib
includedir=${prefix}/include
Name: depgraph-break
Description: A testing pkg-config file
Version: 1.2.3
Libs: -L${libdir} -lfoo
Cflags: -fPIC -I${includedir}/foo
Cflags.private: -DFOO_STATIC
Requires: nonexistant
@@ -0,0 +1,10 @@
prefix=/test
exec_prefix=${prefix}
libdir=${prefix}/lib
includedir=${prefix}/include
Name: dos-lineendings
Description: A testing pkg-config file
Version: 1.2.3
Libs: -L${libdir}/dos-lineendings -ldos-lineendings
Cflags: -fPIC -I${includedir}/dos-lineendings
@@ -0,0 +1,6 @@
xcflags=
Name: empty-tuple
Description: testing file
Version: 1
CFlags: ${xcflags}
@@ -0,0 +1,4 @@
Name: escaped-backslash
Version: 1
Description: test package for backslash escape scenario
Cflags: -IC:\\A
@@ -0,0 +1,7 @@
prefix=/usr
datarootdir=${prefix}/share
pkgdatadir=${pc_sysrootdir}/${datarootdir}/test
Name: Test
Description: Testing pc_sysrootdir auto-expansion
Version: 1.0
@@ -0,0 +1,10 @@
prefix=/test
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
includedir=${prefix}/include
cflags=-I${includedir}
Name: flag order 1
Description: test for flag ordering
Version: 1
Libs: -L${libdir} -Bdynamic -lfoo -Bstatic -lbar
@@ -0,0 +1,10 @@
prefix=/test
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
includedir=${prefix}/include
cflags=-I${includedir}
Name: flag order 3
Description: test for flag ordering
Version: 1
Libs: -L${libdir} -Wl,--start-group -lfoo -lbar -Wl,--end-group

Some files were not shown because too many files have changed in this diff Show More