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