]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - make/utilities.pm
m_spanningtree Remove duplicate code for sending channel messages from RouteCommand()
[user/henk/code/inspircd.git] / make / utilities.pm
1 #
2 # InspIRCd -- Internet Relay Chat Daemon
3 #
4 #   Copyright (C) 2010 Daniel De Graaf <danieldg@inspircd.org>
5 #   Copyright (C) 2007-2008 Craig Edwards <craigedwards@brainbox.cc>
6 #   Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org>
7 #   Copyright (C) 2007 Dennis Friis <peavey@inspircd.org>
8 #
9 # This file is part of InspIRCd.  InspIRCd is free software: you can
10 # redistribute it and/or modify it under the terms of the GNU General Public
11 # License as published by the Free Software Foundation, version 2.
12 #
13 # This program is distributed in the hope that it will be useful, but WITHOUT
14 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15 # FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
16 # details.
17 #
18 # You should have received a copy of the GNU General Public License
19 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 #
21
22
23 BEGIN {
24         require 5.8.0;
25 }
26
27 package make::utilities;
28
29 use strict;
30 use warnings FATAL => qw(all);
31
32 use Exporter 'import';
33 use Fcntl;
34 use File::Path;
35 use File::Spec::Functions qw(rel2abs);
36 use Getopt::Long;
37
38 our @EXPORT = qw(module_installed prompt_bool prompt_dir prompt_string make_rpath pkgconfig_get_include_dirs pkgconfig_get_lib_dirs pkgconfig_check_version translate_functions promptstring);
39
40 # Parse the output of a *_config program,
41 # such as pcre_config, take out the -L
42 # directive and return an rpath for it.
43
44 # \e[1;32msrc/Makefile\e[0m
45
46 my %already_added = ();
47 my $if_skip_lines = 0;
48
49 sub module_installed($)
50 {
51         my $module = shift;
52         eval("use $module;");
53         return !$@;
54 }
55
56 sub prompt_bool($$$) {
57         my ($interactive, $question, $default) = @_;
58         my $answer = prompt_string($interactive, $question, $default ? 'y' : 'n');
59         return $answer =~ /y/i;
60 }
61
62 sub prompt_dir($$$) {
63         my ($interactive, $question, $default) = @_;
64         my ($answer, $create) = (undef, 'y');
65         do {
66                 $answer = rel2abs(prompt_string($interactive, $question, $default));
67                 $create = prompt_bool($interactive && !-d $answer, "$answer does not exist. Create it?", 'y');
68                 my $mkpath = eval {
69                         mkpath($answer, 0, 0750);
70                         return 1;
71                 };
72                 unless (defined $mkpath) {
73                         print "Error: unable to create $answer!\n\n";
74                         $create = 0;
75                 }
76         } while (!$create);
77         return $answer;
78 }
79
80 sub prompt_string($$$) {
81         my ($interactive, $question, $default) = @_;
82         return $default unless $interactive;
83         print $question, "\n";
84         print "[\e[1;32m$default\e[0m] => ";
85         chomp(my $answer = <STDIN>);
86         print "\n";
87         return $answer ? $answer : $default;
88 }
89
90 sub promptstring($$$$$)
91 {
92         my ($prompt, $configitem, $default, $package, $commandlineswitch) = @_;
93         my $var;
94         if (!$main::interactive)
95         {
96                 my $opt_commandlineswitch;
97                 GetOptions ("$commandlineswitch=s" => \$opt_commandlineswitch);
98                 if (defined $opt_commandlineswitch)
99                 {
100                         print "\e[1;32m$opt_commandlineswitch\e[0m\n";
101                         $var = $opt_commandlineswitch;
102                 }
103                 else
104                 {
105                         die "Could not detect $package! Please specify the $prompt via the command line option \e[1;32m--$commandlineswitch=\"/path/to/file\"\e[0m";
106                 }
107         }
108         else
109         {
110                 print "\nPlease enter the $prompt?\n";
111                 print "[\e[1;32m$default\e[0m] -> ";
112                 chomp($var = <STDIN>);
113         }
114         if ($var eq "")
115         {
116                 $var = $default;
117         }
118         $main::config{$configitem} = $var;
119 }
120
121 sub make_rpath($;$)
122 {
123         my ($executable, $module) = @_;
124         chomp(my $data = `$executable`);
125         my $output = "";
126         while ($data =~ /-L(\S+)/)
127         {
128                 my $libpath = $1;
129                 if (!exists $already_added{$libpath})
130                 {
131                         print "Adding extra library path to \e[1;32m$module\e[0m ... \e[1;32m$libpath\e[0m\n";
132                         $already_added{$libpath} = 1;
133                 }
134                 $output .= "-Wl,--rpath -Wl,$libpath -L$libpath " unless defined $main::opt_disablerpath;
135                 $data =~ s/-L(\S+)//;
136         }
137         return $output;
138 }
139
140 sub extend_pkg_path()
141 {
142         if (!exists $ENV{PKG_CONFIG_PATH})
143         {
144                 $ENV{PKG_CONFIG_PATH} = "/usr/lib/pkgconfig:/usr/local/lib/pkgconfig:/usr/local/libdata/pkgconfig:/usr/X11R6/libdata/pkgconfig";
145         }
146         else
147         {
148                 $ENV{PKG_CONFIG_PATH} .= ":/usr/local/lib/pkgconfig:/usr/local/libdata/pkgconfig:/usr/X11R6/libdata/pkgconfig";
149         }
150 }
151
152 sub pkgconfig_get_include_dirs($$$;$)
153 {
154         my ($packagename, $headername, $defaults, $module) = @_;
155
156         extend_pkg_path();
157
158         print "Locating include directory for package \e[1;32m$packagename\e[0m for module \e[1;32m$module\e[0m... ";
159
160         my $v = `pkg-config --modversion $packagename 2>/dev/null`;
161         my $ret = `pkg-config --cflags $packagename 2>/dev/null`;
162         my $foo = "";
163         if ((!defined $v) || ($v eq ""))
164         {
165                 print "\e[31mCould not find $packagename via pkg-config\e[m (\e[1;32mplease install pkg-config\e[m)\n";
166                 $foo = `locate "$headername" 2>/dev/null | head -n 1`;
167                 my $find = $foo =~ /(.+)\Q$headername\E/ ? $1 : '';
168                 chomp($find);
169                 if ((defined $find) && ($find ne "") && ($find ne $packagename))
170                 {
171                         print "(\e[1;32mFound via search\e[0m) ";
172                         $foo = "-I$1";
173                 }
174                 else
175                 {
176                         $foo = " ";
177                         undef $v;
178                 }
179                 $ret = "$foo";
180         }
181         if (($defaults ne "") && (($ret eq "") || (!defined $ret)))
182         {
183                 $ret = "$foo " . $defaults;
184         }
185         chomp($ret);
186         if ((($ret eq " ") || (!defined $ret)) && ((!defined $v) || ($v eq "")))
187         {
188                 my $key = "default_includedir_$packagename";
189                 if (exists $main::config{$key})
190                 {
191                         $ret = $main::config{$key};
192                 }
193                 else
194                 {
195                         $headername =~ s/^\///;
196                         promptstring("path to the directory containing $headername", $key, "/usr/include",$packagename,"$packagename-includes");
197                         $packagename =~ tr/a-z/A-Z/;
198                         if (defined $v)
199                         {
200                                 $main::config{$key} = "-I$main::config{$key}" . " $defaults -DVERSION_$packagename=\"$v\"";
201                         }
202                         else
203                         {
204                                 $main::config{$key} = "-I$main::config{$key}" . " $defaults -DVERSION_$packagename=\"0.0\"";
205                         }
206                         $main::config{$key} =~ s/^\s+//g;
207                         $ret = $main::config{$key};
208                         return $ret;
209                 }
210         }
211         else
212         {
213                 chomp($v);
214                 my $key = "default_includedir_$packagename";
215                 $packagename =~ tr/a-z/A-Z/;
216                 $main::config{$key} = "$ret -DVERSION_$packagename=\"$v\"";
217                 $main::config{$key} =~ s/^\s+//g;
218                 $ret = $main::config{$key};
219                 print "\e[1;32m$ret\e[0m (version $v)\n";
220         }
221         $ret =~ s/^\s+//g;
222         return $ret;
223 }
224
225 sub pkgconfig_check_version($$;$)
226 {
227         my ($packagename, $version, $module) = @_;
228
229         extend_pkg_path();
230
231         print "Checking version of package \e[1;32m$packagename\e[0m is >= \e[1;32m$version\e[0m... ";
232
233         my $v = `pkg-config --modversion $packagename 2>/dev/null`;
234         if (defined $v)
235         {
236                 chomp($v);
237         }
238         if ((defined $v) && ($v ne ""))
239         {
240                 if (!system "pkg-config --atleast-version $version $packagename")
241                 {
242                         print "\e[1;32mYes (version $v)\e[0m\n";
243                         return 1;
244                 }
245                 else
246                 {
247                         print "\e[1;32mNo (version $v)\e[0m\n";
248                         return 0;
249                 }
250         }
251         # If we didnt find it, we  cant definitively say its too old.
252         # Return ok, and let pkgconflibs() or pkgconfincludes() pick up
253         # the missing library later on.
254         print "\e[1;32mNo (not found)\e[0m\n";
255         return 1;
256 }
257
258 sub pkgconfig_get_lib_dirs($$$;$)
259 {
260         my ($packagename, $libname, $defaults, $module) = @_;
261
262         extend_pkg_path();
263
264         print "Locating library directory for package \e[1;32m$packagename\e[0m for module \e[1;32m$module\e[0m... ";
265
266         my $v = `pkg-config --modversion $packagename 2>/dev/null`;
267         my $ret = `pkg-config --libs $packagename 2>/dev/null`;
268
269         my $foo = "";
270         if ((!defined $v) || ($v eq ""))
271         {
272                 $foo = `locate "$libname" | head -n 1`;
273                 $foo =~ /(.+)\Q$libname\E/;
274                 my $find = $1;
275                 chomp($find);
276                 if ((defined $find) && ($find ne "") && ($find ne $packagename))
277                 {
278                         print "(\e[1;32mFound via search\e[0m) ";
279                         $foo = "-L$1";
280                 }
281                 else
282                 {
283                         $foo = " ";
284                         undef $v;
285                 }
286                 $ret = "$foo";
287         }
288
289         if (($defaults ne "") && (($ret eq "") || (!defined $ret)))
290         {
291                 $ret = "$foo " . $defaults;
292         }
293         chomp($ret);
294         if ((($ret eq " ") || (!defined $ret)) && ((!defined $v) || ($v eq "")))
295         {
296                 my $key = "default_libdir_$packagename";
297                 if (exists $main::config{$key})
298                 {
299                         $ret = $main::config{$key};
300                 }
301                 else
302                 {
303                         $libname =~ s/^\///;
304                         promptstring("path to the directory containing $libname", $key, "/usr/lib",$packagename,"$packagename-libs");
305                         $main::config{$key} = "-L$main::config{$key}" . " $defaults";
306                         $main::config{$key} =~ s/^\s+//g;
307                         $ret = $main::config{$key};
308                         return $ret;
309                 }
310         }
311         else
312         {
313                 chomp($v);
314                 print "\e[1;32m$ret\e[0m (version $v)\n";
315                 my $key = "default_libdir_$packagename";
316                 $main::config{$key} = $ret;
317                 $main::config{$key} =~ s/^\s+//g;
318                 $ret =~ s/^\s+//g;
319         }
320         $ret =~ s/^\s+//g;
321         return $ret;
322 }
323
324 # Translate a $CompileFlags etc line and parse out function calls
325 # to functions within these modules at configure time.
326 sub translate_functions($$)
327 {
328         my ($line,$module) = @_;
329
330         eval
331         {
332                 $module =~ /modules*\/(.+?)$/;
333                 $module = $1;
334
335                 if ($line =~ /ifuname\(\!"(\w+)"\)/)
336                 {
337                         my $uname = $1;
338                         if ($uname eq $^O)
339                         {
340                                 $line = "";
341                                 return "";
342                         }
343
344                         $line =~ s/ifuname\(\!"(.+?)"\)//;
345                 }
346
347                 if ($line =~ /ifuname\("(\w+)"\)/)
348                 {
349                         my $uname = $1;
350                         if ($uname ne $^O)
351                         {
352                                 $line = "";
353                                 return "";
354                         }
355
356                         $line =~ s/ifuname\("(.+?)"\)//;
357                 }
358
359                 if ($line =~ /if\("(\w+)"\)/)
360                 {
361                         if (defined $main::config{$1})
362                         {
363                                 if (($main::config{$1} !~ /y/i) and ($main::config{$1} ne "1"))
364                                 {
365                                         $line = "";
366                                         return "";
367                                 }
368                         }
369
370                         $line =~ s/if\("(.+?)"\)//;
371                 }
372                 if ($line =~ /if\(\!"(\w+)"\)/)
373                 {
374                         if (!exists $main::config{$1})
375                         {
376                                 $line = "";
377                                 return "";
378                         }
379                         else
380                         {
381                                 if (defined $1)
382                                 {
383                                         if (exists ($main::config{$1}) and (($main::config{$1} =~ /y/i) or ($main::config{$1} eq "1")))
384                                         {
385                                                 $line = "";
386                                                 return "";
387                                         }
388                                 }
389                         }
390
391                         $line =~ s/if\(\!"(.+?)"\)//;
392                 }
393                 while ($line =~ /exec\("(.+?)"\)/)
394                 {
395                         print "Executing program for module \e[1;32m$module\e[0m ... \e[1;32m$1\e[0m\n";
396                         my $replace = `$1`;
397                         die $replace if ($replace =~ /Configuration failed/);
398                         chomp($replace);
399                         $line =~ s/exec\("(.+?)"\)/$replace/;
400                 }
401                 while ($line =~ /execruntime\("(.+?)"\)/)
402                 {
403                         $line =~ s/execruntime\("(.+?)"\)/`$1`/;
404                 }
405                 while ($line =~ /eval\("(.+?)"\)/)
406                 {
407                         print "Evaluating perl code for module \e[1;32m$module\e[0m ... ";
408                         my $tmpfile;
409                         do
410                         {
411                                 $tmpfile = tmpnam();
412                         } until sysopen(TF, $tmpfile, O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW, 0700);
413                         print "(Created and executed \e[1;32m$tmpfile\e[0m)\n";
414                         print TF $1;
415                         close TF;
416                         my $replace = `perl $tmpfile`;
417                         chomp($replace);
418                         $line =~ s/eval\("(.+?)"\)/$replace/;
419                 }
420                 while ($line =~ /pkgconflibs\("(.+?)","(.+?)","(.+?)"\)/)
421                 {
422                         my $replace = pkgconfig_get_lib_dirs($1, $2, $3, $module);
423                         $line =~ s/pkgconflibs\("(.+?)","(.+?)","(.+?)"\)/$replace/;
424                 }
425                 while ($line =~ /pkgconfversion\("(.+?)","(.+?)"\)/)
426                 {
427                         if (pkgconfig_check_version($1, $2, $module) != 1)
428                         {
429                                 die "Version of package $1 is too old. Please upgrade it to version \e[1;32m$2\e[0m or greater and try again.";
430                         }
431                         # This doesnt actually get replaced with anything
432                         $line =~ s/pkgconfversion\("(.+?)","(.+?)"\)//;
433                 }
434                 while ($line =~ /pkgconflibs\("(.+?)","(.+?)",""\)/)
435                 {
436                         my $replace = pkgconfig_get_lib_dirs($1, $2, "", $module);
437                         $line =~ s/pkgconflibs\("(.+?)","(.+?)",""\)/$replace/;
438                 }
439                 while ($line =~ /pkgconfincludes\("(.+?)","(.+?)",""\)/)
440                 {
441                         my $replace = pkgconfig_get_include_dirs($1, $2, "", $module);
442                         $line =~ s/pkgconfincludes\("(.+?)","(.+?)",""\)/$replace/;
443                 }
444                 while ($line =~ /pkgconfincludes\("(.+?)","(.+?)","(.+?)"\)/)
445                 {
446                         my $replace = pkgconfig_get_include_dirs($1, $2, $3, $module);
447                         $line =~ s/pkgconfincludes\("(.+?)","(.+?)","(.+?)"\)/$replace/;
448                 }
449                 while ($line =~ /rpath\("(.+?)"\)/)
450                 {
451                         my $replace = make_rpath($1,$module);
452                         $replace = "" if ($^O =~ /darwin/i);
453                         $line =~ s/rpath\("(.+?)"\)/$replace/;
454                 }
455         };
456         if ($@)
457         {
458                 my $err = $@;
459                 #$err =~ s/at .+? line \d+.*//g;
460                 print "\n\nConfiguration failed. The following error occured:\n\n$err\n";
461                 print "\nMake sure you have pkg-config installed\n";
462                 print "\nIn the case of gnutls configuration errors on debian,\n";
463                 print "Ubuntu, etc, you should ensure that you have installed\n";
464                 print "gnutls-bin as well as gnutls-dev and gnutls.\n";
465                 exit;
466         }
467         else
468         {
469                 return $line;
470         }
471 }
472
473 1;
474