]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - configure
change startup type from SERVICE_DEMAND_START to SERVICE_AUTO_START so that inspircd...
[user/henk/code/inspircd.git] / configure
1 #!/usr/bin/perl
2 ###################################################
3 # InspIRCd Configuration Script
4 #
5 # Copyright 2002-2008 The InspIRCd Development Team
6 #  http://www.inspircd.org/wiki/index.php/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
30 use Socket;
31 use Cwd;
32 use Getopt::Long;
33
34 # Utility functions for our buildsystem
35 use make::utilities;
36 use make::configure;
37 use make::gnutlscert;
38 use make::opensslcert;
39
40 ###############################################################################################
41 #
42 #                                   EDITABLE VARIABLES
43 #
44 ###############################################################################################
45
46 # If you wish to ignore a dependency throughout the entire core, add it here.
47
48 our @ignoredeps = (
49         "inspircd_win32wrapper.h",      # windows has its own configure program
50 );
51
52 # If you wish for all files in the entire core to have a given dependency, insert it here.
53 # You should keep this to an absolute minimum to avoid rebuilds that are not neccessary.
54
55 our @immutabledeps = (
56         "inspircd_config.h",            # auto re-generated by configure
57         "inspircd.h",
58 );
59
60 ###############################################################################################
61 #
62 #                                 NON-EDITABLE VARIABLES
63 #
64 ###############################################################################################
65
66 # List of commands that make up 'make install' and 'make deinstall'
67
68 our $install_list = "";
69 our $uninstall_list = "";
70
71 # This is a list of all files in the core. Each cpp file is mapped to a shared object file,
72 # whos file extension is omitted (these can vary from system to system). Auto detected by
73 # scanning the src/*.cpp files for files containing /* $Core */ identifiers.
74
75 our %filelist = ();
76
77 # If you wish for a file to have special dependencies in the makefile, add an entry here.
78 # Auto populated by /* $ExtraDeps: */ instruction
79
80 our %specialdeps = ();
81
82 # If you wish for a file to have extra make lines (in between the compile and link steps)
83 # then insert them here.
84 # Auto populated by /* $ExtraBuild: */ instruction
85         
86 our %extrabuildlines = ();
87
88 # If you wish for a file to be linked against extra objects or arctives, insert them here.
89 # Auto populated by /* $ExtraObjects: */ instruction
90
91 our %extraobjects = ();
92
93 # If you wish to compile extra cpp sources into an object, define them here.
94 # NOTE: Certain cpp files such as the socket engines have a value auto calculated
95 # for this table so that their derived class is built.
96 # Auto populated by /* $ExtraSources: */ instruction
97
98 our %extrasources = ();
99
100 our ($opt_use_gnutls, $opt_rebuild, $opt_use_openssl, $opt_nointeractive, $opt_ports,
101     $opt_epoll, $opt_kqueue, $opt_noports, $opt_noepoll, $opt_nokqueue,
102     $opt_ipv6, $opt_ipv6links, $opt_noipv6links, $opt_maxbuf, $opt_disable_debug,
103     $opt_freebsd_port);
104
105 our ($opt_cc, $opt_base_dir, $opt_config_dir, $opt_module_dir, $opt_binary_dir,
106     $opt_library_dir);
107
108 sub list_extras ();
109
110 sub enable_extras (@);
111
112 sub disable_extras (@);
113
114 my @opt_enableextras;
115 my @opt_disableextras;
116
117 GetOptions (
118         'enable-gnutls' => \$opt_use_gnutls,
119         'rebuild' => \$opt_rebuild,
120         'enable-openssl' => \$opt_use_openssl,
121         'disable-interactive' => \$opt_nointeractive,
122         'enable-ports' => \$opt_ports,
123         'enable-epoll' => \$opt_epoll,
124         'enable-kqueue' => \$opt_kqueue,
125         'disable-ports' => \$opt_noports,
126         'disable-epoll' => \$opt_noepoll,
127         'disable-kqueue' => \$opt_nokqueue,
128         'enable-ipv6' => \$opt_ipv6,
129         'enable-remote-ipv6' => \$opt_ipv6links,
130         'disable-remote-ipv6' => \$opt_noipv6links,
131         'with-cc=s' => \$opt_cc,
132         'with-maxbuf=i' => \$opt_maxbuf,
133         'enable-freebsd-ports-openssl' => \$opt_freebsd_port,
134         'prefix=s' => \$opt_base_dir,
135         'config-dir=s' => \$opt_config_dir,
136         'module-dir=s' => \$opt_module_dir,
137         'binary-dir=s' => \$opt_binary_dir,
138         'library-dir=s' => \$opt_library_dir,
139         'disable-debuginfo' => sub { $opt_disable_debug = 1 },
140         'help'  => sub { showhelp(); },
141         'modupdate' => sub { modupdate(); },
142         'update' => sub { update(); },
143         'svnupdate' => sub { svnupdate(); },
144         'clean' => sub { clean(); },
145         'list-extras' => sub { list_extras; exit 0; }, # This, --enable-extras, and --disable-extras are for non-interactive managing.
146         'enable-extras=s@' => \@opt_enableextras, # ^
147         'disable-extras=s@' => \@opt_disableextras, # ^
148 );
149
150 if (scalar(@opt_enableextras) + scalar(@opt_disableextras) > 0) {
151         @opt_enableextras = split /,/, join(',', @opt_enableextras);
152         @opt_disableextras = split /,/, join(',', @opt_disableextras);
153         enable_extras(@opt_enableextras);
154         disable_extras(@opt_disableextras);
155         list_extras;
156         print "Remember: YOU are responsible for making sure any libraries needed have been installed!\n";
157         print "Run $0 -modupdate after you've done this to update the makefiles.\n";
158         exit 0;
159 }
160
161 our $non_interactive = (
162         (defined $opt_library_dir) ||
163         (defined $opt_base_dir) ||
164         (defined $opt_config_dir) ||
165         (defined $opt_module_dir) ||
166         (defined $opt_base_dir) ||
167         (defined $opt_binary_dir) ||
168         (defined $opt_nointeractive) ||
169         (defined $opt_cc) ||
170         (defined $opt_ipv6) ||
171         (defined $opt_ipv6links) ||
172         (defined $opt_noipv6links) ||
173         (defined $opt_kqueue) ||
174         (defined $opt_epoll) ||
175         (defined $opt_ports) ||
176         (defined $opt_use_openssl) ||
177         (defined $opt_nokqueue) ||
178         (defined $opt_noepoll) ||
179         (defined $opt_noports) ||
180         (defined $opt_maxbuf) ||
181         (defined $opt_use_gnutls) ||
182         (defined $opt_freebsd_port)
183 );
184 our $interactive = !$non_interactive;
185
186 chomp(our $topdir = getcwd());
187 our $this = resolve_directory($topdir);                                         # PWD, Regardless.
188 our @modlist = ();                                                                      # Declare for Module List..
189 our %config = ();                                                                       # Initiate Configuration Hash..
190 $config{ME}              = resolve_directory($topdir);                          # Present Working Directory
191
192 $config{BASE_DIR}          = $config{ME};
193
194 if (defined $opt_base_dir)
195 {
196         $config{BASE_DIR} = $opt_base_dir;
197 }
198
199 $config{CONFIG_DIR}      = resolve_directory($config{BASE_DIR}."/conf");        # Configuration Directory
200 $config{MODULE_DIR}      = resolve_directory($config{BASE_DIR}."/modules");     # Modules Directory
201 $config{BINARY_DIR}      = resolve_directory($config{BASE_DIR}."/bin");         # Binary Directory
202 $config{LIBRARY_DIR}    = resolve_directory($config{BASE_DIR}."/lib");          # Library Directory
203
204 if (defined $opt_config_dir)
205 {
206         $config{CONFIG_DIR} = $opt_config_dir;
207 }
208 if (defined $opt_module_dir)
209 {
210         $config{MODULE_DIR} = $opt_module_dir;
211 }
212 if (defined $opt_binary_dir)
213 {
214         $config{BINARY_DIR} = $opt_binary_dir;
215 }
216 if (defined $opt_library_dir)
217 {
218         $config{LIBRARY_DIR} = $opt_library_dir;
219 }
220 chomp($config{HAS_GNUTLS}   = `libgnutls-config --version 2>/dev/null | cut -c 1,2,3`); # GNUTLS Version.
221
222 if (defined $opt_freebsd_port)
223 {
224         chomp($config{HAS_OPENSSL} = `pkg-config --modversion openssl 2>/dev/null`);
225         chomp($config{HAS_OPENSSL_PORT}  = `pkg-config --modversion openssl 2>/dev/null`);
226         $config{USE_FREEBSD_BASE_SSL} = "n";
227 }
228 else
229 {
230         if ($^O eq "freebsd")
231         {
232                 # default: use base ssl
233                 chomp($config{HAS_OPENSSL} = `openssl version | cut -d ' ' -f 2`);                      # OpenSSL version, freebsd specific
234                 chomp($config{HAS_OPENSSL_PORT}  = `pkg-config --modversion openssl 2>/dev/null`);      # Port version, may be different
235         }
236         else
237         {
238                 chomp($config{HAS_OPENSSL}  = `pkg-config --modversion openssl 2>/dev/null`);           # Openssl version, others
239                 $config{HAS_OPENSSL_PORT} = "";
240         }
241 }
242
243 chomp(our $gnutls_ver = $config{HAS_GNUTLS});
244 chomp(our $openssl_ver = $config{HAS_OPENSSL});
245 $config{USE_GNUTLS}         = "n";
246 if (defined $opt_use_gnutls)
247 {
248         $config{USE_GNUTLS} = "y";                                      # Use gnutls.
249 }
250 $config{USE_OPENSSL}    = "n";                                          # Use openssl.
251 if (defined $opt_use_openssl)
252 {
253         $config{USE_OPENSSL} = "y";
254 }
255
256 # no, let's not change these.
257 $config{OPTIMITEMP}      = "0";                                         # Default Optimisation Value
258 if (!defined $opt_disable_debug)
259 {
260         $config{OPTIMISATI}      = "-g1";                               # Optimisation Flag
261 }
262 else
263 {
264         $config{OPTIMISATI}      = "-O2";                               # DEBUGGING OFF!
265 }
266
267 $config{HAS_STRLCPY}    = "false";                                      # strlcpy Check.
268 $config{HAS_STDINT}      = "false";                                     # stdint.h check
269 $config{USE_KQUEUE}      = "y";                                         # kqueue enabled
270 if (defined $opt_kqueue)
271 {
272         $config{USE_KQUEUE} = "y";
273 }
274 if (defined $opt_nokqueue)
275 {
276         $config{USE_KQUEUE} = "n";
277 }
278 $config{USE_EPOLL}        = "y";                                        # epoll enabled
279 if (defined $opt_epoll)
280 {
281         $config{USE_EPOLL} = "y";
282 }
283 if (defined $opt_noepoll)
284 {
285         $config{USE_EPOLL} = "n";
286 }
287 $config{USE_PORTS}        = "y";                                        # epoll enabled
288 if (defined $opt_ports)
289 {
290         $config{USE_PORTS} = "y";
291 }
292 if (defined $opt_noports)
293 {
294         $config{USE_PORTS} = "n";
295 }
296 $config{IPV6}          = "n";                                           # IPv6 support (experimental)
297 if (defined $opt_ipv6)
298 {
299         $config{IPV6} = "y";
300 }
301 $config{SUPPORT_IP6LINKS}   = "y";                                      # IPv4 supporting IPv6 links (experimental)
302 if (defined $opt_ipv6links)
303 {
304         $config{SUPPORT_IP6LINKS} = "y";
305 }
306 if (defined $opt_noipv6links)
307 {
308         $config{SUPPORT_IP6LINKS} = "n";
309 }
310 chomp($config{GCCVER}       = `g++ -dumpversion | cut -c 1`);           # Major GCC Version
311 chomp($config{GCCMINOR}     = `g++ -dumpversion | cut -c 3`);
312 $config{_SOMAXCONN} = SOMAXCONN;                                        # Max connections in accept queue
313 $config{OSNAME}             = $^O;                                      # Operating System Name
314 $config{IS_DARWIN}        = "NO";                                       # Is OSX?
315 $config{STARTSCRIPT}      = "inspircd";                 # start script?
316 $config{DESTINATION}      = "BASE";                             # Is target path.
317 $config{EXTRA_DIR}        = "";                                         # Is empty.
318 if ($config{OSNAME} =~ /darwin/i)
319 {
320         $config{IS_DARWIN} = "YES";
321         $config{STARTSCRIPT}      = "org.inspircd.plist";               # start script for OSX.
322         $config{DESTINATION}      = "LAUNCHDPATH";                              # Is OSX target.
323         $config{EXTRA_DIR}          = " launchd_dir";                           # Is OSX specific path.
324 }
325 $config{CC}                 = "g++";                                            # C++ compiler
326 if (defined $opt_cc)
327 {
328         $config{CC} = $opt_cc;
329 }
330 our $exec = $config{CC} . " -dumpversion | cut -c 1";
331 chomp($config{GCCVER}           = `$exec`);                             # Major GCC Version
332 $exec = $config{CC} . " -dumpversion | cut -c 3";
333 chomp($config{GCCMINOR}         = `$exec`);
334 $config{MAKEORDER}              = "ircd mods";                          # build order
335 $config{MAXBUF}                 = "512";                                # Max buffer size
336
337 if ($config{HAS_OPENSSL} =~ /^([-[:digit:].]+)([a-z])?(\-[a-z][0-9])?$/) {
338         $config{HAS_OPENSSL} = $1;
339 } else {
340         $config{HAS_OPENSSL} = "";
341 }
342
343 if (($config{GCCVER} eq "") || ($config{GCCMINOR} eq "")) {
344         print $config{CC} . " was not found! You require g++ (the GNU C++ compiler, part of GCC) to build InspIRCd!\n";
345         exit;
346 }
347
348 # Get and Set some important vars..
349 getmodules();
350
351 sub clean
352 {
353         unlink(".config.cache");
354 }
355
356 our ($has_epoll, $has_ports, $has_kqueue) = (0, 0, 0);
357
358 sub update
359 {
360         eval {
361                 chomp($topdir = getcwd());
362                 $this = resolve_directory($topdir);                                          # PWD, Regardless.
363                 getmodules();
364                 # Does the cache file exist?
365                 if (!getcache()) {
366                         # No, No it doesn't.. *BASH*
367                         print "You have not run ./configure before. Please do this before trying to run the update script.\n";
368                         exit 0;
369                 } else {
370                         # We've Loaded the cache file and all our variables..
371                         print "Updating files...\n";
372                         getosflags();
373                         if (defined($opt_disable_debug) && $opt_disable_debug == 1)
374                         {
375                                 print "Disabling debug information (-g).\n";
376                                 $config{OPTIMISATI} = "";
377                                 getosflags();
378                         }
379                         $has_epoll = $config{HAS_EPOLL};
380                         $has_ports = $config{HAS_PORTS};
381                         $has_kqueue = $config{HAS_KQUEUE};
382                         writefiles(1);
383                         makecache();
384                         print "Complete.\n";
385                         exit;
386                 }
387         };
388         if ($@)
389         {
390                 print "Configure update failed: $@\n";
391         }
392         exit;
393 }
394
395 sub modupdate
396 {
397         eval {
398                 chomp($topdir = getcwd());
399                 $this = resolve_directory($topdir);                                          # PWD, Regardless.
400                 getmodules();
401                 # Does the cache file exist?
402                 if (!getcache()) {
403                         # No, No it doesn't.. *BASH*
404                         print "You have not run ./configure before. Please do this before trying to run the update script.\n";
405                         exit 0;
406                 } else {
407                         # We've Loaded the cache file and all our variables..
408                         print "Updating files...\n";
409                         getosflags();
410                         $has_epoll = $config{HAS_EPOLL};
411                         $has_ports = $config{HAS_PORTS};
412                         $has_kqueue = $config{HAS_KQUEUE};
413                         writefiles(0);
414                         makecache();
415                         print "Complete.\n";
416                         exit;
417                 }
418         };
419         if ($@)
420         {
421                 print "Module update failed: $@\n";
422         }
423         exit;
424 }
425
426
427
428 sub svnupdate
429 {
430         my $fail = 0;
431         open(FH,"<.svn/entries") or $fail = 1;
432         if ($fail) {
433                 print "This is not an SVN copy of InspIRCd.\n";
434                 exit 1;
435         }
436         else
437         {
438                 close(FH);
439         }
440         open my $fd, "-|", "svn update";
441         my $configurechanged = 0; # Needs ./configure -update
442         my $coredirchanged = 0; # Needs ./configure -update
443         my $moduledirchanged = 0; # Needs ./configure -modupdate
444         my $rootincchanged = 0;
445         my @conflicted = ();
446         while (defined(my $line = <$fd>))
447         {
448                 my ($action, $file);
449                 print $line;
450                 $line =~ m/^([ADUCG])\s+(.*)$/ or next;
451                 ($action, $file) = ($1, $2);
452                 if ($action eq "C")
453                 {
454                         push @conflicted, $file;
455                         if ($file eq "configure")
456                         {
457                                 $configurechanged = 1;
458                         }
459                         elsif ($file =~ m#^src/modules#)
460                         {
461                                 $moduledirchanged = 1;
462                         }
463                         elsif ($file =~ m#^src/#)
464                         {
465                                 $coredirchanged = 1;
466                         }
467                         elsif ($file =~ m/^\..*\.inc$/)
468                         {
469                                 $rootincchanged = 1;
470                         }
471                 }
472                 elsif ($action eq "U" || $action eq "G")
473                 {
474                         if ($file eq "configure")
475                         {
476                                 $configurechanged = 1;
477                         }
478                         elsif ($file =~ m/^\..*\.inc$/)
479                         {
480                                 $rootincchanged = 1;
481                         }
482                 }
483                 elsif ($action eq "A" || $action eq "D")
484                 {
485                         if ($file =~ m#^src/modules#)
486                         {
487                                 $moduledirchanged = 1;
488                         }
489                         elsif ($file =~ m#^src/#)
490                         {
491                                 $coredirchanged = 1;
492                         }
493                 }
494         }
495         unless (close $fd) # close() waits for exit and returns false if the command failed
496         {
497                 if ($! == 0)
498                 {
499                         print STDERR "Problem updating from SVN, please check above for errors\n";
500                 }
501                 else
502                 {
503                         print STDERR "Failed to run SVN: $!\n";
504                 }
505                 exit 1;
506         }
507         if (scalar(@conflicted) > 0)
508         {
509                 print STDERR "\e[0;33;1mERROR:\e[0m You have local modifications which conflicted with the updates from SVN\n";
510                 printf STDERR "Configure is not able to complete the update. Please resolve these conflicts, then run ./configure -%supdate\n", (($coredirchanged || $configurechanged) ? "" : "mod");
511                 print "Conflicted files: " . join ", ", @conflicted . "\n";
512                 exit 1;
513         }
514         if ($configurechanged || $coredirchanged)
515         {
516                 system("perl configure -update");
517         }
518         elsif ($moduledirchanged || $rootincchanged)
519         {
520                 system("perl configure -modupdate");
521         }
522         else
523         {
524                 print "No need to update Makefiles.\n";
525         }
526         if (defined $opt_rebuild) {
527                 system("make install");
528         }
529         exit;
530 }
531
532 print "Running non-interactive configure...\n" unless $interactive;
533 print "Checking for cache from previous configure... ";
534 print ((!getcache()) ? "not found\n" : "found\n");
535 print "Checking operating system version... ";
536 print getosflags() . "\n";
537
538 printf "Checking if stdint.h exists... ";
539 $config{HAS_STDINT} = "true";
540 our $fail = 0;
541 open(STDINT, "</usr/include/stdint.h") or $config{HAS_STDINT} = "false";
542 if ($config{HAS_STDINT} eq "true") {
543         close(STDINT);
544 }
545 print "yes\n" if $config{HAS_STDINT} eq "true";
546 print "no\n" if $config{HAS_STDINT} eq "false";
547
548 printf "Checking if strlcpy exists... ";
549 # Perform the strlcpy() test..
550 $config{HAS_STRLCPY} = "false";
551 $fail = 0;
552 open(STRLCPY, "</usr/include/string.h") or $fail = 1;
553 if (!$fail) {
554         while (defined(my $line = <STRLCPY>)) {
555                 chomp($line);
556                 # try and find the delcaration of:
557                 # size_t strlcpy(...)
558                 if ($line =~ /size_t(\0x9|\s)+strlcpy/) {
559                         $config{HAS_STRLCPY} = "true";
560                 }
561         }
562         close(STRLCPY);
563 }
564 print "yes\n" if $config{HAS_STRLCPY} eq "true";
565 print "no\n" if $config{HAS_STRLCPY} eq "false";
566
567 printf "Checking if kqueue exists... ";
568 $has_kqueue = 0;
569 $fail = 0;
570 open(KQUEUE, "</usr/include/sys/event.h") or $fail = 1;
571 if (!$fail) {
572         while (defined(my $line = <KQUEUE>)) {
573                 chomp($line);
574                 # try and find the delcaration of:
575                 # int kqueue(void);
576                 if ($line =~ /int(\0x9|\s)+kqueue/) {
577                         $has_kqueue = 1;
578                 }
579         }
580         close(KQUEUE);
581 }
582 print "yes\n" if $has_kqueue == 1;
583 print "no\n" if $has_kqueue == 0;
584
585 printf "Checking if epoll exists... ";
586 $has_epoll = 0;
587 $fail = 0;
588 open(EPOLL, "</usr/include/sys/epoll.h") or $fail = 1;
589 if (!$fail) {
590         $has_epoll = 1;
591         close(EPOLL);
592 }
593 if ($has_epoll) {
594         my $kernel = `uname -r`;
595         chomp($kernel);
596         if (($kernel =~ /^2\.0\./) || ($kernel =~ /^2\.2\./) || ($kernel =~ /^2\.4\./)) {
597                 $has_epoll = 0;
598         }
599         else
600         {
601                 # Suggestion from nenolod, weed out odd systems which have glibc built
602                 # against 2.4 kernels (ick)
603                 my $kernel_arch = `uname -p`;
604                 chomp($kernel_arch);
605                 my $libcv = 0.0;
606                 my $kernelv = 0.0;
607                 if ($kernel_arch =~ /x86_64/) {
608                         open (FH,"/lib64/libc.so.6|") or $has_epoll = 0;
609                 }
610                 else {
611                         open (FH,"/lib/libc.so.6|") or $has_epoll = 0;
612                 }
613                 if ($has_epoll)
614                 {
615                         while (defined(my $line = <FH>))
616                         {
617                                 chomp($line);
618                                 if ($line =~ /GNU C Library .* version (.*?) /)
619                                 {
620                                         $libcv = $1;
621                                         $libcv =~  /(\d+\.\d+)/;
622                                         $libcv = $1;
623                                 }
624                                 elsif ($line =~ /Compiled on a Linux (.*?\..*?)\.* system/)
625                                 {
626                                         $kernelv = $1;
627                                         # Fix for some retarded libc builds, strip off >> and << etc.
628                                         $kernelv =~ /(\d+\.\d+)/;
629                                         $kernelv = $1;
630                                 }
631                         }
632                         close FH;
633                         if ($libcv < 2.3)
634                         {
635                                 $has_epoll = 0;
636                                 printf "libc too old: $libcv... ";
637                         }
638                         if ($kernelv < 2.6)
639                         {
640                                 $has_epoll = 0;
641                                 printf "libc built against older kernel $kernelv... ";
642                         }
643                 }
644         }
645 }
646 print "yes\n" if $has_epoll == 1;
647 print "no\n" if $has_epoll == 0;
648
649 printf "Checking if Solaris I/O completion ports are available... ";
650 $has_ports = 0;
651 our $system = `uname -s`;
652 chomp ($system);
653 $has_ports = 1 if ($system eq "SunOS");
654
655 if ($has_ports) {
656         my $kernel = `uname -r`;
657         chomp($kernel);
658         if (($kernel !~ /^5\.1./)) {
659                 $has_ports = 0;
660         }
661 }
662 print "yes\n" if $has_ports == 1;
663 print "no\n" if $has_ports == 0;
664
665 $config{HAS_EPOLL} = $has_epoll;
666 $config{HAS_KQUEUE} = $has_kqueue; 
667
668 printf "Checking for libgnutls... ";
669 if (defined($config{HAS_GNUTLS}) && (($config{HAS_GNUTLS}) || ($config{HAS_GNUTLS} eq "y"))) {
670         print "yes\n";
671         $config{HAS_GNUTLS} = "y";
672 } else {
673         print "no\n";
674         $config{HAS_GNUTLS} = "n";
675 }
676
677 printf "Checking for openssl... ";
678 if (defined($config{HAS_OPENSSL}) && (($config{HAS_OPENSSL}) || ($config{HAS_OPENSSL} eq "y"))) {
679         print "yes\n";
680         $config{HAS_OPENSSL} = "y";
681 } else {
682         print "no\n";
683         $config{HAS_OPENSSL} = "n";
684 }
685
686 printf "Checking if you are running an ancient, unsupported OS... ";
687 if ($config{OSNAME} =~ /FreeBSD/i)
688 {
689         my $version = `uname -r`;
690         if ($version =~ /^4\./)
691         {
692                 my $foundit = `ls -l /usr/local/lib/libgnugetopt* | wc -l`;
693                 if ($foundit > 0)
694                 {
695                         # ICKY ICKY ICK, FREEBSD 4.x! GET AN UPGRADE!
696                         $config{CRAQ} = "-L/usr/local/lib -lgnugetopt -DHAVE_DECL_GETOPT=1";
697                         print "yes\n";
698                 }
699                 else
700                 {
701                         print "\n\nERROR: You require libgnugetopt (from ports or packages) to build InspIRCd on FreeBSD 4.11.\n";
702                 }
703         }
704         else
705         {
706                 $config{CRAQ} = " ";
707                 print "no ($version)\n";
708         }
709 }
710 else
711 {
712         $config{CRAQ} = " ";
713         print "no ($config{OSNAME})\n";
714 }
715
716 ################################################################################
717 #                         BEGIN INTERACTIVE PART                              #
718 ################################################################################
719
720 # Clear the Screen..
721 if ($interactive)
722 {
723         print "\e[2J\e[0G\e[0d"; # J = Erase in Display, 2 = Entire Screen, (G, d) = Move cursor to (..,..)
724         my $wholeos = $^O;
725
726         my $rev = getrevision();
727         # Display Introduction Message..
728         print <<"STOP" ;
729 Welcome to the \e[1mInspIRCd\e[0m Configuration program! (\e[1minteractive mode\e[0m)
730 \e[1mPackage maintainers: Type ./configure --help for non-interactive help\e[0m
731
732 *** If you are unsure of any of these values, leave it blank for    ***
733 *** standard settings that will work, and your server will run      ***
734 *** using them. Please consult your IRC network admin if in doubt.  ***
735
736 Press \e[1m<RETURN>\e[0m to accept the default for any option, or enter
737 a new value. Please note: You will \e[1mHAVE\e[0m to read the docs
738 dir, otherwise you won't have a config file!
739
740 Your operating system is: \e[1;32m$config{OSNAME}\e[0m ($wholeos)
741 Your InspIRCd revision ID is \e[1;32mr$rev\e[0m
742 STOP
743         if ($rev eq "r0") {
744                 print " (Non-SVN build)";
745         }
746         print ".\n\n";
747
748         $config{CHANGE_COMPILER} = "n";
749         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";
750
751         while (($config{GCCVER} < 3) || ($config{GCCVER} eq "")) {
752                 print "\e[1;32mIMPORTANT!\e[0m A GCC 2.x compiler has been detected, and
753 should NOT be used. You should probably specify a newer compiler.\n\n";
754                 yesno('CHANGE_COMPILER',"Do you want to change the compiler?");
755                 if ($config{CHANGE_COMPILER} =~ /y/i) {
756                         print "What command do you want to use to invoke your compiler?\n";
757                         print "[\e[1;32m$config{CC}\e[0m] -> ";
758                         chomp($config{CC} = <STDIN>);
759                         if ($config{CC} eq "") {
760                                 $config{CC} = "g++";
761                         }
762                         chomp(my $foo = `$config{CC} -dumpversion | cut -c 1`);
763                         if ($foo ne "") {
764                                 chomp($config{GCCVER}       = `$config{CC} -dumpversion | cut -c 1`); # we must redo these if we change compilers
765                                 chomp($config{GCCMINOR}     = `$config{CC} -dumpversion | cut -c 3`);
766                                 print "Queried compiler: \e[1;32m$config{CC}\e[0m (version \e[1;32m$config{GCCVER}.$config{GCCMINOR}\e[0m)\n";
767                                 if ($config{GCCVER} < 3) {
768                                         print "\e[1;32mGCC 2.x WILL NOT WORK!\e[0m. Let's try that again, shall we?\n";
769                                 }
770                         }
771                         else {
772                                 print "\e[1;32mWARNING!\e[0m Could not execute the compiler you specified. You may want to try again.\n";
773                         }
774                 }
775         }
776
777         print "\n";
778
779         # Directory Settings..
780         my $tmpbase = $config{BASE_DIR};
781         dir_check("do you wish to install the InspIRCd base", "BASE_DIR");
782         if ($tmpbase ne $config{BASE_DIR}) {
783                 $config{CONFIG_DIR}      = resolve_directory($config{BASE_DIR}."/conf");           # Configuration Dir
784                 $config{MODULE_DIR}      = resolve_directory($config{BASE_DIR}."/modules");     # Modules Directory
785                 $config{BINARY_DIR}      = resolve_directory($config{BASE_DIR}."/bin");     # Binary Directory
786                 $config{LIBRARY_DIR}    = resolve_directory($config{BASE_DIR}."/lib");      # Library Directory
787         }
788
789         dir_check("are the configuration files", "CONFIG_DIR");
790         dir_check("are the modules to be compiled to", "MODULE_DIR");
791         dir_check("is the IRCd binary to be placed", "BINARY_DIR");
792         dir_check("are the IRCd libraries to be placed", "LIBRARY_DIR");
793
794         if ($has_kqueue) {
795                 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?");
796                 print "\n";
797         }
798         if ($has_epoll) {
799                 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?");
800                 print "\n";
801         }
802         if ($has_ports) {
803                 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?");
804                 print "\n";
805         }
806         my $chose_hiperf = (($config{USE_EPOLL} eq "y") || ($config{USE_KQUEUE} eq "y") || ($config{USE_PORTS} eq "y"));
807         if (!$chose_hiperf) {
808                 print "No high-performance socket engines are available, or you chose\n";
809                 print "not to enable one. Defaulting to select() engine.\n\n";
810         }
811
812         yesno('IPV6',"Would you like to build InspIRCd with IPv6 support?");
813         print "\n";
814
815         if ($config{IPV6} eq "y") {
816                 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";
817                 $config{SUPPORT_IP6LINKS} = "y";
818         } else {
819                 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?");
820                 print "\n";
821         }
822
823         $config{USE_FREEBSD_BASE_SSL} = "n";
824         $config{USE_FREEBSD_PORTS_SSL} = "n";
825         if ($config{HAS_OPENSSL_PORT} ne "")
826         {
827                 $config{USE_FREEBSD_PORTS_SSL} = "y";
828                 print "I have detected the OpenSSL FreeBSD port installed on your system,\n";
829                 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";
830                 yesno('USE_FREEBSD_PORTS_SSL', "Do you want to use the FreeBSD ports version?");
831                 print "\n";
832                 $config{USE_FREEBSD_BASE_SSL} = "y" if ($config{USE_FREEBSD_PORTS_SSL} eq "n");
833
834                 if ($config{USE_FREEBSD_BASE_SSL} eq "n")
835                 {
836                         # update to port version
837                         $openssl_ver = $config{HAS_OPENSSL_PORT};
838                 }
839         }
840         else
841         {
842                 $config{USE_FREEBSD_BASE_SSL} = "y" if ($^O eq "freebsd");
843         }
844
845         if (($config{HAS_GNUTLS} eq "y") && ($config{HAS_OPENSSL} eq "y")) {
846                 print "I have detected both \e[1;32mGnuTLS\e[0m and \e[1;32mOpenSSL\e[0m on your system.\n";
847                 print "I will default to GnuTLS. If you wish to use OpenSSL\n";
848                 print "instead, you should enable the OpenSSL module yourself\n";
849                 print "by copying it from src/modules/extra to src/modules.\n\n";
850                 print "Detected GnuTLS version: \e[1;32m" . $gnutls_ver . "\e[0m\n";
851                 print "Detected OpenSSL version: \e[1;32m" . $openssl_ver . "\e[0m\n\n";
852         }
853
854         if ($config{HAS_GNUTLS} eq "y") {
855                 yesno('USE_GNUTLS', "Would you like to enable SSL Support?");
856                 if ($config{USE_GNUTLS} eq "y") {
857                         print "\nUsing GnuTLS SSL module.\n";
858                 }
859         } elsif ($config{HAS_OPENSSL} eq "y") {
860                         yesno('USE_OPENSSL', "Would you like to enable SSL Support?");
861         if ($config{USE_OPENSSL} eq "y") {
862                         print "\nUsing OpenSSL SSL module.\nYou will get better performance if you move to GnuTLS in the future.\n";
863                 }
864         }
865         else {
866                 print "\nCould not detect OpenSSL or GnuTLS. Make sure pkg-config is installed if\nyou intend to use OpenSSL, or that GnuTLS is in your path if you intend\nto use GnuTLS.\n\n";
867         }
868 }
869
870 dumphash();
871
872 if (($config{USE_GNUTLS} eq "y") && ($config{HAS_GNUTLS} ne "y"))
873 {
874         print "Sorry, but i couldn't detect gnutls. Make sure gnutls-config is in your path.\n";
875         exit(0);
876 }
877 if (($config{USE_OPENSSL} eq "y") && ($config{HAS_OPENSSL} ne "y"))
878 {
879         print "Sorry, but i couldn't detect openssl. Make sure openssl is in your path.\n";
880         exit(0);
881 }
882 our $failed = 0;
883
884 if ($config{USE_GNUTLS} eq "y") {
885         unless (-r "src/modules/m_ssl_gnutls.cpp") {
886                 print "Symlinking src/modules/m_ssl_gnutls.cpp from extra/\n";
887                 symlink "extra/m_ssl_gnutls.cpp", "src/modules/m_ssl_gnutls.cpp" or print STDERR "Symlink failed: $!";
888         }
889         getmodules();
890         if ($interactive)
891         {
892                 unless (-r "$config{CONFIG_DIR}/key.pem" && -r "$config{CONFIG_DIR}/cert.pem") {
893                         print "SSL Certificates Not found, Generating.. \n\n
894 *************************************************************
895 * Generating the Private Key may take some time, go grab a  *
896 * Coffee. Even better, to generate some more entropy if it  *
897 * is taking a while, open another console and type du / a   *
898 * few times and get that HD going :) Then answer the        *
899 * Questions which follow. If you are unsure, just hit enter *
900 *************************************************************\n\n";
901                         $failed = make_gnutls_cert();
902                         if ($failed) {
903                                 print "\n\e[1;32mCertificate generation failed!\e[0m\n\n";
904                         } else {
905                                 print "\nCertificate generation complete, copying to config directory... ";
906                                 File::Copy::move("key.pem", "$config{CONFIG_DIR}/key.pem") or print STDERR "Could not copy key.pem!\n";
907                                 File::Copy::move("cert.pem", "$config{CONFIG_DIR}/cert.pem") or print STDERR "Could not copy cert.pem!\n";
908                                 print "Done.\n\n";
909                         }
910                 }
911                 else {
912                         print "SSL Certificates found, skipping.\n\n";
913                 }
914         }
915         else
916         {
917                 print "Skipping SSL certificate generation\nin non-interactive mode.\n\n";
918         }
919 } elsif ($config{USE_OPENSSL} eq "y") {
920         unless (-r "src/modules/m_ssl_openssl.cpp") {
921                 print "Symlinking src/modules/m_ssl_openssl.cpp from extra/\n";
922                 symlink "extra/m_ssl_openssl.cpp", "src/modules/m_ssl_openssl.cpp" or print STDERR "Symlink failed: $!";
923         }
924         getmodules();
925         $failed = 0;
926         if ($interactive)
927         {
928                 unless (-r "$config{CONFIG_DIR}/key.pem" && -r "$config{CONFIG_DIR}/cert.pem") {
929                         print "SSL Certificates Not found, Generating.. \n\n
930 *************************************************************
931 * Generating the certificates may take some time, go grab a *
932 * coffee, or something.                                     *
933 *************************************************************\n\n";
934                         make_openssl_cert();
935                         print "\nCertificate generation complete, copying to config directory... ";
936                         File::Copy::move("key.pem", "$config{CONFIG_DIR}/key.pem") or print STDERR "Could not copy key.pem!\n";
937                         File::Copy::move("cert.pem", "$config{CONFIG_DIR}/cert.pem") or print STDERR "Could not copy cert.pem!\n";
938                         File::Copy::move("dhparams.pem", "$config{CONFIG_DIR}/dhparams.pem") or print STDERR "Could not copy dhparams.pem!\n";
939                         print "Done.\n\n";
940                 } else {
941                         print "SSL Certificates found, skipping.\n\n"
942                 }
943         }
944         else
945         {
946                 print "Skipping SSL certificate generation\nin non-interactive mode.\n\n";
947         }
948 }
949 if (($config{USE_GNUTLS} eq "n") && ($config{USE_OPENSSL} eq "n")) {
950         print "Skipping SSL Certificate generation, SSL support is not available.\n\n";
951 }
952
953 getosflags();
954 writefiles(1);
955 makecache();
956
957 print "\n\n";
958 print "To build your server with these settings, please type '\e[1;32m$config{MAKEPROG}\e[0m' now.\n";
959 if (($config{USE_GNUTLS} eq "y") || ($config{USE_OPENSSL} eq "y")) {
960         print "Please note: for \e[1;32mSSL support\e[0m you will need to load required\n";
961         print "modules in your config. This configure script has added those modules to the\n";
962         print "build process. For more info please refer to:\n";
963         print "\e[1;32mhttp://www.inspircd.org/wiki/Installation_From_Tarball\e[0m\n";
964 }
965 print "*** \e[1;32mRemember to edit your configuration files!!!\e[0m ***\n\n\n";
966 if (($config{OSNAME} eq "OpenBSD") && ($config{CC} ne "eg++")) {
967         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";
968 }
969
970 if ($config{GCCVER} < "3") {
971         print <<FOO2;
972 \e[1;32mWARNING!\e[0m You are attempting to compile InspIRCd on GCC 2.x!
973 GCC 2.x series compilers only had partial (read as broken) C++ support, and
974 your compile will most likely fail horribly! If you have any problems, do NOT
975 report them to the bugtracker or forums without first upgrading your compiler
976 to a newer 3.x or 4.x (or whatever is available currently) version.
977 FOO2
978 }
979
980 ################################################################################
981 #                             HELPER FUNCTIONS                          #
982 ################################################################################
983 sub getcache {
984         # Retrieves the .config.cache file, and loads values into the main config hash.
985         open(CACHE, ".config.cache") or return 0;
986         while (<CACHE>) {
987                 chomp;
988                 # Ignore Blank lines, and comments..
989                 next if /^\s*$/;
990                 next if /^\s*#/;
991                 my ($key, $value) = split("=", $_, 2);
992                 $value =~ /^\"(.*)\"$/;
993                 # Do something with data here!
994                 $config{$key} = $1;
995         }
996         close(CACHE);
997         return 1;
998 }
999
1000 sub makecache {
1001         # Dump the contents of %config
1002         print "Writing \e[1;32mcache file\e[0m for future ./configures ...\n";
1003         open(FILEHANDLE, ">.config.cache");
1004         foreach my $key (keys %config) {
1005                 print FILEHANDLE "$key=\"$config{$key}\"\n";
1006         }
1007         close(FILEHANDLE);
1008 }
1009
1010 sub dir_check {
1011         my ($desc, $hash_key) = @_;
1012         my $complete = 0;
1013         while (!$complete) {
1014                 print "In what directory $desc?\n";
1015                 print "[\e[1;32m$config{$hash_key}\e[0m] -> ";
1016                 chomp(my $var = <STDIN>);
1017                 if ($var eq "") {
1018                         $var = $config{$hash_key};
1019                 }
1020                 if ($var =~ /^\~\/(.+)$/) {
1021                         # Convert it to a full path..
1022                         $var = resolve_directory($ENV{HOME} . "/" . $1);
1023                 }
1024                 elsif ((($config{OSNAME} =~ /MINGW32/i) and ($var !~ /^[A-Z]{1}:\\.*/)) and (substr($var,0,1) ne "/"))
1025                 {
1026                         # Assume relative Path was given.. fill in the rest.
1027                         $var = $this . "/$var";
1028                 }
1029                 
1030                 $var = resolve_directory($var); 
1031                 if (! -e $var) {
1032                         print "$var does not exist. Create it?\n[\e[1;32my\e[0m] ";
1033                         chomp(my $tmp = <STDIN>);
1034                         if (($tmp eq "") || ($tmp =~ /^y/i)) {
1035                                 # Attempt to Create the Dir..
1036                                 my $chk = eval {
1037                                         use File::Path ();
1038                                         File::Path::mkpath($var, 0, 0777);
1039                                         1;
1040                                 };
1041                                 unless (defined($chk) && -d $var) {
1042                                         print "Unable to create directory. ($var)\n\n";
1043                                         # Restart Loop..
1044                                         next;
1045                                 }
1046                         } else {
1047                                 # They said they don't want to create, and we can't install there.
1048                                 print "\n\n";
1049                                 next;
1050                         }
1051                 } else {
1052                         if (!is_dir($var)) {
1053                                 # Target exists, but is not a directory.
1054                                 print "File $var exists, but is not a directory.\n\n";
1055                                 next;
1056                         }
1057                 }
1058                 # Either Dir Exists, or was created fine.
1059                 $config{$hash_key} = $var;
1060                 $complete = 1;
1061                 print "\n";
1062         }
1063 }
1064
1065 our $SHARED = "";
1066
1067 sub getosflags {
1068
1069         # Beware: Linux sets it's own cflags below for some retarded reason
1070         $config{LDLIBS} = "-pthread -lstdc++";
1071         $config{FLAGS}  = "-fPIC -Woverloaded-virtual -Wshadow -Wformat=2 -Wmissing-format-attribute -Wall $config{OPTIMISATI}";
1072         $config{DEVELOPER} = "-fPIC -Woverloaded-virtual -Wshadow -Wall -Wformat=2 -Wmissing-format-attribute -g";
1073         $SHARED = "-shared";
1074         $config{MAKEPROG} = "make";
1075
1076         if ($config{OSNAME} =~ /darwin/i) {
1077                 $config{FLAGS}  = "-DDARWIN -frtti -fPIC -Wall $config{OPTIMISATI}";
1078                 $SHARED = "-bundle -twolevel_namespace -undefined dynamic_lookup";
1079                 $config{LDLIBS} = "-ldl -pthread -lstdc++";
1080         }
1081
1082         if ($config{OSNAME} =~ /OpenBSD/i) {
1083                 $config{MAKEPROG} = "gmake";
1084                 $config{LDLIBS} = $config{LDLIBS} . " -lunwind";
1085                 chomp(my $foo = `eg++ -dumpversion | cut -c 1`);
1086                 # theyre running the package version of gcc (eg++)... detect it and set up its version numbers.
1087                 # if theyre not running this, configure lets the build continue but they probably wont manage to
1088                 # compile as this standard version is 2.95.3!
1089                 if ($foo ne "") {
1090                         $config{CC} = "eg++";
1091                         chomp($config{GCCVER}       = `eg++ -dumpversion | cut -c 1`); # we must redo these if we change the compiler path
1092                         chomp($config{GCCMINOR}     = `eg++ -dumpversion | cut -c 3`);
1093                 }
1094                 return "OpenBSD";
1095         }
1096
1097         if ($config{OSNAME} =~ /Linux/i) {
1098                 $config{LDLIBS} = "-ldl -lstdc++ -pthread";
1099 #               $config{FLAGS}  = "-fPIC -Woverloaded-virtual -Wshadow -Wall $config{OPTIMISATI}";
1100                 $config{FLAGS}  .= " " . $ENV{CXXFLAGS} if exists($ENV{CXXFLAGS});
1101                 $config{LDLIBS} .= " " . $ENV{LDLIBS} if exists($ENV{LDLIBS});
1102                 $config{MAKEPROG} = "make";
1103         }
1104
1105         if ($config{OSNAME} =~ /FreeBSD/i) {
1106                 $config{FLAGS}  .= " " . $ENV{CXXFLAGS} if exists($ENV{CXXFLAGS});
1107                 $config{LDLIBS} .= " " . $ENV{LDLIBS} if exists($ENV{LDLIBS});
1108         }
1109
1110         if ($config{OSNAME} =~ /SunOS/i or $config{OSNAME} =~ /solaris/i)
1111         {
1112                 # solaris/sunos needs these
1113                 # socket = bsd sockets api
1114                 # nsl = dns stuff
1115                 # rt = POSIX realtime extensions
1116                 # resolv = inet_aton only (why isnt this in nsl?!)
1117                 $config{MAKEPROG} = "gmake";
1118                 $config{LDLIBS} .= " -lsocket -lnsl -lrt -lresolv -pthread";
1119                 return "Solaris";
1120         }
1121         
1122         if($config{OSNAME} =~ /MINGW32/i)
1123         {
1124                 # All code is position-independent on windows
1125                 $config{FLAGS} =~ s/-fPIC //;
1126                 return "MinGW";
1127         }
1128
1129         return $config{OSNAME};
1130 }
1131
1132 my ($mliflags, $mfrules, $mobjs, $mfcount) = ("", "", "", 0);
1133
1134 sub writefiles {
1135         my($writeheader) = @_;
1136         my $se = "";
1137         # First File.. inspircd_config.h
1138         chomp(my $incos = `uname -n -s -r`);
1139         chomp(my $version = `sh src/version.sh`);
1140         chomp(my $revision2 = getrevision());
1141         if ($writeheader == 1)
1142         {
1143                 print "Writing \e[1;32minspircd_config.h\e[0m\n";
1144                 open(FILEHANDLE, ">include/inspircd_config.h");
1145                 print FILEHANDLE <<EOF;
1146 /* Auto generated by configure, do not modify! */
1147 #ifndef __CONFIGURATION_AUTO__
1148 #define __CONFIGURATION_AUTO__
1149
1150 /* this is for windows support. */
1151 #define CoreExport /**/
1152 #define DllExport /**/
1153
1154 #define CONFIG_FILE "$config{CONFIG_DIR}/inspircd.conf"
1155 #define MOD_PATH "$config{MODULE_DIR}"
1156 #define VERSION "$version"
1157 #define REVISION "$revision2"
1158 #define SOMAXCONN_S "$config{_SOMAXCONN}"
1159 #define OPTIMISATION $config{OPTIMITEMP}
1160 #define LIBRARYDIR "$config{LIBRARY_DIR}"
1161 #define SYSTEM "$incos"
1162 #define ENTRYPOINT int main(int argc, char** argv)
1163
1164 EOF
1165 print FILEHANDLE "#define MAXBUF " . ($config{MAXBUF}+2) . "\n";
1166
1167                 if ($config{OSNAME} =~ /SunOS/i) {
1168                         print FILEHANDLE "#define IS_SOLARIS\n";
1169                 }
1170                 if ($config{OSNAME} =~ /MINGW32/i) {
1171                         print FILEHANDLE "#define IS_MINGW\n";
1172                 }
1173                 if ($config{GCCVER} >= 3) {
1174                         print FILEHANDLE "#define GCC3\n";
1175                 }
1176                 if (
1177                         (($config{GCCVER} == 4) && ($config{GCCMINOR} >= 3))
1178                                 ||
1179                         ($config{GCCVER} > 4)
1180                 ) {
1181                         print FILEHANDLE "#define HASHMAP_DEPRECATED\n";
1182                 }
1183                 if ($config{HAS_STRLCPY} eq "true") {
1184                         print FILEHANDLE "#define HAS_STRLCPY\n";
1185                 }
1186                 if ($config{HAS_STDINT} eq "true") {
1187                         print FILEHANDLE "#define HAS_STDINT\n";
1188                 }
1189                 if ($config{IPV6} =~ /y/i) {
1190                         print FILEHANDLE "#define IPV6\n";
1191                 }
1192                 if ($config{SUPPORT_IP6LINKS} =~ /y/i) {
1193                         print FILEHANDLE "#define SUPPORT_IP6LINKS\n";
1194                 }
1195                 my $use_hiperf = 0;
1196                 if (($has_kqueue) && ($config{USE_KQUEUE} eq "y")) {
1197                         print FILEHANDLE "#define USE_KQUEUE\n";
1198                         $se = "socketengine_kqueue";
1199                         $use_hiperf = 1;
1200                 }
1201                 if (($has_epoll) && ($config{USE_EPOLL} eq "y")) {
1202                         print FILEHANDLE "#define USE_EPOLL\n";
1203                         $se = "socketengine_epoll";
1204                         $use_hiperf = 1;
1205                 }
1206                 if (($has_ports) && ($config{USE_PORTS} eq "y")) {
1207                         print FILEHANDLE "#define USE_PORTS\n";
1208                         $se = "socketengine_ports";
1209                         $use_hiperf = 1;
1210                 }
1211                 # user didn't choose either epoll or select for their OS.
1212                 # default them to USE_SELECT (ewwy puke puke)
1213                 if (!$use_hiperf) {
1214                         print FILEHANDLE "#define USE_SELECT\n";
1215                         $se = "socketengine_select";
1216                 }
1217                 print FILEHANDLE "\n#include \"threadengines/threadengine_pthread.h\"\n\n#endif\n";
1218                 close(FILEHANDLE);
1219         }
1220
1221         if ($writeheader)
1222         {
1223                 open(FILEHANDLE, ">include/inspircd_se_config.h");
1224                 print FILEHANDLE <<EOF;
1225 /* Auto generated by configure, do not modify or commit to svn! */
1226 #ifndef __CONFIGURATION_SOCKETENGINE__
1227 #define __CONFIGURATION_SOCKETENGINE__
1228
1229 #include "socketengines/$se.h"
1230
1231 #endif
1232 EOF
1233                 close(FILEHANDLE);
1234         }
1235
1236
1237         # Create a Modules List..
1238         my $modules = "";
1239         foreach my $i (@modlist)
1240         {
1241                 $modules .= "m_".$i.".so ";
1242         }
1243         chomp($modules);   # Remove Redundant whitespace..
1244
1245         opendir(DIRHANDLE, "src/modules");
1246         foreach my $name2 (sort readdir(DIRHANDLE)) {
1247                 if ($name2 =~ /^m_(.+?)$/) {
1248                         if (defined(opendir(MDIRHANDLE, "src/modules/$name2"))) {
1249                                 closedir(MDIRHANDLE);
1250                                 $modules .= "$name2.so ";
1251                                 $uninstall_list = $uninstall_list . "   -rm \$(MODULES)/$name2.so\n";
1252                         }
1253                 }
1254         }
1255         closedir(DIRHANDLE);
1256
1257
1258         # Write all .in files.
1259         my $tmp = "";
1260         my $file = "";
1261         my $exe = "inspircd";
1262
1263         # Do this once here, and cache it in the .*.inc files,
1264         # rather than attempting to read src/version.sh from
1265         # compiled code -- we might not have the source to hand.
1266         # Fix for bug#177 by Brain.
1267
1268         chomp($version = `sh ./src/version.sh`);
1269         chomp(my $revision = getrevision());
1270         $version = "$version(r$revision)";
1271
1272         # We can actually parse any file starting with . and ending with .inc,
1273         # but right now we only parse .inspircd.inc to form './inspircd'
1274
1275         print "Writing \e[1;32mMakefiles\e[0m\n";
1276         write_dynamic_modules_makefile();
1277         write_dynamic_makefile();
1278
1279         opendir(DIRHANDLE, $this);
1280
1281         foreach my $name (sort readdir(DIRHANDLE)) {
1282                 if ($name =~ /^\.(.+)\.inc$/) {
1283                         $file = $1;
1284
1285                         # Bug #353, omit this on non-darwin
1286                         next if (($config{OSNAME} !~ /darwin/) && ($file eq "org.inspircd.plist"));
1287
1288                         # All .name.inc files need parsing!
1289                         $tmp = "";
1290                         open(FILEHANDLE, ".$file.inc") or die ("Can't open .$file.inc");
1291                         while (<FILEHANDLE>) {
1292                                 $tmp .= $_;
1293                         }
1294                         close(FILEHANDLE);
1295
1296                         print "Writing \e[1;32m$file\e[0m ...\n";
1297                         $tmp =~ s/\@CC\@/$config{CC}/ if defined $config{CC};
1298                         $tmp =~ s/\@MAKEPROG\@/$config{MAKEPROG}/ if defined $config{MAKEPROG};
1299                         $tmp =~ s/\@FLAGS\@/$config{FLAGS}/ if defined $config{FLAGS};
1300                         $tmp =~ s/\@DEVELOPER\@/$config{DEVELOPER}/ if defined $config{DEVELOPER};
1301                         $tmp =~ s/\@LDLIBS\@/$config{LDLIBS}/ if defined $config{LDLIBS};
1302                         $tmp =~ s/\@BASE_DIR\@/$config{BASE_DIR}/ if defined $config{BASE_DIR};
1303                         $tmp =~ s/\@CONFIG_DIR\@/$config{CONFIG_DIR}/ if defined $config{CONFIG_DIR};
1304                         $tmp =~ s/\@MODULE_DIR\@/$config{MODULE_DIR}/ if defined $config{MODULE_DIR};
1305                         $tmp =~ s/\@BINARY_DIR\@/$config{BINARY_DIR}/ if defined $config{BINARY_DIR};
1306                         $tmp =~ s/\@LIBRARY_DIR\@/$config{LIBRARY_DIR}/ if defined $config{LIBRARY_DIR};
1307                         $tmp =~ s/\@MODULES\@/$modules/ if defined $modules;
1308                         $tmp =~ s/\@STARTSCRIPT\@/$config{STARTSCRIPT}/ if defined $config{STARTSCRIPT};
1309                         $tmp =~ s/\@DESTINATION\@/$config{DESTINATION}/ if defined $config{DESTINATION};
1310                         $tmp =~ s/\@EXTRA_DIR\@/$config{EXTRA_DIR}/ if defined $config{EXTRA_DIR};
1311                         $tmp =~ s/\@EXECUTABLE\@/$exe/ if defined $exe;
1312                         $tmp =~ s/\@MAKEORDER\@/$config{MAKEORDER}/ if defined $config{MAKEORDER};
1313                         $tmp =~ s/\@VERSION\@/$version/ if defined $version;
1314                         $tmp =~ s/\@INSTALL_LIST\@/$install_list/ if defined $install_list;
1315                         $tmp =~ s/\@UNINSTALL_LIST\@/$uninstall_list/ if defined $uninstall_list;
1316
1317                         open(FILEHANDLE, ">$file");
1318                         print FILEHANDLE $tmp;
1319                 }
1320         }
1321         closedir(DIRHANDLE);
1322
1323         # Make inspircd executable!
1324         chmod 0744, 'inspircd';
1325 }
1326
1327 sub write_dynamic_modules_makefile {
1328         # Modules Makefile..
1329         print "Writing \e[1;32msrc/modules/Makefile\e[0m\n";
1330         open(FILEHANDLE, ">src/modules/Makefile");
1331
1332 ###
1333 # Module Makefile Header
1334 ###
1335         print FILEHANDLE <<EOF;
1336 ###################################################
1337 # Copyright 2002-2007 The InspIRCd Development Team
1338 #  http://www.inspircd.org/wiki/index.php/Credits
1339 #
1340 # Thanks to Andrew Church <achurch\@achurch.org>
1341 #   for assisting with making this work right.
1342 #
1343 # Automatically Generated by ./configure to add a
1344 #  modules please run ./configure -modupdate
1345 ###################################################
1346
1347 all: \$(MODULES)
1348
1349 EOF
1350
1351 if ($config{OSNAME} =~ /darwin/) {
1352                 print FILEHANDLE <<EOCHEESE;
1353
1354 PICLDFLAGS = -twolevel_namespace -undefined dynamic_lookup -bundle
1355
1356 EOCHEESE
1357 } else {
1358                 print FILEHANDLE <<EOCHEESE;
1359
1360 PICLDFLAGS = -fPIC -DPIC -shared
1361
1362 EOCHEESE
1363 }
1364
1365         ###
1366         # End Module Makefile Header
1367         ###
1368
1369         # Create a Modules List..
1370         my $modules = "";
1371         my $cmflags = "";
1372         my $liflags = "";
1373         foreach my $i (@modlist) {
1374                 ###
1375                 # Write Entry to the MakeFile
1376                 ###
1377                 $cmflags = getcompilerflags("src/modules/m_".$i.".cpp");
1378                 $liflags = getlinkerflags("src/modules/m_".$i.".cpp");
1379                 my $deps = getdependencies("src/modules/m_".$i.".cpp");
1380         
1381                 #print "file: $i: cmflags=$cmflags; liflags=$liflags; deps=$deps\n";
1382         
1383
1384                 if (nopedantic("src/modules/m_".$i.".cpp"))
1385                 {
1386                         print FILEHANDLE "
1387 m_$i.so: m_$i.cpp ../../include/modules.h ../../include/users.h ../../include/channels.h ../../include/base.h ../../include/inspircd_config.h ../../include/inspircd.h ../../include/configreader.h $deps
1388         \@../../make/run-cc.pl \$(CC) -pipe -I../../include \$(NICEFLAGS) $cmflags \$(PICLDFLAGS) $liflags -export-dynamic -o m_$i.so m_$i.cpp
1389 "
1390                 }
1391                 else
1392                 {
1393                         print FILEHANDLE "
1394 m_$i.so: m_$i.cpp ../../include/modules.h ../../include/users.h ../../include/channels.h ../../include/base.h ../../include/inspircd_config.h ../../include/inspircd.h ../../include/configreader.h $deps
1395         \@../../make/run-cc.pl \$(CC) -pipe -I../../include \$(FLAGS) $cmflags \$(PICLDFLAGS) $liflags -export-dynamic -o m_$i.so m_$i.cpp
1396 ";
1397                 }
1398                 $install_list = $install_list . "       install -m \$(INSTMODE) src/modules/m_$i.so \$(MODPATH)\n";
1399                 $uninstall_list = $uninstall_list . "   -rm \$(MODULES)/m_$i.so\n";
1400 ###
1401                 # End Write Entry to the MakeFile
1402                 ###
1403         }
1404
1405         opendir(DIRHANDLE, "src/modules");
1406         foreach my $name (sort readdir(DIRHANDLE)) {
1407                 if ($name =~ /^m_(.+?)$/) {
1408                         $mfrules = "";
1409                         $mobjs = "";
1410                         $mliflags = "";
1411                         $mfcount = 0;
1412                         # A module made of multiple files, in a dir, e.g. src/modules/m_spanningtree/
1413                         if (defined(opendir(MDIRHANDLE, "src/modules/$name"))) {
1414                                 read_module_directory("src/modules/$name", $name);
1415                                 print "Composing Makefile rules for directory \e[1;32m$name\e[0m... (\e[1;32m$mfcount files found\e[0m)\n";
1416                                 print FILEHANDLE "$name.so: ../../include/modules.h ../../include/users.h ../../include/channels.h ../../include/base.h ../../include/inspircd_config.h ../../include/inspircd.h ../../include/configreader.h $mobjs\n"; 
1417                                 if ($config{IS_DARWIN} eq "YES") {
1418                                         print FILEHANDLE "      \@../../make/run-cc.pl \$(CC) -pipe -twolevel_namespace -undefined dynamic_lookup \$(FLAGS) $mliflags -bundle -o $name.so $mobjs\n"; 
1419                                 } else {
1420                                         print FILEHANDLE "      \@../../make/run-cc.pl \$(CC) -pipe \$(FLAGS) -shared $mliflags -o $name.so $mobjs\n";
1421                                 }
1422                                 print FILEHANDLE "\n$mfrules\n";
1423                                 closedir(MDIRHANDLE);
1424                                 $install_list = $install_list . "       install -m \$(INSTMODE) src/modules/$name.so \$(MODPATH)\n";
1425                         }
1426                 }
1427         }
1428         closedir(DIRHANDLE);
1429 }
1430
1431 sub read_module_directory {
1432         my ($dpath, $reldpath) = @_;
1433         
1434         if (opendir(MDIRHANDLE, $dpath) == 0) {
1435                 return;
1436         }
1437         
1438         foreach my $fname (sort readdir(MDIRHANDLE)) {
1439                 if ($fname =~ /\.cpp$/) {
1440                         my $cmflags = getcompilerflags("$dpath/$fname");
1441                         $mliflags = $mliflags . " " . getlinkerflags("$dpath/$fname");
1442                         my $deps = getdependencies("$dpath/$fname");
1443                         my $oname = $fname;
1444                         $oname =~ s/\.cpp$/.o/g;
1445                         $mfrules = $mfrules .  "$reldpath/$oname: $reldpath/$fname ../../include/modules.h ../../include/users.h ../../include/channels.h ../../include/base.h ../../include/inspircd_config.h ../../include/inspircd.h ../../include/configreader.h $deps\n";
1446                         $mfrules = $mfrules .  "        \@../../make/run-cc.pl \$(CC) -pipe -I../../include -I. \$(FLAGS) $cmflags -export-dynamic -o $reldpath/$oname -c $reldpath/$fname\n\n";
1447                         $mobjs = $mobjs . " $reldpath/$oname";
1448                         $mfcount++;
1449                 }
1450                 elsif ((-d "$dpath/$fname") && !($fname eq ".") && !($fname eq "..")) {
1451                         read_module_directory($dpath."/".$fname, $reldpath."/".$fname);
1452                 }
1453         }
1454 }
1455
1456 sub calcdeps($)
1457 {
1458         # Yes i know we could use gcc -M but it seems to ideneify a lot of 'deep'
1459         # dependencies which are not relevent in C++.
1460
1461         my $file = $_[0];
1462
1463         open (CPP, "<$file") or die("Can't open $file for reading!");
1464
1465         my %dupe = ();
1466         my $retlist = "";
1467
1468         foreach my $d (@ignoredeps)
1469         {
1470                 $dupe{$d} = 1;
1471         }
1472
1473         my $immutable = "";
1474         foreach my $dep (@immutabledeps)
1475         {
1476                 $immutable = $immutable . "../include/$dep ";
1477         }
1478         $immutable =~ s/ $//g;
1479
1480         while (defined(my $line = <CPP>))
1481         {
1482                 chomp($line);
1483                 if ($line =~ /#include "(.+\.h)"/)
1484                 {
1485                         if (!exists($dupe{$1}))
1486                         {
1487                                 $retlist = $retlist . "../include/$1 ";
1488                                 $dupe{$1} = 1;
1489                         }
1490                 }
1491         }
1492         close CPP;
1493         return length($immutable) ? $immutable . " " . $retlist : $retlist;
1494 }
1495
1496 sub write_dynamic_makefile
1497 {
1498         my $i = 0;
1499         my @cmdlist = ();
1500         my %existing_install_list = ();
1501         my %core_files_list = ();
1502
1503         opendir(DIRHANDLE, "src/commands");
1504         foreach my $name (sort readdir(DIRHANDLE))
1505         {
1506                 if ($name =~ /^cmd_(.+)\.cpp$/)
1507                 {
1508                         $cmdlist[$i++] = $1;
1509                         $install_list = $install_list . "       -install -m \$(INSTMODE) src/commands/cmd_" . $1 . ".so \$(LIBPATH)\n";
1510                         $uninstall_list = $uninstall_list . "   -rm \$(LIBPATH)/cmd_$1.so\n";
1511                 }
1512         }
1513         closedir(DIRHANDLE);
1514
1515         if (!$has_epoll)
1516         {
1517                 $config{USE_EPOLL} = 0;
1518         }
1519         if (!$has_kqueue)
1520         {
1521                 $config{USE_KQUEUE} = 0;
1522         }
1523         if (!$has_ports)
1524         {
1525                 $config{USE_PORTS} = 0;
1526         }
1527
1528         # formerly generated below this foreach, now it's not! magic.
1529         my $all_core = "";
1530
1531         foreach my $dir (("src","src/commands","src/modes","src/socketengines","src/modules"))
1532         {
1533                 print "Scanning \e[1;32m$dir\e[0m for core files ";
1534                 opendir(DIRHANDLE, $dir);
1535                 foreach my $name (sort readdir(DIRHANDLE))
1536                 {
1537                         if ($name =~ /\.cpp$/)
1538                         {
1539                                 open (CPP, "<$dir/$name") or die("Can't open $dir/$name to scan it! oh bugger");
1540                                 print ".";
1541                                 while (defined(my $line = <CPP>))
1542                                 {
1543                                         chomp($line);
1544                                         if ($line =~ /\/\* \$Core \*\//i)
1545                                         {
1546                                                 my $sname = $name;
1547                                                 $sname =~ s/\.cpp$/.o/;
1548
1549                                                 # append it to list to be built
1550                                                 $all_core = $all_core . $sname . " ";
1551                                                 $filelist{$name} = $sname;
1552
1553                                                 # mark it as a core file, so it won't get shared object cflags
1554                                                 if (!exists($core_files_list{$name}))
1555                                                 {
1556                                                         $core_files_list{$name} = 1;
1557                                                 }
1558                                         }
1559                                         elsif ($line =~ /\/\* \$ExtraDeps: (.*?) \*\//i)
1560                                         {
1561                                                 $specialdeps{$name} = $1;
1562                                         }
1563                                         elsif ($line =~ /\/\* \$ExtraObjects: (.*?) \*\//i)
1564                                         {
1565                                                 $extraobjects{$name} = $1;
1566                                         }
1567                                         elsif ($line =~ /\/\* \$ExtraBuild: (.*?) \*\//i)
1568                                         {
1569                                                 $extrabuildlines{$name} = $1;
1570                                         }
1571                                         elsif ($line =~ /\/\* \$ExtraSources: (.*?) \*\//i)
1572                                         {
1573                                                 $extrasources{$name} = $1;
1574                                                 }
1575                                         elsif ($line =~ /\/\* \$If: (\w+) \*\//i)
1576                                         {
1577                                                 if (defined $config{$1})
1578                                                 {
1579                                                         if (($config{$1} !~ /y/i) and ($config{$1} ne "1"))
1580                                                         {
1581                                                                 # Skip to 'endif'
1582                                                                 while (defined($line = <CPP>))
1583                                                                 {
1584                                                                         chomp($line);
1585                                                                         die ("\$If buildsystem instruction within another \$If in file $dir/$name") if ($line =~ /\/\* \$If: (\w+) \*\//i);
1586                                                                         last if ($line =~ /\/\* \$EndIf \*\//i);
1587                                                                 }
1588                                                         }
1589                                                 }
1590                                         }
1591                                         elsif ($line =~ /\/\* \$Install: (.*?) \*\//i)
1592                                         {
1593                                                 if (!exists($existing_install_list{$1}))
1594                                                 {
1595                                                         $existing_install_list{$1} = 1;
1596                                                         my $idir = (split(' ',$1))[1];
1597                                                         my $ifile = (split(' ',$1))[0];
1598                                                         $install_list = $install_list . "       -install -m \$(INSTMODE) $1\n";
1599                                                         $ifile =~ s/.*\///g;
1600                                                         $uninstall_list = $uninstall_list . "   -rm $idir/$ifile\n";
1601                                                 }
1602                                         }
1603                                         elsif ($line =~ /\/\* \$CopyInstall: (.*?) \*\//i)
1604                                         {
1605                                                 if (!exists($existing_install_list{$1}))
1606                                                 {
1607                                                         $existing_install_list{$1} = 1;
1608                                                         my $idir = (split(' ',$1))[1];
1609                                                         my $ifile = (split(' ',$1))[0];
1610                                                         $install_list = $install_list . "       -cp $1\n";
1611                                                         $ifile =~ s/.*\///g;
1612                                                         $uninstall_list = $uninstall_list . "   -rm $idir/$ifile\n";
1613                                                 }
1614                                         }
1615                                 }
1616                                 close CPP;
1617                         }
1618                 }
1619                 closedir(DIRHANDLE);
1620                 print " done!\n";
1621         }
1622
1623         # modes need to be compiled in too
1624         $all_core = $all_core . "modes/modeclasses.a";
1625
1626         my $freebsd4libs = (defined $config{CRAQ} ? $config{CRAQ} : "");
1627
1628         my $libraryext = "";
1629         my $binary_rule = "";
1630
1631         if ($config{IS_DARWIN} eq "YES")
1632         {
1633                 $libraryext = "dylib";
1634                 $binary_rule = "        \@../make/run-cc.pl \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c inspircd.cpp\n       \@../make/run-cc.pl \$(CC) -pipe -dynamic -bind_at_load -L. -o inspircd \$(LDLIBS) inspircd.o "
1635         }
1636         else
1637         {
1638                 $libraryext = "so";
1639                 $binary_rule = "        \@../make/run-cc.pl \$(CC) -pipe -I../include \$(FLAGS) $freebsd4libs -rdynamic -L. inspircd.cpp -o inspircd \$(LDLIBS) ";
1640         }
1641
1642         open(FH,">src/Makefile") or die("Could not write src/Makefile");
1643         print FH <<EOM;
1644
1645 CC = im a cheezeball
1646 CXXFLAGS = -I../include \${FLAGS}
1647 CPPFILES = \$(shell /bin/ls -l modes/ | grep '\\.cpp' | sed 's/^.* //' | grep -v svn)
1648 RELCPPFILES = \$(shell /bin/ls -l modes/ | grep '\\.cpp' | sed 's/^.* /modes\\//' | grep -v svn)
1649
1650 EOM
1651
1652         my $buildstring = "";
1653         my $deps = "";
1654
1655         foreach my $cpp (sort keys %filelist)
1656         {
1657                 my $objs = $cpp;
1658                 my $rawcpp = $cpp;
1659                 $objs =~ s/\.cpp$/.o/;
1660                 if (exists($extraobjects{$cpp}))
1661                 {
1662                         $objs = $objs . " " . $extraobjects{$cpp};
1663                         $all_core = $all_core . " " . $extraobjects{$cpp};
1664                 }
1665                 if (exists($extrasources{$cpp}))
1666                 {
1667                         $rawcpp = $rawcpp . " " . $extrasources{$cpp};
1668                 }
1669
1670                 $deps = calcdeps("src/$cpp");
1671                 if (exists($extrasources{$cpp}))
1672                 {
1673                         foreach my $seperate (sort split(' ',$extrasources{$cpp}))
1674                         {
1675                                 my $d = calcdeps("src/$extrasources{$cpp}") . " ";
1676                                 if ($d ne "")
1677                                 {
1678                                         $deps = $deps . $d . " ";
1679                                 }
1680                         }
1681                 }
1682                 $buildstring = $buildstring . $objs . ": $cpp $deps ". (defined($specialdeps{$cpp}) ? $specialdeps{$cpp} : "") . "\n";
1683
1684                 if (exists($core_files_list{$cpp}))
1685                 {
1686                         # core files are statically linked into the binary and do not require -export-dynamic
1687                         $buildstring = $buildstring . " \@../make/run-cc.pl \$(CC) -pipe -I../include \$(FLAGS) -c $rawcpp\n";
1688                 }
1689                 else
1690                 {
1691                         $buildstring = $buildstring . " \@../make/run-cc.pl \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c $rawcpp\n";
1692                 }
1693
1694                 if (exists($extrabuildlines{$cpp}))
1695                 {
1696                         $buildstring = $buildstring . " " . $extrabuildlines{$cpp} . "\n";
1697                 }
1698         }
1699
1700         print FH "all: inspircd moo\n\n\n";
1701
1702         $deps = calcdeps("src/inspircd.cpp");
1703         print FH "inspircd: inspircd.cpp $deps $all_core\n";
1704         print FH "$binary_rule $all_core\n\n";
1705
1706         print FH $buildstring;
1707         print FH "moo:\n        \@\${MAKE} -C \"commands\" DIRNAME=\"src/commands\" CC=\"\$(CC)\" \$(MAKEARGS)\n\n";
1708
1709         # close main makefile
1710         close(FH);
1711
1712         my $cmdobjs = "";
1713         # generate a list of .so
1714         foreach my $cmd (@cmdlist) {
1715                 $cmdobjs = $cmdobjs . "cmd_$cmd.so ";
1716         }
1717
1718         # and now reopen the commands makefile
1719         open(FH,">src/commands/Makefile") or die("Could not write src/commands/Makefile");
1720         print FH <<ITEM;
1721 CC = i am cornholio
1722 CXXFLAGS = -I../../include \${FLAGS}
1723
1724 all: $cmdobjs
1725
1726
1727 ITEM
1728
1729         # now print the command file details.
1730         foreach my $cmd (@cmdlist) {
1731                 print FH <<ITEM;
1732 cmd_$cmd.so: cmd_$cmd.cpp ../../include/base.h ../../include/modules.h ../../include/inspircd.h ../../include/channels.h ../../include/users.h ../../include/inspircd_config.h ../../include/commands/cmd_$cmd.h
1733         \@../../make/run-cc.pl \$(CC) -pipe -I../../include \$(FLAGS) -export-dynamic $SHARED -o cmd_$cmd.so cmd_$cmd.cpp
1734
1735 ITEM
1736         }
1737 }
1738
1739 # Routine to list out the extra/ modules that have been enabled.
1740 # Note: when getting any filenames out and comparing, it's important to lc it if the
1741 # file system is not case-sensitive (== Epoc, MacOS, OS/2 (incl DOS/DJGPP), VMS, Win32
1742 # (incl NetWare, Symbian)). Cygwin may or may not be case-sensitive, depending on
1743 # configuration, however, File::Spec does not currently tell us (it assumes Unix behavior).
1744 sub list_extras () {
1745         use File::Spec;
1746         # @_ not used
1747         my $srcdir = File::Spec->catdir("src", "modules");
1748         my $abs_srcdir = File::Spec->rel2abs($srcdir);
1749         local $_;
1750         my $dd;
1751         opendir $dd, File::Spec->catdir($abs_srcdir, "extra") or die (File::Spec->catdir($abs_srcdir, "extra") . ": $!\n");
1752         my @extras = map { File::Spec->case_tolerant() ? lc($_) : $_ } (readdir($dd));
1753         closedir $dd;
1754         undef $dd;
1755         opendir $dd, $abs_srcdir or die "$abs_srcdir: $!\n";
1756         my @sources = map { File::Spec->case_tolerant() ? lc($_) : $_ } (readdir($dd));
1757         closedir $dd;
1758         undef $dd;
1759         my $maxlen = (sort { $b <=> $a } (map {length($_)} (@extras)))[0];
1760         my %extras = ();
1761 EXTRA:  for my $extra (@extras) {
1762                 next if (File::Spec->curdir() eq $extra || File::Spec->updir() eq $extra);
1763                 next if ($extra eq '.svn');
1764                 my $abs_extra = File::Spec->catfile($abs_srcdir, "extra", $extra);
1765                 my $abs_source = File::Spec->catfile($abs_srcdir, $extra);
1766                 next unless ($extra =~ m/\.(cpp|h)$/ || (-d $abs_extra)); # C++ Source/Header, or directory
1767                 if (-l $abs_source) {
1768                         # Symlink, is it in the right place?
1769                         my $targ = readlink($abs_source);
1770                         my $abs_targ = File::Spec->rel2abs($targ, $abs_srcdir);
1771                         if ($abs_targ eq $abs_extra) {
1772                                 $extras{$extra} = "\e[32;1menabled\e[0m";
1773                         } else {
1774                                 $extras{$extra} = sprintf("\e[31;1mwrong symlink target (%s)\e[0m", $abs_targ);
1775                         }
1776                 } elsif (-e $abs_source) {
1777                         my ($devext, $inoext) = stat($abs_extra);
1778                         my ($devsrc, $inosrc, undef, $lnksrc) = stat($abs_source);
1779                         if ($lnksrc > 1) {
1780                                 if ($devsrc == $devext && $inosrc == $inoext) {
1781                                         $extras{$extra} = "\e[32;1menabled\e[0m";
1782                                 } else {
1783                                         $extras{$extra} = sprintf("\e[31;1mwrong hardlink target (%d:%d)\e[0m", $devsrc, $inosrc);
1784                                 }
1785                         } else {
1786                                 open my $extfd, "<", $abs_extra;
1787                                 open my $srcfd, "<", $abs_source;
1788                                 local $/ = undef;
1789                                 if (scalar(<$extfd>) eq scalar(<$srcfd>)) {
1790                                         $extras{$extra} = "\e[32;1menabled\e[0m";
1791                                 } else {
1792                                         $extras{$extra} = sprintf("\e[31;1mout of synch (re-copy)\e[0m");
1793                                 }
1794                         }
1795                 } else {
1796                         $extras{$extra} = "\e[33;1mdisabled\e[0m";
1797                 }
1798         }
1799         # Now let's add dependency info
1800         for my $extra (keys(%extras)) {
1801                 next unless $extras{$extra} =~ m/enabled/; # only process enabled extras.
1802                 my $abs_extra = File::Spec->catfile($abs_srcdir, "extra", $extra);
1803                 my @deps = split / +/, getdependencies($abs_extra);
1804                 for my $dep (@deps) {
1805                         if (exists($extras{$dep})) {
1806                                 my $ref = \$extras{$dep}; # Take reference.
1807                                 if ($$ref !~ m/needed by/) {
1808                                         # First dependency found.
1809                                         if ($$ref =~ m/enabled/) {
1810                                                 $$ref .= " (needed by \e[32;1m$extra\e[0m";
1811                                         } else {
1812                                                 $$ref =~ s/\e\[.*?m//g; # Strip out previous coloring. Will be set in bold+red+blink later.
1813                                                 $$ref .= " (needed by \e[0;32;1;5m$extra\e[0;31;1;5m";
1814                                         }
1815                                 } else {
1816                                         if ($$ref =~ m/enabled/) {
1817                                                 $$ref .= ", \e[32;1m$extra\e[0m";
1818                                         } else {
1819                                                 $$ref .= ", \e[0;32;1;5m$extra\e[0;31;1;5m";
1820                                         }
1821                                 }
1822                         }
1823                 }
1824         }
1825         for my $extra (sort {$a cmp $b} keys(%extras)) {
1826                 my $text = $extras{$extra};
1827                 if ($text =~ m/needed by/ && $text !~ m/enabled/) {
1828                         printf "\e[31;1;5m%-*s = %s%s\e[0m\n", $maxlen, $extra, $text, ($text =~ m/needed by/ ? ")" : "");
1829                 } else {
1830                         printf "%-*s = %s%s\n", $maxlen, $extra, $text, ($text =~ m/needed by/ ? "\e[0m)" : "");
1831                 }
1832         }
1833         return keys(%extras) if wantarray; # Can be used by manage_extras.
1834 }
1835
1836 sub enable_extras (@) {
1837         my (@extras) = @_;
1838         for my $extra (@extras) {
1839                 my $extrapath = "src/modules/extra/$extra";
1840                 if (!-e $extrapath) {
1841                         print STDERR "Cannot enable \e[32;1m$extra\e[0m : No such file or directory in src/modules/extra\n";
1842                         next;
1843                 }
1844                 my $source = "src/modules/$extra";
1845                 if (-e $source) {
1846                         print STDERR "Cannot enable \e[32;1m$extra\e[0m : destination in src/modules exists (might already be enabled?)\n";
1847                         next;
1848                 }
1849                 # Get dependencies, and add them to be processed.
1850                 my @deps = split / +/, getdependencies($extrapath);
1851                 for my $dep (@deps) {
1852                         next if scalar(grep { $_ eq $dep } (@extras)) > 0; # Skip if we're going to be enabling it anyway.
1853                         if (!-e "src/modules/$dep") {
1854                                 if (-e "src/modules/extra/$dep") {
1855                                         print STDERR "Will also enable extra \e[32;1m$dep\e[0m (needed by \e[32;1m$extra\e[0m)\n";
1856                                         push @extras, $dep;
1857                                 } else {
1858                                         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";
1859                                 }
1860                         }
1861                 }
1862                 print "Enabling $extra ... \n";
1863                 symlink "extra/$extra", $source or print STDERR "$source: Cannot link to 'extra/$extra': $!\n";
1864         }
1865 }
1866
1867 sub disable_extras (@)
1868 {
1869         opendir my $dd, "src/modules/extra/";
1870         my @files = readdir($dd);
1871         closedir $dd;
1872         my (@extras) = @_;
1873 EXTRA:  for my $extra (@extras) {
1874                 my $extrapath = "src/modules/extra/$extra";
1875                 my $source = "src/modules/$extra";
1876                 if (!-e $extrapath) {
1877                         print STDERR "Cannot disable \e[32;1m$extra\e[0m : Is not an extra\n";
1878                         next;
1879                 }
1880                 if ((! -l $source) || readlink($source) ne "extra/$extra") {
1881                         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";
1882                         next;
1883                 }
1884                 # Check if anything needs this.
1885                 for my $file (@files) {
1886                         my @deps = split / +/, getdependencies("src/modules/extra/$file");
1887                         # File depends on this extra...
1888                         if (scalar(grep { $_ eq $extra } @deps) > 0) {
1889                                 # And is both enabled and not about to be disabled.
1890                                 if (-e "src/modules/$file" && scalar(grep { $_ eq $file } @extras) < 1) {
1891                                         print STDERR "Cannot disable \e[32;1m$extra\e[0m : is needed by \e[32;1m$file\e[0m\n";
1892                                         next EXTRA;
1893                                 }
1894                         }
1895                 }
1896                 # Now remove.
1897                 print "Disabling $extra ... \n";
1898                 unlink "src/modules/$extra" or print STDERR "Cannot disable \e[32;1m$extra\e[0m : $!\n";
1899         }
1900 }