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