]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - make/utilities.pm
9776ae7f4900fd80de591eb636ab67639ad35655
[user/henk/code/inspircd.git] / make / utilities.pm
1 #       +------------------------------------+
2 #       | Inspire Internet Relay Chat Daemon |
3 #       +------------------------------------+
4 #
5 #  InspIRCd: (C) 2002-2009 InspIRCd Development Team
6 # See: http://wiki.inspircd.org/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         if ((!defined $v) || ($v eq ""))
118         {
119                 $foo = `locate "$headername" | head -n 1`;
120                 $foo =~ /(.+)\Q$headername\E/;
121                 my $find = $1;
122                 chomp($find);
123                 if ((defined $find) && ($find ne "") && ($find ne $packagename))
124                 {
125                         print "(\e[1;32mFound via search\e[0m) ";
126                         $foo = "-I$1";
127                 }
128                 else
129                 {
130                         $foo = " ";
131                         undef $v;
132                 }
133                 $ret = "$foo";
134         }
135         if (($defaults ne "") && (($ret eq "") || (!defined $ret)))
136         {
137                 $ret = "$foo " . $defaults;
138         }
139         chomp($ret);
140         if ((($ret eq " ") || (!defined $ret)) && ((!defined $v) || ($v eq "")))
141         {
142                 my $key = "default_includedir_$packagename";
143                 if (exists $main::config{$key})
144                 {
145                         $ret = $main::config{$key};
146                 }
147                 else
148                 {
149                         $headername =~ s/^\///;
150                         promptstring("path to the directory containing $headername", $key, "/usr/include",$packagename,"$packagename-includes");
151                         $packagename =~ tr/a-z/A-Z/;
152                         if (defined $v)
153                         {
154                                 $main::config{$key} = "-I$main::config{$key}" . " $defaults -DVERSION_$packagename=\"$v\"";
155                         }
156                         else
157                         {
158                                 $main::config{$key} = "-I$main::config{$key}" . " $defaults -DVERSION_$packagename=\"0.0\"";
159                         }
160                         $main::config{$key} =~ s/^\s+//g;
161                         $ret = $main::config{$key};
162                         return $ret;
163                 }
164         }
165         else
166         {
167                 chomp($v);
168                 my $key = "default_includedir_$packagename";
169                 $packagename =~ tr/a-z/A-Z/;
170                 $main::config{$key} = "$ret -DVERSION_$packagename=\"$v\"";
171                 $main::config{$key} =~ s/^\s+//g;
172                 $ret = $main::config{$key};
173                 print "\e[1;32m$ret\e[0m (version $v)\n";
174         }
175         $ret =~ s/^\s+//g;
176         return $ret;
177 }
178
179 sub vcheck($$)
180 {
181         my ($version1, $version2) = @_;
182         $version1 =~ s/\-r(\d+)/\.$1/g; # minor revs/patchlevels
183         $version2 =~ s/\-r(\d+)/\.$1/g;
184         $version1 =~ s/p(\d+)/\.$1/g;
185         $version2 =~ s/p(\d+)/\.$1/g;
186         $version1 =~ s/\-//g;
187         $version2 =~ s/\-//g;
188         $version1 =~ s/[a-z]//g;
189         $version2 =~ s/[a-z]//g;
190         my @v1 = split('\.', $version1);
191         my @v2 = split('\.', $version2);
192         for (my $curr = 0; $curr < scalar(@v2); $curr++)
193         {
194                 if ($v1[$curr] < $v2[$curr])
195                 {
196                         return 0;
197                 }
198         }
199         return 1;
200 }
201
202 sub pkgconfig_check_version($$;$)
203 {
204         my ($packagename, $version, $module) = @_;
205
206         extend_pkg_path();
207
208         print "Checking version of package \e[1;32m$packagename\e[0m is >= \e[1;32m$version\e[0m... ";
209
210         my $v = `pkg-config --modversion $packagename 2>/dev/null`;
211         if (defined $v)
212         {
213                 chomp($v);
214         }
215         if ((defined $v) && ($v ne ""))
216         {
217                 if (vcheck($v,$version) == 1)
218                 {
219                         print "\e[1;32mYes (version $v)\e[0m\n";
220                         return 1;
221                 }
222                 else
223                 {
224                         print "\e[1;32mNo (version $v)\e[0m\n";
225                         return 0;
226                 }
227         }
228         # If we didnt find it, we  cant definitively say its too old.
229         # Return ok, and let pkgconflibs() or pkgconfincludes() pick up
230         # the missing library later on.
231         print "\e[1;32mNo (not found)\e[0m\n";
232         return 1;
233 }
234
235 sub pkgconfig_get_lib_dirs($$$;$)
236 {
237         my ($packagename, $libname, $defaults, $module) = @_;
238
239         my $key = "default_libdir_$packagename";
240         if (exists $main::config{$key})
241         {
242                 print "Locating library directory for package \e[1;32m$packagename\e[0m for module \e[1;32m$module\e[0m... ";
243                 my $ret = $main::config{$key};
244                 print "\e[1;32m$ret\e[0m (cached)\n";
245                 return $ret;
246         }
247
248         extend_pkg_path();
249
250         print "Locating library directory for package \e[1;32m$packagename\e[0m for module \e[1;32m$module\e[0m... ";
251
252         my $v = `pkg-config --modversion $packagename 2>/dev/null`;
253         my $ret = `pkg-config --libs $packagename 2>/dev/null`;
254
255         my $foo = "";
256         if ((!defined $v) || ($v eq ""))
257         {
258                 $foo = `locate "$libname" | head -n 1`;
259                 $foo =~ /(.+)\Q$libname\E/;
260                 my $find = $1;
261                 chomp($find);
262                 if ((defined $find) && ($find ne "") && ($find ne $packagename))
263                 {
264                         print "(\e[1;32mFound via search\e[0m) ";
265                         $foo = "-L$1";
266                 }
267                 else
268                 {
269                         $foo = " ";
270                         undef $v;
271                 }
272                 $ret = "$foo";
273         }
274
275         if (($defaults ne "") && (($ret eq "") || (!defined $ret)))
276         {
277                 $ret = "$foo " . $defaults;
278         }
279         chomp($ret);
280         if ((($ret eq " ") || (!defined $ret)) && ((!defined $v) || ($v eq "")))
281         {
282                 my $key = "default_libdir_$packagename";
283                 if (exists $main::config{$key})
284                 {
285                         $ret = $main::config{$key};
286                 }
287                 else
288                 {
289                         $libname =~ s/^\///;
290                         promptstring("path to the directory containing $libname", $key, "/usr/lib",$packagename,"$packagename-libs");
291                         $main::config{$key} = "-L$main::config{$key}" . " $defaults";
292                         $main::config{$key} =~ s/^\s+//g;
293                         $ret = $main::config{$key};
294                         return $ret;
295                 }
296         }
297         else
298         {
299                 chomp($v);
300                 print "\e[1;32m$ret\e[0m (version $v)\n";
301                 my $key = "default_libdir_$packagename";
302                 $main::config{$key} = $ret;
303                 $main::config{$key} =~ s/^\s+//g;
304                 $ret =~ s/^\s+//g;
305         }
306         $ret =~ s/^\s+//g;
307         return $ret;
308 }
309
310 # Translate a $CompileFlags etc line and parse out function calls
311 # to functions within these modules at configure time.
312 sub translate_functions($$)
313 {
314         my ($line,$module) = @_;
315
316         eval
317         {
318                 $module =~ /modules*\/(.+?)$/;
319                 $module = $1;
320
321                 # This is only a cursory check, just designed to catch casual accidental use of backticks.
322                 # There are pleanty of ways around it, but its not supposed to be for security, just checking
323                 # that people are using the new configuration api as theyre supposed to and not just using
324                 # backticks instead of eval(), being as eval has accountability. People wanting to get around
325                 # the accountability will do so anyway.
326                 if (($line =~ /`/) && ($line !~ /eval\(.+?`.+?\)/))
327                 {
328                         die "Developers should no longer use backticks in configuration macros. Please use exec() and eval() macros instead. Offending line: $line (In module: $module)";
329                 }
330
331                 if ($line =~ /ifuname\(\!"(\w+)"\)/)
332                 {
333                         my $uname = $1;
334                         if ($uname eq $^O)
335                         {
336                                 $line = "";
337                                 return "";
338                         }
339
340                         $line =~ s/ifuname\(\!"(.+?)"\)//;
341                 }
342
343                 if ($line =~ /ifuname\("(\w+)"\)/)
344                 {
345                         my $uname = $1;
346                         if ($uname ne $^O)
347                         {
348                                 $line = "";
349                                 return "";
350                         }
351
352                         $line =~ s/ifuname\("(.+?)"\)//;
353                 }
354
355                 if ($line =~ /if\("(\w+)"\)/)
356                 {
357                         if (defined $main::config{$1})
358                         {
359                                 if (($main::config{$1} !~ /y/i) and ($main::config{$1} ne "1"))
360                                 {
361                                         $line = "";
362                                         return "";
363                                 }
364                         }
365
366                         $line =~ s/if\("(.+?)"\)//;
367                 }
368                 if ($line =~ /if\(\!"(\w+)"\)/)
369                 {
370                         if (!exists $main::config{$1})
371                         {
372                                 $line = "";
373                                 return "";
374                         }
375                         else
376                         {
377                                 if (defined $1)
378                                 {
379                                         if (exists ($main::config{$1}) and (($main::config{$1} =~ /y/i) or ($main::config{$1} eq "1")))
380                                         {
381                                                 $line = "";
382                                                 return "";
383                                         }
384                                 }
385                         }
386
387                         $line =~ s/if\(\!"(.+?)"\)//;
388                 }
389                 while ($line =~ /exec\("(.+?)"\)/)
390                 {
391                         print "Executing program for module \e[1;32m$module\e[0m ... \e[1;32m$1\e[0m\n";
392                         my $replace = `$1`;
393                         die $replace if ($replace =~ /Configuration failed/);
394                         chomp($replace);
395                         $line =~ s/exec\("(.+?)"\)/$replace/;
396                 }
397                 while ($line =~ /execruntime\("(.+?)"\)/)
398                 {
399                         $line =~ s/execruntime\("(.+?)"\)/`$1`/;
400                 }
401                 while ($line =~ /eval\("(.+?)"\)/)
402                 {
403                         print "Evaluating perl code for module \e[1;32m$module\e[0m ... ";
404                         my $tmpfile;
405                         do
406                         {
407                                 $tmpfile = tmpnam();
408                         } until sysopen(TF, $tmpfile, O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW, 0700);
409                         print "(Created and executed \e[1;32m$tmpfile\e[0m)\n";
410                         print TF $1;
411                         close TF;
412                         my $replace = `perl $tmpfile`;
413                         chomp($replace);
414                         $line =~ s/eval\("(.+?)"\)/$replace/;
415                 }
416                 while ($line =~ /pkgconflibs\("(.+?)","(.+?)","(.+?)"\)/)
417                 {
418                         my $replace = pkgconfig_get_lib_dirs($1, $2, $3, $module);
419                         $line =~ s/pkgconflibs\("(.+?)","(.+?)","(.+?)"\)/$replace/;
420                 }
421                 while ($line =~ /pkgconfversion\("(.+?)","(.+?)"\)/)
422                 {
423                         if (pkgconfig_check_version($1, $2, $module) != 1)
424                         {
425                                 die "Version of package $1 is too old. Please upgrade it to version \e[1;32m$2\e[0m or greater and try again.";
426                         }
427                         # This doesnt actually get replaced with anything
428                         $line =~ s/pkgconfversion\("(.+?)","(.+?)"\)//;
429                 }
430                 while ($line =~ /pkgconflibs\("(.+?)","(.+?)",""\)/)
431                 {
432                         my $replace = pkgconfig_get_lib_dirs($1, $2, "", $module);
433                         $line =~ s/pkgconflibs\("(.+?)","(.+?)",""\)/$replace/;
434                 }
435                 while ($line =~ /pkgconfincludes\("(.+?)","(.+?)",""\)/)
436                 {
437                         my $replace = pkgconfig_get_include_dirs($1, $2, "", $module);
438                         $line =~ s/pkgconfincludes\("(.+?)","(.+?)",""\)/$replace/;
439                 }
440                 while ($line =~ /pkgconfincludes\("(.+?)","(.+?)","(.+?)"\)/)
441                 {
442                         my $replace = pkgconfig_get_include_dirs($1, $2, $3, $module);
443                         $line =~ s/pkgconfincludes\("(.+?)","(.+?)","(.+?)"\)/$replace/;
444                 }
445                 while ($line =~ /rpath\("(.+?)"\)/)
446                 {
447                         my $replace = make_rpath($1,$module);
448                         $replace = "" if ($^O =~ /darwin/i);
449                         $line =~ s/rpath\("(.+?)"\)/$replace/;
450                 }
451         };
452         if ($@)
453         {
454                 my $err = $@;
455                 #$err =~ s/at .+? line \d+.*//g;
456                 print "\n\nConfiguration failed. The following error occured:\n\n$err\n";
457                 print "\nIn the case of gnutls configuration errors on debian,\n";
458                 print "Ubuntu, etc, you should ensure that you have installed\n";
459                 print "gnutls-bin as well as gnutls-dev and gnutls.\n";
460                 exit;
461         }
462         else
463         {
464                 return $line;
465         }
466 }
467
468 1;
469