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