Annotation of src/usr.bin/pkg-config/pkg-config, Revision 1.11
1.1 ckuethe 1: #!/usr/bin/perl
1.11 ! espie 2: # $OpenBSD: pkg-config,v 1.10 2006/12/01 19:32:31 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 = ();
1.11 ! espie 39: my $cfg_list = [];
1.10 espie 40: my %mode = ();
1.11 ! espie 41: my $variables = {};
1.10 espie 42: my $D = 0; # debug flag
1.1 ckuethe 43:
1.7 ckuethe 44: # defaults
1.11 ! espie 45: $mode{printerr} = 1;
1.7 ckuethe 46:
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);} ,
1.11 ! espie 67: 'errors-to-stdout' => sub { $mode{estdout} = 1},
! 68: 'print-errors' => sub { $mode{printerr} = 1},
! 69: 'silence-errors' => sub { $mode{printerr} = 0},
! 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},
1.1 ckuethe 82: 'atleast-version=s' => \$mode{'atleast-version'},
1.11 ! espie 83: 'modversion:s' => \$mode{modversion},
! 84: 'variable=s' => \$mode{variable},
! 85: 'define-variable=s' => $variables,
1.1 ckuethe 86: );
87:
1.4 espie 88: print STDERR "\n[" . join('] [', $0, @ARGV) . "]\n" if $D;
1.11 ! espie 89: self_version($mode{minvers}) if $mode{minvers}; #does not return
! 90: if (defined $mode{modversion}) {
! 91: if ($mode{modversion}) {
! 92: do_modversion($mode{modversion}) ; #does not return
1.6 ckuethe 93: } else {
94: print $version . "\n";
95: exit 0;
96: }
97: }
1.1 ckuethe 98:
1.10 espie 99: {
100: my $p = join(' ', @ARGV);
1.1 ckuethe 101: $p =~ s/\s+/ /g;
102: $p =~ s/^\s//g;
1.4 espie 103: @ARGV = split /\s+/, $p;
1.10 espie 104: }
1.1 ckuethe 105:
1.11 ! espie 106: if (defined $mode{exists}) {
1.4 espie 107: while (@ARGV) {
1.1 ckuethe 108: if ((@ARGV >= 2) && ($ARGV[1] =~ /[<=>]+/) &&
1.4 espie 109: ($ARGV[2] =~ /[0-9\.]+/)) {
110: exit 1 unless versionmatch(@ARGV);
111: shift @ARGV; shift @ARGV; shift @ARGV;
1.1 ckuethe 112: } else {
1.4 espie 113: exit 1 unless pathresolve($ARGV[0]);
114: shift @ARGV;
1.1 ckuethe 115: }
116: }
1.4 espie 117: exit 0;
1.1 ckuethe 118: }
119:
1.11 ! espie 120: do_variable($ARGV[0], $mode{variable}) if $mode{variable};
1.1 ckuethe 121:
122: while (@ARGV){
1.10 espie 123: my $p = $ARGV[0];
1.1 ckuethe 124: if ((@ARGV >= 2) && ($ARGV[1] =~ /[<=>]+/) &&
1.4 espie 125: ($ARGV[2] =~ /[0-9\.]+/)) {
126: shift @ARGV;
127: shift @ARGV;
1.1 ckuethe 128: }
1.4 espie 129: shift @ARGV;
1.1 ckuethe 130: $p =~ s/,//g;
1.11 ! espie 131: handle_config($p);
! 132: }
1.1 ckuethe 133:
1.11 ! espie 134: if ($mode{cflags} || $mode{libs}) {
! 135: my @l = ();
! 136: push @l, do_cflags() if $mode{cflags};
! 137: push @l, do_libs() if $mode{libs};
! 138: print join(' ', @l), "\n";
1.1 ckuethe 139: }
140:
1.4 espie 141: exit 0;
1.1 ckuethe 142:
143: ###########################################################################
144:
1.11 ! espie 145: sub handle_config
! 146: {
! 147: my $p = shift;
! 148:
! 149: return if $configs{$p};
! 150:
! 151: print STDERR "processing $p\n" if $D;
! 152: my $cfg = find_config($p);
! 153:
! 154: if (!defined $cfg) {
! 155: warn "can't find $p\n" if $mode{printerr};
! 156: exit 1;
! 157: }
! 158: return undef if defined $mode{exists};
! 159:
! 160: push(@$cfg_list, $p);
! 161: $configs{$p} = $cfg;
! 162:
! 163: my $deps = $cfg->get_property('Requires', $variables);
! 164: if (defined $deps) {
! 165: # XXX don't handle version yet
! 166: map { s/\s*[<=>]+\s*[\d\.]+//; handle_config($_) } @$deps;
! 167: print STDERR "package $p requires ",
! 168: join(',', @$deps), "\n" if $D;
! 169: }
! 170:
! 171: $deps = $cfg->get_property('Requires.private', $variables);
! 172: if (defined $deps) {
! 173: # XXX don't handle version yet
! 174: map { s/\s*[<=>]+\s*[\d\.]+//; handle_config($_) } @$deps;
! 175: print STDERR "package $p requires (private)",
! 176: join(',', @$deps), "\n" if $D;
! 177: }
! 178: }
! 179:
1.1 ckuethe 180: # look for the .pc file in each of the PKGPATH elements. Return the path or
181: # undef if it's not there
1.4 espie 182: sub pathresolve
183: {
184: my ($p) = @_;
185:
186: foreach my $d (@PKGPATH) {
1.10 espie 187: my $f = "$d/$p.pc";
1.4 espie 188: print STDERR "pathresolve($p) looking in $f\n" if $D;
1.10 espie 189: return $f if -f $f;
1.1 ckuethe 190: }
1.10 espie 191: return undef;
1.1 ckuethe 192: }
193:
1.11 ! espie 194: sub get_config
! 195: {
! 196: my ($f) = @_;
! 197:
! 198: my $cfg;
! 199: eval {
! 200: $cfg = OpenBSD::PkgConfig->read_file($f);
! 201: };
! 202: if (!$@) {
! 203: return $cfg;
! 204: } else {
! 205: print STDERR $@, "\n" if $@;
! 206: }
! 207: return undef;
! 208: }
! 209:
! 210: sub find_config
! 211: {
! 212: my ($p) = @_;
! 213: my $f = pathresolve($p);
! 214: if (defined $f) {
! 215: return get_config($f);
! 216: }
! 217: return undef;
! 218: }
1.1 ckuethe 219:
1.11 ! espie 220: sub stringize
1.4 espie 221: {
1.11 ! espie 222: my $list = shift;
1.4 espie 223:
1.11 ! espie 224: if (defined $list) {
! 225: return join(',', @$list)
! 226: } else {
! 227: return '';
1.1 ckuethe 228: }
229: }
230:
231: #if the variable option is set, pull out the named variable
1.4 espie 232: sub do_variable
233: {
1.11 ! espie 234: my ($p, $v) = @_;
1.1 ckuethe 235:
1.11 ! espie 236: if (my $cfg = find_config($p)) {
! 237: my $value = $cfg->get_variable($v, $variables);
! 238: if (defined $value) {
! 239: print $value, "\n";
! 240: exit 1;
! 241: }
! 242: }
1.4 espie 243: exit 0;
1.1 ckuethe 244: }
245:
246: #if the modversion option is set, pull out the compiler flags
1.4 espie 247: sub do_modversion
248: {
1.11 ! espie 249: my ($p) = @_;
1.1 ckuethe 250:
1.11 ! espie 251: if (my $cfg = find_config($p)) {
! 252: my $value = $cfg->get_property('Version', $variables);
! 253: if (defined $value) {
! 254: print stringize($value), "\n";
! 255: exit 1;
! 256: }
! 257: }
1.4 espie 258: exit 0;
1.1 ckuethe 259: }
260:
261: #if the cflags option is set, pull out the compiler flags
1.4 espie 262: sub do_cflags
263: {
1.11 ! espie 264: my $cflags = [];
1.1 ckuethe 265:
1.11 ! espie 266: foreach my $pkg (@$cfg_list) {
! 267: my $l = $configs{$pkg}->get_property('Cflags', $variables);
! 268: push(@$cflags, @$l) if defined $l;
! 269: }
! 270: return OpenBSD::PkgConfig->compress($cflags,
! 271: sub {
! 272: local $_ = shift;
! 273: if (($mode{cflags} & 1) && /^-I/ ||
! 274: ($mode{cflags} & 2) && !/^-I/) {
! 275: return 1;
! 276: } else {
! 277: return 0;
1.4 espie 278: }
1.11 ! espie 279: });
1.1 ckuethe 280: }
281:
282: #if the lib option is set, pull out the linker flags
1.4 espie 283: sub do_libs
284: {
1.11 ! espie 285: my $libs = [];
1.1 ckuethe 286:
1.11 ! espie 287: foreach my $pkg (@$cfg_list) {
! 288: my $l = $configs{$pkg}->get_property('Libs', $variables);
! 289: push(@$libs, @$l) if defined $l;
! 290: }
! 291: return OpenBSD::PkgConfig->compress($libs,
! 292: sub {
! 293: local $_ = shift;
! 294: if (($mode{libs} & 1) && /^-l/ ||
! 295: ($mode{libs} & 2) && /^-L/ ||
! 296: ($mode{libs} & 4) && !/^-[lL]/) {
! 297: return 1;
! 298: } else {
! 299: return 0;
1.4 espie 300: }
1.11 ! espie 301: });
1.1 ckuethe 302: }
303:
304: #list all packages
1.4 espie 305: sub do_list
306: {
1.1 ckuethe 307: my ($p, $x, $y, @files, $fname, $name);
1.4 espie 308: foreach my $p (@PKGPATH) {
309: push(@files, <$p/*.pc>);
310: }
1.1 ckuethe 311:
312: # Scan the lengths of the package names so I can make a format
313: # string to line the list up just like the real pkgconfig does.
314: $x = 0;
1.4 espie 315: foreach my $f (@files) {
316: $fname = basename($f, '.pc');
317: $y = length $fname;
1.1 ckuethe 318: $x = (($y > $x) ? $y : $x);
319: }
320: $x *= -1;
321:
1.4 espie 322: foreach my $f (@files) {
1.11 ! espie 323: my $cfg = get_config($f);
1.4 espie 324: $fname = basename($f, '.pc');
1.11 ! espie 325: printf("%${x}s %s - %s\n", $fname,
! 326: stringize($cfg->get_property('Name', $variables)),
! 327: stringize($cfg->get_property('Description', $variables)));
1.1 ckuethe 328: }
1.4 espie 329: exit 0;
1.1 ckuethe 330: }
331:
1.4 espie 332: sub help
333: {
1.1 ckuethe 334: print <<EOF
335: Usage: $0 [options]
336: --debug - turn on debugging output
337: --help - this message
338: --usage - this message
339: --list-all - show all packages that $0 can find
1.8 ckuethe 340: --version - print version of pkgconfig
341: --errors-to-stdout - direct error messages to stdout rather than stderr
342: --print-errors - print error messages in case of error
343: --silence-errors - don't print error messages in case of error
1.1 ckuethe 344: --atleast-pkgconfig-version [version] - require a certain version of pkgconfig
345: --cflags package [versionspec] [package [versionspec]]
346: --cflags-only-I - only output -Iincludepath flags
347: --cflags-only-other - only output flags that are not -I
1.11 ! espie 348: --define-variable=NAME=VALUE - define variables
1.1 ckuethe 349: --libs package [versionspec] [package [versionspec]]
350: --libs-only-l - only output -llib flags
351: --libs-only-L - only output -Llibpath flags
352: --libs-only-other - only output flags that are not -l or -L
353: --exists package [versionspec] [package [versionspec]]
354: --uninstalled - allow for uninstalled versions to be used
1.8 ckuethe 355: --static - adjust output for static linking
356: --atleast-version [version] - require a certain version of a package
357: --modversion [package] - query the version of a package
358: --variable var package - return the definition of <var> in <package>
1.1 ckuethe 359: EOF
360: ;
1.4 espie 361: exit 1;
1.1 ckuethe 362: }
363:
364: # do we meet/beat the version the caller requested?
1.4 espie 365: sub self_version
366: {
367: my ($v) = @_;
368: my (@a, @b);
369:
370: @a = split /\./, $v;
371: @b = split /\./, $version;
1.1 ckuethe 372:
1.4 espie 373: if (($b[0] >= $a[0]) && ($b[1] >= $a[1])) {
374: exit 0;
1.1 ckuethe 375: } else {
1.4 espie 376: exit 1;
1.1 ckuethe 377: }
378: }
379:
380: # got a package meeting the requested specific version?
1.4 espie 381: sub versionmatch
382: {
1.11 ! espie 383: my ($pname, $op, $ver) = @_;
1.1 ckuethe 384:
1.4 espie 385: print STDERR "pname = '$pname'\n" if $D;
1.11 ! espie 386: my $cfg = find_config($pname);
1.1 ckuethe 387: # can't possibly match if we can't find the file
1.11 ! espie 388: return 0 if !defined $cfg;
! 389:
! 390: $configs{$pname} = $cfg;
! 391:
! 392: my $v = stringize($cfg->get_property('Version', $variables));
! 393:
1.1 ckuethe 394: # can't possibly match if we can't find the version string
1.11 ! espie 395: return 0 if $v eq '';
1.1 ckuethe 396:
1.11 ! espie 397: print "comparing $ver (wanted) to $v (installed)\n" if $D;
! 398: my @inst = split /\./, $v;
! 399: my @want = split /\./, $ver;
1.1 ckuethe 400:
1.4 espie 401: while (@inst && @want) { #so long as both lists have something
1.1 ckuethe 402: # bail if the requested version element beats existing
1.4 espie 403: return 1 if $inst[0] > $want[0];
404: return 0 if $inst[0] < $want[0];
405: shift @inst; shift @want;
1.1 ckuethe 406: }
407: # the version at least equals the requested. if the requested
408: # version has some micropatchlevel beyond the existing version,
409: # return failure
1.4 espie 410: return 0 if @want;
1.1 ckuethe 411: # and after all that, the version is good enough
412: return 1;
413: }