Annotation of src/usr.bin/pkg-config/pkg-config, Revision 1.12
1.1 ckuethe 1: #!/usr/bin/perl
1.12 ! espie 2: # $OpenBSD: pkg-config,v 1.11 2006/12/02 18:28:22 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 {
1.12 ! espie 205: print STDERR $@, "\n" if $D;
1.11 espie 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: }