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

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