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