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