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

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