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

1.1       ckuethe     1: #!/usr/bin/perl
1.6     ! ckuethe     2: # $OpenBSD: pkg-config,v 1.5 2006/11/27 23:57:51 ckuethe 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.1       ckuethe    23:
                     24: my @PKGPATH = qw(/usr/local/lib/pkgconfig /usr/X11R6/lib/pkgconfig );
                     25:
1.4       espie      26: if (defined($ENV{'PKG_CONFIG_PATH'}) && $ENV{'PKG_CONFIG_PATH'}) {
                     27:        push(@PKGPATH, split /:/, $ENV{'PKG_CONFIG_PATH'});
1.1       ckuethe    28: }
                     29:
                     30: my $logfile = '';
1.4       espie      31: if (defined($ENV{'PKG_CONFIG_LOGFILE'}) && $ENV{'PKG_CONFIG_LOGFILE'}) {
1.1       ckuethe    32:        $logfile = $ENV{'PKG_CONFIG_LOGFILE'};
                     33: }
                     34:
                     35: our $version = 0.19; # pretend to be this version of pkgconfig
                     36: my $parse_args = 1;
                     37: my ($deps, $privdeps, $var, $val, $p, $f);
                     38:
                     39: our %configs = ();
                     40: our %mode = ();
                     41: our $D = 0; # debug flag
                     42:
                     43: $/ = undef;
1.4       espie      44: if ($logfile) {
                     45:        open my $L, ">>" . $logfile;
                     46:        print $L '[' . join('] [', $0, @ARGV) . "]\n";
                     47:        close $L;
1.1       ckuethe    48: }
                     49:
                     50: # combo arg-parsing and dependency resolution loop. Hopefully when the loop
                     51: # terminates, we have a full list of packages upon which we depend, and the
                     52: # right set of compiler and linker flags to use them.
                     53: #
                     54: # as each .pc file is loaded, it is stored in %configs, indexed by package
                     55: # name. this makes it possible to then pull out flags or do substitutions
                     56: # without having to go back and reload the files from disk
                     57:
                     58: Getopt::Long::Configure('no_ignore_case');
                     59: GetOptions(    'debug' => \$D,
                     60:                'help' => \&help, #does not return
                     61:                'usage' => \&help, #does not return
                     62:                'list-all' => \&do_list, #does not return
                     63:                'version' => sub { print "$version\n" ; exit(0);} ,
                     64:                'errors-to-stdout' => sub { $mode{'estdout'} = 1},
                     65:                'print-errors' => sub { $mode{'printerr'} = 1},
                     66:                'atleast-pkgconfig-version=s' => \$mode{'minvers'},
                     67:
                     68:                'cflags' => sub { $mode{'cflags'} = 3},
                     69:                'cflags-only-I' => sub { $mode{'cflags'} |= 1},
                     70:                'cflags-only-other' => sub { $mode{'cflags'} |= 2},
                     71:                'libs' => sub { $mode{'libs'} = 7},
                     72:                'libs-only-l' => sub { $mode{'libs'} |= 1},
                     73:                'libs-only-L' => sub { $mode{'libs'} |= 2},
                     74:                'libs-only-other' => sub { $mode{'libs'} |= 4},
                     75:                'exists' => sub { $mode{'exists'} = 1} ,
                     76:                'static' => sub { $mode{'static'} = 1},
                     77:                'uninstalled' => sub { $mode{'uninstalled'} = 1},
                     78:                'atleast-version=s' => \$mode{'atleast-version'},
1.6     ! ckuethe    79:                'modversion:s' => \$mode{'modversion'},
1.1       ckuethe    80:                'variable=s' => \$mode{'variable'}
                     81:        );
                     82:
1.4       espie      83: print STDERR "\n[" . join('] [', $0, @ARGV) . "]\n" if $D;
                     84: self_version($mode{'minvers'}) if $mode{'minvers'}; #does not return
1.6     ! ckuethe    85: if (defined $mode{'modversion'}) {
        !            86:        if ($mode{'modversion'}) {
        !            87:                do_modversion($mode{'modversion'}) ; #does not return
        !            88:        } else {
        !            89:                print $version . "\n";
        !            90:                exit 0;
        !            91:        }
        !            92: }
1.1       ckuethe    93:
                     94: $p = join(' ', @ARGV);
                     95: $p =~ s/\s+/ /g;
                     96: $p =~ s/^\s//g;
1.4       espie      97: @ARGV = split /\s+/, $p;
1.1       ckuethe    98:
1.4       espie      99: if (defined $mode{'exists'}) {
                    100:        while (@ARGV) {
1.1       ckuethe   101:                if ((@ARGV >= 2)  && ($ARGV[1] =~ /[<=>]+/) &&
1.4       espie     102:                    ($ARGV[2] =~ /[0-9\.]+/)) {
                    103:                        exit 1 unless versionmatch(@ARGV);
                    104:                        shift @ARGV; shift @ARGV; shift @ARGV;
1.1       ckuethe   105:                } else {
1.4       espie     106:                        exit 1 unless pathresolve($ARGV[0]);
                    107:                        shift @ARGV;
1.1       ckuethe   108:                }
                    109:        }
1.4       espie     110:        exit 0;
1.1       ckuethe   111: }
                    112:
1.4       espie     113: do_variable($ARGV[0], $mode{'variable'}) if $mode{'variable'};
1.1       ckuethe   114:
                    115: while (@ARGV){
                    116:        $p = $ARGV[0];
                    117:        if ((@ARGV >= 2)  && ($ARGV[1] =~ /[<=>]+/) &&
1.4       espie     118:            ($ARGV[2] =~ /[0-9\.]+/)) {
                    119:                shift @ARGV;
                    120:                shift @ARGV;
1.1       ckuethe   121:        }
1.4       espie     122:        shift @ARGV;
1.1       ckuethe   123:        $p =~ s/,//g;
1.4       espie     124:        unless ($configs{$p}) { # don't reprocess things we've seen
                    125:                print STDERR "processing $p\n" if $D;
                    126:                if ($f = pathresolve($p)) { # locate the .pc file
                    127:                        exit 0 if defined $mode{'exists'};
1.1       ckuethe   128:
                    129:                        $configs{$p} = slurp($f); # load the config
                    130:                        $deps = '';
1.4       espie     131:                        if ($configs{$p} =~ /\bRequires: +(\w.+?)\n/) {
1.1       ckuethe   132:                                $deps = $1;
                    133:                                # XXX how should i handle versions?
                    134:                                $deps =~ s/[<>=]+\s*[0-9\.]+\s*//;
                    135:                                $deps =~ tr/,/ /;
                    136:                        }
                    137:                        print STDERR "package $p requires '$deps'\n"
1.4       espie     138:                            if $D && $deps;
                    139:                        push(@ARGV, split /\s+/, $deps) if $deps;
1.1       ckuethe   140:
                    141:                        $privdeps = '';
1.4       espie     142:                        if ($configs{$p} =~ /\bRequires\.private: +(\w.+?)\n/) {
1.1       ckuethe   143:                                $privdeps = $1;
                    144:                                # XXX how should i handle versions?
                    145:                                $privdeps =~ s/[<>=]+\s*[0-9\.]+\s*//;
                    146:                        }
                    147:                        print STDERR "package $p requires (private) '" .
1.4       espie     148:                            $privdeps . "'\n" if $D && $privdeps;
                    149:                        push(@ARGV, split /\s+/, $privdeps) if $privdeps;
1.1       ckuethe   150:
                    151:                } else {
1.4       espie     152:                        warn "can't find $p\n";
                    153:                        exit 1;
1.1       ckuethe   154:                }
                    155:        }
                    156: }
                    157:
1.4       espie     158: do_cflags() if $mode{'cflags'};
                    159: do_libs() if $mode{'libs'};
1.1       ckuethe   160:
1.4       espie     161: exit 0;
1.1       ckuethe   162:
                    163: ###########################################################################
                    164:
                    165: # look for the .pc file in each of the PKGPATH elements. Return the path or
                    166: # undef if it's not there
1.4       espie     167: sub pathresolve
                    168: {
                    169:        my ($p) = @_;
                    170:
                    171:        foreach my $d (@PKGPATH) {
                    172:                $f = "$d/$p.pc";
                    173:                print STDERR "pathresolve($p) looking in $f\n" if $D;
                    174:                last if -f $f;
1.1       ckuethe   175:                $f = undef;
                    176:        }
                    177:        return $f;
                    178: }
                    179:
                    180:
                    181: # Given a filename, return its contents. Also do variable substitutions.
1.4       espie     182: sub slurp
                    183: {
                    184:        my ($f) = @_;
                    185:
                    186:        open my $F, '<', $f or return undef;
                    187:        print STDERR "slurp($f) OK\n" if $D;
                    188:        $f = <$F>;
                    189:        close $F;
1.1       ckuethe   190:        $f = varsub($f);
                    191:        return $f;
                    192: }
                    193:
                    194: # Do variable substitutions, so if "target=x11" is present (for example),
                    195: # any lines referring to $target are filled in properly.
1.4       espie     196: sub varsub
                    197: {
                    198:        my ($buf) = @_;
                    199:
1.1       ckuethe   200:        my ($var, $val);
                    201:
1.4       espie     202:        while ($buf =~ /\${(\w+)}/gsm) {
1.1       ckuethe   203:                $var = $1;
1.4       espie     204:                if ($buf =~ /${var}=(.+?)\n/s) {
1.1       ckuethe   205:                        $val = $1;
                    206:                        $buf =~ s/\${$var}/$val/g;
                    207:                }
                    208:        }
                    209:        return $buf;
                    210: }
                    211:
                    212: #if the variable option is set, pull out the named variable
1.4       espie     213: sub do_variable
                    214: {
1.1       ckuethe   215:        my ($p, $v, undef) = @_;
                    216:        my ($f);
                    217:
1.4       espie     218:        exit 1 unless $f = pathresolve($p);
                    219:        exit 1 unless $f = slurp($f);
1.1       ckuethe   220:
1.4       espie     221:        exit 1 unless $f =~ /\b${v}=(.+?)\n/;
1.1       ckuethe   222:        print "$1\n";
1.4       espie     223:        exit 0;
1.1       ckuethe   224: }
                    225:
                    226: #if the modversion option is set, pull out the compiler flags
1.4       espie     227: sub do_modversion
                    228: {
1.1       ckuethe   229:        my ($p, undef) = @_;
                    230:        my ($f);
1.6     ! ckuethe   231:
        !           232:        print "\$p ='$p'\n";
1.1       ckuethe   233:
1.4       espie     234:        exit 1 unless $f = pathresolve($p);
                    235:        exit 1 unless $f = slurp($f);
1.1       ckuethe   236:
1.4       espie     237:        exit 1 unless $f =~ /\bVersion:\s+(.+?)\n/;
1.1       ckuethe   238:        print "$1\n";
1.4       espie     239:        exit 0;
1.1       ckuethe   240: }
                    241:
                    242: #if the cflags option is set, pull out the compiler flags
1.4       espie     243: sub do_cflags
                    244: {
1.1       ckuethe   245:        my %words; # store them as a hash to get de-duplicating
                    246:        my @out;
                    247:
1.4       espie     248:        foreach my $p (keys %configs) {
                    249:                if ($configs{$p} =~ /\bCflags:\s+(.+?)\n/) {
                    250:                        foreach my $q (split /\s+/, $1) {
                    251:                                $words{$q}=1;
                    252:                        }
1.1       ckuethe   253:                }
                    254:        }
1.4       espie     255:        foreach my $k (sort keys %words) {
                    256:                push(@out, $k) if $k =~ /^-I/ && ($mode{'cflags'} & 1);
                    257:                push(@out, $k) if $k =~ /^-[^I]/ && ($mode{'cflags'} & 2);
1.1       ckuethe   258:        }
1.4       espie     259:        print join(' ', @out), "\n";
                    260:        return undef;
1.1       ckuethe   261: }
                    262:
                    263: #if the lib option is set, pull out the linker flags
1.4       espie     264: sub do_libs
                    265: {
1.1       ckuethe   266:        my %words; # store them as a hash to get de-duplicating
                    267:        my @out;
                    268:
1.4       espie     269:        foreach my $p (keys %configs) {
                    270:                if ($configs{$p} =~ /\bLibs:\s+(.+?)\n/) {
                    271:                        foreach my $q (split /\s+/, $1) {
                    272:                                $words{$q}=1;
                    273:                        }
1.1       ckuethe   274:                }
                    275:        }
1.4       espie     276:        foreach my $k (sort keys %words) {
                    277:                push(@out, $k) if $k =~ /^-l/ && ($mode{'libs'} & 1);
                    278:                push(@out, $k) if $k =~ /^-L/ && ($mode{'libs'} & 2);
                    279:                push(@out, $k) if $k =~ /^-[^lL]/ && ($mode{'libs'} & 4);
1.1       ckuethe   280:        }
1.4       espie     281:        print join(' ', @out), "\n";
                    282:        return undef;
1.1       ckuethe   283: }
                    284:
                    285: #list all packages
1.4       espie     286: sub do_list
                    287: {
1.1       ckuethe   288:        my ($p, $x, $y, @files, $fname, $name);
1.4       espie     289:        foreach my $p (@PKGPATH) {
                    290:                push(@files, <$p/*.pc>);
                    291:        }
1.1       ckuethe   292:
                    293:        # Scan the lengths of the package names so I can make a format
                    294:        # string to line the list up just like the real pkgconfig does.
                    295:        $x = 0;
1.4       espie     296:        foreach my $f (@files) {
                    297:                $fname = basename($f, '.pc');
                    298:                $y = length $fname;
1.1       ckuethe   299:                $x = (($y > $x) ? $y : $x);
                    300:        }
                    301:        $x *= -1;
                    302:
1.4       espie     303:        foreach my $f (@files) {
                    304:                $p = slurp($f);
                    305:                $fname = basename($f, '.pc');
                    306:                if ($p =~ /Name: (\w[^\n]+)\n/gm) {
1.1       ckuethe   307:                        $name = $1;
1.4       espie     308:                        if ($p =~ /Description:\s+(\w[^\n]+)\n/gm) {
1.1       ckuethe   309:                                printf("%${x}s %s - %s\n", $fname, $name, $1);
                    310:                        }
                    311:                }
                    312:        }
1.4       espie     313:        exit 0;
1.1       ckuethe   314: }
                    315:
1.4       espie     316: sub help
                    317: {
1.1       ckuethe   318:        print <<EOF
                    319: Usage: $0 [options]
                    320: --debug        - turn on debugging output
                    321: --help - this message
                    322: --usage - this message
                    323: --list-all - show all packages that $0 can find
                    324: --atleast-pkgconfig-version [version] - require a certain version of pkgconfig
                    325: --variable var package - return the definition of <var> in <package>
                    326: --cflags package [versionspec] [package [versionspec]]
                    327: --cflags-only-I - only output -Iincludepath flags
                    328: --cflags-only-other - only output flags that are not -I
                    329: --libs package [versionspec] [package [versionspec]]
                    330: --libs-only-l - only output -llib flags
                    331: --libs-only-L - only output -Llibpath flags
                    332: --libs-only-other - only output flags that are not -l or -L
                    333: --exists package [versionspec] [package [versionspec]]
                    334: --uninstalled - allow for uninstalled versions to be used
                    335: EOF
                    336: ;
1.4       espie     337:        exit 1;
1.1       ckuethe   338: }
                    339:
                    340: # do we meet/beat the version the caller requested?
1.4       espie     341: sub self_version
                    342: {
                    343:        my ($v) = @_;
                    344:        my (@a, @b);
                    345:
                    346:        @a = split /\./, $v;
                    347:        @b = split /\./, $version;
1.1       ckuethe   348:
1.4       espie     349:        if (($b[0] >= $a[0]) && ($b[1] >= $a[1])) {
                    350:                exit 0;
1.1       ckuethe   351:        } else {
1.4       espie     352:                exit 1;
1.1       ckuethe   353:        }
                    354: }
                    355:
                    356: # got a package meeting the requested specific version?
1.4       espie     357: sub versionmatch
                    358: {
1.1       ckuethe   359:        my ($pname, $op, $ver, undef) = @_;
                    360:        my (@want, @inst, $m, $f);
                    361:
1.4       espie     362:        print STDERR "pname = '$pname'\n" if  $D;
1.1       ckuethe   363:        # can't possibly match if we can't find the file
1.4       espie     364:        return 0 unless $f = pathresolve($pname);
1.1       ckuethe   365:        # load the file
                    366:        $configs{$pname} = slurp($f);
                    367:        # can't possibly match if we can't find the version string
1.4       espie     368:        return 0 unless $configs{$pname} =~ /Version: ([0-9\.]+)\n/gm;
1.1       ckuethe   369:
1.4       espie     370:        print "comparing $ver (wanted) to $1 (installed)\n" if $D;
                    371:        @inst = split /\./, $1;
                    372:        @want = split /\./, $ver;
1.1       ckuethe   373:
1.4       espie     374:        while (@inst && @want) { #so long as both lists have something
1.1       ckuethe   375:                # bail if the requested version element beats existing
1.4       espie     376:                return 1 if $inst[0] > $want[0];
                    377:                return 0 if $inst[0] < $want[0];
                    378:                shift @inst; shift @want;
1.1       ckuethe   379:        }
                    380:        # the version at least equals the requested. if the requested
                    381:        # version has some micropatchlevel beyond the existing version,
                    382:        # return failure
1.4       espie     383:        return 0 if @want;
1.1       ckuethe   384:        # and after all that, the version is good enough
                    385:        return 1;
                    386: }