3
* higher-level dependency graph compilation, management and manipulation
5
* Copyright (c) 2011, 2012, 2013 pkgconf authors (see AUTHORS).
7
* Permission to use, copy, modify, and/or distribute this software for any
8
* purpose with or without fee is hereby granted, provided that the above
9
* copyright notice and this permission notice appear in all copies.
11
* This software is provided 'as is' and without any warranty, express or
12
* implied. In no event shall the authors be liable for any damages arising
13
* from the use of this software.
16
#include <libpkgconf/config.h>
17
#include <libpkgconf/stdinc.h>
18
#include <libpkgconf/libpkgconf.h>
23
* libpkgconf `pkg` module
24
* =======================
26
* The `pkg` module provides dependency resolution services and the overall `.pc` file parsing
31
# define PKG_CONFIG_REG_KEY "Software\\pkgconfig\\PKG_CONFIG_PATH"
32
# undef PKG_DEFAULT_PATH
33
# define PKG_DEFAULT_PATH "../lib/pkgconfig;../share/pkgconfig"
34
# define strncasecmp _strnicmp
35
# define strcasecmp _stricmp
38
#define PKG_CONFIG_EXT ".pc"
41
str_has_suffix(const char *str, const char *suffix)
43
size_t str_len = strlen(str);
44
size_t suf_len = strlen(suffix);
46
if (str_len < suf_len)
49
return !strncasecmp(str + str_len - suf_len, suffix, suf_len);
53
pkg_get_parent_dir(pkgconf_pkg_t *pkg)
55
char buf[PKGCONF_ITEM_SIZE], *pathbuf;
57
pkgconf_strlcpy(buf, pkg->filename, sizeof buf);
58
pathbuf = strrchr(buf, PKG_DIR_SEP_S);
60
pathbuf = strrchr(buf, '/');
67
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);
70
const pkgconf_pkg_parser_keyword_func_t func;
71
const ptrdiff_t offset;
72
} pkgconf_pkg_parser_keyword_pair_t;
74
static int pkgconf_pkg_parser_keyword_pair_cmp(const void *key, const void *ptr)
76
const pkgconf_pkg_parser_keyword_pair_t *pair = ptr;
77
return strcasecmp(key, pair->keyword);
81
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)
86
char **dest = (char **)((char *) pkg + offset);
87
*dest = pkgconf_tuple_parse(client, &pkg->vars, value);
91
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)
97
char **dest = (char **)((char *) pkg + offset);
99
/* cut at any detected whitespace */
100
p = pkgconf_tuple_parse(client, &pkg->vars, value);
102
len = strcspn(p, " \t");
103
if (len != strlen(p))
105
i = p + (ptrdiff_t) len;
108
pkgconf_warn(client, "%s:" SIZE_FMT_SPECIFIER ": warning: malformed version field with whitespace, trimming to [%s]\n", pkg->filename,
116
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)
118
pkgconf_list_t *dest = (pkgconf_list_t *)((char *) pkg + offset);
119
bool ret = pkgconf_fragment_parse(client, dest, &pkg->vars, value);
123
pkgconf_warn(client, "%s:" SIZE_FMT_SPECIFIER ": warning: unable to parse field '%s' into an argument vector, value [%s]\n", pkg->filename,
124
lineno, keyword, value);
129
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)
134
pkgconf_list_t *dest = (pkgconf_list_t *)((char *) pkg + offset);
135
pkgconf_dependency_parse(client, pkg, dest, value, 0);
138
/* a variant of pkgconf_pkg_parser_dependency_func which colors the dependency node as an "internal" dependency. */
140
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)
145
pkgconf_list_t *dest = (pkgconf_list_t *)((char *) pkg + offset);
146
pkgconf_dependency_parse(client, pkg, dest, value, PKGCONF_PKG_DEPF_INTERNAL);
149
/* keep this in alphabetical order */
150
static const pkgconf_pkg_parser_keyword_pair_t pkgconf_pkg_parser_keyword_funcs[] = {
151
{"CFLAGS", pkgconf_pkg_parser_fragment_func, offsetof(pkgconf_pkg_t, cflags)},
152
{"CFLAGS.private", pkgconf_pkg_parser_fragment_func, offsetof(pkgconf_pkg_t, cflags_private)},
153
{"Conflicts", pkgconf_pkg_parser_dependency_func, offsetof(pkgconf_pkg_t, conflicts)},
154
{"Description", pkgconf_pkg_parser_tuple_func, offsetof(pkgconf_pkg_t, description)},
155
{"LIBS", pkgconf_pkg_parser_fragment_func, offsetof(pkgconf_pkg_t, libs)},
156
{"LIBS.private", pkgconf_pkg_parser_fragment_func, offsetof(pkgconf_pkg_t, libs_private)},
157
{"Name", pkgconf_pkg_parser_tuple_func, offsetof(pkgconf_pkg_t, realname)},
158
{"Provides", pkgconf_pkg_parser_dependency_func, offsetof(pkgconf_pkg_t, provides)},
159
{"Requires", pkgconf_pkg_parser_dependency_func, offsetof(pkgconf_pkg_t, required)},
160
{"Requires.internal", pkgconf_pkg_parser_internal_dependency_func, offsetof(pkgconf_pkg_t, requires_private)},
161
{"Requires.private", pkgconf_pkg_parser_dependency_func, offsetof(pkgconf_pkg_t, requires_private)},
162
{"Version", pkgconf_pkg_parser_version_func, offsetof(pkgconf_pkg_t, version)},
166
pkgconf_pkg_parser_keyword_set(void *opaque, const size_t lineno, const char *keyword, const char *value)
168
pkgconf_pkg_t *pkg = opaque;
170
const pkgconf_pkg_parser_keyword_pair_t *pair = bsearch(keyword,
171
pkgconf_pkg_parser_keyword_funcs, PKGCONF_ARRAY_SIZE(pkgconf_pkg_parser_keyword_funcs),
172
sizeof(pkgconf_pkg_parser_keyword_pair_t), pkgconf_pkg_parser_keyword_pair_cmp);
174
if (pair == NULL || pair->func == NULL)
177
pair->func(pkg->owner, pkg, keyword, lineno, pair->offset, value);
181
determine_prefix(const pkgconf_pkg_t *pkg, char *buf, size_t buflen)
185
pkgconf_strlcpy(buf, pkg->filename, buflen);
186
pkgconf_path_relocate(buf, buflen);
188
pathiter = strrchr(buf, PKG_DIR_SEP_S);
189
if (pathiter == NULL)
190
pathiter = strrchr(buf, '/');
191
if (pathiter != NULL)
194
pathiter = strrchr(buf, PKG_DIR_SEP_S);
195
if (pathiter == NULL)
196
pathiter = strrchr(buf, '/');
197
if (pathiter == NULL)
200
/* parent dir is not pkgconfig, can't relocate then */
201
if (strcmp(pathiter + 1, "pkgconfig"))
204
/* okay, work backwards and do it again. */
206
pathiter = strrchr(buf, PKG_DIR_SEP_S);
207
if (pathiter == NULL)
208
pathiter = strrchr(buf, '/');
209
if (pathiter == NULL)
218
* Takes a real path and converts it to a pkgconf value. This means normalizing
219
* directory separators and escaping things (only spaces covered atm).
221
* This is useful for things like prefix/pcfiledir which might get injected
222
* at runtime and are not sourced from the .pc file.
224
* "C:\foo bar\baz" -> "C:/foo\ bar/baz"
225
* "/foo bar/baz" -> "/foo\ bar/baz"
228
convert_path_to_value(const char *path)
230
char *buf = calloc((strlen(path) + 1) * 2, 1);
234
for (i = path; *i != '\0'; i++)
236
if (*i == PKG_DIR_SEP_S)
238
else if (*i == ' ') {
249
remove_additional_separators(char *buf)
258
while (*q && *q == '/')
262
memmove (p, q, strlen (q) + 1);
270
canonicalize_path(char *buf)
272
remove_additional_separators(buf);
276
is_path_prefix_equal(const char *path1, const char *path2, size_t path2_len)
279
return !_strnicmp(path1, path2, path2_len);
281
return !strncmp(path1, path2, path2_len);
286
pkgconf_pkg_parser_value_set(void *opaque, const size_t lineno, const char *keyword, const char *value)
288
char canonicalized_value[PKGCONF_ITEM_SIZE];
289
pkgconf_pkg_t *pkg = opaque;
293
pkgconf_strlcpy(canonicalized_value, value, sizeof canonicalized_value);
294
canonicalize_path(canonicalized_value);
296
/* Some pc files will use absolute paths for all of their directories
297
* which is broken when redefining the prefix. We try to outsmart the
298
* file and rewrite any directory that starts with the same prefix.
300
if (strcmp(keyword, pkg->owner->prefix_varname) || !(pkg->owner->flags & PKGCONF_PKG_PKGF_REDEFINE_PREFIX))
302
pkgconf_tuple_add(pkg->owner, &pkg->vars, keyword, value, true);
304
else if (pkg->owner->flags & PKGCONF_PKG_PKGF_REDEFINE_PREFIX && pkg->orig_prefix
305
&& is_path_prefix_equal(canonicalized_value, pkg->orig_prefix->value, strlen(pkg->orig_prefix->value)))
307
char newvalue[PKGCONF_ITEM_SIZE];
309
pkgconf_strlcpy(newvalue, pkg->prefix->value, sizeof newvalue);
310
pkgconf_strlcat(newvalue, canonicalized_value + strlen(pkg->orig_prefix->value), sizeof newvalue);
311
pkgconf_tuple_add(pkg->owner, &pkg->vars, keyword, newvalue, false);
315
char pathbuf[PKGCONF_ITEM_SIZE];
316
const char *relvalue = determine_prefix(pkg, pathbuf, sizeof pathbuf);
318
if (relvalue != NULL)
320
char *prefix_value = convert_path_to_value(relvalue);
321
pkg->orig_prefix = pkgconf_tuple_add(pkg->owner, &pkg->vars, "orig_prefix", canonicalized_value, true);
322
pkgconf_tuple_add_global(pkg->owner, keyword, prefix_value);
326
pkgconf_tuple_add(pkg->owner, &pkg->vars, keyword, value, true);
332
const ptrdiff_t offset;
333
} pkgconf_pkg_validity_check_t;
335
static const pkgconf_pkg_validity_check_t pkgconf_pkg_validations[] = {
336
{"Name", offsetof(pkgconf_pkg_t, realname)},
337
{"Description", offsetof(pkgconf_pkg_t, description)},
338
{"Version", offsetof(pkgconf_pkg_t, version)},
341
static const pkgconf_parser_operand_func_t pkg_parser_funcs[256] = {
342
[':'] = pkgconf_pkg_parser_keyword_set,
343
['='] = pkgconf_pkg_parser_value_set
346
static void pkg_warn_func(pkgconf_pkg_t *pkg, const char *fmt, ...) PRINTFLIKE(2, 3);
349
pkg_warn_func(pkgconf_pkg_t *pkg, const char *fmt, ...)
351
char buf[PKGCONF_ITEM_SIZE];
355
vsnprintf(buf, sizeof buf, fmt, va);
358
pkgconf_warn(pkg->owner, "%s", buf);
362
pkgconf_pkg_validate(const pkgconf_client_t *client, const pkgconf_pkg_t *pkg)
367
for (i = 0; i < PKGCONF_ARRAY_SIZE(pkgconf_pkg_validations); i++)
369
char **p = (char **)((char *) pkg + pkgconf_pkg_validations[i].offset);
374
pkgconf_warn(client, "%s: warning: file does not declare a `%s' field\n", pkg->filename, pkgconf_pkg_validations[i].field);
384
* .. c:function:: pkgconf_pkg_t *pkgconf_pkg_new_from_file(const pkgconf_client_t *client, const char *filename, FILE *f)
386
* Parse a .pc file into a pkgconf_pkg_t object structure.
388
* :param pkgconf_client_t* client: The pkgconf client object to use for dependency resolution.
389
* :param char* filename: The filename of the package file (including full path).
390
* :param FILE* f: The file object to read from.
391
* :returns: A ``pkgconf_pkg_t`` object which contains the package data.
392
* :rtype: pkgconf_pkg_t *
395
pkgconf_pkg_new_from_file(pkgconf_client_t *client, const char *filename, FILE *f)
400
pkg = calloc(sizeof(pkgconf_pkg_t), 1);
402
pkg->filename = strdup(filename);
403
pkg->pc_filedir = pkg_get_parent_dir(pkg);
405
char *pc_filedir_value = convert_path_to_value(pkg->pc_filedir);
406
pkgconf_tuple_add(client, &pkg->vars, "pcfiledir", pc_filedir_value, true);
407
free(pc_filedir_value);
409
/* If pc_filedir is outside of sysroot_dir, clear pc_filedir
410
* See https://github.com/pkgconf/pkgconf/issues/213
412
if (client->sysroot_dir && strncmp(pkg->pc_filedir, client->sysroot_dir, strlen(client->sysroot_dir)))
414
free(client->sysroot_dir);
415
client->sysroot_dir = NULL;
416
pkgconf_client_set_sysroot_dir(client, NULL);
420
if ((idptr = strrchr(pkg->filename, PKG_DIR_SEP_S)) != NULL)
423
idptr = pkg->filename;
426
/* On Windows, both \ and / are allowed in paths, so we have to chop both.
427
* strrchr() took us to the last \ in that case, so we just have to see if
428
* it is followed by a /. If so, lop it off.
431
if ((mungeptr = strrchr(idptr, '/')) != NULL)
435
pkg->id = strdup(idptr);
436
idptr = strrchr(pkg->id, '.');
440
pkgconf_parser_parse(f, pkg, pkg_parser_funcs, (pkgconf_parser_warn_func_t) pkg_warn_func, pkg->filename);
442
if (!pkgconf_pkg_validate(client, pkg))
444
pkgconf_warn(client, "%s: warning: skipping invalid file\n", pkg->filename);
445
pkgconf_pkg_free(client, pkg);
449
pkgconf_dependency_add(client, &pkg->provides, pkg->id, pkg->version, PKGCONF_CMP_EQUAL, 0);
451
return pkgconf_pkg_ref(client, pkg);
457
* .. c:function:: void pkgconf_pkg_free(pkgconf_client_t *client, pkgconf_pkg_t *pkg)
459
* Releases all releases for a given ``pkgconf_pkg_t`` object.
461
* :param pkgconf_client_t* client: The client which owns the ``pkgconf_pkg_t`` object, `pkg`.
462
* :param pkgconf_pkg_t* pkg: The package to free.
466
pkgconf_pkg_free(pkgconf_client_t *client, pkgconf_pkg_t *pkg)
471
if (pkg->flags & PKGCONF_PKG_PROPF_STATIC && !(pkg->flags & PKGCONF_PKG_PROPF_VIRTUAL))
474
pkgconf_cache_remove(client, pkg);
476
pkgconf_dependency_free(&pkg->required);
477
pkgconf_dependency_free(&pkg->requires_private);
478
pkgconf_dependency_free(&pkg->conflicts);
479
pkgconf_dependency_free(&pkg->provides);
481
pkgconf_fragment_free(&pkg->cflags);
482
pkgconf_fragment_free(&pkg->cflags_private);
483
pkgconf_fragment_free(&pkg->libs);
484
pkgconf_fragment_free(&pkg->libs_private);
486
pkgconf_tuple_free(&pkg->vars);
488
if (pkg->flags & PKGCONF_PKG_PROPF_VIRTUAL)
494
if (pkg->filename != NULL)
497
if (pkg->realname != NULL)
500
if (pkg->version != NULL)
503
if (pkg->description != NULL)
504
free(pkg->description);
506
if (pkg->url != NULL)
509
if (pkg->pc_filedir != NULL)
510
free(pkg->pc_filedir);
518
* .. c:function:: pkgconf_pkg_t *pkgconf_pkg_ref(const pkgconf_client_t *client, pkgconf_pkg_t *pkg)
520
* Adds an additional reference to the package object.
522
* :param pkgconf_client_t* client: The pkgconf client object which owns the package being referenced.
523
* :param pkgconf_pkg_t* pkg: The package object being referenced.
524
* :return: The package itself with an incremented reference count.
525
* :rtype: pkgconf_pkg_t *
528
pkgconf_pkg_ref(pkgconf_client_t *client, pkgconf_pkg_t *pkg)
530
if (pkg->owner != NULL && pkg->owner != client)
531
PKGCONF_TRACE(client, "WTF: client %p refers to package %p owned by other client %p", client, pkg, pkg->owner);
534
PKGCONF_TRACE(client, "refcount@%p: %d", pkg, pkg->refcount);
542
* .. c:function:: void pkgconf_pkg_unref(pkgconf_client_t *client, pkgconf_pkg_t *pkg)
544
* Releases a reference on the package object. If the reference count is 0, then also free the package.
546
* :param pkgconf_client_t* client: The pkgconf client object which owns the package being dereferenced.
547
* :param pkgconf_pkg_t* pkg: The package object being dereferenced.
551
pkgconf_pkg_unref(pkgconf_client_t *client, pkgconf_pkg_t *pkg)
553
if (pkg->owner != NULL && pkg->owner != client)
554
PKGCONF_TRACE(client, "WTF: client %p unrefs package %p owned by other client %p", client, pkg, pkg->owner);
557
PKGCONF_TRACE(pkg->owner, "refcount@%p: %d", pkg, pkg->refcount);
559
if (pkg->refcount <= 0)
560
pkgconf_pkg_free(pkg->owner, pkg);
563
static inline pkgconf_pkg_t *
564
pkgconf_pkg_try_specific_path(pkgconf_client_t *client, const char *path, const char *name)
566
pkgconf_pkg_t *pkg = NULL;
568
char locbuf[PKGCONF_ITEM_SIZE];
569
char uninst_locbuf[PKGCONF_ITEM_SIZE];
571
PKGCONF_TRACE(client, "trying path: %s for %s", path, name);
573
snprintf(locbuf, sizeof locbuf, "%s%c%s" PKG_CONFIG_EXT, path, PKG_DIR_SEP_S, name);
574
snprintf(uninst_locbuf, sizeof uninst_locbuf, "%s%c%s-uninstalled" PKG_CONFIG_EXT, path, PKG_DIR_SEP_S, name);
576
if (!(client->flags & PKGCONF_PKG_PKGF_NO_UNINSTALLED) && (f = fopen(uninst_locbuf, "r")) != NULL)
578
PKGCONF_TRACE(client, "found (uninstalled): %s", uninst_locbuf);
579
pkg = pkgconf_pkg_new_from_file(client, uninst_locbuf, f);
581
pkg->flags |= PKGCONF_PKG_PROPF_UNINSTALLED;
583
else if ((f = fopen(locbuf, "r")) != NULL)
585
PKGCONF_TRACE(client, "found: %s", locbuf);
586
pkg = pkgconf_pkg_new_from_file(client, locbuf, f);
592
static pkgconf_pkg_t *
593
pkgconf_pkg_scan_dir(pkgconf_client_t *client, const char *path, void *data, pkgconf_pkg_iteration_func_t func)
596
struct dirent *dirent;
597
pkgconf_pkg_t *outpkg = NULL;
603
PKGCONF_TRACE(client, "scanning dir [%s]", path);
605
for (dirent = readdir(dir); dirent != NULL; dirent = readdir(dir))
607
char filebuf[PKGCONF_ITEM_SIZE];
611
pkgconf_strlcpy(filebuf, path, sizeof filebuf);
612
pkgconf_strlcat(filebuf, "/", sizeof filebuf);
613
pkgconf_strlcat(filebuf, dirent->d_name, sizeof filebuf);
615
if (!str_has_suffix(filebuf, PKG_CONFIG_EXT))
618
PKGCONF_TRACE(client, "trying file [%s]", filebuf);
620
f = fopen(filebuf, "r");
624
pkg = pkgconf_pkg_new_from_file(client, filebuf, f);
633
pkgconf_pkg_unref(client, pkg);
645
* .. c:function:: pkgconf_pkg_t *pkgconf_scan_all(pkgconf_client_t *client, void *data, pkgconf_pkg_iteration_func_t func)
647
* Iterates over all packages found in the `package directory list`, running ``func`` on them. If ``func`` returns true,
648
* then stop iteration and return the last iterated package.
650
* :param pkgconf_client_t* client: The pkgconf client object to use for dependency resolution.
651
* :param void* data: An opaque pointer to data to provide the iteration function with.
652
* :param pkgconf_pkg_iteration_func_t func: A function which is called for each package to determine if the package matches,
653
* always return ``false`` to iterate over all packages.
654
* :return: A package object reference if one is found by the scan function, else ``NULL``.
655
* :rtype: pkgconf_pkg_t *
658
pkgconf_scan_all(pkgconf_client_t *client, void *data, pkgconf_pkg_iteration_func_t func)
663
PKGCONF_FOREACH_LIST_ENTRY(client->dir_list.head, n)
665
pkgconf_path_t *pnode = n->data;
667
PKGCONF_TRACE(client, "scanning directory: %s", pnode->path);
669
if ((pkg = pkgconf_pkg_scan_dir(client, pnode->path, data, func)) != NULL)
677
static pkgconf_pkg_t *
678
pkgconf_pkg_find_in_registry_key(pkgconf_client_t *client, HKEY hkey, const char *name)
680
pkgconf_pkg_t *pkg = NULL;
685
char buf[16384]; /* per registry limits */
686
DWORD bufsize = sizeof buf;
687
if (RegOpenKeyEx(hkey, PKG_CONFIG_REG_KEY,
688
0, KEY_READ, &key) != ERROR_SUCCESS)
691
while (RegEnumValue(key, i++, buf, &bufsize, NULL, NULL, NULL, NULL)
694
char pathbuf[PKGCONF_ITEM_SIZE];
696
DWORD pathbuflen = sizeof pathbuf;
698
if (RegQueryValueEx(key, buf, NULL, &type, (LPBYTE) pathbuf, &pathbuflen)
699
== ERROR_SUCCESS && type == REG_SZ)
701
pkg = pkgconf_pkg_try_specific_path(client, pathbuf, name);
706
bufsize = sizeof buf;
717
* .. c:function:: pkgconf_pkg_t *pkgconf_pkg_find(pkgconf_client_t *client, const char *name)
719
* Search for a package.
721
* :param pkgconf_client_t* client: The pkgconf client object to use for dependency resolution.
722
* :param char* name: The name of the package `atom` to use for searching.
723
* :return: A package object reference if the package was found, else ``NULL``.
724
* :rtype: pkgconf_pkg_t *
727
pkgconf_pkg_find(pkgconf_client_t *client, const char *name)
729
pkgconf_pkg_t *pkg = NULL;
733
PKGCONF_TRACE(client, "looking for: %s", name);
735
/* name might actually be a filename. */
736
if (str_has_suffix(name, PKG_CONFIG_EXT))
738
if ((f = fopen(name, "r")) != NULL)
742
PKGCONF_TRACE(client, "%s is a file", name);
744
pkg = pkgconf_pkg_new_from_file(client, name, f);
747
pkgconf_path_add(pkg->pc_filedir, &client->dir_list, true);
754
if ((pkg = pkgconf_builtin_pkg_get(name)) != NULL)
756
PKGCONF_TRACE(client, "%s is a builtin", name);
761
if (!(client->flags & PKGCONF_PKG_PKGF_NO_CACHE))
763
if ((pkg = pkgconf_cache_lookup(client, name)) != NULL)
765
PKGCONF_TRACE(client, "%s is cached", name);
770
PKGCONF_FOREACH_LIST_ENTRY(client->dir_list.head, n)
772
pkgconf_path_t *pnode = n->data;
774
pkg = pkgconf_pkg_try_specific_path(client, pnode->path, name);
780
/* support getting PKG_CONFIG_PATH from registry */
781
pkg = pkgconf_pkg_find_in_registry_key(client, HKEY_CURRENT_USER, name);
783
pkg = pkgconf_pkg_find_in_registry_key(client, HKEY_LOCAL_MACHINE, name);
787
pkgconf_cache_add(client, pkg);
795
* .. c:function:: int pkgconf_compare_version(const char *a, const char *b)
797
* Compare versions using RPM version comparison rules as described in the LSB.
799
* :param char* a: The first version to compare in the pair.
800
* :param char* b: The second version to compare in the pair.
801
* :return: -1 if the first version is less than, 0 if both versions are equal, 1 if the second version is less than.
805
pkgconf_compare_version(const char *a, const char *b)
808
char buf1[PKGCONF_ITEM_SIZE], buf2[PKGCONF_ITEM_SIZE];
814
/* optimization: if version matches then it's the same version. */
821
if (!strcasecmp(a, b))
824
pkgconf_strlcpy(buf1, a, sizeof buf1);
825
pkgconf_strlcpy(buf2, b, sizeof buf2);
832
while (*one && !isalnum((unsigned int)*one) && *one != '~')
834
while (*two && !isalnum((unsigned int)*two) && *two != '~')
837
if (*one == '~' || *two == '~')
855
if (isdigit((unsigned int)*str1))
857
while (*str1 && isdigit((unsigned int)*str1))
860
while (*str2 && isdigit((unsigned int)*str2))
867
while (*str1 && isalpha((unsigned int)*str1))
870
while (*str2 && isalpha((unsigned int)*str2))
886
return (isnum ? 1 : -1);
898
onelen = strlen(one);
899
twolen = strlen(two);
903
else if (twolen > onelen)
907
ret = strcmp(one, two);
909
return ret < 0 ? -1 : 1;
918
if ((!*one) && (!*two))
927
static pkgconf_pkg_t pkg_config_virtual = {
929
.realname = "pkg-config",
930
.description = "virtual package defining pkg-config API version supported",
931
.url = PACKAGE_BUGREPORT,
932
.version = PACKAGE_VERSION,
933
.flags = PKGCONF_PKG_PROPF_STATIC,
935
.head = &(pkgconf_node_t){
936
.next = &(pkgconf_node_t){
937
.next = &(pkgconf_node_t){
938
.data = &(pkgconf_tuple_t){
939
.key = "pc_system_libdirs",
940
.value = SYSTEM_LIBDIR,
943
.data = &(pkgconf_tuple_t){
944
.key = "pc_system_includedirs",
945
.value = SYSTEM_INCLUDEDIR,
948
.data = &(pkgconf_tuple_t){
950
.value = PKG_DEFAULT_PATH,
957
static pkgconf_pkg_t pkgconf_virtual = {
959
.realname = "pkgconf",
960
.description = "virtual package defining pkgconf API version supported",
961
.url = PACKAGE_BUGREPORT,
962
.version = PACKAGE_VERSION,
963
.flags = PKGCONF_PKG_PROPF_STATIC,
965
.head = &(pkgconf_node_t){
966
.next = &(pkgconf_node_t){
967
.next = &(pkgconf_node_t){
968
.data = &(pkgconf_tuple_t){
969
.key = "pc_system_libdirs",
970
.value = SYSTEM_LIBDIR,
973
.data = &(pkgconf_tuple_t){
974
.key = "pc_system_includedirs",
975
.value = SYSTEM_INCLUDEDIR,
978
.data = &(pkgconf_tuple_t){
980
.value = PKG_DEFAULT_PATH,
990
} pkgconf_builtin_pkg_pair_t;
992
/* keep these in alphabetical order */
993
static const pkgconf_builtin_pkg_pair_t pkgconf_builtin_pkg_pair_set[] = {
994
{"pkg-config", &pkg_config_virtual},
995
{"pkgconf", &pkgconf_virtual},
998
static int pkgconf_builtin_pkg_pair_cmp(const void *key, const void *ptr)
1000
const pkgconf_builtin_pkg_pair_t *pair = ptr;
1001
return strcasecmp(key, pair->name);
1007
* .. c:function:: pkgconf_pkg_t *pkgconf_builtin_pkg_get(const char *name)
1009
* Looks up a built-in package. The package should not be freed or dereferenced.
1011
* :param char* name: An atom corresponding to a built-in package to search for.
1012
* :return: the built-in package if present, else ``NULL``.
1013
* :rtype: pkgconf_pkg_t *
1016
pkgconf_builtin_pkg_get(const char *name)
1018
const pkgconf_builtin_pkg_pair_t *pair = bsearch(name, pkgconf_builtin_pkg_pair_set,
1019
PKGCONF_ARRAY_SIZE(pkgconf_builtin_pkg_pair_set), sizeof(pkgconf_builtin_pkg_pair_t),
1020
pkgconf_builtin_pkg_pair_cmp);
1022
return (pair != NULL) ? pair->pkg : NULL;
1025
typedef bool (*pkgconf_vercmp_res_func_t)(const char *a, const char *b);
1029
pkgconf_pkg_comparator_t compare;
1030
} pkgconf_pkg_comparator_pair_t;
1032
static const pkgconf_pkg_comparator_pair_t pkgconf_pkg_comparator_names[] = {
1033
{"!=", PKGCONF_CMP_NOT_EQUAL},
1034
{"(any)", PKGCONF_CMP_ANY},
1035
{"<", PKGCONF_CMP_LESS_THAN},
1036
{"<=", PKGCONF_CMP_LESS_THAN_EQUAL},
1037
{"=", PKGCONF_CMP_EQUAL},
1038
{">", PKGCONF_CMP_GREATER_THAN},
1039
{">=", PKGCONF_CMP_GREATER_THAN_EQUAL},
1042
static int pkgconf_pkg_comparator_pair_namecmp(const void *key, const void *ptr)
1044
const pkgconf_pkg_comparator_pair_t *pair = ptr;
1045
return strcmp(key, pair->name);
1048
static bool pkgconf_pkg_comparator_lt(const char *a, const char *b)
1050
return (pkgconf_compare_version(a, b) < 0);
1053
static bool pkgconf_pkg_comparator_gt(const char *a, const char *b)
1055
return (pkgconf_compare_version(a, b) > 0);
1058
static bool pkgconf_pkg_comparator_lte(const char *a, const char *b)
1060
return (pkgconf_compare_version(a, b) <= 0);
1063
static bool pkgconf_pkg_comparator_gte(const char *a, const char *b)
1065
return (pkgconf_compare_version(a, b) >= 0);
1068
static bool pkgconf_pkg_comparator_eq(const char *a, const char *b)
1070
return (pkgconf_compare_version(a, b) == 0);
1073
static bool pkgconf_pkg_comparator_ne(const char *a, const char *b)
1075
return (pkgconf_compare_version(a, b) != 0);
1078
static bool pkgconf_pkg_comparator_any(const char *a, const char *b)
1086
static bool pkgconf_pkg_comparator_none(const char *a, const char *b)
1094
static const pkgconf_vercmp_res_func_t pkgconf_pkg_comparator_impls[] = {
1095
[PKGCONF_CMP_ANY] = pkgconf_pkg_comparator_any,
1096
[PKGCONF_CMP_LESS_THAN] = pkgconf_pkg_comparator_lt,
1097
[PKGCONF_CMP_GREATER_THAN] = pkgconf_pkg_comparator_gt,
1098
[PKGCONF_CMP_LESS_THAN_EQUAL] = pkgconf_pkg_comparator_lte,
1099
[PKGCONF_CMP_GREATER_THAN_EQUAL] = pkgconf_pkg_comparator_gte,
1100
[PKGCONF_CMP_EQUAL] = pkgconf_pkg_comparator_eq,
1101
[PKGCONF_CMP_NOT_EQUAL] = pkgconf_pkg_comparator_ne,
1107
* .. c:function:: const char *pkgconf_pkg_get_comparator(const pkgconf_dependency_t *pkgdep)
1109
* Returns the comparator used in a depgraph dependency node as a string.
1111
* :param pkgconf_dependency_t* pkgdep: The depgraph dependency node to return the comparator for.
1112
* :return: A string matching the comparator or ``"???"``.
1116
pkgconf_pkg_get_comparator(const pkgconf_dependency_t *pkgdep)
1118
if (pkgdep->compare >= PKGCONF_ARRAY_SIZE(pkgconf_pkg_comparator_names))
1121
return pkgconf_pkg_comparator_names[pkgdep->compare].name;
1127
* .. c:function:: pkgconf_pkg_comparator_t pkgconf_pkg_comparator_lookup_by_name(const char *name)
1129
* Look up the appropriate comparator bytecode in the comparator set (defined
1130
* in ``pkg.c``, see ``pkgconf_pkg_comparator_names`` and ``pkgconf_pkg_comparator_impls``).
1132
* :param char* name: The comparator to look up by `name`.
1133
* :return: The comparator bytecode if found, else ``PKGCONF_CMP_ANY``.
1134
* :rtype: pkgconf_pkg_comparator_t
1136
pkgconf_pkg_comparator_t
1137
pkgconf_pkg_comparator_lookup_by_name(const char *name)
1139
const pkgconf_pkg_comparator_pair_t *p = bsearch(name, pkgconf_pkg_comparator_names,
1140
PKGCONF_ARRAY_SIZE(pkgconf_pkg_comparator_names), sizeof(pkgconf_pkg_comparator_pair_t),
1141
pkgconf_pkg_comparator_pair_namecmp);
1143
return (p != NULL) ? p->compare : PKGCONF_CMP_ANY;
1147
pkgconf_dependency_t *pkgdep;
1148
} pkgconf_pkg_scan_providers_ctx_t;
1151
const pkgconf_vercmp_res_func_t rulecmp[PKGCONF_CMP_COUNT];
1152
const pkgconf_vercmp_res_func_t depcmp[PKGCONF_CMP_COUNT];
1153
} pkgconf_pkg_provides_vermatch_rule_t;
1155
static const pkgconf_pkg_provides_vermatch_rule_t pkgconf_pkg_provides_vermatch_rules[] = {
1156
[PKGCONF_CMP_ANY] = {
1158
[PKGCONF_CMP_ANY] = pkgconf_pkg_comparator_none,
1161
[PKGCONF_CMP_ANY] = pkgconf_pkg_comparator_none,
1164
[PKGCONF_CMP_LESS_THAN] = {
1166
[PKGCONF_CMP_ANY] = pkgconf_pkg_comparator_none,
1167
[PKGCONF_CMP_LESS_THAN] = pkgconf_pkg_comparator_lt,
1168
[PKGCONF_CMP_GREATER_THAN] = pkgconf_pkg_comparator_gt,
1169
[PKGCONF_CMP_LESS_THAN_EQUAL] = pkgconf_pkg_comparator_lte,
1170
[PKGCONF_CMP_GREATER_THAN_EQUAL] = pkgconf_pkg_comparator_gte,
1173
[PKGCONF_CMP_GREATER_THAN] = pkgconf_pkg_comparator_lt,
1174
[PKGCONF_CMP_GREATER_THAN_EQUAL] = pkgconf_pkg_comparator_lt,
1175
[PKGCONF_CMP_EQUAL] = pkgconf_pkg_comparator_lt,
1176
[PKGCONF_CMP_NOT_EQUAL] = pkgconf_pkg_comparator_gte,
1179
[PKGCONF_CMP_GREATER_THAN] = {
1181
[PKGCONF_CMP_ANY] = pkgconf_pkg_comparator_none,
1182
[PKGCONF_CMP_LESS_THAN] = pkgconf_pkg_comparator_lt,
1183
[PKGCONF_CMP_GREATER_THAN] = pkgconf_pkg_comparator_gt,
1184
[PKGCONF_CMP_LESS_THAN_EQUAL] = pkgconf_pkg_comparator_lte,
1185
[PKGCONF_CMP_GREATER_THAN_EQUAL] = pkgconf_pkg_comparator_gte,
1188
[PKGCONF_CMP_LESS_THAN] = pkgconf_pkg_comparator_gt,
1189
[PKGCONF_CMP_LESS_THAN_EQUAL] = pkgconf_pkg_comparator_gt,
1190
[PKGCONF_CMP_EQUAL] = pkgconf_pkg_comparator_gt,
1191
[PKGCONF_CMP_NOT_EQUAL] = pkgconf_pkg_comparator_lte,
1194
[PKGCONF_CMP_LESS_THAN_EQUAL] = {
1196
[PKGCONF_CMP_ANY] = pkgconf_pkg_comparator_none,
1197
[PKGCONF_CMP_LESS_THAN] = pkgconf_pkg_comparator_lt,
1198
[PKGCONF_CMP_GREATER_THAN] = pkgconf_pkg_comparator_gt,
1199
[PKGCONF_CMP_LESS_THAN_EQUAL] = pkgconf_pkg_comparator_lte,
1200
[PKGCONF_CMP_GREATER_THAN_EQUAL] = pkgconf_pkg_comparator_gte,
1203
[PKGCONF_CMP_GREATER_THAN] = pkgconf_pkg_comparator_lte,
1204
[PKGCONF_CMP_GREATER_THAN_EQUAL] = pkgconf_pkg_comparator_lte,
1205
[PKGCONF_CMP_EQUAL] = pkgconf_pkg_comparator_lte,
1206
[PKGCONF_CMP_NOT_EQUAL] = pkgconf_pkg_comparator_gt,
1209
[PKGCONF_CMP_GREATER_THAN_EQUAL] = {
1211
[PKGCONF_CMP_ANY] = pkgconf_pkg_comparator_none,
1212
[PKGCONF_CMP_LESS_THAN] = pkgconf_pkg_comparator_lt,
1213
[PKGCONF_CMP_GREATER_THAN] = pkgconf_pkg_comparator_gt,
1214
[PKGCONF_CMP_LESS_THAN_EQUAL] = pkgconf_pkg_comparator_lte,
1215
[PKGCONF_CMP_GREATER_THAN_EQUAL] = pkgconf_pkg_comparator_gte,
1218
[PKGCONF_CMP_LESS_THAN] = pkgconf_pkg_comparator_gte,
1219
[PKGCONF_CMP_LESS_THAN_EQUAL] = pkgconf_pkg_comparator_gte,
1220
[PKGCONF_CMP_EQUAL] = pkgconf_pkg_comparator_gte,
1221
[PKGCONF_CMP_NOT_EQUAL] = pkgconf_pkg_comparator_lt,
1224
[PKGCONF_CMP_EQUAL] = {
1226
[PKGCONF_CMP_ANY] = pkgconf_pkg_comparator_none,
1227
[PKGCONF_CMP_LESS_THAN] = pkgconf_pkg_comparator_lt,
1228
[PKGCONF_CMP_GREATER_THAN] = pkgconf_pkg_comparator_gt,
1229
[PKGCONF_CMP_LESS_THAN_EQUAL] = pkgconf_pkg_comparator_lte,
1230
[PKGCONF_CMP_GREATER_THAN_EQUAL] = pkgconf_pkg_comparator_gte,
1231
[PKGCONF_CMP_EQUAL] = pkgconf_pkg_comparator_eq,
1232
[PKGCONF_CMP_NOT_EQUAL] = pkgconf_pkg_comparator_ne
1235
[PKGCONF_CMP_ANY] = pkgconf_pkg_comparator_none,
1238
[PKGCONF_CMP_NOT_EQUAL] = {
1240
[PKGCONF_CMP_ANY] = pkgconf_pkg_comparator_none,
1241
[PKGCONF_CMP_LESS_THAN] = pkgconf_pkg_comparator_gte,
1242
[PKGCONF_CMP_GREATER_THAN] = pkgconf_pkg_comparator_lte,
1243
[PKGCONF_CMP_LESS_THAN_EQUAL] = pkgconf_pkg_comparator_gt,
1244
[PKGCONF_CMP_GREATER_THAN_EQUAL] = pkgconf_pkg_comparator_lt,
1245
[PKGCONF_CMP_EQUAL] = pkgconf_pkg_comparator_ne,
1246
[PKGCONF_CMP_NOT_EQUAL] = pkgconf_pkg_comparator_eq
1249
[PKGCONF_CMP_ANY] = pkgconf_pkg_comparator_none,
1255
* pkgconf_pkg_scan_provides_vercmp(pkgdep, provider)
1257
* compare a provides node against the requested dependency node.
1259
* XXX: maybe handle PKGCONF_CMP_ANY in a versioned comparison
1262
pkgconf_pkg_scan_provides_vercmp(const pkgconf_dependency_t *pkgdep, const pkgconf_dependency_t *provider)
1264
const pkgconf_pkg_provides_vermatch_rule_t *rule = &pkgconf_pkg_provides_vermatch_rules[pkgdep->compare];
1266
if (rule->depcmp[provider->compare] != NULL &&
1267
!rule->depcmp[provider->compare](provider->version, pkgdep->version))
1270
if (rule->rulecmp[provider->compare] != NULL &&
1271
!rule->rulecmp[provider->compare](pkgdep->version, provider->version))
1278
* pkgconf_pkg_scan_provides_entry(pkg, ctx)
1280
* attempt to match a single package's Provides rules against the requested dependency node.
1283
pkgconf_pkg_scan_provides_entry(const pkgconf_pkg_t *pkg, const pkgconf_pkg_scan_providers_ctx_t *ctx)
1285
const pkgconf_dependency_t *pkgdep = ctx->pkgdep;
1286
pkgconf_node_t *node;
1288
PKGCONF_FOREACH_LIST_ENTRY(pkg->provides.head, node)
1290
const pkgconf_dependency_t *provider = node->data;
1291
if (!strcmp(provider->package, pkgdep->package))
1292
return pkgconf_pkg_scan_provides_vercmp(pkgdep, provider);
1299
* pkgconf_pkg_scan_providers(client, pkgdep, eflags)
1301
* scan all available packages to see if a Provides rule matches the pkgdep.
1303
static pkgconf_pkg_t *
1304
pkgconf_pkg_scan_providers(pkgconf_client_t *client, pkgconf_dependency_t *pkgdep, unsigned int *eflags)
1307
pkgconf_pkg_scan_providers_ctx_t ctx = {
1311
pkg = pkgconf_scan_all(client, &ctx, (pkgconf_pkg_iteration_func_t) pkgconf_pkg_scan_provides_entry);
1314
pkgdep->match = pkgconf_pkg_ref(client, pkg);
1319
*eflags |= PKGCONF_PKG_ERRF_PACKAGE_NOT_FOUND;
1327
* .. c:function:: pkgconf_pkg_t *pkgconf_pkg_verify_dependency(pkgconf_client_t *client, pkgconf_dependency_t *pkgdep, unsigned int *eflags)
1329
* Verify a pkgconf_dependency_t node in the depgraph. If the dependency is solvable,
1330
* return the appropriate ``pkgconf_pkg_t`` object, else ``NULL``.
1332
* :param pkgconf_client_t* client: The pkgconf client object to use for dependency resolution.
1333
* :param pkgconf_dependency_t* pkgdep: The dependency graph node to solve.
1334
* :param uint* eflags: An optional pointer that, if set, will be populated with an error code from the resolver.
1335
* :return: On success, the appropriate ``pkgconf_pkg_t`` object to solve the dependency, else ``NULL``.
1336
* :rtype: pkgconf_pkg_t *
1339
pkgconf_pkg_verify_dependency(pkgconf_client_t *client, pkgconf_dependency_t *pkgdep, unsigned int *eflags)
1341
pkgconf_pkg_t *pkg = NULL;
1344
*eflags = PKGCONF_PKG_ERRF_OK;
1346
PKGCONF_TRACE(client, "trying to verify dependency: %s", pkgdep->package);
1348
if (pkgdep->match != NULL)
1350
PKGCONF_TRACE(client, "cached dependency: %s -> %s@%p", pkgdep->package, pkgdep->match->id, pkgdep->match);
1351
return pkgconf_pkg_ref(client, pkgdep->match);
1354
pkg = pkgconf_pkg_find(client, pkgdep->package);
1357
if (client->flags & PKGCONF_PKG_PKGF_SKIP_PROVIDES)
1360
*eflags |= PKGCONF_PKG_ERRF_PACKAGE_NOT_FOUND;
1365
return pkgconf_pkg_scan_providers(client, pkgdep, eflags);
1368
if (pkg->id == NULL)
1369
pkg->id = strdup(pkgdep->package);
1371
if (pkgconf_pkg_comparator_impls[pkgdep->compare](pkg->version, pkgdep->version) != true)
1374
*eflags |= PKGCONF_PKG_ERRF_PACKAGE_VER_MISMATCH;
1377
pkgdep->match = pkgconf_pkg_ref(client, pkg);
1385
* .. c:function:: unsigned int pkgconf_pkg_verify_graph(pkgconf_client_t *client, pkgconf_pkg_t *root, int depth)
1387
* Verify the graph dependency nodes are satisfiable by walking the tree using
1388
* ``pkgconf_pkg_traverse()``.
1390
* :param pkgconf_client_t* client: The pkgconf client object to use for dependency resolution.
1391
* :param pkgconf_pkg_t* root: The root entry in the package dependency graph which should contain the top-level dependencies to resolve.
1392
* :param int depth: The maximum allowed depth for dependency resolution.
1393
* :return: On success, ``PKGCONF_PKG_ERRF_OK`` (0), else an error code.
1394
* :rtype: unsigned int
1397
pkgconf_pkg_verify_graph(pkgconf_client_t *client, pkgconf_pkg_t *root, int depth)
1399
return pkgconf_pkg_traverse(client, root, NULL, NULL, depth, 0);
1403
pkgconf_pkg_report_graph_error(pkgconf_client_t *client, pkgconf_pkg_t *parent, pkgconf_pkg_t *pkg, pkgconf_dependency_t *node, unsigned int eflags)
1405
if (eflags & PKGCONF_PKG_ERRF_PACKAGE_NOT_FOUND)
1407
if (!(client->flags & PKGCONF_PKG_PKGF_SIMPLIFY_ERRORS) & !client->already_sent_notice)
1409
pkgconf_error(client, "Package %s was not found in the pkg-config search path.\n", node->package);
1410
pkgconf_error(client, "Perhaps you should add the directory containing `%s.pc'\n", node->package);
1411
pkgconf_error(client, "to the PKG_CONFIG_PATH environment variable\n");
1412
client->already_sent_notice = true;
1415
pkgconf_error(client, "Package '%s', required by '%s', not found\n", node->package, parent->id);
1416
pkgconf_audit_log(client, "%s NOT-FOUND\n", node->package);
1418
else if (eflags & PKGCONF_PKG_ERRF_PACKAGE_VER_MISMATCH)
1420
pkgconf_error(client, "Package dependency requirement '%s %s %s' could not be satisfied.\n",
1421
node->package, pkgconf_pkg_get_comparator(node), node->version);
1424
pkgconf_error(client, "Package '%s' has version '%s', required version is '%s %s'\n",
1425
node->package, pkg->version, pkgconf_pkg_get_comparator(node), node->version);
1429
pkgconf_pkg_unref(client, pkg);
1434
static inline unsigned int
1435
pkgconf_pkg_walk_list(pkgconf_client_t *client,
1436
pkgconf_pkg_t *parent,
1437
pkgconf_list_t *deplist,
1438
pkgconf_pkg_traverse_func_t func,
1441
unsigned int skip_flags)
1443
unsigned int eflags = PKGCONF_PKG_ERRF_OK;
1444
pkgconf_node_t *node;
1446
PKGCONF_FOREACH_LIST_ENTRY(deplist->head, node)
1448
unsigned int eflags_local = PKGCONF_PKG_ERRF_OK;
1449
pkgconf_dependency_t *depnode = node->data;
1450
pkgconf_pkg_t *pkgdep;
1452
if (*depnode->package == '\0')
1455
pkgdep = pkgconf_pkg_verify_dependency(client, depnode, &eflags_local);
1457
eflags |= eflags_local;
1458
if (eflags_local != PKGCONF_PKG_ERRF_OK && !(client->flags & PKGCONF_PKG_PKGF_SKIP_ERRORS))
1460
pkgconf_pkg_report_graph_error(client, parent, pkgdep, depnode, eflags_local);
1466
if (pkgdep->flags & PKGCONF_PKG_PROPF_SEEN)
1468
pkgconf_pkg_unref(client, pkgdep);
1472
if (skip_flags && (depnode->flags & skip_flags) == skip_flags)
1474
pkgconf_pkg_unref(client, pkgdep);
1478
pkgconf_audit_log_dependency(client, pkgdep, depnode);
1480
pkgdep->flags |= PKGCONF_PKG_PROPF_SEEN;
1481
eflags |= pkgconf_pkg_traverse(client, pkgdep, func, data, depth - 1, skip_flags);
1482
pkgdep->flags &= ~PKGCONF_PKG_PROPF_SEEN;
1483
pkgconf_pkg_unref(client, pkgdep);
1489
static inline unsigned int
1490
pkgconf_pkg_walk_conflicts_list(pkgconf_client_t *client,
1491
pkgconf_pkg_t *root, pkgconf_list_t *deplist)
1493
unsigned int eflags;
1494
pkgconf_node_t *node, *childnode;
1496
PKGCONF_FOREACH_LIST_ENTRY(deplist->head, node)
1498
pkgconf_dependency_t *parentnode = node->data;
1500
if (*parentnode->package == '\0')
1503
PKGCONF_FOREACH_LIST_ENTRY(root->required.head, childnode)
1505
pkgconf_pkg_t *pkgdep;
1506
pkgconf_dependency_t *depnode = childnode->data;
1508
if (*depnode->package == '\0' || strcmp(depnode->package, parentnode->package))
1511
pkgdep = pkgconf_pkg_verify_dependency(client, parentnode, &eflags);
1512
if (eflags == PKGCONF_PKG_ERRF_OK)
1514
pkgconf_error(client, "Version '%s' of '%s' conflicts with '%s' due to satisfying conflict rule '%s %s%s%s'.\n",
1515
pkgdep->version, pkgdep->realname, root->realname, parentnode->package, pkgconf_pkg_get_comparator(parentnode),
1516
parentnode->version != NULL ? " " : "", parentnode->version != NULL ? parentnode->version : "");
1518
if (!(client->flags & PKGCONF_PKG_PKGF_SIMPLIFY_ERRORS))
1520
pkgconf_error(client, "It may be possible to ignore this conflict and continue, try the\n");
1521
pkgconf_error(client, "PKG_CONFIG_IGNORE_CONFLICTS environment variable.\n");
1524
pkgconf_pkg_unref(client, pkgdep);
1526
return PKGCONF_PKG_ERRF_PACKAGE_CONFLICT;
1529
pkgconf_pkg_unref(client, pkgdep);
1533
return PKGCONF_PKG_ERRF_OK;
1539
* .. 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)
1541
* Walk and resolve the dependency graph up to `maxdepth` levels.
1543
* :param pkgconf_client_t* client: The pkgconf client object to use for dependency resolution.
1544
* :param pkgconf_pkg_t* root: The root of the dependency graph.
1545
* :param pkgconf_pkg_traverse_func_t func: A traversal function to call for each resolved node in the dependency graph.
1546
* :param void* data: An opaque pointer to data to be passed to the traversal function.
1547
* :param int maxdepth: The maximum depth to walk the dependency graph for. -1 means infinite recursion.
1548
* :param uint skip_flags: Skip over dependency nodes containing the specified flags. A setting of 0 skips no dependency nodes.
1549
* :return: ``PKGCONF_PKG_ERRF_OK`` on success, else an error code.
1550
* :rtype: unsigned int
1553
pkgconf_pkg_traverse(pkgconf_client_t *client,
1554
pkgconf_pkg_t *root,
1555
pkgconf_pkg_traverse_func_t func,
1558
unsigned int skip_flags)
1560
unsigned int eflags = PKGCONF_PKG_ERRF_OK;
1565
PKGCONF_TRACE(client, "%s: level %d", root->id, maxdepth);
1567
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)
1570
func(client, root, data);
1573
if (!(client->flags & PKGCONF_PKG_PKGF_SKIP_CONFLICTS))
1575
eflags = pkgconf_pkg_walk_conflicts_list(client, root, &root->conflicts);
1576
if (eflags != PKGCONF_PKG_ERRF_OK)
1580
PKGCONF_TRACE(client, "%s: walking requires list", root->id);
1581
eflags = pkgconf_pkg_walk_list(client, root, &root->required, func, data, maxdepth, skip_flags);
1582
if (eflags != PKGCONF_PKG_ERRF_OK)
1585
if (client->flags & PKGCONF_PKG_PKGF_SEARCH_PRIVATE)
1587
PKGCONF_TRACE(client, "%s: walking requires.private list", root->id);
1590
client->flags |= PKGCONF_PKG_PKGF_ITER_PKG_IS_PRIVATE;
1591
eflags = pkgconf_pkg_walk_list(client, root, &root->requires_private, func, data, maxdepth, skip_flags);
1592
client->flags &= ~PKGCONF_PKG_PKGF_ITER_PKG_IS_PRIVATE;
1594
if (eflags != PKGCONF_PKG_ERRF_OK)
1602
pkgconf_pkg_cflags_collect(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data)
1604
pkgconf_list_t *list = data;
1605
pkgconf_node_t *node;
1607
PKGCONF_FOREACH_LIST_ENTRY(pkg->cflags.head, node)
1609
pkgconf_fragment_t *frag = node->data;
1610
pkgconf_fragment_copy(client, list, frag, false);
1615
pkgconf_pkg_cflags_private_collect(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data)
1617
pkgconf_list_t *list = data;
1618
pkgconf_node_t *node;
1620
PKGCONF_FOREACH_LIST_ENTRY(pkg->cflags_private.head, node)
1622
pkgconf_fragment_t *frag = node->data;
1623
pkgconf_fragment_copy(client, list, frag, true);
1630
* .. c:function:: int pkgconf_pkg_cflags(pkgconf_client_t *client, pkgconf_pkg_t *root, pkgconf_list_t *list, int maxdepth)
1632
* Walks a dependency graph and extracts relevant ``CFLAGS`` fragments.
1634
* :param pkgconf_client_t* client: The pkgconf client object to use for dependency resolution.
1635
* :param pkgconf_pkg_t* root: The root of the dependency graph.
1636
* :param pkgconf_list_t* list: The fragment list to add the extracted ``CFLAGS`` fragments to.
1637
* :param int maxdepth: The maximum allowed depth for dependency resolution. -1 means infinite recursion.
1638
* :return: ``PKGCONF_PKG_ERRF_OK`` if successful, otherwise an error code.
1639
* :rtype: unsigned int
1642
pkgconf_pkg_cflags(pkgconf_client_t *client, pkgconf_pkg_t *root, pkgconf_list_t *list, int maxdepth)
1645
unsigned int skip_flags = (client->flags & PKGCONF_PKG_PKGF_DONT_FILTER_INTERNAL_CFLAGS) == 0 ? PKGCONF_PKG_DEPF_INTERNAL : 0;
1646
pkgconf_list_t frags = PKGCONF_LIST_INITIALIZER;
1648
eflag = pkgconf_pkg_traverse(client, root, pkgconf_pkg_cflags_collect, &frags, maxdepth, skip_flags);
1650
if (eflag == PKGCONF_PKG_ERRF_OK && client->flags & PKGCONF_PKG_PKGF_MERGE_PRIVATE_FRAGMENTS)
1651
eflag = pkgconf_pkg_traverse(client, root, pkgconf_pkg_cflags_private_collect, &frags, maxdepth, skip_flags);
1653
if (eflag != PKGCONF_PKG_ERRF_OK)
1655
pkgconf_fragment_free(&frags);
1659
pkgconf_fragment_copy_list(client, list, &frags);
1660
pkgconf_fragment_free(&frags);
1666
pkgconf_pkg_libs_collect(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data)
1668
pkgconf_list_t *list = data;
1669
pkgconf_node_t *node;
1671
PKGCONF_FOREACH_LIST_ENTRY(pkg->libs.head, node)
1673
pkgconf_fragment_t *frag = node->data;
1674
pkgconf_fragment_copy(client, list, frag, (client->flags & PKGCONF_PKG_PKGF_ITER_PKG_IS_PRIVATE) != 0);
1677
if (client->flags & PKGCONF_PKG_PKGF_MERGE_PRIVATE_FRAGMENTS)
1679
PKGCONF_FOREACH_LIST_ENTRY(pkg->libs_private.head, node)
1681
pkgconf_fragment_t *frag = node->data;
1682
pkgconf_fragment_copy(client, list, frag, true);
1690
* .. c:function:: int pkgconf_pkg_libs(pkgconf_client_t *client, pkgconf_pkg_t *root, pkgconf_list_t *list, int maxdepth)
1692
* Walks a dependency graph and extracts relevant ``LIBS`` fragments.
1694
* :param pkgconf_client_t* client: The pkgconf client object to use for dependency resolution.
1695
* :param pkgconf_pkg_t* root: The root of the dependency graph.
1696
* :param pkgconf_list_t* list: The fragment list to add the extracted ``LIBS`` fragments to.
1697
* :param int maxdepth: The maximum allowed depth for dependency resolution. -1 means infinite recursion.
1698
* :return: ``PKGCONF_PKG_ERRF_OK`` if successful, otherwise an error code.
1699
* :rtype: unsigned int
1702
pkgconf_pkg_libs(pkgconf_client_t *client, pkgconf_pkg_t *root, pkgconf_list_t *list, int maxdepth)
1706
eflag = pkgconf_pkg_traverse(client, root, pkgconf_pkg_libs_collect, list, maxdepth, 0);
1708
if (eflag != PKGCONF_PKG_ERRF_OK)
1710
pkgconf_fragment_free(list);