]> mj.ucw.cz Git - libucw.git/blob - ucw/perl/UCW/Configure.pm
6fb84a19f0423dbca95e7120d96490a667b70e6e
[libucw.git] / ucw / perl / UCW / Configure.pm
1 #       Perl module for UCW Configure Scripts
2 #
3 #       (c) 2005 Martin Mares <mj@ucw.cz>
4 #
5 #       This software may be freely distributed and used according to the terms
6 #       of the GNU Lesser General Public License.
7
8 package UCW::Configure;
9
10 use strict;
11 use warnings;
12
13 BEGIN {
14         # The somewhat hairy Perl export mechanism
15         use Exporter();
16         our ($VERSION, @ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS);
17         $VERSION = 1.0;
18         @ISA = qw(Exporter);
19         @EXPORT = qw(&Init &Log &Notice &Warn &Fail &IsSet &IsGiven &Set &UnSet &Append &Override &Get &Test &Include &Finish &FindFile &TryFindFile &TryCmd &PkgConfig &TrivConfig &debPrint);
20         @EXPORT_OK = qw();
21         %EXPORT_TAGS = ();
22 }
23
24 our %vars;
25 our %overriden;
26
27 sub debPrint() {
28   print "VARS:\n";
29 #  print "$_: $vars{$_}\n" foreach( keys %vars );
30 }
31
32 sub Log($) {
33         print @_;
34 }
35
36 sub Notice($) {
37         print @_ if $vars{"VERBOSE"};
38 }
39
40 sub Warn($) {
41         print "WARNING: ", @_;
42 }
43
44 sub Fail($) {
45         Log("ERROR: " . (shift @_) . "\n");
46         exit 1;
47 }
48
49 sub IsSet($) {
50         my ($x) = @_;
51         return exists $vars{$x};
52 }
53
54 sub IsGiven($) {
55         my ($x) = @_;
56         return exists $overriden{$x};
57 }
58
59 sub Get($) {
60         my ($x) = @_;
61         return $vars{$x};
62 }
63
64 sub Set($;$) {
65         my ($x,$y) = @_;
66         $y=1 unless defined $y;
67         $vars{$x}=$y unless $overriden{$x};
68 }
69
70 sub UnSet($) {
71         my ($x) = @_;
72         delete $vars{$x} unless $overriden{$x};
73 }
74
75 sub Append($$) {
76         my ($x,$y) = @_;
77         Set($x, (IsSet($x) ? (Get($x) . " $y") : $y));
78 }
79
80 sub Override($;$) {
81         my ($x,$y) = @_;
82         $y=1 unless defined $y;
83         $vars{$x}=$y;
84         $overriden{$x} = 1;
85 }
86
87 sub Test($$$) {
88         my ($var,$msg,$sub) = @_;
89         Log "$msg ... ";
90         if (!IsSet($var)) {
91                 Set $var, &$sub();
92         }
93         Log Get($var) . "\n";
94 }
95
96 sub TryFindFile($) {
97         my ($f) = @_;
98         if (-f $f) {
99                 return $f;
100         } elsif ($f !~ /^\// && -f (Get("SRCDIR")."/$f")) {
101                 return Get("SRCDIR")."/$f";
102         } else {
103                 return undef;
104         }
105 }
106
107 sub FindFile($) {
108         my ($f) = @_;
109         my $F;
110         defined ($F = TryFindFile($f)) or Fail "Cannot find file $f";
111         return $F;
112 }
113
114 sub Init($$) {
115         my ($srcdir,$defconfig) = @_;
116         sub usage($) {
117                 my ($dc) = @_;
118                 print STDERR "Usage: [<srcdir>/]configure " . (defined $dc ? "[" : "") . "<config-name>" . (defined $dc ? "]" : "") .
119                         " [<option>[=<value>] | -<option>] ...\n";
120                 exit 1;
121         }
122         Set('CONFIG' => $defconfig) if defined $defconfig;
123         if (@ARGV) {
124                 usage($defconfig) if $ARGV[0] eq "--help";
125                 if (!defined($defconfig) || $ARGV[0] !~ /^-?[A-Z][A-Z0-9_]*(=|$)/) {
126                         # This does not look like an option, so read it as a file name
127                         Set('CONFIG' => shift @ARGV);
128                 }
129         }
130         Set("SRCDIR", $srcdir);
131
132         foreach my $x (@ARGV) {
133                 if ($x =~ /^(\w+)=(.*)/) {
134                         Override($1 => $2);
135                 } elsif ($x =~ /^-(\w+)$/) {
136                         Override($1 => 0);
137                         delete $vars{$1};
138                 } elsif ($x =~ /^(\w+)$/) {
139                         Override($1 => 1);
140                 } else {
141                         print STDERR "Invalid option $x\n";
142                         exit 1;
143                 }
144         }
145
146         defined Get("CONFIG") or usage($defconfig);
147         if (!TryFindFile(Get("CONFIG"))) {
148                 TryFindFile(Get("CONFIG")."/config") or Fail "Cannot find configuration " . Get("CONFIG");
149                 Override("CONFIG" => Get("CONFIG")."/config");
150         }
151 }
152
153 sub Include($) {
154         my ($f) = @_;
155         $f = FindFile($f);
156         Notice "Loading configuration $f\n";
157         require $f;
158 }
159
160 sub Finish() {
161         print "\n";
162
163         if (Get("SRCDIR") ne ".") {
164                 Log "Preparing for compilation from directory " . Get("SRCDIR") . " to obj/ ... ";
165                 -l "src" and unlink "src";
166                 symlink Get("SRCDIR"), "src" or Fail "Cannot link source directory to src: $!";
167                 Override("SRCDIR" => "src");
168                 -l "Makefile" and unlink "Makefile";
169                 -f "Makefile" and Fail "Makefile already exists";
170                 symlink "src/Makefile", "Makefile" or Fail "Cannot link Makefile: $!";
171         } else {
172                 Log "Preparing for compilation from current directory to obj/ ... ";
173         }
174         if (-d "obj") {
175                 `rm -rf obj`; Fail "Cannot delete old obj directory" if $?;
176         }
177         -d "obj" or mkdir("obj", 0777) or Fail "Cannot create obj directory: $!";
178         -d "obj/ucw" or mkdir("obj/ucw", 0777) or Fail "Cannot create obj/ucw directory: $!";
179         Log "done\n";
180
181         Log "Generating autoconf.h ... ";
182         open X, ">obj/autoconf.h" or Fail $!;
183         print X "/* Generated automatically by $0, please don't touch manually. */\n";
184         foreach my $x (sort keys %vars) {
185                 # Don't export variables which contain no underscores
186                 next unless $x =~ /_/;
187                 my $v = $vars{$x};
188                 # Try to add quotes if necessary
189                 $v = '"' . $v . '"' unless ($v =~ /^"/ || $v =~ /^\d*$/);
190                 print X "#define $x $v\n";
191         }
192         close X;
193         Log "done\n";
194
195         Log "Generating config.mk ... ";
196         open X, ">obj/config.mk" or Fail $!;
197         print X "# Generated automatically by $0, please don't touch manually.\n";
198         foreach my $x (sort keys %vars) {
199                 print X "$x=$vars{$x}\n";
200         }
201         print X "s=\${SRCDIR}\n";
202         print X "o=obj\n";
203         close X;
204         Log "done\n";
205 }
206
207 sub TryCmd($) {
208         my ($cmd) = @_;
209         my $res = `$cmd`;
210         defined $res or return;
211         chomp $res;
212         return $res unless $?;
213         return;
214 }
215
216 sub maybe_manually($) {
217         my ($n) = @_;
218         if (IsGiven($n)) {
219                 if (Get("$n")) { Log "YES (set manually)\n"; }
220                 else { Log "NO (set manually)\n"; }
221                 return 1;
222         }
223         return 0;
224 }
225
226 sub PkgConfig($@) {
227         my $pkg = shift @_;
228         my %opts = @_;
229         my $upper = $pkg; $upper =~ tr/a-z/A-Z/; $upper =~ s/[^0-9A-Z]+/_/g;
230         Log "Checking for package $pkg ... ";
231         maybe_manually("CONFIG_HAVE_$upper") and return Get("CONFIG_HAVE_$upper");
232         my $ver = TryCmd("pkg-config --modversion $pkg 2>/dev/null");
233         if (!defined $ver) {
234                 Log("NONE\n");
235                 return 0;
236         }
237         if (defined($opts{minversion})) {
238                 my $min = $opts{minversion};
239                 if (!defined TryCmd("pkg-config --atleast-version=$min $pkg")) {
240                         Log("NO: version $ver is too old (need >= $min)\n");
241                         return 0;
242                 }
243         }
244         Log("YES: version $ver\n");
245         Set("CONFIG_HAVE_$upper" => 1);
246         Set("CONFIG_VER_$upper" => $ver);
247         my $cf = TryCmd("pkg-config --cflags $pkg");
248         Set("${upper}_CFLAGS" => $cf) if defined $cf;
249         my $lf = TryCmd("pkg-config --libs $pkg");
250         Set("${upper}_LIBS" => $lf) if defined $lf;
251         return 1;
252 }
253
254 sub ver_norm($) {
255         my ($v) = @_;
256         return join(".", map { sprintf("%05s", $_) } split(/\./, $v));
257 }
258
259 sub TrivConfig($@) {
260         my $pkg = shift @_;
261         my %opts = @_;
262         my $upper = $pkg; $upper =~ tr/a-z/A-Z/; $upper =~ s/[^0-9A-Z]+/_/g;
263         Log "Checking for package $pkg ... ";
264         maybe_manually("CONFIG_HAVE_$upper") and return Get("CONFIG_HAVE_$upper");
265         my $pc = $opts{script};
266         my $ver = TryCmd("$pc --version 2>/dev/null");
267         if (!defined $ver) {
268                 Log("NONE\n");
269                 return 0;
270         }
271         if (defined($opts{minversion})) {
272                 my $min = $opts{minversion};
273                 if (ver_norm($ver) lt ver_norm($min)) {
274                         Log("NO: version $ver is too old (need >= $min)\n");
275                         return 0;
276                 }
277         }
278         Log("YES: version $ver\n");
279         Set("CONFIG_HAVE_$upper" => 1);
280         Set("CONFIG_VER_$upper" => $ver);
281
282         my $want = $opts{want};
283         defined $want or $want = ["cflags", "libs"];
284         for my $w (@$want) {
285                 my $uw = $w; $uw =~ tr/a-z-/A-Z_/;
286                 my $cf = TryCmd("$pc --$w");
287                 Set("${upper}_${uw}" => $cf) if defined $cf;
288         }
289         return 1;
290 }
291
292 1;  # OK