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