Annotation of src/usr.bin/pkg-config/pkg-config, Revision 1.96
1.1 ckuethe 1: #!/usr/bin/perl
1.96 ! espie 2: # $OpenBSD: pkg-config,v 1.95 2020/09/15 07:18:45 jasper Exp $
1.1 ckuethe 3:
4: # Copyright (c) 2006 Chris Kuethe <ckuethe@openbsd.org>
1.95 jasper 5: # Copyright (c) 2011-2020 Jasper Lievisse Adriaanse <jasper@openbsd.org>
1.1 ckuethe 6: #
7: # Permission to use, copy, modify, and distribute this software for any
8: # purpose with or without fee is hereby granted, provided that the above
9: # copyright notice and this permission notice appear in all copies.
10: #
11: # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12: # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13: # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14: # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15: # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16: # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17: # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18:
1.96 ! espie 19: use v5.36;
1.70 jasper 20: use Config;
1.1 ckuethe 21: use Getopt::Long;
1.4 espie 22: use File::Basename;
1.58 jasper 23: use File::stat;
1.11 espie 24: use OpenBSD::PkgConfig;
1.1 ckuethe 25:
1.96 ! espie 26: use constant {
! 27: ONLY_I => 1,
! 28: ONLY_l => 2,
! 29: ONLY_L => 4,
! 30: ONLY_OTHER => 8
! 31: };
! 32:
1.71 ajacouto 33: my @PKGPATH = qw(/usr/lib/pkgconfig
34: /usr/local/lib/pkgconfig
35: /usr/local/share/pkgconfig
36: /usr/X11R6/lib/pkgconfig
37: /usr/X11R6/share/pkgconfig);
1.1 ckuethe 38:
1.16 espie 39: if (defined($ENV{PKG_CONFIG_LIBDIR}) && $ENV{PKG_CONFIG_LIBDIR}) {
1.66 jasper 40: @PKGPATH = split(/:/, $ENV{PKG_CONFIG_LIBDIR});
1.16 espie 41: } elsif (defined($ENV{PKG_CONFIG_PATH}) && $ENV{PKG_CONFIG_PATH}) {
1.66 jasper 42: unshift(@PKGPATH, split(/:/, $ENV{PKG_CONFIG_PATH}));
1.1 ckuethe 43: }
44:
45: my $logfile = '';
1.50 jasper 46: if (defined($ENV{PKG_CONFIG_LOG}) && $ENV{PKG_CONFIG_LOG}) {
47: $logfile = $ENV{PKG_CONFIG_LOG};
1.1 ckuethe 48: }
49:
1.33 jasper 50: my $allow_uninstalled =
1.16 espie 51: defined $ENV{PKG_CONFIG_DISABLE_UNINSTALLED} ? 0 : 1;
1.14 espie 52: my $found_uninstalled = 0;
53:
1.95 jasper 54: my $version = '0.29.2'; # pretend to be this version of pkgconfig
1.10 espie 55:
56: my %configs = ();
1.35 espie 57: setup_self();
58:
1.10 espie 59: my %mode = ();
1.11 espie 60: my $variables = {};
1.1 ckuethe 61:
1.56 jasper 62: $variables->{pc_top_builddir} = $ENV{PKG_CONFIG_TOP_BUILD_DIR} //
1.35 espie 63: '$(top_builddir)';
64:
65: $variables->{pc_sysrootdir} //= $ENV{PKG_CONFIG_SYSROOT_DIR};
66: # The default '/' is implied.
1.29 jasper 67:
1.95 jasper 68: my @sys_includes = ('/usr/include');
69: foreach my $path ($ENV{PKG_CONFIG_SYSTEM_INCLUDE_PATH}, $ENV{C_PATH}, $ENV{C_INCLUDE_PATH},
70: $ENV{CPLUS_INCLUDE_PATH}) {
71: next if !defined($path);
72: unshift(@sys_includes, split(/:/, $path));
73: }
74:
1.61 jasper 75: defined $ENV{PKG_CONFIG_DEBUG_SPEW} ? $mode{debug} = 1 : $mode{debug} = 0;
1.7 ckuethe 76:
1.4 espie 77: if ($logfile) {
1.35 espie 78: open my $L, ">>" , $logfile or die;
1.96 ! espie 79: say $L beautify_list($0, @ARGV);
1.4 espie 80: close $L;
1.1 ckuethe 81: }
82:
83: # combo arg-parsing and dependency resolution loop. Hopefully when the loop
84: # terminates, we have a full list of packages upon which we depend, and the
85: # right set of compiler and linker flags to use them.
86: #
87: # as each .pc file is loaded, it is stored in %configs, indexed by package
88: # name. this makes it possible to then pull out flags or do substitutions
1.34 jasper 89: # without having to go back and reload the files from disk.
1.1 ckuethe 90:
91: Getopt::Long::Configure('no_ignore_case');
1.68 jasper 92: GetOptions( 'debug' => \$mode{debug},
93: 'help' => \&help, #does not return
94: 'usage' => \&help, #does not return
95: 'list-all' => \$mode{list},
1.96 ! espie 96: 'version' => sub { say $version ; exit(0);} ,
1.68 jasper 97: 'errors-to-stdout' => sub { $mode{estdout} = 1},
98: 'print-errors' => sub { $mode{printerr} = 1},
99: 'silence-errors' => sub { $mode{printerr} = 0},
100: 'short-errors' => sub { $mode{printerr} = 0},
1.14 espie 101: 'atleast-pkgconfig-version=s' => \$mode{myminvers},
1.68 jasper 102: 'print-provides' => \$mode{printprovides},
103: 'print-requires' => \$mode{printrequires},
1.30 jasper 104: 'print-requires-private' => \$mode{printrequiresprivate},
1.11 espie 105:
1.96 ! espie 106: 'cflags' => sub { $mode{cflags} = ONLY_I|ONLY_OTHER},
! 107: 'cflags-only-I' => sub { $mode{cflags} |= ONLY_I},
! 108: 'cflags-only-other' => sub { $mode{cflags} |= ONLY_OTHER},
! 109: 'libs' => sub { $mode{libs} = ONLY_L|ONLY_l|ONLY_OTHER},
! 110: 'libs-only-l' => sub { $mode{libs} |= ONLY_l},
! 111: 'libs-only-L' => sub { $mode{libs} |= ONLY_L},
! 112: 'libs-only-other' => sub { $mode{libs} |= ONLY_OTHER},
1.68 jasper 113: 'exists' => sub { $mode{exists} = 1} ,
1.91 jasper 114: 'validate' => sub { $mode{validate} = 1},
1.68 jasper 115: 'static' => sub { $mode{static} = 1},
116: 'uninstalled' => sub { $mode{uninstalled} = 1},
117: 'atleast-version=s' => \$mode{minversion},
118: 'exact-version=s' => \$mode{exactversion},
119: 'max-version=s' => \$mode{maxversion},
120: 'modversion' => \$mode{modversion},
121: 'variable=s' => \$mode{variable},
122: 'define-variable=s' => $variables,
1.1 ckuethe 123: );
124:
1.70 jasper 125: # Unconditionally switch to static mode on static arches as --static
126: # may not have been passed explicitly, but we don't want to re-order
127: # and simplify the libs like we do for shared architectures.
128: {
1.88 jasper 129: my @static_archs = qw();
1.70 jasper 130: my $machine_arch = $Config{'ARCH'};
131: if (grep { $_ eq $machine_arch } @static_archs){
132: $mode{static} = 1;
133: }
134: }
135:
1.14 espie 136: # Initial value of printerr depends on the options...
137: if (!defined $mode{printerr}) {
1.61 jasper 138: if (defined $mode{libs}
139: or defined $mode{cflags}
140: or defined $mode{version}
1.91 jasper 141: or defined $mode{list}
142: or defined $mode{validate}) {
1.14 espie 143: $mode{printerr} = 1;
144: } else {
145: $mode{printerr} = 0;
146: }
147: }
148:
1.62 jasper 149: say_debug("\n" . beautify_list($0, @ARGV));
1.13 espie 150:
151: my $rc = 0;
1.1 ckuethe 152:
1.14 espie 153: # XXX pkg-config is a bit weird
1.10 espie 154: {
155: my $p = join(' ', @ARGV);
1.14 espie 156: $p =~ s/^\s+//;
1.66 jasper 157: @ARGV = split(/\,?\s+/, $p);
1.10 espie 158: }
1.1 ckuethe 159:
1.14 espie 160: if ($mode{myminvers}) {
161: exit self_version($mode{myminvers});
162: }
163:
164: if ($mode{list}) {
165: exit do_list();
1.1 ckuethe 166: }
167:
1.13 espie 168: my $cfg_full_list = [];
1.14 espie 169: my $top_config = [];
1.73 jasper 170:
171: # When we got here we're supposed to have had at least one
172: # package as argument.
1.96 ! espie 173: if (!@ARGV) {
1.73 jasper 174: say_error("No package name(s) specified.");
175: exit 1;
176: }
1.1 ckuethe 177:
1.86 jasper 178: # Return the next module from @ARGV, if it turns out to be a comma separated
179: # module list, take the first one and put the rest back to the front.
1.96 ! espie 180: sub get_next_module()
1.93 espie 181: {
1.86 jasper 182: my $module = shift @ARGV;
183: my $m;
184: if ($module =~ m/,/) {
185: my @ms = split(/,/, $module);
186: $m = shift @ms;
1.96 ! espie 187: unshift(@ARGV, @ms) if @ms != 0;
1.86 jasper 188: } else {
1.96 ! espie 189: return $module;
1.86 jasper 190: }
191:
192: return $m;
193: }
194:
1.96 ! espie 195: while (@ARGV) {
1.86 jasper 196: my $p = get_next_module();
1.13 espie 197: my $op = undef;
198: my $v = undef;
1.85 jca 199: if (@ARGV >= 2 && $ARGV[0] =~ /^[<=>!]+$/ &&
1.59 jasper 200: $ARGV[1] =~ /^[\d\.]+[\w\.]*$/) {
1.13 espie 201: $op = shift @ARGV;
202: $v = shift @ARGV;
1.1 ckuethe 203: }
1.52 jasper 204: # For these modes we just need some meta-information and
205: # parsing the requirements is not needed.
206: if (!($mode{modversion} || $mode{printprovides})) {
207: handle_config($p, $op, $v, $cfg_full_list);
208: }
1.14 espie 209: push(@$top_config, $p);
210: }
211:
1.91 jasper 212: if ($mode{exists} || $mode{validate}) {
1.14 espie 213: exit $rc;
214: }
215:
216: if ($mode{uninstalled}) {
217: $rc = 1 unless $found_uninstalled;
218: exit $rc;
1.11 espie 219: }
1.1 ckuethe 220:
1.30 jasper 221: if ($mode{modversion} || $mode{printprovides}) {
1.14 espie 222: for my $pkg (@$top_config) {
223: do_modversion($pkg);
224: }
225: }
1.13 espie 226:
1.30 jasper 227: if ($mode{printrequires} || $mode{printrequiresprivate}) {
228: for my $pkg (@$top_config) {
229: print_requires($pkg);
230: }
231: }
232:
1.14 espie 233: if ($mode{minversion}) {
234: my $v = $mode{minversion};
235: for my $pkg (@$top_config) {
236: $rc = 1 unless versionmatch($configs{$pkg}, '>=', $v);
237: }
238: exit $rc;
239: }
240:
241: if ($mode{exactversion}) {
242: my $v = $mode{exactversion};
243: for my $pkg (@$top_config) {
244: $rc = 1 unless versionmatch($configs{$pkg}, '=', $v);
245: }
246: exit $rc;
247: }
248:
1.76 jasper 249: if ($mode{maxversion}) {
1.14 espie 250: my $v = $mode{maxversion};
251: for my $pkg (@$top_config) {
252: $rc = 1 unless versionmatch($configs{$pkg}, '<=', $v);
253: }
254: exit $rc;
255: }
256:
257: my @vlist = ();
258:
259: if ($mode{variable}) {
260: for my $pkg (@$top_config) {
261: do_variable($pkg, $mode{variable});
262: }
263: }
264:
1.70 jasper 265: my $dep_cfg_list = $cfg_full_list;
266:
1.72 espie 267: if ($mode{static}){
268: $dep_cfg_list = [reverse(@$cfg_full_list)];
269: } else {
1.70 jasper 270: $dep_cfg_list = simplify_and_reverse($cfg_full_list);
271: }
1.14 espie 272:
273: if ($mode{cflags} || $mode{libs} || $mode{variable}) {
1.66 jasper 274: push @vlist, do_cflags($dep_cfg_list) if $mode{cflags};
275: push @vlist, do_libs($dep_cfg_list) if $mode{libs};
1.96 ! espie 276: say join(' ', @vlist) if $rc == 0;
1.1 ckuethe 277: }
278:
1.13 espie 279: exit $rc;
1.1 ckuethe 280:
281: ###########################################################################
282:
1.96 ! espie 283: sub handle_config($p, $op, $v, $list)
1.11 espie 284: {
1.35 espie 285: my $cfg = cache_find_config($p);
1.13 espie 286:
1.35 espie 287: unshift @$list, $p if defined $cfg;
1.11 espie 288:
1.35 espie 289: if (!defined $cfg) {
290: $rc = 1;
291: return undef;
292: }
1.15 espie 293:
1.35 espie 294: if (defined $op) {
295: if (!versionmatch($cfg, $op, $v)) {
296: mismatch($p, $cfg, $op, $v) if $mode{printerr};
1.13 espie 297: $rc = 1;
298: return undef;
299: }
1.35 espie 300: }
1.11 espie 301:
1.96 ! espie 302: my $get_props = sub($property) {
1.93 espie 303: my $pkg;
1.43 jasper 304:
1.94 jasper 305: # See if there's anything in the environment that we need to
1.93 espie 306: # take into account.
307: ($pkg = $p) =~ s/(^.*\/)?(.*?)\.pc$/$2/g;
308: $pkg = uc($pkg);
309:
310: if (grep {/PKG_CONFIG_${pkg}.*/} keys %ENV) {
1.94 jasper 311: # Now that we know we have something to look for, do
1.93 espie 312: # the inefficient iteration.
313: while (my ($k, $v) = each %ENV) {
314: if ($k =~ /^PKG_CONFIG_${pkg}_(\w+)/) {
315: $variables->{lc($1)} = $v;
316: }
317: }
318: }
319:
320: my $deps = $cfg->get_property($property, $variables);
321: return unless defined $deps;
322: for my $dep (@$deps) {
1.96 ! espie 323: if ($dep =~ m/^(.*?)\s*([<=>]+)\s*([\d\.]+|[\d\.]+\w*\d+)$/) {
1.93 espie 324: handle_config($1, $2, $3, $list);
325: } else {
326: handle_config($dep, undef, undef, $list);
327: }
328: }
329: say_debug("package $p " . lc($property) . " " . join(',', @$deps));
1.43 jasper 330: };
331:
1.66 jasper 332: if (defined $mode{cflags}
333: or ($mode{static} && $mode{libs})
1.74 jasper 334: or $mode{printrequiresprivate}
335: or $mode{exists}) {
1.64 jasper 336: &$get_props("Requires.private");
337: }
1.91 jasper 338:
339: unless (defined $mode{validate}) {
340: &$get_props("Requires");
341: }
1.11 espie 342: }
343:
1.1 ckuethe 344: # look for the .pc file in each of the PKGPATH elements. Return the path or
345: # undef if it's not there
1.96 ! espie 346: sub pathresolve($p)
1.4 espie 347: {
1.14 espie 348: if ($allow_uninstalled && $p !~ m/\-uninstalled$/) {
1.93 espie 349: for my $d (@PKGPATH) {
1.14 espie 350: my $f = "$d/$p-uninstalled.pc";
1.62 jasper 351: say_debug("pathresolve($p) looking in $f");
1.14 espie 352: if (-f $f) {
353: $found_uninstalled = 1;
354: return $f;
355: }
356: }
357: }
358:
1.93 espie 359: for my $d (@PKGPATH) {
1.10 espie 360: my $f = "$d/$p.pc";
1.62 jasper 361: say_debug("pathresolve($p) looking in $f");
1.10 espie 362: return $f if -f $f;
1.1 ckuethe 363: }
1.10 espie 364: return undef;
1.1 ckuethe 365: }
366:
1.96 ! espie 367: sub get_config($f)
1.11 espie 368: {
369: my $cfg;
1.33 jasper 370: eval {
1.96 ! espie 371: $cfg = OpenBSD::PkgConfig->read_file($f);
1.11 espie 372: };
373: if (!$@) {
1.37 jasper 374: return validate_config($f, $cfg);
1.11 espie 375: } else {
1.62 jasper 376: say_debug($@);
1.11 espie 377: }
378: return undef;
379: }
380:
1.96 ! espie 381: sub cache_find_config($name)
1.13 espie 382: {
1.62 jasper 383: say_debug("processing $name");
1.13 espie 384:
385: if (exists $configs{$name}) {
386: return $configs{$name};
387: } else {
388: return $configs{$name} = find_config($name);
389: }
1.37 jasper 390: }
391:
392: # Required elements for a valid .pc file: Name, Description, Version
1.96 ! espie 393: sub validate_config($f, $cfg)
1.37 jasper 394: {
395: my @required_elems = ('Name', 'Description', 'Version');
1.58 jasper 396:
397: # Check if we're dealing with an empty file, but don't error out just
398: # yet, we'll do that when we realize there's no Name field.
1.61 jasper 399: if (stat($f)->size == 0) {
1.80 jasper 400: say_error("Package file '$f' appears to be empty");
1.58 jasper 401: }
1.37 jasper 402:
1.93 espie 403: for my $p (@required_elems) {
404: my $e = $cfg->get_property($p, $variables);
1.37 jasper 405: if (!defined $e) {
1.91 jasper 406: $f =~ s/(^.*\/)?(.*?)\.pc$/$2/g;
1.93 espie 407: say_error("Package '$f' has no $p: field");
1.37 jasper 408: return undef;
409: }
410: }
411:
412: return $cfg;
1.13 espie 413: }
414:
1.35 espie 415: # pkg-config won't install a pkg-config.pc file itself, but it may be
1.63 jasper 416: # listed as a dependency in other files. so prime the cache with self.
1.96 ! espie 417: sub setup_self()
1.35 espie 418: {
419: my $pkg_pc = OpenBSD::PkgConfig->new;
420: $pkg_pc->add_property('Version', $version);
1.38 jasper 421: $pkg_pc->add_variable('pc_path', join(":", @PKGPATH));
1.87 tb 422: $pkg_pc->add_property('URL', "http://man.openbsd.org/pkg-config");
1.63 jasper 423: $pkg_pc->add_property('Description', "fetch metadata about installed software packages");
1.35 espie 424: $configs{'pkg-config'} = $pkg_pc;
425: }
426:
1.96 ! espie 427: sub find_config($p)
1.11 espie 428: {
1.78 jasper 429: # Differentiate between getting a full path and just the module name.
430: my $f = ($p =~ m/\.pc$/ ? $p : pathresolve($p));
1.64 jasper 431:
432: return get_config($f) if defined($f);
433:
1.62 jasper 434: say_error("Package $p was not found in the pkg-config search path");
1.61 jasper 435:
1.11 espie 436: return undef;
437: }
1.1 ckuethe 438:
1.96 ! espie 439: sub stringize($list, $sep = ',')
1.4 espie 440: {
1.11 espie 441: if (defined $list) {
1.21 simon 442: return join($sep, @$list)
1.11 espie 443: } else {
444: return '';
1.1 ckuethe 445: }
446: }
447:
448: #if the variable option is set, pull out the named variable
1.96 ! espie 449: sub do_variable($p, $v)
1.4 espie 450: {
1.13 espie 451: my $cfg = cache_find_config($p);
452:
453: if (defined $cfg) {
1.11 espie 454: my $value = $cfg->get_variable($v, $variables);
455: if (defined $value) {
1.13 espie 456: push(@vlist, $value);
1.11 espie 457: }
1.19 espie 458: return undef;
1.11 espie 459: }
1.19 espie 460: $rc = 1;
1.1 ckuethe 461: }
462:
1.30 jasper 463: #if the modversion or print-provides options are set,
464: #pull out the compiler flags
1.96 ! espie 465: sub do_modversion($p)
1.4 espie 466: {
1.13 espie 467: my $cfg = cache_find_config($p);
468:
469: if (defined $cfg) {
1.11 espie 470: my $value = $cfg->get_property('Version', $variables);
471: if (defined $value) {
1.60 jasper 472: if (defined($mode{printprovides})){
1.96 ! espie 473: say "$p = " , stringize($value);
1.30 jasper 474: return undef;
475: } else {
1.96 ! espie 476: say stringize($value);
1.30 jasper 477: return undef;
478: }
1.11 espie 479: }
480: }
1.13 espie 481: $rc = 1;
1.1 ckuethe 482: }
483:
484: #if the cflags option is set, pull out the compiler flags
1.96 ! espie 485: sub do_cflags($list)
1.4 espie 486: {
1.11 espie 487: my $cflags = [];
1.1 ckuethe 488:
1.93 espie 489: for my $pkg (@$list) {
1.11 espie 490: my $l = $configs{$pkg}->get_property('Cflags', $variables);
1.95 jasper 491: PATH: for my $path (@$l) {
492: for my $sys_path (@sys_includes) {
1.96 ! espie 493: next PATH if $path =~ /\Q${sys_path}\E\/*$/;
1.89 jasper 494: }
1.95 jasper 495: push(@$cflags, $path);
1.89 jasper 496: }
1.11 espie 497: }
1.32 jasper 498: my $a = OpenBSD::PkgConfig->compress($cflags,
1.96 ! espie 499: sub($r) {
! 500: if (($mode{cflags} & ONLY_I) && $r =~ /^-I/ ||
! 501: ($mode{cflags} & ONLY_OTHER) && $r !~ /^-I/) {
1.11 espie 502: return 1;
503: } else {
504: return 0;
1.4 espie 505: }
1.11 espie 506: });
1.96 ! espie 507: if (defined($variables->{pc_sysrootdir})){
1.36 jasper 508: $a =~ s/[\w]?-I/$&$variables->{pc_sysrootdir}/g;
1.32 jasper 509: }
510:
511: return $a;
1.1 ckuethe 512: }
513:
514: #if the lib option is set, pull out the linker flags
1.96 ! espie 515: sub do_libs($list)
1.4 espie 516: {
1.11 espie 517: my $libs = [];
1.1 ckuethe 518:
1.68 jasper 519: # In static mode, we have to make sure we discover the libs in dependency
520: # order, not in search order. Ordering matters for static linking:
521: # Start with Libs (first our own, then dependencies), and append
522: # Libs.private (same order as for Libs).
1.93 espie 523: for my $pkg (@$list) {
1.11 espie 524: my $l = $configs{$pkg}->get_property('Libs', $variables);
1.93 espie 525: for my $path (@$l) {
526: unless ($path =~ /-L\/usr\/lib\/*$/) {
527: push(@$libs, $path);
1.89 jasper 528: }
529: }
1.67 jasper 530: if ($mode{static}) {
531: my $lp = $configs{$pkg}->get_property('Libs.private', $variables);
1.93 espie 532: for my $path (@$lp) {
533: unless ($path =~ /-L\/usr\/lib\/*/) {
534: push(@$libs, $path);
1.89 jasper 535: }
536: }
1.67 jasper 537: }
1.11 espie 538: }
1.66 jasper 539:
1.68 jasper 540: # Get the linker path directives (-L) and store it in $a.
541: # $b will be the actual libraries.
1.96 ! espie 542: my $r = OpenBSD::PkgConfig->compress_list($libs,
! 543: sub($r) {
! 544: if (($mode{libs} & ONLY_L) && $r =~ /^-L/ ||
! 545: ($mode{libs} & ONLY_OTHER) && $r !~ /^-[lL]/) {
1.93 espie 546: return 1;
547: } else {
548: return 0;
549: }
550: });
1.32 jasper 551:
552: if (defined($variables->{pc_sysrootdir})){
1.96 ! espie 553: for my $i (@$r) {
! 554: $i =~ s/[\w]?-[lL]/$&$variables->{pc_sysrootdir}/;
! 555: }
1.32 jasper 556: }
557:
1.96 ! espie 558: if ($mode{libs} & ONLY_l) {
! 559: push(@$r, OpenBSD::PkgConfig->rcompress($libs,
! 560: sub($l) { $l =~ m/^-l/; }));
1.13 espie 561: }
1.96 ! espie 562: return @$r;
1.1 ckuethe 563: }
564:
565: #list all packages
1.96 ! espie 566: sub do_list()
1.4 espie 567: {
1.1 ckuethe 568: my ($p, $x, $y, @files, $fname, $name);
1.96 ! espie 569:
1.20 espie 570: my $error = 0;
571:
1.93 espie 572: for my $p (@PKGPATH) {
1.33 jasper 573: push(@files, <$p/*.pc>);
1.4 espie 574: }
1.1 ckuethe 575:
576: # Scan the lengths of the package names so I can make a format
577: # string to line the list up just like the real pkgconfig does.
578: $x = 0;
1.93 espie 579: for my $f (@files) {
1.4 espie 580: $fname = basename($f, '.pc');
581: $y = length $fname;
1.1 ckuethe 582: $x = (($y > $x) ? $y : $x);
583: }
584: $x *= -1;
585:
1.93 espie 586: for my $f (@files) {
1.11 espie 587: my $cfg = get_config($f);
1.20 espie 588: if (!defined $cfg) {
1.62 jasper 589: say_warning("Problem reading file $f");
1.20 espie 590: $error = 1;
591: next;
592: }
1.4 espie 593: $fname = basename($f, '.pc');
1.33 jasper 594: printf("%${x}s %s - %s\n", $fname,
1.53 jasper 595: stringize($cfg->get_property('Name', $variables), ' '),
1.21 simon 596: stringize($cfg->get_property('Description', $variables),
597: ' '));
1.1 ckuethe 598: }
1.20 espie 599: return $error;
1.1 ckuethe 600: }
601:
1.96 ! espie 602: sub help(@)
1.4 espie 603: {
1.1 ckuethe 604: print <<EOF
605: Usage: $0 [options]
606: --debug - turn on debugging output
607: --help - this message
608: --usage - this message
609: --list-all - show all packages that $0 can find
1.8 ckuethe 610: --version - print version of pkgconfig
611: --errors-to-stdout - direct error messages to stdout rather than stderr
612: --print-errors - print error messages in case of error
1.34 jasper 613: --print-provides - print all the modules the given package provides
614: --print-requires - print all the modules the given package requires
615: --print-requires-private - print all the private modules the given package requires
1.66 jasper 616: --silence-errors - don\'t print error messages in case of error
1.1 ckuethe 617: --atleast-pkgconfig-version [version] - require a certain version of pkgconfig
618: --cflags package [versionspec] [package [versionspec]]
619: --cflags-only-I - only output -Iincludepath flags
620: --cflags-only-other - only output flags that are not -I
1.11 espie 621: --define-variable=NAME=VALUE - define variables
1.1 ckuethe 622: --libs package [versionspec] [package [versionspec]]
623: --libs-only-l - only output -llib flags
624: --libs-only-L - only output -Llibpath flags
625: --libs-only-other - only output flags that are not -l or -L
626: --exists package [versionspec] [package [versionspec]]
1.91 jasper 627: --validate package
1.1 ckuethe 628: --uninstalled - allow for uninstalled versions to be used
1.8 ckuethe 629: --static - adjust output for static linking
630: --atleast-version [version] - require a certain version of a package
1.77 jasper 631: --exact-version [version] - require exactly the specified version of a package
632: --max-version [version] - require at most a certain version of a package
1.8 ckuethe 633: --modversion [package] - query the version of a package
634: --variable var package - return the definition of <var> in <package>
1.1 ckuethe 635: EOF
636: ;
1.22 simon 637: exit 0;
1.1 ckuethe 638: }
639:
640: # do we meet/beat the version the caller requested?
1.96 ! espie 641: sub self_version($v)
1.4 espie 642: {
643: my (@a, @b);
644:
1.66 jasper 645: @a = split(/\./, $v);
646: @b = split(/\./, $version);
1.1 ckuethe 647:
1.4 espie 648: if (($b[0] >= $a[0]) && ($b[1] >= $a[1])) {
1.14 espie 649: return 0;
1.1 ckuethe 650: } else {
1.14 espie 651: return 1;
652: }
653: }
654:
1.96 ! espie 655: sub parse_suffix($s)
1.14 espie 656: {
1.96 ! espie 657: my @l = ();
! 658: my $full = $s;
1.46 jasper 659: # is there a valid non-numeric suffix to deal with later?
1.58 jasper 660: # accepted are (in order): a(lpha) < b(eta) < rc < ' '.
1.46 jasper 661: # suffix[0] is the 'alpha' part, suffix[1] is the '1' part in 'alpha1'.
1.96 ! espie 662: if ($s =~ s/(rc|beta|b|alpha|a)(\d+)$//) {
! 663: @l = ($1, $2);
1.46 jasper 664: }
1.96 ! espie 665: # also deal with -stable extension
! 666: elsif ($s =~ s/(\-stable)$//) {
! 667: @l = ($1);
1.82 jasper 668: }
669: # The above are standard suffixes; deal with single alphabetical
670: # suffixes too, e.g. 1.0.1h
1.96 ! espie 671: elsif ($s =~ s/([a-zA-Z]){1}$//) {
! 672: @l = ($1);
1.82 jasper 673: }
674:
1.96 ! espie 675: if (@l) {
! 676: say_debug("valid suffix @l found in $full.");
! 677: }
! 678:
! 679: return ($s, @l);
! 680: }
! 681:
! 682: sub compare($full_a, $full_b)
! 683: {
! 684: return 0 if $full_a eq $full_b;
! 685:
! 686: my ($a, @suffix_a) = parse_suffix($full_a);
! 687: my ($b, @suffix_b) = parse_suffix($full_b);
1.46 jasper 688:
1.66 jasper 689: my @a = split(/\./, $a);
690: my @b = split(/\./, $b);
1.14 espie 691:
692: while (@a && @b) { #so long as both lists have something
1.46 jasper 693: if (!(@suffix_a || @suffix_b)) {
694: # simple comparison when no suffixes are in the game.
1.48 jasper 695: my $rc = compare_numeric($a[0], $b[0], 0);
696: return $rc if defined($rc);
1.46 jasper 697: } else {
698: # extended comparison.
1.56 jasper 699: if (((@a == 1) || (@b == 1)) &&
1.46 jasper 700: ($a[0] == $b[0])){
701: # one of the arrays has reached the last element,
702: # compare the suffix.
703:
704: # directly compare suffixes, provided both suffixes
705: # are present.
706: if (@suffix_a && @suffix_b) {
1.96 ! espie 707: my $first_char = sub($s) {
! 708: return substr($s, 0, 1);
1.46 jasper 709: };
710:
711: # suffixes are equal, compare on numeric
712: if (&$first_char($suffix_a[0]) eq
713: &$first_char($suffix_b[0])) {
1.48 jasper 714: return compare_numeric($suffix_a[1], $suffix_b[1], 1);
1.46 jasper 715: }
716:
1.47 jasper 717: # rc beats beta beats alpha
1.46 jasper 718: if (&$first_char($suffix_a[0]) lt &$first_char($suffix_b[0])) {
1.62 jasper 719: say_debug("$full_a (installed) < $full_b (wanted)");
1.46 jasper 720: return -1;
721: } else {
1.62 jasper 722: say_debug("$full_a (installed) > $full_b (wanted)");
1.46 jasper 723: return 1;
724: }
725:
726: } else {
727: # one of either is lacking a suffix,
728: # thereby beating the other.
729: # e.g.: 1.02 > 1.02b1
730: if (@suffix_a) { # a is older
1.62 jasper 731: say_debug("$full_a (installed) < $full_b (wanted)");
1.55 jasper 732: return 1;
1.46 jasper 733: }
734:
735: if (@suffix_b) { # b is older
1.62 jasper 736: say_debug("$full_a (installed) > $full_b (wanted)");
1.55 jasper 737: return -1;
1.46 jasper 738: }
739: }
740: } else {
1.48 jasper 741: my $rc = compare_numeric($a[0], $b[0], 0);
742: return $rc if defined($rc);
1.46 jasper 743: }
744: }
1.14 espie 745: shift @a; shift @b;
746: }
747: return 1 if @a;
748: return -1 if @b;
749: return 0;
1.48 jasper 750: }
751:
752: # simple numeric comparison, with optional equality test.
1.96 ! espie 753: sub compare_numeric($x, $y, $eq)
1.48 jasper 754: {
1.81 jasper 755: return 1 if $x > $y;
1.48 jasper 756: return -1 if $x < $y;
1.81 jasper 757: return 0 if (($x == $y) and ($eq == 1));
1.48 jasper 758: return undef;
1.1 ckuethe 759: }
760:
761: # got a package meeting the requested specific version?
1.96 ! espie 762: sub versionmatch($cfg, $op, $want)
1.4 espie 763: {
1.1 ckuethe 764: # can't possibly match if we can't find the file
1.11 espie 765: return 0 if !defined $cfg;
766:
1.14 espie 767: my $inst = stringize($cfg->get_property('Version', $variables));
1.11 espie 768:
1.1 ckuethe 769: # can't possibly match if we can't find the version string
1.14 espie 770: return 0 if $inst eq '';
1.1 ckuethe 771:
1.62 jasper 772: say_debug("comparing $want (wanted) to $inst (installed)");
1.14 espie 773: my $value = compare($inst, $want);
1.31 jasper 774: if ($op eq '>=') { return $value >= 0; }
775: elsif ($op eq '=') { return $value == 0; }
776: elsif ($op eq '!=') { return $value != 0; }
777: elsif ($op eq '<') { return $value < 0; }
778: elsif ($op eq '>') { return $value > 0; }
779: elsif ($op eq '<=') { return $value <= 0; }
1.13 espie 780: }
781:
1.96 ! espie 782: sub mismatch($p, $cfg, $op, $v)
1.13 espie 783: {
1.53 jasper 784: my $name = stringize($cfg->get_property('Name'), ' ');
1.41 jasper 785: my $version = stringize($cfg->get_property('Version'));
786: my $url = stringize($cfg->get_property('URL'));
787:
1.62 jasper 788: say_warning("Requested '$p $op $v' but version of $name is $version");
789: say_warning("You may find new versions of $name at $url") if $url;
1.13 espie 790: }
791:
1.96 ! espie 792: sub simplify_and_reverse($reqlist)
1.13 espie 793: {
794: my $dejavu = {};
795: my $result = [];
796:
797: for my $item (@$reqlist) {
798: if (!$dejavu->{$item}) {
799: unshift @$result, $item;
800: $dejavu->{$item} = 1;
801: }
802: }
803: return $result;
1.30 jasper 804: }
805:
806: # retrieve and print Requires(.private)
1.96 ! espie 807: sub print_requires($p)
1.30 jasper 808: {
809: my $cfg = cache_find_config($p);
810:
811: if (defined($cfg)) {
812: my $value;
813:
814: if (defined($mode{printrequires})) {
815: $value = $cfg->get_property('Requires', $variables);
816: } elsif (defined($mode{printrequiresprivate})) {
817: $value = $cfg->get_property('Requires.private', $variables);
818: } else {
1.62 jasper 819: say_debug("Unknown mode for print_requires.");
1.30 jasper 820: return 1;
821: }
822:
823: if (defined($value)) {
1.96 ! espie 824: say $_ for @$value;
1.30 jasper 825: return undef;
826: }
827: }
828:
829: $rc = 1;
1.35 espie 830: }
831:
1.96 ! espie 832: sub beautify_list(@p)
1.35 espie 833: {
1.96 ! espie 834: return join(' ', map {"[$_]"} @p);
1.61 jasper 835: }
836:
1.96 ! espie 837: sub say_debug($msg)
1.61 jasper 838: {
1.96 ! espie 839: say_msg($msg) if $mode{debug};
1.61 jasper 840: }
841:
1.96 ! espie 842: sub say_error($msg)
1.61 jasper 843: {
1.96 ! espie 844: say_msg($msg) if $mode{printerr}
1.62 jasper 845: }
846:
1.96 ! espie 847: sub say_warning($msg)
1.62 jasper 848: {
1.96 ! espie 849: say_msg($msg);
1.62 jasper 850: }
851:
1.96 ! espie 852: sub say_msg($str)
1.62 jasper 853: {
854: # If --errors-to-stdout was given, close STDERR (to be safe),
855: # then dup the output to STDOUT and delete the key from %mode so we
856: # won't keep checking it. STDERR stays dup'ed.
857: if ($mode{estdout}) {
858: close(STDERR);
859: open(STDERR, ">&STDOUT") or die "Can't dup STDOUT: $!";
860: delete($mode{estdout});
861: }
862:
1.96 ! espie 863: say STDERR $str;
1.1 ckuethe 864: }