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