]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - configure
Fix "make module" to include dependency generation
[user/henk/code/inspircd.git] / configure
1 #!/usr/bin/perl
2 ###################################################
3 # InspIRCd Configuration Script
4 #
5 # Copyright 2002-2009 The InspIRCd Development Team
6 #  http://wiki.inspircd.org/Credits
7 #
8 # Licensed under GPL, please see the COPYING file
9 # for more information
10 #
11 # $Id$
12 #
13 ###################################################
14
15 BEGIN {
16         require 5.8.0;
17 }
18
19 use strict;
20 use warnings FATAL => qw(all);
21
22 use Data::Dumper;
23 BEGIN {
24         $Data::Dumper::Sortkeys = 1;
25         $Data::Dumper::Useqq = 1;
26 };
27
28 use File::Copy ();
29 use Socket;
30 use Cwd;
31 use Getopt::Long;
32
33 # Utility functions for our buildsystem
34 use make::utilities;
35 use make::configure;
36 use make::gnutlscert;
37 use make::opensslcert;
38
39 ###############################################################################################
40 #
41 #                                 NON-EDITABLE VARIABLES
42 #
43 ###############################################################################################
44
45 our ($opt_use_gnutls, $opt_rebuild, $opt_use_openssl, $opt_nointeractive, $opt_ports,
46     $opt_epoll, $opt_kqueue, $opt_noports, $opt_noepoll, $opt_nokqueue,
47     $opt_ipv6, $opt_ipv6links, $opt_noipv6links, $opt_maxbuf, $opt_disable_debug, $opt_freebsd_port);
48
49 our ($opt_cc, $opt_base_dir, $opt_config_dir, $opt_module_dir, $opt_binary_dir,
50     $opt_library_dir);
51
52 sub list_extras ();
53
54 sub enable_extras (@);
55
56 sub disable_extras (@);
57
58 my @opt_enableextras;
59 my @opt_disableextras;
60
61 GetOptions (
62         'enable-gnutls' => \$opt_use_gnutls,
63         'rebuild' => \$opt_rebuild,
64         'enable-openssl' => \$opt_use_openssl,
65         'disable-interactive' => \$opt_nointeractive,
66         'enable-ports' => \$opt_ports,
67         'enable-epoll' => \$opt_epoll,
68         'enable-kqueue' => \$opt_kqueue,
69         'disable-ports' => \$opt_noports,
70         'disable-epoll' => \$opt_noepoll,
71         'disable-kqueue' => \$opt_nokqueue,
72         'enable-ipv6' => \$opt_ipv6,
73         'enable-remote-ipv6' => \$opt_ipv6links,
74         'disable-remote-ipv6' => \$opt_noipv6links,
75         'with-cc=s' => \$opt_cc,
76         'with-maxbuf=i' => \$opt_maxbuf,
77         'enable-freebsd-ports-openssl' => \$opt_freebsd_port,
78         'prefix=s' => \$opt_base_dir,
79         'config-dir=s' => \$opt_config_dir,
80         'module-dir=s' => \$opt_module_dir,
81         'binary-dir=s' => \$opt_binary_dir,
82         'library-dir=s' => \$opt_library_dir,
83         'disable-debuginfo' => sub { $opt_disable_debug = 1 },
84         'help'  => sub { showhelp(); },
85         'update' => sub { update(); },
86         'svnupdate' => sub { svnupdate(); },
87         'clean' => sub { clean(); },
88         'list-extras' => sub { list_extras; exit 0; }, # This, --enable-extras, and --disable-extras are for non-interactive managing.
89         'enable-extras=s@' => \@opt_enableextras, # ^
90         'disable-extras=s@' => \@opt_disableextras, # ^
91         'generate-openssl-cert' => sub { make_openssl_cert(); exit(0); },
92         'generate-gnutls-cert' => sub { make_gnutls_cert(); exit(0); }
93 );
94
95 if (scalar(@opt_enableextras) + scalar(@opt_disableextras) > 0) {
96         @opt_enableextras = split /,/, join(',', @opt_enableextras);
97         @opt_disableextras = split /,/, join(',', @opt_disableextras);
98         enable_extras(@opt_enableextras);
99         disable_extras(@opt_disableextras);
100         list_extras;
101         print "Remember: YOU are responsible for making sure any libraries needed have been installed!\n";
102         exit 0;
103 }
104
105 our $non_interactive = (
106         (defined $opt_library_dir) ||
107         (defined $opt_base_dir) ||
108         (defined $opt_config_dir) ||
109         (defined $opt_module_dir) ||
110         (defined $opt_base_dir) ||
111         (defined $opt_binary_dir) ||
112         (defined $opt_nointeractive) ||
113         (defined $opt_cc) ||
114         (defined $opt_ipv6) ||
115         (defined $opt_ipv6links) ||
116         (defined $opt_noipv6links) ||
117         (defined $opt_kqueue) ||
118         (defined $opt_epoll) ||
119         (defined $opt_ports) ||
120         (defined $opt_use_openssl) ||
121         (defined $opt_nokqueue) ||
122         (defined $opt_noepoll) ||
123         (defined $opt_noports) ||
124         (defined $opt_maxbuf) ||
125         (defined $opt_use_gnutls) ||
126         (defined $opt_freebsd_port)
127 );
128 our $interactive = !$non_interactive;
129
130 chomp(our $topdir = getcwd());
131 our $this = resolve_directory($topdir);                                         # PWD, Regardless.
132 our @modlist = ();                                                                      # Declare for Module List..
133 our %config = ();                                                                       # Initiate Configuration Hash..
134 $config{ME}              = resolve_directory($topdir);                          # Present Working Directory
135
136 $config{BASE_DIR}          = $config{ME};
137
138 if (defined $opt_base_dir)
139 {
140         $config{BASE_DIR} = $opt_base_dir;
141 }
142
143 $config{CONFIG_DIR}      = resolve_directory($config{BASE_DIR}."/conf");        # Configuration Directory
144 $config{MODULE_DIR}      = resolve_directory($config{BASE_DIR}."/modules");     # Modules Directory
145 $config{BINARY_DIR}      = resolve_directory($config{BASE_DIR}."/bin");         # Binary Directory
146 $config{LIBRARY_DIR}    = resolve_directory($config{BASE_DIR}."/lib");          # Library Directory
147
148 if (defined $opt_config_dir)
149 {
150         $config{CONFIG_DIR} = $opt_config_dir;
151 }
152 if (defined $opt_module_dir)
153 {
154         $config{MODULE_DIR} = $opt_module_dir;
155 }
156 if (defined $opt_binary_dir)
157 {
158         $config{BINARY_DIR} = $opt_binary_dir;
159 }
160 if (defined $opt_library_dir)
161 {
162         $config{LIBRARY_DIR} = $opt_library_dir;
163 }
164 chomp($config{HAS_GNUTLS}   = `pkg-config --modversion gnutls 2>/dev/null | cut -c 1,2,3`); # GNUTLS Version.
165
166 if (defined $opt_freebsd_port)
167 {
168         chomp($config{HAS_OPENSSL} = `pkg-config --modversion openssl 2>/dev/null`);
169         chomp($config{HAS_OPENSSL_PORT}  = `pkg-config --modversion openssl 2>/dev/null`);
170         $config{USE_FREEBSD_BASE_SSL} = "n";
171 }
172 else
173 {
174         if ($^O eq "freebsd")
175         {
176                 # default: use base ssl
177                 chomp($config{HAS_OPENSSL} = `openssl version | cut -d ' ' -f 2`);                      # OpenSSL version, freebsd specific
178                 chomp($config{HAS_OPENSSL_PORT}  = `pkg-config --modversion openssl 2>/dev/null`);      # Port version, may be different
179         }
180         else
181         {
182                 chomp($config{HAS_OPENSSL}  = `pkg-config --modversion openssl 2>/dev/null`);           # Openssl version, others
183                 $config{HAS_OPENSSL_PORT} = "";
184         }
185 }
186
187 chomp(our $gnutls_ver = $config{HAS_GNUTLS});
188 chomp(our $openssl_ver = $config{HAS_OPENSSL});
189 $config{USE_GNUTLS}         = "n";
190 if (defined $opt_use_gnutls)
191 {
192         $config{USE_GNUTLS} = "y";                                      # Use gnutls.
193 }
194 $config{USE_OPENSSL}    = "n";                                          # Use openssl.
195 if (defined $opt_use_openssl)
196 {
197         $config{USE_OPENSSL} = "y";
198 }
199
200 # no, let's not change these.
201 $config{OPTIMITEMP}      = "0";                                         # Default Optimisation Value
202 if (!defined $opt_disable_debug)
203 {
204         $config{OPTIMISATI}      = "-g1";                               # Optimisation Flag
205 }
206 else
207 {
208         $config{OPTIMISATI}      = "-O2";                               # DEBUGGING OFF!
209 }
210
211 $config{HAS_STRLCPY}    = "false";                                      # strlcpy Check.
212 $config{HAS_STDINT}      = "false";                                     # stdint.h check
213 $config{USE_KQUEUE}      = "y";                                         # kqueue enabled
214 if (defined $opt_kqueue)
215 {
216         $config{USE_KQUEUE} = "y";
217 }
218 if (defined $opt_nokqueue)
219 {
220         $config{USE_KQUEUE} = "n";
221 }
222 $config{USE_POLL}     = "y";                                    # poll enabled
223 $config{USE_EPOLL}        = "y";                                        # epoll enabled
224 if (defined $opt_epoll)
225 {
226         $config{USE_EPOLL} = "y";
227 }
228 if (defined $opt_noepoll)
229 {
230         $config{USE_EPOLL} = "n";
231 }
232 $config{USE_PORTS}        = "y";                                        # epoll enabled
233 if (defined $opt_ports)
234 {
235         $config{USE_PORTS} = "y";
236 }
237 if (defined $opt_noports)
238 {
239         $config{USE_PORTS} = "n";
240 }
241 $config{IPV6}          = "n";                                           # IPv6 support (experimental)
242 if (defined $opt_ipv6)
243 {
244         $config{IPV6} = "y";
245 }
246 $config{SUPPORT_IP6LINKS}   = "y";                                      # IPv4 supporting IPv6 links (experimental)
247 if (defined $opt_ipv6links)
248 {
249         $config{SUPPORT_IP6LINKS} = "y";
250 }
251 if (defined $opt_noipv6links)
252 {
253         $config{SUPPORT_IP6LINKS} = "n";
254 }
255 chomp($config{GCCVER}       = `g++ -dumpversion | cut -c 1`);           # Major GCC Version
256 chomp($config{GCCMINOR}     = `g++ -dumpversion | cut -c 3`);
257 $config{_SOMAXCONN} = SOMAXCONN;                                        # Max connections in accept queue
258 $config{OSNAME}             = $^O;                                      # Operating System Name
259 $config{IS_DARWIN}        = "NO";                                       # Is OSX?
260 $config{STARTSCRIPT}      = "inspircd";                 # start script?
261 $config{DESTINATION}      = "BASE";                             # Is target path.
262 $config{EXTRA_DIR}        = "";                                         # Is empty.
263 if ($config{OSNAME} =~ /darwin/i)
264 {
265         $config{IS_DARWIN} = "YES";
266         $config{STARTSCRIPT}      = "org.inspircd.plist";               # start script for OSX.
267         $config{DESTINATION}      = "LAUNCHDPATH";                              # Is OSX target.
268         $config{EXTRA_DIR}          = " launchd_dir";                           # Is OSX specific path.
269 }
270 $config{CC}                 = "g++";                                            # C++ compiler
271 if (defined $opt_cc)
272 {
273         $config{CC} = $opt_cc;
274 }
275 our $exec = $config{CC} . " -dumpversion | cut -c 1";
276 chomp($config{GCCVER}           = `$exec`);                             # Major GCC Version
277 $exec = $config{CC} . " -dumpversion | cut -c 3";
278 chomp($config{GCCMINOR}         = `$exec`);
279 $config{MAXBUF}                 = "512";                                # Max buffer size
280
281 if ($config{HAS_OPENSSL} =~ /^([-[:digit:].]+)([a-z])?(\-[a-z][0-9])?$/) {
282         $config{HAS_OPENSSL} = $1;
283 } else {
284         $config{HAS_OPENSSL} = "";
285 }
286
287 if (($config{GCCVER} eq "") || ($config{GCCMINOR} eq "")) {
288         print $config{CC} . " was not found! You require g++ (the GNU C++ compiler, part of GCC) to build InspIRCd!\n";
289         exit;
290 }
291
292 # Get and Set some important vars..
293 getmodules();
294
295 sub clean
296 {
297         unlink(".config.cache");
298 }
299
300 our ($has_epoll, $has_ports, $has_kqueue) = (0, 0, 0);
301
302 sub update
303 {
304         eval {
305                 chomp($topdir = getcwd());
306                 $this = resolve_directory($topdir);                                          # PWD, Regardless.
307                 getmodules();
308                 # Does the cache file exist?
309                 if (!getcache()) {
310                         # No, No it doesn't.. *BASH*
311                         print "You have not run ./configure before. Please do this before trying to run the update script.\n";
312                         exit 0;
313                 } else {
314                         # We've Loaded the cache file and all our variables..
315                         print "Updating files...\n";
316                         getosflags();
317                         if (defined($opt_disable_debug) && $opt_disable_debug == 1)
318                         {
319                                 print "Disabling debug information (-g).\n";
320                                 $config{OPTIMISATI} = "";
321                                 getosflags();
322                         }
323                         $has_epoll = $config{HAS_EPOLL};
324                         $has_ports = $config{HAS_PORTS};
325                         $has_kqueue = $config{HAS_KQUEUE};
326                         writefiles(1);
327                         makecache();
328                         print "Complete.\n";
329                         exit;
330                 }
331         };
332         if ($@)
333         {
334                 print "Configure update failed: $@\n";
335         }
336         exit;
337 }
338
339 sub svnupdate
340 {
341         my $fail = 0;
342         open(FH,"<.svn/entries") or $fail = 1;
343         if ($fail) {
344                 print "This is not an SVN copy of InspIRCd.\n";
345                 exit 1;
346         }
347         else
348         {
349                 close(FH);
350         }
351         open my $fd, "-|", "svn update";
352         my $configurechanged = 0; # Needs ./configure -update
353         my $rootincchanged = 0;
354         my @conflicted = ();
355         while (defined(my $line = <$fd>))
356         {
357                 my ($action, $file);
358                 print $line;
359                 $line =~ m/^([ADUCG])\s+(.*)$/ or next;
360                 ($action, $file) = ($1, $2);
361                 if ($action eq "C")
362                 {
363                         push @conflicted, $file;
364                         if ($file eq "configure")
365                         {
366                                 $configurechanged = 1;
367                         }
368                         elsif ($file =~ m/^\..*\.inc$/)
369                         {
370                                 $rootincchanged = 1;
371                         }
372                 }
373                 elsif ($action eq "U" || $action eq "G")
374                 {
375                         if ($file eq "configure")
376                         {
377                                 $configurechanged = 1;
378                         }
379                         elsif ($file =~ m/^\..*\.inc$/)
380                         {
381                                 $rootincchanged = 1;
382                         }
383                 }
384         }
385         unless (close $fd) # close() waits for exit and returns false if the command failed
386         {
387                 if ($! == 0)
388                 {
389                         print STDERR "Problem updating from SVN, please check above for errors\n";
390                 }
391                 else
392                 {
393                         print STDERR "Failed to run SVN: $!\n";
394                 }
395                 exit 1;
396         }
397         if (scalar(@conflicted) > 0)
398         {
399                 print STDERR "\e[0;33;1mERROR:\e[0m You have local modifications which conflicted with the updates from SVN\n";
400                 print STDERR "Configure is not able to complete the update. Please resolve these conflicts, then run ./configure -update\n";
401                 print "Conflicted files: " . join ", ", @conflicted . "\n";
402                 exit 1;
403         }
404         if ($configurechanged)
405         {
406                 system("perl configure -update");
407         }
408         else
409         {
410                 print "No need to update Makefiles.\n";
411         }
412         if (defined $opt_rebuild) {
413                 system("make install");
414         }
415         exit;
416 }
417
418 sub test_compile {
419         my $feature = shift;
420         my $fail = 0;
421         $fail ||= system "$config{CC} -o test_$feature make/check_$feature.cpp >/dev/null 2>&1";
422         $fail ||= system "./test_$feature";
423         unlink "test_$feature";
424         return !$fail;
425 }
426
427 print "Running non-interactive configure...\n" unless $interactive;
428 print "Checking for cache from previous configure... ";
429 print ((!getcache()) ? "not found\n" : "found\n");
430 print "Checking operating system version... ";
431 print getosflags() . "\n";
432
433 printf "Checking if stdint.h exists... ";
434 $config{HAS_STDINT} = "true";
435 our $fail = 0;
436 open(STDINT, "</usr/include/stdint.h") or $config{HAS_STDINT} = "false";
437 if ($config{HAS_STDINT} eq "true") {
438         close(STDINT);
439 }
440 print "yes\n" if $config{HAS_STDINT} eq "true";
441 print "no\n" if $config{HAS_STDINT} eq "false";
442
443 printf "Checking if strlcpy exists... ";
444 # Perform the strlcpy() test..
445 $config{HAS_STRLCPY} = "false";
446 $fail = 0;
447 open(STRLCPY, "</usr/include/string.h") or $fail = 1;
448 if (!$fail) {
449         while (defined(my $line = <STRLCPY>)) {
450                 chomp($line);
451                 # try and find the delcaration of:
452                 # size_t strlcpy(...)
453                 if ($line =~ /size_t(\0x9|\s)+strlcpy/) {
454                         $config{HAS_STRLCPY} = "true";
455                 }
456         }
457         close(STRLCPY);
458 }
459 print "yes\n" if $config{HAS_STRLCPY} eq "true";
460 print "no\n" if $config{HAS_STRLCPY} eq "false";
461
462 printf "Checking if kqueue exists... ";
463 $has_kqueue = 0;
464 $fail = 0;
465 open(KQUEUE, "</usr/include/sys/event.h") or $fail = 1;
466 if (!$fail) {
467         while (defined(my $line = <KQUEUE>)) {
468                 chomp($line);
469                 # try and find the delcaration of:
470                 # int kqueue(void);
471                 if ($line =~ /int(\0x9|\s)+kqueue/) {
472                         $has_kqueue = 1;
473                 }
474         }
475         close(KQUEUE);
476 }
477 print "yes\n" if $has_kqueue == 1;
478 print "no\n" if $has_kqueue == 0;
479
480 printf "Checking for epoll support... ";
481 $has_epoll = test_compile('epoll');
482 print $has_epoll ? "yes\n" : "no\n";
483
484 printf "Checking for eventfd support... ";
485 $config{HAS_EVENTFD} = test_compile('eventfd') ? 'true' : 'false';
486 print $config{HAS_EVENTFD} eq 'true' ? "yes\n" : "no\n";
487
488 printf "Checking if Solaris I/O completion ports are available... ";
489 $has_ports = 0;
490 our $system = `uname -s`;
491 chomp ($system);
492 $has_ports = 1 if ($system eq "SunOS");
493
494 if ($has_ports) {
495         my $kernel = `uname -r`;
496         chomp($kernel);
497         if (($kernel !~ /^5\.1./)) {
498                 $has_ports = 0;
499         }
500 }
501 print "yes\n" if $has_ports == 1;
502 print "no\n" if $has_ports == 0;
503
504 $config{HAS_EPOLL} = $has_epoll;
505 $config{HAS_KQUEUE} = $has_kqueue;
506
507 printf "Checking for libgnutls... ";
508 if (defined($config{HAS_GNUTLS}) && (($config{HAS_GNUTLS}) || ($config{HAS_GNUTLS} eq "y"))) {
509         if (defined($gnutls_ver) && ($gnutls_ver ne "")) {
510                 print "yes\n";
511                 $config{HAS_GNUTLS} = "y";
512         } else {
513                 print "no\n";
514                 $config{HAS_GNUTLS} = "n";
515         }
516 } else {
517         print "no\n";
518         $config{HAS_GNUTLS} = "n";
519 }
520
521 printf "Checking for openssl... ";
522 if (defined($config{HAS_OPENSSL}) && (($config{HAS_OPENSSL}) || ($config{HAS_OPENSSL} eq "y"))) {
523         if (defined($openssl_ver) && ($openssl_ver ne "")) {
524                 print "yes\n";
525                 $config{HAS_OPENSSL} = "y";
526         } else {
527                 print "no\n";
528                 $config{HAS_OPENSSL} = "n";
529         }
530 } else {
531         print "no\n";
532         $config{HAS_OPENSSL} = "n";
533 }
534
535 printf "Checking if you are running an ancient, unsupported OS... ";
536 if ($config{OSNAME} =~ /FreeBSD/i)
537 {
538         my $version = `uname -r`;
539         if ($version =~ /^4\./)
540         {
541                 my $foundit = `ls -l /usr/local/lib/libgnugetopt* | wc -l`;
542                 if ($foundit > 0)
543                 {
544                         # ICKY ICKY ICK, FREEBSD 4.x! GET AN UPGRADE!
545                         $config{CRAQ} = "-L/usr/local/lib -lgnugetopt -DHAVE_DECL_GETOPT=1";
546                         print "yes (upgrade ffs, freebsd 4 is *way* out of date)\n";
547                 }
548                 else
549                 {
550                         print "\n\nERROR: You require libgnugetopt (from ports or packages) to build InspIRCd on FreeBSD 4.11.\n";
551                 }
552         }
553         else
554         {
555                 $config{CRAQ} = " ";
556                 print "no ($version)\n";
557         }
558 }
559 else
560 {
561         $config{CRAQ} = " ";
562         print "no ($config{OSNAME})\n";
563 }
564
565 print "Checking for upgrades to extra and third party modules... ";
566 system "./modulemanager upgrade";
567
568 ################################################################################
569 #                         BEGIN INTERACTIVE PART                              #
570 ################################################################################
571
572 # Clear the Screen..
573 if ($interactive)
574 {
575         print "\e[2J\e[0G\e[0d"; # J = Erase in Display, 2 = Entire Screen, (G, d) = Move cursor to (..,..)
576         my $wholeos = $^O;
577
578         my $rev = getrevision();
579         # Display Introduction Message..
580         print <<"STOP" ;
581 Welcome to the \e[1mInspIRCd\e[0m Configuration program! (\e[1minteractive mode\e[0m)
582 \e[1mPackage maintainers: Type ./configure --help for non-interactive help\e[0m
583
584 *** If you are unsure of any of these values, leave it blank for    ***
585 *** standard settings that will work, and your server will run      ***
586 *** using them. Please consult your IRC network admin if in doubt.  ***
587
588 Press \e[1m<RETURN>\e[0m to accept the default for any option, or enter
589 a new value. Please note: You will \e[1mHAVE\e[0m to read the docs
590 dir, otherwise you won't have a config file!
591
592 Your operating system is: \e[1;32m$config{OSNAME}\e[0m ($wholeos)
593 Your InspIRCd revision ID is \e[1;32mr$rev\e[0m
594 STOP
595         if ($rev eq "r0") {
596                 print " (Non-SVN build)";
597         }
598         print ".\n\n";
599
600         $config{CHANGE_COMPILER} = "n";
601         print "I have detected the following compiler: \e[1;32m$config{CC}\e[0m (version \e[1;32m$config{GCCVER}.$config{GCCMINOR}\e[0m)\n";
602
603         while (($config{GCCVER} < 3) || ($config{GCCVER} eq "")) {
604                 print "\e[1;32mIMPORTANT!\e[0m A GCC 2.x compiler has been detected, and
605 should NOT be used. You should probably specify a newer compiler.\n\n";
606                 yesno('CHANGE_COMPILER',"Do you want to change the compiler?");
607                 if ($config{CHANGE_COMPILER} =~ /y/i) {
608                         print "What command do you want to use to invoke your compiler?\n";
609                         print "[\e[1;32m$config{CC}\e[0m] -> ";
610                         chomp($config{CC} = <STDIN>);
611                         if ($config{CC} eq "") {
612                                 $config{CC} = "g++";
613                         }
614                         chomp(my $foo = `$config{CC} -dumpversion | cut -c 1`);
615                         if ($foo ne "") {
616                                 chomp($config{GCCVER}       = `$config{CC} -dumpversion | cut -c 1`); # we must redo these if we change compilers
617                                 chomp($config{GCCMINOR}     = `$config{CC} -dumpversion | cut -c 3`);
618                                 print "Queried compiler: \e[1;32m$config{CC}\e[0m (version \e[1;32m$config{GCCVER}.$config{GCCMINOR}\e[0m)\n";
619                                 if ($config{GCCVER} < 3) {
620                                         print "\e[1;32mGCC 2.x WILL NOT WORK!\e[0m. Let's try that again, shall we?\n";
621                                 }
622                         }
623                         else {
624                                 print "\e[1;32mWARNING!\e[0m Could not execute the compiler you specified. You may want to try again.\n";
625                         }
626                 }
627         }
628
629         print "\n";
630
631         # Directory Settings..
632         my $tmpbase = $config{BASE_DIR};
633         dir_check("do you wish to install the InspIRCd base", "BASE_DIR");
634         if ($tmpbase ne $config{BASE_DIR}) {
635                 $config{CONFIG_DIR}      = resolve_directory($config{BASE_DIR}."/conf");           # Configuration Dir
636                 $config{MODULE_DIR}      = resolve_directory($config{BASE_DIR}."/modules");     # Modules Directory
637                 $config{BINARY_DIR}      = resolve_directory($config{BASE_DIR}."/bin");     # Binary Directory
638                 $config{LIBRARY_DIR}    = resolve_directory($config{BASE_DIR}."/lib");      # Library Directory
639         }
640
641         dir_check("are the configuration files", "CONFIG_DIR");
642         dir_check("are the modules to be compiled to", "MODULE_DIR");
643         dir_check("is the IRCd binary to be placed", "BINARY_DIR");
644         dir_check("are the IRCd libraries to be placed", "LIBRARY_DIR");
645
646         my $chose_hiperf = 0;
647         if ($has_kqueue) {
648                 yesno('USE_KQUEUE',"You are running a BSD operating system, and kqueue\nwas detected. Would you like to enable kqueue support?\nThis is likely to increase performance.\nIf you are unsure, answer yes.\n\nEnable kqueue?");
649                 print "\n";
650                 if ($config{USE_KQUEUE} eq "y") {
651                         $chose_hiperf = 1;
652                 }
653         }
654         if ($has_epoll) {
655                 yesno('USE_EPOLL',"You are running a Linux 2.6+ operating system, and epoll\nwas detected. Would you like to enable epoll support?\nThis is likely to increase performance.\nIf you are unsure, answer yes.\n\nEnable epoll?");
656                 print "\n";
657                 if ($config{USE_EPOLL} eq "y") {
658                         $chose_hiperf = 1;
659                 }
660         }
661         if ($has_ports) {
662                 yesno('USE_PORTS',"You are running Solaris 10.\nWould you like to enable I/O completion ports support?\nThis is likely to increase performance.\nIf you are unsure, answer yes.\n\nEnable support for I/O completion ports?");
663                 print "\n";
664                 if ($config{USE_PORTS} eq "y") {
665                         $chose_hiperf = 1;
666                 }
667         }
668
669         if (!$chose_hiperf) {
670                 yesno('USE_POLL', "Would you like to use poll?\n This is likely to increase performance.\nIf you are unsure, answer yes.\n\nEnable poll?\n");
671                 if ($config{USE_POLL} ne "y")
672                 {
673                         print "No high-performance socket engines are available, or you chose\n";
674                         print "not to enable one. Defaulting to select() engine.\n\n";
675                 }
676         }
677
678         yesno('IPV6',"Would you like to build InspIRCd with IPv6 support?");
679         print "\n";
680
681         if ($config{IPV6} eq "y") {
682                 print "You have chosen to build an \e[1;32mIPV6-enabled\e[0m server.\nTo accept IPV4 users, you can still use IPV4 addresses\nin your port bindings..\n\n";
683                 $config{SUPPORT_IP6LINKS} = "y";
684         } else {
685                 yesno('SUPPORT_IP6LINKS',"You have chosen to build an \e[1;32mIPV4-only\e[0m server.\nWould you like to enable support for linking to IPV6-enabled\nInspIRCd servers? If you are using a recent operating system and are\nunsure, answer yes. If you answer 'no' here, your InspIRCd server will\nbe unable to parse IPV6 addresses (e.g. for CIDR bans)\n\nEnable linking to servers which have IPV6 enabled?");
686                 print "\n";
687         }
688
689         $config{USE_FREEBSD_BASE_SSL} = "n";
690         $config{USE_FREEBSD_PORTS_SSL} = "n";
691         if ($config{HAS_OPENSSL_PORT} ne "")
692         {
693                 $config{USE_FREEBSD_PORTS_SSL} = "y";
694                 print "I have detected the OpenSSL FreeBSD port installed on your system,\n";
695                 print "version \e[1;32m".$config{HAS_OPENSSL_PORT}."\e[0m. Your base system OpenSSL is version \e[1;32m".$openssl_ver."\e[0m.\n\n";
696                 yesno('USE_FREEBSD_PORTS_SSL', "Do you want to use the FreeBSD ports version?");
697                 print "\n";
698                 $config{USE_FREEBSD_BASE_SSL} = "y" if ($config{USE_FREEBSD_PORTS_SSL} eq "n");
699
700                 if ($config{USE_FREEBSD_BASE_SSL} eq "n")
701                 {
702                         # update to port version
703                         $openssl_ver = $config{HAS_OPENSSL_PORT};
704                 }
705         }
706         else
707         {
708                 $config{USE_FREEBSD_BASE_SSL} = "y" if ($^O eq "freebsd");
709         }
710
711         $config{USE_SSL} = "n";
712
713         if ($config{HAS_GNUTLS} eq "y" || $config{HAS_OPENSSL} eq "y")
714         {
715                 print "Detected GnuTLS version: \e[1;32m" . $gnutls_ver . "\e[0m\n";
716                 print "Detected OpenSSL version: \e[1;32m" . $openssl_ver . "\e[0m\n\n";
717
718                 yesno('USE_SSL', "One or more SSL libraries detected. Would you like to enable SSL support?");
719                 if ($config{USE_SSL} eq "y")
720                 {
721                         if ($config{HAS_GNUTLS} eq "y")
722                         {
723                                 yesno('USE_GNUTLS',"Would you like to enable SSL with m_ssl_gnutls? (recommended)");
724                                 if ($config{USE_GNUTLS} eq "y")
725                                 {
726                                         print "\nUsing GnuTLS SSL module.\n";
727                                 }
728                         }
729
730                         if ($config{HAS_OPENSSL} eq "y")
731                         {
732                                 yesno('USE_OPENSSL', "Would you like to enable SSL with m_ssl_openssl?");
733                                 if ($config{USE_OPENSSL} eq "y")
734                                 {
735                                         print "\nUsing OpenSSL SSL module.\nYou will get better performance if you move to GnuTLS in the future.\n";
736                                 }
737                         }
738                 }
739         }
740         else
741         {
742                 print "\nCould not detect OpenSSL or GnuTLS. Make sure pkg-config is installed if\n";
743                 print "you intend to use OpenSSL, or that GnuTLS is in your path if you intend\nto use GnuTLS.\n\n";
744         }
745 }
746
747 dumphash();
748
749 if (($config{USE_GNUTLS} eq "y") && ($config{HAS_GNUTLS} ne "y"))
750 {
751         print "Sorry, but i couldn't detect gnutls. Make sure gnutls-config is in your path.\n";
752         exit(0);
753 }
754 if (($config{USE_OPENSSL} eq "y") && ($config{HAS_OPENSSL} ne "y"))
755 {
756         print "Sorry, but i couldn't detect openssl. Make sure openssl is in your path.\n";
757         exit(0);
758 }
759 our $failed = 0;
760
761 $config{CERTGEN} ||= 'y';
762 yesno('CERTGEN',"Would you like generate SSL certificates now?") if ($interactive && ($config{USE_GNUTLS} eq "y" || $config{USE_OPENSSL} eq "y"));
763
764 if ($config{USE_GNUTLS} eq "y") {
765         unless (-r "src/modules/m_ssl_gnutls.cpp") {
766                 print "Symlinking src/modules/m_ssl_gnutls.cpp from extra/\n";
767                 symlink "extra/m_ssl_gnutls.cpp", "src/modules/m_ssl_gnutls.cpp" or print STDERR "Symlink failed: $!";
768         }
769         if ($interactive && $config{CERTGEN} eq 'y')
770         {
771                 unless (-r "$config{CONFIG_DIR}/key.pem" && -r "$config{CONFIG_DIR}/cert.pem") {
772                         print "SSL Certificates Not found, Generating.. \n\n
773 *************************************************************
774 * Generating the Private Key may take some time, go grab a  *
775 * Coffee. Even better, to generate some more entropy if it  *
776 * is taking a while, open another console and type du / a   *
777 * few times and get that HD going :) Then answer the        *
778 * Questions which follow. If you are unsure, just hit enter *
779 *************************************************************\n\n";
780                         $failed = make_gnutls_cert();
781                         if ($failed) {
782                                 print "\n\e[1;32mCertificate generation failed!\e[0m\n\n";
783                         } else {
784                                 print "\nCertificate generation complete, copying to config directory... ";
785                                 File::Copy::move("key.pem", "$config{CONFIG_DIR}/key.pem") or print STDERR "Could not copy key.pem!\n";
786                                 File::Copy::move("cert.pem", "$config{CONFIG_DIR}/cert.pem") or print STDERR "Could not copy cert.pem!\n";
787                                 print "Done.\n\n";
788                         }
789                 }
790                 else {
791                         print "SSL Certificates found, skipping.\n\n";
792                 }
793         }
794         else
795         {
796                 print "Skipping SSL certificate generation\nin non-interactive mode.\n\n";
797         }
798 }
799
800 if ($config{USE_OPENSSL} eq "y") {
801         unless (-r "src/modules/m_ssl_openssl.cpp") {
802                 print "Symlinking src/modules/m_ssl_openssl.cpp from extra/\n";
803                 symlink "extra/m_ssl_openssl.cpp", "src/modules/m_ssl_openssl.cpp" or print STDERR "Symlink failed: $!";
804         }
805         $failed = 0;
806         if ($interactive && $config{CERTGEN} eq 'y')
807         {
808                 unless (-r "$config{CONFIG_DIR}/key.pem" && -r "$config{CONFIG_DIR}/cert.pem") {
809                         print "SSL Certificates Not found, Generating.. \n\n
810 *************************************************************
811 * Generating the certificates may take some time, go grab a *
812 * coffee, or something.                                     *
813 *************************************************************\n\n";
814                         make_openssl_cert();
815                         print "\nCertificate generation complete, copying to config directory... ";
816                         File::Copy::move("key.pem", "$config{CONFIG_DIR}/key.pem") or print STDERR "Could not copy key.pem!\n";
817                         File::Copy::move("cert.pem", "$config{CONFIG_DIR}/cert.pem") or print STDERR "Could not copy cert.pem!\n";
818                         File::Copy::move("dhparams.pem", "$config{CONFIG_DIR}/dhparams.pem") or print STDERR "Could not copy dhparams.pem!\n";
819                         print "Done.\n\n";
820                 } else {
821                         print "SSL Certificates found, skipping.\n\n"
822                 }
823         }
824         else
825         {
826                 print "Skipping SSL certificate generation\nin non-interactive mode.\n\n";
827         }
828 }
829 if (($config{USE_GNUTLS} eq "n") && ($config{USE_OPENSSL} eq "n")) {
830         print "Skipping SSL Certificate generation, SSL support is not available.\n\n";
831 }
832
833 getosflags();
834 writefiles(1);
835 makecache();
836
837 print "\n\n";
838 print "To build your server with these settings, please type '\e[1;32m$config{MAKEPROG}\e[0m' now.\n";
839 if (($config{USE_GNUTLS} eq "y") || ($config{USE_OPENSSL} eq "y")) {
840         print "Please note: for \e[1;32mSSL support\e[0m you will need to load required\n";
841         print "modules in your config. This configure script has added those modules to the\n";
842         print "build process. For more info please refer to:\n";
843         print "\e[1;32mhttp://wiki.inspircd.org/Installation_From_Tarball\e[0m\n";
844 }
845 print "*** \e[1;32mRemember to edit your configuration files!!!\e[0m ***\n\n\n";
846 if (($config{OSNAME} eq "OpenBSD") && ($config{CC} ne "eg++")) {
847         print "\e[1;32mWARNING!\e[0m You are running OpenBSD but you are using the base gcc package\nrather than eg++. This compile will most likely fail, but i'm letting you\ngo ahead with it anyway, just in case i'm wrong :-)\n";
848 }
849
850 if ($config{GCCVER} < "3") {
851         print <<FOO2;
852 \e[1;32mWARNING!\e[0m You are attempting to compile InspIRCd on GCC 2.x!
853 GCC 2.x series compilers only had partial (read as broken) C++ support, and
854 your compile will most likely fail horribly! If you have any problems, do NOT
855 report them to the bugtracker or forums without first upgrading your compiler
856 to a newer 3.x or 4.x (or whatever is available currently) version.
857 FOO2
858 }
859
860 ################################################################################
861 #                             HELPER FUNCTIONS                          #
862 ################################################################################
863 sub getcache {
864         # Retrieves the .config.cache file, and loads values into the main config hash.
865         open(CACHE, ".config.cache") or return 0;
866         while (<CACHE>) {
867                 chomp;
868                 # Ignore Blank lines, and comments..
869                 next if /^\s*$/;
870                 next if /^\s*#/;
871                 my ($key, $value) = split("=", $_, 2);
872                 $value =~ /^\"(.*)\"$/;
873                 # Do something with data here!
874                 $config{$key} = $1;
875         }
876         close(CACHE);
877         return 1;
878 }
879
880 sub makecache {
881         # Dump the contents of %config
882         print "Writing \e[1;32mcache file\e[0m for future ./configures ...\n";
883         open(FILEHANDLE, ">.config.cache");
884         foreach my $key (keys %config) {
885                 print FILEHANDLE "$key=\"$config{$key}\"\n";
886         }
887         close(FILEHANDLE);
888 }
889
890 sub dir_check {
891         my ($desc, $hash_key) = @_;
892         my $complete = 0;
893         while (!$complete) {
894                 print "In what directory $desc?\n";
895                 print "[\e[1;32m$config{$hash_key}\e[0m] -> ";
896                 chomp(my $var = <STDIN>);
897                 if ($var eq "") {
898                         $var = $config{$hash_key};
899                 }
900                 if ($var =~ /^\~\/(.+)$/) {
901                         # Convert it to a full path..
902                         $var = resolve_directory($ENV{HOME} . "/" . $1);
903                 }
904                 elsif ((($config{OSNAME} =~ /MINGW32/i) and ($var !~ /^[A-Z]{1}:\\.*/)) and (substr($var,0,1) ne "/"))
905                 {
906                         # Assume relative Path was given.. fill in the rest.
907                         $var = $this . "/$var";
908                 }
909
910                 $var = resolve_directory($var);
911                 if (! -e $var) {
912                         print "$var does not exist. Create it?\n[\e[1;32my\e[0m] ";
913                         chomp(my $tmp = <STDIN>);
914                         if (($tmp eq "") || ($tmp =~ /^y/i)) {
915                                 # Attempt to Create the Dir..
916                                 my $chk = eval {
917                                         use File::Path ();
918                                         File::Path::mkpath($var, 0, 0777);
919                                         1;
920                                 };
921                                 unless (defined($chk) && -d $var) {
922                                         print "Unable to create directory. ($var)\n\n";
923                                         # Restart Loop..
924                                         next;
925                                 }
926                         } else {
927                                 # They said they don't want to create, and we can't install there.
928                                 print "\n\n";
929                                 next;
930                         }
931                 } else {
932                         if (!is_dir($var)) {
933                                 # Target exists, but is not a directory.
934                                 print "File $var exists, but is not a directory.\n\n";
935                                 next;
936                         }
937                 }
938                 # Either Dir Exists, or was created fine.
939                 $config{$hash_key} = $var;
940                 $complete = 1;
941                 print "\n";
942         }
943 }
944
945 our $SHARED = "";
946
947 sub getosflags {
948
949         # Beware: Linux sets it's own cflags below for some retarded reason
950         $config{LDLIBS} = "-pthread -lstdc++";
951         $config{FLAGS}  = "-pipe -fPIC -Woverloaded-virtual -Wshadow -Wformat=2 -Wmissing-format-attribute -Wall $config{OPTIMISATI}";
952         $config{DEVELOPER} = "-pipe -fPIC -Woverloaded-virtual -Wshadow -Wall -Wformat=2 -Wmissing-format-attribute -g";
953         $SHARED = "-shared -export-dynamic";
954         $config{MAKEPROG} = "make";
955
956         if ($config{OSNAME} =~ /darwin/i) {
957                 $config{FLAGS}  = "-pipe -DDARWIN -frtti -fPIC -Wall $config{OPTIMISATI}";
958                 $SHARED = "-bundle -twolevel_namespace -undefined dynamic_lookup";
959                 $config{LDLIBS} = "-ldl -pthread -lstdc++";
960         }
961
962         if ($config{OSNAME} =~ /OpenBSD/i) {
963                 $config{MAKEPROG} = "gmake";
964 # apparantly (Dagonet says) that this causes problems, so let's try without it.
965 #               $config{LDLIBS} = $config{LDLIBS} . " -lunwind";
966                 chomp(my $foo = `eg++ -dumpversion | cut -c 1`);
967                 # theyre running the package version of gcc (eg++)... detect it and set up its version numbers.
968                 # if theyre not running this, configure lets the build continue but they probably wont manage to
969                 # compile as this standard version is 2.95.3!
970                 if ($foo ne "") {
971                         $config{CC} = "eg++";
972                         chomp($config{GCCVER}       = `eg++ -dumpversion | cut -c 1`); # we must redo these if we change the compiler path
973                         chomp($config{GCCMINOR}     = `eg++ -dumpversion | cut -c 3`);
974                 }
975                 return "OpenBSD";
976         }
977
978         if ($config{OSNAME} =~ /Linux/i) {
979                 $config{LDLIBS} = "-ldl -lstdc++ -pthread";
980 #               $config{FLAGS}  = "-fPIC -Woverloaded-virtual -Wshadow -Wall $config{OPTIMISATI}";
981                 $config{FLAGS}  .= " " . $ENV{CXXFLAGS} if exists($ENV{CXXFLAGS});
982                 $config{LDLIBS} .= " " . $ENV{LDLIBS} if exists($ENV{LDLIBS});
983                 $config{LDLIBS} .= " " . $ENV{LDFLAGS} if exists($ENV{LDFLAGS});
984                 $config{MAKEPROG} = "make";
985         }
986
987         if ($config{OSNAME} =~ /FreeBSD/i) {
988                 $config{FLAGS}  .= " " . $ENV{CXXFLAGS} if exists($ENV{CXXFLAGS});
989                 $config{LDLIBS} .= " " . $ENV{LDLIBS} if exists($ENV{LDLIBS});
990                 $config{LDLIBS} .= " " . $ENV{LDFLAGS} if exists($ENV{LDFLAGS});
991         }
992
993         if ($config{OSNAME} =~ /SunOS/i or $config{OSNAME} =~ /solaris/i)
994         {
995                 # solaris/sunos needs these
996                 # socket = bsd sockets api
997                 # nsl = dns stuff
998                 # rt = POSIX realtime extensions
999                 # resolv = inet_aton only (why isnt this in nsl?!)
1000                 $config{MAKEPROG} = "gmake";
1001                 $config{LDLIBS} .= " -lsocket -lnsl -lrt -lresolv -pthread";
1002                 return "Solaris";
1003         }
1004
1005         if($config{OSNAME} =~ /MINGW32/i)
1006         {
1007                 # All code is position-independent on windows
1008                 $config{FLAGS} =~ s/-fPIC //;
1009                 return "MinGW";
1010         }
1011
1012         return $config{OSNAME};
1013 }
1014
1015 my ($mliflags, $mfrules, $mobjs, $mfcount) = ("", "", "", 0);
1016
1017 sub writefiles {
1018         my($writeheader) = @_;
1019         # First File.. inspircd_config.h
1020         chomp(my $incos = `uname -n -s -r`);
1021         chomp(my $version = `sh src/version.sh`);
1022         chomp(my $revision2 = getrevision());
1023         if ($writeheader == 1)
1024         {
1025                 print "Writing \e[1;32minspircd_config.h\e[0m\n";
1026                 open(FILEHANDLE, ">include/inspircd_config.h.tmp");
1027                 print FILEHANDLE <<EOF;
1028 /* Auto generated by configure, do not modify! */
1029 #ifndef __CONFIGURATION_AUTO__
1030 #define __CONFIGURATION_AUTO__
1031
1032 /* this is for windows support. */
1033 #define CoreExport /**/
1034 #define DllExport /**/
1035
1036 #define CONFIG_FILE "$config{CONFIG_DIR}/inspircd.conf"
1037 #define MOD_PATH "$config{MODULE_DIR}"
1038 #define SOMAXCONN_S "$config{_SOMAXCONN}"
1039 #define OPTIMISATION $config{OPTIMITEMP}
1040 #define LIBRARYDIR "$config{LIBRARY_DIR}"
1041 #define ENTRYPOINT int main(int argc, char** argv)
1042
1043 EOF
1044 print FILEHANDLE "#define MAXBUF " . ($config{MAXBUF}+2) . "\n";
1045
1046                 if ($config{OSNAME} =~ /SunOS/i) {
1047                         print FILEHANDLE "#define IS_SOLARIS\n";
1048                 }
1049                 if ($config{OSNAME} =~ /MINGW32/i) {
1050                         print FILEHANDLE "#define IS_MINGW\n";
1051                 }
1052                 if ($config{GCCVER} >= 3) {
1053                         print FILEHANDLE "#define GCC3\n";
1054                 }
1055                 if (
1056                         (($config{GCCVER} == 4) && ($config{GCCMINOR} >= 3))
1057                                 ||
1058                         ($config{GCCVER} > 4)
1059                 ) {
1060                         print FILEHANDLE "#define HASHMAP_DEPRECATED\n";
1061                 }
1062                 if ($config{HAS_STRLCPY} eq "true") {
1063                         print FILEHANDLE "#define HAS_STRLCPY\n";
1064                 }
1065                 if ($config{HAS_STDINT} eq "true") {
1066                         print FILEHANDLE "#define HAS_STDINT\n";
1067                 }
1068                 if ($config{IPV6} =~ /y/i) {
1069                         print FILEHANDLE "#define IPV6\n";
1070                 }
1071                 if ($config{SUPPORT_IP6LINKS} =~ /y/i) {
1072                         print FILEHANDLE "#define SUPPORT_IP6LINKS\n";
1073                 }
1074                 if ($config{HAS_EVENTFD} eq 'true') {
1075                         print FILEHANDLE "#define HAS_EVENTFD\n";
1076                 }
1077                 my $use_hiperf = 0;
1078                 if (($has_kqueue) && ($config{USE_KQUEUE} eq "y")) {
1079                         print FILEHANDLE "#define USE_KQUEUE\n";
1080                         $config{SOCKETENGINE} = "socketengine_kqueue";
1081                         $use_hiperf = 1;
1082                 }
1083                 if (($has_epoll) && ($config{USE_EPOLL} eq "y")) {
1084                         print FILEHANDLE "#define USE_EPOLL\n";
1085                         $config{SOCKETENGINE} = "socketengine_epoll";
1086                         $use_hiperf = 1;
1087                 }
1088                 if (($has_ports) && ($config{USE_PORTS} eq "y")) {
1089                         print FILEHANDLE "#define USE_PORTS\n";
1090                         $config{SOCKETENGINE} = "socketengine_ports";
1091                         $use_hiperf = 1;
1092                 }
1093                 # user didn't choose either epoll or select for their OS.
1094                 # default them to USE_SELECT (ewwy puke puke)
1095                 if (!$use_hiperf) {
1096                         print "no hi-perf, " . $config{USE_POLL};
1097                         if ($config{USE_POLL} eq "y")
1098                         {
1099                                 print FILEHANDLE "#define USE_POLL\n";
1100                                 $config{SOCKETENGINE} = "socketengine_poll";
1101                         }
1102                         else
1103                         {
1104                                 print FILEHANDLE "#define USE_SELECT\n";
1105                                 $config{SOCKETENGINE} = "socketengine_select";
1106                         }
1107                 }
1108                 print FILEHANDLE "\n#include \"threadengines/threadengine_pthread.h\"\n\n#endif\n";
1109                 close(FILEHANDLE);
1110
1111                 open(FILEHANDLE, ">include/inspircd_se_config.h.tmp");
1112                 print FILEHANDLE <<EOF;
1113 /* Auto generated by configure, do not modify or commit to svn! */
1114 #ifndef __CONFIGURATION_SOCKETENGINE__
1115 #define __CONFIGURATION_SOCKETENGINE__
1116
1117 #include "socketengines/$config{SOCKETENGINE}.h"
1118
1119 #endif
1120 EOF
1121                 close(FILEHANDLE);
1122
1123                 open(FILEHANDLE, ">include/inspircd_version.h.tmp");
1124                 print FILEHANDLE <<EOF;
1125 #define VERSION "$version"
1126 #define REVISION "$revision2"
1127 #define SYSTEM "$incos"
1128 EOF
1129                 close FILEHANDLE;
1130
1131                 for my $file (qw(include/inspircd_config.h include/inspircd_se_config.h include/inspircd_version.h)) {
1132                         my $diff = 0;
1133                         open my $fh1, $file or $diff = 1;
1134                         open my $fh2, $file.'.tmp' or die "Can't read $file.tmp that we just wrote: $!";
1135                         while (!$diff) {
1136                                 my $line1 = <$fh1>;
1137                                 my $line2 = <$fh2>;
1138                                 if (defined($line1) != defined($line2)) {
1139                                         $diff = 1;
1140                                 } elsif (!defined $line1) {
1141                                         last;
1142                                 } else {
1143                                         $diff = ($line1 ne $line2);
1144                                 }
1145                         }
1146                         if ($diff) {
1147                                 unlink $file;
1148                                 rename "$file.tmp", $file;
1149                         } else {
1150                                 unlink "$file.tmp";
1151                         }
1152                 }
1153         }
1154
1155         # Write all .in files.
1156         my $tmp = "";
1157         my $file = "";
1158         my $exe = "inspircd";
1159
1160         # Do this once here, and cache it in the .*.inc files,
1161         # rather than attempting to read src/version.sh from
1162         # compiled code -- we might not have the source to hand.
1163         # Fix for bug#177 by Brain.
1164
1165         chomp($version = `sh ./src/version.sh`);
1166         chomp(my $revision = getrevision());
1167         $version = "$version(r$revision)";
1168
1169         # We can actually parse any file starting with . and ending with .inc,
1170         # but right now we only parse .inspircd.inc to form './inspircd'
1171         prepare_dynamic_makefile();
1172
1173     print "Writing \e[1;32mMakefiles\e[0m\n";
1174
1175         opendir(DIRHANDLE, $this);
1176
1177         foreach my $name (sort readdir(DIRHANDLE)) {
1178                 if ($name =~ /^\.(.+)\.inc$/) {
1179                         $file = $1;
1180
1181                         # Bug #353, omit this on non-darwin
1182                         next if (($config{OSNAME} !~ /darwin/) && ($file eq "org.inspircd.plist"));
1183
1184                         # All .name.inc files need parsing!
1185                         open(FILEHANDLE, ".$file.inc") or die ("Can't open .$file.inc");
1186                         $_ = join '', <FILEHANDLE>;
1187                         close(FILEHANDLE);
1188
1189                         print "Writing \e[1;32m$file\e[0m ...\n";
1190                         for my $var (qw(
1191                                 CC FLAGS DEVELOPER LDLIBS BASE_DIR CONFIG_DIR MODULE_DIR BINARY_DIR LIBRARY_DIR
1192                                 STARTSCRIPT DESTINATION EXTRA_DIR SOCKETENGINE CORE_FLAGS
1193                         )) {
1194                                 s/\@$var\@/$config{$var}/g;
1195                         }
1196                         s/\@EXECUTABLE\@/$exe/ if defined $exe;
1197                         s/\@VERSION\@/$version/ if defined $version;
1198
1199                         if ($file eq 'Makefile') {
1200                                 my $mk_tmp = $_;
1201                                 s/\@IFDEF (\S+)/ifdef $1/g;
1202                                 s/\@IFNDEF (\S+)/ifndef $1/g;
1203                                 s/\@ELSE/else/g;
1204                                 s/\@ENDIF/endif/g;
1205                                 s/ *\@BSD_ONLY .*\n//g;
1206                                 s/\@GNU_ONLY //g;
1207                                 s/\@DO_EXPORT (.*)/export $1/g;
1208                                 open MKF, '>GNUmakefile' or die "Can't write to GNUmakefile: $!";
1209                                 print MKF $_;
1210                                 close MKF;
1211                                 $_ = $mk_tmp;
1212                                 s/\@IFDEF (\S+)/.if defined($1)/g;
1213                                 s/\@IFNDEF (\S+)/.if !defined($1)/g;
1214                                 s/\@ELSE/.else/g;
1215                                 s/\@ENDIF/.endif/g;
1216                                 s/\@BSD_ONLY //g;
1217                                 s/ *\@GNU_ONLY .*\n//g;
1218                                 $mk_tmp = $_;
1219                                 $mk_tmp =~ s#\@DO_EXPORT (.*)#"MAKEENV += ".join ' ', map "$_='\${$_}'", split /\s/, $1#eg;
1220                                 open MKF, '>BSDmakefile' or die "Can't write to BSDmakefile: $!";
1221                                 print MKF $mk_tmp;
1222                                 close MKF;
1223                         } else {
1224                                 open(FILEHANDLE, ">$file") or die("Can't write to $file: $!\n");
1225                                 print FILEHANDLE $_;
1226                                 close(FILEHANDLE);
1227                         }
1228                 }
1229         }
1230         closedir(DIRHANDLE);
1231
1232         # Make inspircd executable!
1233         chmod 0744, 'inspircd';
1234 }
1235
1236 sub prepare_dynamic_makefile
1237 {
1238         my $i = 0;
1239
1240         if (!$has_epoll)
1241         {
1242                 $config{USE_EPOLL} = 0;
1243         }
1244         if (!$has_kqueue)
1245         {
1246                 $config{USE_KQUEUE} = 0;
1247         }
1248         if (!$has_ports)
1249         {
1250                 $config{USE_PORTS} = 0;
1251         }
1252
1253         if ($config{IS_DARWIN} eq "YES")
1254         {
1255                 $config{CORE_FLAGS} = '-dynamic -bind_at_load -L.';
1256         }
1257         else
1258         {
1259                 $config{CORE_FLAGS} = (defined $config{CRAQ} ? $config{CRAQ}. ' ' : "").'-rdynamic -L.'
1260         }
1261 }
1262
1263 # Routine to list out the extra/ modules that have been enabled.
1264 # Note: when getting any filenames out and comparing, it's important to lc it if the
1265 # file system is not case-sensitive (== Epoc, MacOS, OS/2 (incl DOS/DJGPP), VMS, Win32
1266 # (incl NetWare, Symbian)). Cygwin may or may not be case-sensitive, depending on
1267 # configuration, however, File::Spec does not currently tell us (it assumes Unix behavior).
1268 sub list_extras () {
1269         use File::Spec;
1270         # @_ not used
1271         my $srcdir = File::Spec->catdir("src", "modules");
1272         my $abs_srcdir = File::Spec->rel2abs($srcdir);
1273         local $_;
1274         my $dd;
1275         opendir $dd, File::Spec->catdir($abs_srcdir, "extra") or die (File::Spec->catdir($abs_srcdir, "extra") . ": $!\n");
1276         my @extras = map { File::Spec->case_tolerant() ? lc($_) : $_ } (readdir($dd));
1277         closedir $dd;
1278         undef $dd;
1279         opendir $dd, $abs_srcdir or die "$abs_srcdir: $!\n";
1280         my @sources = map { File::Spec->case_tolerant() ? lc($_) : $_ } (readdir($dd));
1281         closedir $dd;
1282         undef $dd;
1283         my $maxlen = (sort { $b <=> $a } (map {length($_)} (@extras)))[0];
1284         my %extras = ();
1285 EXTRA:  for my $extra (@extras) {
1286                 next if (File::Spec->curdir() eq $extra || File::Spec->updir() eq $extra);
1287                 next if ($extra eq '.svn');
1288                 my $abs_extra = File::Spec->catfile($abs_srcdir, "extra", $extra);
1289                 my $abs_source = File::Spec->catfile($abs_srcdir, $extra);
1290                 next unless ($extra =~ m/\.(cpp|h)$/ || (-d $abs_extra)); # C++ Source/Header, or directory
1291                 if (-l $abs_source) {
1292                         # Symlink, is it in the right place?
1293                         my $targ = readlink($abs_source);
1294                         my $abs_targ = File::Spec->rel2abs($targ, $abs_srcdir);
1295                         if ($abs_targ eq $abs_extra) {
1296                                 $extras{$extra} = "\e[32;1menabled\e[0m";
1297                         } else {
1298                                 $extras{$extra} = sprintf("\e[31;1mwrong symlink target (%s)\e[0m", $abs_targ);
1299                         }
1300                 } elsif (-e $abs_source) {
1301                         my ($devext, $inoext) = stat($abs_extra);
1302                         my ($devsrc, $inosrc, undef, $lnksrc) = stat($abs_source);
1303                         if ($lnksrc > 1) {
1304                                 if ($devsrc == $devext && $inosrc == $inoext) {
1305                                         $extras{$extra} = "\e[32;1menabled\e[0m";
1306                                 } else {
1307                                         $extras{$extra} = sprintf("\e[31;1mwrong hardlink target (%d:%d)\e[0m", $devsrc, $inosrc);
1308                                 }
1309                         } else {
1310                                 open my $extfd, "<", $abs_extra;
1311                                 open my $srcfd, "<", $abs_source;
1312                                 local $/ = undef;
1313                                 if (scalar(<$extfd>) eq scalar(<$srcfd>)) {
1314                                         $extras{$extra} = "\e[32;1menabled\e[0m";
1315                                 } else {
1316                                         $extras{$extra} = sprintf("\e[31;1mout of synch (re-copy)\e[0m");
1317                                 }
1318                         }
1319                 } else {
1320                         $extras{$extra} = "\e[33;1mdisabled\e[0m";
1321                 }
1322         }
1323         # Now let's add dependency info
1324         for my $extra (keys(%extras)) {
1325                 next unless $extras{$extra} =~ m/enabled/; # only process enabled extras.
1326                 my $abs_extra = File::Spec->catfile($abs_srcdir, "extra", $extra);
1327                 my @deps = split / +/, getdependencies($abs_extra);
1328                 for my $dep (@deps) {
1329                         if (exists($extras{$dep})) {
1330                                 my $ref = \$extras{$dep}; # Take reference.
1331                                 if ($$ref !~ m/needed by/) {
1332                                         # First dependency found.
1333                                         if ($$ref =~ m/enabled/) {
1334                                                 $$ref .= " (needed by \e[32;1m$extra\e[0m";
1335                                         } else {
1336                                                 $$ref =~ s/\e\[.*?m//g; # Strip out previous coloring. Will be set in bold+red+blink later.
1337                                                 $$ref .= " (needed by \e[0;32;1;5m$extra\e[0;31;1;5m";
1338                                         }
1339                                 } else {
1340                                         if ($$ref =~ m/enabled/) {
1341                                                 $$ref .= ", \e[32;1m$extra\e[0m";
1342                                         } else {
1343                                                 $$ref .= ", \e[0;32;1;5m$extra\e[0;31;1;5m";
1344                                         }
1345                                 }
1346                         }
1347                 }
1348         }
1349         for my $extra (sort {$a cmp $b} keys(%extras)) {
1350                 my $text = $extras{$extra};
1351                 if ($text =~ m/needed by/ && $text !~ m/enabled/) {
1352                         printf "\e[31;1;5m%-*s = %s%s\e[0m\n", $maxlen, $extra, $text, ($text =~ m/needed by/ ? ")" : "");
1353                 } else {
1354                         printf "%-*s = %s%s\n", $maxlen, $extra, $text, ($text =~ m/needed by/ ? "\e[0m)" : "");
1355                 }
1356         }
1357         return keys(%extras) if wantarray; # Can be used by manage_extras.
1358 }
1359
1360 sub enable_extras (@) {
1361         my (@extras) = @_;
1362         for my $extra (@extras) {
1363                 my $extrapath = "src/modules/extra/$extra";
1364                 if (!-e $extrapath) {
1365                         print STDERR "Cannot enable \e[32;1m$extra\e[0m : No such file or directory in src/modules/extra\n";
1366                         next;
1367                 }
1368                 my $source = "src/modules/$extra";
1369                 if (-e $source) {
1370                         print STDERR "Cannot enable \e[32;1m$extra\e[0m : destination in src/modules exists (might already be enabled?)\n";
1371                         next;
1372                 }
1373                 # Get dependencies, and add them to be processed.
1374                 my @deps = split / +/, getdependencies($extrapath);
1375                 for my $dep (@deps) {
1376                         next if scalar(grep { $_ eq $dep } (@extras)) > 0; # Skip if we're going to be enabling it anyway.
1377                         if (!-e "src/modules/$dep") {
1378                                 if (-e "src/modules/extra/$dep") {
1379                                         print STDERR "Will also enable extra \e[32;1m$dep\e[0m (needed by \e[32;1m$extra\e[0m)\n";
1380                                         push @extras, $dep;
1381                                 } else {
1382                                         print STDERR "\e[33;1mWARNING:\e[0m module \e[32;1m$extra\e[0m might be missing dependency \e[32;1m$dep\e[0m - YOU are responsible for satisfying it!\n";
1383                                 }
1384                         }
1385                 }
1386                 print "Enabling $extra ... \n";
1387                 symlink "extra/$extra", $source or print STDERR "$source: Cannot link to 'extra/$extra': $!\n";
1388         }
1389 }
1390
1391 sub disable_extras (@)
1392 {
1393         opendir my $dd, "src/modules/extra/";
1394         my @files = readdir($dd);
1395         closedir $dd;
1396         my (@extras) = @_;
1397 EXTRA:  for my $extra (@extras) {
1398                 my $extrapath = "src/modules/extra/$extra";
1399                 my $source = "src/modules/$extra";
1400                 if (!-e $extrapath) {
1401                         print STDERR "Cannot disable \e[32;1m$extra\e[0m : Is not an extra\n";
1402                         next;
1403                 }
1404                 if ((! -l $source) || readlink($source) ne "extra/$extra") {
1405                         print STDERR "Cannot disable \e[32;1m$extra\e[0m : Source is not a link or doesn't refer to the right file. Remove manually if this is in error.\n";
1406                         next;
1407                 }
1408                 # Check if anything needs this.
1409                 for my $file (@files) {
1410                         my @deps = split / +/, getdependencies("src/modules/extra/$file");
1411                         # File depends on this extra...
1412                         if (scalar(grep { $_ eq $extra } @deps) > 0) {
1413                                 # And is both enabled and not about to be disabled.
1414                                 if (-e "src/modules/$file" && scalar(grep { $_ eq $file } @extras) < 1) {
1415                                         print STDERR "Cannot disable \e[32;1m$extra\e[0m : is needed by \e[32;1m$file\e[0m\n";
1416                                         next EXTRA;
1417                                 }
1418                         }
1419                 }
1420                 # Now remove.
1421                 print "Disabling $extra ... \n";
1422                 unlink "src/modules/$extra" or print STDERR "Cannot disable \e[32;1m$extra\e[0m : $!\n";
1423         }
1424 }