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

1.1       ckuethe     1: #!/usr/bin/perl
1.17    ! espie       2: # $OpenBSD: pkg-config,v 1.16 2006/12/14 10:23:34 espie Exp $
1.1       ckuethe     3:
                      4: #$CSK: pkgconfig.pl,v 1.39 2006/11/27 16:26:20 ckuethe Exp $
                      5: # Copyright (c) 2006 Chris Kuethe <ckuethe@openbsd.org>
                      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:
                     19: use strict;
                     20: use warnings;
                     21: use Getopt::Long;
1.4       espie      22: use File::Basename;
1.11      espie      23: use OpenBSD::PkgConfig;
1.1       ckuethe    24:
                     25: my @PKGPATH = qw(/usr/local/lib/pkgconfig /usr/X11R6/lib/pkgconfig );
                     26:
1.16      espie      27: if (defined($ENV{PKG_CONFIG_LIBDIR}) && $ENV{PKG_CONFIG_LIBDIR}) {
                     28:        @PKGPATH = split /:/, $ENV{PKG_CONFIG_LIBDIR};
                     29: } elsif (defined($ENV{PKG_CONFIG_PATH}) && $ENV{PKG_CONFIG_PATH}) {
                     30:        push(@PKGPATH, split /:/, $ENV{PKG_CONFIG_PATH});
1.1       ckuethe    31: }
                     32:
                     33: my $logfile = '';
1.16      espie      34: if (defined($ENV{PKG_CONFIG_LOGFILE}) && $ENV{PKG_CONFIG_LOGFILE}) {
                     35:        $logfile = $ENV{PKG_CONFIG_LOGFILE};
1.1       ckuethe    36: }
                     37:
1.14      espie      38: my $allow_uninstalled =
1.16      espie      39:        defined $ENV{PKG_CONFIG_DISABLE_UNINSTALLED} ? 0 : 1;
1.14      espie      40: my $found_uninstalled = 0;
                     41:
1.10      espie      42: my $version = 0.19; # pretend to be this version of pkgconfig
                     43:
                     44: my %configs = ();
                     45: my %mode = ();
1.11      espie      46: my $variables = {};
1.10      espie      47: my $D = 0; # debug flag
1.1       ckuethe    48:
1.14      espie      49: {
1.16      espie      50:     my $d = $ENV{PKG_CONFIG_TOP_BUILD_DIR};
1.14      espie      51:     if (defined $d) {
                     52:            $variables->{pc_top_builddir} = $d;
                     53:     } else {
                     54:            $variables->{pc_top_builddir} = '$(top_builddir)';
                     55:     }
                     56: }
1.7       ckuethe    57:
1.4       espie      58: if ($logfile) {
                     59:        open my $L, ">>" . $logfile;
                     60:        print $L '[' . join('] [', $0, @ARGV) . "]\n";
                     61:        close $L;
1.1       ckuethe    62: }
                     63:
                     64: # combo arg-parsing and dependency resolution loop. Hopefully when the loop
                     65: # terminates, we have a full list of packages upon which we depend, and the
                     66: # right set of compiler and linker flags to use them.
                     67: #
                     68: # as each .pc file is loaded, it is stored in %configs, indexed by package
                     69: # name. this makes it possible to then pull out flags or do substitutions
                     70: # without having to go back and reload the files from disk
                     71:
                     72: Getopt::Long::Configure('no_ignore_case');
                     73: GetOptions(    'debug' => \$D,
                     74:                'help' => \&help, #does not return
                     75:                'usage' => \&help, #does not return
1.14      espie      76:                'list-all' => \$mode{list},
1.1       ckuethe    77:                'version' => sub { print "$version\n" ; exit(0);} ,
1.11      espie      78:                'errors-to-stdout' => sub { $mode{estdout} = 1},
                     79:                'print-errors' => sub { $mode{printerr} = 1},
                     80:                'silence-errors' => sub { $mode{printerr} = 0},
1.14      espie      81:                'atleast-pkgconfig-version=s' => \$mode{myminvers},
1.11      espie      82:
                     83:                'cflags' => sub { $mode{cflags} = 3},
                     84:                'cflags-only-I' => sub { $mode{cflags} |= 1},
                     85:                'cflags-only-other' => sub { $mode{cflags} |= 2},
                     86:                'libs' => sub { $mode{libs} = 7},
                     87:                'libs-only-l' => sub { $mode{libs} |= 1},
                     88:                'libs-only-L' => sub { $mode{libs} |= 2},
                     89:                'libs-only-other' => sub { $mode{libs} |= 4},
                     90:                'exists' => sub { $mode{exists} = 1} ,
                     91:                'static' => sub { $mode{static} = 1},
                     92:                'uninstalled' => sub { $mode{uninstalled} = 1},
1.14      espie      93:                'atleast-version=s' => \$mode{minversion},
                     94:                'exact-version=s' => \$mode{exactversion},
                     95:                'max-version=s' => \$mode{maxversion},
1.13      espie      96:                'modversion' => \$mode{modversion},
1.11      espie      97:                'variable=s' => \$mode{variable},
                     98:                'define-variable=s' => $variables,
1.1       ckuethe    99:        );
                    100:
1.14      espie     101: # Initial value of printerr depends on the options...
                    102: if (!defined $mode{printerr}) {
                    103:        if (defined $mode{libs} || defined $mode{cflags}
                    104:            || defined $mode{version} || defined $mode{list}) {
                    105:                $mode{printerr} = 1;
                    106:        } else {
                    107:                $mode{printerr} = 0;
                    108:        }
                    109: }
                    110:
1.4       espie     111: print STDERR "\n[" . join('] [', $0, @ARGV) . "]\n" if $D;
1.13      espie     112:
                    113: my $rc = 0;
1.1       ckuethe   114:
1.14      espie     115: # XXX pkg-config is a bit weird
1.10      espie     116: {
                    117: my $p = join(' ', @ARGV);
1.14      espie     118: $p =~ s/^\s+//;
1.4       espie     119: @ARGV = split /\s+/, $p;
1.10      espie     120: }
1.1       ckuethe   121:
1.14      espie     122: if ($mode{myminvers}) {
                    123:        exit self_version($mode{myminvers});
                    124: }
                    125:
                    126: if ($mode{list}) {
                    127:        exit do_list();
1.1       ckuethe   128: }
                    129:
1.13      espie     130: my $cfg_full_list = [];
1.14      espie     131: my $top_config = [];
1.1       ckuethe   132:
                    133: while (@ARGV){
1.13      espie     134:        my $p = shift @ARGV;
                    135:        my $op = undef;
                    136:        my $v = undef;
                    137:        if (@ARGV >= 2  && $ARGV[0] =~ /[<=>]+/ &&
                    138:            $ARGV[1] =~ /[0-9\.]+/) {
                    139:                $op = shift @ARGV;
                    140:                $v = shift @ARGV;
1.1       ckuethe   141:        }
                    142:        $p =~ s/,//g;
1.13      espie     143:        handle_config($p, $op, $v, $cfg_full_list);
1.14      espie     144:        push(@$top_config, $p);
                    145: }
                    146:
                    147: if ($mode{exists}) {
                    148:        exit $rc;
                    149: }
                    150:
                    151: if ($mode{uninstalled}) {
                    152:        $rc = 1 unless $found_uninstalled;
                    153:        exit $rc;
1.11      espie     154: }
1.1       ckuethe   155:
1.14      espie     156: if ($mode{modversion}) {
                    157:        for my $pkg (@$top_config) {
                    158:                do_modversion($pkg);
                    159:        }
                    160: }
1.13      espie     161:
1.14      espie     162: if ($mode{minversion}) {
                    163:        my $v = $mode{minversion};
                    164:        for my $pkg (@$top_config) {
                    165:                $rc = 1 unless versionmatch($configs{$pkg}, '>=', $v);
                    166:        }
                    167:        exit $rc;
                    168: }
                    169:
                    170: if ($mode{exactversion}) {
                    171:        my $v = $mode{exactversion};
                    172:        for my $pkg (@$top_config) {
                    173:                $rc = 1 unless versionmatch($configs{$pkg}, '=', $v);
                    174:        }
                    175:        exit $rc;
                    176: }
                    177:
                    178: if ($mode{minversion}) {
                    179:        my $v = $mode{maxversion};
                    180:        for my $pkg (@$top_config) {
                    181:                $rc = 1 unless versionmatch($configs{$pkg}, '<=', $v);
                    182:        }
                    183:        exit $rc;
                    184: }
                    185:
                    186: my @vlist = ();
                    187:
                    188: if ($mode{variable}) {
                    189:        for my $pkg (@$top_config) {
                    190:                do_variable($pkg, $mode{variable});
                    191:        }
                    192: }
                    193:
                    194: my $dep_cfg_list = simplify_and_reverse($cfg_full_list);
                    195:
                    196: if ($mode{cflags} || $mode{libs} || $mode{variable}) {
                    197:     push @vlist, do_cflags($dep_cfg_list) if $mode{cflags};
                    198:     push @vlist, do_libs($dep_cfg_list) if $mode{libs};
1.17    ! espie     199:     print join(' ', @vlist), "\n" if $rc == 0;
1.1       ckuethe   200: }
                    201:
1.13      espie     202: exit $rc;
1.1       ckuethe   203:
                    204: ###########################################################################
                    205:
1.11      espie     206: sub handle_config
                    207: {
1.13      espie     208:        my ($p, $op, $v, $list) = @_;
                    209:
1.11      espie     210:
1.13      espie     211:        my $cfg = cache_find_config($p);
1.11      espie     212:
1.13      espie     213:        unshift @$list, $p if defined $cfg;
1.11      espie     214:
1.15      espie     215:        if (!defined $cfg) {
                    216:                $rc = 1;
                    217:                return undef;
                    218:        }
                    219:
1.13      espie     220:        if (defined $op) {
                    221:                if (!versionmatch($cfg, $op, $v)) {
                    222:                        mismatch($p, $cfg, $op, $v) if $mode{printerr};
                    223:                        $rc = 1;
                    224:                        return undef;
                    225:                }
1.14      espie     226:        }
1.11      espie     227:
                    228:        my $deps = $cfg->get_property('Requires', $variables);
                    229:        if (defined $deps) {
1.13      espie     230:                for my $dep (@$deps) {
                    231:                        if ($dep =~ m/^(.*?)\s*([<=>]+)\s*([\d\.]+)$/) {
                    232:                                handle_config($1, $2, $3, $list);
                    233:                        } else {
                    234:                                handle_config($dep, undef, undef, $list);
                    235:                        }
                    236:                }
1.11      espie     237:                print STDERR "package $p requires ",
                    238:                    join(',', @$deps), "\n" if $D;
                    239:        }
                    240:
                    241:        $deps = $cfg->get_property('Requires.private', $variables);
                    242:        if (defined $deps) {
1.13      espie     243:                for my $dep (@$deps) {
                    244:                        if ($dep =~ m/^(.*?)\s*([<=>]+)\s*([\d\.]+)$/) {
                    245:                                handle_config($1, $2, $3, $list);
                    246:                        } else {
                    247:                                handle_config($dep, undef, undef, $list);
                    248:                        }
                    249:                }
1.11      espie     250:                print STDERR "package $p requires (private)",
                    251:                        join(',', @$deps), "\n" if $D;
                    252:        }
                    253: }
                    254:
1.1       ckuethe   255: # look for the .pc file in each of the PKGPATH elements. Return the path or
                    256: # undef if it's not there
1.4       espie     257: sub pathresolve
                    258: {
                    259:        my ($p) = @_;
                    260:
1.14      espie     261:        if ($allow_uninstalled && $p !~ m/\-uninstalled$/) {
                    262:                foreach my $d (@PKGPATH) {
                    263:                        my $f = "$d/$p-uninstalled.pc";
                    264:                        print STDERR "pathresolve($p) looking in $f\n" if $D;
                    265:                        if (-f $f) {
                    266:                                $found_uninstalled = 1;
                    267:                                return $f;
                    268:                        }
                    269:                }
                    270:        }
                    271:
1.4       espie     272:        foreach my $d (@PKGPATH) {
1.10      espie     273:                my $f = "$d/$p.pc";
1.4       espie     274:                print STDERR "pathresolve($p) looking in $f\n" if $D;
1.10      espie     275:                return $f if -f $f;
1.1       ckuethe   276:        }
1.10      espie     277:        return undef;
1.1       ckuethe   278: }
                    279:
1.11      espie     280: sub get_config
                    281: {
                    282:        my ($f) = @_;
                    283:
                    284:        my $cfg;
                    285:        eval {
                    286:            $cfg = OpenBSD::PkgConfig->read_file($f);
                    287:        };
                    288:        if (!$@) {
                    289:                return $cfg;
                    290:        } else {
1.12      espie     291:                print STDERR $@, "\n" if $D;
1.11      espie     292:        }
                    293:        return undef;
                    294: }
                    295:
1.13      espie     296: sub cache_find_config
                    297: {
                    298:        my $name = shift;
                    299:
                    300:        print STDERR "processing $name\n" if $D;
                    301:
                    302:        if (exists $configs{$name}) {
                    303:                return $configs{$name};
                    304:        } else {
                    305:                return $configs{$name} = find_config($name);
                    306:        }
                    307: }
                    308:
1.11      espie     309: sub find_config
                    310: {
                    311:        my ($p) = @_;
                    312:        my $f = pathresolve($p);
                    313:        if (defined $f) {
                    314:                return get_config($f);
                    315:        }
1.13      espie     316:        if ($mode{printerr}) {
                    317:            print STDERR
                    318:                "Package $p was not found in the pkg-config search path\n";
                    319:        }
1.11      espie     320:        return undef;
                    321: }
1.1       ckuethe   322:
1.11      espie     323: sub stringize
1.4       espie     324: {
1.11      espie     325:        my $list = shift;
1.4       espie     326:
1.11      espie     327:        if (defined $list) {
                    328:                return join(',', @$list)
                    329:        } else {
                    330:                return '';
1.1       ckuethe   331:        }
                    332: }
                    333:
                    334: #if the variable option is set, pull out the named variable
1.4       espie     335: sub do_variable
                    336: {
1.11      espie     337:        my ($p, $v) = @_;
1.1       ckuethe   338:
1.13      espie     339:        my $cfg = cache_find_config($p);
                    340:
                    341:        if (defined $cfg) {
1.11      espie     342:                my $value = $cfg->get_variable($v, $variables);
                    343:                if (defined $value) {
1.13      espie     344:                        push(@vlist, $value);
                    345:                        return undef;
1.11      espie     346:                }
                    347:        }
1.13      espie     348:        $rc = 1;
1.1       ckuethe   349: }
                    350:
                    351: #if the modversion option is set, pull out the compiler flags
1.4       espie     352: sub do_modversion
                    353: {
1.11      espie     354:        my ($p) = @_;
1.1       ckuethe   355:
1.13      espie     356:        my $cfg = cache_find_config($p);
                    357:
                    358:        if (defined $cfg) {
1.11      espie     359:                my $value = $cfg->get_property('Version', $variables);
                    360:                if (defined $value) {
                    361:                        print stringize($value), "\n";
1.13      espie     362:                        return undef;
1.11      espie     363:                }
                    364:        }
1.13      espie     365:        $rc = 1;
1.1       ckuethe   366: }
                    367:
                    368: #if the cflags option is set, pull out the compiler flags
1.4       espie     369: sub do_cflags
                    370: {
1.14      espie     371:        my $list = shift;
                    372:
1.11      espie     373:        my $cflags = [];
1.1       ckuethe   374:
1.14      espie     375:        foreach my $pkg (@$list) {
1.11      espie     376:                my $l = $configs{$pkg}->get_property('Cflags', $variables);
                    377:                push(@$cflags, @$l) if defined $l;
                    378:        }
                    379:        return OpenBSD::PkgConfig->compress($cflags,
                    380:                sub {
                    381:                        local $_ = shift;
                    382:                        if (($mode{cflags} & 1) && /^-I/ ||
                    383:                            ($mode{cflags} & 2) && !/^-I/) {
                    384:                            return 1;
                    385:                        } else {
                    386:                            return 0;
1.4       espie     387:                        }
1.11      espie     388:                });
1.14      espie     389:        return undef;
1.1       ckuethe   390: }
                    391:
                    392: #if the lib option is set, pull out the linker flags
1.4       espie     393: sub do_libs
                    394: {
1.14      espie     395:        my $list = shift;
                    396:
1.11      espie     397:        my $libs = [];
1.1       ckuethe   398:
1.14      espie     399:        foreach my $pkg (@$list) {
1.11      espie     400:                my $l = $configs{$pkg}->get_property('Libs', $variables);
                    401:                push(@$libs, @$l) if defined $l;
                    402:        }
1.13      espie     403:        my $a = OpenBSD::PkgConfig->compress($libs,
1.11      espie     404:                sub {
                    405:                        local $_ = shift;
1.13      espie     406:                        if (($mode{libs} & 2) && /^-L/ ||
1.11      espie     407:                            ($mode{libs} & 4) && !/^-[lL]/) {
                    408:                            return 1;
                    409:                        } else {
                    410:                            return 0;
1.4       espie     411:                        }
1.11      espie     412:                });
1.13      espie     413:        if ($mode{libs} & 1) {
                    414:                my $b = OpenBSD::PkgConfig->rcompress($libs,
                    415:                        sub { shift =~ m/^-l/; });
                    416:                return ($a, $b);
                    417:        } else {
                    418:                return $a;
                    419:        }
1.1       ckuethe   420: }
                    421:
                    422: #list all packages
1.4       espie     423: sub do_list
                    424: {
1.1       ckuethe   425:        my ($p, $x, $y, @files, $fname, $name);
1.4       espie     426:        foreach my $p (@PKGPATH) {
                    427:                push(@files, <$p/*.pc>);
                    428:        }
1.1       ckuethe   429:
                    430:        # Scan the lengths of the package names so I can make a format
                    431:        # string to line the list up just like the real pkgconfig does.
                    432:        $x = 0;
1.4       espie     433:        foreach my $f (@files) {
                    434:                $fname = basename($f, '.pc');
                    435:                $y = length $fname;
1.1       ckuethe   436:                $x = (($y > $x) ? $y : $x);
                    437:        }
                    438:        $x *= -1;
                    439:
1.4       espie     440:        foreach my $f (@files) {
1.11      espie     441:                my $cfg = get_config($f);
1.4       espie     442:                $fname = basename($f, '.pc');
1.11      espie     443:                printf("%${x}s %s - %s\n", $fname,
                    444:                    stringize($cfg->get_property('Name', $variables)),
                    445:                    stringize($cfg->get_property('Description', $variables)));
1.1       ckuethe   446:        }
1.14      espie     447:        return 0;
1.1       ckuethe   448: }
                    449:
1.4       espie     450: sub help
                    451: {
1.1       ckuethe   452:        print <<EOF
                    453: Usage: $0 [options]
                    454: --debug        - turn on debugging output
                    455: --help - this message
                    456: --usage - this message
                    457: --list-all - show all packages that $0 can find
1.8       ckuethe   458: --version - print version of pkgconfig
                    459: --errors-to-stdout - direct error messages to stdout rather than stderr
                    460: --print-errors - print error messages in case of error
                    461: --silence-errors - don't print error messages in case of error
1.1       ckuethe   462: --atleast-pkgconfig-version [version] - require a certain version of pkgconfig
                    463: --cflags package [versionspec] [package [versionspec]]
                    464: --cflags-only-I - only output -Iincludepath flags
                    465: --cflags-only-other - only output flags that are not -I
1.11      espie     466: --define-variable=NAME=VALUE - define variables
1.1       ckuethe   467: --libs package [versionspec] [package [versionspec]]
                    468: --libs-only-l - only output -llib flags
                    469: --libs-only-L - only output -Llibpath flags
                    470: --libs-only-other - only output flags that are not -l or -L
                    471: --exists package [versionspec] [package [versionspec]]
                    472: --uninstalled - allow for uninstalled versions to be used
1.8       ckuethe   473: --static - adjust output for static linking
                    474: --atleast-version [version] - require a certain version of a package
                    475: --modversion [package] - query the version of a package
                    476: --variable var package - return the definition of <var> in <package>
1.1       ckuethe   477: EOF
                    478: ;
1.4       espie     479:        exit 1;
1.1       ckuethe   480: }
                    481:
                    482: # do we meet/beat the version the caller requested?
1.4       espie     483: sub self_version
                    484: {
                    485:        my ($v) = @_;
                    486:        my (@a, @b);
                    487:
                    488:        @a = split /\./, $v;
                    489:        @b = split /\./, $version;
1.1       ckuethe   490:
1.4       espie     491:        if (($b[0] >= $a[0]) && ($b[1] >= $a[1])) {
1.14      espie     492:                return 0;
1.1       ckuethe   493:        } else {
1.14      espie     494:                return 1;
                    495:        }
                    496: }
                    497:
                    498: sub compare
                    499: {
                    500:        my ($a, $b) = @_;
                    501:
                    502:        if ($a eq $b) {
                    503:                return 0;
1.1       ckuethe   504:        }
1.14      espie     505:
                    506:        my @a = split /\./, $a;
                    507:        my @b = split /\./, $b;
                    508:
                    509:        while (@a && @b) { #so long as both lists have something
                    510:                return 1 if $a[0] > $b[0];
                    511:                return -1 if $a[0] < $b[0];
                    512:                shift @a; shift @b;
                    513:        }
                    514:        return 1 if @a;
                    515:        return -1 if @b;
                    516:        return 0;
1.1       ckuethe   517: }
                    518:
                    519: # got a package meeting the requested specific version?
1.4       espie     520: sub versionmatch
                    521: {
1.14      espie     522:        my ($cfg, $op, $want) = @_;
1.1       ckuethe   523:
                    524:        # can't possibly match if we can't find the file
1.11      espie     525:        return 0 if !defined $cfg;
                    526:
1.14      espie     527:        my $inst = stringize($cfg->get_property('Version', $variables));
1.11      espie     528:
1.1       ckuethe   529:        # can't possibly match if we can't find the version string
1.14      espie     530:        return 0 if $inst eq '';
1.1       ckuethe   531:
1.14      espie     532:        print "comparing $want (wanted) to $inst (installed)\n" if $D;
                    533:        my $value = compare($inst, $want);
                    534:        if ($op eq '>=') {
                    535:                return $value >= 0;
                    536:        }
                    537:        elsif ($op eq '=') {
                    538:                return $value == 0;
                    539:        } elsif ($op eq '!=') {
                    540:                return $value != 0;
                    541:        } elsif ($op eq '<') {
                    542:                return $value < 0;
                    543:        } elsif ($op eq '>') {
                    544:                return $value > 0;
                    545:        } elsif ($op eq '<=') {
                    546:                return $value <= 0;
                    547:        }
1.13      espie     548: }
                    549:
                    550: sub mismatch
                    551: {
                    552:        my ($p, $cfg, $op, $v) = @_;
                    553:        print STDERR "Requested '$p $op $v' but version of ",
                    554:            stringize($cfg->get_property('Name')), " is ",
                    555:            stringize($cfg->get_property('Version')), "\n";
                    556: }
                    557:
                    558: sub simplify_and_reverse
                    559: {
                    560:        my $reqlist = shift;
                    561:        my $dejavu = {};
                    562:        my $result = [];
                    563:
                    564:        for my $item (@$reqlist) {
                    565:                if (!$dejavu->{$item}) {
                    566:                        unshift @$result, $item;
                    567:                        $dejavu->{$item} = 1;
                    568:                }
                    569:        }
                    570:        return $result;
1.1       ckuethe   571: }