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