Prior to commit 6ecf318, the resolved list of required packages was
built in an appending way where each package on the command line or in
Requires would appear in the list in the order they appeared. With
6ecf318, that list building was changed to prepending, which had a
subtle change on the resolved order.
For example, suppose package a has "Requires: b c d". Previously, the
list would be built as a->b->c->d by appending each as they were
encountered. Now, the list is built by walking all the way down the
dependency chain for each package in a depth first manner and prepending
packages while unwinding. This would result in the package ilst being
a->d->c->b. This same effect happens with the command line packages
where previously requesting packages x and y would create a package list
of x->y and now produces a list of y->x.
While technically these should be the same since there are no
interdependencies, it's causes flags to be output in different order
than previously in pkg-config. This can be seen most readily in the
check-gtk test.
Instead, operate on the package lists backwards when building the
resolved package list.
Walking a GSList backwards involved copying and reversing it so that the
the original list could remain undisturbed. This is wasteful with a
GList where we can just start at the end of the list and work backwards.
Makes the resolved package list be correctly serialized with each
package only appearing once. This provides more consistency between the
various flag outputs by ensuring that the flags from each package are
only grabbed once. This makes a difference since the duplicate flag
stripping happens from the end of the output (-l) or the beginning of
the output (-L/-I/other).
Using a doubly-linked list allows it to be easily traversed in both
directions and makes removing nodes in place much simpler. This adds an
extra pointer to each node and associated manipulation during any list
processing, but this trade seems acceptable over the repeated hacks to
work with singly-linked lists.
Often the expected results for the indirect dependency tests fell behind
because it's not a typical test scenario. However, since the results are
always the same as --static, they can just use the same results and the
test can be run conditionally without --static based on configuration.
Using the GSList functions instead of manually adjusting the list
pointers seems safer and allows an easier path to using another glib
list type if necessary.
The pkg-config testsuite has pretty good coverage of the implementation,
but it lacks a complex case that tests the interactions of non-trivial
.pc files. gtk is a very common package that meets this goal. This is a
snapshot from my F16 system, and it should provide a good way to see how
changes in the implementation regress a real world case.
pkg-config aggressively strips all duplicate arguments from the final
output it builds. This is not only and optimization, but it also allows
the flag ordering to work correctly when a package on the command line
is required by another on the command line.
The current tests are good at checking whether gathering the Cflags or
Libs from one or two packages works correctly, but they don't check the
sorting algorithm much at all. In particular, the interactions between
the package order in the Requires chain and in the path can make the
sorting of the flags subtly different.
The Package key member corresponds to the module filename with the .pc
stripped off while the name member corresponds to the Name field in the
.pc file. The latter is almost never used in practice and just makes
debugging more difficult.
Use a bitmask to keep track of what Libs/Cflags to output. This makes it
simple to handle any combination of --cflags and --libs option variants.
A lot of excess code is removed in the process as all the flags options
can now be carried around in a single variable.
Freedesktop #54388 (https://bugs.freedesktop.org/show_bug.cgi?id=54388)
A relic from the past, the pkg-config.in script exists from a time when
pkg-config was implemented as a shell script. This time is long since
gone and the script is far different than the C implementation. Find it
in git if you want to see how a shell script once did pkg-config.
The --print-variables output is inconsistent with other printing options
when --exists is supplied or not. Move the handling after --exists like
--print-requires and others requiring a valid package list so that
--exists is given it takes priority and exits early.
Freedesktop #54384 (https://bugs.freedesktop.org/show_bug.cgi?id=54384)
When merging the flags from all the packages together, each flags list
was being copied and then concatenated to then end of the combined list.
This was extremely inefficient because it caused the combined list to be
traversed multiple times to find the end. Instead, nest the copying and
merging of the flags together so the last element is always tracked and
can easily be appended to.
Freedesktop #54716 (https://bugs.freedesktop.org/show_bug.cgi?id=54716)
pkg-config(1) states that installed packages should be appended with
"-uninstalled". However, the code was checking only for trailing
"uninstalled" without the hyphen. Make the code consistent with the
documentation.
Freedesktop #54379
Apparently g_hash_table_foreach doesn't check for NULL input, so make
sure we don't call it to print the variables if the variable list is
empty.
Freedesktop #54721
After the packages are parsed, pkg-config recurses through all the
required packages to generate one list. Before descending another level,
check to see if the package has already been handled and skip it. This
allows packages to require each other circularly by breaking the loop.
A test has been added resolving a two level deep circular dependency.
Freedesktop #7331
When the parser encounters Requires or Requires.private, it immediately
tries to sees if we have a parsed package for that entry. If not it
tries to locate the needed file and parse it out. If there's a circular
dependency, this will eventually error opening too many files.
Instead, just store the requires entries so the parsing completes and
the package is added to the database. After parsing, the entries can be
resolved into Packages and any circular requires entries will find the
first package in the database.
This is a partial fix for Freedesktop #7331.
recursive_fill_list() is used to order Requires and Requires.private,
but it relied on fill_one_level() to make the list adjustments as it
descended the package tree. There were two issues with this approach:
1. It added all the dependencies from a package immediately rather than
descending through each dependency first. This made it sort of mix
between depth- and breadth-first resolving.
2. It did not add the requested package to the list, forcing the caller
to add it.
This simplifies the code so that it descends all the way to the least
dependent package and prepends them as it unwinds. This ensures the
ordering will be sorted from most dependent to least dependent package.
Ordering of -l flags is corrected by a later sorting, but this fixes
ordering on non-l flags. Add a new test specifically for non-l Libs
flags.
Freedesktop #34504
The function recursive_fill_list() is designed to descend lists of
packages, so it only makes sense to use with Requires and
Requires.private. Ensure it to make later code additions simpler.
If pkg-config is used in a multiarch or cross-compiling scenario it's
likely pkg-config needs to behave differently for each of them. It's
possible to handle this through environment variables with one
pkg-config, but another option is to have one pkg-config per platform,
each with the host alias prefixed to the program.
PKG_PROG_PKG_CONFIG supports this type of installation, and this is also
how autoconf/libtool handle other build tools like compilers and
linkers.
The host-prefixed tool is installed as a hardlink where supported and a
copy otherwise. This is how gcc handles it's host-prefixed versions.
This feature can be turned off by passing --disable-host-tool to
configure.
Freedesktop #130
From what I can tell, these single package variants have never been used
going back to pkg-config-0.4.0. pkg-config always uses the multipackage
versions that loop over the list of supplied packages.
Make sure that the --*-only-* variants of --cflags and --libs do the
right thing. This should probably be extended to cover a chain of
packages to get the ordering right, but this is good for now.
Test the usage of -uninstalled packages with two .pc files: inst.pc and
inst-uninstalled.pc. pkg-config should prefer the -uninstalled version
unless PKG_CONFIG_DISABLE_UNINSTALLED is set. It should also use the
default value of pc_top_builddir unless PKG_CONFIG_TOP_BUILD_DIR is set.
Add a test for pkg-config's path handling. The first test covers
PKG_CONFIG_PATH, and the second covers the built-in path. For this one
we need to unset the PKG_CONFIG_LIBDIR that normally is set during the
tests. Since we can't rely on the contents of the default path, we just
check to see that the built-in path matches what was specified in
configure. To do this, we need to add a bunch of variables to config.sh
so the variable resolves. These variables don't need to be exported,
though.
Add tests for checking the output of various options that print
information. For --list-all, a subdirectory with only two packages has
been added so that its output doesn't change when more test packages are
added to the check directory.
The run_test shell function was running pkg-config with arguments stored
in an environment variable. This has problems when trying to pass shell
special characters with the proper escaping. Instead, pass the arguments
to the test where they can maintain correct formatting through use of
the special variable "$@".
Use gcov to find how much code coverage our current testing gets. This
can be enabled by passing --with-gcov to configure and running "make
gcov". This is limited to gcc. Here's a run from the current code (for
some reason, gcov insists on profiling gstring.h).
/usr/bin/gcov pkg.h pkg.c parse.h parse.c main.c
File 'pkg.c'
Lines executed:73.16% of 611
pkg.c:creating 'pkg.c.gcov'
File '/usr/include/glib-2.0/glib/gstring.h'
Lines executed:100.00% of 6
/usr/include/glib-2.0/glib/gstring.h:creating 'gstring.h.gcov'
File 'parse.c'
Lines executed:79.67% of 492
parse.c:creating 'parse.c.gcov'
File 'main.c'
Lines executed:57.34% of 293
main.c:creating 'main.c.gcov'
When the VARIABLE-PREFIX tag is used more than once in PKG_CHECK_MODULES
it can result in later runs reporting success without actually running
pkg-config. This is because PKG_CHECK_MODULES looks for FOO_CFLAGS and
FOO_LIBS from the environment as a way to allow users to override the
test. PKG_CHECK_MODULES also sets these variables, though, and
subsequent calls will simply use these values.
Although there are legitimate ways to use the same VARIABLE-PREFIX
(e.g., they're all under conditionals meaning only one will be used),
document that repeated usage is not recommended.
Freedesktop #3550
Making --enable-static --disable-shared the default fixes most cases,
but build environments often pass --enable-shared --disable-static for
all autotooled projects. Force static building by setting the
appropriate variables as if they've come from the command line
parameters.
Without this, if the new ${prefix} path contains spaces, they are not
properly quoted in pkg-config's output. Besides the problems this causes
with things using the output, this also causes nonsensical results when
pkg-config splits such options to combine equal options.
By specifying the pkg-config to use for testing from make, we can easily
control its path and add the .exe extension for Windows. It also allows
easy testing of another pkg-config from make:
make check TESTS_PKG_CONFIG=/usr/bin/pkg-config
Although the trick of finding a POSIX shell in the system PATH works
fine most of the time, it has some drawbacks.
* The commands must be copied into every test script.
* The scripts are always forced to re-execute themselves.
* There's no guarantee the sh found in `getconf PATH` is a POSIX shell
and there's no way to override it.
Move the handling of this shell to configure where we can detect it
once. This gives preference to bash and ksh since they're typically
POSIX compatible. It also uses the current PATH with the getconf PATH at
the end which should allow things to work on platforms where getconf
might not be available like mingw/msys.
By specifying the shell in TESTS_ENVIRONMENT, automake will run each
script with this shell and we can drop the re-exec dance.
When glib is built static, the threads and clock code are not
initialized since DllMain is never run. Instead, initialize them from
the glib constructor.
https://bugzilla.gnome.org/show_bug.cgi?id=678387
pkg-config doesn't use message translation, so there's no need to build
it into the bundled glib. Furthermore, when not using glibc, this drags
in extra dependencies on gettext, libintl and iconv. Remove their usage
in two steps:
1. Don't include libintl.h directly from code. glibintl.h
conditionalizes the include of libintl.h based on the ENABLE_NLS define
and creates fallback macros when it's unwanted.
2. Remove the usage of the gettext macros in glib's configure.ac. This
ensures that the unwanted dependencies aren't searched for. Two defines
are kept around to keep the code happy.
When reapplying the glib patches we often end up with .orig files when
the hunks have moved. Any backup suffix is possible, but this is the
default from patch(1).