[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.96

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