1 /* 2 * pkg.c 3 * higher-level dependency graph compilation, management and manipulation 4 * 5 * SPDX-License-Identifier: pkgconf 6 * 7 * Copyright (c) 2011, 2012, 2013 pkgconf authors (see AUTHORS). 8 * 9 * Permission to use, copy, modify, and/or distribute this software for any 10 * purpose with or without fee is hereby granted, provided that the above 11 * copyright notice and this permission notice appear in all copies. 12 * 13 * This software is provided 'as is' and without any warranty, express or 14 * implied. In no event shall the authors be liable for any damages arising 15 * from the use of this software. 16 */ 17 18 #include <libpkgconf/config.h> 19 #include <libpkgconf/stdinc.h> 20 #include <libpkgconf/libpkgconf.h> 21 #include <libpkgconf/path.h> 22 23 /* 24 * !doc 25 * 26 * libpkgconf `pkg` module 27 * ======================= 28 * 29 * The `pkg` module provides dependency resolution services and the overall `.pc` file parsing 30 * routines. 31 */ 32 33 #define PKG_CONFIG_EXT ".pc" 34 35 static unsigned int 36 pkgconf_pkg_traverse_main(pkgconf_client_t *client, 37 pkgconf_pkg_t *root, 38 pkgconf_pkg_traverse_func_t func, 39 void *data, 40 int maxdepth, 41 unsigned int skip_flags); 42 43 static inline bool 44 str_has_suffix(const char *str, const char *suffix) 45 { 46 if (str == NULL || suffix == NULL) 47 return false; 48 49 size_t str_len = strlen(str); 50 size_t suf_len = strlen(suffix); 51 52 if (str_len < suf_len) 53 return false; 54 55 return !strncasecmp(str + str_len - suf_len, suffix, suf_len); 56 } 57 58 static char * 59 pkg_get_parent_dir(pkgconf_pkg_t *pkg) 60 { 61 pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER; 62 pkgconf_buffer_t pathbuf = PKGCONF_BUFFER_INITIALIZER; 63 64 pkgconf_buffer_append(&buf, pkg->filename); 65 66 #ifndef _WIN32 67 struct stat path_stat; 68 69 while (buf.base != NULL && 70 !lstat(buf.base, &path_stat) && 71 S_ISLNK(path_stat.st_mode)) 72 { 73 char sourcebuf[PKGCONF_ITEM_SIZE]; 74 char *targetfilename, *targetdir; 75 76 pkgconf_buffer_reset(&pathbuf); 77 pkgconf_buffer_append(&pathbuf, buf.base); 78 79 targetfilename = strrchr(pathbuf.base, '/'); 80 if (targetfilename != NULL) 81 { 82 *targetfilename++ = '\0'; 83 targetdir = pathbuf.base; 84 85 if (*targetdir == '\0') 86 targetdir = "/"; 87 } 88 else 89 { 90 targetfilename = pathbuf.base; 91 targetdir = "."; 92 } 93 94 #ifdef HAVE_DECL_READLINKAT 95 const int dirfd = open(targetdir, O_DIRECTORY); 96 if (dirfd == -1) 97 break; 98 99 ssize_t len = readlinkat(dirfd, targetfilename, sourcebuf, sizeof(sourcebuf) - 1); 100 close(dirfd); 101 #else 102 ssize_t len = readlink(buf.base, sourcebuf, sizeof(sourcebuf) - 1); 103 #endif 104 105 if (len == -1) 106 break; 107 sourcebuf[len] = '\0'; 108 109 pkgconf_buffer_reset(&buf); 110 111 /* 112 * The logic here can be a bit tricky, so here's a table: 113 * 114 * <source> | <target> | result 115 * ----------------------------------------------------------------------- 116 * /bar (absolute) | foo/link (relative) | /bar (absolute) 117 * ../bar (relative) | foo/link (relative) | foo/../bar (relative) 118 * /bar (absolute) | /foo/link (absolute) | /bar (absolute) 119 * ../bar (relative) | /foo/link (absolute) | /foo/../bar (relative) 120 */ 121 if ((sourcebuf[0] != '/') && strcmp(targetdir, ".")) 122 pkgconf_buffer_append_fmt(&buf, "%s/", targetdir); 123 124 pkgconf_buffer_append(&buf, sourcebuf); 125 } 126 #endif 127 128 pkgconf_buffer_finalize(&pathbuf); 129 130 if (pkgconf_buffer_len(&buf) > 0) 131 pkgconf_path_trim_basename(&buf); 132 133 return pkgconf_buffer_freeze(&buf); 134 } 135 136 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); 137 typedef struct { 138 const char *keyword; 139 const pkgconf_pkg_parser_keyword_func_t func; 140 const ptrdiff_t offset; 141 } pkgconf_pkg_parser_keyword_pair_t; 142 143 static int pkgconf_pkg_parser_keyword_pair_cmp(const void *key, const void *ptr) 144 { 145 const pkgconf_pkg_parser_keyword_pair_t *pair = ptr; 146 return strcasecmp(key, pair->keyword); 147 } 148 149 static void 150 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) 151 { 152 (void) keyword; 153 (void) warnprefix; 154 155 char **dest = (char **)((char *) pkg + offset); 156 157 if (*dest != NULL) 158 free(*dest); 159 160 *dest = pkgconf_bytecode_eval_str(client, &pkg->vars, value, NULL); 161 } 162 163 static void 164 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) 165 { 166 (void) keyword; 167 (void) warnprefix; 168 169 pkgconf_list_t *dest = (pkgconf_list_t *)((char *) pkg + offset); 170 pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER; 171 172 pkgconf_bytecode_eval_str_to_buf(client, &pkg->vars, value, NULL, &buf); 173 pkgconf_bufferset_extend(dest, &buf); 174 pkgconf_buffer_finalize(&buf); 175 } 176 177 /* parses a comma-separated list of ABI tags, lowercasing each, into a bufferset */ 178 static void 179 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) 180 { 181 (void) keyword; 182 (void) warnprefix; 183 184 pkgconf_list_t *dest = (pkgconf_list_t *)((char *) pkg + offset); 185 char *expanded = pkgconf_bytecode_eval_str(client, &pkg->vars, value, NULL); 186 187 if (expanded == NULL) 188 return; 189 190 for (char *p = expanded; *p != '\0';) 191 { 192 pkgconf_buffer_t tag = PKGCONF_BUFFER_INITIALIZER; 193 194 while (*p == ',' || isspace((unsigned char) *p)) 195 p++; 196 197 while (*p != '\0' && *p != ',' && !isspace((unsigned char) *p)) 198 pkgconf_buffer_push_byte(&tag, (char) tolower((unsigned char) *p++)); 199 200 if (pkgconf_buffer_len(&tag)) 201 pkgconf_bufferset_extend(dest, &tag); 202 203 pkgconf_buffer_finalize(&tag); 204 } 205 206 free(expanded); 207 } 208 209 static void 210 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) 211 { 212 (void) keyword; 213 char *p, *i; 214 size_t len; 215 char **dest = (char **)((char *) pkg + offset); 216 217 /* cut at any detected whitespace */ 218 p = pkgconf_bytecode_eval_str(client, &pkg->vars, value, NULL); 219 if (p == NULL) 220 return; 221 222 len = strcspn(p, " \t"); 223 if (len != strlen(p)) 224 { 225 i = p + (ptrdiff_t) len; 226 *i = '\0'; 227 228 pkgconf_warn(client, "%s: warning: malformed version field with whitespace, trimming to [%s]\n", 229 warnprefix, p); 230 } 231 232 if (*dest != NULL) 233 free(*dest); 234 235 *dest = p; 236 } 237 238 static void 239 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) 240 { 241 pkgconf_list_t *dest = (pkgconf_list_t *)((char *) pkg + offset); 242 bool ret = pkgconf_fragment_parse(client, dest, &pkg->vars, value, pkg->flags); 243 244 if (!ret) 245 { 246 pkgconf_warn(client, "%s: warning: unable to parse field '%s' into an argument vector, value [%s]\n", 247 warnprefix, keyword, value); 248 } 249 } 250 251 static void 252 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) 253 { 254 pkgconf_list_t *dest = (pkgconf_list_t *)((char *) pkg + offset); 255 256 if (dest->tail != NULL) 257 { 258 pkgconf_warn(client, "%s: warning: merging duplicate field '%s' (undefined behavior)\n", 259 warnprefix, keyword); 260 } 261 262 pkgconf_dependency_parse(client, pkg, dest, value, 0); 263 } 264 265 /* a variant of pkgconf_pkg_parser_dependency_func which colors the dependency node as an "internal" dependency. */ 266 static void 267 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) 268 { 269 pkgconf_list_t *dest = (pkgconf_list_t *)((char *) pkg + offset); 270 271 if (dest->tail != NULL) 272 { 273 pkgconf_warn(client, "%s: warning: merging duplicate field '%s' (undefined behavior)\n", 274 warnprefix, keyword); 275 } 276 277 pkgconf_dependency_parse(client, pkg, dest, value, PKGCONF_PKG_DEPF_INTERNAL); 278 } 279 280 /* a variant of pkgconf_pkg_parser_dependency_func which colors the dependency node as a "private" dependency. */ 281 static void 282 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) 283 { 284 pkgconf_list_t *dest = (pkgconf_list_t *)((char *) pkg + offset); 285 286 if (dest->tail != NULL) 287 { 288 pkgconf_warn(client, "%s: warning: merging duplicate field '%s' (undefined behavior)\n", 289 warnprefix, keyword); 290 } 291 292 pkgconf_dependency_parse(client, pkg, dest, value, PKGCONF_PKG_DEPF_PRIVATE); 293 } 294 295 /* a variant of pkgconf_pkg_parser_dependency_func which colors the dependency node as a "shared" dependency. */ 296 static void 297 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) 298 { 299 pkgconf_list_t *dest = (pkgconf_list_t *)((char *) pkg + offset); 300 301 if (dest->tail != NULL) 302 { 303 pkgconf_warn(client, "%s: warning: merging duplicate field '%s' (undefined behavior)\n", 304 warnprefix, keyword); 305 } 306 307 pkgconf_dependency_parse(client, pkg, dest, value, PKGCONF_PKG_DEPF_SHARED); 308 } 309 310 /* Evaluates SPDX expression or parses comma separated list of licenses */ 311 static void 312 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) 313 { 314 pkgconf_list_t *dest = (pkgconf_list_t *)((char *) pkg + offset); 315 (void)keyword; 316 (void)warnprefix; 317 pkgconf_license_evaluate(client, pkg, dest, value, 0); 318 } 319 320 /* keep this in alphabetical order */ 321 static const pkgconf_pkg_parser_keyword_pair_t pkgconf_pkg_parser_keyword_funcs[] = { 322 {"CFLAGS", pkgconf_pkg_parser_fragment_func, offsetof(pkgconf_pkg_t, cflags)}, 323 {"CFLAGS.private", pkgconf_pkg_parser_fragment_func, offsetof(pkgconf_pkg_t, cflags_private)}, 324 {"CFLAGS.shared", pkgconf_pkg_parser_fragment_func, offsetof(pkgconf_pkg_t, cflags_shared)}, 325 {"Conflicts", pkgconf_pkg_parser_dependency_func, offsetof(pkgconf_pkg_t, conflicts)}, 326 {"Copyright", pkgconf_pkg_parser_bufferset_func, offsetof(pkgconf_pkg_t, copyright)}, 327 {"Description", pkgconf_pkg_parser_tuple_func, offsetof(pkgconf_pkg_t, description)}, 328 {"LIBS", pkgconf_pkg_parser_fragment_func, offsetof(pkgconf_pkg_t, libs)}, 329 {"LIBS.private", pkgconf_pkg_parser_fragment_func, offsetof(pkgconf_pkg_t, libs_private)}, 330 {"LIBS.shared", pkgconf_pkg_parser_fragment_func, offsetof(pkgconf_pkg_t, libs_shared)}, 331 {"License", pkgconf_pkg_evaluate_license_func, offsetof(pkgconf_pkg_t, license)}, 332 {"License.file", pkgconf_pkg_parser_tuple_func, offsetof(pkgconf_pkg_t, license_file)}, 333 {"Link.ABI", pkgconf_pkg_parser_link_abi_func, offsetof(pkgconf_pkg_t, link_abi)}, 334 {"Maintainer", pkgconf_pkg_parser_tuple_func, offsetof(pkgconf_pkg_t, maintainer)}, 335 {"Name", pkgconf_pkg_parser_tuple_func, offsetof(pkgconf_pkg_t, realname)}, 336 {"Provides", pkgconf_pkg_parser_dependency_func, offsetof(pkgconf_pkg_t, provides)}, 337 {"Requires", pkgconf_pkg_parser_dependency_func, offsetof(pkgconf_pkg_t, required)}, 338 {"Requires.internal", pkgconf_pkg_parser_internal_dependency_func, offsetof(pkgconf_pkg_t, requires_private)}, 339 {"Requires.private", pkgconf_pkg_parser_private_dependency_func, offsetof(pkgconf_pkg_t, requires_private)}, 340 {"Requires.shared", pkgconf_pkg_parser_shared_dependency_func, offsetof(pkgconf_pkg_t, requires_shared)}, 341 {"Source", pkgconf_pkg_parser_tuple_func, offsetof(pkgconf_pkg_t, source)}, 342 {"URL", pkgconf_pkg_parser_tuple_func, offsetof(pkgconf_pkg_t, url)}, 343 {"Version", pkgconf_pkg_parser_version_func, offsetof(pkgconf_pkg_t, version)}, 344 }; 345 346 static void 347 pkgconf_pkg_parser_keyword_set(void *opaque, const char *warnprefix, const char *keyword, const char *value) 348 { 349 pkgconf_pkg_t *pkg = opaque; 350 351 const pkgconf_pkg_parser_keyword_pair_t *pair = bsearch(keyword, 352 pkgconf_pkg_parser_keyword_funcs, PKGCONF_ARRAY_SIZE(pkgconf_pkg_parser_keyword_funcs), 353 sizeof(pkgconf_pkg_parser_keyword_pair_t), pkgconf_pkg_parser_keyword_pair_cmp); 354 355 if (pair == NULL || pair->func == NULL) 356 return; 357 358 pair->func(pkg->owner, pkg, keyword, warnprefix, pair->offset, value); 359 } 360 361 static bool 362 determine_prefix(const pkgconf_pkg_t *pkg, pkgconf_buffer_t *pathbuf) 363 { 364 pkgconf_buffer_append(pathbuf, pkg->filename); 365 pkgconf_path_relocate(pathbuf); 366 367 pkgconf_path_trim_basename(pathbuf); 368 369 if (strcmp(pkgconf_path_find_basename(pkgconf_buffer_str_or_empty(pathbuf)), "pkgconfig")) 370 return false; 371 372 if (!pkgconf_path_trim_basename(pathbuf)) 373 return false; 374 375 if (!pkgconf_path_trim_basename(pathbuf)) 376 return false; 377 378 return true; 379 } 380 381 /* 382 * Takes a real path and converts it to a pkgconf value. This means normalizing 383 * directory separators and escaping things (only spaces covered atm). 384 * 385 * This is useful for things like prefix/pcfiledir which might get injected 386 * at runtime and are not sourced from the .pc file. 387 * 388 * "C:\foo bar\baz" -> "C:/foo\ bar/baz" 389 * "/foo bar/baz" -> "/foo\ bar/baz" 390 */ 391 static char * 392 convert_path_to_value(const char *path) 393 { 394 pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER; 395 const char *i; 396 397 for (i = path; *i != '\0'; i++) 398 { 399 if (*i == PKG_DIR_SEP_S) 400 pkgconf_buffer_push_byte(&buf, '/'); 401 else if (*i == ' ') 402 { 403 pkgconf_buffer_push_byte(&buf, '\\'); 404 pkgconf_buffer_push_byte(&buf, ' '); 405 } 406 else 407 pkgconf_buffer_push_byte(&buf, *i); 408 } 409 410 return pkgconf_buffer_freeze(&buf); 411 } 412 413 static void 414 remove_additional_separators(char *buf) 415 { 416 char *p = buf; 417 418 while (*p) { 419 if (*p == '/') { 420 char *q; 421 422 q = ++p; 423 while (*q && *q == '/') 424 q++; 425 426 if (p != q) 427 memmove (p, q, strlen (q) + 1); 428 } else { 429 p++; 430 } 431 } 432 } 433 434 static void 435 canonicalize_path(char *buf) 436 { 437 remove_additional_separators(buf); 438 } 439 440 static bool 441 is_path_prefix_equal(const char *path1, const char *path2, size_t path2_len) 442 { 443 #ifdef _WIN32 444 return !_strnicmp(path1, path2, path2_len); 445 #else 446 return !strncmp(path1, path2, path2_len); 447 #endif 448 } 449 450 static inline const char * 451 lookup_val_from_env(const pkgconf_client_t *client, const char *pkg_id, const char *keyword) 452 { 453 char env_var[PKGCONF_ITEM_SIZE]; 454 char *c; 455 456 snprintf(env_var, sizeof env_var, "PKG_CONFIG_%s_%s", pkg_id, keyword); 457 458 for (c = env_var; *c; c++) 459 { 460 *c = (char) toupper((unsigned char) *c); 461 462 if (!isalnum((unsigned char) *c)) 463 *c = '_'; 464 } 465 466 return pkgconf_client_getenv(client, env_var); 467 } 468 469 static void 470 pkgconf_pkg_parser_value_set(void *opaque, const char *warnprefix, const char *keyword, const char *value) 471 { 472 pkgconf_buffer_t canonicalized_value = PKGCONF_BUFFER_INITIALIZER; 473 pkgconf_pkg_t *pkg = opaque; 474 const char *env_content; 475 476 (void) warnprefix; 477 478 env_content = lookup_val_from_env(pkg->owner, pkg->id, keyword); 479 if (env_content != NULL) 480 { 481 PKGCONF_TRACE(pkg->owner, "overriding %s from environment", keyword); 482 value = env_content; 483 } 484 485 if (!pkgconf_buffer_append(&canonicalized_value, value)) 486 goto out; 487 488 canonicalize_path(canonicalized_value.base); 489 490 if (!(pkg->owner->flags & PKGCONF_PKG_PKGF_REDEFINE_PREFIX)) 491 { 492 pkgconf_tuple_add(pkg->owner, &pkg->vars, keyword, value, true, pkg->flags); 493 goto out; 494 } 495 496 /* Some pc files will use absolute paths for all of their directories 497 * which is broken when redefining the prefix. We try to outsmart the 498 * file and rewrite any directory that starts with the same prefix. 499 */ 500 if (strcmp(keyword, pkg->owner->prefix_varname)) 501 { 502 if (pkgconf_buffer_len(&pkg->orig_prefix) != 0) 503 { 504 const char *op = pkgconf_buffer_str_or_empty(&pkg->orig_prefix); 505 const size_t oplen = pkgconf_buffer_len(&pkg->orig_prefix); 506 507 if (is_path_prefix_equal(pkgconf_buffer_str(&canonicalized_value), op, oplen)) 508 { 509 pkgconf_buffer_t newvalue = PKGCONF_BUFFER_INITIALIZER; 510 511 pkgconf_buffer_append(&newvalue, pkgconf_buffer_str_or_empty(&pkg->calculated_prefix)); 512 pkgconf_buffer_append(&newvalue, pkgconf_buffer_str(&canonicalized_value) + oplen); 513 514 pkgconf_tuple_add(pkg->owner, &pkg->vars, keyword, pkgconf_buffer_str(&newvalue), false, pkg->flags); 515 pkgconf_buffer_finalize(&newvalue); 516 517 goto out; 518 } 519 } 520 521 pkgconf_tuple_add(pkg->owner, &pkg->vars, keyword, value, true, pkg->flags); 522 } 523 else 524 { 525 pkgconf_buffer_t pathbuf = PKGCONF_BUFFER_INITIALIZER; 526 527 if (determine_prefix(pkg, &pathbuf)) 528 { 529 const char *relvalue = pkgconf_buffer_str(&pathbuf); 530 char *prefix_value = convert_path_to_value(relvalue); 531 532 pkgconf_buffer_append(&pkg->orig_prefix, pkgconf_buffer_str(&canonicalized_value)); 533 pkgconf_buffer_append(&pkg->calculated_prefix, prefix_value); 534 535 pkgconf_tuple_add(pkg->owner, &pkg->vars, keyword, prefix_value, false, pkg->flags); 536 free(prefix_value); 537 } 538 else 539 pkgconf_tuple_add(pkg->owner, &pkg->vars, keyword, value, true, pkg->flags); 540 541 pkgconf_buffer_finalize(&pathbuf); 542 } 543 544 out: 545 pkgconf_buffer_finalize(&canonicalized_value); 546 } 547 548 typedef struct { 549 const char *field; 550 const ptrdiff_t offset; 551 } pkgconf_pkg_validity_check_t; 552 553 static const pkgconf_pkg_validity_check_t pkgconf_pkg_validations[] = { 554 {"Name", offsetof(pkgconf_pkg_t, realname)}, 555 {"Description", offsetof(pkgconf_pkg_t, description)}, 556 {"Version", offsetof(pkgconf_pkg_t, version)}, 557 }; 558 559 static const pkgconf_parser_operand_func_t pkg_parser_funcs[256] = { 560 [':'] = pkgconf_pkg_parser_keyword_set, 561 ['='] = pkgconf_pkg_parser_value_set 562 }; 563 564 static void pkg_warn_func(void *pkg_p, const char *fmt, ...) PRINTFLIKE(2, 3); 565 566 static void 567 pkg_warn_func(void *pkg_p, const char *fmt, ...) 568 { 569 pkgconf_pkg_t *pkg = pkg_p; 570 char buf[PKGCONF_ITEM_SIZE]; 571 va_list va; 572 573 va_start(va, fmt); 574 vsnprintf(buf, sizeof buf, fmt, va); 575 va_end(va); 576 577 pkgconf_warn(pkg->owner, "%s", buf); 578 } 579 580 static bool 581 pkgconf_pkg_validate(const pkgconf_client_t *client, const pkgconf_pkg_t *pkg) 582 { 583 size_t i; 584 bool valid = true; 585 586 for (i = 0; i < PKGCONF_ARRAY_SIZE(pkgconf_pkg_validations); i++) 587 { 588 char **p = (char **)((char *) pkg + pkgconf_pkg_validations[i].offset); 589 590 if (*p != NULL) 591 continue; 592 593 pkgconf_warn(client, "%s: warning: file does not declare a `%s' field\n", pkg->filename, pkgconf_pkg_validations[i].field); 594 valid = false; 595 } 596 597 return valid; 598 } 599 600 static void 601 pkg_free_object(pkgconf_pkg_t *pkg) 602 { 603 if (pkg->flags & PKGCONF_PKG_PROPF_PRELOADED) 604 pkgconf_node_delete(&pkg->preload_node, &pkg->owner->preloaded_pkgs); 605 606 if (pkg->id != NULL) 607 free(pkg->id); 608 609 if (pkg->filename != NULL) 610 free(pkg->filename); 611 612 if (pkg->realname != NULL) 613 free(pkg->realname); 614 615 if (pkg->version != NULL) 616 free(pkg->version); 617 618 if (pkg->description != NULL) 619 free(pkg->description); 620 621 if (pkg->url != NULL) 622 free(pkg->url); 623 624 if (pkg->pc_filedir != NULL) 625 free(pkg->pc_filedir); 626 627 if (pkg->license_file != NULL) 628 free(pkg->license_file); 629 630 if (pkg->maintainer != NULL) 631 free(pkg->maintainer); 632 633 if (pkg->why != NULL) 634 free(pkg->why); 635 636 if (pkg->source != NULL) 637 free(pkg->source); 638 639 pkgconf_buffer_finalize(&pkg->orig_prefix); 640 pkgconf_buffer_finalize(&pkg->calculated_prefix); 641 642 free(pkg); 643 } 644 645 static void 646 pkg_free_lists(pkgconf_pkg_t *pkg) 647 { 648 pkgconf_bufferset_free(&pkg->copyright); 649 pkgconf_bufferset_free(&pkg->link_abi); 650 651 pkgconf_dependency_free(&pkg->required); 652 pkgconf_dependency_free(&pkg->requires_private); 653 pkgconf_dependency_free(&pkg->requires_shared); 654 pkgconf_dependency_free(&pkg->conflicts); 655 pkgconf_dependency_free(&pkg->provides); 656 657 pkgconf_fragment_free(&pkg->cflags); 658 pkgconf_fragment_free(&pkg->cflags_private); 659 pkgconf_fragment_free(&pkg->cflags_shared); 660 pkgconf_license_free(&pkg->license); 661 pkgconf_fragment_free(&pkg->libs); 662 pkgconf_fragment_free(&pkg->libs_private); 663 pkgconf_fragment_free(&pkg->libs_shared); 664 665 pkgconf_tuple_free(&pkg->vars); 666 } 667 668 /* 669 * !doc 670 * 671 * .. c:function:: pkgconf_pkg_t *pkgconf_pkg_new_from_path(const pkgconf_client_t *client, const char *filename, unsigned int flags) 672 * 673 * Parse a .pc file into a pkgconf_pkg_t object structure. 674 * 675 * :param pkgconf_client_t* client: The pkgconf client object to use for dependency resolution. 676 * :param char* filename: The filename of the package file (including full path). 677 * :param FILE* f: The file object to read from. 678 * :param uint flags: The flags to use when parsing. 679 * :returns: A ``pkgconf_pkg_t`` object which contains the package data. 680 * :rtype: pkgconf_pkg_t * 681 */ 682 pkgconf_pkg_t * 683 pkgconf_pkg_new_from_path(pkgconf_client_t *client, const char *filename, unsigned int flags) 684 { 685 pkgconf_pkg_t *pkg; 686 char *idptr; 687 FILE *f; 688 689 /* make sure we only load .pc files */ 690 if (!str_has_suffix(filename, PKG_CONFIG_EXT)) 691 return NULL; 692 693 f = fopen(filename, "rb"); 694 if (f == NULL) 695 return NULL; 696 697 pkg = calloc(1, sizeof(pkgconf_pkg_t)); 698 if (pkg == NULL) 699 { 700 fclose(f); 701 return NULL; 702 } 703 704 pkg->owner = client; 705 pkg->flags = flags; 706 707 pkg->filename = strdup(filename); 708 if (pkg->filename == NULL) 709 { 710 fclose(f); 711 pkg_free_object(pkg); 712 return NULL; 713 } 714 715 pkg->pc_filedir = pkg_get_parent_dir(pkg); 716 if (pkg->pc_filedir == NULL) 717 { 718 fclose(f); 719 pkg_free_object(pkg); 720 return NULL; 721 } 722 723 char *pc_filedir_value = convert_path_to_value(pkg->pc_filedir); 724 pkgconf_tuple_add(client, &pkg->vars, "pcfiledir", pc_filedir_value, true, pkg->flags); 725 free(pc_filedir_value); 726 727 /* If pc_filedir is outside of sysroot_dir, override sysroot_dir for this 728 * package. 729 * See https://github.com/pkgconf/pkgconf/issues/213 730 */ 731 if (client->sysroot_dir != NULL && strncmp(pkg->pc_filedir, client->sysroot_dir, strlen(client->sysroot_dir)) && 732 !(client->flags & PKGCONF_PKG_PKGF_PKGCONF1_SYSROOT_RULES)) 733 pkgconf_tuple_add(client, &pkg->vars, "pc_sysrootdir", "", false, pkg->flags); 734 735 /* make module id */ 736 pkg->id = strdup(pkgconf_path_find_basename(pkg->filename)); 737 if (pkg->id == NULL) 738 { 739 fclose(f); 740 pkg_free_lists(pkg); 741 pkg_free_object(pkg); 742 return NULL; 743 } 744 745 idptr = strrchr(pkg->id, '.'); 746 if (idptr) 747 *idptr = '\0'; 748 749 if (pkg->flags & PKGCONF_PKG_PROPF_UNINSTALLED) 750 { 751 idptr = strrchr(pkg->id, '-'); 752 if (idptr) 753 *idptr = '\0'; 754 } 755 756 pkgconf_parser_parse(f, pkg, pkg_parser_funcs, pkg_warn_func, pkg->filename); 757 fclose(f); 758 759 if (!pkgconf_pkg_validate(client, pkg)) 760 { 761 pkgconf_warn(client, "%s: warning: skipping invalid file\n", pkg->filename); 762 pkgconf_pkg_free(client, pkg); 763 return NULL; 764 } 765 766 /* a package that does not declare a Link.ABI defaults to the C ABI; a 767 * declared Link.ABI replaces this default rather than adding to it. 768 */ 769 if (pkg->link_abi.head == NULL) 770 { 771 pkgconf_buffer_t abibuf = PKGCONF_BUFFER_INITIALIZER; 772 773 pkgconf_buffer_append(&abibuf, "c"); 774 pkgconf_bufferset_extend(&pkg->link_abi, &abibuf); 775 pkgconf_buffer_finalize(&abibuf); 776 } 777 778 pkgconf_dependency_t *dep = pkgconf_dependency_add(client, &pkg->provides, pkg->id, pkg->version, PKGCONF_CMP_EQUAL, 0); 779 if (dep == NULL) 780 { 781 pkgconf_pkg_free(client, pkg); 782 return NULL; 783 } 784 785 pkgconf_dependency_unref(dep->owner, dep); 786 787 return pkgconf_pkg_ref(client, pkg); 788 } 789 790 /* 791 * !doc 792 * 793 * .. c:function:: void pkgconf_pkg_free(pkgconf_client_t *client, pkgconf_pkg_t *pkg) 794 * 795 * Releases all releases for a given ``pkgconf_pkg_t`` object. 796 * 797 * :param pkgconf_client_t* client: The client which owns the ``pkgconf_pkg_t`` object, `pkg`. 798 * :param pkgconf_pkg_t* pkg: The package to free. 799 * :return: nothing 800 */ 801 void 802 pkgconf_pkg_free(pkgconf_client_t *client, pkgconf_pkg_t *pkg) 803 { 804 if (pkg == NULL) 805 return; 806 807 if (pkg->flags & PKGCONF_PKG_PROPF_STATIC && !(pkg->flags & PKGCONF_PKG_PROPF_VIRTUAL)) 808 return; 809 810 pkgconf_cache_remove(client, pkg); 811 812 pkg_free_lists(pkg); 813 814 if (pkg->flags & PKGCONF_PKG_PROPF_VIRTUAL) 815 return; 816 817 pkg_free_object(pkg); 818 } 819 820 /* 821 * !doc 822 * 823 * .. c:function:: pkgconf_pkg_t *pkgconf_pkg_ref(const pkgconf_client_t *client, pkgconf_pkg_t *pkg) 824 * 825 * Adds an additional reference to the package object. 826 * 827 * :param pkgconf_client_t* client: The pkgconf client object which owns the package being referenced. 828 * :param pkgconf_pkg_t* pkg: The package object being referenced. 829 * :return: The package itself with an incremented reference count. 830 * :rtype: pkgconf_pkg_t * 831 */ 832 pkgconf_pkg_t * 833 pkgconf_pkg_ref(pkgconf_client_t *client, pkgconf_pkg_t *pkg) 834 { 835 if (pkg->owner != NULL && pkg->owner != client) 836 PKGCONF_TRACE(client, "WTF: client %p refers to package %p owned by other client %p", client, pkg, pkg->owner); 837 838 pkg->refcount++; 839 PKGCONF_TRACE(client, "%s refcount@%p: %d", pkg->id, pkg, pkg->refcount); 840 841 return pkg; 842 } 843 844 /* 845 * !doc 846 * 847 * .. c:function:: void pkgconf_pkg_unref(pkgconf_client_t *client, pkgconf_pkg_t *pkg) 848 * 849 * Releases a reference on the package object. If the reference count is 0, then also free the package. 850 * 851 * :param pkgconf_client_t* client: The pkgconf client object which owns the package being dereferenced. 852 * :param pkgconf_pkg_t* pkg: The package object being dereferenced. 853 * :return: nothing 854 */ 855 void 856 pkgconf_pkg_unref(pkgconf_client_t *client, pkgconf_pkg_t *pkg) 857 { 858 if (pkg == NULL) { 859 PKGCONF_TRACE(client, "WTF: client %p unrefs a NULL package", client); 860 return; 861 } 862 863 if (pkg->owner != NULL && pkg->owner != client) 864 PKGCONF_TRACE(client, "WTF: client %p unrefs package %p owned by other client %p", client, pkg, pkg->owner); 865 866 pkg->refcount--; 867 PKGCONF_TRACE(pkg->owner, "%s refcount@%p: %d", pkg->id, pkg, pkg->refcount); 868 869 if (pkg->refcount <= 0) 870 pkgconf_pkg_free(pkg->owner, pkg); 871 } 872 873 static inline pkgconf_pkg_t * 874 pkgconf_pkg_try_specific_path(pkgconf_client_t *client, const char *path, const char *name) 875 { 876 pkgconf_pkg_t *pkg = NULL; 877 char locbuf[PKGCONF_ITEM_SIZE]; 878 char uninst_locbuf[PKGCONF_ITEM_SIZE]; 879 880 PKGCONF_TRACE(client, "trying path: %s for %s", path, name); 881 882 snprintf(locbuf, sizeof locbuf, "%s%c%s" PKG_CONFIG_EXT, path, PKG_DIR_SEP_S, name); 883 snprintf(uninst_locbuf, sizeof uninst_locbuf, "%s%c%s-uninstalled" PKG_CONFIG_EXT, path, PKG_DIR_SEP_S, name); 884 885 if (!(client->flags & PKGCONF_PKG_PKGF_NO_UNINSTALLED)) 886 pkg = pkgconf_pkg_new_from_path(client, uninst_locbuf, PKGCONF_PKG_PROPF_UNINSTALLED); 887 888 if (pkg == NULL) 889 pkg = pkgconf_pkg_new_from_path(client, locbuf, 0); 890 891 if (pkg != NULL) 892 PKGCONF_TRACE(client, "found%s: %s", pkg->flags & PKGCONF_PKG_PROPF_UNINSTALLED ? " (uninstalled)" : "", uninst_locbuf); 893 894 return pkg; 895 } 896 897 static pkgconf_pkg_t * 898 pkgconf_pkg_scan_dir(pkgconf_client_t *client, const char *path, void *data, pkgconf_pkg_iteration_func_t func) 899 { 900 DIR *dir; 901 struct dirent *dirent; 902 pkgconf_pkg_t *outpkg = NULL; 903 904 dir = opendir(path); 905 if (dir == NULL) 906 return NULL; 907 908 PKGCONF_TRACE(client, "scanning dir [%s]", path); 909 910 for (dirent = readdir(dir); dirent != NULL; dirent = readdir(dir)) 911 { 912 pkgconf_buffer_t filebuf = PKGCONF_BUFFER_INITIALIZER; 913 pkgconf_pkg_t *pkg; 914 915 pkgconf_buffer_join(&filebuf, '/', path, dirent->d_name, NULL); 916 917 if (!str_has_suffix(pkgconf_buffer_str(&filebuf), PKG_CONFIG_EXT)) 918 { 919 pkgconf_buffer_finalize(&filebuf); 920 continue; 921 } 922 923 PKGCONF_TRACE(client, "trying file [%s]", pkgconf_buffer_str(&filebuf)); 924 925 pkg = pkgconf_pkg_new_from_path(client, pkgconf_buffer_str(&filebuf), 0); 926 pkgconf_buffer_finalize(&filebuf); 927 928 if (pkg != NULL) 929 { 930 if (func(pkg, data)) 931 { 932 outpkg = pkg; 933 goto out; 934 } 935 936 pkgconf_pkg_unref(client, pkg); 937 } 938 } 939 940 out: 941 closedir(dir); 942 return outpkg; 943 } 944 945 /* 946 * !doc 947 * 948 * .. c:function:: pkgconf_pkg_t *pkgconf_scan_all(pkgconf_client_t *client, void *data, pkgconf_pkg_iteration_func_t func) 949 * 950 * Iterates over all packages found in the `package directory list`, running ``func`` on them. If ``func`` returns true, 951 * then stop iteration and return the last iterated package. 952 * 953 * :param pkgconf_client_t* client: The pkgconf client object to use for dependency resolution. 954 * :param void* data: An opaque pointer to data to provide the iteration function with. 955 * :param pkgconf_pkg_iteration_func_t func: A function which is called for each package to determine if the package matches, 956 * always return ``false`` to iterate over all packages. 957 * :return: A package object reference if one is found by the scan function, else ``NULL``. 958 * :rtype: pkgconf_pkg_t * 959 */ 960 pkgconf_pkg_t * 961 pkgconf_scan_all(pkgconf_client_t *client, void *data, pkgconf_pkg_iteration_func_t func) 962 { 963 pkgconf_node_t *n; 964 pkgconf_pkg_t *pkg; 965 966 PKGCONF_TRACE(client, "scanning preloaded list"); 967 PKGCONF_FOREACH_LIST_ENTRY(client->preloaded_pkgs.head, n) 968 { 969 pkg = n->data; 970 971 /* add an additional reference to ensure preloaded packages have the same 972 * object ownership semantics as non-preloaded packages 973 */ 974 pkgconf_pkg_ref(client, pkg); 975 976 if (func(pkg, data)) 977 return pkg; 978 979 pkgconf_pkg_unref(client, pkg); 980 } 981 982 PKGCONF_FOREACH_LIST_ENTRY(client->dir_list.head, n) 983 { 984 pkgconf_path_t *pnode = n->data; 985 986 PKGCONF_TRACE(client, "scanning directory: %s", pnode->path); 987 988 if ((pkg = pkgconf_pkg_scan_dir(client, pnode->path, data, func)) != NULL) 989 return pkg; 990 } 991 992 return NULL; 993 } 994 995 static pkgconf_pkg_t * 996 search_preload_list(pkgconf_client_t *client, const char *name) 997 { 998 pkgconf_node_t *n; 999 1000 PKGCONF_FOREACH_LIST_ENTRY(client->preloaded_pkgs.head, n) 1001 { 1002 pkgconf_pkg_t *pkg = n->data; 1003 1004 if (!strcmp(pkg->id, name)) 1005 { 1006 pkgconf_pkg_ref(client, pkg); 1007 return pkg; 1008 } 1009 } 1010 1011 return NULL; 1012 } 1013 1014 /* 1015 * !doc 1016 * 1017 * .. c:function:: pkgconf_pkg_t *pkgconf_pkg_find(pkgconf_client_t *client, const char *name) 1018 * 1019 * Search for a package. 1020 * 1021 * :param pkgconf_client_t* client: The pkgconf client object to use for dependency resolution. 1022 * :param char* name: The name of the package `atom` to use for searching. 1023 * :return: A package object reference if the package was found, else ``NULL``. 1024 * :rtype: pkgconf_pkg_t * 1025 */ 1026 pkgconf_pkg_t * 1027 pkgconf_pkg_find(pkgconf_client_t *client, const char *name) 1028 { 1029 pkgconf_pkg_t *pkg = NULL; 1030 pkgconf_node_t *n; 1031 1032 PKGCONF_TRACE(client, "looking for: %s", name); 1033 1034 /* name might actually be a filename. */ 1035 if (str_has_suffix(name, PKG_CONFIG_EXT)) 1036 { 1037 if (client->unveil_handler != NULL) 1038 client->unveil_handler(client, name, "r"); 1039 1040 pkg = pkgconf_pkg_new_from_path(client, name, 0); 1041 if (pkg != NULL) 1042 { 1043 PKGCONF_TRACE(client, "%s is a file", name); 1044 1045 if (client->unveil_handler != NULL) 1046 client->unveil_handler(client, pkg->pc_filedir, "r"); 1047 1048 pkgconf_path_add(pkg->pc_filedir, &client->dir_list, true); 1049 goto out; 1050 } 1051 } 1052 1053 /* check cache */ 1054 if (!(client->flags & PKGCONF_PKG_PKGF_NO_CACHE)) 1055 { 1056 if ((pkg = pkgconf_cache_lookup(client, name)) != NULL) 1057 { 1058 PKGCONF_TRACE(client, "%s is cached", name); 1059 return pkg; 1060 } 1061 } 1062 1063 /* check preload list */ 1064 if ((pkg = search_preload_list(client, name)) != NULL) 1065 { 1066 PKGCONF_TRACE(client, "%s is preloaded", name); 1067 return pkg; 1068 } 1069 1070 PKGCONF_FOREACH_LIST_ENTRY(client->dir_list.head, n) 1071 { 1072 pkgconf_path_t *pnode = n->data; 1073 1074 pkg = pkgconf_pkg_try_specific_path(client, pnode->path, name); 1075 if (pkg != NULL) 1076 goto out; 1077 } 1078 1079 out: 1080 pkgconf_cache_add(client, pkg); 1081 1082 return pkg; 1083 } 1084 1085 typedef bool (*pkgconf_vercmp_res_func_t)(const char *a, const char *b); 1086 1087 typedef struct { 1088 const char *name; 1089 pkgconf_pkg_comparator_t compare; 1090 } pkgconf_pkg_comparator_pair_t; 1091 1092 static const pkgconf_pkg_comparator_pair_t pkgconf_pkg_comparator_names[] = { 1093 {"!=", PKGCONF_CMP_NOT_EQUAL}, 1094 {"(any)", PKGCONF_CMP_ANY}, 1095 {"<", PKGCONF_CMP_LESS_THAN}, 1096 {"<=", PKGCONF_CMP_LESS_THAN_EQUAL}, 1097 {"=", PKGCONF_CMP_EQUAL}, 1098 {">", PKGCONF_CMP_GREATER_THAN}, 1099 {">=", PKGCONF_CMP_GREATER_THAN_EQUAL}, 1100 }; 1101 1102 static int pkgconf_pkg_comparator_pair_namecmp(const void *key, const void *ptr) 1103 { 1104 const pkgconf_pkg_comparator_pair_t *pair = ptr; 1105 return strcmp(key, pair->name); 1106 } 1107 1108 static bool pkgconf_pkg_comparator_lt(const char *a, const char *b) 1109 { 1110 return (pkgconf_compare_version(a, b) < 0); 1111 } 1112 1113 static bool pkgconf_pkg_comparator_gt(const char *a, const char *b) 1114 { 1115 return (pkgconf_compare_version(a, b) > 0); 1116 } 1117 1118 static bool pkgconf_pkg_comparator_lte(const char *a, const char *b) 1119 { 1120 return (pkgconf_compare_version(a, b) <= 0); 1121 } 1122 1123 static bool pkgconf_pkg_comparator_gte(const char *a, const char *b) 1124 { 1125 return (pkgconf_compare_version(a, b) >= 0); 1126 } 1127 1128 static bool pkgconf_pkg_comparator_eq(const char *a, const char *b) 1129 { 1130 return (pkgconf_compare_version(a, b) == 0); 1131 } 1132 1133 static bool pkgconf_pkg_comparator_ne(const char *a, const char *b) 1134 { 1135 return (pkgconf_compare_version(a, b) != 0); 1136 } 1137 1138 static bool pkgconf_pkg_comparator_any(const char *a, const char *b) 1139 { 1140 (void) a; 1141 (void) b; 1142 1143 return true; 1144 } 1145 1146 static bool pkgconf_pkg_comparator_none(const char *a, const char *b) 1147 { 1148 (void) a; 1149 (void) b; 1150 1151 return false; 1152 } 1153 1154 static const pkgconf_vercmp_res_func_t pkgconf_pkg_comparator_impls[] = { 1155 [PKGCONF_CMP_ANY] = pkgconf_pkg_comparator_any, 1156 [PKGCONF_CMP_LESS_THAN] = pkgconf_pkg_comparator_lt, 1157 [PKGCONF_CMP_GREATER_THAN] = pkgconf_pkg_comparator_gt, 1158 [PKGCONF_CMP_LESS_THAN_EQUAL] = pkgconf_pkg_comparator_lte, 1159 [PKGCONF_CMP_GREATER_THAN_EQUAL] = pkgconf_pkg_comparator_gte, 1160 [PKGCONF_CMP_EQUAL] = pkgconf_pkg_comparator_eq, 1161 [PKGCONF_CMP_NOT_EQUAL] = pkgconf_pkg_comparator_ne, 1162 }; 1163 1164 /* 1165 * !doc 1166 * 1167 * .. c:function:: const char *pkgconf_pkg_get_comparator(const pkgconf_dependency_t *pkgdep) 1168 * 1169 * Returns the comparator used in a depgraph dependency node as a string. 1170 * 1171 * :param pkgconf_dependency_t* pkgdep: The depgraph dependency node to return the comparator for. 1172 * :return: A string matching the comparator or ``"???"``. 1173 * :rtype: char * 1174 */ 1175 const char * 1176 pkgconf_pkg_get_comparator(const pkgconf_dependency_t *pkgdep) 1177 { 1178 if (pkgdep->compare >= PKGCONF_ARRAY_SIZE(pkgconf_pkg_comparator_names)) 1179 return "???"; 1180 1181 return pkgconf_pkg_comparator_names[pkgdep->compare].name; 1182 } 1183 1184 /* 1185 * !doc 1186 * 1187 * .. c:function:: pkgconf_pkg_comparator_t pkgconf_pkg_comparator_lookup_by_name(const char *name) 1188 * 1189 * Look up the appropriate comparator bytecode in the comparator set (defined 1190 * in ``pkg.c``, see ``pkgconf_pkg_comparator_names`` and ``pkgconf_pkg_comparator_impls``). 1191 * 1192 * :param char* name: The comparator to look up by `name`. 1193 * :return: The comparator bytecode if found, else ``PKGCONF_CMP_ANY``. 1194 * :rtype: pkgconf_pkg_comparator_t 1195 */ 1196 pkgconf_pkg_comparator_t 1197 pkgconf_pkg_comparator_lookup_by_name(const char *name) 1198 { 1199 if (name == NULL) 1200 return PKGCONF_CMP_ANY; 1201 1202 const pkgconf_pkg_comparator_pair_t *p = bsearch(name, pkgconf_pkg_comparator_names, 1203 PKGCONF_ARRAY_SIZE(pkgconf_pkg_comparator_names), sizeof(pkgconf_pkg_comparator_pair_t), 1204 pkgconf_pkg_comparator_pair_namecmp); 1205 1206 return (p != NULL) ? p->compare : PKGCONF_CMP_ANY; 1207 } 1208 1209 typedef struct { 1210 pkgconf_dependency_t *pkgdep; 1211 } pkgconf_pkg_scan_providers_ctx_t; 1212 1213 typedef struct { 1214 const pkgconf_vercmp_res_func_t rulecmp[PKGCONF_CMP_COUNT]; 1215 const pkgconf_vercmp_res_func_t depcmp[PKGCONF_CMP_COUNT]; 1216 } pkgconf_pkg_provides_vermatch_rule_t; 1217 1218 static const pkgconf_pkg_provides_vermatch_rule_t pkgconf_pkg_provides_vermatch_rules[] = { 1219 [PKGCONF_CMP_ANY] = { 1220 .rulecmp = { 1221 [PKGCONF_CMP_ANY] = pkgconf_pkg_comparator_none, 1222 }, 1223 .depcmp = { 1224 [PKGCONF_CMP_ANY] = pkgconf_pkg_comparator_none, 1225 }, 1226 }, 1227 [PKGCONF_CMP_LESS_THAN] = { 1228 .rulecmp = { 1229 [PKGCONF_CMP_ANY] = pkgconf_pkg_comparator_none, 1230 [PKGCONF_CMP_LESS_THAN] = pkgconf_pkg_comparator_lt, 1231 [PKGCONF_CMP_GREATER_THAN] = pkgconf_pkg_comparator_gt, 1232 [PKGCONF_CMP_LESS_THAN_EQUAL] = pkgconf_pkg_comparator_lte, 1233 [PKGCONF_CMP_GREATER_THAN_EQUAL] = pkgconf_pkg_comparator_gte, 1234 }, 1235 .depcmp = { 1236 [PKGCONF_CMP_GREATER_THAN] = pkgconf_pkg_comparator_lt, 1237 [PKGCONF_CMP_GREATER_THAN_EQUAL] = pkgconf_pkg_comparator_lt, 1238 [PKGCONF_CMP_EQUAL] = pkgconf_pkg_comparator_lt, 1239 [PKGCONF_CMP_NOT_EQUAL] = pkgconf_pkg_comparator_gte, 1240 }, 1241 }, 1242 [PKGCONF_CMP_GREATER_THAN] = { 1243 .rulecmp = { 1244 [PKGCONF_CMP_ANY] = pkgconf_pkg_comparator_none, 1245 [PKGCONF_CMP_LESS_THAN] = pkgconf_pkg_comparator_lt, 1246 [PKGCONF_CMP_GREATER_THAN] = pkgconf_pkg_comparator_gt, 1247 [PKGCONF_CMP_LESS_THAN_EQUAL] = pkgconf_pkg_comparator_lte, 1248 [PKGCONF_CMP_GREATER_THAN_EQUAL] = pkgconf_pkg_comparator_gte, 1249 }, 1250 .depcmp = { 1251 [PKGCONF_CMP_LESS_THAN] = pkgconf_pkg_comparator_gt, 1252 [PKGCONF_CMP_LESS_THAN_EQUAL] = pkgconf_pkg_comparator_gt, 1253 [PKGCONF_CMP_EQUAL] = pkgconf_pkg_comparator_gt, 1254 [PKGCONF_CMP_NOT_EQUAL] = pkgconf_pkg_comparator_lte, 1255 }, 1256 }, 1257 [PKGCONF_CMP_LESS_THAN_EQUAL] = { 1258 .rulecmp = { 1259 [PKGCONF_CMP_ANY] = pkgconf_pkg_comparator_none, 1260 [PKGCONF_CMP_LESS_THAN] = pkgconf_pkg_comparator_lt, 1261 [PKGCONF_CMP_GREATER_THAN] = pkgconf_pkg_comparator_gt, 1262 [PKGCONF_CMP_LESS_THAN_EQUAL] = pkgconf_pkg_comparator_lte, 1263 [PKGCONF_CMP_GREATER_THAN_EQUAL] = pkgconf_pkg_comparator_gte, 1264 }, 1265 .depcmp = { 1266 [PKGCONF_CMP_GREATER_THAN] = pkgconf_pkg_comparator_lte, 1267 [PKGCONF_CMP_GREATER_THAN_EQUAL] = pkgconf_pkg_comparator_lte, 1268 [PKGCONF_CMP_EQUAL] = pkgconf_pkg_comparator_lte, 1269 [PKGCONF_CMP_NOT_EQUAL] = pkgconf_pkg_comparator_gt, 1270 }, 1271 }, 1272 [PKGCONF_CMP_GREATER_THAN_EQUAL] = { 1273 .rulecmp = { 1274 [PKGCONF_CMP_ANY] = pkgconf_pkg_comparator_none, 1275 [PKGCONF_CMP_LESS_THAN] = pkgconf_pkg_comparator_lt, 1276 [PKGCONF_CMP_GREATER_THAN] = pkgconf_pkg_comparator_gt, 1277 [PKGCONF_CMP_LESS_THAN_EQUAL] = pkgconf_pkg_comparator_lte, 1278 [PKGCONF_CMP_GREATER_THAN_EQUAL] = pkgconf_pkg_comparator_gte, 1279 }, 1280 .depcmp = { 1281 [PKGCONF_CMP_LESS_THAN] = pkgconf_pkg_comparator_gte, 1282 [PKGCONF_CMP_LESS_THAN_EQUAL] = pkgconf_pkg_comparator_gte, 1283 [PKGCONF_CMP_EQUAL] = pkgconf_pkg_comparator_gte, 1284 [PKGCONF_CMP_NOT_EQUAL] = pkgconf_pkg_comparator_lt, 1285 }, 1286 }, 1287 [PKGCONF_CMP_EQUAL] = { 1288 .rulecmp = { 1289 [PKGCONF_CMP_ANY] = pkgconf_pkg_comparator_none, 1290 [PKGCONF_CMP_LESS_THAN] = pkgconf_pkg_comparator_lt, 1291 [PKGCONF_CMP_GREATER_THAN] = pkgconf_pkg_comparator_gt, 1292 [PKGCONF_CMP_LESS_THAN_EQUAL] = pkgconf_pkg_comparator_lte, 1293 [PKGCONF_CMP_GREATER_THAN_EQUAL] = pkgconf_pkg_comparator_gte, 1294 [PKGCONF_CMP_EQUAL] = pkgconf_pkg_comparator_eq, 1295 [PKGCONF_CMP_NOT_EQUAL] = pkgconf_pkg_comparator_ne 1296 }, 1297 .depcmp = { 1298 [PKGCONF_CMP_ANY] = pkgconf_pkg_comparator_none, 1299 }, 1300 }, 1301 [PKGCONF_CMP_NOT_EQUAL] = { 1302 .rulecmp = { 1303 [PKGCONF_CMP_ANY] = pkgconf_pkg_comparator_none, 1304 [PKGCONF_CMP_LESS_THAN] = pkgconf_pkg_comparator_gte, 1305 [PKGCONF_CMP_GREATER_THAN] = pkgconf_pkg_comparator_lte, 1306 [PKGCONF_CMP_LESS_THAN_EQUAL] = pkgconf_pkg_comparator_gt, 1307 [PKGCONF_CMP_GREATER_THAN_EQUAL] = pkgconf_pkg_comparator_lt, 1308 [PKGCONF_CMP_EQUAL] = pkgconf_pkg_comparator_ne, 1309 [PKGCONF_CMP_NOT_EQUAL] = pkgconf_pkg_comparator_eq 1310 }, 1311 .depcmp = { 1312 [PKGCONF_CMP_ANY] = pkgconf_pkg_comparator_none, 1313 }, 1314 }, 1315 }; 1316 1317 /* 1318 * pkgconf_pkg_scan_provides_vercmp(pkgdep, provider) 1319 * 1320 * compare a provides node against the requested dependency node. 1321 * 1322 * XXX: maybe handle PKGCONF_CMP_ANY in a versioned comparison 1323 */ 1324 static bool 1325 pkgconf_pkg_scan_provides_vercmp(const pkgconf_dependency_t *pkgdep, const pkgconf_dependency_t *provider) 1326 { 1327 const pkgconf_pkg_provides_vermatch_rule_t *rule = &pkgconf_pkg_provides_vermatch_rules[pkgdep->compare]; 1328 1329 if (rule->depcmp[provider->compare] != NULL && 1330 !rule->depcmp[provider->compare](provider->version, pkgdep->version)) 1331 return false; 1332 1333 if (rule->rulecmp[provider->compare] != NULL && 1334 !rule->rulecmp[provider->compare](pkgdep->version, provider->version)) 1335 return false; 1336 1337 return true; 1338 } 1339 1340 /* 1341 * pkgconf_pkg_scan_provides_entry(pkg, ctx) 1342 * 1343 * attempt to match a single package's Provides rules against the requested dependency node. 1344 */ 1345 static bool 1346 pkgconf_pkg_scan_provides_entry(const pkgconf_pkg_t *pkg, void *data) 1347 { 1348 const pkgconf_pkg_scan_providers_ctx_t *ctx = data; 1349 const pkgconf_dependency_t *pkgdep = ctx->pkgdep; 1350 pkgconf_node_t *node; 1351 1352 PKGCONF_FOREACH_LIST_ENTRY(pkg->provides.head, node) 1353 { 1354 const pkgconf_dependency_t *provider = node->data; 1355 if (!strcmp(provider->package, pkgdep->package)) 1356 return pkgconf_pkg_scan_provides_vercmp(pkgdep, provider); 1357 } 1358 1359 return false; 1360 } 1361 1362 /* 1363 * pkgconf_pkg_scan_providers(client, pkgdep, eflags) 1364 * 1365 * scan all available packages to see if a Provides rule matches the pkgdep. 1366 */ 1367 static pkgconf_pkg_t * 1368 pkgconf_pkg_scan_providers(pkgconf_client_t *client, pkgconf_dependency_t *pkgdep, unsigned int *eflags) 1369 { 1370 pkgconf_pkg_t *pkg; 1371 pkgconf_pkg_scan_providers_ctx_t ctx = { 1372 .pkgdep = pkgdep, 1373 }; 1374 1375 pkg = pkgconf_scan_all(client, &ctx, pkgconf_pkg_scan_provides_entry); 1376 if (pkg != NULL) 1377 { 1378 pkgdep->match = pkgconf_pkg_ref(client, pkg); 1379 return pkg; 1380 } 1381 1382 if (eflags != NULL) 1383 *eflags |= PKGCONF_PKG_ERRF_PACKAGE_NOT_FOUND; 1384 1385 return NULL; 1386 } 1387 1388 /* 1389 * !doc 1390 * 1391 * .. c:function:: pkgconf_pkg_t *pkgconf_pkg_verify_dependency(pkgconf_client_t *client, pkgconf_dependency_t *pkgdep, unsigned int *eflags) 1392 * 1393 * Verify a pkgconf_dependency_t node in the depgraph. If the dependency is solvable, 1394 * return the appropriate ``pkgconf_pkg_t`` object, else ``NULL``. 1395 * 1396 * :param pkgconf_client_t* client: The pkgconf client object to use for dependency resolution. 1397 * :param pkgconf_dependency_t* pkgdep: The dependency graph node to solve. 1398 * :param uint* eflags: An optional pointer that, if set, will be populated with an error code from the resolver. 1399 * :return: On success, the appropriate ``pkgconf_pkg_t`` object to solve the dependency, else ``NULL``. 1400 * :rtype: pkgconf_pkg_t * 1401 */ 1402 pkgconf_pkg_t * 1403 pkgconf_pkg_verify_dependency(pkgconf_client_t *client, pkgconf_dependency_t *pkgdep, unsigned int *eflags) 1404 { 1405 pkgconf_pkg_t *pkg = NULL; 1406 1407 if (eflags != NULL) 1408 *eflags = PKGCONF_PKG_ERRF_OK; 1409 1410 PKGCONF_TRACE(client, "trying to verify dependency: %s", pkgdep->package); 1411 1412 if (pkgdep->match != NULL) 1413 { 1414 PKGCONF_TRACE(client, "cached dependency: %s -> %s@%p", pkgdep->package, pkgdep->match->id, pkgdep->match); 1415 return pkgconf_pkg_ref(client, pkgdep->match); 1416 } 1417 1418 pkg = pkgconf_pkg_find(client, pkgdep->package); 1419 if (pkg == NULL) 1420 { 1421 if (client->flags & PKGCONF_PKG_PKGF_SKIP_PROVIDES) 1422 { 1423 if (eflags != NULL) 1424 *eflags |= PKGCONF_PKG_ERRF_PACKAGE_NOT_FOUND; 1425 1426 return NULL; 1427 } 1428 1429 pkg = pkgconf_pkg_scan_providers(client, pkgdep, eflags); 1430 } 1431 else 1432 { 1433 if (pkg->id == NULL) 1434 pkg->id = strdup(pkgdep->package); 1435 1436 if (pkgconf_pkg_comparator_impls[pkgdep->compare](pkg->version, pkgdep->version) != true) 1437 { 1438 if (eflags != NULL) 1439 *eflags |= PKGCONF_PKG_ERRF_PACKAGE_VER_MISMATCH; 1440 } 1441 else 1442 pkgdep->match = pkgconf_pkg_ref(client, pkg); 1443 } 1444 1445 if (pkg != NULL && pkg->why == NULL) 1446 pkg->why = strdup(pkgdep->package); 1447 1448 return pkg; 1449 } 1450 1451 /* 1452 * !doc 1453 * 1454 * .. c:function:: unsigned int pkgconf_pkg_verify_graph(pkgconf_client_t *client, pkgconf_pkg_t *root, int depth) 1455 * 1456 * Verify the graph dependency nodes are satisfiable by walking the tree using 1457 * ``pkgconf_pkg_traverse()``. 1458 * 1459 * :param pkgconf_client_t* client: The pkgconf client object to use for dependency resolution. 1460 * :param pkgconf_pkg_t* root: The root entry in the package dependency graph which should contain the top-level dependencies to resolve. 1461 * :param int depth: The maximum allowed depth for dependency resolution. 1462 * :return: On success, ``PKGCONF_PKG_ERRF_OK`` (0), else an error code. 1463 * :rtype: unsigned int 1464 */ 1465 unsigned int 1466 pkgconf_pkg_verify_graph(pkgconf_client_t *client, pkgconf_pkg_t *root, int depth) 1467 { 1468 return pkgconf_pkg_traverse(client, root, NULL, NULL, depth, 0); 1469 } 1470 1471 static unsigned int 1472 pkgconf_pkg_report_graph_error(pkgconf_client_t *client, pkgconf_pkg_t *parent, pkgconf_pkg_t *pkg, pkgconf_dependency_t *node, unsigned int eflags) 1473 { 1474 if (eflags & PKGCONF_PKG_ERRF_PACKAGE_NOT_FOUND) 1475 { 1476 if (!(client->flags & PKGCONF_PKG_PKGF_SIMPLIFY_ERRORS) && !client->already_sent_notice) 1477 { 1478 pkgconf_error(client, "Package %s was not found in the pkg-config search path.\n", node->package); 1479 pkgconf_error(client, "Perhaps you should add the directory containing `%s.pc'\n", node->package); 1480 pkgconf_error(client, "to the PKG_CONFIG_PATH environment variable\n"); 1481 client->already_sent_notice = true; 1482 } 1483 1484 if (parent->flags & PKGCONF_PKG_PROPF_VIRTUAL) 1485 pkgconf_error(client, "Package '%s' not found\n", node->package); 1486 else 1487 pkgconf_error(client, "Package '%s', required by '%s', not found\n", node->package, parent->id); 1488 1489 pkgconf_audit_log(client, "%s NOT-FOUND\n", node->package); 1490 } 1491 else if (eflags & PKGCONF_PKG_ERRF_PACKAGE_VER_MISMATCH) 1492 { 1493 pkgconf_error(client, "Package dependency requirement '%s %s %s' could not be satisfied.\n", 1494 node->package, pkgconf_pkg_get_comparator(node), node->version); 1495 1496 if (pkg != NULL) 1497 pkgconf_error(client, "Package '%s' has version '%s', required version is '%s %s'\n", 1498 node->package, pkg->version, pkgconf_pkg_get_comparator(node), node->version); 1499 } 1500 1501 if (pkg != NULL) 1502 pkgconf_pkg_unref(client, pkg); 1503 1504 return eflags; 1505 } 1506 1507 static inline bool 1508 missing_node_is_tolerable(const pkgconf_client_t *client, const pkgconf_dependency_t *dep) 1509 { 1510 if (!(dep->flags & PKGCONF_PKG_DEPF_INTERNAL)) 1511 return false; 1512 1513 if ((client->flags & PKGCONF_PKG_PKGF_REQUIRE_INTERNAL)) 1514 return false; 1515 1516 return true; 1517 } 1518 1519 static inline unsigned int 1520 pkgconf_pkg_walk_list(pkgconf_client_t *client, 1521 pkgconf_pkg_t *parent, 1522 pkgconf_list_t *deplist, 1523 pkgconf_pkg_traverse_func_t func, 1524 void *data, 1525 int depth, 1526 unsigned int skip_flags) 1527 { 1528 unsigned int eflags = PKGCONF_PKG_ERRF_OK; 1529 pkgconf_node_t *node, *next; 1530 1531 parent->flags |= PKGCONF_PKG_PROPF_ANCESTOR; 1532 1533 PKGCONF_FOREACH_LIST_ENTRY_SAFE(deplist->head, next, node) 1534 { 1535 unsigned int eflags_local = PKGCONF_PKG_ERRF_OK; 1536 pkgconf_dependency_t *depnode = node->data; 1537 pkgconf_pkg_t *pkgdep; 1538 1539 if (*depnode->package == '\0') 1540 continue; 1541 1542 pkgdep = pkgconf_pkg_verify_dependency(client, depnode, &eflags_local); 1543 if (eflags_local != PKGCONF_PKG_ERRF_OK) 1544 { 1545 if (missing_node_is_tolerable(client, depnode)) 1546 continue; 1547 1548 if (!(client->flags & PKGCONF_PKG_PKGF_SKIP_ERRORS)) 1549 pkgconf_pkg_report_graph_error(client, parent, pkgdep, depnode, eflags_local); 1550 1551 eflags |= eflags_local; 1552 continue; 1553 } 1554 1555 if((pkgdep->flags & PKGCONF_PKG_PROPF_ANCESTOR) != 0) 1556 { 1557 /* In this case we have a circular reference. 1558 * We break that by deleteing the circular node from the 1559 * the list, so that we dont create a situation where 1560 * memory is leaked due to circular ownership. 1561 * i.e: A owns B owns A 1562 * 1563 * TODO(ariadne): Breaking circular references between Requires and Requires.private 1564 * lists causes problems. Find a way to refactor the Requires.private list out. 1565 */ 1566 if (!(depnode->flags & PKGCONF_PKG_DEPF_PRIVATE) && 1567 !(depnode->flags & PKGCONF_PKG_DEPF_SHARED) && 1568 !(parent->flags & PKGCONF_PKG_PROPF_VIRTUAL)) 1569 { 1570 pkgconf_warn(client, "%s: breaking circular reference (%s -> %s -> %s)\n", 1571 parent->id, parent->id, pkgdep->id, parent->id); 1572 1573 pkgconf_node_delete(node, deplist); 1574 pkgconf_dependency_unref(client, depnode); 1575 } 1576 1577 goto next; 1578 } 1579 1580 if (skip_flags && (depnode->flags & skip_flags) == skip_flags) 1581 goto next; 1582 1583 pkgconf_audit_log_dependency(client, pkgdep, depnode); 1584 1585 eflags |= pkgconf_pkg_traverse_main(client, pkgdep, func, data, depth - 1, skip_flags); 1586 next: 1587 pkgconf_pkg_unref(client, pkgdep); 1588 } 1589 1590 parent->flags &= ~PKGCONF_PKG_PROPF_ANCESTOR; 1591 1592 return eflags; 1593 } 1594 1595 unsigned int 1596 pkgconf_pkg_walk_conflicts_list(pkgconf_client_t *client, 1597 pkgconf_pkg_t *root, pkgconf_list_t *deplist) 1598 { 1599 unsigned int eflags; 1600 pkgconf_node_t *node, *childnode; 1601 1602 PKGCONF_FOREACH_LIST_ENTRY(deplist->head, node) 1603 { 1604 pkgconf_dependency_t *parentnode = node->data; 1605 1606 if (*parentnode->package == '\0') 1607 continue; 1608 1609 PKGCONF_FOREACH_LIST_ENTRY(root->required.head, childnode) 1610 { 1611 pkgconf_pkg_t *pkgdep; 1612 pkgconf_dependency_t *depnode = childnode->data; 1613 1614 if (*depnode->package == '\0' || strcmp(depnode->package, parentnode->package)) 1615 continue; 1616 1617 pkgdep = pkgconf_pkg_verify_dependency(client, parentnode, &eflags); 1618 if (eflags == PKGCONF_PKG_ERRF_OK) 1619 { 1620 pkgconf_error(client, "Version '%s' of '%s' conflicts with '%s' due to satisfying conflict rule '%s %s%s%s'.\n", 1621 pkgdep->version, pkgdep->id, parentnode->why, parentnode->package, pkgconf_pkg_get_comparator(parentnode), 1622 parentnode->version != NULL ? " " : "", parentnode->version != NULL ? parentnode->version : ""); 1623 1624 if (!(client->flags & PKGCONF_PKG_PKGF_SIMPLIFY_ERRORS)) 1625 { 1626 pkgconf_error(client, "It may be possible to ignore this conflict and continue, try the\n"); 1627 pkgconf_error(client, "PKG_CONFIG_IGNORE_CONFLICTS environment variable.\n"); 1628 } 1629 1630 pkgconf_pkg_unref(client, pkgdep); 1631 1632 return PKGCONF_PKG_ERRF_PACKAGE_CONFLICT; 1633 } 1634 1635 pkgconf_pkg_unref(client, pkgdep); 1636 } 1637 } 1638 1639 return PKGCONF_PKG_ERRF_OK; 1640 } 1641 1642 /* 1643 * !doc 1644 * 1645 * .. 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) 1646 * 1647 * Walk and resolve the dependency graph up to `maxdepth` levels. 1648 * 1649 * :param pkgconf_client_t* client: The pkgconf client object to use for dependency resolution. 1650 * :param pkgconf_pkg_t* root: The root of the dependency graph. 1651 * :param pkgconf_pkg_traverse_func_t func: A traversal function to call for each resolved node in the dependency graph. 1652 * :param void* data: An opaque pointer to data to be passed to the traversal function. 1653 * :param int maxdepth: The maximum depth to walk the dependency graph for. -1 means infinite recursion. 1654 * :param uint skip_flags: Skip over dependency nodes containing the specified flags. A setting of 0 skips no dependency nodes. 1655 * :return: ``PKGCONF_PKG_ERRF_OK`` on success, else an error code. 1656 * :rtype: unsigned int 1657 */ 1658 static unsigned int 1659 pkgconf_pkg_traverse_main(pkgconf_client_t *client, 1660 pkgconf_pkg_t *root, 1661 pkgconf_pkg_traverse_func_t func, 1662 void *data, 1663 int maxdepth, 1664 unsigned int skip_flags) 1665 { 1666 unsigned int eflags = PKGCONF_PKG_ERRF_OK; 1667 1668 if (maxdepth == 0) 1669 return eflags; 1670 1671 /* Short-circuit if we have already visited this node. 1672 */ 1673 if (root->serial == client->serial) 1674 return eflags; 1675 1676 root->serial = client->serial; 1677 1678 if (root->identifier == 0) 1679 root->identifier = ++client->identifier; 1680 1681 PKGCONF_TRACE(client, "%s: level %d, serial %llu", root->id, maxdepth, (unsigned long long) client->serial); 1682 1683 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) 1684 { 1685 if (func != NULL) 1686 func(client, root, data); 1687 } 1688 1689 if (!(client->flags & PKGCONF_PKG_PKGF_SKIP_CONFLICTS) && root->conflicts.head != NULL) 1690 { 1691 PKGCONF_TRACE(client, "%s: walking 'Conflicts' list", root->id); 1692 1693 eflags = pkgconf_pkg_walk_conflicts_list(client, root, &root->conflicts); 1694 if (eflags != PKGCONF_PKG_ERRF_OK) 1695 return eflags; 1696 } 1697 1698 PKGCONF_TRACE(client, "%s: walking 'Requires' list", root->id); 1699 eflags = pkgconf_pkg_walk_list(client, root, &root->required, func, data, maxdepth, skip_flags); 1700 if (eflags != PKGCONF_PKG_ERRF_OK) 1701 return eflags; 1702 1703 if (!(client->flags & PKGCONF_PKG_PKGF_MERGE_PRIVATE_FRAGMENTS)) 1704 { 1705 PKGCONF_TRACE(client, "%s: walking 'Requires.shared' list", root->id); 1706 1707 eflags = pkgconf_pkg_walk_list(client, root, &root->requires_shared, func, data, maxdepth, skip_flags); 1708 if (eflags != PKGCONF_PKG_ERRF_OK) 1709 return eflags; 1710 } 1711 1712 PKGCONF_TRACE(client, "%s: walking 'Requires.private' list", root->id); 1713 1714 /* XXX: ugly */ 1715 client->flags |= PKGCONF_PKG_PKGF_ITER_PKG_IS_PRIVATE; 1716 eflags = pkgconf_pkg_walk_list(client, root, &root->requires_private, func, data, maxdepth, skip_flags); 1717 client->flags &= ~PKGCONF_PKG_PKGF_ITER_PKG_IS_PRIVATE; 1718 1719 if (eflags != PKGCONF_PKG_ERRF_OK) 1720 return eflags; 1721 1722 return eflags; 1723 } 1724 1725 unsigned int 1726 pkgconf_pkg_traverse(pkgconf_client_t *client, 1727 pkgconf_pkg_t *root, 1728 pkgconf_pkg_traverse_func_t func, 1729 void *data, 1730 int maxdepth, 1731 unsigned int skip_flags) 1732 { 1733 if (root->flags & PKGCONF_PKG_PROPF_VIRTUAL) 1734 client->serial++; 1735 1736 if ((client->flags & PKGCONF_PKG_PKGF_SEARCH_PRIVATE) == 0) 1737 { 1738 skip_flags |= PKGCONF_PKG_DEPF_PRIVATE; 1739 } 1740 1741 if (client->flags & PKGCONF_PKG_PKGF_MERGE_PRIVATE_FRAGMENTS) 1742 // Skip shared deps in static mode 1743 skip_flags |= PKGCONF_PKG_DEPF_SHARED; 1744 1745 return pkgconf_pkg_traverse_main(client, root, func, data, maxdepth, skip_flags); 1746 } 1747 1748 static void 1749 pkgconf_pkg_cflags_collect(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data) 1750 { 1751 pkgconf_list_t *list = data; 1752 pkgconf_node_t *node; 1753 1754 PKGCONF_FOREACH_LIST_ENTRY(pkg->cflags.head, node) 1755 { 1756 pkgconf_fragment_t *frag = node->data; 1757 pkgconf_fragment_copy(client, list, frag, false); 1758 } 1759 } 1760 1761 static void 1762 pkgconf_pkg_cflags_private_collect(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data) 1763 { 1764 pkgconf_list_t *list = data; 1765 pkgconf_node_t *node; 1766 1767 PKGCONF_FOREACH_LIST_ENTRY(pkg->cflags_private.head, node) 1768 { 1769 pkgconf_fragment_t *frag = node->data; 1770 pkgconf_fragment_copy(client, list, frag, true); 1771 } 1772 } 1773 1774 static void 1775 pkgconf_pkg_cflags_shared_collect(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data) 1776 { 1777 pkgconf_list_t *list = data; 1778 pkgconf_node_t *node; 1779 1780 PKGCONF_FOREACH_LIST_ENTRY(pkg->cflags_shared.head, node) 1781 { 1782 pkgconf_fragment_t *frag = node->data; 1783 pkgconf_fragment_copy(client, list, frag, true); 1784 } 1785 } 1786 1787 /* 1788 * !doc 1789 * 1790 * .. c:function:: int pkgconf_pkg_cflags(pkgconf_client_t *client, pkgconf_pkg_t *root, pkgconf_list_t *list, int maxdepth) 1791 * 1792 * Walks a dependency graph and extracts relevant ``CFLAGS`` fragments. 1793 * 1794 * :param pkgconf_client_t* client: The pkgconf client object to use for dependency resolution. 1795 * :param pkgconf_pkg_t* root: The root of the dependency graph. 1796 * :param pkgconf_list_t* list: The fragment list to add the extracted ``CFLAGS`` fragments to. 1797 * :param int maxdepth: The maximum allowed depth for dependency resolution. -1 means infinite recursion. 1798 * :return: ``PKGCONF_PKG_ERRF_OK`` if successful, otherwise an error code. 1799 * :rtype: unsigned int 1800 */ 1801 unsigned int 1802 pkgconf_pkg_cflags(pkgconf_client_t *client, pkgconf_pkg_t *root, pkgconf_list_t *list, int maxdepth) 1803 { 1804 unsigned int eflag; 1805 unsigned int skip_flags = (client->flags & PKGCONF_PKG_PKGF_DONT_FILTER_INTERNAL_CFLAGS) == 0 ? PKGCONF_PKG_DEPF_INTERNAL : 0; 1806 pkgconf_list_t frags = PKGCONF_LIST_INITIALIZER; 1807 1808 eflag = pkgconf_pkg_traverse(client, root, pkgconf_pkg_cflags_collect, &frags, maxdepth, skip_flags); 1809 1810 if (eflag == PKGCONF_PKG_ERRF_OK) 1811 { 1812 if (client->flags & PKGCONF_PKG_PKGF_MERGE_PRIVATE_FRAGMENTS) 1813 { 1814 eflag = pkgconf_pkg_traverse(client, root, pkgconf_pkg_cflags_private_collect, &frags, maxdepth, skip_flags); 1815 } 1816 else 1817 { 1818 eflag = pkgconf_pkg_traverse(client, root, pkgconf_pkg_cflags_shared_collect, &frags, maxdepth, skip_flags); 1819 } 1820 } 1821 1822 if (eflag != PKGCONF_PKG_ERRF_OK) 1823 { 1824 pkgconf_fragment_free(&frags); 1825 return eflag; 1826 } 1827 1828 pkgconf_fragment_copy_list(client, list, &frags); 1829 pkgconf_fragment_free(&frags); 1830 1831 return eflag; 1832 } 1833 1834 static void 1835 pkgconf_pkg_libs_collect(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data) 1836 { 1837 pkgconf_list_t *list = data; 1838 pkgconf_node_t *node; 1839 1840 if (!(client->flags & PKGCONF_PKG_PKGF_SEARCH_PRIVATE) && pkg->flags & PKGCONF_PKG_PROPF_VISITED_PRIVATE) 1841 return; 1842 1843 PKGCONF_FOREACH_LIST_ENTRY(pkg->libs.head, node) 1844 { 1845 pkgconf_fragment_t *frag = node->data; 1846 pkgconf_fragment_copy(client, list, frag, (client->flags & PKGCONF_PKG_PKGF_ITER_PKG_IS_PRIVATE) != 0); 1847 } 1848 1849 if (client->flags & PKGCONF_PKG_PKGF_MERGE_PRIVATE_FRAGMENTS) 1850 { 1851 PKGCONF_FOREACH_LIST_ENTRY(pkg->libs_private.head, node) 1852 { 1853 pkgconf_fragment_t *frag = node->data; 1854 pkgconf_fragment_copy(client, list, frag, true); 1855 } 1856 } 1857 else 1858 { 1859 PKGCONF_FOREACH_LIST_ENTRY(pkg->libs_shared.head, node) 1860 { 1861 pkgconf_fragment_t *frag = node->data; 1862 pkgconf_fragment_copy(client, list, frag, true); 1863 } 1864 } 1865 } 1866 1867 /* 1868 * !doc 1869 * 1870 * .. c:function:: int pkgconf_pkg_libs(pkgconf_client_t *client, pkgconf_pkg_t *root, pkgconf_list_t *list, int maxdepth) 1871 * 1872 * Walks a dependency graph and extracts relevant ``LIBS`` fragments. 1873 * 1874 * :param pkgconf_client_t* client: The pkgconf client object to use for dependency resolution. 1875 * :param pkgconf_pkg_t* root: The root of the dependency graph. 1876 * :param pkgconf_list_t* list: The fragment list to add the extracted ``LIBS`` fragments to. 1877 * :param int maxdepth: The maximum allowed depth for dependency resolution. -1 means infinite recursion. 1878 * :return: ``PKGCONF_PKG_ERRF_OK`` if successful, otherwise an error code. 1879 * :rtype: unsigned int 1880 */ 1881 unsigned int 1882 pkgconf_pkg_libs(pkgconf_client_t *client, pkgconf_pkg_t *root, pkgconf_list_t *list, int maxdepth) 1883 { 1884 unsigned int eflag; 1885 1886 eflag = pkgconf_pkg_traverse(client, root, pkgconf_pkg_libs_collect, list, maxdepth, 0); 1887 1888 if (eflag != PKGCONF_PKG_ERRF_OK) 1889 { 1890 pkgconf_fragment_free(list); 1891 return eflag; 1892 } 1893 1894 return eflag; 1895 } 1896 1897 static void 1898 pkgconf_pkg_link_abi_collect(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data) 1899 { 1900 pkgconf_list_t *list = data; 1901 pkgconf_node_t *node; 1902 1903 if (!(client->flags & PKGCONF_PKG_PKGF_SEARCH_PRIVATE) && pkg->flags & PKGCONF_PKG_PROPF_VISITED_PRIVATE) 1904 return; 1905 1906 PKGCONF_FOREACH_LIST_ENTRY(pkg->link_abi.head, node) 1907 { 1908 pkgconf_bufferset_t *tag = node->data; 1909 pkgconf_node_t *iter; 1910 bool seen = false; 1911 1912 PKGCONF_FOREACH_LIST_ENTRY(list->head, iter) 1913 { 1914 pkgconf_bufferset_t *existing = iter->data; 1915 1916 if (pkgconf_buffer_match(&existing->buffer, &tag->buffer)) 1917 { 1918 seen = true; 1919 break; 1920 } 1921 } 1922 1923 if (!seen) 1924 pkgconf_bufferset_extend(list, &tag->buffer); 1925 } 1926 } 1927 1928 /* 1929 * !doc 1930 * 1931 * .. c:function:: int pkgconf_pkg_link_abi(pkgconf_client_t *client, pkgconf_pkg_t *root, pkgconf_list_t *list, int maxdepth) 1932 * 1933 * Walks a dependency graph and collects the union of ``Link.ABI`` tags. 1934 * 1935 * The tags describe the ABI a consumer must link the module against. They 1936 * are gathered over the same closure as ``LIBS``: the module's own tags and 1937 * those of its public ``Requires`` always contribute, while ``Requires.private`` 1938 * tags contribute only when private dependencies are being linked (i.e. a 1939 * static link). Unlike a runtime library load, ABI compatibility of the 1940 * exposed interface applies equally to shared and static linking. 1941 * 1942 * :param pkgconf_client_t* client: The pkgconf client object to use for dependency resolution. 1943 * :param pkgconf_pkg_t* root: The root of the dependency graph. 1944 * :param pkgconf_list_t* list: The bufferset list to add the collected ``Link.ABI`` tags to. 1945 * :param int maxdepth: The maximum allowed depth for dependency resolution. -1 means infinite recursion. 1946 * :return: ``PKGCONF_PKG_ERRF_OK`` if successful, otherwise an error code. 1947 * :rtype: unsigned int 1948 */ 1949 unsigned int 1950 pkgconf_pkg_link_abi(pkgconf_client_t *client, pkgconf_pkg_t *root, pkgconf_list_t *list, int maxdepth) 1951 { 1952 unsigned int eflag; 1953 1954 eflag = pkgconf_pkg_traverse(client, root, pkgconf_pkg_link_abi_collect, list, maxdepth, 0); 1955 1956 if (eflag != PKGCONF_PKG_ERRF_OK) 1957 { 1958 pkgconf_bufferset_free(list); 1959 return eflag; 1960 } 1961 1962 return eflag; 1963 } 1964