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

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