aboutsummaryrefslogtreecommitdiff
path: root/libpkgconf/pkg.c
diff options
context:
space:
mode:
Diffstat (limited to 'libpkgconf/pkg.c')
-rw-r--r--libpkgconf/pkg.c918
1 files changed, 473 insertions, 445 deletions
diff --git a/libpkgconf/pkg.c b/libpkgconf/pkg.c
index 491c0defcd65..79a4e1d6065f 100644
--- a/libpkgconf/pkg.c
+++ b/libpkgconf/pkg.c
@@ -2,6 +2,8 @@
* pkg.c
* higher-level dependency graph compilation, management and manipulation
*
+ * SPDX-License-Identifier: pkgconf
+ *
* Copyright (c) 2011, 2012, 2013 pkgconf authors (see AUTHORS).
*
* Permission to use, copy, modify, and/or distribute this software for any
@@ -16,15 +18,7 @@
#include <libpkgconf/config.h>
#include <libpkgconf/stdinc.h>
#include <libpkgconf/libpkgconf.h>
-
-#ifndef _WIN32
-#include <fcntl.h> // open
-#include <libgen.h> // basename/dirname
-#include <sys/stat.h> // lstat, S_ISLNK
-#include <unistd.h> // close, readlinkat
-
-#include <string.h>
-#endif
+#include <libpkgconf/path.h>
/*
* !doc
@@ -36,13 +30,6 @@
* routines.
*/
-#ifdef _WIN32
-# undef PKG_DEFAULT_PATH
-# define PKG_DEFAULT_PATH "../lib/pkgconfig;../share/pkgconfig"
-# define strncasecmp _strnicmp
-# define strcasecmp _stricmp
-#endif
-
#define PKG_CONFIG_EXT ".pc"
static unsigned int
@@ -56,6 +43,9 @@ pkgconf_pkg_traverse_main(pkgconf_client_t *client,
static inline bool
str_has_suffix(const char *str, const char *suffix)
{
+ if (str == NULL || suffix == NULL)
+ return false;
+
size_t str_len = strlen(str);
size_t suf_len = strlen(suffix);
@@ -68,48 +58,56 @@ str_has_suffix(const char *str, const char *suffix)
static char *
pkg_get_parent_dir(pkgconf_pkg_t *pkg)
{
- char buf[PKGCONF_ITEM_SIZE], *pathbuf;
+ pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER;
+ pkgconf_buffer_t pathbuf = PKGCONF_BUFFER_INITIALIZER;
+
+ pkgconf_buffer_append(&buf, pkg->filename);
- pkgconf_strlcpy(buf, pkg->filename, sizeof buf);
#ifndef _WIN32
- /*
- * We want to resolve symlinks, since ${pcfiledir} should point to the
- * parent of the file symlinked to.
- */
struct stat path_stat;
- while (!lstat(buf, &path_stat) && S_ISLNK(path_stat.st_mode))
+
+ while (buf.base != NULL &&
+ !lstat(buf.base, &path_stat) &&
+ S_ISLNK(path_stat.st_mode))
{
- /*
- * Have to split the path into the dir + file components,
- * in order to extract the directory file descriptor.
- *
- * The nomenclature here uses the
- *
- * ln <source> <target>
- *
- * model.
- */
- char basenamebuf[PKGCONF_ITEM_SIZE];
- pkgconf_strlcpy(basenamebuf, buf, sizeof(basenamebuf));
- const char* targetfilename = basename(basenamebuf);
+ char sourcebuf[PKGCONF_ITEM_SIZE];
+ char *targetfilename, *targetdir;
+
+ pkgconf_buffer_reset(&pathbuf);
+ pkgconf_buffer_append(&pathbuf, buf.base);
- char dirnamebuf[PKGCONF_ITEM_SIZE];
- pkgconf_strlcpy(dirnamebuf, buf, sizeof(dirnamebuf));
- const char* targetdir = dirname(dirnamebuf);
+ targetfilename = strrchr(pathbuf.base, '/');
+ if (targetfilename != NULL)
+ {
+ *targetfilename++ = '\0';
+ targetdir = pathbuf.base;
+ if (*targetdir == '\0')
+ targetdir = "/";
+ }
+ else
+ {
+ targetfilename = pathbuf.base;
+ targetdir = ".";
+ }
+
+#ifdef HAVE_DECL_READLINKAT
const int dirfd = open(targetdir, O_DIRECTORY);
if (dirfd == -1)
break;
- char sourcebuf[PKGCONF_ITEM_SIZE];
ssize_t len = readlinkat(dirfd, targetfilename, sourcebuf, sizeof(sourcebuf) - 1);
close(dirfd);
+#else
+ ssize_t len = readlink(buf.base, sourcebuf, sizeof(sourcebuf) - 1);
+#endif
if (len == -1)
break;
sourcebuf[len] = '\0';
- memset(buf, '\0', sizeof buf);
+ pkgconf_buffer_reset(&buf);
+
/*
* The logic here can be a bit tricky, so here's a table:
*
@@ -120,26 +118,22 @@ pkg_get_parent_dir(pkgconf_pkg_t *pkg)
* /bar (absolute) | /foo/link (absolute) | /bar (absolute)
* ../bar (relative) | /foo/link (absolute) | /foo/../bar (relative)
*/
- if ((sourcebuf[0] != '/') /* absolute path in <source> wins */
- && (strcmp(targetdir, "."))) /* do not prepend "." */
- {
- pkgconf_strlcat(buf, targetdir, sizeof buf);
- pkgconf_strlcat(buf, "/", sizeof buf);
- }
- pkgconf_strlcat(buf, sourcebuf, sizeof buf);
+ if ((sourcebuf[0] != '/') && strcmp(targetdir, "."))
+ pkgconf_buffer_append_fmt(&buf, "%s/", targetdir);
+
+ pkgconf_buffer_append(&buf, sourcebuf);
}
#endif
- pathbuf = strrchr(buf, PKG_DIR_SEP_S);
- if (pathbuf == NULL)
- pathbuf = strrchr(buf, '/');
- if (pathbuf != NULL)
- pathbuf[0] = '\0';
+ pkgconf_buffer_finalize(&pathbuf);
+
+ if (pkgconf_buffer_len(&buf) > 0)
+ pkgconf_path_trim_basename(&buf);
- return strdup(buf);
+ return pkgconf_buffer_freeze(&buf);
}
-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 void (*pkgconf_pkg_parser_keyword_func_t)(pkgconf_client_t *client, pkgconf_pkg_t *pkg, const char *keyword, const char *warnprefix, const ptrdiff_t offset, const char *value);
typedef struct {
const char *keyword;
const pkgconf_pkg_parser_keyword_func_t func;
@@ -153,26 +147,77 @@ static int pkgconf_pkg_parser_keyword_pair_cmp(const void *key, const void *ptr)
}
static void
-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)
+pkgconf_pkg_parser_tuple_func(pkgconf_client_t *client, pkgconf_pkg_t *pkg, const char *keyword, const char *warnprefix, const ptrdiff_t offset, const char *value)
{
(void) keyword;
- (void) lineno;
+ (void) warnprefix;
char **dest = (char **)((char *) pkg + offset);
- *dest = pkgconf_tuple_parse(client, &pkg->vars, value, pkg->flags);
+
+ if (*dest != NULL)
+ free(*dest);
+
+ *dest = pkgconf_bytecode_eval_str(client, &pkg->vars, value, NULL);
}
static void
-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)
+pkgconf_pkg_parser_bufferset_func(pkgconf_client_t *client, pkgconf_pkg_t *pkg, const char *keyword, const char *warnprefix, const ptrdiff_t offset, const char *value)
+{
+ (void) keyword;
+ (void) warnprefix;
+
+ pkgconf_list_t *dest = (pkgconf_list_t *)((char *) pkg + offset);
+ pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER;
+
+ pkgconf_bytecode_eval_str_to_buf(client, &pkg->vars, value, NULL, &buf);
+ pkgconf_bufferset_extend(dest, &buf);
+ pkgconf_buffer_finalize(&buf);
+}
+
+/* parses a comma-separated list of ABI tags, lowercasing each, into a bufferset */
+static void
+pkgconf_pkg_parser_link_abi_func(pkgconf_client_t *client, pkgconf_pkg_t *pkg, const char *keyword, const char *warnprefix, const ptrdiff_t offset, const char *value)
+{
+ (void) keyword;
+ (void) warnprefix;
+
+ pkgconf_list_t *dest = (pkgconf_list_t *)((char *) pkg + offset);
+ char *expanded = pkgconf_bytecode_eval_str(client, &pkg->vars, value, NULL);
+
+ if (expanded == NULL)
+ return;
+
+ for (char *p = expanded; *p != '\0';)
+ {
+ pkgconf_buffer_t tag = PKGCONF_BUFFER_INITIALIZER;
+
+ while (*p == ',' || isspace((unsigned char) *p))
+ p++;
+
+ while (*p != '\0' && *p != ',' && !isspace((unsigned char) *p))
+ pkgconf_buffer_push_byte(&tag, (char) tolower((unsigned char) *p++));
+
+ if (pkgconf_buffer_len(&tag))
+ pkgconf_bufferset_extend(dest, &tag);
+
+ pkgconf_buffer_finalize(&tag);
+ }
+
+ free(expanded);
+}
+
+static void
+pkgconf_pkg_parser_version_func(pkgconf_client_t *client, pkgconf_pkg_t *pkg, const char *keyword, const char *warnprefix, const ptrdiff_t offset, const char *value)
{
(void) keyword;
- (void) lineno;
char *p, *i;
size_t len;
char **dest = (char **)((char *) pkg + offset);
/* cut at any detected whitespace */
- p = pkgconf_tuple_parse(client, &pkg->vars, value, pkg->flags);
+ p = pkgconf_bytecode_eval_str(client, &pkg->vars, value, NULL);
+ if (p == NULL)
+ return;
len = strcspn(p, " \t");
if (len != strlen(p))
@@ -180,88 +225,126 @@ pkgconf_pkg_parser_version_func(pkgconf_client_t *client, pkgconf_pkg_t *pkg, co
i = p + (ptrdiff_t) len;
*i = '\0';
- pkgconf_warn(client, "%s:" SIZE_FMT_SPECIFIER ": warning: malformed version field with whitespace, trimming to [%s]\n", pkg->filename,
- lineno, p);
+ pkgconf_warn(client, "%s: warning: malformed version field with whitespace, trimming to [%s]\n",
+ warnprefix, p);
}
+ if (*dest != NULL)
+ free(*dest);
+
*dest = p;
}
static void
-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_pkg_parser_fragment_func(pkgconf_client_t *client, pkgconf_pkg_t *pkg, const char *keyword, const char *warnprefix, const ptrdiff_t offset, const char *value)
{
pkgconf_list_t *dest = (pkgconf_list_t *)((char *) pkg + offset);
-
- /* we patch client-wide sysroot dir and then patch it back when it is overridden */
- char *sysroot_dir = client->sysroot_dir;
- char *pkg_sysroot_dir = pkgconf_tuple_find(client, &pkg->vars, "pc_sysrootdir");
- if (pkg_sysroot_dir != NULL)
- client->sysroot_dir = pkg_sysroot_dir;
-
bool ret = pkgconf_fragment_parse(client, dest, &pkg->vars, value, pkg->flags);
- client->sysroot_dir = sysroot_dir;
if (!ret)
{
- pkgconf_warn(client, "%s:" SIZE_FMT_SPECIFIER ": warning: unable to parse field '%s' into an argument vector, value [%s]\n", pkg->filename,
- lineno, keyword, value);
+ pkgconf_warn(client, "%s: warning: unable to parse field '%s' into an argument vector, value [%s]\n",
+ warnprefix, keyword, value);
}
}
static void
-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)
+pkgconf_pkg_parser_dependency_func(pkgconf_client_t *client, pkgconf_pkg_t *pkg, const char *keyword, const char *warnprefix, const ptrdiff_t offset, const char *value)
{
- (void) keyword;
- (void) lineno;
-
pkgconf_list_t *dest = (pkgconf_list_t *)((char *) pkg + offset);
+
+ if (dest->tail != NULL)
+ {
+ pkgconf_warn(client, "%s: warning: merging duplicate field '%s' (undefined behavior)\n",
+ warnprefix, keyword);
+ }
+
pkgconf_dependency_parse(client, pkg, dest, value, 0);
}
/* a variant of pkgconf_pkg_parser_dependency_func which colors the dependency node as an "internal" dependency. */
static void
-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)
+pkgconf_pkg_parser_internal_dependency_func(pkgconf_client_t *client, pkgconf_pkg_t *pkg, const char *keyword, const char *warnprefix, const ptrdiff_t offset, const char *value)
{
- (void) keyword;
- (void) lineno;
-
pkgconf_list_t *dest = (pkgconf_list_t *)((char *) pkg + offset);
+
+ if (dest->tail != NULL)
+ {
+ pkgconf_warn(client, "%s: warning: merging duplicate field '%s' (undefined behavior)\n",
+ warnprefix, keyword);
+ }
+
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)
+pkgconf_pkg_parser_private_dependency_func(pkgconf_client_t *client, pkgconf_pkg_t *pkg, const char *keyword, const char *warnprefix, const ptrdiff_t offset, const char *value)
{
- (void) keyword;
- (void) lineno;
-
pkgconf_list_t *dest = (pkgconf_list_t *)((char *) pkg + offset);
+
+ if (dest->tail != NULL)
+ {
+ pkgconf_warn(client, "%s: warning: merging duplicate field '%s' (undefined behavior)\n",
+ warnprefix, keyword);
+ }
+
pkgconf_dependency_parse(client, pkg, dest, value, PKGCONF_PKG_DEPF_PRIVATE);
}
+/* a variant of pkgconf_pkg_parser_dependency_func which colors the dependency node as a "shared" dependency. */
+static void
+pkgconf_pkg_parser_shared_dependency_func(pkgconf_client_t *client, pkgconf_pkg_t *pkg, const char *keyword, const char *warnprefix, const ptrdiff_t offset, const char *value)
+{
+ pkgconf_list_t *dest = (pkgconf_list_t *)((char *) pkg + offset);
+
+ if (dest->tail != NULL)
+ {
+ pkgconf_warn(client, "%s: warning: merging duplicate field '%s' (undefined behavior)\n",
+ warnprefix, keyword);
+ }
+
+ pkgconf_dependency_parse(client, pkg, dest, value, PKGCONF_PKG_DEPF_SHARED);
+}
+
+/* Evaluates SPDX expression or parses comma separated list of licenses */
+static void
+pkgconf_pkg_evaluate_license_func(pkgconf_client_t *client, pkgconf_pkg_t *pkg, const char *keyword, const char *warnprefix, const ptrdiff_t offset, const char *value)
+{
+ pkgconf_list_t *dest = (pkgconf_list_t *)((char *) pkg + offset);
+ (void)keyword;
+ (void)warnprefix;
+ pkgconf_license_evaluate(client, pkg, dest, value, 0);
+}
+
/* keep this in alphabetical order */
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.private", pkgconf_pkg_parser_fragment_func, offsetof(pkgconf_pkg_t, cflags_private)},
+ {"CFLAGS.shared", pkgconf_pkg_parser_fragment_func, offsetof(pkgconf_pkg_t, cflags_shared)},
{"Conflicts", pkgconf_pkg_parser_dependency_func, offsetof(pkgconf_pkg_t, conflicts)},
- {"Copyright", pkgconf_pkg_parser_tuple_func, offsetof(pkgconf_pkg_t, copyright)},
+ {"Copyright", pkgconf_pkg_parser_bufferset_func, offsetof(pkgconf_pkg_t, copyright)},
{"Description", pkgconf_pkg_parser_tuple_func, offsetof(pkgconf_pkg_t, description)},
{"LIBS", pkgconf_pkg_parser_fragment_func, offsetof(pkgconf_pkg_t, libs)},
{"LIBS.private", pkgconf_pkg_parser_fragment_func, offsetof(pkgconf_pkg_t, libs_private)},
- {"License", pkgconf_pkg_parser_tuple_func, offsetof(pkgconf_pkg_t, license)},
+ {"LIBS.shared", pkgconf_pkg_parser_fragment_func, offsetof(pkgconf_pkg_t, libs_shared)},
+ {"License", pkgconf_pkg_evaluate_license_func, offsetof(pkgconf_pkg_t, license)},
+ {"License.file", pkgconf_pkg_parser_tuple_func, offsetof(pkgconf_pkg_t, license_file)},
+ {"Link.ABI", pkgconf_pkg_parser_link_abi_func, offsetof(pkgconf_pkg_t, link_abi)},
{"Maintainer", pkgconf_pkg_parser_tuple_func, offsetof(pkgconf_pkg_t, maintainer)},
{"Name", pkgconf_pkg_parser_tuple_func, offsetof(pkgconf_pkg_t, realname)},
{"Provides", pkgconf_pkg_parser_dependency_func, offsetof(pkgconf_pkg_t, provides)},
{"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.private", pkgconf_pkg_parser_private_dependency_func, offsetof(pkgconf_pkg_t, requires_private)},
+ {"Requires.shared", pkgconf_pkg_parser_shared_dependency_func, offsetof(pkgconf_pkg_t, requires_shared)},
+ {"Source", pkgconf_pkg_parser_tuple_func, offsetof(pkgconf_pkg_t, source)},
{"URL", pkgconf_pkg_parser_tuple_func, offsetof(pkgconf_pkg_t, url)},
{"Version", pkgconf_pkg_parser_version_func, offsetof(pkgconf_pkg_t, version)},
};
static void
-pkgconf_pkg_parser_keyword_set(void *opaque, const size_t lineno, const char *keyword, const char *value)
+pkgconf_pkg_parser_keyword_set(void *opaque, const char *warnprefix, const char *keyword, const char *value)
{
pkgconf_pkg_t *pkg = opaque;
@@ -272,44 +355,27 @@ pkgconf_pkg_parser_keyword_set(void *opaque, const size_t lineno, const char *ke
if (pair == NULL || pair->func == NULL)
return;
- pair->func(pkg->owner, pkg, keyword, lineno, pair->offset, value);
+ pair->func(pkg->owner, pkg, keyword, warnprefix, pair->offset, value);
}
-static const char *
-determine_prefix(const pkgconf_pkg_t *pkg, char *buf, size_t buflen)
+static bool
+determine_prefix(const pkgconf_pkg_t *pkg, pkgconf_buffer_t *pathbuf)
{
- char *pathiter;
-
- pkgconf_strlcpy(buf, pkg->filename, buflen);
- pkgconf_path_relocate(buf, buflen);
+ pkgconf_buffer_append(pathbuf, pkg->filename);
+ pkgconf_path_relocate(pathbuf);
- pathiter = strrchr(buf, PKG_DIR_SEP_S);
- if (pathiter == NULL)
- pathiter = strrchr(buf, '/');
- if (pathiter != NULL)
- pathiter[0] = '\0';
+ pkgconf_path_trim_basename(pathbuf);
- pathiter = strrchr(buf, PKG_DIR_SEP_S);
- if (pathiter == NULL)
- pathiter = strrchr(buf, '/');
- if (pathiter == NULL)
- return NULL;
-
- /* parent dir is not pkgconfig, can't relocate then */
- if (strcmp(pathiter + 1, "pkgconfig"))
- return NULL;
+ if (strcmp(pkgconf_path_find_basename(pkgconf_buffer_str_or_empty(pathbuf)), "pkgconfig"))
+ return false;
- /* okay, work backwards and do it again. */
- pathiter[0] = '\0';
- pathiter = strrchr(buf, PKG_DIR_SEP_S);
- if (pathiter == NULL)
- pathiter = strrchr(buf, '/');
- if (pathiter == NULL)
- return NULL;
+ if (!pkgconf_path_trim_basename(pathbuf))
+ return false;
- pathiter[0] = '\0';
+ if (!pkgconf_path_trim_basename(pathbuf))
+ return false;
- return buf;
+ return true;
}
/*
@@ -325,25 +391,23 @@ determine_prefix(const pkgconf_pkg_t *pkg, char *buf, size_t buflen)
static char *
convert_path_to_value(const char *path)
{
- char *buf = calloc(1, (strlen(path) + 1) * 2);
- if (buf == NULL)
- return NULL;
-
- char *bptr = buf;
+ pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER;
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;
+ pkgconf_buffer_push_byte(&buf, '/');
+ else if (*i == ' ')
+ {
+ pkgconf_buffer_push_byte(&buf, '\\');
+ pkgconf_buffer_push_byte(&buf, ' ');
+ }
+ else
+ pkgconf_buffer_push_byte(&buf, *i);
}
- return buf;
+ return pkgconf_buffer_freeze(&buf);
}
static void
@@ -383,47 +447,102 @@ is_path_prefix_equal(const char *path1, const char *path2, size_t path2_len)
#endif
}
+static inline const char *
+lookup_val_from_env(const pkgconf_client_t *client, const char *pkg_id, const char *keyword)
+{
+ char env_var[PKGCONF_ITEM_SIZE];
+ char *c;
+
+ snprintf(env_var, sizeof env_var, "PKG_CONFIG_%s_%s", pkg_id, keyword);
+
+ for (c = env_var; *c; c++)
+ {
+ *c = (char) toupper((unsigned char) *c);
+
+ if (!isalnum((unsigned char) *c))
+ *c = '_';
+ }
+
+ return pkgconf_client_getenv(client, env_var);
+}
+
static void
-pkgconf_pkg_parser_value_set(void *opaque, const size_t lineno, const char *keyword, const char *value)
+pkgconf_pkg_parser_value_set(void *opaque, const char *warnprefix, const char *keyword, const char *value)
{
- char canonicalized_value[PKGCONF_ITEM_SIZE];
+ pkgconf_buffer_t canonicalized_value = PKGCONF_BUFFER_INITIALIZER;
pkgconf_pkg_t *pkg = opaque;
+ const char *env_content;
+
+ (void) warnprefix;
- (void) lineno;
+ env_content = lookup_val_from_env(pkg->owner, pkg->id, keyword);
+ if (env_content != NULL)
+ {
+ PKGCONF_TRACE(pkg->owner, "overriding %s from environment", keyword);
+ value = env_content;
+ }
+
+ if (!pkgconf_buffer_append(&canonicalized_value, value))
+ goto out;
- pkgconf_strlcpy(canonicalized_value, value, sizeof canonicalized_value);
- canonicalize_path(canonicalized_value);
+ canonicalize_path(canonicalized_value.base);
+
+ if (!(pkg->owner->flags & PKGCONF_PKG_PKGF_REDEFINE_PREFIX))
+ {
+ pkgconf_tuple_add(pkg->owner, &pkg->vars, keyword, value, true, pkg->flags);
+ goto out;
+ }
/* Some pc files will use absolute paths for all of their directories
* which is broken when redefining the prefix. We try to outsmart the
* file and rewrite any directory that starts with the same prefix.
*/
- if (pkg->owner->flags & PKGCONF_PKG_PKGF_REDEFINE_PREFIX && pkg->orig_prefix
- && is_path_prefix_equal(canonicalized_value, pkg->orig_prefix->value, strlen(pkg->orig_prefix->value)))
+ if (strcmp(keyword, pkg->owner->prefix_varname))
{
- char newvalue[PKGCONF_ITEM_SIZE];
+ if (pkgconf_buffer_len(&pkg->orig_prefix) != 0)
+ {
+ const char *op = pkgconf_buffer_str_or_empty(&pkg->orig_prefix);
+ const size_t oplen = pkgconf_buffer_len(&pkg->orig_prefix);
+
+ if (is_path_prefix_equal(pkgconf_buffer_str(&canonicalized_value), op, oplen))
+ {
+ pkgconf_buffer_t newvalue = PKGCONF_BUFFER_INITIALIZER;
+
+ pkgconf_buffer_append(&newvalue, pkgconf_buffer_str_or_empty(&pkg->calculated_prefix));
+ pkgconf_buffer_append(&newvalue, pkgconf_buffer_str(&canonicalized_value) + oplen);
+
+ pkgconf_tuple_add(pkg->owner, &pkg->vars, keyword, pkgconf_buffer_str(&newvalue), false, pkg->flags);
+ pkgconf_buffer_finalize(&newvalue);
+
+ goto out;
+ }
+ }
- pkgconf_strlcpy(newvalue, pkg->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, pkg->flags);
- }
- 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, pkg->flags);
+ }
else
{
- char pathbuf[PKGCONF_ITEM_SIZE];
- const char *relvalue = determine_prefix(pkg, pathbuf, sizeof pathbuf);
+ pkgconf_buffer_t pathbuf = PKGCONF_BUFFER_INITIALIZER;
- if (relvalue != NULL)
+ if (determine_prefix(pkg, &pathbuf))
{
+ const char *relvalue = pkgconf_buffer_str(&pathbuf);
char *prefix_value = convert_path_to_value(relvalue);
- 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);
+
+ pkgconf_buffer_append(&pkg->orig_prefix, pkgconf_buffer_str(&canonicalized_value));
+ pkgconf_buffer_append(&pkg->calculated_prefix, prefix_value);
+
+ pkgconf_tuple_add(pkg->owner, &pkg->vars, keyword, prefix_value, false, pkg->flags);
free(prefix_value);
}
else
pkgconf_tuple_add(pkg->owner, &pkg->vars, keyword, value, true, pkg->flags);
+
+ pkgconf_buffer_finalize(&pathbuf);
}
+
+out:
+ pkgconf_buffer_finalize(&canonicalized_value);
}
typedef struct {
@@ -442,11 +561,12 @@ static const pkgconf_parser_operand_func_t pkg_parser_funcs[256] = {
['='] = pkgconf_pkg_parser_value_set
};
-static void pkg_warn_func(pkgconf_pkg_t *pkg, const char *fmt, ...) PRINTFLIKE(2, 3);
+static void pkg_warn_func(void *pkg_p, const char *fmt, ...) PRINTFLIKE(2, 3);
static void
-pkg_warn_func(pkgconf_pkg_t *pkg, const char *fmt, ...)
+pkg_warn_func(void *pkg_p, const char *fmt, ...)
{
+ pkgconf_pkg_t *pkg = pkg_p;
char buf[PKGCONF_ITEM_SIZE];
va_list va;
@@ -504,33 +624,43 @@ pkg_free_object(pkgconf_pkg_t *pkg)
if (pkg->pc_filedir != NULL)
free(pkg->pc_filedir);
- if (pkg->license != NULL)
- free(pkg->license);
+ if (pkg->license_file != NULL)
+ free(pkg->license_file);
if (pkg->maintainer != NULL)
free(pkg->maintainer);
- if (pkg->copyright != NULL)
- free(pkg->copyright);
-
if (pkg->why != NULL)
free(pkg->why);
+ if (pkg->source != NULL)
+ free(pkg->source);
+
+ pkgconf_buffer_finalize(&pkg->orig_prefix);
+ pkgconf_buffer_finalize(&pkg->calculated_prefix);
+
free(pkg);
}
static void
pkg_free_lists(pkgconf_pkg_t *pkg)
{
+ pkgconf_bufferset_free(&pkg->copyright);
+ pkgconf_bufferset_free(&pkg->link_abi);
+
pkgconf_dependency_free(&pkg->required);
pkgconf_dependency_free(&pkg->requires_private);
+ pkgconf_dependency_free(&pkg->requires_shared);
pkgconf_dependency_free(&pkg->conflicts);
pkgconf_dependency_free(&pkg->provides);
pkgconf_fragment_free(&pkg->cflags);
pkgconf_fragment_free(&pkg->cflags_private);
+ pkgconf_fragment_free(&pkg->cflags_shared);
+ pkgconf_license_free(&pkg->license);
pkgconf_fragment_free(&pkg->libs);
pkgconf_fragment_free(&pkg->libs_private);
+ pkgconf_fragment_free(&pkg->libs_shared);
pkgconf_tuple_free(&pkg->vars);
}
@@ -560,7 +690,7 @@ pkgconf_pkg_new_from_path(pkgconf_client_t *client, const char *filename, unsign
if (!str_has_suffix(filename, PKG_CONFIG_EXT))
return NULL;
- f = fopen(filename, "r");
+ f = fopen(filename, "rb");
if (f == NULL)
return NULL;
@@ -598,26 +728,12 @@ pkgconf_pkg_new_from_path(pkgconf_client_t *client, const char *filename, unsign
* package.
* See https://github.com/pkgconf/pkgconf/issues/213
*/
- if (client->sysroot_dir && strncmp(pkg->pc_filedir, client->sysroot_dir, strlen(client->sysroot_dir)))
+ if (client->sysroot_dir != NULL && strncmp(pkg->pc_filedir, client->sysroot_dir, strlen(client->sysroot_dir)) &&
+ !(client->flags & PKGCONF_PKG_PKGF_PKGCONF1_SYSROOT_RULES))
pkgconf_tuple_add(client, &pkg->vars, "pc_sysrootdir", "", false, pkg->flags);
/* make module id */
- if ((idptr = strrchr(pkg->filename, PKG_DIR_SEP_S)) != NULL)
- idptr++;
- else
- 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(pkgconf_path_find_basename(pkg->filename));
if (pkg->id == NULL)
{
fclose(f);
@@ -637,7 +753,7 @@ pkgconf_pkg_new_from_path(pkgconf_client_t *client, const char *filename, unsign
*idptr = '\0';
}
- pkgconf_parser_parse(f, pkg, pkg_parser_funcs, (pkgconf_parser_warn_func_t) pkg_warn_func, pkg->filename);
+ pkgconf_parser_parse(f, pkg, pkg_parser_funcs, pkg_warn_func, pkg->filename);
fclose(f);
if (!pkgconf_pkg_validate(client, pkg))
@@ -647,7 +763,25 @@ pkgconf_pkg_new_from_path(pkgconf_client_t *client, const char *filename, unsign
return NULL;
}
+ /* a package that does not declare a Link.ABI defaults to the C ABI; a
+ * declared Link.ABI replaces this default rather than adding to it.
+ */
+ if (pkg->link_abi.head == NULL)
+ {
+ pkgconf_buffer_t abibuf = PKGCONF_BUFFER_INITIALIZER;
+
+ pkgconf_buffer_append(&abibuf, "c");
+ pkgconf_bufferset_extend(&pkg->link_abi, &abibuf);
+ pkgconf_buffer_finalize(&abibuf);
+ }
+
pkgconf_dependency_t *dep = pkgconf_dependency_add(client, &pkg->provides, pkg->id, pkg->version, PKGCONF_CMP_EQUAL, 0);
+ if (dep == NULL)
+ {
+ pkgconf_pkg_free(client, pkg);
+ return NULL;
+ }
+
pkgconf_dependency_unref(dep->owner, dep);
return pkgconf_pkg_ref(client, pkg);
@@ -775,19 +909,22 @@ pkgconf_pkg_scan_dir(pkgconf_client_t *client, const char *path, void *data, pkg
for (dirent = readdir(dir); dirent != NULL; dirent = readdir(dir))
{
- char filebuf[PKGCONF_ITEM_SIZE];
+ pkgconf_buffer_t filebuf = PKGCONF_BUFFER_INITIALIZER;
pkgconf_pkg_t *pkg;
- pkgconf_strlcpy(filebuf, path, sizeof filebuf);
- pkgconf_strlcat(filebuf, "/", sizeof filebuf);
- pkgconf_strlcat(filebuf, dirent->d_name, sizeof filebuf);
+ pkgconf_buffer_join(&filebuf, '/', path, dirent->d_name, NULL);
- if (!str_has_suffix(filebuf, PKG_CONFIG_EXT))
+ if (!str_has_suffix(pkgconf_buffer_str(&filebuf), PKG_CONFIG_EXT))
+ {
+ pkgconf_buffer_finalize(&filebuf);
continue;
+ }
+
+ PKGCONF_TRACE(client, "trying file [%s]", pkgconf_buffer_str(&filebuf));
- PKGCONF_TRACE(client, "trying file [%s]", filebuf);
+ pkg = pkgconf_pkg_new_from_path(client, pkgconf_buffer_str(&filebuf), 0);
+ pkgconf_buffer_finalize(&filebuf);
- pkg = pkgconf_pkg_new_from_path(client, filebuf, 0);
if (pkg != NULL)
{
if (func(pkg, data))
@@ -913,13 +1050,6 @@ pkgconf_pkg_find(pkgconf_client_t *client, const char *name)
}
}
- /* check builtins */
- if ((pkg = pkgconf_builtin_pkg_get(name)) != NULL)
- {
- PKGCONF_TRACE(client, "%s is a builtin", name);
- return pkg;
- }
-
/* check cache */
if (!(client->flags & PKGCONF_PKG_PKGF_NO_CACHE))
{
@@ -952,240 +1082,6 @@ out:
return pkg;
}
-/*
- * !doc
- *
- * .. c:function:: int pkgconf_compare_version(const char *a, const char *b)
- *
- * Compare versions using RPM version comparison rules as described in the LSB.
- *
- * :param char* a: The first version to compare in the pair.
- * :param char* b: The second version to compare in the pair.
- * :return: -1 if the first version is less than, 0 if both versions are equal, 1 if the second version is less than.
- * :rtype: int
- */
-int
-pkgconf_compare_version(const char *a, const char *b)
-{
- char oldch1, oldch2;
- char buf1[PKGCONF_ITEM_SIZE], buf2[PKGCONF_ITEM_SIZE];
- char *str1, *str2;
- char *one, *two;
- int ret;
- bool isnum;
-
- /* optimization: if version matches then it's the same version. */
- if (a == NULL)
- return -1;
-
- if (b == NULL)
- return 1;
-
- if (!strcasecmp(a, b))
- return 0;
-
- pkgconf_strlcpy(buf1, a, sizeof buf1);
- pkgconf_strlcpy(buf2, b, sizeof buf2);
-
- one = buf1;
- two = buf2;
-
- while (*one || *two)
- {
- while (*one && !isalnum((unsigned char)*one) && *one != '~')
- one++;
- while (*two && !isalnum((unsigned char)*two) && *two != '~')
- two++;
-
- if (*one == '~' || *two == '~')
- {
- if (*one != '~')
- return 1;
- if (*two != '~')
- return -1;
-
- one++;
- two++;
- continue;
- }
-
- if (!(*one && *two))
- break;
-
- str1 = one;
- str2 = two;
-
- if (isdigit((unsigned char)*str1))
- {
- while (*str1 && isdigit((unsigned char)*str1))
- str1++;
-
- while (*str2 && isdigit((unsigned char)*str2))
- str2++;
-
- isnum = true;
- }
- else
- {
- while (*str1 && isalpha((unsigned char)*str1))
- str1++;
-
- while (*str2 && isalpha((unsigned char)*str2))
- str2++;
-
- isnum = false;
- }
-
- oldch1 = *str1;
- oldch2 = *str2;
-
- *str1 = '\0';
- *str2 = '\0';
-
- if (one == str1)
- return -1;
-
- if (two == str2)
- return (isnum ? 1 : -1);
-
- if (isnum)
- {
- int onelen, twolen;
-
- while (*one == '0')
- one++;
-
- while (*two == '0')
- two++;
-
- onelen = strlen(one);
- twolen = strlen(two);
-
- if (onelen > twolen)
- return 1;
- else if (twolen > onelen)
- return -1;
- }
-
- ret = strcmp(one, two);
- if (ret != 0)
- return ret < 0 ? -1 : 1;
-
- *str1 = oldch1;
- *str2 = oldch2;
-
- one = str1;
- two = str2;
- }
-
- if ((!*one) && (!*two))
- return 0;
-
- if (!*one)
- return -1;
-
- return 1;
-}
-
-static pkgconf_pkg_t pkg_config_virtual = {
- .id = "pkg-config",
- .realname = "pkg-config",
- .description = "virtual package defining pkg-config API version supported",
- .url = PACKAGE_BUGREPORT,
- .version = PACKAGE_VERSION,
- .flags = PKGCONF_PKG_PROPF_STATIC,
- .vars = {
- .head = &(pkgconf_node_t){
- .next = &(pkgconf_node_t){
- .next = &(pkgconf_node_t){
- .data = &(pkgconf_tuple_t){
- .key = "pc_system_libdirs",
- .value = SYSTEM_LIBDIR,
- }
- },
- .data = &(pkgconf_tuple_t){
- .key = "pc_system_includedirs",
- .value = SYSTEM_INCLUDEDIR,
- }
- },
- .data = &(pkgconf_tuple_t){
- .key = "pc_path",
- .value = PKG_DEFAULT_PATH,
- },
- },
- .tail = NULL,
- }
-};
-
-static pkgconf_pkg_t pkgconf_virtual = {
- .id = "pkgconf",
- .realname = "pkgconf",
- .description = "virtual package defining pkgconf API version supported",
- .url = PACKAGE_BUGREPORT,
- .version = PACKAGE_VERSION,
- .license = "ISC",
- .flags = PKGCONF_PKG_PROPF_STATIC,
- .vars = {
- .head = &(pkgconf_node_t){
- .next = &(pkgconf_node_t){
- .next = &(pkgconf_node_t){
- .data = &(pkgconf_tuple_t){
- .key = "pc_system_libdirs",
- .value = SYSTEM_LIBDIR,
- }
- },
- .data = &(pkgconf_tuple_t){
- .key = "pc_system_includedirs",
- .value = SYSTEM_INCLUDEDIR,
- }
- },
- .data = &(pkgconf_tuple_t){
- .key = "pc_path",
- .value = PKG_DEFAULT_PATH,
- },
- },
- .tail = NULL,
- },
-};
-
-typedef struct {
- const char *name;
- pkgconf_pkg_t *pkg;
-} pkgconf_builtin_pkg_pair_t;
-
-/* keep these in alphabetical order */
-static const pkgconf_builtin_pkg_pair_t pkgconf_builtin_pkg_pair_set[] = {
- {"pkg-config", &pkg_config_virtual},
- {"pkgconf", &pkgconf_virtual},
-};
-
-static int pkgconf_builtin_pkg_pair_cmp(const void *key, const void *ptr)
-{
- const pkgconf_builtin_pkg_pair_t *pair = ptr;
- return strcasecmp(key, pair->name);
-}
-
-/*
- * !doc
- *
- * .. c:function:: pkgconf_pkg_t *pkgconf_builtin_pkg_get(const char *name)
- *
- * Looks up a built-in package. The package should not be freed or dereferenced.
- *
- * :param char* name: An atom corresponding to a built-in package to search for.
- * :return: the built-in package if present, else ``NULL``.
- * :rtype: pkgconf_pkg_t *
- */
-pkgconf_pkg_t *
-pkgconf_builtin_pkg_get(const char *name)
-{
- const pkgconf_builtin_pkg_pair_t *pair = bsearch(name, pkgconf_builtin_pkg_pair_set,
- PKGCONF_ARRAY_SIZE(pkgconf_builtin_pkg_pair_set), sizeof(pkgconf_builtin_pkg_pair_t),
- pkgconf_builtin_pkg_pair_cmp);
-
- return (pair != NULL) ? pair->pkg : NULL;
-}
-
typedef bool (*pkgconf_vercmp_res_func_t)(const char *a, const char *b);
typedef struct {
@@ -1300,6 +1196,9 @@ pkgconf_pkg_get_comparator(const pkgconf_dependency_t *pkgdep)
pkgconf_pkg_comparator_t
pkgconf_pkg_comparator_lookup_by_name(const char *name)
{
+ if (name == NULL)
+ return PKGCONF_CMP_ANY;
+
const pkgconf_pkg_comparator_pair_t *p = bsearch(name, pkgconf_pkg_comparator_names,
PKGCONF_ARRAY_SIZE(pkgconf_pkg_comparator_names), sizeof(pkgconf_pkg_comparator_pair_t),
pkgconf_pkg_comparator_pair_namecmp);
@@ -1320,10 +1219,10 @@ static const pkgconf_pkg_provides_vermatch_rule_t pkgconf_pkg_provides_vermatch_
[PKGCONF_CMP_ANY] = {
.rulecmp = {
[PKGCONF_CMP_ANY] = pkgconf_pkg_comparator_none,
- },
+ },
.depcmp = {
[PKGCONF_CMP_ANY] = pkgconf_pkg_comparator_none,
- },
+ },
},
[PKGCONF_CMP_LESS_THAN] = {
.rulecmp = {
@@ -1397,7 +1296,7 @@ static const pkgconf_pkg_provides_vermatch_rule_t pkgconf_pkg_provides_vermatch_
},
.depcmp = {
[PKGCONF_CMP_ANY] = pkgconf_pkg_comparator_none,
- },
+ },
},
[PKGCONF_CMP_NOT_EQUAL] = {
.rulecmp = {
@@ -1411,7 +1310,7 @@ static const pkgconf_pkg_provides_vermatch_rule_t pkgconf_pkg_provides_vermatch_
},
.depcmp = {
[PKGCONF_CMP_ANY] = pkgconf_pkg_comparator_none,
- },
+ },
},
};
@@ -1428,11 +1327,11 @@ pkgconf_pkg_scan_provides_vercmp(const pkgconf_dependency_t *pkgdep, const pkgco
const pkgconf_pkg_provides_vermatch_rule_t *rule = &pkgconf_pkg_provides_vermatch_rules[pkgdep->compare];
if (rule->depcmp[provider->compare] != NULL &&
- !rule->depcmp[provider->compare](provider->version, pkgdep->version))
+ !rule->depcmp[provider->compare](provider->version, pkgdep->version))
return false;
if (rule->rulecmp[provider->compare] != NULL &&
- !rule->rulecmp[provider->compare](pkgdep->version, provider->version))
+ !rule->rulecmp[provider->compare](pkgdep->version, provider->version))
return false;
return true;
@@ -1444,8 +1343,9 @@ pkgconf_pkg_scan_provides_vercmp(const pkgconf_dependency_t *pkgdep, const pkgco
* attempt to match a single package's Provides rules against the requested dependency node.
*/
static bool
-pkgconf_pkg_scan_provides_entry(const pkgconf_pkg_t *pkg, const pkgconf_pkg_scan_providers_ctx_t *ctx)
+pkgconf_pkg_scan_provides_entry(const pkgconf_pkg_t *pkg, void *data)
{
+ const pkgconf_pkg_scan_providers_ctx_t *ctx = data;
const pkgconf_dependency_t *pkgdep = ctx->pkgdep;
pkgconf_node_t *node;
@@ -1472,7 +1372,7 @@ pkgconf_pkg_scan_providers(pkgconf_client_t *client, pkgconf_dependency_t *pkgde
.pkgdep = pkgdep,
};
- pkg = pkgconf_scan_all(client, &ctx, (pkgconf_pkg_iteration_func_t) pkgconf_pkg_scan_provides_entry);
+ pkg = pkgconf_scan_all(client, &ctx, pkgconf_pkg_scan_provides_entry);
if (pkg != NULL)
{
pkgdep->match = pkgconf_pkg_ref(client, pkg);
@@ -1573,7 +1473,7 @@ pkgconf_pkg_report_graph_error(pkgconf_client_t *client, pkgconf_pkg_t *parent,
{
if (eflags & PKGCONF_PKG_ERRF_PACKAGE_NOT_FOUND)
{
- if (!(client->flags & PKGCONF_PKG_PKGF_SIMPLIFY_ERRORS) & !client->already_sent_notice)
+ if (!(client->flags & PKGCONF_PKG_PKGF_SIMPLIFY_ERRORS) && !client->already_sent_notice)
{
pkgconf_error(client, "Package %s was not found in the pkg-config search path.\n", node->package);
pkgconf_error(client, "Perhaps you should add the directory containing `%s.pc'\n", node->package);
@@ -1604,6 +1504,18 @@ pkgconf_pkg_report_graph_error(pkgconf_client_t *client, pkgconf_pkg_t *parent,
return eflags;
}
+static inline bool
+missing_node_is_tolerable(const pkgconf_client_t *client, const pkgconf_dependency_t *dep)
+{
+ if (!(dep->flags & PKGCONF_PKG_DEPF_INTERNAL))
+ return false;
+
+ if ((client->flags & PKGCONF_PKG_PKGF_REQUIRE_INTERNAL))
+ return false;
+
+ return true;
+}
+
static inline unsigned int
pkgconf_pkg_walk_list(pkgconf_client_t *client,
pkgconf_pkg_t *parent,
@@ -1628,15 +1540,17 @@ pkgconf_pkg_walk_list(pkgconf_client_t *client,
continue;
pkgdep = pkgconf_pkg_verify_dependency(client, depnode, &eflags_local);
-
- eflags |= eflags_local;
- if (eflags_local != PKGCONF_PKG_ERRF_OK && !(client->flags & PKGCONF_PKG_PKGF_SKIP_ERRORS))
+ if (eflags_local != PKGCONF_PKG_ERRF_OK)
{
- pkgconf_pkg_report_graph_error(client, parent, pkgdep, depnode, eflags_local);
+ if (missing_node_is_tolerable(client, depnode))
+ continue;
+
+ if (!(client->flags & PKGCONF_PKG_PKGF_SKIP_ERRORS))
+ pkgconf_pkg_report_graph_error(client, parent, pkgdep, depnode, eflags_local);
+
+ eflags |= eflags_local;
continue;
}
- if (pkgdep == NULL)
- continue;
if((pkgdep->flags & PKGCONF_PKG_PROPF_ANCESTOR) != 0)
{
@@ -1650,10 +1564,11 @@ pkgconf_pkg_walk_list(pkgconf_client_t *client,
* 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))
+ !(depnode->flags & PKGCONF_PKG_DEPF_SHARED) &&
+ !(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);
+ parent->id, parent->id, pkgdep->id, parent->id);
pkgconf_node_delete(node, deplist);
pkgconf_dependency_unref(client, depnode);
@@ -1677,7 +1592,7 @@ next:
return eflags;
}
-static inline unsigned int
+unsigned int
pkgconf_pkg_walk_conflicts_list(pkgconf_client_t *client,
pkgconf_pkg_t *root, pkgconf_list_t *deplist)
{
@@ -1703,7 +1618,7 @@ pkgconf_pkg_walk_conflicts_list(pkgconf_client_t *client,
if (eflags == PKGCONF_PKG_ERRF_OK)
{
pkgconf_error(client, "Version '%s' of '%s' conflicts with '%s' due to satisfying conflict rule '%s %s%s%s'.\n",
- pkgdep->version, pkgdep->realname, root->realname, parentnode->package, pkgconf_pkg_get_comparator(parentnode),
+ pkgdep->version, pkgdep->id, parentnode->why, parentnode->package, pkgconf_pkg_get_comparator(parentnode),
parentnode->version != NULL ? " " : "", parentnode->version != NULL ? parentnode->version : "");
if (!(client->flags & PKGCONF_PKG_PKGF_SIMPLIFY_ERRORS))
@@ -1727,7 +1642,7 @@ pkgconf_pkg_walk_conflicts_list(pkgconf_client_t *client,
/*
* !doc
*
- * .. 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)
+ * .. c:function:: 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)
*
* Walk and resolve the dependency graph up to `maxdepth` levels.
*
@@ -1785,6 +1700,15 @@ pkgconf_pkg_traverse_main(pkgconf_client_t *client,
if (eflags != PKGCONF_PKG_ERRF_OK)
return eflags;
+ if (!(client->flags & PKGCONF_PKG_PKGF_MERGE_PRIVATE_FRAGMENTS))
+ {
+ PKGCONF_TRACE(client, "%s: walking 'Requires.shared' list", root->id);
+
+ eflags = pkgconf_pkg_walk_list(client, root, &root->requires_shared, func, data, maxdepth, skip_flags);
+ if (eflags != PKGCONF_PKG_ERRF_OK)
+ return eflags;
+ }
+
PKGCONF_TRACE(client, "%s: walking 'Requires.private' list", root->id);
/* XXX: ugly */
@@ -1810,7 +1734,13 @@ pkgconf_pkg_traverse(pkgconf_client_t *client,
client->serial++;
if ((client->flags & PKGCONF_PKG_PKGF_SEARCH_PRIVATE) == 0)
+ {
skip_flags |= PKGCONF_PKG_DEPF_PRIVATE;
+ }
+
+ if (client->flags & PKGCONF_PKG_PKGF_MERGE_PRIVATE_FRAGMENTS)
+ // Skip shared deps in static mode
+ skip_flags |= PKGCONF_PKG_DEPF_SHARED;
return pkgconf_pkg_traverse_main(client, root, func, data, maxdepth, skip_flags);
}
@@ -1841,6 +1771,19 @@ pkgconf_pkg_cflags_private_collect(pkgconf_client_t *client, pkgconf_pkg_t *pkg,
}
}
+static void
+pkgconf_pkg_cflags_shared_collect(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data)
+{
+ pkgconf_list_t *list = data;
+ pkgconf_node_t *node;
+
+ PKGCONF_FOREACH_LIST_ENTRY(pkg->cflags_shared.head, node)
+ {
+ pkgconf_fragment_t *frag = node->data;
+ pkgconf_fragment_copy(client, list, frag, true);
+ }
+}
+
/*
* !doc
*
@@ -1864,8 +1807,17 @@ pkgconf_pkg_cflags(pkgconf_client_t *client, pkgconf_pkg_t *root, pkgconf_list_t
eflag = pkgconf_pkg_traverse(client, root, pkgconf_pkg_cflags_collect, &frags, maxdepth, skip_flags);
- if (eflag == PKGCONF_PKG_ERRF_OK && client->flags & PKGCONF_PKG_PKGF_MERGE_PRIVATE_FRAGMENTS)
- eflag = pkgconf_pkg_traverse(client, root, pkgconf_pkg_cflags_private_collect, &frags, maxdepth, skip_flags);
+ if (eflag == PKGCONF_PKG_ERRF_OK)
+ {
+ if (client->flags & PKGCONF_PKG_PKGF_MERGE_PRIVATE_FRAGMENTS)
+ {
+ eflag = pkgconf_pkg_traverse(client, root, pkgconf_pkg_cflags_private_collect, &frags, maxdepth, skip_flags);
+ }
+ else
+ {
+ eflag = pkgconf_pkg_traverse(client, root, pkgconf_pkg_cflags_shared_collect, &frags, maxdepth, skip_flags);
+ }
+ }
if (eflag != PKGCONF_PKG_ERRF_OK)
{
@@ -1902,6 +1854,14 @@ pkgconf_pkg_libs_collect(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *dat
pkgconf_fragment_copy(client, list, frag, true);
}
}
+ else
+ {
+ PKGCONF_FOREACH_LIST_ENTRY(pkg->libs_shared.head, node)
+ {
+ pkgconf_fragment_t *frag = node->data;
+ pkgconf_fragment_copy(client, list, frag, true);
+ }
+ }
}
/*
@@ -1933,3 +1893,71 @@ pkgconf_pkg_libs(pkgconf_client_t *client, pkgconf_pkg_t *root, pkgconf_list_t *
return eflag;
}
+
+static void
+pkgconf_pkg_link_abi_collect(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data)
+{
+ pkgconf_list_t *list = data;
+ pkgconf_node_t *node;
+
+ if (!(client->flags & PKGCONF_PKG_PKGF_SEARCH_PRIVATE) && pkg->flags & PKGCONF_PKG_PROPF_VISITED_PRIVATE)
+ return;
+
+ PKGCONF_FOREACH_LIST_ENTRY(pkg->link_abi.head, node)
+ {
+ pkgconf_bufferset_t *tag = node->data;
+ pkgconf_node_t *iter;
+ bool seen = false;
+
+ PKGCONF_FOREACH_LIST_ENTRY(list->head, iter)
+ {
+ pkgconf_bufferset_t *existing = iter->data;
+
+ if (pkgconf_buffer_match(&existing->buffer, &tag->buffer))
+ {
+ seen = true;
+ break;
+ }
+ }
+
+ if (!seen)
+ pkgconf_bufferset_extend(list, &tag->buffer);
+ }
+}
+
+/*
+ * !doc
+ *
+ * .. c:function:: int pkgconf_pkg_link_abi(pkgconf_client_t *client, pkgconf_pkg_t *root, pkgconf_list_t *list, int maxdepth)
+ *
+ * Walks a dependency graph and collects the union of ``Link.ABI`` tags.
+ *
+ * The tags describe the ABI a consumer must link the module against. They
+ * are gathered over the same closure as ``LIBS``: the module's own tags and
+ * those of its public ``Requires`` always contribute, while ``Requires.private``
+ * tags contribute only when private dependencies are being linked (i.e. a
+ * static link). Unlike a runtime library load, ABI compatibility of the
+ * exposed interface applies equally to shared and static linking.
+ *
+ * :param pkgconf_client_t* client: The pkgconf client object to use for dependency resolution.
+ * :param pkgconf_pkg_t* root: The root of the dependency graph.
+ * :param pkgconf_list_t* list: The bufferset list to add the collected ``Link.ABI`` tags to.
+ * :param int maxdepth: The maximum allowed depth for dependency resolution. -1 means infinite recursion.
+ * :return: ``PKGCONF_PKG_ERRF_OK`` if successful, otherwise an error code.
+ * :rtype: unsigned int
+ */
+unsigned int
+pkgconf_pkg_link_abi(pkgconf_client_t *client, pkgconf_pkg_t *root, pkgconf_list_t *list, int maxdepth)
+{
+ unsigned int eflag;
+
+ eflag = pkgconf_pkg_traverse(client, root, pkgconf_pkg_link_abi_collect, list, maxdepth, 0);
+
+ if (eflag != PKGCONF_PKG_ERRF_OK)
+ {
+ pkgconf_bufferset_free(list);
+ return eflag;
+ }
+
+ return eflag;
+}