Annotation of src/usr.bin/pkg-config/pkg-config, Revision 1.54
1.1 ckuethe 1: #!/usr/bin/perl
1.54 ! jasper 2: # $OpenBSD: pkg-config,v 1.53 2011/06/07 12:22:46 jasper 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.40 jasper 6: # Copyright (c) 2011 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;
22: use Getopt::Long;
1.4 espie 23: use File::Basename;
1.11 espie 24: use OpenBSD::PkgConfig;
1.1 ckuethe 25:
1.27 jasper 26: my @PKGPATH = qw(/usr/lib/pkgconfig /usr/local/lib/pkgconfig /usr/X11R6/lib/pkgconfig);
1.1 ckuethe 27:
1.16 espie 28: if (defined($ENV{PKG_CONFIG_LIBDIR}) && $ENV{PKG_CONFIG_LIBDIR}) {
29: @PKGPATH = split /:/, $ENV{PKG_CONFIG_LIBDIR};
30: } elsif (defined($ENV{PKG_CONFIG_PATH}) && $ENV{PKG_CONFIG_PATH}) {
1.24 ckuethe 31: unshift(@PKGPATH, split /:/, $ENV{PKG_CONFIG_PATH});
1.1 ckuethe 32: }
33:
34: my $logfile = '';
1.50 jasper 35: if (defined($ENV{PKG_CONFIG_LOG}) && $ENV{PKG_CONFIG_LOG}) {
36: $logfile = $ENV{PKG_CONFIG_LOG};
1.1 ckuethe 37: }
38:
1.33 jasper 39: my $allow_uninstalled =
1.16 espie 40: defined $ENV{PKG_CONFIG_DISABLE_UNINSTALLED} ? 0 : 1;
1.14 espie 41: my $found_uninstalled = 0;
42:
1.49 jasper 43: my $version = 0.25; # pretend to be this version of pkgconfig
1.10 espie 44:
45: my %configs = ();
1.35 espie 46: setup_self();
47:
1.10 espie 48: my %mode = ();
1.11 espie 49: my $variables = {};
1.10 espie 50: my $D = 0; # debug flag
1.1 ckuethe 51:
1.35 espie 52: $variables->{pc_top_builddir} = $ENV{PKG_CONFIG_TOP_BUILD_DIR} //
53: '$(top_builddir)';
54:
55: $variables->{pc_sysrootdir} //= $ENV{PKG_CONFIG_SYSROOT_DIR};
56: # The default '/' is implied.
1.29 jasper 57:
1.35 espie 58: $D = 1 if defined $ENV{PKG_CONFIG_DEBUG_SPEW};
1.7 ckuethe 59:
1.4 espie 60: if ($logfile) {
1.35 espie 61: open my $L, ">>" , $logfile or die;
1.51 jasper 62: print $L beautify_list($0, @ARGV), "\n";
1.4 espie 63: close $L;
1.1 ckuethe 64: }
65:
66: # combo arg-parsing and dependency resolution loop. Hopefully when the loop
67: # terminates, we have a full list of packages upon which we depend, and the
68: # right set of compiler and linker flags to use them.
69: #
70: # as each .pc file is loaded, it is stored in %configs, indexed by package
71: # name. this makes it possible to then pull out flags or do substitutions
1.34 jasper 72: # without having to go back and reload the files from disk.
1.1 ckuethe 73:
74: Getopt::Long::Configure('no_ignore_case');
75: GetOptions( 'debug' => \$D,
76: 'help' => \&help, #does not return
77: 'usage' => \&help, #does not return
1.14 espie 78: 'list-all' => \$mode{list},
1.1 ckuethe 79: 'version' => sub { print "$version\n" ; exit(0);} ,
1.11 espie 80: 'errors-to-stdout' => sub { $mode{estdout} = 1},
81: 'print-errors' => sub { $mode{printerr} = 1},
82: 'silence-errors' => sub { $mode{printerr} = 0},
1.23 jasper 83: 'short-errors' => sub { $mode{printerr} = 0},
1.14 espie 84: 'atleast-pkgconfig-version=s' => \$mode{myminvers},
1.30 jasper 85: 'print-provides' => \$mode{printprovides},
86: 'print-requires' => \$mode{printrequires},
87: 'print-requires-private' => \$mode{printrequiresprivate},
1.11 espie 88:
89: 'cflags' => sub { $mode{cflags} = 3},
90: 'cflags-only-I' => sub { $mode{cflags} |= 1},
91: 'cflags-only-other' => sub { $mode{cflags} |= 2},
92: 'libs' => sub { $mode{libs} = 7},
93: 'libs-only-l' => sub { $mode{libs} |= 1},
94: 'libs-only-L' => sub { $mode{libs} |= 2},
95: 'libs-only-other' => sub { $mode{libs} |= 4},
96: 'exists' => sub { $mode{exists} = 1} ,
97: 'static' => sub { $mode{static} = 1},
98: 'uninstalled' => sub { $mode{uninstalled} = 1},
1.14 espie 99: 'atleast-version=s' => \$mode{minversion},
100: 'exact-version=s' => \$mode{exactversion},
101: 'max-version=s' => \$mode{maxversion},
1.13 espie 102: 'modversion' => \$mode{modversion},
1.11 espie 103: 'variable=s' => \$mode{variable},
104: 'define-variable=s' => $variables,
1.1 ckuethe 105: );
106:
1.14 espie 107: # Initial value of printerr depends on the options...
108: if (!defined $mode{printerr}) {
1.33 jasper 109: if (defined $mode{libs} || defined $mode{cflags}
1.14 espie 110: || defined $mode{version} || defined $mode{list}) {
111: $mode{printerr} = 1;
112: } else {
113: $mode{printerr} = 0;
114: }
115: }
116:
1.35 espie 117: print STDERR "\n", beautify_list($0, @ARGV), "\n" if $D;
1.13 espie 118:
119: my $rc = 0;
1.1 ckuethe 120:
1.14 espie 121: # XXX pkg-config is a bit weird
1.10 espie 122: {
123: my $p = join(' ', @ARGV);
1.14 espie 124: $p =~ s/^\s+//;
1.35 espie 125: @ARGV = split /\,?\s+/, $p;
1.10 espie 126: }
1.1 ckuethe 127:
1.14 espie 128: if ($mode{myminvers}) {
129: exit self_version($mode{myminvers});
130: }
131:
132: if ($mode{list}) {
133: exit do_list();
1.1 ckuethe 134: }
135:
1.13 espie 136: my $cfg_full_list = [];
1.14 espie 137: my $top_config = [];
1.1 ckuethe 138:
139: while (@ARGV){
1.13 espie 140: my $p = shift @ARGV;
141: my $op = undef;
142: my $v = undef;
1.35 espie 143: if (@ARGV >= 2 && $ARGV[0] =~ /^[<=>]+$/ &&
1.42 espie 144: $ARGV[1] =~ /^[\d\.]+\w?$/) {
1.13 espie 145: $op = shift @ARGV;
146: $v = shift @ARGV;
1.1 ckuethe 147: }
1.52 jasper 148: # For these modes we just need some meta-information and
149: # parsing the requirements is not needed.
150: if (!($mode{modversion} || $mode{printprovides})) {
151: handle_config($p, $op, $v, $cfg_full_list);
152: }
1.14 espie 153: push(@$top_config, $p);
154: }
155:
156: if ($mode{exists}) {
157: exit $rc;
158: }
159:
160: if ($mode{uninstalled}) {
161: $rc = 1 unless $found_uninstalled;
162: exit $rc;
1.11 espie 163: }
1.1 ckuethe 164:
1.30 jasper 165: if ($mode{modversion} || $mode{printprovides}) {
1.14 espie 166: for my $pkg (@$top_config) {
167: do_modversion($pkg);
168: }
169: }
1.13 espie 170:
1.30 jasper 171: if ($mode{printrequires} || $mode{printrequiresprivate}) {
172: for my $pkg (@$top_config) {
173: print_requires($pkg);
174: }
175: }
176:
1.14 espie 177: if ($mode{minversion}) {
178: my $v = $mode{minversion};
179: for my $pkg (@$top_config) {
180: $rc = 1 unless versionmatch($configs{$pkg}, '>=', $v);
181: }
182: exit $rc;
183: }
184:
185: if ($mode{exactversion}) {
186: my $v = $mode{exactversion};
187: for my $pkg (@$top_config) {
188: $rc = 1 unless versionmatch($configs{$pkg}, '=', $v);
189: }
190: exit $rc;
191: }
192:
193: if ($mode{minversion}) {
194: my $v = $mode{maxversion};
195: for my $pkg (@$top_config) {
196: $rc = 1 unless versionmatch($configs{$pkg}, '<=', $v);
197: }
198: exit $rc;
199: }
200:
201: my @vlist = ();
202:
203: if ($mode{variable}) {
204: for my $pkg (@$top_config) {
205: do_variable($pkg, $mode{variable});
206: }
207: }
208:
209: my $dep_cfg_list = simplify_and_reverse($cfg_full_list);
210:
211: if ($mode{cflags} || $mode{libs} || $mode{variable}) {
212: push @vlist, do_cflags($dep_cfg_list) if $mode{cflags};
213: push @vlist, do_libs($dep_cfg_list) if $mode{libs};
1.17 espie 214: print join(' ', @vlist), "\n" if $rc == 0;
1.1 ckuethe 215: }
216:
1.13 espie 217: exit $rc;
1.1 ckuethe 218:
219: ###########################################################################
220:
1.11 espie 221: sub handle_config
222: {
1.13 espie 223: my ($p, $op, $v, $list) = @_;
1.35 espie 224: my $cfg = cache_find_config($p);
1.13 espie 225:
1.35 espie 226: unshift @$list, $p if defined $cfg;
1.11 espie 227:
1.35 espie 228: if (!defined $cfg) {
229: $rc = 1;
230: return undef;
231: }
1.15 espie 232:
1.35 espie 233: if (defined $op) {
234: if (!versionmatch($cfg, $op, $v)) {
235: mismatch($p, $cfg, $op, $v) if $mode{printerr};
1.13 espie 236: $rc = 1;
237: return undef;
238: }
1.35 espie 239: }
1.11 espie 240:
1.43 jasper 241: my $get_props = sub {
242: my $property = shift;
243:
244: my $deps = $cfg->get_property($property, $variables);
245: if (defined $deps) {
246: for my $dep (@$deps) {
1.46 jasper 247: if ($dep =~ m/^(.*?)\s*([<=>]+)\s*([\d\.]+|[\d\.]+[\w]*[\d]+)$/) {
1.43 jasper 248: handle_config($1, $2, $3, $list);
249: } else {
250: handle_config($dep, undef, undef, $list);
251: }
1.26 jasper 252: }
1.43 jasper 253: print STDERR "package $p ", lc($property), " ",
254: join(',', @$deps), "\n" if $D;
1.26 jasper 255: }
1.43 jasper 256: };
257:
258: &$get_props("Requires");
259: &$get_props("Requires.private");
1.26 jasper 260:
1.11 espie 261: }
262:
1.1 ckuethe 263: # look for the .pc file in each of the PKGPATH elements. Return the path or
264: # undef if it's not there
1.4 espie 265: sub pathresolve
266: {
267: my ($p) = @_;
268:
1.14 espie 269: if ($allow_uninstalled && $p !~ m/\-uninstalled$/) {
270: foreach my $d (@PKGPATH) {
271: my $f = "$d/$p-uninstalled.pc";
272: print STDERR "pathresolve($p) looking in $f\n" if $D;
273: if (-f $f) {
274: $found_uninstalled = 1;
275: return $f;
276: }
277: }
278: }
279:
1.4 espie 280: foreach my $d (@PKGPATH) {
1.10 espie 281: my $f = "$d/$p.pc";
1.4 espie 282: print STDERR "pathresolve($p) looking in $f\n" if $D;
1.10 espie 283: return $f if -f $f;
1.1 ckuethe 284: }
1.10 espie 285: return undef;
1.1 ckuethe 286: }
287:
1.11 espie 288: sub get_config
289: {
290: my ($f) = @_;
291:
292: my $cfg;
1.33 jasper 293: eval {
1.11 espie 294: $cfg = OpenBSD::PkgConfig->read_file($f);
295: };
296: if (!$@) {
1.37 jasper 297: return validate_config($f, $cfg);
1.11 espie 298: } else {
1.12 espie 299: print STDERR $@, "\n" if $D;
1.11 espie 300: }
301: return undef;
302: }
303:
1.13 espie 304: sub cache_find_config
305: {
306: my $name = shift;
307:
308: print STDERR "processing $name\n" if $D;
309:
310: if (exists $configs{$name}) {
311: return $configs{$name};
312: } else {
313: return $configs{$name} = find_config($name);
314: }
1.37 jasper 315: }
316:
317: # Required elements for a valid .pc file: Name, Description, Version
318: sub validate_config
319: {
320: my ($f, $cfg) = @_;
321: my @required_elems = ('Name', 'Description', 'Version');
322: my $e;
323:
324: foreach (@required_elems) {
325: $e = $cfg->get_property($_, $variables);
326: if (!defined $e) {
1.39 jasper 327: $f =~ s/(^.*\/)(.*?)\.pc$/$2/g;
328: print STDERR "Package '$f' has no $_: field\n";
1.37 jasper 329: return undef;
330: }
331: }
332:
333: return $cfg;
1.13 espie 334: }
335:
1.35 espie 336: # pkg-config won't install a pkg-config.pc file itself, but it may be
337:
338: # listed as a dependency in other files.
339: # so, prime the cache with self
340: sub setup_self
341: {
342: my $pkg_pc = OpenBSD::PkgConfig->new;
343: $pkg_pc->add_property('Version', $version);
1.38 jasper 344: $pkg_pc->add_variable('pc_path', join(":", @PKGPATH));
1.35 espie 345: $configs{'pkg-config'} = $pkg_pc;
346: }
347:
1.11 espie 348: sub find_config
349: {
350: my ($p) = @_;
351: my $f = pathresolve($p);
352: if (defined $f) {
353: return get_config($f);
354: }
1.13 espie 355: if ($mode{printerr}) {
1.33 jasper 356: print STDERR
1.13 espie 357: "Package $p was not found in the pkg-config search path\n";
358: }
1.11 espie 359: return undef;
360: }
1.1 ckuethe 361:
1.11 espie 362: sub stringize
1.4 espie 363: {
1.11 espie 364: my $list = shift;
1.21 simon 365: my $sep = shift || ',';
1.4 espie 366:
1.11 espie 367: if (defined $list) {
1.21 simon 368: return join($sep, @$list)
1.11 espie 369: } else {
370: return '';
1.1 ckuethe 371: }
372: }
373:
374: #if the variable option is set, pull out the named variable
1.4 espie 375: sub do_variable
376: {
1.11 espie 377: my ($p, $v) = @_;
1.1 ckuethe 378:
1.13 espie 379: my $cfg = cache_find_config($p);
380:
381: if (defined $cfg) {
1.11 espie 382: my $value = $cfg->get_variable($v, $variables);
383: if (defined $value) {
1.13 espie 384: push(@vlist, $value);
1.11 espie 385: }
1.19 espie 386: return undef;
1.11 espie 387: }
1.19 espie 388: $rc = 1;
1.1 ckuethe 389: }
390:
1.30 jasper 391: #if the modversion or print-provides options are set,
392: #pull out the compiler flags
1.4 espie 393: sub do_modversion
394: {
1.11 espie 395: my ($p) = @_;
1.1 ckuethe 396:
1.13 espie 397: my $cfg = cache_find_config($p);
398:
399: if (defined $cfg) {
1.11 espie 400: my $value = $cfg->get_property('Version', $variables);
401: if (defined $value) {
1.30 jasper 402: if (!defined($mode{printprovides})){
403: print stringize($value), "\n";
404: return undef;
405: } else {
406: print "$p = " . stringize($value) . "\n";
407: return undef;
408: }
1.11 espie 409: }
410: }
1.13 espie 411: $rc = 1;
1.1 ckuethe 412: }
413:
414: #if the cflags option is set, pull out the compiler flags
1.4 espie 415: sub do_cflags
416: {
1.14 espie 417: my $list = shift;
418:
1.11 espie 419: my $cflags = [];
1.1 ckuethe 420:
1.14 espie 421: foreach my $pkg (@$list) {
1.11 espie 422: my $l = $configs{$pkg}->get_property('Cflags', $variables);
423: push(@$cflags, @$l) if defined $l;
424: }
1.32 jasper 425: my $a = OpenBSD::PkgConfig->compress($cflags,
1.11 espie 426: sub {
427: local $_ = shift;
428: if (($mode{cflags} & 1) && /^-I/ ||
429: ($mode{cflags} & 2) && !/^-I/) {
430: return 1;
431: } else {
432: return 0;
1.4 espie 433: }
1.11 espie 434: });
1.32 jasper 435: if (defined($a) && defined($variables->{pc_sysrootdir})){
1.36 jasper 436: $a =~ s/[\w]?-I/$&$variables->{pc_sysrootdir}/g;
1.32 jasper 437: }
438:
439: return $a;
1.1 ckuethe 440: }
441:
442: #if the lib option is set, pull out the linker flags
1.4 espie 443: sub do_libs
444: {
1.14 espie 445: my $list = shift;
446:
1.11 espie 447: my $libs = [];
1.1 ckuethe 448:
1.14 espie 449: foreach my $pkg (@$list) {
1.11 espie 450: my $l = $configs{$pkg}->get_property('Libs', $variables);
451: push(@$libs, @$l) if defined $l;
452: }
1.13 espie 453: my $a = OpenBSD::PkgConfig->compress($libs,
1.11 espie 454: sub {
455: local $_ = shift;
1.13 espie 456: if (($mode{libs} & 2) && /^-L/ ||
1.11 espie 457: ($mode{libs} & 4) && !/^-[lL]/) {
458: return 1;
459: } else {
460: return 0;
1.4 espie 461: }
1.11 espie 462: });
1.32 jasper 463:
464: if (defined($variables->{pc_sysrootdir})){
1.36 jasper 465: $a =~ s/[\w]?-[lL]/$&$variables->{pc_sysrootdir}/g;
1.32 jasper 466: }
467:
1.13 espie 468: if ($mode{libs} & 1) {
469: my $b = OpenBSD::PkgConfig->rcompress($libs,
470: sub { shift =~ m/^-l/; });
471: return ($a, $b);
472: } else {
473: return $a;
474: }
1.1 ckuethe 475: }
476:
477: #list all packages
1.4 espie 478: sub do_list
479: {
1.1 ckuethe 480: my ($p, $x, $y, @files, $fname, $name);
1.20 espie 481: my $error = 0;
482:
1.33 jasper 483: foreach my $p (@PKGPATH) {
484: push(@files, <$p/*.pc>);
1.4 espie 485: }
1.1 ckuethe 486:
487: # Scan the lengths of the package names so I can make a format
488: # string to line the list up just like the real pkgconfig does.
489: $x = 0;
1.4 espie 490: foreach my $f (@files) {
491: $fname = basename($f, '.pc');
492: $y = length $fname;
1.1 ckuethe 493: $x = (($y > $x) ? $y : $x);
494: }
495: $x *= -1;
496:
1.4 espie 497: foreach my $f (@files) {
1.11 espie 498: my $cfg = get_config($f);
1.20 espie 499: if (!defined $cfg) {
500: print STDERR "Problem reading file $f\n";
501: $error = 1;
502: next;
503: }
1.4 espie 504: $fname = basename($f, '.pc');
1.33 jasper 505: printf("%${x}s %s - %s\n", $fname,
1.53 jasper 506: stringize($cfg->get_property('Name', $variables), ' '),
1.21 simon 507: stringize($cfg->get_property('Description', $variables),
508: ' '));
1.1 ckuethe 509: }
1.20 espie 510: return $error;
1.1 ckuethe 511: }
512:
1.4 espie 513: sub help
514: {
1.1 ckuethe 515: print <<EOF
516: Usage: $0 [options]
517: --debug - turn on debugging output
518: --help - this message
519: --usage - this message
520: --list-all - show all packages that $0 can find
1.8 ckuethe 521: --version - print version of pkgconfig
522: --errors-to-stdout - direct error messages to stdout rather than stderr
523: --print-errors - print error messages in case of error
1.34 jasper 524: --print-provides - print all the modules the given package provides
525: --print-requires - print all the modules the given package requires
526: --print-requires-private - print all the private modules the given package requires
1.8 ckuethe 527: --silence-errors - don't print error messages in case of error
1.1 ckuethe 528: --atleast-pkgconfig-version [version] - require a certain version of pkgconfig
529: --cflags package [versionspec] [package [versionspec]]
530: --cflags-only-I - only output -Iincludepath flags
531: --cflags-only-other - only output flags that are not -I
1.11 espie 532: --define-variable=NAME=VALUE - define variables
1.1 ckuethe 533: --libs package [versionspec] [package [versionspec]]
534: --libs-only-l - only output -llib flags
535: --libs-only-L - only output -Llibpath flags
536: --libs-only-other - only output flags that are not -l or -L
537: --exists package [versionspec] [package [versionspec]]
538: --uninstalled - allow for uninstalled versions to be used
1.8 ckuethe 539: --static - adjust output for static linking
540: --atleast-version [version] - require a certain version of a package
541: --modversion [package] - query the version of a package
542: --variable var package - return the definition of <var> in <package>
1.1 ckuethe 543: EOF
544: ;
1.22 simon 545: exit 0;
1.1 ckuethe 546: }
547:
548: # do we meet/beat the version the caller requested?
1.4 espie 549: sub self_version
550: {
551: my ($v) = @_;
552: my (@a, @b);
553:
554: @a = split /\./, $v;
555: @b = split /\./, $version;
1.1 ckuethe 556:
1.4 espie 557: if (($b[0] >= $a[0]) && ($b[1] >= $a[1])) {
1.14 espie 558: return 0;
1.1 ckuethe 559: } else {
1.14 espie 560: return 1;
561: }
562: }
563:
564: sub compare
565: {
566: my ($a, $b) = @_;
1.46 jasper 567: my ($full_a, $full_b) = ($a, $b);
568: my (@suffix_a, @suffix_b);
1.14 espie 569:
1.28 jasper 570: return 0 if ($a eq $b);
1.14 espie 571:
1.46 jasper 572: # is there a valid non-numeric suffix to deal with later?
1.47 jasper 573: # accepter are (in order): a(lpha) < b(eta) < rc < ' '.
1.46 jasper 574: # suffix[0] is the 'alpha' part, suffix[1] is the '1' part in 'alpha1'.
1.54 ! jasper 575: # XXX: add back 'rc'.
! 576: if ($a =~ s/(beta|b|alpha|a)(\d+)$//) {
1.46 jasper 577: print STDERR "valid suffix $1$2 found in $a.\n" if $D;
578: $suffix_a[0] = $1;
579: $suffix_a[1] = $2;
580: }
581:
1.54 ! jasper 582: if ($b =~ s/(beta|b|alpha|a)(\d+)$//) {
1.46 jasper 583: print STDERR "valid suffix $1$2 found in $b.\n" if $D;
584: $suffix_b[0] = $1;
585: $suffix_b[1] = $2;
586: }
587:
1.14 espie 588: my @a = split /\./, $a;
589: my @b = split /\./, $b;
590:
591: while (@a && @b) { #so long as both lists have something
1.46 jasper 592: if (!(@suffix_a || @suffix_b)) {
593: # simple comparison when no suffixes are in the game.
1.48 jasper 594: my $rc = compare_numeric($a[0], $b[0], 0);
595: return $rc if defined($rc);
1.46 jasper 596: } else {
597: # extended comparison.
1.49 jasper 598: if (((@a == 1) || (@b == 1)) &&
1.46 jasper 599: ($a[0] == $b[0])){
600: # one of the arrays has reached the last element,
601: # compare the suffix.
602:
603: # directly compare suffixes, provided both suffixes
604: # are present.
605: if (@suffix_a && @suffix_b) {
606: my $first_char = sub {
607: return substr(shift, 0, 1);
608: };
609:
610: # suffixes are equal, compare on numeric
611: if (&$first_char($suffix_a[0]) eq
612: &$first_char($suffix_b[0])) {
1.48 jasper 613: return compare_numeric($suffix_a[1], $suffix_b[1], 1);
1.46 jasper 614: }
615:
1.47 jasper 616: # rc beats beta beats alpha
1.46 jasper 617: if (&$first_char($suffix_a[0]) lt &$first_char($suffix_b[0])) {
618: print STDERR "$full_a (installed) < $full_b (wanted)\n" if $D;
619: return -1;
620: } else {
621: print STDERR "$full_a (installed) > $full_b (wanted)\n" if $D;
622: return 1;
623: }
624:
625: } else {
626: # one of either is lacking a suffix,
627: # thereby beating the other.
628: # e.g.: 1.02 > 1.02b1
629: if (@suffix_a) { # a is older
630: print STDERR "$full_a (installed) < $full_b (wanted)\n" if $D;
631: return -1;
632: }
633:
634: if (@suffix_b) { # b is older
635: print STDERR "$full_a (installed) > $full_b (wanted)\n" if $D;
636: return 1;
637: }
638: }
639:
640: } else {
1.48 jasper 641: my $rc = compare_numeric($a[0], $b[0], 0);
642: return $rc if defined($rc);
1.46 jasper 643: }
644:
645: }
1.14 espie 646: shift @a; shift @b;
647: }
648: return 1 if @a;
649: return -1 if @b;
650: return 0;
1.48 jasper 651: }
652:
653: # simple numeric comparison, with optional equality test.
654: sub compare_numeric
655: {
656: my ($x, $y, $eq) = @_;
657:
658: return 1 if $x > $y;
659: return -1 if $x < $y;
660: return 0 if (($x == $y) and ($eq == 1));
661: return undef;
1.1 ckuethe 662: }
663:
664: # got a package meeting the requested specific version?
1.4 espie 665: sub versionmatch
666: {
1.14 espie 667: my ($cfg, $op, $want) = @_;
1.33 jasper 668:
1.1 ckuethe 669: # can't possibly match if we can't find the file
1.11 espie 670: return 0 if !defined $cfg;
671:
1.14 espie 672: my $inst = stringize($cfg->get_property('Version', $variables));
1.11 espie 673:
1.1 ckuethe 674: # can't possibly match if we can't find the version string
1.14 espie 675: return 0 if $inst eq '';
1.1 ckuethe 676:
1.14 espie 677: print "comparing $want (wanted) to $inst (installed)\n" if $D;
678: my $value = compare($inst, $want);
1.31 jasper 679: if ($op eq '>=') { return $value >= 0; }
680: elsif ($op eq '=') { return $value == 0; }
681: elsif ($op eq '!=') { return $value != 0; }
682: elsif ($op eq '<') { return $value < 0; }
683: elsif ($op eq '>') { return $value > 0; }
684: elsif ($op eq '<=') { return $value <= 0; }
1.13 espie 685: }
686:
687: sub mismatch
688: {
689: my ($p, $cfg, $op, $v) = @_;
1.53 jasper 690: my $name = stringize($cfg->get_property('Name'), ' ');
1.41 jasper 691: my $version = stringize($cfg->get_property('Version'));
692: my $url = stringize($cfg->get_property('URL'));
693:
694: print STDERR "Requested '$p $op $v' but version of $name is $version\n";
695: print STDERR "You may find new versions of $name at $url\n" if $url;
1.13 espie 696: }
697:
698: sub simplify_and_reverse
699: {
700: my $reqlist = shift;
701: my $dejavu = {};
702: my $result = [];
703:
704: for my $item (@$reqlist) {
705: if (!$dejavu->{$item}) {
706: unshift @$result, $item;
707: $dejavu->{$item} = 1;
708: }
709: }
710: return $result;
1.30 jasper 711: }
712:
713: # retrieve and print Requires(.private)
714: sub print_requires
715: {
716: my ($p) = @_;
717:
718: my $cfg = cache_find_config($p);
719:
720: if (defined($cfg)) {
721: my $value;
722:
723: if (defined($mode{printrequires})) {
724: $value = $cfg->get_property('Requires', $variables);
725: } elsif (defined($mode{printrequiresprivate})) {
726: $value = $cfg->get_property('Requires.private', $variables);
727: } else {
728: print STDERR "Unknown mode for print_requires.\n" if $D;
729: return 1;
730: }
731:
732: if (defined($value)) {
733: print "$_\n" foreach (@$value);
734: return undef;
735: }
736: }
737:
738: $rc = 1;
1.35 espie 739: }
740:
741: sub beautify_list
742: {
743: return join(' ', map {"[$_]"} @_);
1.1 ckuethe 744: }