]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - make/utilities.pm
OOPS! We try again, since I'm smoking craq. LF is 0x0a NOT CR.
[user/henk/code/inspircd.git] / make / utilities.pm
1 #
2 # Copyright 2002-2007 The ChatSpike Development Team
3 # <brain@chatspike.net>
4 # <Craig@chatspike.net>
5 #
6 # Licensed under GPL, please see the COPYING file
7 # for more information
8 #
9
10 package make::utilities;
11 use Exporter 'import';
12 use POSIX;
13 use Getopt::Long;
14 @EXPORT = qw(make_rpath pkgconfig_get_include_dirs pkgconfig_get_lib_dirs pkgconfig_check_version translate_functions promptstring vcheck);
15
16 # Parse the output of a *_config program,
17 # such as pcre_config, take out the -L
18 # directive and return an rpath for it.
19
20 # \033[1;32msrc/Makefile\033[0m
21
22 my %already_added = ();
23
24 sub promptstring($$$$$)
25 {
26         my ($prompt, $configitem, $default, $package, $commandlineswitch) = @_;
27         my $var;
28         if (!$main::interactive)
29         {
30                 undef $opt_commandlineswitch;
31                 GetOptions ("$commandlineswitch=s" => \$opt_commandlineswitch);
32                 if (defined $opt_commandlineswitch)
33                 {
34                         print "\033[1;32m$opt_commandlineswitch\033[0m\n";
35                         $var = $opt_commandlineswitch;
36                 }
37                 else
38                 {
39                         die "Could not detect $package! Please specify the $prompt via the command line option \033[1;32m--$commandlineswitch=\"/path/to/file\"\033[0m";
40                 }
41         }
42         else
43         {
44                 print "\nPlease enter the $prompt?\n";
45                 print "[\033[1;32m$default\033[0m] -> ";
46                 chomp($var = <STDIN>);
47         }
48         if ($var eq "")
49         {
50                 $var = $default;
51         }
52         $main::config{$configitem} = $var;
53 }
54
55 sub make_rpath($;$)
56 {
57         my ($executable, $module) = @_;
58         chomp($data = `$executable`);
59         my $output = "";
60         while ($data =~ /-L(\S+)/)
61         {
62                 $libpath = $1;
63                 if (!exists $already_added{$libpath})
64                 {
65                         print "Adding extra library path to \033[1;32m$module\033[0m ... \033[1;32m$libpath\033[0m\n";
66                         $already_added{$libpath} = 1;
67                 }
68                 $output .= "-Wl,--rpath -Wl,$libpath -L$libpath ";
69                 $data =~ s/-L(\S+)//;
70         }
71         return $output;
72 }
73
74 sub extend_pkg_path()
75 {
76         if (!exists $ENV{PKG_CONFIG_PATH})
77         {
78                 $ENV{PKG_CONFIG_PATH} = "/usr/lib/pkgconfig:/usr/local/lib/pkgconfig:/usr/local/libdata/pkgconfig:/usr/X11R6/libdata/pkgconfig";
79         }
80         else
81         {
82                 $ENV{PKG_CONFIG_PATH} .= ":/usr/local/lib/pkgconfig:/usr/local/libdata/pkgconfig:/usr/X11R6/libdata/pkgconfig";
83         }
84 }
85
86 sub pkgconfig_get_include_dirs($$$;$)
87 {
88         my ($packagename, $headername, $defaults, $module) = @_;
89
90         my $key = "default_includedir_$packagename";
91         if (exists $main::config{$key})
92         {
93                 print "Locating include directory for package \033[1;32m$packagename\033[0m for module \033[1;32m$module\033[0m... ";
94                 $ret = $main::config{$key};
95                 print "\033[1;32m$ret\033[0m (cached)\n";
96                 return $ret;
97         }
98
99         extend_pkg_path();
100
101         print "Locating include directory for package \033[1;32m$packagename\033[0m for module \033[1;32m$module\033[0m... ";
102
103         $v = `pkg-config --modversion $packagename 2>/dev/null`;
104         $ret = `pkg-config --cflags $packagename 2>/dev/null`;
105
106         if ((!defined $v) || ($v eq ""))
107         {
108                 $foo = `locate "$headername" | head -n 1`;
109                 $foo =~ /(.+)\Q$headername\E/;
110                 $find = $1;
111                 chomp($find);
112                 if ((defined $find) && ($find ne "") && ($find ne $packagename))
113                 {
114                         print "(\033[1;32mFound via search\033[0m) ";
115                         $foo = "-I$1";
116                 }
117                 else
118                 {
119                         $foo = " ";
120                         undef $v;
121                 }
122                 $ret = "$foo";
123         }
124         if (($defaults ne "") && (($ret eq "") || (!defined $ret)))
125         {
126                 $ret = "$foo " . $defaults;
127         }
128         chomp($ret);
129         if ((($ret eq " ") || (!defined $ret)) && ((!defined $v) || ($v eq "")))
130         {
131                 my $key = "default_includedir_$packagename";
132                 if (exists $main::config{$key})
133                 {
134                         $ret = $main::config{$key};
135                 }
136                 else
137                 {
138                         $headername =~ s/^\///;
139                         promptstring("path to the directory containing $headername", $key, "/usr/include",$packagename,"$packagename-includes");
140                         $packagename =~ tr/a-z/A-Z/;
141                         $main::config{$key} = "-I$main::config{$key}" . " $defaults -DVERSION_$packagename=\"$v\"";
142                         $main::config{$key} =~ s/^\s+//g;
143                         $ret = $main::config{$key};
144                         return $ret;
145                 }
146         }
147         else
148         {
149                 chomp($v);
150                 my $key = "default_includedir_$packagename";
151                 $packagename =~ tr/a-z/A-Z/;
152                 $main::config{$key} = "$ret -DVERSION_$packagename=\"$v\"";
153                 $main::config{$key} =~ s/^\s+//g;
154                 $ret = $main::config{$key};
155                 print "\033[1;32m$ret\033[0m (version $v)\n";
156         }
157         $ret =~ s/^\s+//g;
158         return $ret;
159 }
160
161 sub vcheck($$)
162 {
163         my ($version1, $version2) = @_;
164         $version1 =~ s/\-r(\d+)/\.\1/g; # minor revs/patchlevels
165         $version2 =~ s/\-r(\d+)/\.\1/g;
166         $version1 =~ s/p(\d+)/\.\1/g;
167         $version2 =~ s/p(\d+)/\.\1/g;
168         $version1 =~ s/\-//g;
169         $version2 =~ s/\-//g;
170         $version1 =~ s/a-z//g;
171         $version2 =~ s/a-z//g;
172         my @v1 = split('\.', $version1);
173         my @v2 = split('\.', $version2);
174         for ($curr = 0; $curr < scalar(@v1); $curr++)
175         {
176                 if ($v1[$curr] < $v2[$curr])
177                 {
178                         return 0;
179                 }
180         }
181         return 1;
182 }
183
184 sub pkgconfig_check_version($$;$)
185 {
186         my ($packagename, $version, $module) = @_;
187
188         extend_pkg_path();
189
190         print "Checking version of package \033[1;32m$packagename\033[0m is >= \033[1;32m$version\033[0m... ";
191
192         $v = `pkg-config --modversion $packagename 2>/dev/null`;
193         if (defined $v)
194         {
195                 chomp($v);
196         }
197         if ((defined $v) && ($v ne ""))
198         {
199                 if (vcheck($v,$version) == 1)
200                 {
201                         print "\033[1;32mYes (version $v)\033[0m\n";
202                         return 1;
203                 }
204                 else
205                 {
206                         print "\033[1;32mNo (version $v)\033[0m\n";
207                         return 0;
208                 }
209         }
210         # If we didnt find it, we  cant definitively say its too old.
211         # Return ok, and let pkgconflibs() or pkgconfincludes() pick up
212         # the missing library later on.
213         print "\033[1;32mNo (not found)\033[0m\n";
214         return 1;
215 }
216
217 sub pkgconfig_get_lib_dirs($$$;$)
218 {
219         my ($packagename, $libname, $defaults, $module) = @_;
220
221         my $key = "default_libdir_$packagename";
222         if (exists $main::config{$key})
223         {
224                 print "Locating library directory for package \033[1;32m$packagename\033[0m for module \033[1;32m$module\033[0m... ";
225                 $ret = $main::config{$key};
226                 print "\033[1;32m$ret\033[0m (cached)\n";
227                 return $ret;
228         }
229
230         extend_pkg_path();
231
232         print "Locating library directory for package \033[1;32m$packagename\033[0m for module \033[1;32m$module\033[0m... ";
233
234         $v = `pkg-config --modversion $packagename 2>/dev/null`;
235         $ret = `pkg-config --libs $packagename 2>/dev/null`;
236
237         if ((!defined $v) || ($v eq ""))
238         {
239                 $foo = `locate "$libname" | head -n 1`;
240                 $foo =~ /(.+)\Q$libname\E/;
241                 $find = $1;
242                 chomp($find);
243                 if ((defined $find) && ($find ne "") && ($find ne $packagename))
244                 {
245                         print "(\033[1;32mFound via search\033[0m) ";
246                         $foo = "-L$1";
247                 }
248                 else
249                 {
250                         $foo = " ";
251                         undef $v;
252                 }
253                 $ret = "$foo";
254         }
255
256         if (($defaults ne "") && (($ret eq "") || (!defined $ret)))
257         {
258                 $ret = "$foo " . $defaults;
259         }
260         chomp($ret);
261         if ((($ret eq " ") || (!defined $ret)) && ((!defined $v) || ($v eq "")))
262         {
263                 my $key = "default_libdir_$packagename";
264                 if (exists $main::config{$key})
265                 {
266                         $ret = $main::config{$key};
267                 }
268                 else
269                 {
270                         $libname =~ s/^\///;
271                         promptstring("path to the directory containing $libname", $key, "/usr/lib",$packagename,"$packagename-libs");
272                         $main::config{$key} = "-L$main::config{$key}" . " $defaults";
273                         $main::config{$key} =~ s/^\s+//g;
274                         $ret = $main::config{$key};
275                         return $ret;
276                 }
277         }
278         else
279         {
280                 chomp($v);
281                 print "\033[1;32m$ret\033[0m (version $v)\n";
282                 my $key = "default_libdir_$packagename";
283                 $main::config{$key} = $ret;
284                 $main::config{$key} =~ s/^\s+//g;
285                 $ret =~ s/^\s+//g;
286         }
287         $ret =~ s/^\s+//g;
288         return $ret;
289 }
290
291 # Translate a $CompileFlags etc line and parse out function calls
292 # to functions within these modules at configure time.
293 sub translate_functions($$)
294 {
295         my ($line,$module) = @_;
296
297         eval
298         {
299                 $module =~ /modules*\/(.+?)$/;
300                 $module = $1;
301
302                 # This is only a cursory check, just designed to catch casual accidental use of backticks.
303                 # There are pleanty of ways around it, but its not supposed to be for security, just checking
304                 # that people are using the new configuration api as theyre supposed to and not just using
305                 # backticks instead of eval(), being as eval has accountability. People wanting to get around
306                 # the accountability will do so anyway.
307                 if (($line =~ /`/) && ($line !~ /eval\(.+?`.+?\)/))
308                 {
309                         die "Developers should no longer use backticks in configuration macros. Please use exec() and eval() macros instead. Offending line: $line (In module: $module)";
310                 }
311                 while ($line =~ /exec\("(.+?)"\)/)
312                 {
313                         print "Executing program for module \033[1;32m$module\033[0m ... \033[1;32m$1\033[0m\n";
314                         my $replace = `$1`;
315                         chomp($replace);
316                         $line =~ s/exec\("(.+?)"\)/$replace/;
317                 }
318                 while ($line =~ /eval\("(.+?)"\)/)
319                 {
320                         print "Evaluating perl code for module \033[1;32m$module\033[0m ... ";
321                         my $tmpfile;
322                         do
323                         {
324                                 $tmpfile = tmpnam();
325                         } until sysopen(TF, $tmpfile, O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW, 0700);
326                         print "(Created and executed \033[1;32m$tmpfile\033[0m)\n";
327                         print TF $1;
328                         close TF;
329                         my $replace = `perl $tmpfile`;
330                         chomp($replace);
331                         $line =~ s/eval\("(.+?)"\)/$replace/;
332                 }
333                 while ($line =~ /pkgconflibs\("(.+?)","(.+?)","(.+?)"\)/)
334                 {
335                         my $replace = pkgconfig_get_lib_dirs($1, $2, $3, $module);
336                         $line =~ s/pkgconflibs\("(.+?)","(.+?)","(.+?)"\)/$replace/;
337                 }
338                 while ($line =~ /pkgconfversion\("(.+?)","(.+?)"\)/)
339                 {
340                         if (pkgconfig_check_version($1, $2, $module) != 1)
341                         {
342                                 die "Version of package $1 is too old. Please upgrade it to version \033[1;32m$2\033[0m or greater and try again.";
343                         }
344                         # This doesnt actually get replaced with anything
345                         $line =~ s/pkgconfversion\("(.+?)","(.+?)"\)//;
346                 }
347                 while ($line =~ /pkgconflibs\("(.+?)","(.+?)",""\)/)
348                 {
349                         my $replace = pkgconfig_get_lib_dirs($1, $2, "", $module);
350                         $line =~ s/pkgconflibs\("(.+?)","(.+?)",""\)/$replace/;
351                 }
352                 while ($line =~ /pkgconfincludes\("(.+?)","(.+?)",""\)/)
353                 {
354                         my $replace = pkgconfig_get_include_dirs($1, $2, "", $module);
355                         $line =~ s/pkgconfincludes\("(.+?)","(.+?)",""\)/$replace/;
356                 }
357                 while ($line =~ /pkgconfincludes\("(.+?)","(.+?)","(.+?)"\)/)
358                 {
359                         my $replace = pkgconfig_get_include_dirs($1, $2, $3, $module);
360                         $line =~ s/pkgconfincludes\("(.+?)","(.+?)","(.+?)"\)/$replace/;
361                 }
362                 while ($line =~ /rpath\("(.+?)"\)/)
363                 {
364                         my $replace = make_rpath($1,$module);
365                         $replace = "" if ($^O =~ /darwin/i);
366                         $line =~ s/rpath\("(.+?)"\)/$replace/;
367                 }
368         };
369         if ($@)
370         {
371                 $err = $@;
372                 $err =~ s/at .+? line \d+.*//g;
373                 print "\n\nConfiguration failed. The following error occured:\n\n$err\n";
374                 exit;
375         }
376         else
377         {
378                 return $line;
379         }
380 }
381
382 1;
383