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