Compare commits

...

289 Commits

Author SHA1 Message Date
Ariadne Conill 094dc38468 pkgconf 1.9.5.
Signed-off-by: Ariadne Conill <ariadne@dereferenced.org>
2023-05-02 12:10:54 -07:00
Ariadne Conill 35b1a62314 update libpkgconf version to 10905
Signed-off-by: Ariadne Conill <ariadne@dereferenced.org>
2023-05-02 12:09:55 -07:00
Ariadne Conill 83f412a1fd update NEWS for 1.9.5.
Signed-off-by: Ariadne Conill <ariadne@dereferenced.org>
2023-05-02 12:09:19 -07:00
Ariadne Conill 7bfc2289fd tests: add regression test for maximum package count off-by-one
Signed-off-by: Ariadne Conill <ariadne@dereferenced.org>
2023-05-02 11:58:56 -07:00
Ariadne Conill 1e179963d4 Enforce maximum package count correctly for --modversion
Signed-off-by: Ariadne Conill <ariadne@dereferenced.org>
2023-05-02 11:58:39 -07:00
Harmen Stoppels f7bebba664 fix meson.build
Co-authored-by: Ariadne Conill <ariadne@dereferenced.org>
2023-05-02 11:52:10 -07:00
Harmen Stoppels 434cb2935e use includes 2023-05-02 11:49:34 -07:00
Harmen Stoppels 40638f2472 use AC_CHECK_DECLS to avoid implicit function definition
AC_CHECK_FUNCS is not safe, since implicit function definitions is just
a warning. On 64-bit glibc systems where reallocarray is not defined or
hidden behind macros that are not set, it gets implicitly defined to
return an integer, which is a big problem given that it should return a
pointer, and leads to immediate segfaults.
2023-05-02 11:49:34 -07:00
h30032433 b08733f45d Fix the issue where tests/meson.build was deleted. 2023-05-02 11:48:38 -07:00
huyubiao 6d1f160e89 argvsplit: fix some quoting rules 2023-05-02 11:45:42 -07:00
Taylor R Campbell 212c85863a Avoid undefined behaviour with the ctype(3) functions.
fix https://github.com/pkgconf/pkgconf/issues/291

As defined in the C standard:

        In all cases the argument is an int, the value of which shall
        be representable as an unsigned char or shall equal the value
        of the macro EOF.  If the argument has any other value, the
        behavior is undefined.

This is because they're designed to work with the int values returned
by getc or fgetc; they need extra work to handle a char value.

If EOF is -1 (as it almost always is), with 8-bit bytes, the allowed
inputs to the ctype(3) functions are:

        {-1, 0, 1, 2, 3, ..., 255}.

However, on platforms where char is signed, such as x86 with the
usual ABI, code like

        char *ptr = ...;
        ... isspace(*ptr) ...

may pass in values in the range:

        {-128, -127, -126, ..., -2, -1, 0, 1, ..., 127}.

This has two problems:

1. Inputs in the set {-128, -127, -126, ..., -2} are forbidden.

2. The non-EOF byte 0xff is conflated with the value EOF = -1, so
   even though the input is not forbidden, it may give the wrong
   answer.

Casting char to unsigned int first before passing the result to
ctype(3) doesn't help: inputs like -128 are unchanged by this cast,
because (on a two's-complement machine with 32-bit int and unsigned
int), converting the signed char with integer value -128 to unsigned
int gives integer value 2^32 - 128 = 0xffffff80, which is out of
range, and which is converted in int back to -128, which is also out
of range.

It is necessary to cast char inputs to unsigned char first; you can
then cast to unsigned int if you like but there's no need because the
functions will always convert the argument to int by definition.  So
the above fragment needs to be:

        char *ptr = ...;
        ... isspace((unsigned char)*ptr) ...

This patch changes unsigned int casts to unsigned char casts, and
adds unsigned char casts where they are missing.
2023-05-02 11:43:56 -07:00
Andrej Shadura 78f3abc935 doc: Regenerate the documentation for libpkgconf
Signed-off-by: Andrej Shadura <andrew.shadura@collabora.co.uk>
2023-01-22 10:58:01 +00:00
Andrej Shadura 9ab5ea2e83 doc: personality: Add a documentation header
Signed-off-by: Andrej Shadura <andrew.shadura@collabora.co.uk>
2023-01-22 10:58:01 +00:00
Andrej Shadura cfda825f80 doc: extract: Use "==" instead of "is" with literals
This fixes:
    SyntaxWarning: "is" with a literal. Did you mean "=="?

Signed-off-by: Andrej Shadura <andrew.shadura@collabora.co.uk>
2023-01-22 10:58:01 +00:00
Ariadne Conill 873e51aaae pkgconf 1.9.4. 2023-01-22 04:56:44 +00:00
Ariadne Conill f7305434eb libpkgconf: bump API version to 10904 2023-01-22 04:56:06 +00:00
Ariadne Conill 93edd215b4 update NEWS for 1.9.4 2023-01-22 04:52:25 +00:00
Ariadne Conill 49ab0b2ab7 tests: fixup! 2023-01-21 21:43:23 +00:00
Ariadne Conill 98b33b48cd cli: use flattened solution for almost all user-facing queries 2023-01-21 21:43:08 +00:00
Ariadne Conill d9e507cc6e pkg: do not do serial checks for flattened solutions, as they are already flattened 2023-01-21 21:31:38 +00:00
Ariadne Conill 90b65c866b main: use flattened solution for cflags/libs only 2023-01-21 21:31:16 +00:00
Ariadne Conill 1ce000f397 Revert "pkg.m4: PKG_CHECK_MODULES provides modversion"
This reverts commit 8d9d3de6eb.
2023-01-21 20:59:22 +00:00
Ariadne Conill 99bc93fbe5 use SIZE_FMT_SPECIFIER everywhere 2023-01-21 20:45:29 +00:00
Ariadne Conill e2a12fd4c2 main: reset solver when solving for library groups 2023-01-21 20:39:53 +00:00
Ariadne Conill 8f12d36b76 tests: fixup trailing whitespace in expected results 2023-01-21 20:22:03 +00:00
Ariadne Conill b106de0c7a cli: add whitespace between cflags and libs fragments 2023-01-21 20:21:26 +00:00
Ariadne Conill 648a2249fc fragment: render: only include trailing space if there is another fragment 2023-01-21 20:17:33 +00:00
Ariadne Conill dd741e722f README: fix tests option to reflect meson changes 2023-01-21 20:12:02 +00:00
Timo Röhling 506ebab7d6 Ignore whitespace indentation
Fixes #265
2023-01-21 20:09:52 +00:00
Ariadne Conill be0d811942 argvsplit: fix some quoting rules to match POSIX 2023-01-21 19:51:24 +00:00
Ariadne Conill 6a5b55740d tests: fix test regressions caused by tilde changes 2023-01-21 19:25:46 +00:00
Doug Freed 131619ae4b doc: update libpkgconf-pkg docs to match 2023-01-20 22:21:31 +00:00
Doug Freed 08db74c474 pkg: make pkgconf_compare_version consistent
The code taken from rpmvercmp in pkg-config returns -1 if a is less than
b, 0 if a is equal to b, and 1 if a is greater than b. This matches the
expectations of the comparison operators that use this function.
However, the tilde handling, the NULL handling, and the docstring all do
the opposite.

This fixes the tilde handling, the NULL handling, and the docstring to
match the behavior of the rpmvercmp code and the expectations of the
comparison operators.
2023-01-20 22:21:31 +00:00
Doug Freed eb5c6b49d6 Fix Mingw GH CI broken by 179a056 2023-01-20 22:19:13 +00:00
Ziemowit Łąski 1c3f246198 pkgconf: Handle spaces correctly when expanding variables
Given the following .pc fragment:

includedir=/mingw64/include
Cflags: -I${includedir} -I${includedir}/taglib

Should includedir be assigned the value 'C:/Program\ Files/Git/mingw64/include', the expansion of ${includedir} will be chopped off after the first space:

Cflags: -IC:/Program\

With this patch, the expansion is corrected:

Cflags: -IC:/Program\ Files/Git/mingw64/include -IC:/Program\ Files/Git/mingw64/include/taglib

Create spaces-in-paths.pc
2023-01-20 22:18:26 +00:00
wi24rd 27287f323d Update sum value of types of property. 2023-01-20 22:17:33 +00:00
Eli Schwartz 8f233383cd meson: remove useless command that isn't needed
The tests/*.sh are executable in the source tree, and don't need to be
chmodded after being copied to the build tree.
2023-01-20 22:13:21 +00:00
Ariadne Conill 2f51733e34 tests: add regression test for billion-laughs 2023-01-20 22:11:00 +00:00
Ariadne Conill 628b2b2baf tuple: test for, and stop string processing, on truncation
otherwise a buffer overflow occurs.
this has been a bug in pkgconf since the beginning, it seems.
instead of disclosing the bug correctly, a "hotshot" developer
decided to blog about it instead.  sigh.

https://nullprogram.com/blog/2023/01/18/
2023-01-20 22:07:03 +00:00
Ariadne Conill 3e481581ba add billion-laughs test fixture 2023-01-20 22:01:38 +00:00
Ariadne Conill 0226cdda6d Merge pull request 'meson: use a feature option for tests instead of boolean' (#244) from dcbaker/pkgconf:tests-feature into master
Reviewed-on: ariadne/pkgconf#244
2022-08-20 13:27:45 +00:00
Dylan Baker fa803c7ecd meson: use a feature option for tests instead of boolean
This allows tests to be autodetected gracefully, which is particularly
convenient for kyua and atf_sh which are fairly painful to build and
install by hand. Those who want to ensure tests are enabled or disabled
may pass `-Dtests=enabled` or `-Dtests=disabled` respectively.

This does require a modest bump in the required meson version to 0.49,
which was released at the end of 2018, so roughly 4 years ago.
2022-08-17 11:07:44 -07:00
Ariadne Conill bddf1641f8 bomtool: fix ASan issues 2022-08-16 20:41:10 +00:00
Ariadne Conill 8754bdfe09 pkgconf 1.9.3. 2022-08-16 19:50:26 +00:00
Ariadne Conill 6a66b312b4 libpkgconf: increase API level to 10903 2022-08-16 19:49:42 +00:00
Ariadne Conill 4c38d3f60c update NEWS for pkgconf 1.9.3 2022-08-16 19:49:02 +00:00
Ariadne Conill b7593aea27 build: automake: use top_srcdir as needed 2022-08-16 19:48:44 +00:00
Ariadne Conill dbd78db67f tests: add regression test for github #259 2022-08-16 19:42:13 +00:00
Ariadne Conill 80bc5ac3b9 tuple: if a global tuple is explicitly defined with --define-variable, prefer it
fixes github #259
2022-08-16 19:39:05 +00:00
Ariadne Conill 5044491f43 queue: add function to free a compiled solution 2022-08-16 19:27:35 +00:00
Ariadne Conill c6d14e6fa1 cli: renderer-msvc: remove pointless buf_remaining store 2022-08-16 18:53:29 +00:00
Ariadne Conill ced9bee613 pkg: remove dead store in pkgconf_compare_version 2022-08-16 18:51:11 +00:00
Ariadne Conill 2c89541101 bomtool: return EXIT_FAILURE if solver fails to solve 2022-08-16 18:50:35 +00:00
Ariadne Conill 5500a15133 fragment: avoid trying to merge fragments where data == NULL 2022-08-16 18:46:43 +00:00
Ariadne Conill 74faf8d0e2 queue: do not enqueue unsolved nodes as part of a solution 2022-08-16 18:38:46 +00:00
Ariadne Conill c918b6e225 bomtool: enable PKGCONF_PKG_PKGF_SEARCH_PRIVATE to collect dev dependencies 2022-08-13 06:44:40 +00:00
Ariadne Conill 12f3a30980 bomtool: write dependency relationships in both directions 2022-08-13 06:44:19 +00:00
Ariadne Conill 01c1d9f4cc bomtool: remove empty creation date field 2022-08-12 13:07:58 +00:00
Ariadne Conill 9e8052b699 bomtool: add enough to generate a basic SBOM 2022-08-12 12:57:53 +00:00
Ariadne Conill 696124b608 pkg: add support for parsing the URL from pc files 2022-08-12 12:36:21 +00:00
Ariadne Conill 79327b8967 add bomtool skeleton 2022-08-12 12:07:56 +00:00
Ariadne Conill f3021a82c5 libpkgconf.pc: add license 2022-08-12 11:59:11 +00:00
Ariadne Conill 194ad3e656 man: pc.5: document copyright/maintainer fields 2022-08-11 16:01:30 +00:00
Ariadne Conill aa99ddf789 pkg: add Copyright and Maintainer fields
These are helpful pieces of information for BOM documents
generated by pkgconf.
2022-08-11 15:52:33 +00:00
Ariadne Conill 68b5cab72d cli: remove redundant SEARCH_PRIVATE block
It turns out there was already a check for PKG_CFLAGS being requested,
but the check was busted because PKG_CFLAGS is a combined-or of all of
the various --cflags flags.

Check that PKG_CFLAGS bits are set at all on want_flags instead.
2022-08-11 15:06:08 +00:00
Ariadne Conill 78f00da130 Merge pull request 'cli: use Requires.private when cflags are requested' (#243) from psykose/pkgconf:cflags-i into master
Reviewed-on: ariadne/pkgconf#243
2022-08-11 13:49:44 +00:00
psykose 746005582f
cli: use Requires.private when cflags are requested 2022-08-11 15:47:32 +02:00
Ariadne Conill 28b5d57b98 pkg: free SPDX license tags when a package is destroyed 2022-08-08 10:25:24 +00:00
Ariadne Conill af9b26c15c pkgconf 1.9.2. 2022-08-08 10:03:15 +00:00
Ariadne Conill c0d2d65347 NEWS for pkgconf 1.9.2. 2022-08-08 10:02:56 +00:00
Ariadne Conill 69a3d458ef libpkgconf: revise API revision to 10902 2022-08-08 09:59:50 +00:00
Ariadne Conill 7e9aa7e1fc pkg: do not break cycles across dependency lists 2022-08-08 09:56:28 +00:00
Ariadne Conill 4e449bd45f cli: do not search requires.private for --libs unless --static 2022-08-08 09:42:01 +00:00
Ariadne Conill 69f630aadc pkg: only advance serial if we are actually traversing from a root 2022-08-08 09:34:45 +00:00
Ariadne Conill 760d1eea10 cli: use pkgconf_queue_solve instead of pkgconf_queue_apply 2022-08-08 09:27:39 +00:00
Ariadne Conill 8764578719 tests: ignore stdout on regress:missing test 2022-08-08 09:26:22 +00:00
Ariadne Conill 5b10a85a82 queue: add pkgconf_queue_solve API 2022-08-08 09:08:27 +00:00
Ariadne Conill 884a88583b tests: add testcase for requires.private debounce 2022-08-08 08:56:53 +00:00
Ariadne Conill 4e8f376c5d tests: add fixtures for github #258 2022-08-08 05:26:00 +00:00
Ariadne Conill 79d25f979d queue: ensure private deps get flattened when --static is requested 2022-08-08 00:58:55 +00:00
Ariadne Conill 03ba00d30b Merge pull request 'bsdstubs: include errno.h' (#242) from dcbaker/pkgconf:bsdstubs-errno into master
Reviewed-on: ariadne/pkgconf#242
2022-08-08 00:51:32 +00:00
Ariadne Conill 1a66d963cf pkgconf 1.9.1. 2022-08-08 00:44:23 +00:00
Ariadne Conill 8271ea1952 NEWS: update for pkgconf 1.9.1. 2022-08-08 00:43:20 +00:00
Ariadne Conill b29f9d8713 cli: do not flatten or traverse the graph when asking for module-specific values 2022-08-08 00:40:52 +00:00
Ariadne Conill 94b3f118cc tests: add regression test to catch --modversion regression introduced by new solver 2022-08-08 00:37:07 +00:00
Dylan Baker 7976daab9a bsdstubs: include errno.h
Needed for ENOMEM, and fixes the build on MacOS.
2022-08-06 22:30:25 -07:00
Ariadne Conill d8d669f637 pkgconf 1.9.0. 2022-08-07 04:47:04 +00:00
Ariadne Conill 23556ff818 Bump libpkgconf SOVERSION for 1.9.0 changes. 2022-08-07 04:46:35 +00:00
Ariadne Conill da9b2cfbc1 NEWS: note the SPDX license branch has been merged 2022-08-07 04:45:33 +00:00
Ariadne Conill b2579a661b man: pc(5): document the License field 2022-08-07 04:42:55 +00:00
Ariadne Conill 666b520273 tests: add tests for SPDX license assertions 2022-08-07 04:40:31 +00:00
Ariadne Conill d5f9bdae57 cli: add support for dumping SPDX expressions from modules 2022-08-07 04:40:19 +00:00
Ariadne Conill 0e05308f9c pkg: add SPDX license assertion to pkgconf builtin 2022-08-07 04:35:29 +00:00
Ariadne Conill 1389aa05ba pkg: add pkgconf_pkg_t.license field
The pkgconf_pkg_t.license field maps to the new License keyword, and
should be an SPDX license expression.
2022-08-07 04:21:22 +00:00
Ariadne Conill dce34e9afd Update NEWS for pending 1.9.0 release 2022-08-07 04:13:43 +00:00
Ariadne Conill 9aa0006c27 tests: improve circular reference tests to make use of the circular reference diagnostic 2022-08-07 01:35:12 +00:00
Ariadne Conill 7edfdbff0b pkg: upgrade circular reference trace to a warning 2022-08-07 01:29:21 +00:00
Ariadne Conill 662668d082 pkg: add trace log when breaking a circular reference 2022-08-07 01:09:07 +00:00
Eli Schwartz 59a56dfa64 trivial sync of pkg.m4 from freedesktop
This contains 3 changes, mostly inconsequential:

- fix some spelling issues in the comments

  eb866ade77

- bump the serial number; upstream rationale is very 🤷 but it is
  what it is:
  > There aren't any significant changes here, but this will cause aclocal
  > to get the latest version.

  677e924875

- make the status log for PKG_CHECK_MODULES say "checking for <mod>..."
  instead of "checking for <VAR>..."

  3b96e7434c

There are additional whitespace-only changes that could be synced, and
were explicitly synced in commit 95b683c864
but then undone in commit 360a818f2f so
rather than fighting over it, are simply ignored. Diffing against the
freedesktop version of pkg.m4 will therefore show additional
inconsistencies.
2022-08-07 00:40:17 +00:00
Ariadne Conill 56881f64f0 cli: resolve uninitialized pointer warnings reported by GCC 12 2022-08-07 00:38:38 +00:00
Ariadne Conill b310728111 Merge pull request 'Do a better job cleaning up memory' (#239) from dcbaker/pkgconf:free-memory into master
Reviewed-on: ariadne/pkgconf#239
2022-08-04 23:36:15 +00:00
Dylan Baker 179a0560a6 ci: run meson test with the address sanitizer enabled
Set the ASAN_OPTION so that the exitcode is not 1, this avoids asan
returning the exitcode that the tests already expect from a normal
pkgconf error
2022-08-04 15:52:10 -07:00
Dylan Baker 1cfa2d1e20 pkg: prevent circular ownership
Otherwise in a case where A references B, and B references A, A and B
will have mutual ownership of each other and prevent each other from
being free'd.
2022-08-04 15:52:10 -07:00
Dylan Baker 301d8fa0c6 queue: free unused dependencies when flattening 2022-08-04 15:52:10 -07:00
Dylan Baker 34b110200a dependency: zero list after freeing 2022-08-04 15:52:10 -07:00
Dylan Baker e71a5a3370 dependency: add debug information for dependency refcounting 2022-08-04 15:52:10 -07:00
Dylan Baker 4934205737 pkg: add name of pkg being refed/unrefed to debug outpu 2022-08-04 15:52:10 -07:00
Dylan Baker a46ce3672f queue: when collecting dependents don't iterate private twice
Currently, the private field is iterated collecting private deps and
normal deps. It should only be iterated when collecting private deps.
2022-08-04 15:52:10 -07:00
Dylan Baker 4493a322f6 main: do cleanup when checking required version 2022-08-04 15:52:10 -07:00
Dylan Baker a391f9b650 pkg: use goto cleanup idiom 2022-08-04 15:52:10 -07:00
Dylan Baker 38103134a5 main: goto cleanup in validate case too
This fixes leaks in two tests
2022-08-04 15:52:10 -07:00
Dylan Baker 171738024e cache: clear the cache with pkgconf_cache_remove
Which results in more code re-use.
2022-08-04 15:52:10 -07:00
Dylan Baker e4d1c8ffa5 queue: when flattening do nothing if the flattened deps are empty 2022-08-04 15:52:10 -07:00
Dylan Baker 6609001114 queue: unref dependency in all cases 2022-08-04 15:52:10 -07:00
Dylan Baker e275594ba6 queue: ensure cleanup happens when applying 2022-08-04 15:52:10 -07:00
Dylan Baker 4a1119aa2a dependency: Fix reference counting of dependency_addraw
We only want a reference to be added for the value inserted into the
list, not the one returned. The returned one is unowned until it reaches
the public dependency_add function, which returns an owned pointer
instead. This makes things semantically more correct.

Unfortunately, this means in a few cases we have to write some ugly
code like:
```c
pkgconf_dependency_t *dep = pkgcond_dependency_add("args");
pkgconf_dependency_unref(dep->owner, dep);
```
2022-08-04 15:52:10 -07:00
Dylan Baker a4de6235c2 cache: when removing a package from the cache unset the cached flag 2022-08-04 15:52:10 -07:00
Dylan Baker ebe74fd253 cache: free the cache table when it is empty and set to NULL
We do the latter for the benefit of libpkgconf. This cleans up a
significant number of memory leaks in the cache handling.
2022-08-04 15:52:10 -07:00
Ariadne Conill d240afe7d9 Merge pull request 'Fix macro definition interfering with -Wmisleading-indentation' (#241) from dcbaker/pkgconf:submit/misleading-indentation into master
Reviewed-on: ariadne/pkgconf#241
2022-08-04 04:33:11 +00:00
Dylan Baker 125a13d3b9 meson: add -Wmisleading-indentation
A useful warning when loop and conditional statements are allowed
without braces.
2022-08-03 12:03:15 -07:00
Dylan Baker 96c61cbab0 libpkgconf: remove trailing ; from macro definition
GCC has a lovely bug (which I will report as soon as I have an account),
which causes -Wmisleading-indentation to miss cases of misleading
indentation after a `;;`, since the macro adds `;`, and in call cases
the caller also adds `;`, we end up with a double macro and gcc fails to
warn.
2022-08-03 12:03:15 -07:00
Ariadne Conill a042827951 Merge pull request 'meson cleanups and fixes' (#240) from dcbaker/pkgconf:submit/meson-cleanups into master
Reviewed-on: ariadne/pkgconf#240
2022-08-02 23:09:24 +00:00
Dylan Baker dd779ad9f8 meson: add check to run_command
Because we really should be checking that it succeeds, and because not
setting it is deprecated.
2022-08-01 09:40:08 -07:00
Dylan Baker c04097e491 meson: pass configured files idiomatically
Instead of attempting to figure out what the paths will be, take the
returned file object and pass that around, meson will then automatically
figure out the correct paths.
2022-08-01 09:40:08 -07:00
Dylan Baker 06fe2e23b0 meson: use current_source_dir and current_build_dir instead of *_root
The latter doesn't work correctly when being used as a subproject, as it
returns the *absolute* root. So if pkgconf is being built as part of
muon, then it will return muon's source root. current_source_dir, on the
other hand returns the directory correctly whether being built as a
subproject or superproject.
2022-08-01 09:40:08 -07:00
Dylan Baker 1f993bc095 meson: use string methods to avoid repeating data
Instead of writing `['HAVE_FOO_H', 'foo.h']`, use meson's string methods
to just write `['foo.h']`, and let meson create `HAVE_FOO_H` for us.
2022-08-01 09:40:08 -07:00
Dylan Baker f947af057f meson: use str.format for improved readability 2022-08-01 09:40:08 -07:00
Dylan Baker 5ba74dec93 meson: use straight indexing instead of array.get()
It's more terse, and we don't need the support of a fallback value.
2022-08-01 09:40:08 -07:00
Dylan Baker bf307c1d95 ci: set meson to build with -Werror
This will help catch any new warnings added in CI.
2022-08-01 09:40:08 -07:00
Dylan Baker 4a2c9c285f meson: use C99 as the standard
autoconf uses either C99 or Gnu99. Meson does not provide a graceful way
to select gnu99 if possible or c99 (though there are several proposals
currently happening to get there), so I've selected c99 as the
conservative default. Without this, the compiler uses whatever it's
default happens to be, which may or may not work out correctly, and
hides bugs from CI that are present with c99 as the default.
2022-07-29 10:23:18 -07:00
Dylan Baker 40ec08594e meson: add warning for implicit-function-declarations
This would be triggered without the previous addition of -D_BSD_SOURCE
for strdup, among others
2022-07-29 10:23:18 -07:00
Dylan Baker 71974d8c54 meson: Add _BSD_SOURCE and _DEFAULT_SOURCE
To avoid warnings about string functions like strdup which are otherwise
undefined, but succeed at linking anyway when the C standard is c99.
2022-07-29 10:23:02 -07:00
Ariadne Conill 918b660992 woodpecker: track debian testing for autoconf 2.71 2022-07-26 18:15:50 +00:00
Ariadne Conill f93870efd9 tests: add testcase for legacy FDO rules plus pc_sysrootdir 2022-07-26 18:05:31 +00:00
Ariadne Conill 18e2406002 tests: add omg-sysroot-uninstalled fixture 2022-07-26 18:03:15 +00:00
Ariadne Conill 6c70781aad introduce PKG_CONFIG_PKGCONF1_SYSROOT_RULES for legacy pkgconf behavior 2022-07-26 18:00:22 +00:00
Ariadne Conill f8aefea7ec pkg: add flags argument to pkgconf_pkg_new_from_file 2022-07-26 17:13:15 +00:00
Ariadne Conill 297e18f2c8 tuple: add flags parameter to pkgconf_tuple_parse 2022-07-26 17:08:48 +00:00
Ariadne Conill d9ec3ee642 tests: add testcases for confirming desired sysroot behavior regarding -uninstalled packages 2022-07-26 16:46:39 +00:00
Ariadne Conill b0802cb3d1 Revert "pkgconf_pkg_parser_value_set(): fix code-path ordering bug."
This reverts commit 13fe4c8c58.
2022-06-26 19:41:31 +00:00
Ariadne Conill b602e33141 github actions: use debian testing 2022-06-26 19:39:09 +00:00
Ariadne Conill 72e429ae70 tuple: use ${pc_sysrootdir} instead of client->sysroot_dir where relevant 2022-06-26 19:35:19 +00:00
Ariadne Conill 7fa632a658 tests: sysroot: add additional tests 2022-06-26 19:34:54 +00:00
Ariadne Conill 9950312fde tests: add additional test fixtures 2022-06-26 19:34:39 +00:00
Ariadne Conill 19b1befb5d add additional sysroot testcase fixtures 2022-06-26 19:21:52 +00:00
Ariadne Conill a61193c723 pkg: fix sysroot_dir logic for github 213 2022-06-26 19:16:00 +00:00
Ariadne Conill d68a867dc0 tuple: fall back to using globals rather than preferring them 2022-06-26 19:15:07 +00:00
Ariadne Conill bc272e4e9f autoconf: run autoupdate 2022-06-26 18:58:08 +00:00
Ariadne Conill 623b8f7851 tests: further fixups 2022-06-26 18:56:36 +00:00
Ariadne Conill fdd7d192e0 queue: fix ISO C conformance for fallthrough label 2022-06-26 18:39:00 +00:00
Ariadne Conill 11164376f7 main: handle --personality load failure 2022-06-26 18:34:22 +00:00
Ariadne Conill ab352222a2 tests: fix up some test changes from the solver optimizations
the output of pkgconf is basically functionally equivalent in both cases
2022-06-26 18:22:04 +00:00
Ariadne Conill 04a6dda79f main: refactor apply_variable 2022-06-26 18:17:30 +00:00
Ariadne Conill a1a415111f queue: handle pkgconf_pkg_verify_dependency failure while flattening 2022-06-26 18:09:22 +00:00
Ariadne Conill 9bc6d80e61 queue: push new unresolved dependencies to the front of the queue, rather than the tail 2022-06-26 18:06:04 +00:00
Ariadne Conill fe4db3aad9 queue: skip dependency collection for root node 2022-06-26 18:04:42 +00:00
Ariadne Conill 5a82a259ac queue: use maxdepth after flattening 2022-06-26 15:17:08 +00:00
Ariadne Conill a416dc1fd6 queue: advance client serial when walking requires.private for flattening 2022-06-26 15:16:36 +00:00
Ariadne Conill 197fcadd4c queue: add flattening code 2022-06-26 15:02:37 +00:00
Ariadne Conill 5817e8848f pkg: track the number of hits a package has gotten while solving for dependencies 2022-06-26 07:22:56 +00:00
Ariadne Conill 6ae17bd0ef pkg: split pkgconf_pkg_traverse into a serial-modifying version 2022-06-26 06:05:40 +00:00
Ariadne Conill ffa0805d58 cache: use pkgconf_reallocarray stub 2022-06-26 04:38:02 +00:00
Ariadne Conill c1579d381c bsdstubs: add pkgconf_reallocarray 2022-06-26 04:37:18 +00:00
Ariadne Conill 4c76f6bf01 meson: check for reallocarray
it is needed for the new cache code
2022-06-26 04:33:47 +00:00
Ariadne Conill 664f741f26 autoconf: check for reallocarray
it is needed for the new cache code
2022-06-26 04:33:25 +00:00
Ariadne Conill 464672404e cache: refactor to use a continguous table and bsearch
cache functions are the hottest part of the pkgconf code when
profiled, by removing the linked list for lookups, we can turn
lookups into an O(k) operation
2022-06-26 04:30:35 +00:00
Dylan Baker c0fa7879b2 libpkgconf: zero path lists after freeing
This is required to make the pointer safely re-usable after being freed,
otherwise the list still says that it has nodes, but they point nowhere.
This is particularly important for libpkgconf, if a caller needs to
re-enter the library after freeing a path in a static path (such as the
default personality)
2022-06-26 03:12:34 +00:00
Dylan Baker 2d201af326 libpkgconf: Add a helper to zero `pkgconf_list_t`s 2022-06-26 03:12:34 +00:00
Ariadne Conill 21ffd343e1 CI: woodpecker: use matrix builds 2022-06-26 03:11:36 +00:00
Ariadne Conill a441455bf4 CI: add woodpecker config 2022-06-26 03:11:36 +00:00
Ariadne Conill cf48b61a59 stdinc: include strings.h on POSIX 2022-02-21 04:42:26 -06:00
Ariadne Conill 40131312ec meson: check for strdup, strcasecmp, strncasecmp 2022-02-21 04:41:08 -06:00
Ariadne Conill cc4ccc1429 meson: use _BSD_SOURCE for checking for symbols 2022-02-21 04:39:49 -06:00
Ariadne Conill ac964d13f3
Merge pull request #240 from Tachi107/readme-meson
docs: mention Meson instead of CMake for Win build
2022-02-21 04:27:20 -06:00
Ariadne Conill 0995e49977
Merge branch 'master' into readme-meson 2022-02-21 04:27:11 -06:00
Ariadne Conill 820af53a2d
Merge pull request #241 from Olf0/patch-1
Re-do MR #235, i.e. the vanished commit fe98e1b
2022-02-21 04:25:48 -06:00
Ariadne Conill a45dbccc01
Merge pull request #242 from data-man/dirent_latest
Update dirent.h to latest
2022-02-21 04:25:36 -06:00
Ariadne Conill c6cfca6730
Merge pull request #245 from dcbaker/submit/remove-const
libpkgconf: remove const modifier from error_handler data pointer
2022-02-21 04:25:26 -06:00
Ariadne Conill aaabc2cb15
Merge pull request #246 from dcbaker/submit/personality-deinit
personality: use an unsigned to track initializations instead of a bool.
2022-02-21 04:25:14 -06:00
Dylan Baker c581e24a67 personality: use an unsigned to track initializations
Instead of a bool. The latter will result in de-initing leaving the
library unable to init again, which works out for the cli, but is
problematic for other consumers (meson++ and muon).

v2: - Add docs that the functions are not thread safe
2022-02-14 21:22:05 -08:00
Dylan Baker f5d6bb71f8 libpkgconf: remove const modifier from error_handler data pointer
Currently, the data pointer is `const void *`, which means that the
handler can't modify the data without casting away the constness.
2022-02-07 09:34:09 -08:00
data-man b132ce8317 Update dirent.h to latest 2022-01-08 10:55:28 +05:00
olf ae3a9c5440
Re-do MR #235, i.e. the vanished commit fe98e1b 2021-12-11 22:56:31 +01:00
Andrea Pappacoda 6109e06089
docs: mention Meson instead of CMake for Win build
Fixes #233
2021-12-11 14:49:19 +01:00
Dylan Baker 1044bb57ca meson: make use of override_dependency() if possible
This allows simplifying the subproject override to simply

```meson
dependency('libpkgconf')
```
2021-12-01 09:17:07 -06:00
Dylan Baker 72c59b89c6 meson: Add dependency for for libpkgconf
This allows others using libpkgconf as a dependency to do use this as a
subproject. They can write something like:

```meson
dependency('libpkgconf', fallback : ['libpkgconf', 'dep_libpkgconf'])
```

Then install a wrap file for libpkgconf and build it as part of their
project.
2021-12-01 09:17:07 -06:00
Mattias Hansson 8d9d3de6eb pkg.m4: PKG_CHECK_MODULES provides modversion
Projects using PKG_CHECK_MODULES wants to add dependency versions to
their binaries. Currently, the projects have to resolve dependency
versions themselves when using pkgconf.

With this patch PKG_CHECK_MODULES now defines a $PKG_VERSION variable
that represents `--modversion`.
2021-10-27 06:41:28 -05:00
Mattias Hansson 360a818f2f pkg.m4: Unified indentation in PKG_CHECK_MODULES
Currently the indentation in PKG_CHECK_MODULES is a mix och tabs and
spaces which makes it hard to read. This patch unifies the indentation
in the function to spaces.
2021-10-27 06:41:28 -05:00
Ariadne Conill f3049d634d README: note that --debug output should not be considered stable 2021-10-25 21:52:52 -06:00
Ariadne Conill bf933903aa hackfix a couple of flaky tests 2021-10-07 01:29:29 -06:00
Ariadne Conill 2b82a4f63e use a serial instead of PKGCONF_PKG_PROPF_SEEN 2021-10-07 00:27:32 -06:00
Ariadne Conill 7d8cc1e4ce dependency: add pkgconf_dependency_copy() 2021-10-06 13:13:34 -06:00
Ariadne Conill c547edd07f deconst the client on pkgconf_dependency_add() 2021-10-06 11:52:18 -06:00
Ariadne Conill 4144d506bb implement dependency refcounting 2021-10-06 11:48:37 -06:00
olf d87114068f Fix typo
verses -> versus
2021-10-06 12:30:49 -05:00
Ariadne Conill 8130dd159e dependency: add pkgconf_dependency_free_one 2021-10-06 11:29:18 -06:00
Ariadne Conill 2b390ea9cf add memory leak fix info to NEWS 2021-08-17 15:32:30 -06:00
Ariadne Conill 4b87e256d3 cache: clear package cache without using the refcounts 2021-08-17 15:29:55 -06:00
Ariadne Conill df1b671c83 dependency: use dependency match owner with pkgconf_pkg_unref() 2021-08-17 15:18:47 -06:00
Ariadne Conill 41bff10998 cli: ensure the client and cross-personality are cleaned up in all cases 2021-08-17 14:54:36 -06:00
Ariadne Conill f411e7e55b cli: free package resolution queue unconditionally 2021-08-17 14:47:10 -06:00
Ariadne Conill ce82e36c14 cli: fix memory leak when packages are not provided on the command line 2021-08-17 14:39:44 -06:00
Ariadne Conill cef30268e1 pkgconf 1.8.0. 2021-07-24 20:40:52 -06:00
Ariadne Conill a10a88ef64 tests: regress: disable sysroot_munge test for now, not working with distcheck 2021-07-24 20:39:29 -06:00
Ariadne Conill 2ed2b98e64 workflows: more distcheck fixes 2021-07-24 20:28:04 -06:00
Ariadne Conill 9b49eb2280 workflows: install xz package 2021-07-24 20:26:44 -06:00
Ariadne Conill 4d5b378f9e workflows: use distcheck instead of check for autotools tests 2021-07-24 20:25:15 -06:00
Ariadne Conill f3f7145963 NEWS: add updates for pkgconf 1.8.0 2021-07-24 20:19:46 -06:00
Ariadne Conill 78bcb17116 personality: do not perform path filtering on default SYSTEM_INCLUDE_PATHS and SYSTEM_LIBRARY_PATHS
This is not consistent with the way the personality files or environment variables
are handled.

Fixes #224.
2021-07-24 20:06:55 -06:00
Ariadne Conill 4e73e37d29 meson: fix non-static build 2021-07-24 19:56:46 -06:00
Ariadne Conill ceece2c195 pkg: fix up comment about issue #213 workaround 2021-07-24 19:47:33 -06:00
Ariadne Conill 76968a4f8d fix static builds on Windows with Meson
Fixes #222
2021-07-24 19:45:43 -06:00
Sandro Mani ed86f2dda3 Don't prepend sysroot_dir if pkg-config file lies outside of sysroot_dir 2021-07-24 20:43:58 -05:00
Ariadne Conill 9ea26eb913 README: expand on the pkg-config compatibility promise
A bunch of CMake developers, who apparently did not comprehend the previous
compatibility promise statement, decided to passive-aggressively demand we fix
their non-bug anyway.

Clarify in more detail what level of pkg-config compatibility we provide, and
mention that such passive-aggressive behaviour is considered a CoC violation.

Fixes #228.
2021-07-24 19:41:48 -06:00
Stone Tickle fa859bb045 close error_msgout if opened 2021-07-24 06:08:25 -05:00
Stone Tickle dba2600014 deinit personality in cli 2021-07-24 06:08:25 -05:00
Stone Tickle d688a7bd03 implement pkgconf_cross_personality_deinit 2021-07-24 06:08:25 -05:00
midipix 13fe4c8c58 pkgconf_pkg_parser_value_set(): fix code-path ordering bug.
Prior to this commit, the code path responsible for prefix redefinition
(motivated by --define-prefix or otherwise) was visited more than
once, specifically since the check ignored pkg->owner->prefix_varname.
2021-06-18 14:42:41 -05:00
Ariadne Conill 1f319c2608 we are moving to OFTC 2021-05-19 05:52:27 -05:00
orbea 2fdc5f0081 man: Document the --validate option. 2021-03-29 09:50:41 -08:00
Christoph Reiter 4f73f6a1d6 Rework path handling on native Windows
The current approach was to parse the .pc and, detect the prefix, throw
everything together and at the end replace all \ with / to not produce invalid
escape sequences.

This has the problem that escaping in .pc files is ignored and no longer
possible. Also in case the prefix path has a space in it the result would be
invalid because of missing escaping.

This changes the following things:

* We no longer normalize values at the end. Instead we assume .pc files use "/"
  as a directory separator or "\\", same format as under Unix. "\" alone no
  longer works. This shouldn't be a problem since most build tools produce .pc
  files with "/" like meson, cmake, autotools.

* When injecting the prefix at runtime we convert the prefix to use "/" and
  escape spaces so that in combination with the .pc content the result is a
  valid escaped path value again.

This patch has been used in MSYS2 for some months now.

See #212
2021-03-20 06:59:38 -08:00
Christoph Reiter 4be39c59fb Remove usage of cygwin_conv_path() under cygwin/msys
This converted Unix paths to Windows paths, but all cygwin tools
work with Unix paths so this shouldn't be needed.

There is one use case if you use a cygwin pkgconf with a non-cygwin toolchain,
but pkgconf works reasonable well natively now so this shouldn't be needed
anymore and more likely leads to problems and confusion.

Both cygwin and msys have patched this out already:
* https://cygwin.com/git-cygwin-packages/?p=git/cygwin-packages/pkgconf.git;a=blob;f=pkgconf.cygport;h=e5d003f3f3dfc9e374b916974018022ad8d68852;hb=HEAD#l55
* a4bce0c294/pkgconf/PKGBUILD (L26)
2021-03-20 06:58:53 -08:00
Ariadne Conill 458101e787 pkgconf 1.7.4. 2021-03-18 07:05:03 -06:00
Ariadne Conill dbb6a232e5 path: don't use PATH_MAX, use PKGCONF_ITEM_SIZE * 4 for realpath buffer 2021-03-18 06:56:55 -06:00
Ariadne Conill a4e8cf87ad remove sourcehut CI config 2021-03-18 06:52:55 -06:00
Ariadne Conill 9f6b2ced47 README: use github CI badge 2021-03-18 06:52:31 -06:00
Ariadne Conill 37b596ccda CI: fix alpine autotools CI 2021-03-18 06:49:16 -06:00
Ariadne Conill caaf4861cf CI: fix alpine CI 2021-03-18 06:48:07 -06:00
Ariadne Conill 00cc9a8caf CI: add alpine CI alongside debian CI 2021-03-18 06:46:09 -06:00
Ariadne Conill 599dfcb264 main: extend copyright notice to 2021 2021-03-18 06:42:57 -06:00
Ariadne Conill 402fd9fe1f add funding.yml 2021-03-18 06:38:24 -06:00
Ariadne Conill fd1b8ccca6 main: if PKG_CONFIG_FDO_SYSROOT_RULES is set, or DESTDIR matches PKG_CONFIG_SYSROOT_DIRS, disable the automatic sysroot rewriting
Closes #205.
2021-03-18 06:22:11 -06:00
Ariadne Conill b6c8f6fb0a NEWS: document --static --pure default on Windows (closes #207) 2021-03-18 06:05:48 -06:00
Ariadne Conill 008d706958 libpkgconf: personality: default: set want_default_static and want_default_pure to true on windows 2021-03-18 06:03:47 -06:00
Ariadne Conill f9531ce9fe add support for pkgconf_cross_personality_t.want_default_pure 2021-03-18 06:02:00 -06:00
Ariadne Conill 52d19e1b9e libpkgconf: fileio: pkgconf_fgetline(): handle quoted=true when a comment introduction is encountered
Fixes #215.
2021-03-18 05:45:41 -06:00
Ariadne Conill 347281ebfe tests: add fragment-comment testcase (ref #215) 2021-03-18 05:39:45 -06:00
Jeff Moguillansky dcf529b83d cli: add environment variable PKG_CONFIG_DONT_DEFINE_PREFIX
On Windows, pkgconf redefines the prefix by default.
This gives the user the option to disable this behavior via an environment variable.
The benefit of an environment variable is the user can change this behavior when
using a build system such as cmake or meson, which may not expose this
parameter to the user.
2021-02-06 14:06:04 -07:00
Ryan Scott ab404bc25b Fix #209
This commit fixes #209 by applying the suggestion from
https://github.com/pkgconf/pkgconf/issues/209#issuecomment-771609136.
2021-02-05 23:57:10 -07:00
Fabian Groffen 13a5d9a5f0 libpkgconf: path: supply buffer to realpath
To avoid a crash on some platforms (like Darwin 9) provide a buffer to
realpath(3).

Darwin 9 (last PPC target) documents realpath needs to be given a buffer
to the resolved_path argument large enough to hold PATH_MAX bytes.
With NULL argument it crashes.  Solaris makes no mention of
resolved_path to be allowed NULL, yet recent versions accept it and
malloc(3) accordingly.

Because the documentation explicitly mentions PATH_MAX being the limit
to what realpath(3) would write in resolved_path, switching to a static
buffer here doesn't limit resolution compared to dynamically allocating
a buffer by realpath(3).

While this change requires a bit more space on the stack, it avoids a
malloc/free sequence, and allows successful operation on (older)
platforms that lack support for dynamically allocating a return buffer
in realpath(3).

Signed-off-by: Fabian Groffen <grobian@gentoo.org>
2021-01-08 18:44:40 -05:00
Christoph Reiter 78a77dd497 meson: install README.md/AUTHORS to share/doc/pkgconf
To mirror what the autotools build does.
2020-11-28 19:42:00 -07:00
Christoph Reiter 0526364b85 meson: allow building a static version of libpkgconf
when using library() instead of shared_library() the user can decide
to build a shared or static version, or both. The default is still shared
as before.

This mirrors what the autotools based build sysstem can do.
2020-11-28 19:42:00 -07:00
Christoph Reiter a69bdfa28e meson: generate a .pc file for libpkgconf 2020-11-28 19:42:00 -07:00
Christoph Reiter de8fc9e438 meson: install headers into pkgconf/libpkgconf instead of just libpkgconf
To mirror what the autotools build does
2020-11-28 19:42:00 -07:00
Christoph Reiter 869f2a84d6 pkgconf_pkg_parser_version_func: fix whitespace detection
In case the version string has no whitespace then strcspn() returns
strlen() of the input, so whitespace is only found if len != strlen.

This fixes invalid warnings when parsing version fields.
2020-11-28 19:17:03 -07:00
Christoph Reiter b218cae5a9 Add CI for debian+meson/autotools
Builds and runs tests. Using Debian testing since the test framework
is only in testing right now.
2020-11-23 10:31:52 -07:00
Christoph Reiter 24589cddb0 Add basic CI for mingw-w64 32/64 bit
This only builds things with meson and no tests are run.
2020-11-23 04:13:05 -07:00
Ariadne Conill f418b997e5 configure: shift issue tracking back to github 2020-11-21 10:00:41 -07:00
orbea bd960e9d05 man: Silence pkgconf-personality.5 warning.
man: ./pkgconf-personality.5:97:2: WARNING: unusual Xr order: pc(5) after pkg.m4(7)
2020-08-09 20:22:14 -06:00
Ariadne Conill 1eeb4ee5c2 start NEWS for 1.7.4 2020-06-11 18:03:42 -06:00
Ariadne Conill 2a8bebf289 libpkgconf: path: rewrite DOS paths in non-cygwin case too 2020-06-11 18:00:56 -06:00
Tobias Stoeckmann 262a0c964f man: pkgconf: fixed typo
Fixed typo in it's vs its.
2020-06-10 00:20:36 -06:00
Tobias Stoeckmann f818a69b3d libpkgconf: pkg: fix out ouf boundary access
If a file with a matching "uninstalled" name exists but cannot be
parsed, an invalid memory area is accessed.

How to reproduce:
$ touch poc-uninstalled.pc
$ PKG_CONFIG_PATH=. pkgconf poc
2020-06-10 00:20:36 -06:00
Ariadne Conill ef135d819c meson: remove some autotools cruft 2020-06-02 18:58:00 -06:00
Ariadne Conill aca0674837 pkgconf 1.7.3. 2020-05-30 19:20:25 -06:00
Ariadne Conill 40726b14ac update NEWS 2020-05-30 19:20:25 -06:00
Ariadne Conill 354c87279b libpkgconf: tuple: fix truncation when no overflow occurs 2020-05-30 19:20:25 -06:00
Tobias Stoeckmann 5eb9cae009 libpkgconf: tuple: fix out of boundary write
This is the same issue which has been fixed in dependency code.

If a line contains a variable which is longer than PKGCONF_ITEM_SIZE,
then the varname buffer overflows.

The code itself still does not check if a closing } exists and
truncates variable names which are too long. Since these would
be functional changes and this commit is about a protection against
undefined behaviour on a language level, these changes are not
included.

Proof of concept:
$ echo "Description: poc" > poc.pc
$ echo "Version: 1" >> poc.pc
$ echo -n 'Name: ${'
$ dd if=/dev/zero bs=1 count=66535 | tr '\0' 'x' >> poc.pc
$ echo >> poc.pc
$ pkgconf poc.pc

On my Linux system, when compiled with gcc, the varname buffer overflows
directly into buf, which means that no crash can be notified.

It's easiest to figure out when adding strlen() and sizeof() output
as debug lines.
2020-05-30 19:09:24 -06:00
Tobias Stoeckmann 100bc605de libpkgconf: fragment: fix out of boundary write
fragment_quote adds quotation to fragments if needed. It allocates a
buffer and grows it as needed.

Unfortunately the dst pointer is not updated after a realloc, which
means that dst still points into the old memory area. Further writing
characters into that area leads to out of boundy writes.

Proof of concept:

$ cat > poc.pc << EOF
Name: poc
Description: poc
Version: 1
CFlags: -Ia
CFlags: -I%%%%%%%%%%%%%%%%%%%%b
CFlags: -I%%%%%%%%%%%%%%%%%%%%c
CFlags: -Id
EOF
$ pkgconf --cflags poc.pc

Most reliable attempt is to compile pkgconf with address sanitizer,
but this file should lead to an abort on a glibc system due to modified
chunk pointers (tested with Linux on amd64).

But since this is undefined behaviour, it depends on system details.
2020-05-30 19:05:53 -06:00
Ariadne Conill 7bd08a51bf update NEWS 2020-05-30 12:43:08 -06:00
Tobias Stoeckmann dc04193c48 libpkgconf: fragment: fix out of boundary read
Parsing a fragment which consists only of a single dash leads to
an out of boundary read. It duplicates the following entry which
is not expected behaviour if another fragment follows.

Proof of concept:

$ cat > poc.pc << "EOF"
Name: poc
Description: poc
Version: 1
Cflags: - -I/somewhere
EOF
$ PKG_CONFIG_PATH=. pkgconf --cflags poc
-I/somewhere -I/somewhere

If - is the last entry, it leads to an out of boundary read, which is
easy to see if pkgconf is compiled with address sanitizer.
2020-05-30 12:43:08 -06:00
Vincent Torri 42b355310f fix missing backslashes in paths on Windows
According to

https://docs.microsoft.com/fr-fr/windows/win32/fileio/naming-a-file

backslashes (with slashes) are a path separator, hence must no be
considered as an escape code.

The first fix, in argvsplit.c, disables this. But because of fragment_quote(),
the backslashes are doubled. Hence the second fix in fragment.c

With this pc file :

prefix=C:/Documents/msys2/opt/efl_64
libdir=${prefix}/lib
includedir=${prefix}/include

Name: eina
Description: efl: eina
Version: 1.24.99
Requires.private: iconv
Libs: -L${libdir} -leina -pthread -levil
Libs.private: -lpsapi -lole32 -lws2_32 -lsecur32 -luuid -lregex -lm
Cflags:-I${includedir}/eina-1 -I${includedir}/efl-1
-I${includedir}/eina-1/eina -pthread

pkgconf.exe --cflags eina

returns :

-IC:\Documents\msys2\opt\efl_64/include/eina-1
-IC:\Documents\msys2\opt\efl_64/include/efl-1
-IC:\Documents\msys2\opt\efl_64/include/eina-1/eina -pthread
-DWINICONV_CONST= -IC:\Documents\msys2\opt\ewpi_64/include
2020-05-30 12:39:43 -06:00
Ariadne Conill e3e89926b5 start NEWS for 1.7.3 2020-05-26 14:04:34 -06:00
Tobias Stoeckmann fb9acedcad libpkgconf: dependency: fix out of boundary write
It is possible to trigger an out of boundary write in function
pkgconf_dependency_parse_str if a dependency line contains a very
long comparator. The comparator is stored in a temporary buffer which
has a size of PKGCONF_ITEM_SIZE.

The line which is parsed can be up to PKGCONF_BUFSIZE characters long,
which is larger than PKGCONF_ITEM_SIZE (although it depends on PATH_MAX).

Having a comparator which is longer than PKGCONF_ITEM_SIZE therefore
leads to an out of boundary write. Although it is undefined behaviour,
this can lead to an overridden compare variable, which in turn can lead
to an invalid instruction pointer, i.e. most likely a crash or code
execution (very unlikely).

Proof of concept:

$ echo "Requires: x " > poc.pc
$ dd if=/dev/zero bs=1 count=65535 | tr '\0' '<' >> poc.pc
$ pkgconf poc.pc

Eiter compile pkgconf with address sanitizer or run pkgconf multiple
times, eventually it might crash (assuming that ASLR is in place).

In order to fix this, I decided to use an end pointer to avoid OOB write.
Alternative would be to increase the buffer size, but I try to avoid that
since this would be additional ~60 KB stack space for a very unlikely
situation.
2020-05-26 14:03:55 -06:00
Ariadne Conill c6b93941a0 pkgconf 1.7.2. 2020-05-26 13:46:20 -06:00
Ariadne Conill c613eb5cce libpkgconf: pkg: use a second pointer for demunging windows paths 2020-05-26 13:42:39 -06:00
Ariadne Conill 92b09aef9a pkgconf 1.7.1. 2020-05-26 11:06:35 -06:00
Ariadne Conill e70b536ea3 libpkgconf: pkg: when generating a search path, use the correct path separator
Before, this could result in generated paths like C:\foo\pkgconfig/bar.pc on Windows.
2020-05-26 11:01:46 -06:00
Ariadne Conill 47466470d2 main: extend copyright statement to 2020 in --about 2020-05-26 10:57:51 -06:00
Ariadne Conill ee1fe1a70a update NEWS for 1.7.1 changes so far 2020-05-26 07:49:15 -06:00
Ariadne Conill 0253fddc1d libpkgconf: pkg: fix computation of pkgconf_pkg_t.id on Windows.
Windows allows both \ and / as valid path characters.  A computed path
such as C:\development\libfoo\pkgconfig/foo.pc will result in a computed
pkgconf_pkg_t.id of "pkgconfig/foo".

Accordingly, correct the path normalization for checking for / after
the \ path has been dealt with in all cases.
2020-05-26 07:41:16 -06:00
Neal Gompa be6b382dde Makefile.am: Add remaining Meson files to be included in dist tarballs
The tarballs produced by 'make distcheck' did not include all files
required for using Meson because they were not all enumerated in
EXTRA_DIST.

This change adds the remaining Meson files to the tarball.
2020-05-25 05:59:35 -06:00
Tobias Stoeckmann 9e16d2709c libpkgconf: personality: fix out of boundary access
It is possible to set the instruction pointer to undefined values by
using an operator larger than ':' in ASCII.

Since the personality function array does not have 256 entries, an
invalid operator can overflow the array.

Proof of concept:

$ echo "a _ b" > poc
$ ln -s $(which pkgconf) poc-pkgconf
$ ./poc-pkgconf
2020-05-25 05:55:39 -06:00
Ariadne Conill dd57abfe9f pkgconf 1.7.0. 2020-05-24 14:55:02 -06:00
Ariadne Conill 82d57184e7 meson: fix detection of strndup() on windows 2020-05-24 14:54:58 -06:00
Ariadne Conill 4fb7683c3e add support for the PKGCONF_PKG_PKGF_DONT_MERGE_SPECIAL_FRAGMENTS flag used in build2. 2020-05-24 14:40:47 -06:00
Ariadne Conill fb9c2258d1 update NEWS for previous patch 2020-05-24 14:37:13 -06:00
Ben 011db1bb88 Do not complain about malformed whitespace from \n on Version line
Every version line has a newline at the end; the malformed whitespace checker
should just check for trailing spaces and tabs.

Resolves https://todo.sr.ht/~kaniini/pkgconf/15
2020-05-24 14:36:46 -06:00
Ariadne Conill fce1199b53 cli: add support for PKG_CONFIG_MSVC_SYNTAX env variable
Patch from Dan Kegel.
2020-05-24 14:34:17 -06:00
Olaf Hering cdc2bf887e use correct autoconf macro name
AC_CONFIG_MACRO_DIR without trailing S is known by autoconf since 2.58.
AC_CONFIG_MACRO_DIR with trailing S is known by autoconf newer than 2.69.

This fixes libtool after 'autoreconf -fi'.

Fixes commit a8a65c7f6c
Related to issue #145

Signed-off-by: Olaf Hering <olaf@aepfle.de>
2020-05-24 14:29:19 -06:00
Ariadne Conill 80508f7138 NEWS: start NEWS for 1.7.0
was hoping to go straight into 2.0 but we need a new maintenance
branch :(
2020-05-24 14:27:52 -06:00
Ariadne Conill 382a89c173 pkg: pkgconf_compare_version(): do not return levenshtein distance in strcmp() case 2020-05-24 14:18:16 -06:00
Tobias Stoeckmann 92745ad9cb libpkgconf: parser: fix out of boundary access
It is possible to trigger an out of boundary access with specially
crafted files. If a line consist of only a key and spaces, then
op will point to '\0'-ending of the buffer. Since p is iterated by
one byte right past this ending '\0', the next read access to p is
effectively out of bounds.

Theoretically this can also lead to out of boundary writes if spaces
are encountered.

Proof of concept (I recommend to compile with address sanitizer):

$ echo -n a > poc.pc
$ dd if=/dev/zero bs=1 count=65533 | tr '\0' ' ' >> poc.pc
$ pkgconf poc.pc
2020-05-24 14:10:18 -06:00
Tobias Stoeckmann bd4ed1ca02 libpkgconf: fileio: prevent buffer overflow.
pkgconf_fgetline is called with a user-defined buffer, its size, and
a FILE stream to read input from.

If the buffer is almost completely filled and the file stream contains
an escaped character, then it is possible to trigger an off-by-one
buffer overflow with a '\0' character.

Easiest example to trigger this:

char buf[2];
pkgconf_fgetline(buf, sizeof(buf), stdin);

Enter "\\" (two backslashes) and press enter. If the library and the
program are compiled with address sanitizer, you will see the program
crashing. Otherwise it depends on your architecture what happens.

Since nobody should be using a buffer of only size 1 or 2, keep enough
space for a possibly escaped character in while loop by subtracting one
more byte for this situation, not just for '\0'.
2020-05-24 14:09:44 -06:00
Ariadne Conill 62bbd3b664 cli: remove --version to --modversion remapping
This has been a source of frequent complaints, so we drop it.
Resolves: https://todo.sr.ht/~kaniini/pkgconf/6
2020-01-21 10:32:36 -06:00
Ariadne Conill 48dc665ae3 personality: add support for WantDefaultStatic setting 2019-10-19 00:56:17 -05:00
Ariadne Conill 40fe48355b cli: main: add --shared option 2019-10-19 00:46:32 -05:00
Ariadne Conill f1ce393632 fix pkgconf-personality man page 2019-09-30 05:22:21 -05:00
Ariadne Conill 2adafc2729 libpkgconf: personality: return the default personality if loading a personality file failed 2019-08-23 12:48:11 -05:00
78 changed files with 3358 additions and 1398 deletions

View File

@ -1,23 +0,0 @@
image: alpine/edge
packages:
- build-base
- autoconf
- automake
- libtool
- kyua
- atf
- xz
- gzip
sources:
- https://git.sr.ht/~kaniini/pkgconf
tasks:
- autogen: |
cd ~/pkgconf
sh autogen.sh
- configure: |
cd ~/pkgconf
./configure
- distcheck: |
cd ~/pkgconf
make distcheck

View File

@ -1,25 +0,0 @@
image: fedora/rawhide
packages:
- make
- kernel-devel
- gcc
- gcc-c++
- autoconf
- automake
- libtool
- kyua
- libatf-sh
- xz
- gzip
sources:
- https://git.sr.ht/~kaniini/pkgconf
tasks:
- autogen: |
cd ~/pkgconf
sh autogen.sh
- configure: |
cd ~/pkgconf
./configure
- distcheck: |
cd ~/pkgconf
make distcheck

View File

@ -1,19 +0,0 @@
image: freebsd/latest
packages:
- autoconf
- automake
- libtool
- kyua
- atf
sources:
- https://git.sr.ht/~kaniini/pkgconf
tasks:
- autogen: |
cd ~/pkgconf
sh autogen.sh
- configure: |
cd ~/pkgconf
./configure
- distcheck: |
cd ~/pkgconf
make distcheck

View File

@ -1,17 +0,0 @@
image: alpine/edge
packages:
- build-base
- meson
- ninja
- kyua
- atf
sources:
- https://git.sr.ht/~kaniini/pkgconf
tasks:
- configure: |
cd ~/pkgconf
meson build
- distcheck: |
cd ~/pkgconf
ninja -C build
ninja -C build test

View File

@ -1,16 +0,0 @@
image: fedora/rawhide
packages:
- meson
- ninja-build
- kyua
- libatf-sh
sources:
- https://git.sr.ht/~kaniini/pkgconf
tasks:
- configure: |
cd ~/pkgconf
meson build
- distcheck: |
cd ~/pkgconf
ninja -C build
ninja -C build test

View File

@ -1,16 +0,0 @@
image: freebsd/latest
packages:
- meson
- ninja
- kyua
- atf
sources:
- https://git.sr.ht/~kaniini/pkgconf
tasks:
- configure: |
cd ~/pkgconf
meson build
- distcheck: |
cd ~/pkgconf
ninja -C build
ninja -C build test

3
.github/FUNDING.yml vendored Normal file
View File

@ -0,0 +1,3 @@
github: kaniini
patreon: kaniini
liberapay: kaniini

153
.github/workflows/test.yml vendored Normal file
View File

@ -0,0 +1,153 @@
name: test
on:
push:
pull_request:
jobs:
msys2:
runs-on: windows-latest
strategy:
fail-fast: false
matrix:
include: [
{ msystem: MINGW64, arch: x86_64},
{ msystem: MINGW32, arch: i686}
]
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: setup-msys2
uses: msys2/setup-msys2@v2
with:
msystem: ${{ matrix.msystem }}
update: true
install: >-
mingw-w64-${{ matrix.arch }}-meson
mingw-w64-${{ matrix.arch }}-ninja
mingw-w64-${{ matrix.arch }}-gcc
- name: Build
shell: msys2 {0}
run: |
# the code assumes msvc style printf atm
export CFLAGS=-D__USE_MINGW_ANSI_STDIO=0
meson -Dtests=disabled _build
meson compile -C _build
debian-meson:
runs-on: ubuntu-latest
container:
image: debian:testing
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Update system and add dependencies
run: |
apt-get update
apt-get install -y kyua atf-sh build-essential meson
- name: Build
run: |
meson _build -Dwerror=true
meson compile -C _build
- name: Run tests
run: |
meson test -v -C _build
debian-meson-asan:
runs-on: ubuntu-latest
container:
image: debian:testing
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Update system and add dependencies
run: |
apt-get update
apt-get install -y kyua atf-sh build-essential meson
- name: Build
run: |
meson _build -Db_sanitize=address
meson compile -C _build
- name: Run tests
run: |
meson test -v -C _build
env:
ASAN_OPTIONS: "exitcode=7"
debian-autotools:
runs-on: ubuntu-latest
container:
image: debian:testing
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Update system and add dependencies
run: |
apt-get update
apt-get install -y kyua atf-sh build-essential autoconf libtool
- name: Build
run: |
./autogen.sh
./configure
make -j9
- name: Run tests
run: |
make distcheck
alpine-meson:
runs-on: ubuntu-latest
container:
image: alpine
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Update system and add dependencies
run: |
apk update
apk add kyua atf build-base meson
- name: Build
run: |
meson _build -Dwerror=true
meson compile -C _build
- name: Run tests
run: |
meson test -v -C _build
alpine-autotools:
runs-on: ubuntu-latest
container:
image: alpine
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Update system and add dependencies
run: |
apk update
apk add kyua atf build-base autoconf automake libtool xz gzip
- name: Build
run: |
./autogen.sh
./configure
make -j9
- name: Run tests
run: |
make distcheck

75
.woodpecker.yml Normal file
View File

@ -0,0 +1,75 @@
pipeline:
debian-meson:
image: debian:testing
commands:
- apt-get update
- apt-get install -y kyua atf-sh build-essential meson
- meson _build -Dwerror=true
- meson compile -C _build
- meson test -v -C _build
when:
matrix:
IMAGE: debian
BUILD: meson
debian-meson-asan:
image: debian:testing
environment:
- ASAN_OPTIONS="exitcode=7"
commands:
- apt-get update
- apt-get install -y kyua atf-sh build-essential meson
- meson _build -Db_sanitize=address
- meson compile -C _build
- meson test -v -C _build
when:
matrix:
IMAGE: debian
BUILD: meson
debian-autotools:
image: debian:testing
commands:
- apt-get update
- apt-get install -y kyua atf-sh build-essential autoconf libtool
- ./autogen.sh
- ./configure
- make -j
- make distcheck
when:
matrix:
IMAGE: debian
BUILD: autotools
alpine-meson:
image: alpine
commands:
- apk add -U --no-cache kyua atf build-base meson
- meson _build -Dwerror=true
- meson compile -C _build
- meson test -v -C _build
when:
matrix:
IMAGE: alpine
BUILD: meson
alpine-autotools:
image: alpine
commands:
- apk add -U --no-cache kyua atf build-base autoconf automake libtool xz gzip
- ./autogen.sh
- ./configure
- make -j
- make distcheck
when:
matrix:
IMAGE: alpine
BUILD: autotools
matrix:
IMAGE:
- debian
- alpine
BUILD:
- meson
- autotools

View File

@ -11,14 +11,18 @@ nodist_pkgconfig_DATA = libpkgconf.pc
AM_CFLAGS = -DPERSONALITY_PATH=\"$(personality_dir)\" -DPKG_DEFAULT_PATH=\"$(pkg_default_dir)\" -DSYSTEM_INCLUDEDIR=\"$(system_includedir)\" -DSYSTEM_LIBDIR=\"$(system_libdir)\" AM_CFLAGS = -DPERSONALITY_PATH=\"$(personality_dir)\" -DPKG_DEFAULT_PATH=\"$(pkg_default_dir)\" -DSYSTEM_INCLUDEDIR=\"$(system_includedir)\" -DSYSTEM_LIBDIR=\"$(system_libdir)\"
bin_PROGRAMS = pkgconf bin_PROGRAMS = pkgconf bomtool
lib_LTLIBRARIES = libpkgconf.la lib_LTLIBRARIES = libpkgconf.la
EXTRA_DIST = pkg.m4 \ EXTRA_DIST = pkg.m4 \
meson.build \ meson.build \
meson_options.txt \
libpkgconf/meson.build \
libpkgconf/config.h.meson \
libpkgconf/win-dirent.h \ libpkgconf/win-dirent.h \
tests/lib-relocatable/lib/pkgconfig/foo.pc \ tests/lib-relocatable/lib/pkgconfig/foo.pc \
tests/lib1/argv-parse-2.pc \ tests/lib1/argv-parse-2.pc \
tests/lib1/billion-laughs.pc \
tests/lib1/dos-lineendings.pc \ tests/lib1/dos-lineendings.pc \
tests/lib1/paren-quoting.pc \ tests/lib1/paren-quoting.pc \
tests/lib1/argv-parse-3.pc \ tests/lib1/argv-parse-3.pc \
@ -58,6 +62,7 @@ EXTRA_DIST = pkg.m4 \
tests/lib3/bar.pc \ tests/lib3/bar.pc \
tests/lib1/conflicts.pc \ tests/lib1/conflicts.pc \
tests/lib1/omg-uninstalled.pc \ tests/lib1/omg-uninstalled.pc \
tests/lib1/omg-sysroot-uninstalled.pc \
tests/lib1/isystem.pc \ tests/lib1/isystem.pc \
tests/lib1/idirafter.pc \ tests/lib1/idirafter.pc \
tests/lib1/idirafter-ordering.pc \ tests/lib1/idirafter-ordering.pc \
@ -73,6 +78,7 @@ EXTRA_DIST = pkg.m4 \
tests/lib1/fragment-collision-intermediary.pc \ tests/lib1/fragment-collision-intermediary.pc \
tests/lib1/fragment-collision-1.pc \ tests/lib1/fragment-collision-1.pc \
tests/lib1/fragment-collision-2.pc \ tests/lib1/fragment-collision-2.pc \
tests/lib1/fragment-comment.pc \
tests/lib1/fragment-escaping-1.pc \ tests/lib1/fragment-escaping-1.pc \
tests/lib1/fragment-escaping-2.pc \ tests/lib1/fragment-escaping-2.pc \
tests/lib1/fragment-escaping-3.pc \ tests/lib1/fragment-escaping-3.pc \
@ -84,6 +90,9 @@ EXTRA_DIST = pkg.m4 \
tests/lib1/malformed-1.pc \ tests/lib1/malformed-1.pc \
tests/lib1/malformed-quoting.pc \ tests/lib1/malformed-quoting.pc \
tests/lib1/malformed-version.pc \ tests/lib1/malformed-version.pc \
tests/lib1/metapackage.pc \
tests/lib1/metapackage-1.pc \
tests/lib1/metapackage-2.pc \
tests/lib1/explicit-sysroot.pc \ tests/lib1/explicit-sysroot.pc \
tests/lib1/escaped-backslash.pc \ tests/lib1/escaped-backslash.pc \
tests/lib1/cflags-internal.pc \ tests/lib1/cflags-internal.pc \
@ -94,6 +103,10 @@ EXTRA_DIST = pkg.m4 \
tests/lib1/tuple-quoting.pc \ tests/lib1/tuple-quoting.pc \
tests/lib1/empty-tuple.pc \ tests/lib1/empty-tuple.pc \
tests/lib1/orphaned-requires-private.pc \ tests/lib1/orphaned-requires-private.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 \
$(test_scripts) \ $(test_scripts) \
doc/conf.py \ doc/conf.py \
doc/extract.py \ doc/extract.py \
@ -122,7 +135,8 @@ test_scripts= tests/meson.build \
tests/sysroot.sh \ tests/sysroot.sh \
tests/version.sh tests/version.sh
check_SCRIPTS= $(test_scripts:.sh=) test_sh = $(filter-out tests/meson.build, $(test_scripts))
check_SCRIPTS = $(test_sh:.sh=)
SUFFIXES= .sh SUFFIXES= .sh
@ -142,7 +156,7 @@ libpkgconf_la_SOURCES = \
libpkgconf/path.c \ libpkgconf/path.c \
libpkgconf/personality.c \ libpkgconf/personality.c \
libpkgconf/parser.c libpkgconf/parser.c
libpkgconf_la_LDFLAGS = -no-undefined -version-info 3:0:0 -export-symbols-regex '^pkgconf_' libpkgconf_la_LDFLAGS = -no-undefined -version-info 4:0:0 -export-symbols-regex '^pkgconf_'
dist_man_MANS = \ dist_man_MANS = \
man/pkgconf.1 \ man/pkgconf.1 \
@ -155,11 +169,17 @@ pkgconf_SOURCES = \
cli/main.c \ cli/main.c \
cli/getopt_long.c \ cli/getopt_long.c \
cli/renderer-msvc.c cli/renderer-msvc.c
pkgconf_CPPFLAGS = -Ilibpkgconf -Icli pkgconf_CPPFLAGS = -I$(top_srcdir)/libpkgconf -I$(top_srcdir)/cli
noinst_HEADERS = \ noinst_HEADERS = \
cli/getopt_long.h \ cli/getopt_long.h \
cli/renderer-msvc.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 dist_doc_DATA = README.md AUTHORS
m4datadir = $(datadir)/aclocal m4datadir = $(datadir)/aclocal

213
NEWS
View File

@ -1,6 +1,219 @@
Changes from previous version of pkgconf Changes from previous version of pkgconf
======================================== ========================================
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: Changes from 1.6.2 to 1.6.3:
---------------------------- ----------------------------

View File

@ -1,11 +1,11 @@
# pkgconf [![builds.sr.ht status](https://builds.sr.ht/~kaniini/pkgconf.svg)](https://builds.sr.ht/~kaniini/pkgconf?) # 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 `pkgconf` is a program which helps to configure compiler and linker flags for
development libraries. It is similar to pkg-config from freedesktop.org. development libraries. It is similar to pkg-config from freedesktop.org.
`libpkgconf` is a library which provides access to most of `pkgconf`'s functionality, to allow `libpkgconf` is a library which provides access to most of `pkgconf`'s functionality,
other tooling such as compilers and IDEs to discover and use libraries configured by to allow other tooling such as compilers and IDEs to discover and use libraries
pkgconf. configured by pkgconf.
## using `pkgconf` with autotools ## using `pkgconf` with autotools
@ -41,7 +41,7 @@ to improve this behaviour.
As of the 1.1 series, pkgconf also fully implements support for `Provides` rules, As of the 1.1 series, pkgconf also fully implements support for `Provides` rules,
while pkg-config does not. pkg-config only provides the `--print-provides` functionality while pkg-config does not. pkg-config only provides the `--print-provides` functionality
as a stub. There are other intentional implementation differences in pkgconf's dependency as a stub. There are other intentional implementation differences in pkgconf's dependency
resolver verses pkg-config's dependency resolver in terms of completeness and correctness, resolver versus pkg-config's dependency resolver in terms of completeness and correctness,
such as, for example, how `Conflicts` rules are processed. such as, for example, how `Conflicts` rules are processed.
## linker flags optimization ## linker flags optimization
@ -60,6 +60,10 @@ Doing so is discouraged by the [freedesktop tutorial][fd-tut] anyway.
## compatibility with pkg-config ## compatibility with pkg-config
I really hate that I have to have this section, I like being a nice person, but we
unfortunately have to say this because otherwise we get passive-aggressive people who
try to argue with us about what pkg-config compatibility means.
We do not provide bug-level compatibility with pkg-config. 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, What that means is, if you feel that there is a legitimate regression versus pkg-config,
@ -67,6 +71,26 @@ do let us know, but also make sure that the .pc files are valid and follow the r
the [pkg-config tutorial][fd-tut], as most likely fixing them to follow the specified the [pkg-config tutorial][fd-tut], as most likely fixing them to follow the specified
rules will solve the problem. rules will solve the problem.
Additionally, **we do not consider pkgconf doing what you tell it to do, in cases for
which pkg-config fails to do so, to be a bug**.
If, for example, you use environment variables such as `PKG_CONFIG_SYSTEM_[INCLUDE|LIBRARY]_PATH`
and then find yourself surprised that `pkgconf` is stripping `-I` and `-L` flags relating
to those paths, it is not a `pkgconf` problem -- `pkgconf` is doing exactly what you told
it to do.
We will reject bugs like this, and if someone insists on fixing such a non-bug, this
constitutes a violation of our [Code of Conduct](CODE_OF_CONDUCT.md), which may be
addressed by banning from this repository.
## 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 ## compiling `pkgconf` and `libpkgconf` on UNIX
pkgconf is basically compiled the same way any other autotools-based project is pkgconf is basically compiled the same way any other autotools-based project is
@ -88,17 +112,16 @@ flags like so:
$ make $ make
$ sudo make install $ sudo make install
## compiling `pkgconf` and `libpkgconf` with CMake (usually for Windows) ## compiling `pkgconf` and `libpkgconf` with Meson (usually for Windows)
pkgconf is compiled using CMake on Windows. In theory, you could also use CMake to build
on UNIX, but this is not recommended at this time as it pkgconf is typically built much earlier
than CMake.
$ mkdir build pkgconf is compiled using [Meson](https://mesonbuild.com) on Windows. In theory, you could also use
$ cd build Meson to build on UNIX, but this is not recommended at this time as it pkgconf is typically built
$ cmake .. much earlier than Meson.
$ make
$ sudo make install $ 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. 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 However, on Windows, the default PKGCONFIGDIR value is usually overridden at runtime based
@ -119,8 +142,8 @@ Please only use the tarballs from distfiles.dereferenced.org.
## contacts ## contacts
You can report bugs at <https://todo.sr.ht/~kaniini/pkgconf>. You can report bugs at <https://github.com/pkgconf/pkgconf/issues>.
There is a mailing list at <https://lists.sr.ht/~kaniini/pkgconf>. There is a mailing list at <https://lists.sr.ht/~kaniini/pkgconf>.
You can contact us via IRC at `#pkgconf` at `irc.freenode.net`. You can contact us via IRC at `#pkgconf` at `irc.oftc.net`.

365
cli/bomtool/main.c Normal file
View File

@ -0,0 +1,365 @@
/*
* 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->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;
}

View File

@ -69,6 +69,8 @@
#define PKG_MSVC_SYNTAX (((uint64_t) 1) << 41) #define PKG_MSVC_SYNTAX (((uint64_t) 1) << 41)
#define PKG_INTERNAL_CFLAGS (((uint64_t) 1) << 42) #define PKG_INTERNAL_CFLAGS (((uint64_t) 1) << 42)
#define PKG_DUMP_PERSONALITY (((uint64_t) 1) << 43) #define PKG_DUMP_PERSONALITY (((uint64_t) 1) << 43)
#define PKG_SHARED (((uint64_t) 1) << 44)
#define PKG_DUMP_LICENSE (((uint64_t) 1) << 45)
static pkgconf_client_t pkg_client; static pkgconf_client_t pkg_client;
static const pkgconf_fragment_render_ops_t *want_render_ops = NULL; static const pkgconf_fragment_render_ops_t *want_render_ops = NULL;
@ -84,7 +86,7 @@ FILE *error_msgout = NULL;
FILE *logfile_out = NULL; FILE *logfile_out = NULL;
static bool static bool
error_handler(const char *msg, const pkgconf_client_t *client, const void *data) error_handler(const char *msg, const pkgconf_client_t *client, void *data)
{ {
(void) client; (void) client;
(void) data; (void) data;
@ -345,16 +347,6 @@ apply_path(pkgconf_client_t *client, pkgconf_pkg_t *world, void *unused, int max
return true; return true;
} }
static void
print_variable(pkgconf_client_t *client, pkgconf_pkg_t *pkg, const char *variable)
{
const char *var;
var = pkgconf_tuple_find(client, &pkg->vars, variable);
if (var != NULL)
printf("%s", var);
}
static bool static bool
apply_variable(pkgconf_client_t *client, pkgconf_pkg_t *world, void *variable, int maxdepth) apply_variable(pkgconf_client_t *client, pkgconf_pkg_t *world, void *variable, int maxdepth)
{ {
@ -365,11 +357,12 @@ apply_variable(pkgconf_client_t *client, pkgconf_pkg_t *world, void *variable, i
{ {
pkgconf_dependency_t *dep = iter->data; pkgconf_dependency_t *dep = iter->data;
pkgconf_pkg_t *pkg = dep->match; pkgconf_pkg_t *pkg = dep->match;
const char *var;
if (iter->prev != NULL) var = pkgconf_tuple_find(client, &pkg->vars, variable);
printf(" ");
print_variable(client, pkg, variable); if (var != NULL)
printf("%s%s", iter->prev != NULL ? " " : "", var);
} }
printf("\n"); printf("\n");
@ -414,7 +407,8 @@ apply_env(pkgconf_client_t *client, pkgconf_pkg_t *world, void *env_prefix_p, in
char workbuf[PKGCONF_ITEM_SIZE]; char workbuf[PKGCONF_ITEM_SIZE];
for (it = want_env_prefix; *it != '\0'; it++) for (it = want_env_prefix; *it != '\0'; it++)
if (!isalpha(*it) && !isdigit(*it)) if (!isalpha((unsigned char)*it) &&
!isdigit((unsigned char)*it))
return false; return false;
snprintf(workbuf, sizeof workbuf, "%s_CFLAGS", want_env_prefix); snprintf(workbuf, sizeof workbuf, "%s_CFLAGS", want_env_prefix);
@ -592,6 +586,32 @@ apply_simulate(pkgconf_client_t *client, pkgconf_pkg_t *world, void *data, int m
} }
#endif #endif
static void
print_license(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data)
{
(void) client;
(void) data;
if (pkg->flags & PKGCONF_PKG_PROPF_VIRTUAL)
return;
/* NOASSERTION is the default when the license is unknown, per SPDX spec § 3.15 */
printf("%s: %s\n", pkg->id, pkg->license != NULL ? pkg->license : "NOASSERTION");
}
static bool
apply_license(pkgconf_client_t *client, pkgconf_pkg_t *world, void *data, int maxdepth)
{
int eflag;
eflag = pkgconf_pkg_traverse(client, world, print_license, data, maxdepth, 0);
if (eflag != PKGCONF_PKG_ERRF_OK)
return false;
return true;
}
static void static void
version(void) version(void)
{ {
@ -602,7 +622,7 @@ static void
about(void) about(void)
{ {
printf("%s %s\n", PACKAGE_NAME, PACKAGE_VERSION); printf("%s %s\n", PACKAGE_NAME, PACKAGE_VERSION);
printf("Copyright (c) 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019\n"); 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(" pkgconf authors (see AUTHORS in documentation directory).\n\n");
printf("Permission to use, copy, modify, and/or distribute this software for any\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("purpose with or without fee is hereby granted, provided that the above\n");
@ -664,6 +684,7 @@ usage(void)
printf(" --maximum-traverse-depth maximum allowed depth for dependency graph\n"); printf(" --maximum-traverse-depth maximum allowed depth for dependency graph\n");
printf(" --static be more aggressive when computing dependency graph\n"); printf(" --static be more aggressive when computing dependency graph\n");
printf(" (for static linking)\n"); printf(" (for static linking)\n");
printf(" --shared use a simplified dependency graph (usually default)\n");
printf(" --pure optimize a static dependency graph as if it were a normal\n"); printf(" --pure optimize a static dependency graph as if it were a normal\n");
printf(" dependency graph\n"); printf(" dependency graph\n");
printf(" --env-only look only for package entries in PKG_CONFIG_PATH\n"); printf(" --env-only look only for package entries in PKG_CONFIG_PATH\n");
@ -694,6 +715,7 @@ usage(void)
printf(" --path show the exact filenames for any matching .pc files\n"); printf(" --path show the exact filenames for any matching .pc files\n");
printf(" --modversion print the specified module's version to stdout\n"); printf(" --modversion print the specified module's version to stdout\n");
printf(" --internal-cflags do not filter 'internal' cflags from output\n"); printf(" --internal-cflags do not filter 'internal' cflags from output\n");
printf(" --license print the specified module's license to stdout if known\n");
printf("\nfiltering output:\n\n"); printf("\nfiltering output:\n\n");
#ifndef PKGCONF_LITE #ifndef PKGCONF_LITE
@ -799,7 +821,13 @@ main(int argc, char *argv[])
char *logfile_arg = NULL; char *logfile_arg = NULL;
char *want_env_prefix = NULL; char *want_env_prefix = NULL;
unsigned int want_client_flags = PKGCONF_PKG_PKGF_NONE; unsigned int want_client_flags = PKGCONF_PKG_PKGF_NONE;
pkgconf_cross_personality_t *personality; pkgconf_cross_personality_t *personality = NULL;
bool opened_error_msgout = false;
pkgconf_pkg_t world = {
.id = "virtual:world",
.realname = "virtual world package",
.flags = PKGCONF_PKG_PROPF_STATIC | PKGCONF_PKG_PROPF_VIRTUAL,
};
want_flags = 0; want_flags = 0;
@ -827,6 +855,7 @@ main(int argc, char *argv[])
{ "short-errors", no_argument, &want_flags, PKG_SHORT_ERRORS, }, { "short-errors", no_argument, &want_flags, PKG_SHORT_ERRORS, },
{ "maximum-traverse-depth", required_argument, NULL, 11, }, { "maximum-traverse-depth", required_argument, NULL, 11, },
{ "static", no_argument, &want_flags, PKG_STATIC, }, { "static", no_argument, &want_flags, PKG_STATIC, },
{ "shared", no_argument, &want_flags, PKG_SHARED, },
{ "pure", no_argument, &want_flags, PKG_PURE, }, { "pure", no_argument, &want_flags, PKG_PURE, },
{ "print-requires", no_argument, &want_flags, PKG_REQUIRES, }, { "print-requires", no_argument, &want_flags, PKG_REQUIRES, },
{ "print-variables", no_argument, &want_flags, PKG_VARIABLES|PKG_PRINT_ERRORS, }, { "print-variables", no_argument, &want_flags, PKG_VARIABLES|PKG_PRINT_ERRORS, },
@ -879,6 +908,7 @@ main(int argc, char *argv[])
{ "dump-personality", no_argument, &want_flags, PKG_DUMP_PERSONALITY }, { "dump-personality", no_argument, &want_flags, PKG_DUMP_PERSONALITY },
{ "personality", required_argument, NULL, 53 }, { "personality", required_argument, NULL, 53 },
#endif #endif
{ "license", no_argument, &want_flags, PKG_DUMP_LICENSE },
{ NULL, 0, NULL, 0 } { NULL, 0, NULL, 0 }
}; };
@ -890,12 +920,6 @@ main(int argc, char *argv[])
} }
#endif #endif
#ifndef PKGCONF_LITE
personality = deduce_personality(argv);
#else
personality = pkgconf_cross_personality_default();
#endif
while ((ret = pkg_getopt_long_only(argc, argv, "", options, NULL)) != -1) while ((ret = pkg_getopt_long_only(argc, argv, "", options, NULL)) != -1)
{ {
switch (ret) switch (ret)
@ -946,13 +970,21 @@ main(int argc, char *argv[])
#endif #endif
case '?': case '?':
case ':': case ':':
return EXIT_FAILURE; ret = EXIT_FAILURE;
break; goto out;
default: default:
break; break;
} }
} }
if (personality == NULL) {
#ifndef PKGCONF_LITE
personality = deduce_personality(argv);
#else
personality = pkgconf_cross_personality_default();
#endif
}
pkgconf_path_copy_list(&personality->dir_list, &dir_list); pkgconf_path_copy_list(&personality->dir_list, &dir_list);
pkgconf_path_free(&dir_list); pkgconf_path_free(&dir_list);
@ -968,7 +1000,7 @@ main(int argc, char *argv[])
pkgconf_client_init(&pkg_client, error_handler, NULL, personality); pkgconf_client_init(&pkg_client, error_handler, NULL, personality);
#ifndef PKGCONF_LITE #ifndef PKGCONF_LITE
if ((want_flags & PKG_MSVC_SYNTAX) == PKG_MSVC_SYNTAX) if ((want_flags & PKG_MSVC_SYNTAX) == PKG_MSVC_SYNTAX || getenv("PKG_CONFIG_MSVC_SYNTAX") != NULL)
want_render_ops = msvc_renderer_get(); want_render_ops = msvc_renderer_get();
#endif #endif
@ -997,31 +1029,33 @@ main(int argc, char *argv[])
if ((want_flags & PKG_ABOUT) == PKG_ABOUT) if ((want_flags & PKG_ABOUT) == PKG_ABOUT)
{ {
about(); about();
return EXIT_SUCCESS;
ret = EXIT_SUCCESS;
goto out;
} }
if ((want_flags & PKG_VERSION) == PKG_VERSION) if ((want_flags & PKG_VERSION) == PKG_VERSION)
{
if (argc > 2)
{
fprintf(stderr, "%s: --version specified with other options or module names, assuming --modversion.\n", argv[0]);
want_flags &= ~PKG_VERSION;
want_flags |= PKG_MODVERSION;
}
else
{ {
version(); version();
return EXIT_SUCCESS;
} ret = EXIT_SUCCESS;
goto out;
} }
if ((want_flags & PKG_HELP) == PKG_HELP) if ((want_flags & PKG_HELP) == PKG_HELP)
{ {
usage(); usage();
return EXIT_SUCCESS;
ret = EXIT_SUCCESS;
goto out;
} }
if (getenv("PKG_CONFIG_FDO_SYSROOT_RULES"))
want_client_flags |= PKGCONF_PKG_PKGF_FDO_SYSROOT_RULES;
if (getenv("PKG_CONFIG_PKGCONF1_SYSROOT_RULES"))
want_client_flags |= PKGCONF_PKG_PKGF_PKGCONF1_SYSROOT_RULES;
if ((want_flags & PKG_SHORT_ERRORS) == PKG_SHORT_ERRORS) if ((want_flags & PKG_SHORT_ERRORS) == PKG_SHORT_ERRORS)
want_client_flags |= PKGCONF_PKG_PKGF_SIMPLIFY_ERRORS; want_client_flags |= PKGCONF_PKG_PKGF_SIMPLIFY_ERRORS;
@ -1031,20 +1065,25 @@ main(int argc, char *argv[])
error_msgout = stderr; error_msgout = stderr;
if ((want_flags & PKG_ERRORS_ON_STDOUT) == PKG_ERRORS_ON_STDOUT) if ((want_flags & PKG_ERRORS_ON_STDOUT) == PKG_ERRORS_ON_STDOUT)
error_msgout = stdout; error_msgout = stdout;
if ((want_flags & PKG_SILENCE_ERRORS) == PKG_SILENCE_ERRORS) if ((want_flags & PKG_SILENCE_ERRORS) == PKG_SILENCE_ERRORS) {
error_msgout = fopen(PATH_DEV_NULL, "w"); error_msgout = fopen(PATH_DEV_NULL, "w");
opened_error_msgout = true;
}
if ((want_flags & PKG_IGNORE_CONFLICTS) == PKG_IGNORE_CONFLICTS || getenv("PKG_CONFIG_IGNORE_CONFLICTS") != NULL) if ((want_flags & PKG_IGNORE_CONFLICTS) == PKG_IGNORE_CONFLICTS || getenv("PKG_CONFIG_IGNORE_CONFLICTS") != NULL)
want_client_flags |= PKGCONF_PKG_PKGF_SKIP_CONFLICTS; want_client_flags |= PKGCONF_PKG_PKGF_SKIP_CONFLICTS;
if ((want_flags & PKG_STATIC) == PKG_STATIC) if ((want_flags & PKG_STATIC) == PKG_STATIC || personality->want_default_static)
want_client_flags |= (PKGCONF_PKG_PKGF_SEARCH_PRIVATE | PKGCONF_PKG_PKGF_MERGE_PRIVATE_FRAGMENTS); want_client_flags |= (PKGCONF_PKG_PKGF_SEARCH_PRIVATE | PKGCONF_PKG_PKGF_MERGE_PRIVATE_FRAGMENTS);
if ((want_flags & PKG_SHARED) == PKG_SHARED)
want_client_flags &= ~(PKGCONF_PKG_PKGF_SEARCH_PRIVATE | PKGCONF_PKG_PKGF_MERGE_PRIVATE_FRAGMENTS);
/* if --static and --pure are both specified, then disable merge-back. /* if --static and --pure are both specified, then disable merge-back.
* this allows for a --static which searches private modules, but has the same fragment behaviour as if * this allows for a --static which searches private modules, but has the same fragment behaviour as if
* --static were disabled. see <https://github.com/pkgconf/pkgconf/issues/83> for rationale. * --static were disabled. see <https://github.com/pkgconf/pkgconf/issues/83> for rationale.
*/ */
if ((want_flags & PKG_PURE) == PKG_PURE || getenv("PKG_CONFIG_PURE_DEPGRAPH") != NULL) if ((want_flags & PKG_PURE) == PKG_PURE || getenv("PKG_CONFIG_PURE_DEPGRAPH") != NULL || personality->want_default_pure)
want_client_flags &= ~PKGCONF_PKG_PKGF_MERGE_PRIVATE_FRAGMENTS; want_client_flags &= ~PKGCONF_PKG_PKGF_MERGE_PRIVATE_FRAGMENTS;
if ((want_flags & PKG_ENV_ONLY) == PKG_ENV_ONLY) if ((want_flags & PKG_ENV_ONLY) == PKG_ENV_ONLY)
@ -1066,23 +1105,17 @@ main(int argc, char *argv[])
if ((want_flags & PKG_NO_PROVIDES) == PKG_NO_PROVIDES) if ((want_flags & PKG_NO_PROVIDES) == PKG_NO_PROVIDES)
want_client_flags |= PKGCONF_PKG_PKGF_SKIP_PROVIDES; want_client_flags |= PKGCONF_PKG_PKGF_SKIP_PROVIDES;
if ((want_flags & PKG_DONT_DEFINE_PREFIX) == PKG_DONT_DEFINE_PREFIX) if ((want_flags & PKG_DONT_DEFINE_PREFIX) == PKG_DONT_DEFINE_PREFIX || getenv("PKG_CONFIG_DONT_DEFINE_PREFIX") != NULL)
want_client_flags &= ~PKGCONF_PKG_PKGF_REDEFINE_PREFIX; want_client_flags &= ~PKGCONF_PKG_PKGF_REDEFINE_PREFIX;
if ((want_flags & PKG_INTERNAL_CFLAGS) == PKG_INTERNAL_CFLAGS) if ((want_flags & PKG_INTERNAL_CFLAGS) == PKG_INTERNAL_CFLAGS)
want_client_flags |= PKGCONF_PKG_PKGF_DONT_FILTER_INTERNAL_CFLAGS; want_client_flags |= PKGCONF_PKG_PKGF_DONT_FILTER_INTERNAL_CFLAGS;
#ifdef XXX_NOTYET
/* if these selectors are used, it means that we are inquiring about a single package. /* if these selectors are used, it means that we are inquiring about a single package.
* so signal to libpkgconf that we do not want to use the dependency resolver for more than one level, * so signal to libpkgconf that we do not want to use the dependency resolver for more than one level,
* and also limit the SAT problem to a single package. * and also limit the SAT problem to a single package.
*
* i disabled this because too many upstream maintainers are still invoking pkg-config correctly to have
* the more sane behaviour as default. use --maximum-traverse-depth=1 or PKG_CONFIG_MAXIMUM_TRAVERSE_DEPTH
* environment variable to get the same results in meantime.
*/ */
if ((want_flags & PKG_EXISTS) == 0 && if (((want_flags & PKG_REQUIRES) == PKG_REQUIRES ||
((want_flags & PKG_REQUIRES) == PKG_REQUIRES ||
(want_flags & PKG_REQUIRES_PRIVATE) == PKG_REQUIRES_PRIVATE || (want_flags & PKG_REQUIRES_PRIVATE) == PKG_REQUIRES_PRIVATE ||
(want_flags & PKG_PROVIDES) == PKG_PROVIDES || (want_flags & PKG_PROVIDES) == PKG_PROVIDES ||
(want_flags & PKG_VARIABLES) == PKG_VARIABLES || (want_flags & PKG_VARIABLES) == PKG_VARIABLES ||
@ -1093,7 +1126,6 @@ main(int argc, char *argv[])
maximum_package_count = 1; maximum_package_count = 1;
maximum_traverse_depth = 1; maximum_traverse_depth = 1;
} }
#endif
if (getenv("PKG_CONFIG_ALLOW_SYSTEM_CFLAGS") != NULL) if (getenv("PKG_CONFIG_ALLOW_SYSTEM_CFLAGS") != NULL)
want_flags |= PKG_KEEP_SYSTEM_CFLAGS; want_flags |= PKG_KEEP_SYSTEM_CFLAGS;
@ -1104,9 +1136,25 @@ main(int argc, char *argv[])
if ((builddir = getenv("PKG_CONFIG_TOP_BUILD_DIR")) != NULL) if ((builddir = getenv("PKG_CONFIG_TOP_BUILD_DIR")) != NULL)
pkgconf_client_set_buildroot_dir(&pkg_client, builddir); pkgconf_client_set_buildroot_dir(&pkg_client, builddir);
if ((want_flags & PKG_REQUIRES_PRIVATE) == PKG_REQUIRES_PRIVATE ||
(want_flags & PKG_CFLAGS))
{
want_client_flags |= PKGCONF_PKG_PKGF_SEARCH_PRIVATE;
}
if ((sysroot_dir = getenv("PKG_CONFIG_SYSROOT_DIR")) != NULL) if ((sysroot_dir = getenv("PKG_CONFIG_SYSROOT_DIR")) != NULL)
{
const char *destdir;
pkgconf_client_set_sysroot_dir(&pkg_client, sysroot_dir); pkgconf_client_set_sysroot_dir(&pkg_client, sysroot_dir);
if ((destdir = getenv("DESTDIR")) != NULL)
{
if (!strcmp(destdir, sysroot_dir))
want_client_flags |= PKGCONF_PKG_PKGF_FDO_SYSROOT_RULES;
}
}
/* we have determined what features we want most likely. in some cases, we override later. */ /* we have determined what features we want most likely. in some cases, we override later. */
pkgconf_client_set_flags(&pkg_client, want_client_flags); pkgconf_client_set_flags(&pkg_client, want_client_flags);
@ -1116,21 +1164,25 @@ main(int argc, char *argv[])
if (required_pkgconfig_version != NULL) if (required_pkgconfig_version != NULL)
{ {
if (pkgconf_compare_version(PACKAGE_VERSION, required_pkgconfig_version) >= 0) if (pkgconf_compare_version(PACKAGE_VERSION, required_pkgconfig_version) >= 0)
return EXIT_SUCCESS; ret = EXIT_SUCCESS;
else
ret = EXIT_FAILURE;
return EXIT_FAILURE; goto out;
} }
if ((want_flags & PKG_LIST) == PKG_LIST) if ((want_flags & PKG_LIST) == PKG_LIST)
{ {
pkgconf_scan_all(&pkg_client, NULL, print_list_entry); pkgconf_scan_all(&pkg_client, NULL, print_list_entry);
return EXIT_SUCCESS; ret = EXIT_SUCCESS;
goto out;
} }
if ((want_flags & PKG_LIST_PACKAGE_NAMES) == PKG_LIST_PACKAGE_NAMES) if ((want_flags & PKG_LIST_PACKAGE_NAMES) == PKG_LIST_PACKAGE_NAMES)
{ {
pkgconf_scan_all(&pkg_client, NULL, print_package_entry); pkgconf_scan_all(&pkg_client, NULL, print_package_entry);
return EXIT_SUCCESS; ret = EXIT_SUCCESS;
goto out;
} }
if (logfile_arg == NULL) if (logfile_arg == NULL)
@ -1144,7 +1196,7 @@ main(int argc, char *argv[])
if (required_module_version != NULL) if (required_module_version != NULL)
{ {
pkgconf_pkg_t *pkg; pkgconf_pkg_t *pkg = NULL;
pkgconf_node_t *node; pkgconf_node_t *node;
pkgconf_list_t deplist = PKGCONF_LIST_INITIALIZER; pkgconf_list_t deplist = PKGCONF_LIST_INITIALIZER;
@ -1163,18 +1215,28 @@ main(int argc, char *argv[])
{ {
if (want_flags & PKG_PRINT_ERRORS) if (want_flags & PKG_PRINT_ERRORS)
pkgconf_error(&pkg_client, "Package '%s' was not found\n", pkgiter->package); pkgconf_error(&pkg_client, "Package '%s' was not found\n", pkgiter->package);
return EXIT_FAILURE;
ret = EXIT_FAILURE;
goto cleanup;
} }
if (pkgconf_compare_version(pkg->version, required_module_version) >= 0) if (pkgconf_compare_version(pkg->version, required_module_version) >= 0)
return EXIT_SUCCESS; {
ret = EXIT_SUCCESS;
goto cleanup;
}
} }
return EXIT_FAILURE; ret = EXIT_FAILURE;
cleanup:
if (pkg != NULL)
pkgconf_pkg_unref(&pkg_client, pkg);
pkgconf_dependency_free(&deplist);
goto out;
} }
else if (required_exact_module_version != NULL) else if (required_exact_module_version != NULL)
{ {
pkgconf_pkg_t *pkg; pkgconf_pkg_t *pkg = NULL;
pkgconf_node_t *node; pkgconf_node_t *node;
pkgconf_list_t deplist = PKGCONF_LIST_INITIALIZER; pkgconf_list_t deplist = PKGCONF_LIST_INITIALIZER;
@ -1193,18 +1255,28 @@ main(int argc, char *argv[])
{ {
if (want_flags & PKG_PRINT_ERRORS) if (want_flags & PKG_PRINT_ERRORS)
pkgconf_error(&pkg_client, "Package '%s' was not found\n", pkgiter->package); pkgconf_error(&pkg_client, "Package '%s' was not found\n", pkgiter->package);
return EXIT_FAILURE;
ret = EXIT_FAILURE;
goto cleanup2;
} }
if (pkgconf_compare_version(pkg->version, required_exact_module_version) == 0) if (pkgconf_compare_version(pkg->version, required_exact_module_version) == 0)
return EXIT_SUCCESS; {
ret = EXIT_SUCCESS;
goto cleanup2;
}
} }
return EXIT_FAILURE; ret = EXIT_FAILURE;
cleanup2:
if (pkg != NULL)
pkgconf_pkg_unref(&pkg_client, pkg);
pkgconf_dependency_free(&deplist);
goto out;
} }
else if (required_max_module_version != NULL) else if (required_max_module_version != NULL)
{ {
pkgconf_pkg_t *pkg; pkgconf_pkg_t *pkg = NULL;
pkgconf_node_t *node; pkgconf_node_t *node;
pkgconf_list_t deplist = PKGCONF_LIST_INITIALIZER; pkgconf_list_t deplist = PKGCONF_LIST_INITIALIZER;
@ -1223,14 +1295,24 @@ main(int argc, char *argv[])
{ {
if (want_flags & PKG_PRINT_ERRORS) if (want_flags & PKG_PRINT_ERRORS)
pkgconf_error(&pkg_client, "Package '%s' was not found\n", pkgiter->package); pkgconf_error(&pkg_client, "Package '%s' was not found\n", pkgiter->package);
return EXIT_FAILURE;
ret = EXIT_FAILURE;
goto cleanup3;
} }
if (pkgconf_compare_version(pkg->version, required_max_module_version) <= 0) if (pkgconf_compare_version(pkg->version, required_max_module_version) <= 0)
return EXIT_SUCCESS; {
ret = EXIT_SUCCESS;
goto cleanup3;
}
} }
return EXIT_FAILURE; ret = EXIT_FAILURE;
cleanup3:
if (pkg != NULL)
pkgconf_pkg_unref(&pkg_client, pkg);
pkgconf_dependency_free(&deplist);
goto out;
} }
while (1) while (1)
@ -1243,10 +1325,10 @@ main(int argc, char *argv[])
/* check if there is a limit to the number of packages allowed to be included, if so and we have hit /* 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. * the limit, stop adding packages to the queue.
*/ */
if (maximum_package_count > 0 && pkgq.length > maximum_package_count) if (maximum_package_count > 0 && pkgq.length >= maximum_package_count)
break; break;
while (isspace((unsigned int)package[0])) while (isspace((unsigned char)package[0]))
package++; package++;
/* skip empty packages */ /* skip empty packages */
@ -1274,85 +1356,68 @@ main(int argc, char *argv[])
if (pkgq.head == NULL) if (pkgq.head == NULL)
{ {
fprintf(stderr, "Please specify at least one package name on the command line.\n"); fprintf(stderr, "Please specify at least one package name on the command line.\n");
return EXIT_FAILURE; ret = EXIT_FAILURE;
goto out;
} }
ret = EXIT_SUCCESS; ret = EXIT_SUCCESS;
if (!pkgconf_queue_solve(&pkg_client, &pkgq, &world, maximum_traverse_depth))
{
ret = EXIT_FAILURE;
goto out;
}
#ifndef PKGCONF_LITE #ifndef PKGCONF_LITE
if ((want_flags & PKG_SIMULATE) == PKG_SIMULATE) if ((want_flags & PKG_SIMULATE) == PKG_SIMULATE)
{ {
want_flags &= ~(PKG_CFLAGS|PKG_LIBS); want_flags &= ~(PKG_CFLAGS|PKG_LIBS);
pkgconf_client_set_flags(&pkg_client, want_client_flags | PKGCONF_PKG_PKGF_SKIP_ERRORS); pkgconf_client_set_flags(&pkg_client, want_client_flags | PKGCONF_PKG_PKGF_SKIP_ERRORS);
if (!pkgconf_queue_apply(&pkg_client, &pkgq, apply_simulate, -1, NULL)) apply_simulate(&pkg_client, &world, NULL, -1);
{
ret = EXIT_FAILURE;
goto out;
}
} }
#endif #endif
if (!pkgconf_queue_validate(&pkg_client, &pkgq, maximum_traverse_depth)) if ((want_flags & PKG_VALIDATE) == PKG_VALIDATE)
goto out;
if ((want_flags & PKG_DUMP_LICENSE) == PKG_DUMP_LICENSE)
{ {
ret = EXIT_FAILURE; apply_license(&pkg_client, &world, &ret, 2);
goto out; goto out;
} }
if ((want_flags & PKG_VALIDATE) == PKG_VALIDATE)
return 0;
if ((want_flags & PKG_UNINSTALLED) == PKG_UNINSTALLED) if ((want_flags & PKG_UNINSTALLED) == PKG_UNINSTALLED)
{ {
ret = EXIT_FAILURE; ret = EXIT_FAILURE;
pkgconf_queue_apply(&pkg_client, &pkgq, apply_uninstalled, maximum_traverse_depth, &ret); apply_uninstalled(&pkg_client, &world, &ret, 2);
goto out; goto out;
} }
if (want_env_prefix != NULL) if (want_env_prefix != NULL)
{ {
if (!pkgconf_queue_apply(&pkg_client, &pkgq, apply_env, maximum_traverse_depth, want_env_prefix)) apply_env(&pkg_client, &world, want_env_prefix, 2);
{
ret = EXIT_FAILURE;
goto out;
}
want_flags = 0; want_flags = 0;
} }
if ((want_flags & PKG_PROVIDES) == PKG_PROVIDES) if ((want_flags & PKG_PROVIDES) == PKG_PROVIDES)
{ {
want_flags &= ~(PKG_CFLAGS|PKG_LIBS); want_flags &= ~(PKG_CFLAGS|PKG_LIBS);
apply_provides(&pkg_client, &world, NULL, 2);
if (!pkgconf_queue_apply(&pkg_client, &pkgq, apply_provides, maximum_traverse_depth, NULL))
{
ret = EXIT_FAILURE;
goto out;
}
} }
#ifndef PKGCONF_LITE #ifndef PKGCONF_LITE
if ((want_flags & PKG_DIGRAPH) == PKG_DIGRAPH) if ((want_flags & PKG_DIGRAPH) == PKG_DIGRAPH)
{ {
want_flags &= ~(PKG_CFLAGS|PKG_LIBS); want_flags &= ~(PKG_CFLAGS|PKG_LIBS);
apply_digraph(&pkg_client, &world, NULL, 2);
if (!pkgconf_queue_apply(&pkg_client, &pkgq, apply_digraph, maximum_traverse_depth, NULL))
{
ret = EXIT_FAILURE;
goto out;
}
} }
#endif #endif
if ((want_flags & PKG_MODVERSION) == PKG_MODVERSION) if ((want_flags & PKG_MODVERSION) == PKG_MODVERSION)
{ {
want_flags &= ~(PKG_CFLAGS|PKG_LIBS); want_flags &= ~(PKG_CFLAGS|PKG_LIBS);
apply_modversion(&pkg_client, &world, NULL, 2);
if (!pkgconf_queue_apply(&pkg_client, &pkgq, apply_modversion, maximum_traverse_depth, NULL))
{
ret = EXIT_FAILURE;
goto out;
}
} }
if ((want_flags & PKG_PATH) == PKG_PATH) if ((want_flags & PKG_PATH) == PKG_PATH)
@ -1360,22 +1425,13 @@ main(int argc, char *argv[])
want_flags &= ~(PKG_CFLAGS|PKG_LIBS); want_flags &= ~(PKG_CFLAGS|PKG_LIBS);
pkgconf_client_set_flags(&pkg_client, want_client_flags | PKGCONF_PKG_PKGF_SKIP_ROOT_VIRTUAL); pkgconf_client_set_flags(&pkg_client, want_client_flags | PKGCONF_PKG_PKGF_SKIP_ROOT_VIRTUAL);
if (!pkgconf_queue_apply(&pkg_client, &pkgq, apply_path, maximum_traverse_depth, NULL)) apply_path(&pkg_client, &world, NULL, 2);
{
ret = EXIT_FAILURE;
goto out;
}
} }
if ((want_flags & PKG_VARIABLES) == PKG_VARIABLES) if ((want_flags & PKG_VARIABLES) == PKG_VARIABLES)
{ {
want_flags &= ~(PKG_CFLAGS|PKG_LIBS); want_flags &= ~(PKG_CFLAGS|PKG_LIBS);
apply_variables(&pkg_client, &world, NULL, 2);
if (!pkgconf_queue_apply(&pkg_client, &pkgq, apply_variables, maximum_traverse_depth, NULL))
{
ret = EXIT_FAILURE;
goto out;
}
} }
if (want_variable) if (want_variable)
@ -1383,72 +1439,63 @@ main(int argc, char *argv[])
want_flags &= ~(PKG_CFLAGS|PKG_LIBS); want_flags &= ~(PKG_CFLAGS|PKG_LIBS);
pkgconf_client_set_flags(&pkg_client, want_client_flags | PKGCONF_PKG_PKGF_SKIP_ROOT_VIRTUAL); pkgconf_client_set_flags(&pkg_client, want_client_flags | PKGCONF_PKG_PKGF_SKIP_ROOT_VIRTUAL);
if (!pkgconf_queue_apply(&pkg_client, &pkgq, apply_variable, maximum_traverse_depth, want_variable)) apply_variable(&pkg_client, &world, want_variable, 2);
{
ret = EXIT_FAILURE;
goto out;
}
} }
if ((want_flags & PKG_REQUIRES) == PKG_REQUIRES) if ((want_flags & PKG_REQUIRES) == PKG_REQUIRES)
{ {
want_flags &= ~(PKG_CFLAGS|PKG_LIBS); want_flags &= ~(PKG_CFLAGS|PKG_LIBS);
apply_requires(&pkg_client, &world, NULL, 2);
if (!pkgconf_queue_apply(&pkg_client, &pkgq, apply_requires, maximum_traverse_depth, NULL))
{
ret = EXIT_FAILURE;
goto out;
}
} }
if ((want_flags & PKG_REQUIRES_PRIVATE) == PKG_REQUIRES_PRIVATE) if ((want_flags & PKG_REQUIRES_PRIVATE) == PKG_REQUIRES_PRIVATE)
{ {
want_flags &= ~(PKG_CFLAGS|PKG_LIBS); want_flags &= ~(PKG_CFLAGS|PKG_LIBS);
pkgconf_client_set_flags(&pkg_client, want_client_flags | PKGCONF_PKG_PKGF_SEARCH_PRIVATE); apply_requires_private(&pkg_client, &world, NULL, 2);
if (!pkgconf_queue_apply(&pkg_client, &pkgq, apply_requires_private, maximum_traverse_depth, NULL))
{
ret = EXIT_FAILURE;
goto out;
}
pkgconf_client_set_flags(&pkg_client, want_client_flags);
} }
if ((want_flags & PKG_CFLAGS)) if ((want_flags & PKG_CFLAGS))
{ {
pkgconf_client_set_flags(&pkg_client, want_client_flags | PKGCONF_PKG_PKGF_SEARCH_PRIVATE); apply_cflags(&pkg_client, &world, NULL, 2);
if (!pkgconf_queue_apply(&pkg_client, &pkgq, apply_cflags, maximum_traverse_depth, NULL))
{
ret = EXIT_FAILURE;
goto out_println;
}
pkgconf_client_set_flags(&pkg_client, want_client_flags);
} }
if ((want_flags & PKG_LIBS)) if ((want_flags & PKG_LIBS))
{ {
if (!pkgconf_queue_apply(&pkg_client, &pkgq, apply_libs, maximum_traverse_depth, NULL)) if (want_flags & PKG_CFLAGS)
printf(" ");
if (!(want_flags & PKG_STATIC))
{
pkgconf_client_set_flags(&pkg_client, pkg_client.flags & ~PKGCONF_PKG_PKGF_SEARCH_PRIVATE);
/* redo the solution for the library set: free the solution itself, and any cached graph nodes */
pkgconf_solution_free(&pkg_client, &world);
pkgconf_cache_free(&pkg_client);
if (!pkgconf_queue_solve(&pkg_client, &pkgq, &world, maximum_traverse_depth))
{ {
ret = EXIT_FAILURE; ret = EXIT_FAILURE;
goto out_println; goto out;
} }
} }
pkgconf_queue_free(&pkgq); apply_libs(&pkg_client, &world, NULL, 2);
}
out_println:
if (want_flags & (PKG_CFLAGS|PKG_LIBS)) if (want_flags & (PKG_CFLAGS|PKG_LIBS))
printf("\n"); printf("\n");
out: out:
pkgconf_solution_free(&pkg_client, &world);
pkgconf_queue_free(&pkgq);
pkgconf_cross_personality_deinit(personality);
pkgconf_client_deinit(&pkg_client); pkgconf_client_deinit(&pkg_client);
if (logfile_out != NULL) if (logfile_out != NULL)
fclose(logfile_out); fclose(logfile_out);
if (opened_error_msgout)
fclose(error_msgout);
return ret; return ret;
} }

View File

@ -149,7 +149,6 @@ msvc_renderer_render_buf(const pkgconf_list_t *list, char *buf, size_t buflen, b
{ {
cnt = pkgconf_strlcpy(bptr, ".lib", buf_remaining); cnt = pkgconf_strlcpy(bptr, ".lib", buf_remaining);
bptr += cnt; bptr += cnt;
buf_remaining -= cnt;
} }
if (escape) if (escape)

View File

@ -11,10 +11,10 @@ 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 implied. In no event shall the authors be liable for any damages arising
dnl from the use of this software. dnl from the use of this software.
AC_PREREQ([2.68]) AC_PREREQ([2.71])
AC_INIT([pkgconf], [1.9.90], [https://todo.sr.ht/~kaniini/pkgconf]) AC_INIT([pkgconf],[1.9.5],[https://github.com/pkgconf/pkgconf/issues/new])
AC_CONFIG_SRCDIR([cli/main.c]) AC_CONFIG_SRCDIR([cli/main.c])
AC_CONFIG_MACRO_DIRS([m4]) AC_CONFIG_MACRO_DIR([m4])
AX_CHECK_COMPILE_FLAG([-Wall], [CFLAGS="$CFLAGS -Wall"]) AX_CHECK_COMPILE_FLAG([-Wall], [CFLAGS="$CFLAGS -Wall"])
AX_CHECK_COMPILE_FLAG([-Wextra], [CFLAGS="$CFLAGS -Wextra"]) AX_CHECK_COMPILE_FLAG([-Wextra], [CFLAGS="$CFLAGS -Wextra"])
AX_CHECK_COMPILE_FLAG([-Wformat=2], [CFLAGS="$CFLAGS -Wformat=2"]) AX_CHECK_COMPILE_FLAG([-Wformat=2], [CFLAGS="$CFLAGS -Wformat=2"])
@ -22,7 +22,8 @@ AX_CHECK_COMPILE_FLAG([-std=gnu99], [CFLAGS="$CFLAGS -std=gnu99"], [
AX_CHECK_COMPILE_FLAG([-std=c99], [CFLAGS="$CFLAGS -std=c99"]) AX_CHECK_COMPILE_FLAG([-std=c99], [CFLAGS="$CFLAGS -std=c99"])
]) ])
AC_CONFIG_HEADERS([libpkgconf/config.h]) AC_CONFIG_HEADERS([libpkgconf/config.h])
AC_CHECK_FUNCS([strlcpy strlcat strndup cygwin_conv_path]) AC_CHECK_DECLS([strlcpy, strlcat, strndup], [], [], [[#include <string.h>]])
AC_CHECK_DECLS([reallocarray])
AC_CHECK_HEADERS([sys/stat.h]) AC_CHECK_HEADERS([sys/stat.h])
AM_INIT_AUTOMAKE([foreign dist-xz subdir-objects]) AM_INIT_AUTOMAKE([foreign dist-xz subdir-objects])
AM_SILENT_RULES([yes]) AM_SILENT_RULES([yes])
@ -30,26 +31,26 @@ LT_INIT
AC_SYS_LARGEFILE AC_SYS_LARGEFILE
AC_ARG_WITH([personality-dir],[AC_HELP_STRING([--with-personality-dir],[specify AC_ARG_WITH([personality-dir],[AS_HELP_STRING([--with-personality-dir],[specify
the place where cross-compile personality files will be found])], the place where cross-compile personality files will be found])],
PERSONALITY_PATH="$withval", PERSONALITY_PATH="$withval",
PERSONALITY_PATH="${datadir}/pkgconfig/personality.d:${sysconfdir}/pkgconfig/personality.d") PERSONALITY_PATH="${datadir}/pkgconfig/personality.d:${sysconfdir}/pkgconfig/personality.d")
AC_SUBST([PERSONALITY_PATH]) AC_SUBST([PERSONALITY_PATH])
AC_ARG_WITH([pkg-config-dir],[AC_HELP_STRING([--with-pkg-config-dir],[specify 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", the place where pc files will be found])],PKG_DEFAULT_PATH="$withval",
PKG_DEFAULT_PATH="${libdir}/pkgconfig:${datadir}/pkgconfig") PKG_DEFAULT_PATH="${libdir}/pkgconfig:${datadir}/pkgconfig")
AC_SUBST([PKG_DEFAULT_PATH]) AC_SUBST([PKG_DEFAULT_PATH])
AC_ARG_WITH([system-libdir],[AC_HELP_STRING([--with-system-libdir],[specify the AC_ARG_WITH([system-libdir],[AS_HELP_STRING([--with-system-libdir],[specify the
system library directory (default LIBDIR)])], system library directory (default LIBDIR)])],
SYSTEM_LIBDIR="$withval", SYSTEM_LIBDIR="${libdir}") SYSTEM_LIBDIR="$withval", SYSTEM_LIBDIR="${libdir}")
AC_SUBST([SYSTEM_LIBDIR]) AC_SUBST([SYSTEM_LIBDIR])
AC_ARG_WITH([system-includedir],[AC_HELP_STRING([--with-system-includedir],[specify the AC_ARG_WITH([system-includedir],[AS_HELP_STRING([--with-system-includedir],[specify the
system include directory (default INCLUDEDIR)])], system include directory (default INCLUDEDIR)])],
SYSTEM_INCLUDEDIR="$withval", SYSTEM_INCLUDEDIR="${includedir}") SYSTEM_INCLUDEDIR="$withval", SYSTEM_INCLUDEDIR="${includedir}")

View File

@ -70,21 +70,21 @@ def extract_comments(filename):
while True: while True:
char = source_file.read(1) char = source_file.read(1)
if not char: if not char:
if state is 3 or state is 4: if state == 3 or state == 4:
raise UnterminatedCommentError() raise UnterminatedCommentError()
if state is 2: if state == 2:
# Was in single line comment. Create comment. # Was in single line comment. Create comment.
comment = Comment(current_comment, line_counter, False) comment = Comment(current_comment, line_counter, False)
comments.append(comment) comments.append(comment)
return comments return comments
if state is 0: if state == 0:
# Waiting for comment start character or beginning of # Waiting for comment start character or beginning of
# string. # string.
if char == '/': if char == '/':
state = 1 state = 1
elif char == '"': elif char == '"':
state = 5 state = 5
elif state is 1: elif state == 1:
# Found comment start character, classify next character and # Found comment start character, classify next character and
# determine if single or multiline comment. # determine if single or multiline comment.
if char == '/': if char == '/':
@ -94,7 +94,7 @@ def extract_comments(filename):
state = 3 state = 3
else: else:
state = 0 state = 0
elif state is 2: elif state == 2:
# In single line comment, read characters until EOL. # In single line comment, read characters until EOL.
if char == '\n': if char == '\n':
comment = Comment(current_comment, line_counter, False) comment = Comment(current_comment, line_counter, False)
@ -103,14 +103,14 @@ def extract_comments(filename):
state = 0 state = 0
else: else:
current_comment += char current_comment += char
elif state is 3: elif state == 3:
# In multi-line comment, add characters until '*' # In multi-line comment, add characters until '*'
# encountered. # encountered.
if char == '*': if char == '*':
state = 4 state = 4
else: else:
current_comment += char current_comment += char
elif state is 4: elif state == 4:
# In multi-line comment with asterisk found. Determine if # In multi-line comment with asterisk found. Determine if
# comment is ending. # comment is ending.
if char == '/': if char == '/':
@ -125,13 +125,13 @@ def extract_comments(filename):
if char != '*': if char != '*':
current_comment += char current_comment += char
state = 3 state = 3
elif state is 5: elif state == 5:
# In string literal, expect literal end or escape char. # In string literal, expect literal end or escape char.
if char == '"': if char == '"':
state = 0 state = 0
elif char == '\\': elif char == '\\':
state = 6 state = 6
elif state is 6: elif state == 6:
# In string literal, escaping current char. # In string literal, escaping current char.
state = 5 state = 5
if char == '\n': if char == '\n':

View File

@ -9,21 +9,32 @@ in parallel.
Client objects are not thread safe, in other words, a client object should not be shared across Client objects are not thread safe, in other words, a client object should not be shared across
thread boundaries. thread boundaries.
.. c:function:: void pkgconf_client_init(pkgconf_client_t *client, pkgconf_error_handler_func_t error_handler) .. 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. Initialise a pkgconf client object.
:param pkgconf_client_t* client: The client to initialise. :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 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 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 :return: nothing
.. c:function:: pkgconf_client_t* pkgconf_client_new(pkgconf_error_handler_func_t error_handler) .. 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. 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 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 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. :return: A pkgconf client object.
:rtype: pkgconf_client_t* :rtype: pkgconf_client_t*
@ -97,11 +108,14 @@ thread boundaries.
:return: true if the warn handler processed the message, else false. :return: true if the warn handler processed the message, else false.
:rtype: bool :rtype: bool
.. c:function:: bool pkgconf_trace(const pkgconf_client_t *client, const char *format, ...) .. 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. 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 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. :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. :return: true if the trace handler processed the message, else false.
:rtype: bool :rtype: bool

View File

@ -14,6 +14,7 @@ The `dependency` module provides support for building `dependency lists` (the ba
:param char* package: The package `atom` to set on the dependency node. :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 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 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. :return: A dependency node.
:rtype: pkgconf_dependency_t * :rtype: pkgconf_dependency_t *
@ -25,6 +26,29 @@ The `dependency` module provides support for building `dependency lists` (the ba
:param pkgconf_dependency_t* tail: The dependency node to add to the tail of the dependency list. :param pkgconf_dependency_t* tail: The dependency node to add to the tail of the dependency list.
:return: nothing :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) .. c:function:: void pkgconf_dependency_free(pkgconf_list_t *list)
Release a dependency list and it's child dependency nodes. Release a dependency list and it's child dependency nodes.
@ -41,6 +65,7 @@ The `dependency` module provides support for building `dependency lists` (the ba
:param pkgconf_client_t* client: The client object that owns the package this dependency list belongs to. :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 pkgconf_list_t* deplist_head: The dependency list to populate with dependency nodes.
:param char* depends: The dependency data to parse. :param char* depends: The dependency data to parse.
:param uint flags: Any flags to attach to the dependency nodes.
:return: nothing :return: nothing
.. c:function:: void pkgconf_dependency_parse(const pkgconf_client_t *client, pkgconf_pkg_t *pkg, pkgconf_list_t *deplist, const char *depends) .. c:function:: void pkgconf_dependency_parse(const pkgconf_client_t *client, pkgconf_pkg_t *pkg, pkgconf_list_t *deplist, const char *depends)
@ -53,4 +78,13 @@ The `dependency` module provides support for building `dependency lists` (the ba
:param pkgconf_pkg_t* pkg: The package object that owns this dependency list. :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 pkgconf_list_t* deplist: The dependency list to populate with dependency nodes.
:param char* depends: The dependency data to parse. :param char* depends: The dependency data to parse.
:param uint flags: Any flags to attach to the dependency nodes.
:return: nothing :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

View File

@ -6,13 +6,14 @@ The `fragment` module provides low-level management and rendering of fragment li
`fragment list` contains various `fragments` of text (such as ``-I /usr/include``) in a matter `fragment list` contains various `fragments` of text (such as ``-I /usr/include``) in a matter
which is composable, mergeable and reorderable. which is composable, mergeable and reorderable.
.. c:function:: void pkgconf_fragment_add(const pkgconf_client_t *client, pkgconf_list_t *list, const char *string) .. 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. 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_client_t* client: The pkgconf client being accessed.
:param pkgconf_list_t* list: The fragment list. :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 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 :return: nothing
.. c:function:: bool pkgconf_fragment_has_system_dir(const pkgconf_client_t *client, const pkgconf_fragment_t *frag) .. c:function:: bool pkgconf_fragment_has_system_dir(const pkgconf_client_t *client, const pkgconf_fragment_t *frag)
@ -110,5 +111,6 @@ which is composable, mergeable and reorderable.
:param pkgconf_client_t* client: The pkgconf client being accessed. :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* 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 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. :param char* value: The string to parse into fragments.
:return: true on success, false on parse error :return: true on success, false on parse error

View File

@ -25,12 +25,12 @@ variables.
:return: number of path nodes added to the path list :return: number of path nodes added to the path list
:rtype: size_t :rtype: size_t
.. c:function:: size_t pkgconf_path_build_from_environ(const char *environ, const char *fallback, pkgconf_list_t *dirlist) .. 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, 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. an optional default set of paths is added.
:param char* environ: The environment variable to look up. :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 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 pkgconf_list_t* dirlist: The path list to add the path nodes to.
:param bool filter: Whether to perform duplicate filtering. :param bool filter: Whether to perform duplicate filtering.
@ -46,6 +46,14 @@ variables.
:return: true if the path list has a matching prefix, otherwise false :return: true if the path list has a matching prefix, otherwise false
:rtype: bool :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) .. c:function:: void pkgconf_path_free(pkgconf_list_t *dirlist)
Releases any path nodes attached to the given path list. Releases any path nodes attached to the given path list.
@ -55,7 +63,7 @@ variables.
.. c:function:: bool pkgconf_path_relocate(char *buf, size_t buflen) .. c:function:: bool pkgconf_path_relocate(char *buf, size_t buflen)
Relocates a path, possibly calling normpath() or cygwin_conv_path() on it. Relocates a path, possibly calling normpath() on it.
:param char* buf: The path to relocate. :param char* buf: The path to relocate.
:param size_t buflen: The buffer length the path is contained in. :param size_t buflen: The buffer length the path is contained in.

View File

@ -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

View File

@ -5,22 +5,14 @@ libpkgconf `pkg` module
The `pkg` module provides dependency resolution services and the overall `.pc` file parsing The `pkg` module provides dependency resolution services and the overall `.pc` file parsing
routines. routines.
.. c:function:: void pkgconf_pkg_dir_list_build(pkgconf_client_t *client) .. c:function:: pkgconf_pkg_t *pkgconf_pkg_new_from_file(const pkgconf_client_t *client, const char *filename, FILE *f, unsigned int flags)
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:: 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. 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 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 char* filename: The filename of the package file (including full path).
:param FILE* f: The file object to read from. :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. :returns: A ``pkgconf_pkg_t`` object which contains the package data.
:rtype: pkgconf_pkg_t * :rtype: pkgconf_pkg_t *
@ -76,7 +68,7 @@ routines.
:param char* a: The first version to compare in the pair. :param char* a: The first version to compare in the pair.
:param char* b: The second version to compare in the pair. :param char* b: The second version to compare in the pair.
:return: -1 if the first version is greater, 0 if both versions are equal, 1 if the second version is greater. :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 :rtype: int
.. c:function:: pkgconf_pkg_t *pkgconf_builtin_pkg_get(const char *name) .. c:function:: pkgconf_pkg_t *pkgconf_builtin_pkg_get(const char *name)
@ -126,7 +118,7 @@ routines.
:return: On success, ``PKGCONF_PKG_ERRF_OK`` (0), else an error code. :return: On success, ``PKGCONF_PKG_ERRF_OK`` (0), else an error code.
:rtype: unsigned int :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) .. 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. Walk and resolve the dependency graph up to `maxdepth` levels.
@ -135,6 +127,7 @@ routines.
:param pkgconf_pkg_traverse_func_t func: A traversal function to call for each resolved node in 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 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 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. :return: ``PKGCONF_PKG_ERRF_OK`` on success, else an error code.
:rtype: unsigned int :rtype: unsigned int

View File

@ -33,11 +33,32 @@ Using the `queue` module functions is the recommended way of working with depend
:param pkgconf_list_t* list: The dependency resolution queue to release. :param pkgconf_list_t* list: The dependency resolution queue to release.
:return: nothing :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) .. 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 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. 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_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_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 pkgconf_queue_apply_func_t func: The callback function to call if a solution is found by the dependency resolver.

View File

@ -64,13 +64,14 @@ attached to a given client object.
:return: the value of the variable or ``NULL`` :return: the value of the variable or ``NULL``
:rtype: char * :rtype: char *
.. c:function:: char *pkgconf_tuple_parse(const pkgconf_client_t *client, pkgconf_list_t *vars, const char *value) .. 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. Parse an expression for variable substitution.
:param pkgconf_client_t* client: The pkgconf client object to access. :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 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 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 :return: the variable data with any variables substituted
:rtype: char * :rtype: char *

View File

@ -11,6 +11,7 @@ libpkgconf - an API for managing `pkg-config` modules
libpkgconf-dependency libpkgconf-dependency
libpkgconf-fragment libpkgconf-fragment
libpkgconf-path libpkgconf-path
libpkgconf-personality
libpkgconf-pkg libpkgconf-pkg
libpkgconf-queue libpkgconf-queue
libpkgconf-tuple libpkgconf-tuple

View File

@ -5,7 +5,8 @@ libdir=@libdir@
Name: libpkgconf Name: libpkgconf
Description: a library for accessing and manipulating development framework configuration Description: a library for accessing and manipulating development framework configuration
URL: http://github.com/pkgconf/pkgconf URL: https://gitea.treehouse.systems/ariadne/pkgconf
License: ISC
Version: @PACKAGE_VERSION@ Version: @PACKAGE_VERSION@
CFlags: -I${includedir}/pkgconf CFlags: -I${includedir}/pkgconf
Libs: -L${libdir} -lpkgconf Libs: -L${libdir} -lpkgconf

View File

@ -80,7 +80,7 @@ pkgconf_argv_split(const char *src, int *argc, char ***argv)
if (escaped) if (escaped)
{ {
/* POSIX: only \CHAR is special inside a double quote if CHAR is {$, `, ", \, newline}. */ /* POSIX: only \CHAR is special inside a double quote if CHAR is {$, `, ", \, newline}. */
if (quote == '\"') if (quote == '"')
{ {
if (!(*src_iter == '$' || *src_iter == '`' || *src_iter == '"' || *src_iter == '\\')) if (!(*src_iter == '$' || *src_iter == '`' || *src_iter == '"' || *src_iter == '\\'))
*dst_iter++ = '\\'; *dst_iter++ = '\\';
@ -88,7 +88,9 @@ pkgconf_argv_split(const char *src, int *argc, char ***argv)
*dst_iter++ = *src_iter; *dst_iter++ = *src_iter;
} }
else else
{
*dst_iter++ = *src_iter; *dst_iter++ = *src_iter;
}
escaped = false; escaped = false;
} }
@ -101,7 +103,7 @@ pkgconf_argv_split(const char *src, int *argc, char ***argv)
else else
*dst_iter++ = *src_iter; *dst_iter++ = *src_iter;
} }
else if (isspace((unsigned int)*src_iter)) else if (isspace((unsigned char)*src_iter))
{ {
if ((*argv)[argc_count] != NULL) if ((*argv)[argc_count] != NULL)
{ {

View File

@ -20,11 +20,12 @@
#include <stdlib.h> #include <stdlib.h>
#include <sys/types.h> #include <sys/types.h>
#include <string.h> #include <string.h>
#include <errno.h>
#include <libpkgconf/bsdstubs.h> #include <libpkgconf/bsdstubs.h>
#include <libpkgconf/config.h> #include <libpkgconf/config.h>
#ifndef HAVE_STRLCPY #if !HAVE_DECL_STRLCPY
/* /*
* Copy src to string dst of size siz. At most siz-1 characters * Copy src to string dst of size siz. At most siz-1 characters
* will be copied. Always NUL terminates (unless siz == 0). * will be copied. Always NUL terminates (unless siz == 0).
@ -57,7 +58,7 @@ strlcpy(char *dst, const char *src, size_t siz)
} }
#endif #endif
#ifndef HAVE_STRLCAT #if !HAVE_DECL_STRLCAT
/* /*
* Appends src to string dst of size siz (unlike strncat, siz is the * 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 * full size of dst, not space left). At most siz-1 characters
@ -106,7 +107,7 @@ strlcat(char *dst, const char *src, size_t siz)
* from the use of this software. * from the use of this software.
*/ */
#ifndef HAVE_STRNDUP #if !HAVE_DECL_STRNDUP
/* /*
* Creates a memory buffer and copies at most 'len' characters to it. * 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. * If 'len' is less than the length of the source string, truncation occured.
@ -137,3 +138,23 @@ pkgconf_strndup(const char *src, size_t len)
{ {
return strndup(src, 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);
}

View File

@ -25,6 +25,7 @@ extern "C" {
PKGCONF_API extern size_t pkgconf_strlcpy(char *dst, const char *src, size_t siz); 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 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 char *pkgconf_strndup(const char *src, size_t len);
PKGCONF_API extern void *pkgconf_reallocarray(void *ptr, size_t m, size_t n);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -16,6 +16,8 @@
#include <libpkgconf/stdinc.h> #include <libpkgconf/stdinc.h>
#include <libpkgconf/libpkgconf.h> #include <libpkgconf/libpkgconf.h>
#include <assert.h>
/* /*
* !doc * !doc
* *
@ -29,6 +31,46 @@
* be shared across threads. * 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 * !doc
* *
@ -46,17 +88,19 @@
pkgconf_pkg_t * pkgconf_pkg_t *
pkgconf_cache_lookup(pkgconf_client_t *client, const char *id) pkgconf_cache_lookup(pkgconf_client_t *client, const char *id)
{ {
pkgconf_node_t *node; if (client->cache_table == NULL)
return NULL;
PKGCONF_FOREACH_LIST_ENTRY(client->pkg_cache.head, node) pkgconf_pkg_t **pkg;
{
pkgconf_pkg_t *pkg = node->data;
if (!strcmp(pkg->id, id)) 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); PKGCONF_TRACE(client, "found: %s @%p", id, *pkg);
return pkgconf_pkg_ref(client, pkg); return pkgconf_pkg_ref(client, *pkg);
}
} }
PKGCONF_TRACE(client, "miss: %s", id); PKGCONF_TRACE(client, "miss: %s", id);
@ -82,12 +126,19 @@ pkgconf_cache_add(pkgconf_client_t *client, pkgconf_pkg_t *pkg)
return; return;
pkgconf_pkg_ref(client, pkg); pkgconf_pkg_ref(client, pkg);
pkgconf_node_insert(&pkg->cache_iter, pkg, &client->pkg_cache);
PKGCONF_TRACE(client, "added @%p to cache", pkg); PKGCONF_TRACE(client, "added @%p to cache", pkg);
/* mark package as cached */ /* mark package as cached */
pkg->flags |= PKGCONF_PKG_PROPF_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);
} }
/* /*
@ -104,6 +155,9 @@ pkgconf_cache_add(pkgconf_client_t *client, pkgconf_pkg_t *pkg)
void void
pkgconf_cache_remove(pkgconf_client_t *client, pkgconf_pkg_t *pkg) pkgconf_cache_remove(pkgconf_client_t *client, pkgconf_pkg_t *pkg)
{ {
if (client->cache_table == NULL)
return;
if (pkg == NULL) if (pkg == NULL)
return; return;
@ -112,7 +166,41 @@ pkgconf_cache_remove(pkgconf_client_t *client, pkgconf_pkg_t *pkg)
PKGCONF_TRACE(client, "removed @%p from cache", pkg); PKGCONF_TRACE(client, "removed @%p from cache", pkg);
pkgconf_node_delete(&pkg->cache_iter, &client->pkg_cache); 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;
}
} }
/* /*
@ -129,15 +217,15 @@ pkgconf_cache_remove(pkgconf_client_t *client, pkgconf_pkg_t *pkg)
void void
pkgconf_cache_free(pkgconf_client_t *client) pkgconf_cache_free(pkgconf_client_t *client)
{ {
pkgconf_node_t *iter, *iter2; if (client->cache_table == NULL)
return;
PKGCONF_FOREACH_LIST_ENTRY_SAFE(client->pkg_cache.head, iter2, iter) while (client->cache_count > 0)
{ pkgconf_cache_remove(client, client->cache_table[0]);
pkgconf_pkg_t *pkg = iter->data;
pkgconf_pkg_unref(client, pkg);
}
memset(&client->pkg_cache, 0, sizeof client->pkg_cache); free(client->cache_table);
client->cache_table = NULL;
client->cache_count = 0;
PKGCONF_TRACE(client, "cleared package cache"); PKGCONF_TRACE(client, "cleared package cache");
} }

View File

@ -98,6 +98,8 @@ pkgconf_client_init(pkgconf_client_t *client, pkgconf_error_handler_func_t error
client->error_handler_data = error_handler_data; client->error_handler_data = error_handler_data;
client->error_handler = error_handler; client->error_handler = error_handler;
client->auditf = NULL; client->auditf = NULL;
client->cache_table = NULL;
client->cache_count = 0;
#ifndef PKGCONF_LITE #ifndef PKGCONF_LITE
if (client->trace_handler == NULL) if (client->trace_handler == NULL)
@ -401,7 +403,7 @@ pkgconf_trace(const pkgconf_client_t *client, const char *filename, size_t linen
* :rtype: bool * :rtype: bool
*/ */
bool bool
pkgconf_default_error_handler(const char *msg, const pkgconf_client_t *client, const void *data) pkgconf_default_error_handler(const char *msg, const pkgconf_client_t *client, void *data)
{ {
(void) msg; (void) msg;
(void) client; (void) client;

View File

@ -1,29 +1,5 @@
/* libpkgconf/config.h.in. Generated from configure.ac by autoheader. */ /* libpkgconf/config.h.in. Generated from configure.ac by autoheader. */
/* Define to 1 if you have the `cygwin_conv_path' function. */
#mesondefine HAVE_CYGWIN_CONV_PATH
/* Define to 1 if you have the <dlfcn.h> header file. */
#mesondefine HAVE_DLFCN_H
/* Define to 1 if you have the <inttypes.h> header file. */
#mesondefine HAVE_INTTYPES_H
/* Define to 1 if you have the <memory.h> header file. */
#mesondefine HAVE_MEMORY_H
/* Define to 1 if you have the <stdint.h> header file. */
#mesondefine HAVE_STDINT_H
/* Define to 1 if you have the <stdlib.h> header file. */
#mesondefine HAVE_STDLIB_H
/* Define to 1 if you have the <strings.h> header file. */
#mesondefine HAVE_STRINGS_H
/* Define to 1 if you have the <string.h> header file. */
#mesondefine HAVE_STRING_H
/* Define to 1 if you have the `strlcat' function. */ /* Define to 1 if you have the `strlcat' function. */
#mesondefine HAVE_STRLCAT #mesondefine HAVE_STRLCAT
@ -33,17 +9,20 @@
/* Define to 1 if you have the `strndup' function. */ /* Define to 1 if you have the `strndup' function. */
#mesondefine HAVE_STRNDUP #mesondefine HAVE_STRNDUP
/* Define to 1 if you have the <sys/stat.h> header file. */ /* Define to 1 if you have the `reallocarray' function. */
#mesondefine HAVE_SYS_STAT_H #mesondefine HAVE_REALLOCARRAY
/* Define to 1 if you have the <sys/types.h> header file. */ /* Define to 1 if you have the `strlcat' function. */
#mesondefine HAVE_SYS_TYPES_H #mesondefine HAVE_DECL_STRLCAT
/* Define to 1 if you have the <unistd.h> header file. */ /* Define to 1 if you have the `strlcpy' function. */
#mesondefine HAVE_UNISTD_H #mesondefine HAVE_DECL_STRLCPY
/* Define to the sub-directory where libtool stores uninstalled libraries. */ /* Define to 1 if you have the `strndup' function. */
#mesondefine LT_OBJDIR #mesondefine HAVE_DECL_STRNDUP
/* Define to 1 if you have the `reallocarray' function. */
#mesondefine HAVE_DECL_REALLOCARRAY
/* Name of package */ /* Name of package */
#mesondefine PACKAGE #mesondefine PACKAGE

View File

@ -73,7 +73,7 @@ find_colliding_dependency(const pkgconf_dependency_t *dep, const pkgconf_list_t
} }
static inline pkgconf_dependency_t * static inline pkgconf_dependency_t *
add_or_replace_dependency_node(const pkgconf_client_t *client, pkgconf_dependency_t *dep, pkgconf_list_t *list) add_or_replace_dependency_node(pkgconf_client_t *client, pkgconf_dependency_t *dep, pkgconf_list_t *list)
{ {
char depbuf[PKGCONF_ITEM_SIZE]; char depbuf[PKGCONF_ITEM_SIZE];
pkgconf_dependency_t *dep2 = find_colliding_dependency(dep, list); pkgconf_dependency_t *dep2 = find_colliding_dependency(dep, list);
@ -92,7 +92,7 @@ add_or_replace_dependency_node(const pkgconf_client_t *client, pkgconf_dependenc
{ {
PKGCONF_TRACE(client, "dropping dependency [%s]@%p because of collision", depbuf, dep); PKGCONF_TRACE(client, "dropping dependency [%s]@%p because of collision", depbuf, dep);
free(dep); pkgconf_dependency_unref(dep->owner, dep);
return NULL; return NULL;
} }
else if (dep2->flags && dep->flags == 0) else if (dep2->flags && dep->flags == 0)
@ -100,7 +100,7 @@ add_or_replace_dependency_node(const pkgconf_client_t *client, pkgconf_dependenc
PKGCONF_TRACE(client, "dropping dependency [%s]@%p because of collision", depbuf2, dep2); PKGCONF_TRACE(client, "dropping dependency [%s]@%p because of collision", depbuf2, dep2);
pkgconf_node_delete(&dep2->iter, list); pkgconf_node_delete(&dep2->iter, list);
free(dep2); pkgconf_dependency_unref(dep2->owner, dep2);
} }
else else
/* If both dependencies have equal strength, we keep both, because of situations like: /* If both dependencies have equal strength, we keep both, because of situations like:
@ -113,13 +113,20 @@ add_or_replace_dependency_node(const pkgconf_client_t *client, pkgconf_dependenc
} }
PKGCONF_TRACE(client, "added dependency [%s] to list @%p; flags=%x", dependency_to_str(dep, depbuf, sizeof depbuf), list, dep->flags); 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, dep, list); 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; return dep;
} }
static inline pkgconf_dependency_t * static inline pkgconf_dependency_t *
pkgconf_dependency_addraw(const 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_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; pkgconf_dependency_t *dep;
@ -131,6 +138,8 @@ pkgconf_dependency_addraw(const pkgconf_client_t *client, pkgconf_list_t *list,
dep->compare = compare; dep->compare = compare;
dep->flags = flags; dep->flags = flags;
dep->owner = client;
dep->refcount = 0;
return add_or_replace_dependency_node(client, dep, list); return add_or_replace_dependency_node(client, dep, list);
} }
@ -152,12 +161,12 @@ pkgconf_dependency_addraw(const pkgconf_client_t *client, pkgconf_list_t *list,
* :rtype: pkgconf_dependency_t * * :rtype: pkgconf_dependency_t *
*/ */
pkgconf_dependency_t * pkgconf_dependency_t *
pkgconf_dependency_add(const pkgconf_client_t *client, pkgconf_list_t *list, const char *package, const char *version, pkgconf_pkg_comparator_t compare, unsigned int flags) 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)
{ {
if (version != NULL) pkgconf_dependency_t *dep;
return pkgconf_dependency_addraw(client, list, package, strlen(package), version, strlen(version), compare, flags); dep = pkgconf_dependency_addraw(client, list, package, strlen(package), version,
version != NULL ? strlen(version) : 0, compare, flags);
return pkgconf_dependency_addraw(client, list, package, strlen(package), NULL, 0, compare, flags); return pkgconf_dependency_ref(dep->owner, dep);
} }
/* /*
@ -177,6 +186,77 @@ pkgconf_dependency_append(pkgconf_list_t *list, pkgconf_dependency_t *tail)
pkgconf_node_insert_tail(&tail->iter, tail, list); 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 * !doc
* *
@ -196,17 +276,11 @@ pkgconf_dependency_free(pkgconf_list_t *list)
{ {
pkgconf_dependency_t *dep = node->data; pkgconf_dependency_t *dep = node->data;
if (dep->match != NULL) pkgconf_node_delete(&dep->iter, list);
pkgconf_pkg_unref(NULL, dep->match); pkgconf_dependency_unref(dep->owner, dep);
if (dep->package != NULL)
free(dep->package);
if (dep->version != NULL)
free(dep->version);
free(dep);
} }
pkgconf_list_zero(list);
} }
/* /*
@ -225,7 +299,7 @@ pkgconf_dependency_free(pkgconf_list_t *list)
* :return: nothing * :return: nothing
*/ */
void void
pkgconf_dependency_parse_str(const pkgconf_client_t *client, pkgconf_list_t *deplist_head, const char *depends, unsigned int flags) 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; parse_state_t state = OUTSIDE_MODULE;
pkgconf_pkg_comparator_t compare = PKGCONF_CMP_ANY; pkgconf_pkg_comparator_t compare = PKGCONF_CMP_ANY;
@ -237,6 +311,7 @@ pkgconf_dependency_parse_str(const pkgconf_client_t *client, pkgconf_list_t *dep
char *vstart = NULL; char *vstart = NULL;
char *package = NULL, *version = NULL; char *package = NULL, *version = NULL;
char *cnameptr = cmpname; char *cnameptr = cmpname;
char *cnameend = cmpname + PKGCONF_ITEM_SIZE - 1;
memset(cmpname, '\0', sizeof cmpname); memset(cmpname, '\0', sizeof cmpname);
@ -254,11 +329,11 @@ pkgconf_dependency_parse_str(const pkgconf_client_t *client, pkgconf_list_t *dep
break; break;
case INSIDE_MODULE_NAME: case INSIDE_MODULE_NAME:
if (isspace((unsigned int)*ptr)) if (isspace((unsigned char)*ptr))
{ {
const char *sptr = ptr; const char *sptr = ptr;
while (*sptr && isspace((unsigned int)*sptr)) while (*sptr && isspace((unsigned char)*sptr))
sptr++; sptr++;
if (*sptr == '\0') if (*sptr == '\0')
@ -304,6 +379,7 @@ pkgconf_dependency_parse_str(const pkgconf_client_t *client, pkgconf_list_t *dep
if (PKGCONF_IS_OPERATOR_CHAR(*ptr)) if (PKGCONF_IS_OPERATOR_CHAR(*ptr))
{ {
state = INSIDE_OPERATOR; state = INSIDE_OPERATOR;
if (cnameptr < cnameend)
*cnameptr++ = *ptr; *cnameptr++ = *ptr;
} }
@ -315,13 +391,13 @@ pkgconf_dependency_parse_str(const pkgconf_client_t *client, pkgconf_list_t *dep
state = AFTER_OPERATOR; state = AFTER_OPERATOR;
compare = pkgconf_pkg_comparator_lookup_by_name(cmpname); compare = pkgconf_pkg_comparator_lookup_by_name(cmpname);
} }
else else if (cnameptr < cnameend)
*cnameptr++ = *ptr; *cnameptr++ = *ptr;
break; break;
case AFTER_OPERATOR: case AFTER_OPERATOR:
if (!isspace((unsigned int)*ptr)) if (!isspace((unsigned char)*ptr))
{ {
vstart = ptr; vstart = ptr;
state = INSIDE_VERSION; state = INSIDE_VERSION;
@ -369,10 +445,43 @@ pkgconf_dependency_parse_str(const pkgconf_client_t *client, pkgconf_list_t *dep
* :return: nothing * :return: nothing
*/ */
void void
pkgconf_dependency_parse(const pkgconf_client_t *client, pkgconf_pkg_t *pkg, pkgconf_list_t *deplist, const char *depends, unsigned int flags) 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); char *kvdepends = pkgconf_tuple_parse(client, &pkg->vars, depends, pkg->flags);
pkgconf_dependency_parse_str(client, deplist, kvdepends, flags); pkgconf_dependency_parse_str(client, deplist, kvdepends, flags);
free(kvdepends); 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(sizeof(pkgconf_dependency_t), 1);
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);
}

View File

@ -20,7 +20,7 @@ char *
pkgconf_fgetline(char *line, size_t size, FILE *stream) pkgconf_fgetline(char *line, size_t size, FILE *stream)
{ {
char *s = line; char *s = line;
char *end = line + size - 1; char *end = line + size - 2;
bool quoted = false; bool quoted = false;
int c = '\0', c2; int c = '\0', c2;
@ -44,6 +44,9 @@ pkgconf_fgetline(char *line, size_t size, FILE *stream)
*s++ = c; *s++ = c;
break; break;
} }
else
*s++ = c;
quoted = false; quoted = false;
continue; continue;
} }

View File

@ -93,15 +93,18 @@ pkgconf_fragment_is_special(const char *string)
} }
static inline void static inline void
pkgconf_fragment_munge(const pkgconf_client_t *client, char *buf, size_t buflen, const char *source, const char *sysroot_dir) 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'; *buf = '\0';
if (!(flags & PKGCONF_PKG_PROPF_UNINSTALLED) || (client->flags & PKGCONF_PKG_PKGF_PKGCONF1_SYSROOT_RULES))
{
if (sysroot_dir == NULL) if (sysroot_dir == NULL)
sysroot_dir = pkgconf_tuple_find_global(client, "pc_sysrootdir"); sysroot_dir = pkgconf_tuple_find_global(client, "pc_sysrootdir");
if (sysroot_dir != NULL && pkgconf_fragment_should_munge(source, sysroot_dir)) if (sysroot_dir != NULL && pkgconf_fragment_should_munge(source, sysroot_dir))
pkgconf_strlcat(buf, sysroot_dir, buflen); pkgconf_strlcat(buf, sysroot_dir, buflen);
}
pkgconf_strlcat(buf, source, buflen); pkgconf_strlcat(buf, source, buflen);
@ -110,39 +113,40 @@ pkgconf_fragment_munge(const pkgconf_client_t *client, char *buf, size_t buflen,
} }
static inline char * static inline char *
pkgconf_fragment_copy_munged(const pkgconf_client_t *client, const char *source) pkgconf_fragment_copy_munged(const pkgconf_client_t *client, const char *source, unsigned int flags)
{ {
char mungebuf[PKGCONF_ITEM_SIZE]; char mungebuf[PKGCONF_ITEM_SIZE];
pkgconf_fragment_munge(client, mungebuf, sizeof mungebuf, source, client->sysroot_dir); pkgconf_fragment_munge(client, mungebuf, sizeof mungebuf, source, client->sysroot_dir, flags);
return strdup(mungebuf); return strdup(mungebuf);
} }
/* /*
* !doc * !doc
* *
* .. c:function:: void pkgconf_fragment_add(const pkgconf_client_t *client, pkgconf_list_t *list, const char *string) * .. 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. * 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_client_t* client: The pkgconf client being accessed.
* :param pkgconf_list_t* list: The fragment list. * :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 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 * :return: nothing
*/ */
void void
pkgconf_fragment_add(const pkgconf_client_t *client, pkgconf_list_t *list, const char *string) pkgconf_fragment_add(const pkgconf_client_t *client, pkgconf_list_t *list, const char *string, unsigned int flags)
{ {
pkgconf_fragment_t *frag; pkgconf_fragment_t *frag;
if (*string == '\0') if (*string == '\0')
return; return;
if (!pkgconf_fragment_is_special(string)) if (strlen(string) > 1 && !pkgconf_fragment_is_special(string))
{ {
frag = calloc(sizeof(pkgconf_fragment_t), 1); frag = calloc(sizeof(pkgconf_fragment_t), 1);
frag->type = *(string + 1); frag->type = *(string + 1);
frag->data = pkgconf_fragment_copy_munged(client, string + 2); 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); PKGCONF_TRACE(client, "added fragment {%c, '%s'} to list @%p", frag->type, frag->data, list);
} }
@ -150,17 +154,18 @@ pkgconf_fragment_add(const pkgconf_client_t *client, pkgconf_list_t *list, const
{ {
char mungebuf[PKGCONF_ITEM_SIZE]; char mungebuf[PKGCONF_ITEM_SIZE];
if (list->tail != NULL && list->tail->data != NULL) if (list->tail != NULL && list->tail->data != NULL &&
!(client->flags & PKGCONF_PKG_PKGF_DONT_MERGE_SPECIAL_FRAGMENTS))
{ {
pkgconf_fragment_t *parent = list->tail->data; pkgconf_fragment_t *parent = list->tail->data;
/* only attempt to merge 'special' fragments together */ /* only attempt to merge 'special' fragments together */
if (!parent->type && pkgconf_fragment_is_unmergeable(parent->data)) if (!parent->type && parent->data != NULL && pkgconf_fragment_is_unmergeable(parent->data))
{ {
size_t len; size_t len;
char *newdata; char *newdata;
pkgconf_fragment_munge(client, mungebuf, sizeof mungebuf, string, NULL); pkgconf_fragment_munge(client, mungebuf, sizeof mungebuf, string, NULL, flags);
len = strlen(parent->data) + strlen(mungebuf) + 2; len = strlen(parent->data) + strlen(mungebuf) + 2;
newdata = malloc(len); newdata = malloc(len);
@ -432,7 +437,11 @@ fragment_quote(const pkgconf_fragment_t *frag)
(*src > ')' && *src < '+') || (*src > ')' && *src < '+') ||
(*src > ':' && *src < '=') || (*src > ':' && *src < '=') ||
(*src > '=' && *src < '@') || (*src > '=' && *src < '@') ||
(*src > 'Z' && *src < '^') || (*src > 'Z' && *src < '\\') ||
#ifndef _WIN32
(*src == '\\') ||
#endif
(*src > '\\' && *src < '^') ||
(*src == '`') || (*src == '`') ||
(*src > 'z' && *src < '~') || (*src > 'z' && *src < '~') ||
(*src > '~'))) (*src > '~')))
@ -442,8 +451,10 @@ fragment_quote(const pkgconf_fragment_t *frag)
if ((ptrdiff_t)(dst - out) + 2 > outlen) if ((ptrdiff_t)(dst - out) + 2 > outlen)
{ {
ptrdiff_t offset = dst - out;
outlen *= 2; outlen *= 2;
out = realloc(out, outlen); out = realloc(out, outlen);
dst = out + offset;
} }
} }
@ -520,6 +531,7 @@ fragment_render_buf(const pkgconf_list_t *list, char *buf, size_t buflen, bool e
free(quoted); free(quoted);
} }
if (node->next != NULL)
*bptr++ = ' '; *bptr++ = ' ';
} }
@ -656,15 +668,16 @@ pkgconf_fragment_free(pkgconf_list_t *list)
* :param pkgconf_client_t* client: The pkgconf client being accessed. * :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* 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 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. * :param char* value: The string to parse into fragments.
* :return: true on success, false on parse error * :return: true on success, false on parse error
*/ */
bool bool
pkgconf_fragment_parse(const pkgconf_client_t *client, pkgconf_list_t *list, pkgconf_list_t *vars, const char *value) 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; int i, ret, argc;
char **argv; char **argv;
char *repstr = pkgconf_tuple_parse(client, vars, value); char *repstr = pkgconf_tuple_parse(client, vars, value, flags);
PKGCONF_TRACE(client, "post-subst: [%s] -> [%s]", value, repstr); PKGCONF_TRACE(client, "post-subst: [%s] -> [%s]", value, repstr);
@ -678,6 +691,8 @@ pkgconf_fragment_parse(const pkgconf_client_t *client, pkgconf_list_t *list, pkg
for (i = 0; i < argc; i++) for (i = 0; i < argc; i++)
{ {
PKGCONF_TRACE(client, "processing %s", argv[i]);
if (argv[i] == NULL) if (argv[i] == NULL)
{ {
PKGCONF_TRACE(client, "parsed fragment string is inconsistent: argc = %d while argv[%d] == NULL", argc, i); PKGCONF_TRACE(client, "parsed fragment string is inconsistent: argc = %d while argv[%d] == NULL", argc, i);
@ -686,7 +701,7 @@ pkgconf_fragment_parse(const pkgconf_client_t *client, pkgconf_list_t *list, pkg
return false; return false;
} }
pkgconf_fragment_add(client, list, argv[i]); pkgconf_fragment_add(client, list, argv[i], flags);
} }
pkgconf_argv_free(argv); pkgconf_argv_free(argv);

View File

@ -34,6 +34,14 @@ typedef struct {
#define PKGCONF_LIST_INITIALIZER { NULL, NULL, 0 } #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 static inline void
pkgconf_node_insert(pkgconf_node_t *node, void *data, pkgconf_list_t *list) pkgconf_node_insert(pkgconf_node_t *node, void *data, pkgconf_list_t *list)
{ {

View File

@ -2,8 +2,7 @@
#define LIBPKGCONF_LIBPKGCONF_API_H #define LIBPKGCONF_LIBPKGCONF_API_H
/* Makefile.am specifies visibility using the libtool option -export-symbols-regex '^pkgconf_' /* Makefile.am specifies visibility using the libtool option -export-symbols-regex '^pkgconf_'
* Unfortunately, that is not available when building with cmake, so use attributes instead, * Unfortunately, that is not available when building with meson, so use attributes instead.
* in a way that doesn't depend on any cmake magic.
*/ */
#if defined(PKGCONFIG_IS_STATIC) #if defined(PKGCONFIG_IS_STATIC)
# define PKGCONF_API # define PKGCONF_API

View File

@ -20,6 +20,7 @@
#include <stdarg.h> #include <stdarg.h>
#include <stddef.h> #include <stddef.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h>
#include <libpkgconf/libpkgconf-api.h> #include <libpkgconf/libpkgconf-api.h>
#include <libpkgconf/iter.h> #include <libpkgconf/iter.h>
#include <libpkgconf/bsdstubs.h> #include <libpkgconf/bsdstubs.h>
@ -78,8 +79,8 @@ typedef struct pkgconf_cross_personality_ pkgconf_cross_personality_t;
#define PKGCONF_FOREACH_LIST_ENTRY_REVERSE(tail, value) \ #define PKGCONF_FOREACH_LIST_ENTRY_REVERSE(tail, value) \
for ((value) = (tail); (value) != NULL; (value) = (value)->prev) for ((value) = (tail); (value) != NULL; (value) = (value)->prev)
#define LIBPKGCONF_VERSION 10990 #define LIBPKGCONF_VERSION 10905
#define LIBPKGCONF_VERSION_STR "1.9.90" #define LIBPKGCONF_VERSION_STR "1.9.5"
struct pkgconf_fragment_ { struct pkgconf_fragment_ {
pkgconf_node_t iter; pkgconf_node_t iter;
@ -100,6 +101,9 @@ struct pkgconf_dependency_ {
pkgconf_pkg_t *match; pkgconf_pkg_t *match;
unsigned int flags; unsigned int flags;
int refcount;
pkgconf_client_t *owner;
}; };
struct pkgconf_tuple_ { struct pkgconf_tuple_ {
@ -107,8 +111,12 @@ struct pkgconf_tuple_ {
char *key; char *key;
char *value; char *value;
unsigned int flags;
}; };
#define PKGCONF_PKG_TUPLEF_OVERRIDE 0x1
struct pkgconf_path_ { struct pkgconf_path_ {
pkgconf_node_t lnode; pkgconf_node_t lnode;
@ -120,13 +128,10 @@ struct pkgconf_path_ {
#define PKGCONF_PKG_PROPF_NONE 0x00 #define PKGCONF_PKG_PROPF_NONE 0x00
#define PKGCONF_PKG_PROPF_STATIC 0x01 #define PKGCONF_PKG_PROPF_STATIC 0x01
#define PKGCONF_PKG_PROPF_CACHED 0x02 #define PKGCONF_PKG_PROPF_CACHED 0x02
#define PKGCONF_PKG_PROPF_SEEN 0x04
#define PKGCONF_PKG_PROPF_UNINSTALLED 0x08 #define PKGCONF_PKG_PROPF_UNINSTALLED 0x08
#define PKGCONF_PKG_PROPF_VIRTUAL 0x10 #define PKGCONF_PKG_PROPF_VIRTUAL 0x10
struct pkgconf_pkg_ { struct pkgconf_pkg_ {
pkgconf_node_t cache_iter;
int refcount; int refcount;
char *id; char *id;
char *filename; char *filename;
@ -135,6 +140,9 @@ struct pkgconf_pkg_ {
char *description; char *description;
char *url; char *url;
char *pc_filedir; char *pc_filedir;
char *license;
char *maintainer;
char *copyright;
pkgconf_list_t libs; pkgconf_list_t libs;
pkgconf_list_t libs_private; pkgconf_list_t libs_private;
@ -157,16 +165,19 @@ struct pkgconf_pkg_ {
*/ */
pkgconf_tuple_t *orig_prefix; pkgconf_tuple_t *orig_prefix;
pkgconf_tuple_t *prefix; pkgconf_tuple_t *prefix;
uint64_t serial;
size_t hits;
}; };
typedef bool (*pkgconf_pkg_iteration_func_t)(const pkgconf_pkg_t *pkg, void *data); 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 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_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, const void *data); typedef bool (*pkgconf_error_handler_func_t)(const char *msg, const pkgconf_client_t *client, void *data);
struct pkgconf_client_ { struct pkgconf_client_ {
pkgconf_list_t dir_list; pkgconf_list_t dir_list;
pkgconf_list_t pkg_cache;
pkgconf_list_t filter_libdirs; pkgconf_list_t filter_libdirs;
pkgconf_list_t filter_includedirs; pkgconf_list_t filter_includedirs;
@ -191,6 +202,11 @@ struct pkgconf_client_ {
char *prefix_varname; char *prefix_varname;
bool already_sent_notice; bool already_sent_notice;
uint64_t serial;
pkgconf_pkg_t **cache_table;
size_t cache_count;
}; };
struct pkgconf_cross_personality_ { struct pkgconf_cross_personality_ {
@ -202,6 +218,9 @@ struct pkgconf_cross_personality_ {
pkgconf_list_t filter_includedirs; pkgconf_list_t filter_includedirs;
char *sysroot_dir; char *sysroot_dir;
bool want_default_static;
bool want_default_pure;
}; };
/* client.c */ /* client.c */
@ -228,8 +247,9 @@ PKGCONF_API void pkgconf_client_dir_list_build(pkgconf_client_t *client, const p
/* personality.c */ /* personality.c */
PKGCONF_API pkgconf_cross_personality_t *pkgconf_cross_personality_default(void); 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 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 int)(c))) #define PKGCONF_IS_MODULE_SEPARATOR(c) ((c) == ',' || isspace ((unsigned char)(c)))
#define PKGCONF_IS_OPERATOR_CHAR(c) ((c) == '<' || (c) == '>' || (c) == '!' || (c) == '=') #define PKGCONF_IS_OPERATOR_CHAR(c) ((c) == '<' || (c) == '>' || (c) == '!' || (c) == '=')
#define PKGCONF_PKG_PKGF_NONE 0x0000 #define PKGCONF_PKG_PKGF_NONE 0x0000
@ -247,8 +267,12 @@ PKGCONF_API pkgconf_cross_personality_t *pkgconf_cross_personality_find(const ch
#define PKGCONF_PKG_PKGF_DONT_RELOCATE_PATHS 0x0800 #define PKGCONF_PKG_PKGF_DONT_RELOCATE_PATHS 0x0800
#define PKGCONF_PKG_PKGF_SIMPLIFY_ERRORS 0x1000 #define PKGCONF_PKG_PKGF_SIMPLIFY_ERRORS 0x1000
#define PKGCONF_PKG_PKGF_DONT_FILTER_INTERNAL_CFLAGS 0x2000 #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_INTERNAL 0x1
#define PKGCONF_PKG_DEPF_PRIVATE 0x2
#define PKGCONF_PKG_ERRF_OK 0x0 #define PKGCONF_PKG_ERRF_OK 0x0
#define PKGCONF_PKG_ERRF_PACKAGE_NOT_FOUND 0x1 #define PKGCONF_PKG_ERRF_PACKAGE_NOT_FOUND 0x1
@ -276,17 +300,17 @@ PKGCONF_API void pkgconf_parser_parse(FILE *f, void *data, const pkgconf_parser_
PKGCONF_API bool pkgconf_error(const pkgconf_client_t *client, const char *format, ...) PRINTFLIKE(2, 3); 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_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_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, const void *data); PKGCONF_API bool pkgconf_default_error_handler(const char *msg, const pkgconf_client_t *client, void *data);
#ifndef PKGCONF_LITE #ifndef PKGCONF_LITE
#if defined(__GNUC__) || defined(__INTEL_COMPILER) #if defined(__GNUC__) || defined(__INTEL_COMPILER)
#define PKGCONF_TRACE(client, ...) do { \ #define PKGCONF_TRACE(client, ...) do { \
pkgconf_trace(client, __FILE__, __LINE__, __PRETTY_FUNCTION__, __VA_ARGS__); \ pkgconf_trace(client, __FILE__, __LINE__, __PRETTY_FUNCTION__, __VA_ARGS__); \
} while (0); } while (0)
#else #else
#define PKGCONF_TRACE(client, ...) do { \ #define PKGCONF_TRACE(client, ...) do { \
pkgconf_trace(client, __FILE__, __LINE__, __func__, __VA_ARGS__); \ pkgconf_trace(client, __FILE__, __LINE__, __func__, __VA_ARGS__); \
} while (0); } while (0)
#endif #endif
#else #else
#define PKGCONF_TRACE(client, ...) #define PKGCONF_TRACE(client, ...)
@ -309,12 +333,16 @@ 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); PKGCONF_API pkgconf_pkg_t *pkgconf_scan_all(pkgconf_client_t *client, void *ptr, pkgconf_pkg_iteration_func_t func);
/* parse.c */ /* parse.c */
PKGCONF_API pkgconf_pkg_t *pkgconf_pkg_new_from_file(pkgconf_client_t *client, const char *path, FILE *f); PKGCONF_API pkgconf_pkg_t *pkgconf_pkg_new_from_file(pkgconf_client_t *client, const char *path, FILE *f, unsigned int flags);
PKGCONF_API void pkgconf_dependency_parse_str(const pkgconf_client_t *client, pkgconf_list_t *deplist_head, const char *depends, 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(const pkgconf_client_t *client, pkgconf_pkg_t *pkg, 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_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(pkgconf_list_t *list);
PKGCONF_API pkgconf_dependency_t *pkgconf_dependency_add(const pkgconf_client_t *client, pkgconf_list_t *list, const char *package, const char *version, pkgconf_pkg_comparator_t compare, unsigned int flags); 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 */ /* argvsplit.c */
PKGCONF_API int pkgconf_argv_split(const char *src, int *argc, char ***argv); PKGCONF_API int pkgconf_argv_split(const char *src, int *argc, char ***argv);
@ -327,8 +355,8 @@ typedef struct pkgconf_fragment_render_ops_ {
} pkgconf_fragment_render_ops_t; } pkgconf_fragment_render_ops_t;
typedef bool (*pkgconf_fragment_filter_func_t)(const pkgconf_client_t *client, const pkgconf_fragment_t *frag, void *data); 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); 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_add(const pkgconf_client_t *client, pkgconf_list_t *list, const char *string); 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(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_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_delete(pkgconf_list_t *list, pkgconf_fragment_t *node);
@ -343,9 +371,9 @@ PKGCONF_API bool pkgconf_fragment_has_system_dir(const pkgconf_client_t *client,
PKGCONF_API char *pkgconf_fgetline(char *line, size_t size, FILE *stream); PKGCONF_API char *pkgconf_fgetline(char *line, size_t size, FILE *stream);
/* tuple.c */ /* 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); 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_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); 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(pkgconf_list_t *list);
PKGCONF_API void pkgconf_tuple_free_entry(pkgconf_tuple_t *tuple, 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 void pkgconf_tuple_add_global(pkgconf_client_t *client, const char *key, const char *value);
@ -356,9 +384,11 @@ PKGCONF_API void pkgconf_tuple_define_global(pkgconf_client_t *client, const cha
/* queue.c */ /* queue.c */
PKGCONF_API void pkgconf_queue_push(pkgconf_list_t *list, const char *package); 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_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 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_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 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 */ /* cache.c */
PKGCONF_API pkgconf_pkg_t *pkgconf_cache_lookup(pkgconf_client_t *client, const char *id); PKGCONF_API pkgconf_pkg_t *pkgconf_cache_lookup(pkgconf_client_t *client, const char *id);

View File

@ -8,5 +8,5 @@ install_headers('libpkgconf.h',
'iter.h', 'iter.h',
'bsdstubs.h', 'bsdstubs.h',
'libpkgconf-api.h', 'libpkgconf-api.h',
subdir : 'libpkgconf') subdir : 'pkgconf/libpkgconf')

View File

@ -44,14 +44,23 @@ pkgconf_parser_parse(FILE *f, void *data, const pkgconf_parser_operand_func_t *o
lineno++; lineno++;
p = readbuf; p = readbuf;
while (*p && (isalpha((unsigned int)*p) || isdigit((unsigned int)*p) || *p == '_' || *p == '.')) while (*p && isspace((unsigned char)*p))
p++;
if (*p && p != readbuf)
{
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++; p++;
key = readbuf; if (!isalpha((unsigned char)*key) &&
if (!isalpha((unsigned int)*key) && !isdigit((unsigned int)*p)) !isdigit((unsigned char)*p))
continue; continue;
while (*p && isspace((unsigned int)*p)) while (*p && isspace((unsigned char)*p))
{ {
if (!warned_key_whitespace) if (!warned_key_whitespace)
{ {
@ -66,15 +75,18 @@ pkgconf_parser_parse(FILE *f, void *data, const pkgconf_parser_operand_func_t *o
} }
op = *p; op = *p;
if (*p != '\0')
{
*p = '\0'; *p = '\0';
p++; p++;
}
while (*p && isspace((unsigned int)*p)) while (*p && isspace((unsigned char)*p))
p++; p++;
value = p; value = p;
p = value + (strlen(value) - 1); p = value + (strlen(value) - 1);
while (*p && isspace((unsigned int) *p) && p > value) while (*p && isspace((unsigned char) *p) && p > value)
{ {
if (!warned_value_whitespace && op == '=') if (!warned_value_whitespace && op == '=')
{ {
@ -86,7 +98,6 @@ pkgconf_parser_parse(FILE *f, void *data, const pkgconf_parser_operand_func_t *o
*p = '\0'; *p = '\0';
p--; p--;
} }
if (ops[(unsigned char) op]) if (ops[(unsigned char) op])
ops[(unsigned char) op](data, lineno, key, value); ops[(unsigned char) op](data, lineno, key, value);
} }

View File

@ -17,10 +17,6 @@
#include <libpkgconf/stdinc.h> #include <libpkgconf/stdinc.h>
#include <libpkgconf/libpkgconf.h> #include <libpkgconf/libpkgconf.h>
#if defined(HAVE_CYGWIN_CONV_PATH) && defined(__MSYS__)
# include <sys/cygwin.h>
#endif
#if defined(HAVE_SYS_STAT_H) && ! defined(_WIN32) #if defined(HAVE_SYS_STAT_H) && ! defined(_WIN32)
# include <sys/stat.h> # include <sys/stat.h>
# define PKGCONF_CACHE_INODES # define PKGCONF_CACHE_INODES
@ -92,16 +88,12 @@ pkgconf_path_add(const char *text, pkgconf_list_t *dirlist, bool filter)
return; return;
if (S_ISLNK(st.st_mode)) if (S_ISLNK(st.st_mode))
{ {
char *linkdest = realpath(path, NULL); char pathbuf[PKGCONF_ITEM_SIZE * 4];
char *linkdest = realpath(path, pathbuf);
if (linkdest != NULL && stat(linkdest, &st) == -1) if (linkdest != NULL && stat(linkdest, &st) == -1)
{
free(linkdest);
return; return;
} }
free(linkdest);
}
if (path_list_contains_entry(path, dirlist, &st)) if (path_list_contains_entry(path, dirlist, &st))
return; return;
} }
@ -276,6 +268,8 @@ pkgconf_path_free(pkgconf_list_t *dirlist)
free(pnode->path); free(pnode->path);
free(pnode); free(pnode);
} }
pkgconf_list_zero(dirlist);
} }
static char * static char *
@ -310,7 +304,7 @@ normpath(const char *path)
* *
* .. c:function:: bool pkgconf_path_relocate(char *buf, size_t buflen) * .. c:function:: bool pkgconf_path_relocate(char *buf, size_t buflen)
* *
* Relocates a path, possibly calling normpath() or cygwin_conv_path() on it. * Relocates a path, possibly calling normpath() on it.
* *
* :param char* buf: The path to relocate. * :param char* buf: The path to relocate.
* :param size_t buflen: The buffer length the path is contained in. * :param size_t buflen: The buffer length the path is contained in.
@ -320,28 +314,10 @@ normpath(const char *path)
bool bool
pkgconf_path_relocate(char *buf, size_t buflen) pkgconf_path_relocate(char *buf, size_t buflen)
{ {
#if defined(HAVE_CYGWIN_CONV_PATH) && defined(__MSYS__) #ifdef _WIN32
ssize_t size; char *ti;
char *tmpbuf, *ti; #endif
size = cygwin_conv_path(CCP_POSIX_TO_WIN_A, buf, NULL, 0);
if (size < 0 || (size_t) size > buflen)
return false;
tmpbuf = malloc(size);
if (cygwin_conv_path(CCP_POSIX_TO_WIN_A, buf, tmpbuf, size))
return false;
pkgconf_strlcpy(buf, tmpbuf, buflen);
free(tmpbuf);
/* rewrite any backslash arguments for best compatibility */
for (ti = buf; *ti != '\0'; ti++)
{
if (*ti == '\\')
*ti = '/';
}
#else
char *tmpbuf; char *tmpbuf;
if ((tmpbuf = normpath(buf)) != NULL) if ((tmpbuf = normpath(buf)) != NULL)
@ -356,7 +332,6 @@ pkgconf_path_relocate(char *buf, size_t buflen)
pkgconf_strlcpy(buf, tmpbuf, buflen); pkgconf_strlcpy(buf, tmpbuf, buflen);
free(tmpbuf); free(tmpbuf);
} }
#endif
return true; return true;
} }

View File

@ -17,13 +17,30 @@
#include <libpkgconf/stdinc.h> #include <libpkgconf/stdinc.h>
#include <libpkgconf/libpkgconf.h> #include <libpkgconf/libpkgconf.h>
/*
* !doc
*
* libpkgconf `personality` module
* =========================
*/
#ifdef _WIN32 #ifdef _WIN32
# define strcasecmp _stricmp # define strcasecmp _stricmp
#endif #endif
static bool default_personality_init = false; /*
* 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 = { static pkgconf_cross_personality_t default_personality = {
.name = "default", .name = "default",
#ifdef _WIN32
.want_default_static = true,
.want_default_pure = true,
#endif
}; };
static inline void static inline void
@ -81,24 +98,49 @@ build_default_search_path(pkgconf_list_t* dirlist)
* *
* Returns the default cross-compile personality. * Returns the default cross-compile personality.
* *
* Not thread safe.
*
* :rtype: pkgconf_cross_personality_t* * :rtype: pkgconf_cross_personality_t*
* :return: the default cross-compile personality * :return: the default cross-compile personality
*/ */
pkgconf_cross_personality_t * pkgconf_cross_personality_t *
pkgconf_cross_personality_default(void) pkgconf_cross_personality_default(void)
{ {
if (default_personality_init) if (default_personality_init) {
++default_personality_init;
return &default_personality; return &default_personality;
}
build_default_search_path(&default_personality.dir_list); build_default_search_path(&default_personality.dir_list);
pkgconf_path_split(SYSTEM_LIBDIR, &default_personality.filter_libdirs, true); pkgconf_path_split(SYSTEM_LIBDIR, &default_personality.filter_libdirs, false);
pkgconf_path_split(SYSTEM_INCLUDEDIR, &default_personality.filter_includedirs, true); pkgconf_path_split(SYSTEM_INCLUDEDIR, &default_personality.filter_includedirs, false);
default_personality_init = true; ++default_personality_init;
return &default_personality; return &default_personality;
} }
/*
* !doc
*
* .. c:function:: void pkgconf_cross_personality_deinit(pkgconf_cross_personality_t *)
*
* Decrements the count of default cross personality instances.
*
* Not thread safe.
*
* :rtype: void
*/
void
pkgconf_cross_personality_deinit(pkgconf_cross_personality_t *personality)
{
if (--default_personality_init == 0) {
pkgconf_path_free(&personality->dir_list);
pkgconf_path_free(&personality->filter_libdirs);
pkgconf_path_free(&personality->filter_includedirs);
}
}
#ifndef PKGCONF_LITE #ifndef PKGCONF_LITE
static bool static bool
valid_triplet(const char *triplet) valid_triplet(const char *triplet)
@ -106,7 +148,7 @@ valid_triplet(const char *triplet)
const char *c = triplet; const char *c = triplet;
for (; *c; c++) for (; *c; c++)
if (!isalnum(*c) && *c != '-' && *c != '_') if (!isalnum((unsigned char)*c) && *c != '-' && *c != '_')
return false; return false;
return true; return true;
@ -119,6 +161,16 @@ typedef struct {
const ptrdiff_t offset; const ptrdiff_t offset;
} personality_keyword_pair_t; } 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 static void
personality_copy_func(pkgconf_cross_personality_t *p, const char *keyword, const size_t lineno, const ptrdiff_t offset, char *value) personality_copy_func(pkgconf_cross_personality_t *p, const char *keyword, const size_t lineno, const ptrdiff_t offset, char *value)
{ {
@ -146,6 +198,8 @@ static const personality_keyword_pair_t personality_keyword_pairs[] = {
{"SystemIncludePaths", personality_fragment_func, offsetof(pkgconf_cross_personality_t, filter_includedirs)}, {"SystemIncludePaths", personality_fragment_func, offsetof(pkgconf_cross_personality_t, filter_includedirs)},
{"SystemLibraryPaths", personality_fragment_func, offsetof(pkgconf_cross_personality_t, filter_libdirs)}, {"SystemLibraryPaths", personality_fragment_func, offsetof(pkgconf_cross_personality_t, filter_libdirs)},
{"Triplet", personality_copy_func, offsetof(pkgconf_cross_personality_t, name)}, {"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 static int
@ -168,7 +222,7 @@ personality_keyword_set(pkgconf_cross_personality_t *p, const size_t lineno, con
pair->func(p, keyword, lineno, pair->offset, value); pair->func(p, keyword, lineno, pair->offset, value);
} }
static const pkgconf_parser_operand_func_t personality_parser_ops[] = { static const pkgconf_parser_operand_func_t personality_parser_ops[256] = {
[':'] = (pkgconf_parser_operand_func_t) personality_keyword_set [':'] = (pkgconf_parser_operand_func_t) personality_keyword_set
}; };
@ -248,6 +302,6 @@ pkgconf_cross_personality_find(const char *triplet)
finish: finish:
pkgconf_path_free(&plist); pkgconf_path_free(&plist);
return out; return out != NULL ? out : pkgconf_cross_personality_default();
} }
#endif #endif

View File

@ -37,6 +37,14 @@
#define PKG_CONFIG_EXT ".pc" #define PKG_CONFIG_EXT ".pc"
static unsigned int
pkgconf_pkg_traverse_main(pkgconf_client_t *client,
pkgconf_pkg_t *root,
pkgconf_pkg_traverse_func_t func,
void *data,
int maxdepth,
unsigned int skip_flags);
static inline bool static inline bool
str_has_suffix(const char *str, const char *suffix) str_has_suffix(const char *str, const char *suffix)
{ {
@ -64,7 +72,7 @@ pkg_get_parent_dir(pkgconf_pkg_t *pkg)
return strdup(buf); return strdup(buf);
} }
typedef void (*pkgconf_pkg_parser_keyword_func_t)(const pkgconf_client_t *client, pkgconf_pkg_t *pkg, const char *keyword, const size_t lineno, const ptrdiff_t offset, const char *value); typedef void (*pkgconf_pkg_parser_keyword_func_t)(pkgconf_client_t *client, pkgconf_pkg_t *pkg, const char *keyword, const size_t lineno, const ptrdiff_t offset, const char *value);
typedef struct { typedef struct {
const char *keyword; const char *keyword;
const pkgconf_pkg_parser_keyword_func_t func; const pkgconf_pkg_parser_keyword_func_t func;
@ -78,17 +86,17 @@ static int pkgconf_pkg_parser_keyword_pair_cmp(const void *key, const void *ptr)
} }
static void static void
pkgconf_pkg_parser_tuple_func(const pkgconf_client_t *client, pkgconf_pkg_t *pkg, const char *keyword, const size_t lineno, const ptrdiff_t offset, const char *value) pkgconf_pkg_parser_tuple_func(pkgconf_client_t *client, pkgconf_pkg_t *pkg, const char *keyword, const size_t lineno, const ptrdiff_t offset, const char *value)
{ {
(void) keyword; (void) keyword;
(void) lineno; (void) lineno;
char **dest = (char **)((char *) pkg + offset); char **dest = (char **)((char *) pkg + offset);
*dest = pkgconf_tuple_parse(client, &pkg->vars, value); *dest = pkgconf_tuple_parse(client, &pkg->vars, value, pkg->flags);
} }
static void static void
pkgconf_pkg_parser_version_func(const pkgconf_client_t *client, pkgconf_pkg_t *pkg, const char *keyword, const size_t lineno, const ptrdiff_t offset, const char *value) pkgconf_pkg_parser_version_func(pkgconf_client_t *client, pkgconf_pkg_t *pkg, const char *keyword, const size_t lineno, const ptrdiff_t offset, const char *value)
{ {
(void) keyword; (void) keyword;
(void) lineno; (void) lineno;
@ -97,10 +105,10 @@ pkgconf_pkg_parser_version_func(const pkgconf_client_t *client, pkgconf_pkg_t *p
char **dest = (char **)((char *) pkg + offset); char **dest = (char **)((char *) pkg + offset);
/* cut at any detected whitespace */ /* cut at any detected whitespace */
p = pkgconf_tuple_parse(client, &pkg->vars, value); p = pkgconf_tuple_parse(client, &pkg->vars, value, pkg->flags);
len = strcspn(p, " \t\r\n"); len = strcspn(p, " \t");
if (len) if (len != strlen(p))
{ {
i = p + (ptrdiff_t) len; i = p + (ptrdiff_t) len;
*i = '\0'; *i = '\0';
@ -113,10 +121,10 @@ pkgconf_pkg_parser_version_func(const pkgconf_client_t *client, pkgconf_pkg_t *p
} }
static void static void
pkgconf_pkg_parser_fragment_func(const pkgconf_client_t *client, pkgconf_pkg_t *pkg, const char *keyword, const size_t lineno, const ptrdiff_t offset, const char *value) pkgconf_pkg_parser_fragment_func(pkgconf_client_t *client, pkgconf_pkg_t *pkg, const char *keyword, const size_t lineno, const ptrdiff_t offset, const char *value)
{ {
pkgconf_list_t *dest = (pkgconf_list_t *)((char *) pkg + offset); pkgconf_list_t *dest = (pkgconf_list_t *)((char *) pkg + offset);
bool ret = pkgconf_fragment_parse(client, dest, &pkg->vars, value); bool ret = pkgconf_fragment_parse(client, dest, &pkg->vars, value, pkg->flags);
if (!ret) if (!ret)
{ {
@ -126,7 +134,7 @@ pkgconf_pkg_parser_fragment_func(const pkgconf_client_t *client, pkgconf_pkg_t *
} }
static void static void
pkgconf_pkg_parser_dependency_func(const pkgconf_client_t *client, pkgconf_pkg_t *pkg, const char *keyword, const size_t lineno, const ptrdiff_t offset, const char *value) pkgconf_pkg_parser_dependency_func(pkgconf_client_t *client, pkgconf_pkg_t *pkg, const char *keyword, const size_t lineno, const ptrdiff_t offset, const char *value)
{ {
(void) keyword; (void) keyword;
(void) lineno; (void) lineno;
@ -137,7 +145,7 @@ pkgconf_pkg_parser_dependency_func(const pkgconf_client_t *client, pkgconf_pkg_t
/* a variant of pkgconf_pkg_parser_dependency_func which colors the dependency node as an "internal" dependency. */ /* a variant of pkgconf_pkg_parser_dependency_func which colors the dependency node as an "internal" dependency. */
static void static void
pkgconf_pkg_parser_internal_dependency_func(const pkgconf_client_t *client, pkgconf_pkg_t *pkg, const char *keyword, const size_t lineno, const ptrdiff_t offset, const char *value) pkgconf_pkg_parser_internal_dependency_func(pkgconf_client_t *client, pkgconf_pkg_t *pkg, const char *keyword, const size_t lineno, const ptrdiff_t offset, const char *value)
{ {
(void) keyword; (void) keyword;
(void) lineno; (void) lineno;
@ -146,19 +154,34 @@ pkgconf_pkg_parser_internal_dependency_func(const pkgconf_client_t *client, pkgc
pkgconf_dependency_parse(client, pkg, dest, value, PKGCONF_PKG_DEPF_INTERNAL); pkgconf_dependency_parse(client, pkg, dest, value, PKGCONF_PKG_DEPF_INTERNAL);
} }
/* a variant of pkgconf_pkg_parser_dependency_func which colors the dependency node as a "private" dependency. */
static void
pkgconf_pkg_parser_private_dependency_func(pkgconf_client_t *client, pkgconf_pkg_t *pkg, const char *keyword, const size_t lineno, const ptrdiff_t offset, const char *value)
{
(void) keyword;
(void) lineno;
pkgconf_list_t *dest = (pkgconf_list_t *)((char *) pkg + offset);
pkgconf_dependency_parse(client, pkg, dest, value, PKGCONF_PKG_DEPF_PRIVATE);
}
/* keep this in alphabetical order */ /* keep this in alphabetical order */
static const pkgconf_pkg_parser_keyword_pair_t pkgconf_pkg_parser_keyword_funcs[] = { static const pkgconf_pkg_parser_keyword_pair_t pkgconf_pkg_parser_keyword_funcs[] = {
{"CFLAGS", pkgconf_pkg_parser_fragment_func, offsetof(pkgconf_pkg_t, cflags)}, {"CFLAGS", pkgconf_pkg_parser_fragment_func, offsetof(pkgconf_pkg_t, cflags)},
{"CFLAGS.private", pkgconf_pkg_parser_fragment_func, offsetof(pkgconf_pkg_t, cflags_private)}, {"CFLAGS.private", pkgconf_pkg_parser_fragment_func, offsetof(pkgconf_pkg_t, cflags_private)},
{"Conflicts", pkgconf_pkg_parser_dependency_func, offsetof(pkgconf_pkg_t, conflicts)}, {"Conflicts", pkgconf_pkg_parser_dependency_func, offsetof(pkgconf_pkg_t, conflicts)},
{"Copyright", pkgconf_pkg_parser_tuple_func, offsetof(pkgconf_pkg_t, copyright)},
{"Description", pkgconf_pkg_parser_tuple_func, offsetof(pkgconf_pkg_t, description)}, {"Description", pkgconf_pkg_parser_tuple_func, offsetof(pkgconf_pkg_t, description)},
{"LIBS", pkgconf_pkg_parser_fragment_func, offsetof(pkgconf_pkg_t, libs)}, {"LIBS", pkgconf_pkg_parser_fragment_func, offsetof(pkgconf_pkg_t, libs)},
{"LIBS.private", pkgconf_pkg_parser_fragment_func, offsetof(pkgconf_pkg_t, libs_private)}, {"LIBS.private", pkgconf_pkg_parser_fragment_func, offsetof(pkgconf_pkg_t, libs_private)},
{"License", pkgconf_pkg_parser_tuple_func, offsetof(pkgconf_pkg_t, license)},
{"Maintainer", pkgconf_pkg_parser_tuple_func, offsetof(pkgconf_pkg_t, maintainer)},
{"Name", pkgconf_pkg_parser_tuple_func, offsetof(pkgconf_pkg_t, realname)}, {"Name", pkgconf_pkg_parser_tuple_func, offsetof(pkgconf_pkg_t, realname)},
{"Provides", pkgconf_pkg_parser_dependency_func, offsetof(pkgconf_pkg_t, provides)}, {"Provides", pkgconf_pkg_parser_dependency_func, offsetof(pkgconf_pkg_t, provides)},
{"Requires", pkgconf_pkg_parser_dependency_func, offsetof(pkgconf_pkg_t, required)}, {"Requires", pkgconf_pkg_parser_dependency_func, offsetof(pkgconf_pkg_t, required)},
{"Requires.internal", pkgconf_pkg_parser_internal_dependency_func, offsetof(pkgconf_pkg_t, requires_private)}, {"Requires.internal", pkgconf_pkg_parser_internal_dependency_func, offsetof(pkgconf_pkg_t, requires_private)},
{"Requires.private", pkgconf_pkg_parser_dependency_func, offsetof(pkgconf_pkg_t, requires_private)}, {"Requires.private", pkgconf_pkg_parser_private_dependency_func, offsetof(pkgconf_pkg_t, requires_private)},
{"URL", pkgconf_pkg_parser_tuple_func, offsetof(pkgconf_pkg_t, url)},
{"Version", pkgconf_pkg_parser_version_func, offsetof(pkgconf_pkg_t, version)}, {"Version", pkgconf_pkg_parser_version_func, offsetof(pkgconf_pkg_t, version)},
}; };
@ -214,6 +237,37 @@ determine_prefix(const pkgconf_pkg_t *pkg, char *buf, size_t buflen)
return buf; return buf;
} }
/*
* Takes a real path and converts it to a pkgconf value. This means normalizing
* directory separators and escaping things (only spaces covered atm).
*
* This is useful for things like prefix/pcfiledir which might get injected
* at runtime and are not sourced from the .pc file.
*
* "C:\foo bar\baz" -> "C:/foo\ bar/baz"
* "/foo bar/baz" -> "/foo\ bar/baz"
*/
static char *
convert_path_to_value(const char *path)
{
char *buf = calloc((strlen(path) + 1) * 2, 1);
char *bptr = buf;
const char *i;
for (i = path; *i != '\0'; i++)
{
if (*i == PKG_DIR_SEP_S)
*bptr++ = '/';
else if (*i == ' ') {
*bptr++ = '\\';
*bptr++ = *i;
} else
*bptr++ = *i;
}
return buf;
}
static void static void
remove_additional_separators(char *buf) remove_additional_separators(char *buf)
{ {
@ -238,16 +292,6 @@ remove_additional_separators(char *buf)
static void static void
canonicalize_path(char *buf) canonicalize_path(char *buf)
{ {
#ifdef _WIN32
char *p = buf;
while (*p) {
if (*p == '\\')
*p = '/';
p++;
}
#endif
remove_additional_separators(buf); remove_additional_separators(buf);
} }
@ -283,10 +327,10 @@ pkgconf_pkg_parser_value_set(void *opaque, const size_t lineno, const char *keyw
pkgconf_strlcpy(newvalue, pkg->prefix->value, sizeof newvalue); pkgconf_strlcpy(newvalue, pkg->prefix->value, sizeof newvalue);
pkgconf_strlcat(newvalue, canonicalized_value + strlen(pkg->orig_prefix->value), sizeof newvalue); pkgconf_strlcat(newvalue, canonicalized_value + strlen(pkg->orig_prefix->value), sizeof newvalue);
pkgconf_tuple_add(pkg->owner, &pkg->vars, keyword, newvalue, false); pkgconf_tuple_add(pkg->owner, &pkg->vars, keyword, newvalue, false, pkg->flags);
} }
else if (strcmp(keyword, pkg->owner->prefix_varname) || !(pkg->owner->flags & PKGCONF_PKG_PKGF_REDEFINE_PREFIX)) else if (strcmp(keyword, pkg->owner->prefix_varname) || !(pkg->owner->flags & PKGCONF_PKG_PKGF_REDEFINE_PREFIX))
pkgconf_tuple_add(pkg->owner, &pkg->vars, keyword, value, true); pkgconf_tuple_add(pkg->owner, &pkg->vars, keyword, value, true, pkg->flags);
else else
{ {
char pathbuf[PKGCONF_ITEM_SIZE]; char pathbuf[PKGCONF_ITEM_SIZE];
@ -294,11 +338,13 @@ pkgconf_pkg_parser_value_set(void *opaque, const size_t lineno, const char *keyw
if (relvalue != NULL) if (relvalue != NULL)
{ {
pkg->orig_prefix = pkgconf_tuple_add(pkg->owner, &pkg->vars, "orig_prefix", canonicalized_value, true); char *prefix_value = convert_path_to_value(relvalue);
pkg->prefix = pkgconf_tuple_add(pkg->owner, &pkg->vars, keyword, relvalue, false); pkg->orig_prefix = pkgconf_tuple_add(pkg->owner, &pkg->vars, "orig_prefix", canonicalized_value, true, pkg->flags);
pkg->prefix = pkgconf_tuple_add(pkg->owner, &pkg->vars, keyword, prefix_value, false, pkg->flags);
free(prefix_value);
} }
else else
pkgconf_tuple_add(pkg->owner, &pkg->vars, keyword, value, true); pkgconf_tuple_add(pkg->owner, &pkg->vars, keyword, value, true, pkg->flags);
} }
} }
@ -356,18 +402,19 @@ pkgconf_pkg_validate(const pkgconf_client_t *client, const pkgconf_pkg_t *pkg)
/* /*
* !doc * !doc
* *
* .. c:function:: pkgconf_pkg_t *pkgconf_pkg_new_from_file(const pkgconf_client_t *client, const char *filename, FILE *f) * .. 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. * 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 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 char* filename: The filename of the package file (including full path).
* :param FILE* f: The file object to read from. * :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. * :returns: A ``pkgconf_pkg_t`` object which contains the package data.
* :rtype: pkgconf_pkg_t * * :rtype: pkgconf_pkg_t *
*/ */
pkgconf_pkg_t * pkgconf_pkg_t *
pkgconf_pkg_new_from_file(pkgconf_client_t *client, const char *filename, FILE *f) pkgconf_pkg_new_from_file(pkgconf_client_t *client, const char *filename, FILE *f, unsigned int flags)
{ {
pkgconf_pkg_t *pkg; pkgconf_pkg_t *pkg;
char *idptr; char *idptr;
@ -376,18 +423,35 @@ pkgconf_pkg_new_from_file(pkgconf_client_t *client, const char *filename, FILE *
pkg->owner = client; pkg->owner = client;
pkg->filename = strdup(filename); pkg->filename = strdup(filename);
pkg->pc_filedir = pkg_get_parent_dir(pkg); pkg->pc_filedir = pkg_get_parent_dir(pkg);
pkgconf_tuple_add(client, &pkg->vars, "pcfiledir", pkg->pc_filedir, true); pkg->flags = flags;
char *pc_filedir_value = convert_path_to_value(pkg->pc_filedir);
pkgconf_tuple_add(client, &pkg->vars, "pcfiledir", pc_filedir_value, true, pkg->flags);
free(pc_filedir_value);
/* If pc_filedir is outside of sysroot_dir, override sysroot_dir for this
* package.
* See https://github.com/pkgconf/pkgconf/issues/213
*/
if (client->sysroot_dir && strncmp(pkg->pc_filedir, client->sysroot_dir, strlen(client->sysroot_dir)))
pkgconf_tuple_add(client, &pkg->vars, "pc_sysrootdir", "", false, pkg->flags);
/* make module id */ /* make module id */
if ((idptr = strrchr(pkg->filename, PKG_DIR_SEP_S)) != NULL) if ((idptr = strrchr(pkg->filename, PKG_DIR_SEP_S)) != NULL)
idptr++; idptr++;
#ifdef _WIN32
else if ((idptr = strrchr(pkg->filename, '/')) != NULL)
idptr++;
#endif
else else
idptr = pkg->filename; idptr = pkg->filename;
#ifdef _WIN32
/* On Windows, both \ and / are allowed in paths, so we have to chop both.
* strrchr() took us to the last \ in that case, so we just have to see if
* it is followed by a /. If so, lop it off.
*/
char *mungeptr;
if ((mungeptr = strrchr(idptr, '/')) != NULL)
idptr = ++mungeptr;
#endif
pkg->id = strdup(idptr); pkg->id = strdup(idptr);
idptr = strrchr(pkg->id, '.'); idptr = strrchr(pkg->id, '.');
if (idptr) if (idptr)
@ -402,7 +466,8 @@ pkgconf_pkg_new_from_file(pkgconf_client_t *client, const char *filename, FILE *
return NULL; return NULL;
} }
pkgconf_dependency_add(client, &pkg->provides, pkg->id, pkg->version, PKGCONF_CMP_EQUAL, 0); pkgconf_dependency_t *dep = pkgconf_dependency_add(client, &pkg->provides, pkg->id, pkg->version, PKGCONF_CMP_EQUAL, 0);
pkgconf_dependency_unref(dep->owner, dep);
return pkgconf_pkg_ref(client, pkg); return pkgconf_pkg_ref(client, pkg);
} }
@ -465,6 +530,15 @@ pkgconf_pkg_free(pkgconf_client_t *client, pkgconf_pkg_t *pkg)
if (pkg->pc_filedir != NULL) if (pkg->pc_filedir != NULL)
free(pkg->pc_filedir); free(pkg->pc_filedir);
if (pkg->license != NULL)
free(pkg->license);
if (pkg->maintainer != NULL)
free(pkg->maintainer);
if (pkg->copyright != NULL)
free(pkg->copyright);
free(pkg); free(pkg);
} }
@ -487,7 +561,7 @@ pkgconf_pkg_ref(pkgconf_client_t *client, pkgconf_pkg_t *pkg)
PKGCONF_TRACE(client, "WTF: client %p refers to package %p owned by other client %p", client, pkg, pkg->owner); PKGCONF_TRACE(client, "WTF: client %p refers to package %p owned by other client %p", client, pkg, pkg->owner);
pkg->refcount++; pkg->refcount++;
PKGCONF_TRACE(client, "refcount@%p: %d", pkg, pkg->refcount); PKGCONF_TRACE(client, "%s refcount@%p: %d", pkg->id, pkg, pkg->refcount);
return pkg; return pkg;
} }
@ -510,7 +584,7 @@ pkgconf_pkg_unref(pkgconf_client_t *client, pkgconf_pkg_t *pkg)
PKGCONF_TRACE(client, "WTF: client %p unrefs package %p owned by other client %p", client, pkg, pkg->owner); PKGCONF_TRACE(client, "WTF: client %p unrefs package %p owned by other client %p", client, pkg, pkg->owner);
pkg->refcount--; pkg->refcount--;
PKGCONF_TRACE(pkg->owner, "refcount@%p: %d", pkg, pkg->refcount); PKGCONF_TRACE(pkg->owner, "%s refcount@%p: %d", pkg->id, pkg, pkg->refcount);
if (pkg->refcount <= 0) if (pkg->refcount <= 0)
pkgconf_pkg_free(pkg->owner, pkg); pkgconf_pkg_free(pkg->owner, pkg);
@ -526,19 +600,18 @@ pkgconf_pkg_try_specific_path(pkgconf_client_t *client, const char *path, const
PKGCONF_TRACE(client, "trying path: %s for %s", path, name); PKGCONF_TRACE(client, "trying path: %s for %s", path, name);
snprintf(locbuf, sizeof locbuf, "%s/%s" PKG_CONFIG_EXT, path, name); snprintf(locbuf, sizeof locbuf, "%s%c%s" PKG_CONFIG_EXT, path, PKG_DIR_SEP_S, name);
snprintf(uninst_locbuf, sizeof uninst_locbuf, "%s/%s-uninstalled" PKG_CONFIG_EXT, path, name); snprintf(uninst_locbuf, sizeof uninst_locbuf, "%s%c%s-uninstalled" PKG_CONFIG_EXT, path, PKG_DIR_SEP_S, name);
if (!(client->flags & PKGCONF_PKG_PKGF_NO_UNINSTALLED) && (f = fopen(uninst_locbuf, "r")) != NULL) if (!(client->flags & PKGCONF_PKG_PKGF_NO_UNINSTALLED) && (f = fopen(uninst_locbuf, "r")) != NULL)
{ {
PKGCONF_TRACE(client, "found (uninstalled): %s", uninst_locbuf); PKGCONF_TRACE(client, "found (uninstalled): %s", uninst_locbuf);
pkg = pkgconf_pkg_new_from_file(client, uninst_locbuf, f); pkg = pkgconf_pkg_new_from_file(client, uninst_locbuf, f, PKGCONF_PKG_PROPF_UNINSTALLED);
pkg->flags |= PKGCONF_PKG_PROPF_UNINSTALLED;
} }
else if ((f = fopen(locbuf, "r")) != NULL) else if ((f = fopen(locbuf, "r")) != NULL)
{ {
PKGCONF_TRACE(client, "found: %s", locbuf); PKGCONF_TRACE(client, "found: %s", locbuf);
pkg = pkgconf_pkg_new_from_file(client, locbuf, f); pkg = pkgconf_pkg_new_from_file(client, locbuf, f, 0);
} }
return pkg; return pkg;
@ -576,7 +649,7 @@ pkgconf_pkg_scan_dir(pkgconf_client_t *client, const char *path, void *data, pkg
if (f == NULL) if (f == NULL)
continue; continue;
pkg = pkgconf_pkg_new_from_file(client, filebuf, f); pkg = pkgconf_pkg_new_from_file(client, filebuf, f, 0);
if (pkg != NULL) if (pkg != NULL)
{ {
if (func(pkg, data)) if (func(pkg, data))
@ -696,7 +769,7 @@ pkgconf_pkg_find(pkgconf_client_t *client, const char *name)
PKGCONF_TRACE(client, "%s is a file", name); PKGCONF_TRACE(client, "%s is a file", name);
pkg = pkgconf_pkg_new_from_file(client, name, f); pkg = pkgconf_pkg_new_from_file(client, name, f, 0);
if (pkg != NULL) if (pkg != NULL)
{ {
pkgconf_path_add(pkg->pc_filedir, &client->dir_list, true); pkgconf_path_add(pkg->pc_filedir, &client->dir_list, true);
@ -753,7 +826,7 @@ out:
* *
* :param char* a: The first version to compare in the pair. * :param char* a: The first version to compare in the pair.
* :param char* b: The second version to compare in the pair. * :param char* b: The second version to compare in the pair.
* :return: -1 if the first version is greater, 0 if both versions are equal, 1 if the second version is greater. * :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 * :rtype: int
*/ */
int int
@ -768,10 +841,10 @@ pkgconf_compare_version(const char *a, const char *b)
/* optimization: if version matches then it's the same version. */ /* optimization: if version matches then it's the same version. */
if (a == NULL) if (a == NULL)
return 1; return -1;
if (b == NULL) if (b == NULL)
return -1; return 1;
if (!strcasecmp(a, b)) if (!strcasecmp(a, b))
return 0; return 0;
@ -779,22 +852,22 @@ pkgconf_compare_version(const char *a, const char *b)
pkgconf_strlcpy(buf1, a, sizeof buf1); pkgconf_strlcpy(buf1, a, sizeof buf1);
pkgconf_strlcpy(buf2, b, sizeof buf2); pkgconf_strlcpy(buf2, b, sizeof buf2);
one = str1 = buf1; one = buf1;
two = str2 = buf2; two = buf2;
while (*one || *two) while (*one || *two)
{ {
while (*one && !isalnum((unsigned int)*one) && *one != '~') while (*one && !isalnum((unsigned char)*one) && *one != '~')
one++; one++;
while (*two && !isalnum((unsigned int)*two) && *two != '~') while (*two && !isalnum((unsigned char)*two) && *two != '~')
two++; two++;
if (*one == '~' || *two == '~') if (*one == '~' || *two == '~')
{ {
if (*one != '~') if (*one != '~')
return -1;
if (*two != '~')
return 1; return 1;
if (*two != '~')
return -1;
one++; one++;
two++; two++;
@ -807,22 +880,22 @@ pkgconf_compare_version(const char *a, const char *b)
str1 = one; str1 = one;
str2 = two; str2 = two;
if (isdigit((unsigned int)*str1)) if (isdigit((unsigned char)*str1))
{ {
while (*str1 && isdigit((unsigned int)*str1)) while (*str1 && isdigit((unsigned char)*str1))
str1++; str1++;
while (*str2 && isdigit((unsigned int)*str2)) while (*str2 && isdigit((unsigned char)*str2))
str2++; str2++;
isnum = true; isnum = true;
} }
else else
{ {
while (*str1 && isalpha((unsigned int)*str1)) while (*str1 && isalpha((unsigned char)*str1))
str1++; str1++;
while (*str2 && isalpha((unsigned int)*str2)) while (*str2 && isalpha((unsigned char)*str2))
str2++; str2++;
isnum = false; isnum = false;
@ -860,8 +933,8 @@ pkgconf_compare_version(const char *a, const char *b)
} }
ret = strcmp(one, two); ret = strcmp(one, two);
if (ret) if (ret != 0)
return ret; return ret < 0 ? -1 : 1;
*str1 = oldch1; *str1 = oldch1;
*str2 = oldch2; *str2 = oldch2;
@ -915,6 +988,7 @@ static pkgconf_pkg_t pkgconf_virtual = {
.description = "virtual package defining pkgconf API version supported", .description = "virtual package defining pkgconf API version supported",
.url = PACKAGE_BUGREPORT, .url = PACKAGE_BUGREPORT,
.version = PACKAGE_VERSION, .version = PACKAGE_VERSION,
.license = "ISC",
.flags = PKGCONF_PKG_PROPF_STATIC, .flags = PKGCONF_PKG_PROPF_STATIC,
.vars = { .vars = {
.head = &(pkgconf_node_t){ .head = &(pkgconf_node_t){
@ -1396,9 +1470,9 @@ pkgconf_pkg_walk_list(pkgconf_client_t *client,
unsigned int skip_flags) unsigned int skip_flags)
{ {
unsigned int eflags = PKGCONF_PKG_ERRF_OK; unsigned int eflags = PKGCONF_PKG_ERRF_OK;
pkgconf_node_t *node; pkgconf_node_t *node, *next;
PKGCONF_FOREACH_LIST_ENTRY(deplist->head, node) PKGCONF_FOREACH_LIST_ENTRY_SAFE(deplist->head, next, node)
{ {
unsigned int eflags_local = PKGCONF_PKG_ERRF_OK; unsigned int eflags_local = PKGCONF_PKG_ERRF_OK;
pkgconf_dependency_t *depnode = node->data; pkgconf_dependency_t *depnode = node->data;
@ -1418,23 +1492,41 @@ pkgconf_pkg_walk_list(pkgconf_client_t *client,
if (pkgdep == NULL) if (pkgdep == NULL)
continue; continue;
if (pkgdep->flags & PKGCONF_PKG_PROPF_SEEN) if (pkgdep->serial == client->serial && !(parent->flags & PKGCONF_PKG_PROPF_VIRTUAL))
{ {
pkgconf_pkg_unref(client, pkgdep); pkgdep->hits++;
continue;
/* In this case we have a circular reference.
* We break that by deleteing the circular node from the
* the list, so that we dont create a situation where
* memory is leaked due to circular ownership.
* i.e: A owns B owns A
*
* TODO(ariadne): Breaking circular references between Requires and Requires.private
* lists causes problems. Find a way to refactor the Requires.private list out.
*/
if (!(depnode->flags & PKGCONF_PKG_DEPF_PRIVATE) &&
!(parent->flags & PKGCONF_PKG_PROPF_VIRTUAL))
{
pkgconf_warn(client, "%s: breaking circular reference (%s -> %s -> %s)\n",
parent->id, parent->id, pkgdep->id, parent->id);
pkgconf_node_delete(node, deplist);
pkgconf_dependency_unref(client, depnode);
}
goto next;
} }
if (skip_flags && (depnode->flags & skip_flags) == skip_flags) if (skip_flags && (depnode->flags & skip_flags) == skip_flags)
{ goto next;
pkgconf_pkg_unref(client, pkgdep);
continue;
}
pkgconf_audit_log_dependency(client, pkgdep, depnode); pkgconf_audit_log_dependency(client, pkgdep, depnode);
pkgdep->flags |= PKGCONF_PKG_PROPF_SEEN; pkgdep->hits++;
eflags |= pkgconf_pkg_traverse(client, pkgdep, func, data, depth - 1, skip_flags); pkgdep->serial = client->serial;
pkgdep->flags &= ~PKGCONF_PKG_PROPF_SEEN; eflags |= pkgconf_pkg_traverse_main(client, pkgdep, func, data, depth - 1, skip_flags);
next:
pkgconf_pkg_unref(client, pkgdep); pkgconf_pkg_unref(client, pkgdep);
} }
@ -1504,8 +1596,8 @@ pkgconf_pkg_walk_conflicts_list(pkgconf_client_t *client,
* :return: ``PKGCONF_PKG_ERRF_OK`` on success, else an error code. * :return: ``PKGCONF_PKG_ERRF_OK`` on success, else an error code.
* :rtype: unsigned int * :rtype: unsigned int
*/ */
unsigned int static unsigned int
pkgconf_pkg_traverse(pkgconf_client_t *client, pkgconf_pkg_traverse_main(pkgconf_client_t *client,
pkgconf_pkg_t *root, pkgconf_pkg_t *root,
pkgconf_pkg_traverse_func_t func, pkgconf_pkg_traverse_func_t func,
void *data, void *data,
@ -1517,7 +1609,7 @@ pkgconf_pkg_traverse(pkgconf_client_t *client,
if (maxdepth == 0) if (maxdepth == 0)
return eflags; return eflags;
PKGCONF_TRACE(client, "%s: level %d", root->id, maxdepth); PKGCONF_TRACE(client, "%s: level %d, serial %lu", root->id, maxdepth, client->serial);
if ((root->flags & PKGCONF_PKG_PROPF_VIRTUAL) != PKGCONF_PKG_PROPF_VIRTUAL || (client->flags & PKGCONF_PKG_PKGF_SKIP_ROOT_VIRTUAL) != PKGCONF_PKG_PKGF_SKIP_ROOT_VIRTUAL) if ((root->flags & PKGCONF_PKG_PROPF_VIRTUAL) != PKGCONF_PKG_PROPF_VIRTUAL || (client->flags & PKGCONF_PKG_PKGF_SKIP_ROOT_VIRTUAL) != PKGCONF_PKG_PKGF_SKIP_ROOT_VIRTUAL)
{ {
@ -1553,6 +1645,20 @@ pkgconf_pkg_traverse(pkgconf_client_t *client,
return eflags; return eflags;
} }
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)
{
if (root->flags & PKGCONF_PKG_PROPF_VIRTUAL)
client->serial++;
return pkgconf_pkg_traverse_main(client, root, func, data, maxdepth, skip_flags);
}
static void static void
pkgconf_pkg_cflags_collect(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data) pkgconf_pkg_cflags_collect(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data)
{ {

View File

@ -51,7 +51,7 @@ pkgconf_queue_push(pkgconf_list_t *list, const char *package)
pkgconf_queue_t *pkgq = calloc(sizeof(pkgconf_queue_t), 1); pkgconf_queue_t *pkgq = calloc(sizeof(pkgconf_queue_t), 1);
pkgq->package = strdup(package); pkgq->package = strdup(package);
pkgconf_node_insert_tail(&pkgq->iter, pkgq, list); pkgconf_node_insert(&pkgq->iter, pkgq, list);
} }
/* /*
@ -107,13 +107,199 @@ pkgconf_queue_free(pkgconf_list_t *list)
} }
} }
static void
pkgconf_queue_collect_dependents(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data)
{
pkgconf_node_t *node;
pkgconf_pkg_t *world = data;
if (pkg == world)
return;
PKGCONF_FOREACH_LIST_ENTRY(pkg->required.head, node)
{
pkgconf_dependency_t *flattened_dep;
flattened_dep = pkgconf_dependency_copy(client, node->data);
pkgconf_node_insert(&flattened_dep->iter, flattened_dep, &world->required);
}
if (client->flags & PKGCONF_PKG_PKGF_SEARCH_PRIVATE)
{
PKGCONF_FOREACH_LIST_ENTRY(pkg->requires_private.head, node)
{
pkgconf_dependency_t *flattened_dep;
flattened_dep = pkgconf_dependency_copy(client, node->data);
pkgconf_node_insert(&flattened_dep->iter, flattened_dep, &world->requires_private);
}
}
}
static int
dep_sort_cmp(const void *a, const void *b)
{
const pkgconf_dependency_t *depA = *(void **) a;
const pkgconf_dependency_t *depB = *(void **) b;
return depB->match->hits - depA->match->hits;
}
static inline void
flatten_dependency_set(pkgconf_client_t *client, pkgconf_list_t *list)
{
pkgconf_node_t *node, *next;
pkgconf_dependency_t **deps = NULL;
size_t dep_count = 0, i;
PKGCONF_FOREACH_LIST_ENTRY_SAFE(list->head, next, node)
{
pkgconf_dependency_t *dep = node->data;
pkgconf_pkg_t *pkg = pkgconf_pkg_verify_dependency(client, dep, NULL);
if (pkg == NULL)
continue;
if (pkg->serial == client->serial)
{
pkgconf_node_delete(node, list);
pkgconf_dependency_unref(client, dep);
goto next;
}
if (dep->match == NULL)
{
PKGCONF_TRACE(client, "WTF: unmatched dependency %p <%s>", dep, dep->package);
abort();
}
/* for virtuals, we need to check to see if there are dupes */
for (i = 0; i < dep_count; i++)
{
pkgconf_dependency_t *other_dep = deps[i];
PKGCONF_TRACE(client, "dedup %s = %s?", dep->package, other_dep->package);
if (!strcmp(dep->package, other_dep->package))
{
PKGCONF_TRACE(client, "skipping, "SIZE_FMT_SPECIFIER" deps", dep_count);
goto next;
}
}
pkg->serial = client->serial;
/* copy to the deps table */
dep_count++;
deps = pkgconf_reallocarray(deps, dep_count, sizeof (void *));
deps[dep_count - 1] = dep;
PKGCONF_TRACE(client, "added %s to dep table", dep->package);
next:
pkgconf_pkg_unref(client, pkg);
}
if (deps == NULL)
return;
qsort(deps, dep_count, sizeof (void *), dep_sort_cmp);
/* zero the list and start readding */
pkgconf_list_zero(list);
for (i = 0; i < dep_count; i++)
{
pkgconf_dependency_t *dep = deps[i];
if (dep->match == NULL)
continue;
memset(&dep->iter, '\0', sizeof (dep->iter));
pkgconf_node_insert(&dep->iter, dep, list);
PKGCONF_TRACE(client, "slot "SIZE_FMT_SPECIFIER": dep %s matched to %p<%s> hits "SIZE_FMT_SPECIFIER, i, dep->package, dep->match, dep->match->id, dep->match->hits);
}
free(deps);
}
static inline unsigned int static inline unsigned int
pkgconf_queue_verify(pkgconf_client_t *client, pkgconf_pkg_t *world, pkgconf_list_t *list, int maxdepth) pkgconf_queue_verify(pkgconf_client_t *client, pkgconf_pkg_t *world, pkgconf_list_t *list, int maxdepth)
{ {
unsigned int result;
if (!pkgconf_queue_compile(client, world, list)) if (!pkgconf_queue_compile(client, world, list))
return PKGCONF_PKG_ERRF_DEPGRAPH_BREAK; return PKGCONF_PKG_ERRF_DEPGRAPH_BREAK;
return pkgconf_pkg_verify_graph(client, world, maxdepth); /* collect all the dependencies */
result = pkgconf_pkg_traverse(client, world, pkgconf_queue_collect_dependents, world, maxdepth, 0);
if (result != PKGCONF_PKG_ERRF_OK)
return result;
/* flatten the dependency set using serials.
* we copy the dependencies to a vector, and then erase the list.
* then we copy them back to the list.
*/
++client->serial;
PKGCONF_TRACE(client, "flattening requires deps");
flatten_dependency_set(client, &world->required);
++client->serial;
PKGCONF_TRACE(client, "flattening requires.private deps");
flatten_dependency_set(client, &world->requires_private);
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;
return pkgconf_queue_verify(client, world, list, maxdepth) == PKGCONF_PKG_ERRF_OK;
} }
/* /*
@ -124,6 +310,8 @@ pkgconf_queue_verify(pkgconf_client_t *client, pkgconf_pkg_t *world, pkgconf_lis
* Attempt to compile a dependency resolution queue into a dependency resolution problem, then attempt to solve the problem and * 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. * 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_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_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 pkgconf_queue_apply_func_t func: The callback function to call if a solution is found by the dependency resolver.
@ -135,6 +323,7 @@ pkgconf_queue_verify(pkgconf_client_t *client, pkgconf_pkg_t *world, pkgconf_lis
bool bool
pkgconf_queue_apply(pkgconf_client_t *client, pkgconf_list_t *list, pkgconf_queue_apply_func_t func, int maxdepth, void *data) 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 = { pkgconf_pkg_t world = {
.id = "virtual:world", .id = "virtual:world",
.realname = "virtual world package", .realname = "virtual world package",
@ -145,18 +334,18 @@ pkgconf_queue_apply(pkgconf_client_t *client, pkgconf_list_t *list, pkgconf_queu
if (!maxdepth) if (!maxdepth)
maxdepth = -1; maxdepth = -1;
if (pkgconf_queue_verify(client, &world, list, maxdepth) != PKGCONF_PKG_ERRF_OK) if (!pkgconf_queue_solve(client, list, &world, maxdepth))
return false; goto cleanup;
/* the world dependency set is flattened after it is returned from pkgconf_queue_verify */
if (!func(client, &world, data, maxdepth)) if (!func(client, &world, data, maxdepth))
{ goto cleanup;
pkgconf_pkg_free(client, &world);
return false;
}
pkgconf_pkg_free(client, &world); ret = true;
return true; cleanup:
pkgconf_pkg_free(client, &world);
return ret;
} }
/* /*

View File

@ -59,6 +59,7 @@
# include <dirent.h> # include <dirent.h>
# include <unistd.h> # include <unistd.h>
# include <limits.h> # include <limits.h>
# include <strings.h>
# ifdef PATH_MAX # ifdef PATH_MAX
# define PKGCONF_ITEM_SIZE (PATH_MAX + 1024) # define PKGCONF_ITEM_SIZE (PATH_MAX + 1024)
# else # else

View File

@ -45,7 +45,23 @@
void void
pkgconf_tuple_add_global(pkgconf_client_t *client, const char *key, const char *value) pkgconf_tuple_add_global(pkgconf_client_t *client, const char *key, const char *value)
{ {
pkgconf_tuple_add(client, &client->global_vars, key, value, false); 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;
} }
/* /*
@ -63,17 +79,13 @@ pkgconf_tuple_add_global(pkgconf_client_t *client, const char *key, const char *
char * char *
pkgconf_tuple_find_global(const pkgconf_client_t *client, const char *key) pkgconf_tuple_find_global(const pkgconf_client_t *client, const char *key)
{ {
pkgconf_node_t *node; pkgconf_tuple_t *tuple;
PKGCONF_FOREACH_LIST_ENTRY(client->global_vars.head, node)
{
pkgconf_tuple_t *tuple = node->data;
if (!strcmp(tuple->key, key))
return tuple->value;
}
tuple = lookup_global_tuple(client, key);
if (tuple == NULL)
return NULL; return NULL;
return tuple->value;
} }
/* /*
@ -108,13 +120,18 @@ pkgconf_tuple_define_global(pkgconf_client_t *client, const char *kv)
{ {
char *workbuf = strdup(kv); char *workbuf = strdup(kv);
char *value; char *value;
pkgconf_tuple_t *tuple;
value = strchr(workbuf, '='); value = strchr(workbuf, '=');
if (value == NULL) if (value == NULL)
goto out; goto out;
*value++ = '\0'; *value++ = '\0';
pkgconf_tuple_add_global(client, workbuf, value);
tuple = pkgconf_tuple_add(client, &client->global_vars, workbuf, value, false, 0);
if (tuple != NULL)
tuple->flags = PKGCONF_PKG_TUPLEF_OVERRIDE;
out: out:
free(workbuf); free(workbuf);
} }
@ -161,6 +178,45 @@ dequote(const char *value)
return buf; 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 * !doc
* *
@ -177,7 +233,7 @@ dequote(const char *value)
* :rtype: pkgconf_tuple_t * * :rtype: pkgconf_tuple_t *
*/ */
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) 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; char *dequote_value;
pkgconf_tuple_t *tuple = calloc(sizeof(pkgconf_tuple_t), 1); pkgconf_tuple_t *tuple = calloc(sizeof(pkgconf_tuple_t), 1);
@ -186,14 +242,14 @@ pkgconf_tuple_add(const pkgconf_client_t *client, pkgconf_list_t *list, const ch
dequote_value = dequote(value); dequote_value = dequote(value);
PKGCONF_TRACE(client, "adding tuple to @%p: %s => %s (parsed? %d)", list, key, dequote_value, parse);
tuple->key = strdup(key); tuple->key = strdup(key);
if (parse) if (parse)
tuple->value = pkgconf_tuple_parse(client, list, dequote_value); tuple->value = pkgconf_tuple_parse(client, list, dequote_value, flags);
else else
tuple->value = strdup(dequote_value); 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); pkgconf_node_insert(&tuple->iter, tuple, list);
free(dequote_value); free(dequote_value);
@ -218,10 +274,11 @@ char *
pkgconf_tuple_find(const pkgconf_client_t *client, pkgconf_list_t *list, const char *key) pkgconf_tuple_find(const pkgconf_client_t *client, pkgconf_list_t *list, const char *key)
{ {
pkgconf_node_t *node; pkgconf_node_t *node;
char *res; pkgconf_tuple_t *global_tuple;
if ((res = pkgconf_tuple_find_global(client, key)) != NULL) global_tuple = lookup_global_tuple(client, key);
return res; if (global_tuple != NULL && global_tuple->flags & PKGCONF_PKG_TUPLEF_OVERRIDE)
return global_tuple->value;
PKGCONF_FOREACH_LIST_ENTRY(list->head, node) PKGCONF_FOREACH_LIST_ENTRY(list->head, node)
{ {
@ -231,31 +288,39 @@ pkgconf_tuple_find(const pkgconf_client_t *client, pkgconf_list_t *list, const c
return tuple->value; return tuple->value;
} }
if (global_tuple != NULL)
return global_tuple->value;
return NULL; return NULL;
} }
/* /*
* !doc * !doc
* *
* .. c:function:: char *pkgconf_tuple_parse(const pkgconf_client_t *client, pkgconf_list_t *vars, const char *value) * .. 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. * Parse an expression for variable substitution.
* *
* :param pkgconf_client_t* client: The pkgconf client object to access. * :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 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 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 * :return: the variable data with any variables substituted
* :rtype: char * * :rtype: char *
*/ */
char * char *
pkgconf_tuple_parse(const pkgconf_client_t *client, pkgconf_list_t *vars, const char *value) pkgconf_tuple_parse(const pkgconf_client_t *client, pkgconf_list_t *vars, const char *value, unsigned int flags)
{ {
char buf[PKGCONF_BUFSIZE]; char buf[PKGCONF_BUFSIZE];
const char *ptr; const char *ptr;
char *bptr = buf; 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))) if (*value == '/' && client->sysroot_dir != NULL && strncmp(value, client->sysroot_dir, strlen(client->sysroot_dir)))
bptr += pkgconf_strlcpy(buf, client->sysroot_dir, sizeof buf); bptr += pkgconf_strlcpy(buf, client->sysroot_dir, sizeof buf);
}
for (ptr = value; *ptr != '\0' && bptr - buf < PKGCONF_BUFSIZE; ptr++) for (ptr = value; *ptr != '\0' && bptr - buf < PKGCONF_BUFSIZE; ptr++)
{ {
@ -264,6 +329,7 @@ pkgconf_tuple_parse(const pkgconf_client_t *client, pkgconf_list_t *vars, const
else if (*(ptr + 1) == '{') else if (*(ptr + 1) == '{')
{ {
char varname[PKGCONF_ITEM_SIZE]; char varname[PKGCONF_ITEM_SIZE];
char *vend = varname + PKGCONF_ITEM_SIZE - 1;
char *vptr = varname; char *vptr = varname;
const char *pptr; const char *pptr;
char *kv, *parsekv; char *kv, *parsekv;
@ -273,6 +339,8 @@ pkgconf_tuple_parse(const pkgconf_client_t *client, pkgconf_list_t *vars, const
for (pptr = ptr + 2; *pptr != '\0'; pptr++) for (pptr = ptr + 2; *pptr != '\0'; pptr++)
{ {
if (*pptr != '}') if (*pptr != '}')
{
if (vptr < vend)
*vptr++ = *pptr; *vptr++ = *pptr;
else else
{ {
@ -280,13 +348,30 @@ pkgconf_tuple_parse(const pkgconf_client_t *client, pkgconf_list_t *vars, const
break; break;
} }
} }
else
{
*vptr = '\0';
break;
}
}
PKGCONF_TRACE(client, "lookup tuple %s", varname);
size_t remain = PKGCONF_BUFSIZE - (bptr - buf);
ptr += (pptr - ptr); ptr += (pptr - ptr);
kv = pkgconf_tuple_find_global(client, varname); kv = pkgconf_tuple_find_global(client, varname);
if (kv != NULL) if (kv != NULL)
{ {
strncpy(bptr, kv, PKGCONF_BUFSIZE - (bptr - buf)); size_t nlen = pkgconf_strlcpy(bptr, kv, remain);
bptr += strlen(kv); if (nlen > remain)
{
pkgconf_warn(client, "warning: truncating very long variable to 64KB\n");
bptr = buf + (PKGCONF_BUFSIZE - 1);
break;
}
bptr += nlen;
} }
else else
{ {
@ -294,12 +379,21 @@ pkgconf_tuple_parse(const pkgconf_client_t *client, pkgconf_list_t *vars, const
if (kv != NULL) if (kv != NULL)
{ {
parsekv = pkgconf_tuple_parse(client, vars, kv); size_t nlen;
strncpy(bptr, parsekv, PKGCONF_BUFSIZE - (bptr - buf));
bptr += strlen(parsekv);
parsekv = pkgconf_tuple_parse(client, vars, kv, flags);
nlen = pkgconf_strlcpy(bptr, parsekv, remain);
free(parsekv); free(parsekv);
if (nlen > remain)
{
pkgconf_warn(client, "warning: truncating very long variable to 64KB\n");
bptr = buf + (PKGCONF_BUFSIZE - 1);
break;
}
bptr += nlen;
} }
} }
} }
@ -321,16 +415,15 @@ pkgconf_tuple_parse(const pkgconf_client_t *client, pkgconf_list_t *vars, const
* safe to skip ahead in the string to scan for our sysroot dir. * 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. * 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 (*buf == '/' && if (should_rewrite_sysroot(client, vars, buf, flags))
client->sysroot_dir != NULL &&
strcmp(client->sysroot_dir, "/") != 0 &&
strlen(buf) > strlen(client->sysroot_dir) &&
strstr(buf + strlen(client->sysroot_dir), client->sysroot_dir) != NULL)
{ {
char cleanpath[PKGCONF_ITEM_SIZE]; char cleanpath[PKGCONF_ITEM_SIZE];
const char *sysroot_dir = find_sysroot(client, vars);
pkgconf_strlcpy(cleanpath, buf + strlen(client->sysroot_dir), sizeof cleanpath); pkgconf_strlcpy(cleanpath, buf + strlen(sysroot_dir), sizeof cleanpath);
pkgconf_path_relocate(cleanpath, sizeof cleanpath); pkgconf_path_relocate(cleanpath, sizeof cleanpath);
return strdup(cleanpath); return strdup(cleanpath);
@ -378,4 +471,6 @@ pkgconf_tuple_free(pkgconf_list_t *list)
PKGCONF_FOREACH_LIST_ENTRY_SAFE(list->head, next, node) PKGCONF_FOREACH_LIST_ENTRY_SAFE(list->head, next, node)
pkgconf_tuple_free_entry(node->data, list); pkgconf_tuple_free_entry(node->data, list);
pkgconf_list_zero(list);
} }

File diff suppressed because it is too large Load Diff

View File

@ -99,6 +99,9 @@ These flags are always used, regardless of whether static compilation is request
.It Cflags.private .It Cflags.private
Required compiler flags for static compilation. Required compiler flags for static compilation.
(optional; fragment list; pkgconf extension) (optional; fragment list; pkgconf extension)
.It Copyright
A copyright attestation statement.
(optional; literal; pkgconf extension)
.It Libs .It Libs
Required linking flags for this package. Required linking flags for this package.
Libraries this package depends on for linking against it, which are not Libraries this package depends on for linking against it, which are not
@ -110,6 +113,13 @@ statically.
Libraries this package depends on for linking against it statically, which are Libraries this package depends on for linking against it statically, which are
not described as dependencies should be specified here. not described as dependencies should be specified here.
(optional; fragment list) (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 .It Requires
Required dependencies that must be met for the package to be usable. 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 All dependencies must be satisfied or the pkg-config implementation must not use
@ -151,6 +161,9 @@ includedir=${prefix}/include
Name: libfoo # human-readable name Name: libfoo # human-readable name
Description: an example library called libfoo # human-readable description 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 Version: 1.0
URL: http://www.pkgconf.org URL: http://www.pkgconf.org
Requires: libbar > 2.0.0 Requires: libbar > 2.0.0

View File

@ -36,7 +36,7 @@ Properties are set using RFC822-style stanzas which consist of a keyword, follow
by a colon (:) and then the value the property should be set to. by a colon (:) and then the value the property should be set to.
Variable substitution is always performed regardless of property type. Variable substitution is always performed regardless of property type.
.Pp .Pp
There are two types of property: There are three types of property:
.\" .\"
.Bl -tag -width indent .Bl -tag -width indent
.\" .\"
@ -47,6 +47,11 @@ The property will be set to the text of the value.
The property will be set to a list of fragments parsed from the text. 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 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. 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 .El
.Ss PROPERTY KEYWORDS .Ss PROPERTY KEYWORDS
@ -71,6 +76,12 @@ include files.
A list of directories that are included by default in the search path for A list of directories that are included by default in the search path for
libraries. libraries.
(mandatory; fragment list) (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 .El
.Sh EXAMPLES .Sh EXAMPLES
@ -79,12 +90,11 @@ An example .personality file:
# This is a comment # This is a comment
Triplet: x86_64-pc-linux-gnu Triplet: x86_64-pc-linux-gnu
SysrootDir: /home/kaniini/sysroot/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 \\ DefaultSearchPaths: /home/kaniini/sysroot/x86_64-pc-linux-gnu/lib/pkgconfig:/home/kaniini/sysroot/x86_64-pc-linux-gnu/share/pkgconfig
/home/kaniini/sysroot/x86_64-pc-linux-gnu/share/pkgconfig
SystemIncludePaths: /home/kaniini/sysroot/x86_64-pc-linux-gnu/include SystemIncludePaths: /home/kaniini/sysroot/x86_64-pc-linux-gnu/include
SystemLibraryPaths: /home/kaniini/sysroot/x86_64-pc-linux-gnu/lib SystemLibraryPaths: /home/kaniini/sysroot/x86_64-pc-linux-gnu/lib
.Ed .Ed
.Sh SEE ALSO .Sh SEE ALSO
.Xr pkgconf 1 , .Xr pkgconf 1 ,
.Xr pkg.m4 7 , .Xr pc 5 ,
.Xr pc 5 .Xr pkg.m4 7

View File

@ -51,6 +51,10 @@ Ignore
rules in modules. rules in modules.
.It Fl -env-only .It Fl -env-only
Learn about pkgconf's configuration strictly from environmental variables. Learn about pkgconf's configuration strictly from environmental variables.
.It Fl -validate Ar package ...
Validate specific
.Sq .pc
files for correctness.
.It Fl -maximum-traverse-depth Ns = Ns Ar DEPTH .It Fl -maximum-traverse-depth Ns = Ns Ar DEPTH
Impose a limit on the allowed depth in the dependency graph. Impose a limit on the allowed depth in the dependency graph.
For example, a depth of 2 will restrict the resolver from acting on child For example, a depth of 2 will restrict the resolver from acting on child
@ -58,6 +62,8 @@ dependencies of modules added to the resolver's solution.
.It Fl -static .It Fl -static
Compute a deeper dependency graph and use compiler/linker flags intended for Compute a deeper dependency graph and use compiler/linker flags intended for
static linking. static linking.
.It Fl -shared
Compute a simple dependency graph that is only suitable for shared linking.
.It Fl -pure .It Fl -pure
Treats the computed dependency graph as if it were pure. Treats the computed dependency graph as if it were pure.
This is mainly intended for use with the This is mainly intended for use with the
@ -104,7 +110,7 @@ the requested modules.
.It Fl -uninstalled .It Fl -uninstalled
Exit with a non-zero result if the dependency resolver uses an Exit with a non-zero result if the dependency resolver uses an
.Sq uninstalled .Sq uninstalled
module as part of it's solution. module as part of its solution.
.It Fl -no-uninstalled .It Fl -no-uninstalled
Forbids the dependency resolver from considering 'uninstalled' modules as part Forbids the dependency resolver from considering 'uninstalled' modules as part
of a solution. of a solution.
@ -209,6 +215,12 @@ If set, enables additional debug logging.
The format of the debug log messages is implementation-specific. The format of the debug log messages is implementation-specific.
.It Va PKG_CONFIG_DONT_RELOCATE_PATHS .It Va PKG_CONFIG_DONT_RELOCATE_PATHS
If set, disables the path relocation feature. If set, disables the path relocation feature.
.It Va PKG_CONFIG_MSVC_SYNTAX
If set, uses MSVC syntax for fragments.
.It Va PKG_CONFIG_FDO_SYSROOT_RULES
If set, follow the sysroot prefixing rules that freedesktop.org pkg-config uses.
.It Va DESTDIR
If set to PKG_CONFIG_SYSROOT_DIR, assume that PKG_CONFIG_FDO_SYSROOT_RULES is set.
.El .El
.Sh EXAMPLES .Sh EXAMPLES
Displaying the CFLAGS of a package: Displaying the CFLAGS of a package:

View File

@ -1,42 +1,41 @@
project('pkgconf', 'c', project('pkgconf', 'c',
version : '1.9.90', version : '1.9.5',
license : 'ISC', license : 'ISC',
meson_version : '>=0.47') meson_version : '>=0.49',
default_options : ['c_std=c99'],
)
cc = meson.get_compiler('c') cc = meson.get_compiler('c')
add_project_arguments(
'-D_BSD_SOURCE',
'-D_DEFAULT_SOURCE',
cc.get_supported_arguments(
'-Wimplicit-function-declaration',
'-Wmisleading-indentation',
),
language : 'c',
)
cdata = configuration_data() cdata = configuration_data()
check_headers = [
['HAVE_DLFCN_H', 'dlfcn.h'],
['HAVE_INTTYPES_H', 'inttypes.h'],
['HAVE_MEMORY_H', 'memory.h'],
['HAVE_STDINT_H', 'stdint.h'],
['HAVE_STDLIB_H', 'stdlib.h'],
['HAVE_STRINGS_H', 'strings.h'],
['HAVE_STRING_H', 'string.h'],
['HAVE_SYS_STAT_H', 'sys/stat.h'],
['HAVE_SYS_TYPES_H', 'sys/types.h'],
['HAVE_UNISTD_H', 'unistd.h'],
]
foreach h : check_headers
if cc.has_header(h.get(1))
cdata.set(h.get(0), 1)
endif
endforeach
check_functions = [ check_functions = [
['HAVE_CYGWIN_CONV_PATH', 'cygwin_conv_path', '#include<sys/cygwin.h>'], ['strlcat', 'string.h'],
['HAVE_STRLCAT', 'strlcat', '#include<string.h>'], ['strlcpy', 'string.h'],
['HAVE_STRLCPY', 'strlcpy', '#include<string.h>'], ['strndup', 'string.h'],
['HAVE_STRNDUP', 'strndup', '#include<string.h>'], ['strdup', 'string.h'],
['strncasecmp', 'strings.h'],
['strcasecmp', 'strings.h'],
['reallocarray', 'stdlib.h'],
] ]
foreach f : check_functions foreach f : check_functions
if cc.has_function(f.get(1), prefix : f.get(2)) name = f[0].to_upper().underscorify()
cdata.set(f.get(0), 1) if cc.has_function(f[0], prefix : '#define _BSD_SOURCE\n#include <@0@>'.format(f[1])) and cc.has_header_symbol(f[1], f[0], prefix : '#define _BSD_SOURCE')
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 endif
endforeach endforeach
@ -57,13 +56,20 @@ cdata.set_quoted('PERSONALITY_PATH', ':'.join(personality_path))
cdata.set_quoted('PACKAGE_NAME', meson.project_name()) cdata.set_quoted('PACKAGE_NAME', meson.project_name())
cdata.set_quoted('PACKAGE_VERSION', meson.project_version()) cdata.set_quoted('PACKAGE_VERSION', meson.project_version())
cdata.set_quoted('PACKAGE_BUGREPORT', 'https://todo.sr.ht/~kaniini/pkgconf') cdata.set_quoted('PACKAGE_BUGREPORT', 'https://todo.sr.ht/~kaniini/pkgconf')
cdata.set('abs_top_srcdir', meson.source_root()) cdata.set('abs_top_srcdir', meson.current_source_dir())
cdata.set('abs_top_builddir', meson.build_root()) cdata.set('abs_top_builddir', meson.current_build_dir())
subdir('libpkgconf') subdir('libpkgconf')
libpkgconf = shared_library('pkgconf', 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/argvsplit.c',
'libpkgconf/audit.c', 'libpkgconf/audit.c',
'libpkgconf/bsdstubs.c', 'libpkgconf/bsdstubs.c',
@ -78,10 +84,32 @@ libpkgconf = shared_library('pkgconf',
'libpkgconf/pkg.c', 'libpkgconf/pkg.c',
'libpkgconf/queue.c', 'libpkgconf/queue.c',
'libpkgconf/tuple.c', 'libpkgconf/tuple.c',
c_args: '-DLIBPKGCONF_EXPORT', c_args: ['-DLIBPKGCONF_EXPORT', build_static],
install : true, install : true,
version : '3.0.0', version : '4.0.0',
soversion : '3', soversion : '4',
)
# 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
) )
@ -90,20 +118,20 @@ pkgconf_exe = executable('pkgconf',
'cli/getopt_long.c', 'cli/getopt_long.c',
'cli/renderer-msvc.c', 'cli/renderer-msvc.c',
link_with : libpkgconf, link_with : libpkgconf,
c_args: build_static,
install : true) install : true)
if get_option('tests') with_tests = get_option('tests')
kyua_exe = find_program('kyua') kyua_exe = find_program('kyua', required : with_tests, disabler : true)
atf_sh_exe = find_program('atf-sh') atf_sh_exe = find_program('atf-sh', required : with_tests, disabler : true)
test('kyua', kyua_exe, args : ['--config=none', 'test', '--kyuafile=' + join_paths(meson.build_root(), 'Kyuafile'), '--build-root=' + meson.build_root()]) 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()])
configure_file(input : 'Kyuafile.in', output : 'Kyuafile', configuration : cdata)
subdir('tests') subdir('tests')
endif
install_man('man/pkgconf.1') install_man('man/pkgconf.1')
install_man('man/pkg.m4.7') install_man('man/pkg.m4.7')
install_man('man/pc.5') install_man('man/pc.5')
install_man('man/pkgconf-personality.5') install_man('man/pkgconf-personality.5')
install_data('pkg.m4', install_dir: 'share/aclocal') 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')

View File

@ -1,3 +1,5 @@
option('tests', type: 'boolean', value: true, option(
description: 'Build tests which depends upon the kyua framework' 'tests',
type: 'feature',
description: 'Build tests which depends upon the kyua framework',
) )

10
pkg.m4
View File

@ -1,5 +1,5 @@
# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- # pkg.m4 - Macros to locate and use pkg-config. -*- Autoconf -*-
# serial 11 (pkg-config-0.29.1) # serial 12 (pkg-config-0.29.2)
dnl Copyright © 2004 Scott James Remnant <scott@netsplit.com>. dnl Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
dnl Copyright © 2012-2015 Dan Nicholson <dbn.lists@gmail.com> dnl Copyright © 2012-2015 Dan Nicholson <dbn.lists@gmail.com>
@ -41,7 +41,7 @@ dnl
dnl See the "Since" comment for each macro you use to see what version dnl See the "Since" comment for each macro you use to see what version
dnl of the macros you require. dnl of the macros you require.
m4_defun([PKG_PREREQ], m4_defun([PKG_PREREQ],
[m4_define([PKG_MACROS_VERSION], [0.29.1]) [m4_define([PKG_MACROS_VERSION], [0.29.2])
m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1, 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])]) [m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])])
])dnl PKG_PREREQ ])dnl PKG_PREREQ
@ -86,7 +86,7 @@ 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 PKG_CHECK_MODULES(), but does not set variables or print errors.
dnl dnl
dnl Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG]) dnl Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG])
dnl only at the first occurence in configure.ac, so if the first place 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 it's called might be skipped (such as if it is within an "if", you
dnl have to call PKG_CHECK_EXISTS manually dnl have to call PKG_CHECK_EXISTS manually
AC_DEFUN([PKG_CHECK_EXISTS], AC_DEFUN([PKG_CHECK_EXISTS],
@ -142,7 +142,7 @@ 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 AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl
pkg_failed=no pkg_failed=no
AC_MSG_CHECKING([for $1]) AC_MSG_CHECKING([for $2])
_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) _PKG_CONFIG([$1][_CFLAGS], [cflags], [$2])
_PKG_CONFIG([$1][_LIBS], [libs], [$2]) _PKG_CONFIG([$1][_LIBS], [libs], [$2])

View File

@ -29,6 +29,9 @@ tests_init \
libs_circular_directpc \ libs_circular_directpc \
libs_static \ libs_static \
libs_static_ordering \ libs_static_ordering \
license_isc \
license_noassertion \
modversion_noflatten \
pkg_config_path \ pkg_config_path \
nolibs \ nolibs \
nocflags \ nocflags \
@ -72,7 +75,7 @@ libs_cflags_version_multiple_body()
{ {
export PKG_CONFIG_PATH="${selfdir}/lib1" export PKG_CONFIG_PATH="${selfdir}/lib1"
atf_check \ atf_check \
-o inline:"-I/test/include/foo -fPIC -L/test/lib -lbar -lfoo \n" \ -o inline:"-fPIC -I/test/include/foo -L/test/lib -lbar -lfoo\n" \
pkgconf --cflags --libs 'foo > 1.2 bar >= 1.3' pkgconf --cflags --libs 'foo > 1.2 bar >= 1.3'
} }
@ -80,7 +83,7 @@ libs_cflags_version_multiple_coma_body()
{ {
export PKG_CONFIG_PATH="${selfdir}/lib1" export PKG_CONFIG_PATH="${selfdir}/lib1"
atf_check \ atf_check \
-o inline:"-I/test/include/foo -fPIC -L/test/lib -lbar -lfoo \n" \ -o inline:"-fPIC -I/test/include/foo -L/test/lib -lbar -lfoo\n" \
pkgconf --cflags --libs 'foo > 1.2,bar >= 1.3' pkgconf --cflags --libs 'foo > 1.2,bar >= 1.3'
} }
@ -176,7 +179,7 @@ exists_version_bad3_body()
export PKG_CONFIG_PATH="${selfdir}/lib1" export PKG_CONFIG_PATH="${selfdir}/lib1"
atf_check \ atf_check \
-s exit:1 \ -s exit:1 \
pkgconf --exists 'tilde <= 1.0.0' pkgconf --exists 'tilde >= 1.0.0'
} }
exists_body() exists_body()
@ -190,7 +193,7 @@ exists2_body()
{ {
export PKG_CONFIG_PATH="${selfdir}/lib1" export PKG_CONFIG_PATH="${selfdir}/lib1"
atf_check \ atf_check \
pkgconf --exists 'tilde >= 1.0.0' pkgconf --exists 'tilde <= 1.0.0'
} }
exists3_body() exists3_body()
@ -208,26 +211,26 @@ libs_intermediary_body()
pkgconf --libs intermediary-1 intermediary-2 pkgconf --libs intermediary-1 intermediary-2
} }
libs_circular1_body()
{
export PKG_CONFIG_PATH="${selfdir}/lib1"
atf_check \
-o inline:"-lcircular-1 -lcircular-2 -lcircular-3 \n" \
pkgconf --libs circular-1
}
libs_circular2_body() libs_circular2_body()
{ {
export PKG_CONFIG_PATH="${selfdir}/lib1" export PKG_CONFIG_PATH="${selfdir}/lib1"
atf_check \ atf_check \
-o inline:"-lcircular-3 -lcircular-1 -lcircular-2 \n" \ -o inline:"circular-1: breaking circular reference (circular-1 -> circular-2 -> circular-1)\n" \
pkgconf --libs circular-3 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() libs_circular_directpc_body()
{ {
atf_check \ atf_check \
-o inline:"-lcircular-1 -lcircular-2 -lcircular-3 \n" \ -o inline:"-lcircular-2 -lcircular-3 -lcircular-1\n" \
pkgconf --libs ${selfdir}/lib1/circular-3.pc pkgconf --libs ${selfdir}/lib1/circular-3.pc
} }
@ -307,3 +310,24 @@ single_depth_selectors_body()
-o inline:"foo\n" \ -o inline:"foo\n" \
pkgconf --with-path=${selfdir}/lib3 --print-requires bar 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
}

View File

@ -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!

View File

@ -9,3 +9,4 @@ Version: 1.2.3
Libs: -L${libdir} -lfoo Libs: -L${libdir} -lfoo
Cflags: -fPIC -I${includedir}/foo Cflags: -fPIC -I${includedir}/foo
Cflags.private: -DFOO_STATIC Cflags.private: -DFOO_STATIC
License: ISC

View File

@ -0,0 +1,4 @@
Name: fragment-comment
Description: Test case for issue #215
Version: 1.0
Cflags: kuku=\#ttt

View File

@ -0,0 +1,6 @@
Name: metapackage-1
Version: 0.1
Description: metapackage for testing purposes
Requires.private: metapackage-2
Libs: -lmetapackage-1
Cflags: -I/metapackage-1

View File

@ -0,0 +1,5 @@
Name: metapackage-2
Version: 0.1
Description: metapackage for testing purposes
Libs: -lmetapackage-2
Cflags: -I/metapackage-2

View File

@ -0,0 +1,4 @@
Name: metapackage
Version: 0.1
Description: metapackage for testing purposes
Requires: metapackage-1, metapackage-2

View File

@ -0,0 +1,10 @@
prefix=${pc_sysrootdir}/test
exec_prefix=${prefix}
libdir=${prefix}/lib
includedir=${prefix}/include
Name: omg-sysroot
Description: A testing pkg-config file
Version: 1.2.3
Libs: -L${libdir} -lomg
Cflags: -fPIC -I${includedir}/omg

View File

@ -7,4 +7,4 @@ Name: quotes
Description: A testing pkg-config file Description: A testing pkg-config file
Version: 1.2.3 Version: 1.2.3
Libs: -L${libdir} -lfoo Libs: -L${libdir} -lfoo
Cflags: -DQUOTED=\"bla\" Cflags: -DQUOTED=\"bla\" -DA=\"escaped\ string\'\ \literal\" -DB="\1\$" -DC='bla'

View File

@ -0,0 +1,7 @@
prefix=/test\ with\ spaces
includedir=${prefix}/include
Name: spaces-in-paths
Version: 1
Description: test package for properly expanding spaces in variables
Cflags: -I${includedir} -I${includedir}/subdir

View File

@ -0,0 +1,7 @@
prefix=${pc_sysrootdir}/usr
Name: sysroot-dir
Description: Package for testing whether sysroot dirs are repeated or not
Version: 1
CFlags: -I${prefix}/include
Libs: -L${prefix}/lib -lfoo

View File

@ -0,0 +1,9 @@
prefix=/sysroot/usr
includedir=${prefix}/include
libdir=${prefix}/lib
Name: sysroot-dir
Description: Package for testing whether sysroot dirs are repeated or not
Version: 1
CFlags: -I${includedir}
Libs: -L${libdir} -lfoo

View File

@ -0,0 +1,9 @@
prefix=${pc_sysrootdir}/usr
includedir=${prefix}/include
libdir=${prefix}/lib
Name: sysroot-dir
Description: Package for testing whether sysroot dirs are repeated or not
Version: 1
CFlags: -I${includedir}
Libs: -L${libdir} -lfoo

View File

@ -0,0 +1,9 @@
prefix=/sysroot/usr
includedir=${prefix}/include
libdir=${prefix}/lib
Name: sysroot-dir
Description: Package for testing whether sysroot dirs are repeated or not
Version: 1
CFlags: -I${includedir}
Libs: -L${libdir} -lfoo

10
tests/lib1/utf8.pc Normal file
View File

@ -0,0 +1,10 @@
prefix=/tëst
exec_prefix=${prefix}
libdir=${prefix}/lib
includedir=${prefix}/include
Name: utf8
Description: Library installed in a prefix with UTF-8
Version: 0
Libs: -L${libdir} -lutf8
Cflags: -I${includedir}

View File

@ -18,6 +18,5 @@ tests = [
# yuck # yuck
foreach test : tests foreach test : tests
configure_file(input: test + '.sh', output: test, copy: true) test_file = configure_file(input: test + '.sh', output: test, copy: true)
run_command('chmod', '755', join_paths(meson.build_root(), 'tests', test))
endforeach endforeach

View File

@ -29,6 +29,7 @@ tests_init \
fragment_quoting_3 \ fragment_quoting_3 \
fragment_quoting_5 \ fragment_quoting_5 \
fragment_quoting_7 \ fragment_quoting_7 \
fragment_comment \
msvc_fragment_quoting \ msvc_fragment_quoting \
msvc_fragment_render_cflags \ msvc_fragment_render_cflags \
tuple_dequote \ tuple_dequote \
@ -141,7 +142,7 @@ quoted_body()
{ {
export PKG_CONFIG_PATH="${selfdir}/lib1" export PKG_CONFIG_PATH="${selfdir}/lib1"
atf_check \ atf_check \
-o inline:"-DQUOTED=\\\"bla\\\" \n" \ -o inline:"-DQUOTED=\\\"bla\\\" -DA=\\\"escaped\\ string\\\'\\ literal\\\" -DB=\\\\\\1\$ -DC=bla\n" \
pkgconf --cflags quotes pkgconf --cflags quotes
} }
@ -264,6 +265,14 @@ fragment_quoting_7a_body()
set +x set +x
} }
fragment_comment_body()
{
atf_check \
-o inline:'kuku=\#ttt\n' \
pkgconf --with-path="${selfdir}/lib1" --cflags fragment-comment
}
msvc_fragment_quoting_body() msvc_fragment_quoting_body()
{ {
export PKG_CONFIG_PATH="${selfdir}/lib1" export PKG_CONFIG_PATH="${selfdir}/lib1"

View File

@ -8,6 +8,7 @@ tests_init \
depgraph_break_2 \ depgraph_break_2 \
depgraph_break_3 \ depgraph_break_3 \
define_variable \ define_variable \
define_variable_override \
variable \ variable \
keep_system_libs \ keep_system_libs \
libs \ libs \
@ -23,13 +24,17 @@ tests_init \
idirafter_munge_sysroot \ idirafter_munge_sysroot \
idirafter_ordering \ idirafter_ordering \
pcpath \ pcpath \
sysroot_munge \
virtual_variable \ virtual_variable \
fragment_collision \ fragment_collision \
malformed_1 \ malformed_1 \
malformed_quoting \ malformed_quoting \
explicit_sysroot \ explicit_sysroot \
empty_tuple empty_tuple \
solver_requires_private_debounce \
billion_laughs \
maximum_package_depth_off_by_one
# sysroot_munge \
case_sensitivity_body() case_sensitivity_body()
{ {
@ -70,6 +75,13 @@ define_variable_body()
pkgconf --variable=typelibdir --define-variable='libdir=\${libdir}' typelibdir pkgconf --variable=typelibdir --define-variable='libdir=\${libdir}' typelibdir
} }
define_variable_override_body()
{
export PKG_CONFIG_PATH="${selfdir}/lib1"
atf_check -o inline:"/test\n" \
pkgconf --variable=prefix --define-variable='prefix=/test' typelibdir
}
variable_body() variable_body()
{ {
export PKG_CONFIG_PATH="${selfdir}/lib1" export PKG_CONFIG_PATH="${selfdir}/lib1"
@ -160,9 +172,9 @@ isystem_munge_order_body()
isystem_munge_sysroot_body() isystem_munge_sysroot_body()
{ {
export PKG_CONFIG_PATH="${selfdir}/lib1" PKG_CONFIG_SYSROOT_DIR='/test' export PKG_CONFIG_PATH="${selfdir}/lib1" PKG_CONFIG_SYSROOT_DIR="${selfdir}"
atf_check \ atf_check \
-o match:"-isystem /test/opt/bad/include" \ -o match:"-isystem ${selfdir}/opt/bad/include" \
pkgconf --cflags isystem pkgconf --cflags isystem
} }
@ -176,9 +188,9 @@ idirafter_munge_order_body()
idirafter_munge_sysroot_body() idirafter_munge_sysroot_body()
{ {
export PKG_CONFIG_PATH="${selfdir}/lib1" PKG_CONFIG_SYSROOT_DIR='/test' export PKG_CONFIG_PATH="${selfdir}/lib1" PKG_CONFIG_SYSROOT_DIR="${selfdir}"
atf_check \ atf_check \
-o match:"-idirafter /test/opt/bad/include" \ -o match:"-idirafter ${selfdir}/opt/bad/include" \
pkgconf --cflags idirafter pkgconf --cflags idirafter
} }
@ -200,15 +212,11 @@ pcpath_body()
sysroot_munge_body() sysroot_munge_body()
{ {
export PKG_CONFIG_PATH="${selfdir}/lib1" PKG_CONFIG_SYSROOT_DIR="/sysroot" sed "s|/sysroot/|${selfdir}/|g" ${selfdir}/lib1/sysroot-dir.pc > ${selfdir}/lib1/sysroot-dir-selfdir.pc
export PKG_CONFIG_PATH="${selfdir}/lib1" PKG_CONFIG_SYSROOT_DIR="${selfdir}"
atf_check \ atf_check \
-o inline:"-L/sysroot/lib -lfoo \n" \ -o inline:"-L${selfdir}/lib -lfoo\n" \
pkgconf --libs sysroot-dir pkgconf --libs sysroot-dir-selfdir
export PKG_CONFIG_SYSROOT_DIR="/sysroot2"
atf_check \
-o inline:"-L/sysroot2/sysroot/lib -lfoo \n" \
pkgconf --libs sysroot-dir
} }
virtual_variable_body() virtual_variable_body()
@ -244,8 +252,8 @@ malformed_quoting_body()
explicit_sysroot_body() explicit_sysroot_body()
{ {
export PKG_CONFIG_SYSROOT_DIR=/sysroot export PKG_CONFIG_SYSROOT_DIR=${selfdir}
atf_check -o inline:"/sysroot/usr/share/test\n" \ atf_check -o inline:"${selfdir}/usr/share/test\n" \
pkgconf --with-path="${selfdir}/lib1" --variable=pkgdatadir explicit-sysroot pkgconf --with-path="${selfdir}/lib1" --variable=pkgdatadir explicit-sysroot
} }
@ -254,3 +262,21 @@ empty_tuple_body()
atf_check -o inline:"\n" \ atf_check -o inline:"\n" \
pkgconf --with-path="${selfdir}/lib1" --cflags empty-tuple pkgconf --with-path="${selfdir}/lib1" --cflags empty-tuple
} }
solver_requires_private_debounce_body()
{
atf_check -o inline:"-I/metapackage-1 -I/metapackage-2 -lmetapackage-1 -lmetapackage-2\n" \
pkgconf --with-path="${selfdir}/lib1" --cflags --libs metapackage
}
billion_laughs_body()
{
atf_check -o inline:"warning: truncating very long variable to 64KB\nwarning: truncating very long variable to 64KB\nwarning: truncating very long variable to 64KB\nwarning: truncating very long variable to 64KB\nwarning: truncating very long variable to 64KB\n" \
pkgconf --with-path="${selfdir}/lib1" --validate billion-laughs
}
maximum_package_depth_off_by_one_body()
{
atf_check -o inline:"1.2.3\n" \
pkgconf --with-path="${selfdir}/lib1" --modversion foo bar baz
}

View File

@ -69,7 +69,7 @@ private_duplication_body()
{ {
export PKG_CONFIG_PATH="${selfdir}/lib1" export PKG_CONFIG_PATH="${selfdir}/lib1"
atf_check \ atf_check \
-o inline:"-lprivate -lfoo -lbaz -lzee -lbar -lfoo \n" \ -o inline:"-lprivate -lbaz -lzee -lbar -lfoo -lfoo\n" \
pkgconf --static --libs-only-l private-libs-duplication pkgconf --static --libs-only-l private-libs-duplication
} }
@ -87,7 +87,7 @@ missing_body()
atf_check \ atf_check \
-s exit:1 \ -s exit:1 \
-e ignore \ -e ignore \
-o inline:"\n" \ -o ignore \
pkgconf --cflags missing-require pkgconf --cflags missing-require
} }

View File

@ -6,6 +6,11 @@ tests_init \
cflags \ cflags \
variable \ variable \
do_not_eat_slash \ do_not_eat_slash \
do_not_duplicate_sysroot_dir \
uninstalled \
uninstalled_pkgconf1 \
uninstalled_fdo \
uninstalled_fdo_pc_sysrootdir
do_not_eat_slash_body() do_not_eat_slash_body()
{ {
@ -36,3 +41,70 @@ variable_body()
-o inline:"${SYSROOT_DIR}/test/include\n" \ -o inline:"${SYSROOT_DIR}/test/include\n" \
pkgconf --variable=includedir foo pkgconf --variable=includedir foo
} }
do_not_duplicate_sysroot_dir_body()
{
export PKG_CONFIG_PATH="${selfdir}/lib1"
export PKG_CONFIG_SYSROOT_DIR="/sysroot"
atf_check \
-o inline:"-I/sysroot/usr/include\n" \
pkgconf --cflags sysroot-dir-2
atf_check \
-o inline:"-I/sysroot/usr/include\n" \
pkgconf --cflags sysroot-dir-3
atf_check \
-o inline:"-I/sysroot/usr/include\n" \
pkgconf --cflags sysroot-dir-5
export PKG_CONFIG_SYSROOT_DIR="${SYSROOT_DIR}"
atf_check \
-o inline:"-I${SYSROOT_DIR}/usr/include\n" \
pkgconf --cflags sysroot-dir-4
}
uninstalled_body()
{
export PKG_CONFIG_PATH="${selfdir}/lib1"
export PKG_CONFIG_SYSROOT_DIR="/sysroot"
atf_check \
-o inline:"-L/test/lib -lomg\n" \
pkgconf --libs omg
}
uninstalled_pkgconf1_body()
{
export PKG_CONFIG_PATH="${selfdir}/lib1"
export PKG_CONFIG_SYSROOT_DIR="/sysroot"
export PKG_CONFIG_PKGCONF1_SYSROOT_RULES="1"
atf_check \
-o inline:"-L/sysroot/test/lib -lomg\n" \
pkgconf --libs omg
}
uninstalled_fdo_body()
{
export PKG_CONFIG_PATH="${selfdir}/lib1"
export PKG_CONFIG_SYSROOT_DIR="/sysroot"
export PKG_CONFIG_FDO_SYSROOT_RULES="1"
atf_check \
-o inline:"-L/test/lib -lomg\n" \
pkgconf --libs omg
}
uninstalled_fdo_pc_sysrootdir_body()
{
export PKG_CONFIG_PATH="${selfdir}/lib1"
export PKG_CONFIG_SYSROOT_DIR="/sysroot"
export PKG_CONFIG_FDO_SYSROOT_RULES="1"
atf_check \
-o inline:"-L/sysroot/test/lib -lomg\n" \
pkgconf --libs omg-sysroot
}

View File

@ -24,9 +24,8 @@ done
selfdir="@abs_top_srcdir@/tests" selfdir="@abs_top_srcdir@/tests"
LIBRARY_PATH_ENV="LIBRARY_PATH" LIBRARY_PATH_ENV="LIBRARY_PATH"
PATH_SEP=":" PATH_SEP=":"
SYSROOT_DIR="${selfdir}/test" SYSROOT_DIR="${selfdir}"
case "$(uname -s)" in case "$(uname -s)" in
Msys|CYGWIN*) PATH_SEP=";";;
Haiku) LIBRARY_PATH_ENV="BELIBRARIES";; Haiku) LIBRARY_PATH_ENV="BELIBRARIES";;
esac esac