[BACK]Return to pkg-config CVS log [TXT][DIR] Up to [local] / src / usr.bin / pkg-config

Annotation of src/usr.bin/pkg-config/pkg-config, Revision 1.90

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