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