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