1 /* 2 * core.c 3 * core, printer functions 4 * 5 * SPDX-License-Identifier: pkgconf 6 * 7 * Copyright (c) 2011-2025 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 "core.h" 22 #include "getopt_long.h" 23 #ifndef PKGCONF_LITE 24 #include "renderer-msvc.h" 25 #endif 26 27 static bool 28 print_list_entry(const pkgconf_pkg_t *entry, void *data) 29 { 30 const pkgconf_node_t *n; 31 pkgconf_client_t *client = data; 32 33 if (entry->flags & PKGCONF_PKG_PROPF_UNINSTALLED) 34 return false; 35 36 pkgconf_output_fmt(client->output, PKGCONF_OUTPUT_STDOUT, 37 "%-30s %s - %s\n", entry->id, entry->realname, entry->description); 38 39 PKGCONF_FOREACH_LIST_ENTRY(entry->provides.head, n) 40 { 41 const pkgconf_dependency_t *dep = n->data; 42 43 if (!strcmp(dep->package, entry->id)) 44 continue; 45 46 pkgconf_output_fmt(client->output, PKGCONF_OUTPUT_STDOUT, 47 "%-30s %s - %s (provided by %s)\n", dep->package, entry->realname, entry->description, entry->id); 48 } 49 50 return false; 51 } 52 53 static bool 54 print_package_entry(const pkgconf_pkg_t *entry, void *data) 55 { 56 const pkgconf_node_t *n; 57 pkgconf_client_t *client = data; 58 59 if (entry->flags & PKGCONF_PKG_PROPF_UNINSTALLED) 60 return false; 61 62 pkgconf_output_puts(client->output, PKGCONF_OUTPUT_STDOUT, entry->id); 63 64 PKGCONF_FOREACH_LIST_ENTRY(entry->provides.head, n) 65 { 66 const pkgconf_dependency_t *dep = n->data; 67 68 if (!strcmp(dep->package, entry->id)) 69 continue; 70 71 pkgconf_output_puts(client->output, PKGCONF_OUTPUT_STDOUT, dep->package); 72 } 73 74 return false; 75 } 76 77 static bool 78 filter_cflags(const pkgconf_client_t *client, const pkgconf_fragment_t *frag, void *data) 79 { 80 int got_flags = 0; 81 pkgconf_cli_state_t *state = client->client_data; 82 (void) data; 83 84 if (!(state->want_flags & PKG_KEEP_SYSTEM_CFLAGS) && pkgconf_fragment_has_system_dir(client, frag)) 85 return false; 86 87 if (state->want_fragment_filter != NULL && (strchr(state->want_fragment_filter, frag->type) == NULL || !frag->type)) 88 return false; 89 90 if (frag->type == 'I') 91 got_flags = PKG_CFLAGS_ONLY_I; 92 else 93 got_flags = PKG_CFLAGS_ONLY_OTHER; 94 95 return (state->want_flags & got_flags) != 0; 96 } 97 98 static bool 99 filter_libs(const pkgconf_client_t *client, const pkgconf_fragment_t *frag, void *data) 100 { 101 int got_flags = 0; 102 pkgconf_cli_state_t *state = client->client_data; 103 (void) data; 104 105 if (!(state->want_flags & PKG_KEEP_SYSTEM_LIBS) && pkgconf_fragment_has_system_dir(client, frag)) 106 return false; 107 108 if (state->want_fragment_filter != NULL && (strchr(state->want_fragment_filter, frag->type) == NULL || !frag->type)) 109 return false; 110 111 switch (frag->type) 112 { 113 case 'L': got_flags = PKG_LIBS_ONLY_LDPATH; break; 114 case 'l': got_flags = PKG_LIBS_ONLY_LIBNAME; break; 115 default: got_flags = PKG_LIBS_ONLY_OTHER; break; 116 } 117 118 return (state->want_flags & got_flags) != 0; 119 } 120 121 static void 122 print_variables(pkgconf_output_t *output, pkgconf_pkg_t *pkg) 123 { 124 pkgconf_node_t *node; 125 126 PKGCONF_FOREACH_LIST_ENTRY(pkg->vars.head, node) 127 { 128 pkgconf_tuple_t *tuple = node->data; 129 130 pkgconf_output_puts(output, PKGCONF_OUTPUT_STDOUT, tuple->key); 131 } 132 } 133 134 static void 135 print_dependency_list(pkgconf_output_t *output, pkgconf_list_t *list) 136 { 137 pkgconf_node_t *node; 138 139 PKGCONF_FOREACH_LIST_ENTRY(list->head, node) 140 { 141 pkgconf_dependency_t *dep = node->data; 142 143 pkgconf_output_fmt(output, PKGCONF_OUTPUT_STDOUT, "%s", dep->package); 144 145 if (dep->version != NULL) 146 pkgconf_output_fmt(output, PKGCONF_OUTPUT_STDOUT, " %s %s", 147 pkgconf_pkg_get_comparator(dep), dep->version); 148 149 pkgconf_output_fmt(output, PKGCONF_OUTPUT_STDOUT, "\n"); 150 } 151 } 152 153 static bool 154 apply_provides(pkgconf_client_t *client, pkgconf_pkg_t *world, void *unused, int maxdepth) 155 { 156 pkgconf_node_t *iter; 157 (void) unused; 158 (void) maxdepth; 159 160 PKGCONF_FOREACH_LIST_ENTRY(world->required.head, iter) 161 { 162 pkgconf_dependency_t *dep = iter->data; 163 pkgconf_pkg_t *pkg = dep->match; 164 165 print_dependency_list(client->output, &pkg->provides); 166 } 167 168 return true; 169 } 170 171 #ifndef PKGCONF_LITE 172 static void 173 print_digraph_node(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data) 174 { 175 pkgconf_node_t *node; 176 pkgconf_pkg_t **last_seen = data; 177 178 if (pkg->flags & PKGCONF_PKG_PROPF_VIRTUAL) 179 return; 180 181 pkgconf_output_fmt(client->output, PKGCONF_OUTPUT_STDOUT, "\"%s\" [fontname=Sans fontsize=8", pkg->id); 182 183 if (pkg->flags & PKGCONF_PKG_PROPF_VISITED_PRIVATE) 184 pkgconf_output_fmt(client->output, PKGCONF_OUTPUT_STDOUT, " fontcolor=gray color=gray"); 185 186 pkgconf_output_fmt(client->output, PKGCONF_OUTPUT_STDOUT, " label=\"%s@%s\"]\n", pkg->id, pkg->version); 187 188 if (last_seen != NULL) 189 { 190 if (*last_seen != NULL) 191 pkgconf_output_fmt(client->output, PKGCONF_OUTPUT_STDOUT, 192 "\"%s\" -> \"%s\" [fontname=Sans fontsize=8 color=red]\n", (*last_seen)->id, pkg->id); 193 194 *last_seen = pkg; 195 } 196 197 PKGCONF_FOREACH_LIST_ENTRY(pkg->required.head, node) 198 { 199 pkgconf_dependency_t *dep = node->data; 200 const char *dep_id = (dep->match != NULL) ? dep->match->id : dep->package; 201 202 pkgconf_output_fmt(client->output, PKGCONF_OUTPUT_STDOUT, "\"%s\" -> \"%s\" [fontname=Sans fontsize=8", 203 pkg->id, dep_id); 204 205 if (dep->flags & PKGCONF_PKG_DEPF_PRIVATE) 206 pkgconf_output_fmt(client->output, PKGCONF_OUTPUT_STDOUT, " color=gray"); 207 208 pkgconf_output_puts(client->output, PKGCONF_OUTPUT_STDOUT, "]"); 209 } 210 211 PKGCONF_FOREACH_LIST_ENTRY(pkg->requires_private.head, node) 212 { 213 pkgconf_dependency_t *dep = node->data; 214 const char *dep_id = (dep->match != NULL) ? dep->match->id : dep->package; 215 216 pkgconf_output_fmt(client->output, PKGCONF_OUTPUT_STDOUT, 217 "\"%s\" -> \"%s\" [fontname=Sans fontsize=8 color=gray]\n", pkg->id, dep_id); 218 } 219 220 if (!(client->flags & PKGCONF_PKG_PKGF_MERGE_PRIVATE_FRAGMENTS)) 221 { 222 PKGCONF_FOREACH_LIST_ENTRY(pkg->requires_shared.head, node) 223 { 224 pkgconf_dependency_t *dep = node->data; 225 const char *dep_id = (dep->match != NULL) ? dep->match->id : dep->package; 226 pkgconf_output_fmt(client->output, PKGCONF_OUTPUT_STDOUT, 227 "\"%s\" -> \"%s\" [fontname=Sans fontsize=8 color=orange]\n", pkg->id, dep_id); 228 } 229 } 230 } 231 232 static bool 233 apply_digraph(pkgconf_client_t *client, pkgconf_pkg_t *world, void *data, int maxdepth) 234 { 235 int eflag; 236 pkgconf_cli_state_t *state = client->client_data; 237 pkgconf_list_t *list = data; 238 pkgconf_pkg_t *last_seen = NULL; 239 pkgconf_node_t *iter; 240 241 pkgconf_output_puts(client->output, PKGCONF_OUTPUT_STDOUT, 242 "digraph deptree {\n" 243 "edge [color=blue len=7.5 fontname=Sans fontsize=8]\n" 244 "node [fontname=Sans fontsize=8]\n"); 245 246 if (state->want_flags & PKG_PRINT_DIGRAPH_QUERY_NODES) 247 { 248 pkgconf_output_puts(client->output, PKGCONF_OUTPUT_STDOUT, 249 "\"user:request\" [fontname=Sans fontsize=8]\n"); 250 251 PKGCONF_FOREACH_LIST_ENTRY(list->head, iter) 252 { 253 pkgconf_queue_t *pkgq = iter->data; 254 pkgconf_pkg_t *pkg = pkgconf_pkg_find(client, pkgq->package); 255 256 pkgconf_output_fmt(client->output, PKGCONF_OUTPUT_STDOUT, 257 "\"user:request\" -> \"%s\" [fontname=Sans fontsize=8]\n", 258 pkg == NULL ? pkgq->package : pkg->id); 259 260 if (pkg != NULL) 261 pkgconf_pkg_unref(client, pkg); 262 } 263 } 264 265 eflag = pkgconf_pkg_traverse(client, world, print_digraph_node, &last_seen, maxdepth, 0); 266 267 if (eflag != PKGCONF_PKG_ERRF_OK) 268 return false; 269 270 pkgconf_output_puts(client->output, PKGCONF_OUTPUT_STDOUT, "}"); 271 return true; 272 } 273 274 static void 275 print_solution_node(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *unused) 276 { 277 (void) unused; 278 279 pkgconf_output_fmt(client->output, PKGCONF_OUTPUT_STDOUT, "%s (%llu)%s\n", 280 pkg->id, (unsigned long long) pkg->identifier, 281 (pkg->flags & PKGCONF_PKG_PROPF_VISITED_PRIVATE) == PKGCONF_PKG_PROPF_VISITED_PRIVATE ? " [private]" : ""); 282 } 283 284 static bool 285 apply_print_solution(pkgconf_client_t *client, pkgconf_pkg_t *world, void *unused, int maxdepth) 286 { 287 int eflag; 288 289 eflag = pkgconf_pkg_traverse(client, world, print_solution_node, unused, maxdepth, 0); 290 291 return eflag == PKGCONF_PKG_ERRF_OK; 292 } 293 #endif 294 295 static bool 296 apply_modversion(pkgconf_client_t *client, pkgconf_pkg_t *world, void *data, int maxdepth) 297 { 298 pkgconf_cli_state_t *state = client->client_data; 299 pkgconf_node_t *queue_iter; 300 pkgconf_list_t *pkgq = data; 301 (void) maxdepth; 302 303 PKGCONF_FOREACH_LIST_ENTRY(pkgq->head, queue_iter) 304 { 305 pkgconf_node_t *world_iter; 306 pkgconf_queue_t *queue_node = queue_iter->data; 307 308 PKGCONF_FOREACH_LIST_ENTRY(world->required.head, world_iter) 309 { 310 pkgconf_dependency_t *dep = world_iter->data; 311 pkgconf_pkg_t *pkg = dep->match; 312 313 const size_t name_len = strlen(pkg->why); 314 if (name_len > strlen(queue_node->package) || 315 strncmp(pkg->why, queue_node->package, name_len) || 316 (queue_node->package[name_len] != 0 && 317 !isspace((unsigned char)queue_node->package[name_len]) && 318 !PKGCONF_IS_OPERATOR_CHAR(queue_node->package[name_len]))) 319 { 320 continue; 321 } 322 323 if (pkg->version != NULL) { 324 if (state->verbosity) 325 pkgconf_output_fmt(client->output, PKGCONF_OUTPUT_STDOUT, "%s: ", pkg->id); 326 327 pkgconf_output_puts(client->output, PKGCONF_OUTPUT_STDOUT, pkg->version); 328 } 329 330 break; 331 } 332 } 333 334 return true; 335 } 336 337 static bool 338 apply_variables(pkgconf_client_t *client, pkgconf_pkg_t *world, void *unused, int maxdepth) 339 { 340 pkgconf_node_t *iter; 341 (void) unused; 342 (void) maxdepth; 343 344 PKGCONF_FOREACH_LIST_ENTRY(world->required.head, iter) 345 { 346 pkgconf_dependency_t *dep = iter->data; 347 pkgconf_pkg_t *pkg = dep->match; 348 349 print_variables(client->output, pkg); 350 } 351 352 return true; 353 } 354 355 static bool 356 apply_path(pkgconf_client_t *client, pkgconf_pkg_t *world, void *unused, int maxdepth) 357 { 358 pkgconf_node_t *iter; 359 (void) unused; 360 (void) maxdepth; 361 362 PKGCONF_FOREACH_LIST_ENTRY(world->required.head, iter) 363 { 364 pkgconf_dependency_t *dep = iter->data; 365 pkgconf_pkg_t *pkg = dep->match; 366 367 /* a module entry with no filename is either virtual, static (builtin) or synthesized. */ 368 if (pkg->filename != NULL) 369 pkgconf_output_puts(client->output, PKGCONF_OUTPUT_STDOUT, pkg->filename); 370 } 371 372 return true; 373 } 374 375 static char * 376 variable_eval(pkgconf_client_t *client, const pkgconf_list_t *vars, const char *varname) 377 { 378 pkgconf_buffer_t varbuf = PKGCONF_BUFFER_INITIALIZER; 379 const pkgconf_buffer_t *sysroot_dir = PKGCONF_BUFFER_FROM_STR(client->sysroot_dir); 380 bool saw_sysroot = false; 381 pkgconf_variable_t *v; 382 383 pkgconf_bytecode_eval_ctx_t ctx = { 384 .client = client, 385 .vars = vars, 386 }; 387 388 v = pkgconf_bytecode_eval_lookup_var(&ctx, varname, strlen(varname)); 389 (void) pkgconf_variable_eval(client, vars, v, &varbuf, &saw_sysroot); 390 391 if (!saw_sysroot && pkgconf_path_is_plausible(&varbuf)) 392 { 393 /* if sysroot is set, and value does not already begin with sysroot */ 394 if (!pkgconf_buffer_has_prefix(&varbuf, sysroot_dir)) 395 pkgconf_buffer_prepend(&varbuf, pkgconf_buffer_str_or_empty(sysroot_dir)); 396 } 397 398 return pkgconf_buffer_freeze(&varbuf); 399 } 400 401 static bool 402 apply_variable(pkgconf_client_t *client, pkgconf_pkg_t *world, const void *variable, int maxdepth) 403 { 404 pkgconf_node_t *iter; 405 (void) maxdepth; 406 407 PKGCONF_FOREACH_LIST_ENTRY(world->required.head, iter) 408 { 409 pkgconf_dependency_t *dep = iter->data; 410 pkgconf_pkg_t *pkg = dep->match; 411 char *result; 412 413 if (pkg == NULL) 414 continue; 415 416 result = variable_eval(client, &pkg->vars, variable); 417 418 if (result != NULL) 419 { 420 pkgconf_output_fmt(client->output, PKGCONF_OUTPUT_STDOUT, 421 "%s%s", iter->prev != NULL ? " " : "", result); 422 free(result); 423 } 424 } 425 426 pkgconf_output_puts(client->output, PKGCONF_OUTPUT_STDOUT, ""); 427 428 return true; 429 } 430 431 static bool 432 apply_env_var(const char *prefix, pkgconf_client_t *client, pkgconf_pkg_t *world, int maxdepth, 433 unsigned int (*collect_fn)(pkgconf_client_t *client, pkgconf_pkg_t *world, pkgconf_list_t *list, int maxdepth), 434 bool (*filter_fn)(const pkgconf_client_t *client, const pkgconf_fragment_t *frag, void *data), 435 void (*postprocess_fn)(pkgconf_client_t *client, pkgconf_pkg_t *world, pkgconf_list_t *fragment_list)) 436 { 437 pkgconf_cli_state_t *state = client->client_data; 438 pkgconf_list_t unfiltered_list = PKGCONF_LIST_INITIALIZER; 439 pkgconf_list_t filtered_list = PKGCONF_LIST_INITIALIZER; 440 pkgconf_buffer_t render_buf = PKGCONF_BUFFER_INITIALIZER; 441 unsigned int eflag; 442 443 eflag = collect_fn(client, world, &unfiltered_list, maxdepth); 444 if (eflag != PKGCONF_PKG_ERRF_OK) 445 return false; 446 447 pkgconf_fragment_filter(client, &filtered_list, &unfiltered_list, filter_fn, NULL); 448 449 if (postprocess_fn != NULL) 450 postprocess_fn(client, world, &filtered_list); 451 452 if (filtered_list.head == NULL) 453 goto out; 454 455 pkgconf_fragment_render_buf(&filtered_list, &render_buf, true, state->want_render_ops, (state->want_flags & PKG_NEWLINES) ? '\n' : ' '); 456 pkgconf_output_fmt(client->output, PKGCONF_OUTPUT_STDOUT, "%s='%s'\n", 457 prefix, pkgconf_buffer_str_or_empty(&render_buf)); 458 pkgconf_buffer_finalize(&render_buf); 459 460 out: 461 pkgconf_fragment_free(&unfiltered_list); 462 pkgconf_fragment_free(&filtered_list); 463 464 return true; 465 } 466 467 static void 468 maybe_add_module_definitions(pkgconf_client_t *client, pkgconf_pkg_t *world, pkgconf_list_t *fragment_list) 469 { 470 pkgconf_node_t *world_iter; 471 pkgconf_cli_state_t *state = client->client_data; 472 473 if ((state->want_flags & PKG_EXISTS_CFLAGS) != PKG_EXISTS_CFLAGS) 474 return; 475 476 PKGCONF_FOREACH_LIST_ENTRY(world->required.head, world_iter) 477 { 478 pkgconf_dependency_t *dep = world_iter->data; 479 char havebuf[PKGCONF_ITEM_SIZE]; 480 char *p; 481 482 if ((dep->flags & PKGCONF_PKG_DEPF_QUERY) != PKGCONF_PKG_DEPF_QUERY) 483 continue; 484 485 if (dep->match == NULL) 486 continue; 487 488 snprintf(havebuf, sizeof havebuf, "HAVE_%s", dep->match->id); 489 490 for (p = havebuf; *p; p++) 491 { 492 switch (*p) 493 { 494 case ' ': 495 case '-': 496 *p = '_'; 497 break; 498 499 default: 500 *p = (char) toupper((unsigned char) *p); 501 } 502 } 503 504 pkgconf_fragment_insert(client, fragment_list, 'D', havebuf, false); 505 } 506 } 507 508 static void 509 apply_env_variables(pkgconf_client_t *client, pkgconf_pkg_t *world, const char *env_prefix) 510 { 511 pkgconf_node_t *world_iter; 512 pkgconf_cli_state_t *state = client->client_data; 513 514 PKGCONF_FOREACH_LIST_ENTRY(world->required.head, world_iter) 515 { 516 pkgconf_dependency_t *dep = world_iter->data; 517 pkgconf_pkg_t *pkg = dep->match; 518 pkgconf_node_t *tuple_iter; 519 520 if ((dep->flags & PKGCONF_PKG_DEPF_QUERY) != PKGCONF_PKG_DEPF_QUERY) 521 continue; 522 523 if (dep->match == NULL) 524 continue; 525 526 PKGCONF_FOREACH_LIST_ENTRY(pkg->vars.head, tuple_iter) 527 { 528 pkgconf_tuple_t *tuple = tuple_iter->data; 529 char havebuf[PKGCONF_ITEM_SIZE]; 530 char *p; 531 532 if (state->want_variable != NULL && strcmp(state->want_variable, tuple->key)) 533 continue; 534 535 snprintf(havebuf, sizeof havebuf, "%s_%s", env_prefix, tuple->key); 536 537 for (p = havebuf; *p; p++) 538 { 539 switch (*p) 540 { 541 case ' ': 542 case '-': 543 *p = '_'; 544 break; 545 546 default: 547 *p = (char) toupper((unsigned char) *p); 548 } 549 } 550 551 char *val = pkgconf_variable_eval_str(client, &pkg->vars, tuple, NULL); 552 pkgconf_output_fmt(client->output, PKGCONF_OUTPUT_STDOUT, 553 "%s='%s'\n", havebuf, val); 554 free(val); 555 } 556 } 557 } 558 559 static bool 560 apply_env(pkgconf_client_t *client, pkgconf_pkg_t *world, const void *env_prefix_p, int maxdepth) 561 { 562 pkgconf_cli_state_t *state = client->client_data; 563 const char *want_env_prefix = env_prefix_p, *it; 564 char workbuf[PKGCONF_ITEM_SIZE]; 565 566 for (it = want_env_prefix; *it != '\0'; it++) 567 if (!isalpha((unsigned char)*it) && 568 !isdigit((unsigned char)*it)) 569 { 570 return false; 571 } 572 573 snprintf(workbuf, sizeof workbuf, "%s_CFLAGS", want_env_prefix); 574 if (!apply_env_var(workbuf, client, world, maxdepth, pkgconf_pkg_cflags, filter_cflags, maybe_add_module_definitions)) 575 return false; 576 577 snprintf(workbuf, sizeof workbuf, "%s_LIBS", want_env_prefix); 578 if (!apply_env_var(workbuf, client, world, maxdepth, pkgconf_pkg_libs, filter_libs, NULL)) 579 return false; 580 581 if ((state->want_flags & PKG_VARIABLES) == PKG_VARIABLES || state->want_variable != NULL) 582 apply_env_variables(client, world, want_env_prefix); 583 584 return true; 585 } 586 587 static bool 588 apply_cflags(pkgconf_client_t *client, pkgconf_pkg_t *world, pkgconf_list_t *target_list, int maxdepth) 589 { 590 pkgconf_list_t unfiltered_list = PKGCONF_LIST_INITIALIZER; 591 pkgconf_list_t filtered_list = PKGCONF_LIST_INITIALIZER; 592 int eflag; 593 594 eflag = pkgconf_pkg_cflags(client, world, &unfiltered_list, maxdepth); 595 if (eflag != PKGCONF_PKG_ERRF_OK) 596 return false; 597 598 pkgconf_fragment_filter(client, &filtered_list, &unfiltered_list, filter_cflags, NULL); 599 maybe_add_module_definitions(client, world, &filtered_list); 600 601 if (filtered_list.head == NULL) 602 goto out; 603 604 pkgconf_fragment_copy_list(client, target_list, &filtered_list); 605 606 out: 607 pkgconf_fragment_free(&unfiltered_list); 608 pkgconf_fragment_free(&filtered_list); 609 610 return true; 611 } 612 613 static bool 614 apply_libs(pkgconf_client_t *client, pkgconf_pkg_t *world, pkgconf_list_t *target_list, int maxdepth) 615 { 616 pkgconf_list_t unfiltered_list = PKGCONF_LIST_INITIALIZER; 617 pkgconf_list_t filtered_list = PKGCONF_LIST_INITIALIZER; 618 int eflag; 619 620 eflag = pkgconf_pkg_libs(client, world, &unfiltered_list, maxdepth); 621 if (eflag != PKGCONF_PKG_ERRF_OK) 622 return false; 623 624 pkgconf_fragment_filter(client, &filtered_list, &unfiltered_list, filter_libs, NULL); 625 626 if (filtered_list.head == NULL) 627 goto out; 628 629 pkgconf_fragment_copy_list(client, target_list, &filtered_list); 630 631 out: 632 pkgconf_fragment_free(&unfiltered_list); 633 pkgconf_fragment_free(&filtered_list); 634 635 return true; 636 } 637 638 static bool 639 apply_requires(pkgconf_client_t *client, pkgconf_pkg_t *world, void *unused, int maxdepth) 640 { 641 pkgconf_node_t *iter; 642 (void) unused; 643 (void) maxdepth; 644 645 PKGCONF_FOREACH_LIST_ENTRY(world->required.head, iter) 646 { 647 pkgconf_dependency_t *dep = iter->data; 648 pkgconf_pkg_t *pkg = dep->match; 649 650 print_dependency_list(client->output, &pkg->required); 651 } 652 653 return true; 654 } 655 656 static bool 657 apply_requires_private(pkgconf_client_t *client, pkgconf_pkg_t *world, void *unused, int maxdepth) 658 { 659 pkgconf_node_t *iter; 660 (void) unused; 661 (void) maxdepth; 662 663 PKGCONF_FOREACH_LIST_ENTRY(world->required.head, iter) 664 { 665 pkgconf_dependency_t *dep = iter->data; 666 pkgconf_pkg_t *pkg = dep->match; 667 668 print_dependency_list(client->output, &pkg->requires_private); 669 } 670 return true; 671 } 672 673 static void 674 check_uninstalled(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data) 675 { 676 int *retval = data; 677 (void) client; 678 679 if (pkg->flags & PKGCONF_PKG_PROPF_UNINSTALLED) 680 *retval = EXIT_SUCCESS; 681 } 682 683 static bool 684 apply_uninstalled(pkgconf_client_t *client, pkgconf_pkg_t *world, void *data, int maxdepth) 685 { 686 int eflag; 687 688 eflag = pkgconf_pkg_traverse(client, world, check_uninstalled, data, maxdepth, 0); 689 690 if (eflag != PKGCONF_PKG_ERRF_OK) 691 return false; 692 693 return true; 694 } 695 696 #ifndef PKGCONF_LITE 697 static void 698 print_graph_node(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data) 699 { 700 pkgconf_node_t *n; 701 702 (void) data; 703 704 pkgconf_output_fmt(client->output, PKGCONF_OUTPUT_STDOUT, "node '%s' {\n", pkg->id); 705 706 if (pkg->version != NULL) 707 pkgconf_output_fmt(client->output, PKGCONF_OUTPUT_STDOUT, " version = '%s';\n", pkg->version); 708 709 PKGCONF_FOREACH_LIST_ENTRY(pkg->required.head, n) 710 { 711 pkgconf_dependency_t *dep = n->data; 712 713 pkgconf_output_fmt(client->output, PKGCONF_OUTPUT_STDOUT, " dependency '%s'", dep->package); 714 715 if (dep->compare != PKGCONF_CMP_ANY) 716 { 717 pkgconf_output_fmt(client->output, PKGCONF_OUTPUT_STDOUT, 718 " {\n" 719 " comparator = '%s';\n" 720 " version = '%s';\n" 721 " };\n", 722 pkgconf_pkg_get_comparator(dep), dep->version); 723 } 724 else 725 pkgconf_output_puts(client->output, PKGCONF_OUTPUT_STDOUT, ";"); 726 } 727 728 pkgconf_output_puts(client->output, PKGCONF_OUTPUT_STDOUT, "};"); 729 } 730 731 static bool 732 apply_simulate(pkgconf_client_t *client, pkgconf_pkg_t *world, void *data, int maxdepth) 733 { 734 int eflag; 735 736 eflag = pkgconf_pkg_traverse(client, world, print_graph_node, data, maxdepth, 0); 737 738 if (eflag != PKGCONF_PKG_ERRF_OK) 739 return false; 740 741 return true; 742 } 743 #endif 744 745 static void 746 print_fragment_tree_branch(pkgconf_output_t *output, pkgconf_list_t *fragment_list, int indent) 747 { 748 pkgconf_node_t *iter; 749 750 PKGCONF_FOREACH_LIST_ENTRY(fragment_list->head, iter) 751 { 752 pkgconf_fragment_t *frag = iter->data; 753 754 if (frag->type) 755 pkgconf_output_fmt(output, PKGCONF_OUTPUT_STDOUT, 756 "%*s'-%c%s' [type %c, " SIZE_FMT_SPECIFIER " children]\n", indent, "", frag->type, frag->data, frag->type, frag->children.length); 757 else 758 pkgconf_output_fmt(output, PKGCONF_OUTPUT_STDOUT, 759 "%*s'%s' [untyped, " SIZE_FMT_SPECIFIER " children]\n", indent, "", frag->data, frag->children.length); 760 761 print_fragment_tree_branch(output, &frag->children, indent + 2); 762 } 763 764 if (fragment_list->head != NULL) 765 pkgconf_output_puts(output, PKGCONF_OUTPUT_STDOUT, ""); 766 } 767 768 static bool 769 apply_fragment_tree(pkgconf_client_t *client, pkgconf_pkg_t *world, void *data, int maxdepth) 770 { 771 pkgconf_list_t unfiltered_list = PKGCONF_LIST_INITIALIZER; 772 int eflag; 773 774 (void) data; 775 776 eflag = pkgconf_pkg_cflags(client, world, &unfiltered_list, maxdepth); 777 if (eflag != PKGCONF_PKG_ERRF_OK) 778 return false; 779 780 eflag = pkgconf_pkg_libs(client, world, &unfiltered_list, maxdepth); 781 if (eflag != PKGCONF_PKG_ERRF_OK) 782 return false; 783 784 print_fragment_tree_branch(client->output, &unfiltered_list, 0); 785 pkgconf_fragment_free(&unfiltered_list); 786 787 return true; 788 } 789 790 static void 791 print_license(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data) 792 { 793 pkgconf_buffer_t render_buf = PKGCONF_BUFFER_INITIALIZER; 794 (void) data; 795 796 if (pkg->flags & PKGCONF_PKG_PROPF_VIRTUAL) 797 return; 798 799 if (pkg->license.head == NULL) 800 { 801 pkgconf_output_fmt(client->output, PKGCONF_OUTPUT_STDOUT, 802 "%s: NOASSERTION\n", pkg->id); 803 } 804 else 805 { 806 /* NOASSERTION is the default when the license is unknown, per SPDX spec § 3.15 */ 807 pkgconf_license_render(client, &pkg->license, &render_buf); 808 pkgconf_output_fmt(client->output, PKGCONF_OUTPUT_STDOUT, "%s: ", pkg->id); 809 pkgconf_output_putbuf(client->output, PKGCONF_OUTPUT_STDOUT, &render_buf, true); 810 pkgconf_buffer_finalize(&render_buf); 811 } 812 } 813 814 static bool 815 apply_license(pkgconf_client_t *client, pkgconf_pkg_t *world, void *data, int maxdepth) 816 { 817 int eflag; 818 819 eflag = pkgconf_pkg_traverse(client, world, print_license, data, maxdepth, 0); 820 821 if (eflag != PKGCONF_PKG_ERRF_OK) 822 return false; 823 824 return true; 825 } 826 827 static bool 828 apply_link_abi(pkgconf_client_t *client, pkgconf_pkg_t *world, void *data, int maxdepth) 829 { 830 pkgconf_list_t abis = PKGCONF_LIST_INITIALIZER; 831 pkgconf_buffer_t render_buf = PKGCONF_BUFFER_INITIALIZER; 832 pkgconf_node_t *node; 833 int *retval = data; 834 835 if (pkgconf_pkg_link_abi(client, world, &abis, maxdepth) != PKGCONF_PKG_ERRF_OK) 836 { 837 pkgconf_bufferset_free(&abis); 838 *retval = EXIT_FAILURE; 839 return false; 840 } 841 842 PKGCONF_FOREACH_LIST_ENTRY(abis.head, node) 843 { 844 pkgconf_bufferset_t *tag = node->data; 845 846 if (pkgconf_buffer_len(&render_buf)) 847 pkgconf_buffer_push_byte(&render_buf, ' '); 848 849 pkgconf_buffer_append(&render_buf, pkgconf_buffer_str(&tag->buffer)); 850 } 851 852 pkgconf_output_putbuf(client->output, PKGCONF_OUTPUT_STDOUT, &render_buf, true); 853 854 pkgconf_buffer_finalize(&render_buf); 855 pkgconf_bufferset_free(&abis); 856 857 return true; 858 } 859 860 static void 861 print_license_file(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data) 862 { 863 (void) data; 864 865 if (pkg->flags & PKGCONF_PKG_PROPF_VIRTUAL) 866 return; 867 868 /* If license file location is not available then just print empty */ 869 pkgconf_output_fmt(client->output, PKGCONF_OUTPUT_STDOUT, "%s: %s\n", 870 pkg->id, pkg->license_file != NULL ? pkg->license_file : ""); 871 } 872 873 static bool 874 apply_license_file(pkgconf_client_t *client, pkgconf_pkg_t *world, void *data, int maxdepth) 875 { 876 int eflag; 877 878 eflag = pkgconf_pkg_traverse(client, world, print_license_file, data, maxdepth, 0); 879 880 if (eflag != PKGCONF_PKG_ERRF_OK) 881 return false; 882 883 return true; 884 } 885 886 static void 887 print_source(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data) 888 { 889 (void) data; 890 891 if (pkg->flags & PKGCONF_PKG_PROPF_VIRTUAL) 892 return; 893 894 /* If source is empty then empty string is printed otherwise URL */ 895 pkgconf_output_fmt(client->output, PKGCONF_OUTPUT_STDOUT, "%s: %s\n", 896 pkg->id, pkg->source != NULL ? pkg->source : ""); 897 } 898 899 static bool 900 apply_source(pkgconf_client_t *client, pkgconf_pkg_t *world, void *data, int maxdepth) 901 { 902 int eflag; 903 904 eflag = pkgconf_pkg_traverse(client, world, print_source, data, maxdepth, 0); 905 906 if (eflag != PKGCONF_PKG_ERRF_OK) 907 return false; 908 909 return true; 910 } 911 912 void 913 path_list_to_buffer(const pkgconf_list_t *list, pkgconf_buffer_t *buffer, char delim) 914 { 915 pkgconf_node_t *n; 916 917 PKGCONF_FOREACH_LIST_ENTRY(list->head, n) 918 { 919 pkgconf_path_t *pn = n->data; 920 921 if (n != list->head) 922 pkgconf_buffer_push_byte(buffer, delim); 923 924 pkgconf_buffer_append(buffer, pn->path); 925 } 926 } 927 928 static void 929 unveil_search_paths(pkgconf_client_t *client, const pkgconf_cross_personality_t *personality) 930 { 931 pkgconf_node_t *n; 932 933 client->unveil_handler(client, "/dev/null", "rwc"); 934 935 PKGCONF_FOREACH_LIST_ENTRY(client->dir_list.head, n) 936 { 937 pkgconf_path_t *pn = n->data; 938 939 client->unveil_handler(client, pn->path, "r"); 940 } 941 942 PKGCONF_FOREACH_LIST_ENTRY(personality->dir_list.head, n) 943 { 944 pkgconf_path_t *pn = n->data; 945 946 client->unveil_handler(client, pn->path, "r"); 947 } 948 } 949 950 /* SAFETY: pkgconf_client_t takes ownership of these package objects */ 951 static void 952 register_builtins(pkgconf_client_t *client, const pkgconf_cross_personality_t *personality) 953 { 954 pkgconf_buffer_t pc_path_buf = PKGCONF_BUFFER_INITIALIZER; 955 path_list_to_buffer(&personality->dir_list, &pc_path_buf, ':'); 956 957 pkgconf_buffer_t pc_system_libdirs_buf = PKGCONF_BUFFER_INITIALIZER; 958 path_list_to_buffer(&personality->filter_libdirs, &pc_system_libdirs_buf, ':'); 959 960 pkgconf_buffer_t pc_system_includedirs_buf = PKGCONF_BUFFER_INITIALIZER; 961 path_list_to_buffer(&personality->filter_includedirs, &pc_system_includedirs_buf, ':'); 962 963 pkgconf_pkg_t *pkg_config_virtual = calloc(1, sizeof(pkgconf_pkg_t)); 964 if (pkg_config_virtual == NULL) 965 { 966 goto error; 967 } 968 969 pkg_config_virtual->owner = client; 970 pkg_config_virtual->id = strdup("pkg-config"); 971 pkg_config_virtual->realname = strdup("pkg-config"); 972 pkg_config_virtual->description = strdup("virtual package defining pkgconf API version supported"); 973 pkg_config_virtual->url = strdup(PACKAGE_BUGREPORT); 974 pkg_config_virtual->version = strdup(PACKAGE_VERSION); 975 976 pkgconf_tuple_add(client, &pkg_config_virtual->vars, "pc_system_libdirs", pkgconf_buffer_str_or_empty(&pc_system_libdirs_buf), false, 0); 977 pkgconf_tuple_add(client, &pkg_config_virtual->vars, "pc_system_includedirs", pkgconf_buffer_str_or_empty(&pc_system_includedirs_buf), false, 0); 978 pkgconf_tuple_add(client, &pkg_config_virtual->vars, "pc_path", pkgconf_buffer_str_or_empty(&pc_path_buf), false, 0); 979 980 if (!pkgconf_client_preload_one(client, pkg_config_virtual)) 981 { 982 goto error; 983 } 984 985 pkgconf_pkg_t *pkgconf_virtual = calloc(1, sizeof(pkgconf_pkg_t)); 986 if (pkgconf_virtual == NULL) 987 { 988 goto error; 989 } 990 991 pkgconf_virtual->owner = client; 992 pkgconf_virtual->id = strdup("pkgconf"); 993 pkgconf_virtual->realname = strdup("pkgconf"); 994 pkgconf_virtual->description = strdup("virtual package defining pkgconf API version supported"); 995 pkgconf_virtual->url = strdup(PACKAGE_BUGREPORT); 996 pkgconf_virtual->version = strdup(PACKAGE_VERSION); 997 998 pkgconf_tuple_add(client, &pkgconf_virtual->vars, "pc_system_libdirs", pkgconf_buffer_str_or_empty(&pc_system_libdirs_buf), false, 0); 999 pkgconf_tuple_add(client, &pkgconf_virtual->vars, "pc_system_includedirs", pkgconf_buffer_str_or_empty(&pc_system_includedirs_buf), false, 0); 1000 pkgconf_tuple_add(client, &pkgconf_virtual->vars, "pc_path", pkgconf_buffer_str_or_empty(&pc_path_buf), false, 0); 1001 1002 if (!pkgconf_client_preload_one(client, pkgconf_virtual)) 1003 { 1004 goto error; 1005 } 1006 1007 error: 1008 pkgconf_buffer_finalize(&pc_path_buf); 1009 pkgconf_buffer_finalize(&pc_system_libdirs_buf); 1010 pkgconf_buffer_finalize(&pc_system_includedirs_buf); 1011 } 1012 1013 #ifndef PKGCONF_LITE 1014 static void 1015 dump_personality(pkgconf_output_t *output, const pkgconf_cross_personality_t *p) 1016 { 1017 pkgconf_buffer_t pc_path_buf = PKGCONF_BUFFER_INITIALIZER; 1018 path_list_to_buffer(&p->dir_list, &pc_path_buf, ':'); 1019 1020 pkgconf_buffer_t pc_system_libdirs_buf = PKGCONF_BUFFER_INITIALIZER; 1021 path_list_to_buffer(&p->filter_libdirs, &pc_system_libdirs_buf, ':'); 1022 1023 pkgconf_buffer_t pc_system_includedirs_buf = PKGCONF_BUFFER_INITIALIZER; 1024 path_list_to_buffer(&p->filter_includedirs, &pc_system_includedirs_buf, ':'); 1025 1026 pkgconf_output_fmt(output, PKGCONF_OUTPUT_STDOUT, "Triplet: %s\n", p->name); 1027 1028 if (p->sysroot_dir) 1029 pkgconf_output_fmt(output, PKGCONF_OUTPUT_STDOUT, "SysrootDir: %s\n", p->sysroot_dir); 1030 1031 pkgconf_output_fmt(output, PKGCONF_OUTPUT_STDOUT, "DefaultSearchPaths: %s\n", pc_path_buf.base); 1032 pkgconf_output_fmt(output, PKGCONF_OUTPUT_STDOUT, "SystemIncludePaths: %s\n", pc_system_includedirs_buf.base); 1033 pkgconf_output_fmt(output, PKGCONF_OUTPUT_STDOUT, "SystemLibraryPaths: %s\n", pc_system_libdirs_buf.base); 1034 1035 if (p->want_default_pure) 1036 pkgconf_output_fmt(output, PKGCONF_OUTPUT_STDOUT, "WantDefaultPure: true\n"); 1037 1038 if (p->want_default_static) 1039 pkgconf_output_fmt(output, PKGCONF_OUTPUT_STDOUT, "WantDefaultStatic: true\n"); 1040 1041 pkgconf_buffer_finalize(&pc_path_buf); 1042 pkgconf_buffer_finalize(&pc_system_libdirs_buf); 1043 pkgconf_buffer_finalize(&pc_system_includedirs_buf); 1044 } 1045 #endif 1046 1047 int 1048 pkgconf_cli_run(pkgconf_cli_state_t *state, int argc, char *argv[], int last_argc) 1049 { 1050 (void) argc; 1051 1052 int ret = EXIT_SUCCESS; 1053 unsigned int want_client_flags = PKGCONF_PKG_PKGF_NONE; 1054 const char *builddir; 1055 const char *sysroot_dir; 1056 pkgconf_list_t pkgq = PKGCONF_LIST_INITIALIZER; 1057 pkgconf_list_t deplist = PKGCONF_LIST_INITIALIZER; 1058 pkgconf_node_t *node; 1059 pkgconf_buffer_t queryparams = PKGCONF_BUFFER_INITIALIZER; 1060 pkgconf_pkg_t world = { 1061 .id = "virtual:world", 1062 .realname = "virtual world package", 1063 .flags = PKGCONF_PKG_PROPF_STATIC | PKGCONF_PKG_PROPF_VIRTUAL, 1064 }; 1065 1066 #ifndef PKGCONF_LITE 1067 if ((state->want_flags & PKG_DUMP_PERSONALITY) == PKG_DUMP_PERSONALITY) 1068 { 1069 dump_personality(state->pkg_client.output, state->pkg_client.personality); 1070 1071 ret = EXIT_SUCCESS; 1072 goto out; 1073 } 1074 #endif 1075 1076 #ifndef PKGCONF_LITE 1077 if ((state->want_flags & PKG_MSVC_SYNTAX) == PKG_MSVC_SYNTAX) 1078 state->want_render_ops = msvc_renderer_get(); 1079 #endif 1080 1081 if (pkgconf_client_getenv(&state->pkg_client, "PKG_CONFIG_FDO_SYSROOT_RULES")) 1082 want_client_flags |= PKGCONF_PKG_PKGF_FDO_SYSROOT_RULES; 1083 1084 if (pkgconf_client_getenv(&state->pkg_client, "PKG_CONFIG_PKGCONF1_SYSROOT_RULES")) 1085 want_client_flags |= PKGCONF_PKG_PKGF_PKGCONF1_SYSROOT_RULES; 1086 1087 if ((state->want_flags & PKG_SHORT_ERRORS) == PKG_SHORT_ERRORS) 1088 want_client_flags |= PKGCONF_PKG_PKGF_SIMPLIFY_ERRORS; 1089 1090 if ((state->want_flags & PKG_DONT_RELOCATE_PATHS) == PKG_DONT_RELOCATE_PATHS) 1091 want_client_flags |= PKGCONF_PKG_PKGF_DONT_RELOCATE_PATHS; 1092 1093 state->error_msgout = stderr; 1094 if ((state->want_flags & PKG_ERRORS_ON_STDOUT) == PKG_ERRORS_ON_STDOUT) 1095 state->error_msgout = stdout; 1096 if ((state->want_flags & PKG_SILENCE_ERRORS) == PKG_SILENCE_ERRORS) { 1097 state->error_msgout = fopen(PATH_DEV_NULL, "w"); 1098 state->opened_error_msgout = true; 1099 } 1100 1101 if ((state->want_flags & PKG_IGNORE_CONFLICTS) == PKG_IGNORE_CONFLICTS || pkgconf_client_getenv(&state->pkg_client, "PKG_CONFIG_IGNORE_CONFLICTS") != NULL) 1102 want_client_flags |= PKGCONF_PKG_PKGF_SKIP_CONFLICTS; 1103 1104 if ((state->want_flags & PKG_STATIC) == PKG_STATIC || state->pkg_client.personality->want_default_static) 1105 want_client_flags |= (PKGCONF_PKG_PKGF_SEARCH_PRIVATE | PKGCONF_PKG_PKGF_MERGE_PRIVATE_FRAGMENTS); 1106 1107 if ((state->want_flags & PKG_SHARED) == PKG_SHARED) 1108 want_client_flags &= ~(PKGCONF_PKG_PKGF_SEARCH_PRIVATE | PKGCONF_PKG_PKGF_MERGE_PRIVATE_FRAGMENTS); 1109 1110 /* if --static and --pure are both specified, then disable merge-back. 1111 * this allows for a --static which searches private modules, but has the same fragment behaviour as if 1112 * --static were disabled. see <https://github.com/pkgconf/pkgconf/issues/83> for rationale. 1113 */ 1114 if ((state->want_flags & PKG_PURE) == PKG_PURE || pkgconf_client_getenv(&state->pkg_client, "PKG_CONFIG_PURE_DEPGRAPH") != NULL || state->pkg_client.personality->want_default_pure) 1115 want_client_flags &= ~PKGCONF_PKG_PKGF_MERGE_PRIVATE_FRAGMENTS; 1116 1117 if ((state->want_flags & PKG_ENV_ONLY) == PKG_ENV_ONLY) 1118 want_client_flags |= PKGCONF_PKG_PKGF_ENV_ONLY; 1119 1120 if ((state->want_flags & PKG_NO_CACHE) == PKG_NO_CACHE) 1121 want_client_flags |= PKGCONF_PKG_PKGF_NO_CACHE; 1122 1123 /* On Windows we want to always redefine the prefix by default 1124 * but allow that behavior to be manually disabled */ 1125 #if !defined(_WIN32) && !defined(_WIN64) 1126 if ((state->want_flags & PKG_DEFINE_PREFIX) == PKG_DEFINE_PREFIX || pkgconf_client_getenv(&state->pkg_client, "PKG_CONFIG_RELOCATE_PATHS") != NULL) 1127 #endif 1128 want_client_flags |= PKGCONF_PKG_PKGF_REDEFINE_PREFIX; 1129 1130 if ((state->want_flags & PKG_NO_UNINSTALLED) == PKG_NO_UNINSTALLED || pkgconf_client_getenv(&state->pkg_client, "PKG_CONFIG_DISABLE_UNINSTALLED") != NULL) 1131 want_client_flags |= PKGCONF_PKG_PKGF_NO_UNINSTALLED; 1132 1133 if ((state->want_flags & PKG_NO_PROVIDES) == PKG_NO_PROVIDES) 1134 want_client_flags |= PKGCONF_PKG_PKGF_SKIP_PROVIDES; 1135 1136 if ((state->want_flags & PKG_DONT_DEFINE_PREFIX) == PKG_DONT_DEFINE_PREFIX || pkgconf_client_getenv(&state->pkg_client, "PKG_CONFIG_DONT_DEFINE_PREFIX") != NULL) 1137 want_client_flags &= ~PKGCONF_PKG_PKGF_REDEFINE_PREFIX; 1138 1139 if ((state->want_flags & PKG_INTERNAL_CFLAGS) == PKG_INTERNAL_CFLAGS) 1140 want_client_flags |= PKGCONF_PKG_PKGF_DONT_FILTER_INTERNAL_CFLAGS; 1141 1142 /* --static --libs, --exists require the full dependency graph to be solved */ 1143 if ((state->want_flags & (PKG_STATIC|PKG_LIBS)) == (PKG_STATIC|PKG_LIBS) || (state->want_flags & PKG_EXISTS) == PKG_EXISTS) 1144 want_client_flags |= PKGCONF_PKG_PKGF_REQUIRE_INTERNAL; 1145 1146 /* if these selectors are used, it means that we are querying metadata. 1147 * so signal to libpkgconf that we only want to walk the flattened dependency set. 1148 */ 1149 if ((state->want_flags & PKG_MODVERSION) == PKG_MODVERSION || 1150 (state->want_flags & PKG_REQUIRES) == PKG_REQUIRES || 1151 (state->want_flags & PKG_REQUIRES_PRIVATE) == PKG_REQUIRES_PRIVATE || 1152 (state->want_flags & PKG_PROVIDES) == PKG_PROVIDES || 1153 (state->want_flags & PKG_VARIABLES) == PKG_VARIABLES || 1154 (state->want_flags & PKG_PATH) == PKG_PATH || 1155 state->want_variable != NULL) 1156 state->maximum_traverse_depth = 1; 1157 1158 /* if we are asking for a variable, path or list of variables, this only makes sense 1159 * for a single package. 1160 */ 1161 if ((state->want_flags & PKG_VARIABLES) == PKG_VARIABLES || 1162 (state->want_flags & PKG_PATH) == PKG_PATH || 1163 state->want_variable != NULL) 1164 { 1165 state->maximum_package_count = 1; 1166 } 1167 1168 if ((state->want_flags & PKG_REQUIRES_PRIVATE) == PKG_REQUIRES_PRIVATE || 1169 (state->want_flags & PKG_CFLAGS)) 1170 { 1171 want_client_flags |= PKGCONF_PKG_PKGF_SEARCH_PRIVATE; 1172 } 1173 1174 if ((builddir = pkgconf_client_getenv(&state->pkg_client, "PKG_CONFIG_TOP_BUILD_DIR")) != NULL) 1175 pkgconf_client_set_buildroot_dir(&state->pkg_client, builddir); 1176 1177 if ((sysroot_dir = pkgconf_client_getenv(&state->pkg_client, "PKG_CONFIG_SYSROOT_DIR")) != NULL) 1178 { 1179 const char *destdir; 1180 1181 pkgconf_client_set_sysroot_dir(&state->pkg_client, sysroot_dir); 1182 1183 if ((destdir = pkgconf_client_getenv(&state->pkg_client, "DESTDIR")) != NULL) 1184 { 1185 if (!strcmp(destdir, sysroot_dir)) 1186 want_client_flags |= PKGCONF_PKG_PKGF_FDO_SYSROOT_RULES; 1187 } 1188 } 1189 1190 /* we have determined what features we want most likely. in some cases, we override later. */ 1191 pkgconf_client_set_flags(&state->pkg_client, want_client_flags); 1192 1193 /* at this point, want_client_flags should be set, so build the dir list */ 1194 pkgconf_client_dir_list_build(&state->pkg_client, state->pkg_client.personality); 1195 1196 /* unveil the entire search path now that we have loaded the personality data and built the dir list. */ 1197 unveil_search_paths(&state->pkg_client, state->pkg_client.personality); 1198 1199 /* register built-in packages */ 1200 register_builtins(&state->pkg_client, state->pkg_client.personality); 1201 1202 /* preload any files in PKG_CONFIG_PRELOADED_FILES */ 1203 pkgconf_client_preload_from_environ(&state->pkg_client, "PKG_CONFIG_PRELOADED_FILES"); 1204 1205 if (state->required_pkgconfig_version != NULL) 1206 { 1207 if (pkgconf_compare_version(PACKAGE_VERSION, state->required_pkgconfig_version) >= 0) 1208 ret = EXIT_SUCCESS; 1209 else 1210 ret = EXIT_FAILURE; 1211 1212 goto out; 1213 } 1214 1215 if ((state->want_flags & PKG_LIST) == PKG_LIST) 1216 { 1217 pkgconf_scan_all(&state->pkg_client, &state->pkg_client, print_list_entry); 1218 ret = EXIT_SUCCESS; 1219 goto out; 1220 } 1221 1222 if ((state->want_flags & PKG_LIST_PACKAGE_NAMES) == PKG_LIST_PACKAGE_NAMES) 1223 { 1224 pkgconf_scan_all(&state->pkg_client, &state->pkg_client, print_package_entry); 1225 ret = EXIT_SUCCESS; 1226 goto out; 1227 } 1228 1229 while (last_argc < argc && argv[last_argc]) 1230 { 1231 if (pkgconf_buffer_len(&queryparams) > 0) 1232 pkgconf_buffer_push_byte(&queryparams, ' '); 1233 1234 pkgconf_buffer_append(&queryparams, argv[last_argc]); 1235 last_argc++; 1236 } 1237 1238 pkgconf_dependency_parse_str(&state->pkg_client, &deplist, pkgconf_buffer_str_or_empty(&queryparams), 0); 1239 pkgconf_buffer_finalize(&queryparams); 1240 1241 if (state->required_module_version != NULL || state->required_exact_module_version != NULL || state->required_max_module_version != NULL) 1242 { 1243 const char *target_version = NULL; 1244 pkgconf_pkg_comparator_t compare = PKGCONF_CMP_ANY; 1245 1246 if (state->required_module_version != NULL) 1247 { 1248 target_version = state->required_module_version; 1249 compare = PKGCONF_CMP_GREATER_THAN_EQUAL; 1250 } 1251 else if (state->required_exact_module_version != NULL) 1252 { 1253 target_version = state->required_exact_module_version; 1254 compare = PKGCONF_CMP_EQUAL; 1255 } 1256 else if (state->required_max_module_version != NULL) 1257 { 1258 target_version = state->required_max_module_version; 1259 compare = PKGCONF_CMP_LESS_THAN_EQUAL; 1260 } 1261 1262 PKGCONF_FOREACH_LIST_ENTRY(deplist.head, node) 1263 { 1264 pkgconf_dependency_t *dep = node->data; 1265 1266 /* already constrained at query level */ 1267 if (dep->compare != PKGCONF_CMP_ANY) 1268 continue; 1269 1270 dep->compare = compare; 1271 dep->version = strdup(target_version); 1272 } 1273 } 1274 1275 PKGCONF_FOREACH_LIST_ENTRY(deplist.head, node) 1276 { 1277 pkgconf_dependency_t *dep = node->data; 1278 pkgconf_queue_push_dependency(&pkgq, dep); 1279 } 1280 1281 pkgconf_dependency_free(&deplist); 1282 1283 if (pkgq.head == NULL) 1284 { 1285 pkgconf_output_puts(state->pkg_client.output, PKGCONF_OUTPUT_STDERR, 1286 "Please specify at least one package name on the command line."); 1287 ret = EXIT_FAILURE; 1288 goto out; 1289 } 1290 1291 ret = EXIT_SUCCESS; 1292 1293 if (!pkgconf_queue_solve(&state->pkg_client, &pkgq, &world, state->maximum_traverse_depth)) 1294 { 1295 ret = EXIT_FAILURE; 1296 goto out; 1297 } 1298 1299 /* we shouldn't need to unveil any more filesystem accesses from this point, so lock it down */ 1300 state->pkg_client.unveil_handler(&state->pkg_client, NULL, NULL); 1301 1302 #ifndef PKGCONF_LITE 1303 if ((state->want_flags & PKG_SIMULATE) == PKG_SIMULATE) 1304 { 1305 state->want_flags &= ~(PKG_CFLAGS|PKG_LIBS); 1306 1307 pkgconf_client_set_flags(&state->pkg_client, want_client_flags | PKGCONF_PKG_PKGF_SKIP_ERRORS); 1308 apply_simulate(&state->pkg_client, &world, NULL, -1); 1309 } 1310 #endif 1311 1312 if ((state->want_flags & PKG_VALIDATE) == PKG_VALIDATE) 1313 goto out; 1314 1315 if ((state->want_flags & PKG_DUMP_LICENSE) == PKG_DUMP_LICENSE) 1316 { 1317 apply_license(&state->pkg_client, &world, &ret, 2); 1318 goto out; 1319 } 1320 1321 if ((state->want_flags & PKG_LINK_ABI) == PKG_LINK_ABI) 1322 { 1323 /* private dependencies only contribute their ABI when statically linked */ 1324 if (!(state->want_flags & PKG_STATIC)) 1325 pkgconf_client_set_flags(&state->pkg_client, state->pkg_client.flags & ~PKGCONF_PKG_PKGF_SEARCH_PRIVATE); 1326 1327 apply_link_abi(&state->pkg_client, &world, &ret, 2); 1328 goto out; 1329 } 1330 1331 if ((state->want_flags & PKG_DUMP_LICENSE_FILE) == PKG_DUMP_LICENSE_FILE) 1332 { 1333 apply_license_file(&state->pkg_client, &world, &ret, 2); 1334 goto out; 1335 } 1336 1337 if ((state->want_flags & PKG_DUMP_SOURCE) == PKG_DUMP_SOURCE) 1338 { 1339 apply_source(&state->pkg_client, &world, &ret, 2); 1340 goto out; 1341 } 1342 1343 1344 if ((state->want_flags & PKG_UNINSTALLED) == PKG_UNINSTALLED) 1345 { 1346 ret = EXIT_FAILURE; 1347 apply_uninstalled(&state->pkg_client, &world, &ret, 2); 1348 goto out; 1349 } 1350 1351 if (state->want_env_prefix != NULL) 1352 { 1353 apply_env(&state->pkg_client, &world, state->want_env_prefix, 2); 1354 goto out; 1355 } 1356 1357 if ((state->want_flags & PKG_PROVIDES) == PKG_PROVIDES) 1358 { 1359 state->want_flags &= ~(PKG_CFLAGS|PKG_LIBS); 1360 apply_provides(&state->pkg_client, &world, NULL, 2); 1361 } 1362 1363 #ifndef PKGCONF_LITE 1364 if ((state->want_flags & PKG_DIGRAPH) == PKG_DIGRAPH) 1365 { 1366 state->want_flags &= ~(PKG_CFLAGS|PKG_LIBS); 1367 apply_digraph(&state->pkg_client, &world, &pkgq, 2); 1368 } 1369 1370 if ((state->want_flags & PKG_SOLUTION) == PKG_SOLUTION) 1371 { 1372 state->want_flags &= ~(PKG_CFLAGS|PKG_LIBS); 1373 apply_print_solution(&state->pkg_client, &world, NULL, 2); 1374 } 1375 #endif 1376 1377 if ((state->want_flags & PKG_MODVERSION) == PKG_MODVERSION) 1378 { 1379 state->want_flags &= ~(PKG_CFLAGS|PKG_LIBS); 1380 apply_modversion(&state->pkg_client, &world, &pkgq, 2); 1381 } 1382 1383 if ((state->want_flags & PKG_PATH) == PKG_PATH) 1384 { 1385 state->want_flags &= ~(PKG_CFLAGS|PKG_LIBS); 1386 1387 pkgconf_client_set_flags(&state->pkg_client, want_client_flags | PKGCONF_PKG_PKGF_SKIP_ROOT_VIRTUAL); 1388 apply_path(&state->pkg_client, &world, NULL, 2); 1389 } 1390 1391 if ((state->want_flags & PKG_VARIABLES) == PKG_VARIABLES) 1392 { 1393 state->want_flags &= ~(PKG_CFLAGS|PKG_LIBS); 1394 apply_variables(&state->pkg_client, &world, NULL, 2); 1395 } 1396 1397 if (state->want_variable != NULL) 1398 { 1399 state->want_flags &= ~(PKG_CFLAGS|PKG_LIBS); 1400 1401 pkgconf_client_set_flags(&state->pkg_client, want_client_flags | PKGCONF_PKG_PKGF_SKIP_ROOT_VIRTUAL); 1402 apply_variable(&state->pkg_client, &world, state->want_variable, 2); 1403 } 1404 1405 if ((state->want_flags & PKG_REQUIRES) == PKG_REQUIRES) 1406 { 1407 state->want_flags &= ~(PKG_CFLAGS|PKG_LIBS); 1408 apply_requires(&state->pkg_client, &world, NULL, 2); 1409 } 1410 1411 if ((state->want_flags & PKG_REQUIRES_PRIVATE) == PKG_REQUIRES_PRIVATE) 1412 { 1413 state->want_flags &= ~(PKG_CFLAGS|PKG_LIBS); 1414 1415 apply_requires_private(&state->pkg_client, &world, NULL, 2); 1416 } 1417 1418 if ((state->want_flags & PKG_FRAGMENT_TREE)) 1419 { 1420 state->want_flags &= ~(PKG_CFLAGS|PKG_LIBS); 1421 1422 apply_fragment_tree(&state->pkg_client, &world, NULL, 2); 1423 } 1424 1425 if ((state->want_flags & (PKG_CFLAGS|PKG_LIBS))) 1426 { 1427 pkgconf_list_t target_list = PKGCONF_LIST_INITIALIZER; 1428 pkgconf_buffer_t render_buf = PKGCONF_BUFFER_INITIALIZER; 1429 1430 if ((state->want_flags & PKG_CFLAGS)) 1431 apply_cflags(&state->pkg_client, &world, &target_list, 2); 1432 1433 if ((state->want_flags & PKG_LIBS) && !(state->want_flags & PKG_STATIC)) 1434 pkgconf_client_set_flags(&state->pkg_client, state->pkg_client.flags & ~PKGCONF_PKG_PKGF_SEARCH_PRIVATE); 1435 1436 if ((state->want_flags & PKG_LIBS)) 1437 apply_libs(&state->pkg_client, &world, &target_list, 2); 1438 1439 pkgconf_fragment_render_buf(&target_list, &render_buf, true, state->want_render_ops, (state->want_flags & PKG_NEWLINES) ? '\n' : ' '); 1440 pkgconf_output_putbuf(state->pkg_client.output, PKGCONF_OUTPUT_STDOUT, &render_buf, true); 1441 pkgconf_buffer_finalize(&render_buf); 1442 1443 pkgconf_fragment_free(&target_list); 1444 } 1445 1446 out: 1447 pkgconf_solution_free(&state->pkg_client, &world); 1448 pkgconf_queue_free(&pkgq); 1449 pkgconf_cli_state_reset(state); 1450 1451 return ret; 1452 } 1453 1454 void 1455 pkgconf_cli_state_reset(pkgconf_cli_state_t *state) 1456 { 1457 pkgconf_cross_personality_deinit((void *) state->pkg_client.personality); 1458 pkgconf_client_deinit(&state->pkg_client); 1459 1460 if (state->logfile_out != NULL) 1461 fclose(state->logfile_out); 1462 if (state->opened_error_msgout) 1463 fclose(state->error_msgout); 1464 } 1465