]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - configure
Run modulemanager upgrade to check for updates to third party (and extras) modules...
[user/henk/code/inspircd.git] / configure
1 #!/usr/bin/perl
2 ###################################################
3 # InspIRCd Configuration Script
4 #
5 # Copyright 2002-2009 The InspIRCd Development Team
6 #  http://wiki.inspircd.org/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 use Socket;
30 use Cwd;
31 use Getopt::Long;
32
33 # Utility functions for our buildsystem
34 use make::utilities;
35 use make::configure;
36 use make::gnutlscert;
37 use make::opensslcert;
38
39 ###############################################################################################
40 #
41 #                                   EDITABLE VARIABLES
42 #
43 ###############################################################################################
44
45 # If you wish to ignore a dependency throughout the entire core, add it here.
46
47 our @ignoredeps = (
48         "inspircd_win32wrapper.h",      # windows has its own configure program
49 );
50
51 # If you wish for all files in the entire core to have a given dependency, insert it here.
52 # You should keep this to an absolute minimum to avoid rebuilds that are not neccessary.
53
54 our @immutabledeps = (
55         "inspircd_config.h",            # auto re-generated by configure
56         "inspircd.h",
57 );
58
59 ###############################################################################################
60 #
61 #                                 NON-EDITABLE VARIABLES
62 #
63 ###############################################################################################
64
65 # List of commands that make up 'make install' and 'make deinstall'
66
67 our $install_list = "";
68 our $uninstall_list = "";
69
70 # This is a list of all files in the core. Each cpp file is mapped to a shared object file,
71 # whos file extension is omitted (these can vary from system to system). Auto detected by
72 # scanning the src/*.cpp files for files containing /* $Core */ identifiers.
73
74 our %filelist = ();
75
76 # If you wish for a file to have special dependencies in the makefile, add an entry here.
77 # Auto populated by /* $ExtraDeps: */ instruction
78
79 our %specialdeps = ();
80
81 # If you wish for a file to have extra make lines (in between the compile and link steps)
82 # then insert them here.
83 # Auto populated by /* $ExtraBuild: */ instruction
84
85 our %extrabuildlines = ();
86
87 # If you wish for a file to be linked against extra objects or arctives, insert them here.
88 # Auto populated by /* $ExtraObjects: */ instruction
89
90 our %extraobjects = ();
91
92 # If you wish to compile extra cpp sources into an object, define them here.
93 # NOTE: Certain cpp files such as the socket engines have a value auto calculated
94 # for this table so that their derived class is built.
95 # Auto populated by /* $ExtraSources: */ instruction
96
97 our %extrasources = ();
98
99 our ($opt_use_gnutls, $opt_rebuild, $opt_use_openssl, $opt_nointeractive, $opt_ports,
100     $opt_epoll, $opt_kqueue, $opt_noports, $opt_noepoll, $opt_nokqueue,
101     $opt_ipv6, $opt_ipv6links, $opt_noipv6links, $opt_maxbuf, $opt_disable_debug,
102     $opt_freebsd_port);
103
104 our ($opt_cc, $opt_base_dir, $opt_config_dir, $opt_module_dir, $opt_binary_dir,
105     $opt_library_dir);
106
107 sub list_extras ();
108
109 sub enable_extras (@);
110
111 sub disable_extras (@);
112
113 my @opt_enableextras;
114 my @opt_disableextras;
115
116 GetOptions (
117         'enable-gnutls' => \$opt_use_gnutls,
118         'rebuild' => \$opt_rebuild,
119         'enable-openssl' => \$opt_use_openssl,
120         'disable-interactive' => \$opt_nointeractive,
121         'enable-ports' => \$opt_ports,
122         'enable-epoll' => \$opt_epoll,
123         'enable-kqueue' => \$opt_kqueue,
124         'disable-ports' => \$opt_noports,
125         'disable-epoll' => \$opt_noepoll,
126         'disable-kqueue' => \$opt_nokqueue,
127         'enable-ipv6' => \$opt_ipv6,
128         'enable-remote-ipv6' => \$opt_ipv6links,
129         'disable-remote-ipv6' => \$opt_noipv6links,
130         'with-cc=s' => \$opt_cc,
131         'with-maxbuf=i' => \$opt_maxbuf,
132         'enable-freebsd-ports-openssl' => \$opt_freebsd_port,
133         'prefix=s' => \$opt_base_dir,
134         'config-dir=s' => \$opt_config_dir,
135         'module-dir=s' => \$opt_module_dir,
136         'binary-dir=s' => \$opt_binary_dir,
137         'library-dir=s' => \$opt_library_dir,
138         'disable-debuginfo' => sub { $opt_disable_debug = 1 },
139         'help'  => sub { showhelp(); },
140         'modupdate' => sub { modupdate(); },
141         'update' => sub { update(); },
142         'svnupdate' => sub { svnupdate(); },
143         'clean' => sub { clean(); },
144         'list-extras' => sub { list_extras; exit 0; }, # This, --enable-extras, and --disable-extras are for non-interactive managing.
145         'enable-extras=s@' => \@opt_enableextras, # ^
146         'disable-extras=s@' => \@opt_disableextras, # ^
147         'generate-openssl-cert' => sub { make_openssl_cert(); exit(0); },
148         'generate-gnutls-cert' => sub { make_gnutls_cert(); exit(0); }
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}   = `pkg-config --modversion gnutls 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_POLL}     = "y";                                    # poll enabled
280 $config{USE_EPOLL}        = "y";                                        # epoll enabled
281 if (defined $opt_epoll)
282 {
283         $config{USE_EPOLL} = "y";
284 }
285 if (defined $opt_noepoll)
286 {
287         $config{USE_EPOLL} = "n";
288 }
289 $config{USE_PORTS}        = "y";                                        # epoll enabled
290 if (defined $opt_ports)
291 {
292         $config{USE_PORTS} = "y";
293 }
294 if (defined $opt_noports)
295 {
296         $config{USE_PORTS} = "n";
297 }
298 $config{IPV6}          = "n";                                           # IPv6 support (experimental)
299 if (defined $opt_ipv6)
300 {
301         $config{IPV6} = "y";
302 }
303 $config{SUPPORT_IP6LINKS}   = "y";                                      # IPv4 supporting IPv6 links (experimental)
304 if (defined $opt_ipv6links)
305 {
306         $config{SUPPORT_IP6LINKS} = "y";
307 }
308 if (defined $opt_noipv6links)
309 {
310         $config{SUPPORT_IP6LINKS} = "n";
311 }
312 chomp($config{GCCVER}       = `g++ -dumpversion | cut -c 1`);           # Major GCC Version
313 chomp($config{GCCMINOR}     = `g++ -dumpversion | cut -c 3`);
314 $config{_SOMAXCONN} = SOMAXCONN;                                        # Max connections in accept queue
315 $config{OSNAME}             = $^O;                                      # Operating System Name
316 $config{IS_DARWIN}        = "NO";                                       # Is OSX?
317 $config{STARTSCRIPT}      = "inspircd";                 # start script?
318 $config{DESTINATION}      = "BASE";                             # Is target path.
319 $config{EXTRA_DIR}        = "";                                         # Is empty.
320 if ($config{OSNAME} =~ /darwin/i)
321 {
322         $config{IS_DARWIN} = "YES";
323         $config{STARTSCRIPT}      = "org.inspircd.plist";               # start script for OSX.
324         $config{DESTINATION}      = "LAUNCHDPATH";                              # Is OSX target.
325         $config{EXTRA_DIR}          = " launchd_dir";                           # Is OSX specific path.
326 }
327 $config{CC}                 = "g++";                                            # C++ compiler
328 if (defined $opt_cc)
329 {
330         $config{CC} = $opt_cc;
331 }
332 our $exec = $config{CC} . " -dumpversion | cut -c 1";
333 chomp($config{GCCVER}           = `$exec`);                             # Major GCC Version
334 $exec = $config{CC} . " -dumpversion | cut -c 3";
335 chomp($config{GCCMINOR}         = `$exec`);
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 sub test_compile {
534         my $feature = shift;
535         my $fail = 0;
536         $fail ||= system "$config{CC} -o test_$feature make/check_$feature.cpp >/dev/null 2>&1";
537         $fail ||= system "./test_$feature";
538         unlink "test_$feature";
539         return !$fail;
540 }
541
542 print "Running non-interactive configure...\n" unless $interactive;
543 print "Checking for cache from previous configure... ";
544 print ((!getcache()) ? "not found\n" : "found\n");
545 print "Checking operating system version... ";
546 print getosflags() . "\n";
547
548 printf "Checking if stdint.h exists... ";
549 $config{HAS_STDINT} = "true";
550 our $fail = 0;
551 open(STDINT, "</usr/include/stdint.h") or $config{HAS_STDINT} = "false";
552 if ($config{HAS_STDINT} eq "true") {
553         close(STDINT);
554 }
555 print "yes\n" if $config{HAS_STDINT} eq "true";
556 print "no\n" if $config{HAS_STDINT} eq "false";
557
558 printf "Checking if strlcpy exists... ";
559 # Perform the strlcpy() test..
560 $config{HAS_STRLCPY} = "false";
561 $fail = 0;
562 open(STRLCPY, "</usr/include/string.h") or $fail = 1;
563 if (!$fail) {
564         while (defined(my $line = <STRLCPY>)) {
565                 chomp($line);
566                 # try and find the delcaration of:
567                 # size_t strlcpy(...)
568                 if ($line =~ /size_t(\0x9|\s)+strlcpy/) {
569                         $config{HAS_STRLCPY} = "true";
570                 }
571         }
572         close(STRLCPY);
573 }
574 print "yes\n" if $config{HAS_STRLCPY} eq "true";
575 print "no\n" if $config{HAS_STRLCPY} eq "false";
576
577 printf "Checking if kqueue exists... ";
578 $has_kqueue = 0;
579 $fail = 0;
580 open(KQUEUE, "</usr/include/sys/event.h") or $fail = 1;
581 if (!$fail) {
582         while (defined(my $line = <KQUEUE>)) {
583                 chomp($line);
584                 # try and find the delcaration of:
585                 # int kqueue(void);
586                 if ($line =~ /int(\0x9|\s)+kqueue/) {
587                         $has_kqueue = 1;
588                 }
589         }
590         close(KQUEUE);
591 }
592 print "yes\n" if $has_kqueue == 1;
593 print "no\n" if $has_kqueue == 0;
594
595 printf "Checking for epoll support... ";
596 $has_epoll = test_compile('epoll');
597 print $has_epoll ? "yes\n" : "no\n";
598
599 printf "Checking for eventfd support... ";
600 $config{HAS_EVENTFD} = test_compile('eventfd') ? 'true' : 'false';
601 print $config{HAS_EVENTFD} eq 'true' ? "yes\n" : "no\n";
602
603 printf "Checking if Solaris I/O completion ports are available... ";
604 $has_ports = 0;
605 our $system = `uname -s`;
606 chomp ($system);
607 $has_ports = 1 if ($system eq "SunOS");
608
609 if ($has_ports) {
610         my $kernel = `uname -r`;
611         chomp($kernel);
612         if (($kernel !~ /^5\.1./)) {
613                 $has_ports = 0;
614         }
615 }
616 print "yes\n" if $has_ports == 1;
617 print "no\n" if $has_ports == 0;
618
619 $config{HAS_EPOLL} = $has_epoll;
620 $config{HAS_KQUEUE} = $has_kqueue;
621
622 printf "Checking for libgnutls... ";
623 if (defined($config{HAS_GNUTLS}) && (($config{HAS_GNUTLS}) || ($config{HAS_GNUTLS} eq "y"))) {
624         if (defined($gnutls_ver) && ($gnutls_ver ne "")) {
625                 print "yes\n";
626                 $config{HAS_GNUTLS} = "y";
627         } else {
628                 print "no\n";
629                 $config{HAS_GNUTLS} = "n";
630         }
631 } else {
632         print "no\n";
633         $config{HAS_GNUTLS} = "n";
634 }
635
636 printf "Checking for openssl... ";
637 if (defined($config{HAS_OPENSSL}) && (($config{HAS_OPENSSL}) || ($config{HAS_OPENSSL} eq "y"))) {
638         if (defined($openssl_ver) && ($openssl_ver ne "")) {
639                 print "yes\n";
640                 $config{HAS_OPENSSL} = "y";
641         } else {
642                 print "no\n";
643                 $config{HAS_OPENSSL} = "n";
644         }
645 } else {
646         print "no\n";
647         $config{HAS_OPENSSL} = "n";
648 }
649
650 printf "Checking if you are running an ancient, unsupported OS... ";
651 if ($config{OSNAME} =~ /FreeBSD/i)
652 {
653         my $version = `uname -r`;
654         if ($version =~ /^4\./)
655         {
656                 my $foundit = `ls -l /usr/local/lib/libgnugetopt* | wc -l`;
657                 if ($foundit > 0)
658                 {
659                         # ICKY ICKY ICK, FREEBSD 4.x! GET AN UPGRADE!
660                         $config{CRAQ} = "-L/usr/local/lib -lgnugetopt -DHAVE_DECL_GETOPT=1";
661                         print "yes (upgrade ffs, freebsd 4 is *way* out of date)\n";
662                 }
663                 else
664                 {
665                         print "\n\nERROR: You require libgnugetopt (from ports or packages) to build InspIRCd on FreeBSD 4.11.\n";
666                 }
667         }
668         else
669         {
670                 $config{CRAQ} = " ";
671                 print "no ($version)\n";
672         }
673 }
674 else
675 {
676         $config{CRAQ} = " ";
677         print "no ($config{OSNAME})\n";
678 }
679
680 print "Checking for upgrades to extra and third party modules... ";
681 system "./modulemanager upgrade";
682
683 ################################################################################
684 #                         BEGIN INTERACTIVE PART                              #
685 ################################################################################
686
687 # Clear the Screen..
688 if ($interactive)
689 {
690         print "\e[2J\e[0G\e[0d"; # J = Erase in Display, 2 = Entire Screen, (G, d) = Move cursor to (..,..)
691         my $wholeos = $^O;
692
693         my $rev = getrevision();
694         # Display Introduction Message..
695         print <<"STOP" ;
696 Welcome to the \e[1mInspIRCd\e[0m Configuration program! (\e[1minteractive mode\e[0m)
697 \e[1mPackage maintainers: Type ./configure --help for non-interactive help\e[0m
698
699 *** If you are unsure of any of these values, leave it blank for    ***
700 *** standard settings that will work, and your server will run      ***
701 *** using them. Please consult your IRC network admin if in doubt.  ***
702
703 Press \e[1m<RETURN>\e[0m to accept the default for any option, or enter
704 a new value. Please note: You will \e[1mHAVE\e[0m to read the docs
705 dir, otherwise you won't have a config file!
706
707 Your operating system is: \e[1;32m$config{OSNAME}\e[0m ($wholeos)
708 Your InspIRCd revision ID is \e[1;32mr$rev\e[0m
709 STOP
710         if ($rev eq "r0") {
711                 print " (Non-SVN build)";
712         }
713         print ".\n\n";
714
715         $config{CHANGE_COMPILER} = "n";
716         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";
717
718         while (($config{GCCVER} < 3) || ($config{GCCVER} eq "")) {
719                 print "\e[1;32mIMPORTANT!\e[0m A GCC 2.x compiler has been detected, and
720 should NOT be used. You should probably specify a newer compiler.\n\n";
721                 yesno('CHANGE_COMPILER',"Do you want to change the compiler?");
722                 if ($config{CHANGE_COMPILER} =~ /y/i) {
723                         print "What command do you want to use to invoke your compiler?\n";
724                         print "[\e[1;32m$config{CC}\e[0m] -> ";
725                         chomp($config{CC} = <STDIN>);
726                         if ($config{CC} eq "") {
727                                 $config{CC} = "g++";
728                         }
729                         chomp(my $foo = `$config{CC} -dumpversion | cut -c 1`);
730                         if ($foo ne "") {
731                                 chomp($config{GCCVER}       = `$config{CC} -dumpversion | cut -c 1`); # we must redo these if we change compilers
732                                 chomp($config{GCCMINOR}     = `$config{CC} -dumpversion | cut -c 3`);
733                                 print "Queried compiler: \e[1;32m$config{CC}\e[0m (version \e[1;32m$config{GCCVER}.$config{GCCMINOR}\e[0m)\n";
734                                 if ($config{GCCVER} < 3) {
735                                         print "\e[1;32mGCC 2.x WILL NOT WORK!\e[0m. Let's try that again, shall we?\n";
736                                 }
737                         }
738                         else {
739                                 print "\e[1;32mWARNING!\e[0m Could not execute the compiler you specified. You may want to try again.\n";
740                         }
741                 }
742         }
743
744         print "\n";
745
746         # Directory Settings..
747         my $tmpbase = $config{BASE_DIR};
748         dir_check("do you wish to install the InspIRCd base", "BASE_DIR");
749         if ($tmpbase ne $config{BASE_DIR}) {
750                 $config{CONFIG_DIR}      = resolve_directory($config{BASE_DIR}."/conf");           # Configuration Dir
751                 $config{MODULE_DIR}      = resolve_directory($config{BASE_DIR}."/modules");     # Modules Directory
752                 $config{BINARY_DIR}      = resolve_directory($config{BASE_DIR}."/bin");     # Binary Directory
753                 $config{LIBRARY_DIR}    = resolve_directory($config{BASE_DIR}."/lib");      # Library Directory
754         }
755
756         dir_check("are the configuration files", "CONFIG_DIR");
757         dir_check("are the modules to be compiled to", "MODULE_DIR");
758         dir_check("is the IRCd binary to be placed", "BINARY_DIR");
759         dir_check("are the IRCd libraries to be placed", "LIBRARY_DIR");
760
761         my $chose_hiperf = 0;
762         if ($has_kqueue) {
763                 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?");
764                 print "\n";
765                 if ($config{USE_KQUEUE} eq "y") {
766                         $chose_hiperf = 1;
767                 }
768         }
769         if ($has_epoll) {
770                 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?");
771                 print "\n";
772                 if ($config{USE_EPOLL} eq "y") {
773                         $chose_hiperf = 1;
774                 }
775         }
776         if ($has_ports) {
777                 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?");
778                 print "\n";
779                 if ($config{USE_PORTS} eq "y") {
780                         $chose_hiperf = 1;
781                 }
782         }
783
784         if (!$chose_hiperf) {
785                 yesno('USE_POLL', "Would you like to use poll?\n This is likely to increase performance.\nIf you are unsure, answer yes.\n\nEnable poll?\n");
786                 if ($config{USE_POLL} ne "y")
787                 {
788                         print "No high-performance socket engines are available, or you chose\n";
789                         print "not to enable one. Defaulting to select() engine.\n\n";
790                 }
791         }
792
793         yesno('IPV6',"Would you like to build InspIRCd with IPv6 support?");
794         print "\n";
795
796         if ($config{IPV6} eq "y") {
797                 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";
798                 $config{SUPPORT_IP6LINKS} = "y";
799         } else {
800                 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?");
801                 print "\n";
802         }
803
804         $config{USE_FREEBSD_BASE_SSL} = "n";
805         $config{USE_FREEBSD_PORTS_SSL} = "n";
806         if ($config{HAS_OPENSSL_PORT} ne "")
807         {
808                 $config{USE_FREEBSD_PORTS_SSL} = "y";
809                 print "I have detected the OpenSSL FreeBSD port installed on your system,\n";
810                 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";
811                 yesno('USE_FREEBSD_PORTS_SSL', "Do you want to use the FreeBSD ports version?");
812                 print "\n";
813                 $config{USE_FREEBSD_BASE_SSL} = "y" if ($config{USE_FREEBSD_PORTS_SSL} eq "n");
814
815                 if ($config{USE_FREEBSD_BASE_SSL} eq "n")
816                 {
817                         # update to port version
818                         $openssl_ver = $config{HAS_OPENSSL_PORT};
819                 }
820         }
821         else
822         {
823                 $config{USE_FREEBSD_BASE_SSL} = "y" if ($^O eq "freebsd");
824         }
825
826         $config{USE_SSL} = "n";
827
828         if ($config{HAS_GNUTLS} eq "y" || $config{HAS_OPENSSL} eq "y")
829         {
830                 print "Detected GnuTLS version: \e[1;32m" . $gnutls_ver . "\e[0m\n";
831                 print "Detected OpenSSL version: \e[1;32m" . $openssl_ver . "\e[0m\n\n";
832
833                 yesno('USE_SSL', "One or more SSL libraries detected. Would you like to enable SSL support?");
834                 if ($config{USE_SSL} eq "y")
835                 {
836                         if ($config{HAS_GNUTLS} eq "y")
837                         {
838                                 yesno('USE_GNUTLS',"Would you like to enable SSL with m_ssl_gnutls? (recommended)");
839                                 if ($config{USE_GNUTLS} eq "y")
840                                 {
841                                         print "\nUsing GnuTLS SSL module.\n";
842                                 }
843                         }
844
845                         if ($config{HAS_OPENSSL} eq "y")
846                         {
847                                 yesno('USE_OPENSSL', "Would you like to enable SSL with m_ssl_openssl?");
848                                 if ($config{USE_OPENSSL} eq "y")
849                                 {
850                                         print "\nUsing OpenSSL SSL module.\nYou will get better performance if you move to GnuTLS in the future.\n";
851                                 }
852                         }
853                 }
854         }
855         else
856         {
857                 print "\nCould not detect OpenSSL or GnuTLS. Make sure pkg-config is installed if\n";
858                 print "you intend to use OpenSSL, or that GnuTLS is in your path if you intend\nto use GnuTLS.\n\n";
859         }
860 }
861
862 dumphash();
863
864 if (($config{USE_GNUTLS} eq "y") && ($config{HAS_GNUTLS} ne "y"))
865 {
866         print "Sorry, but i couldn't detect gnutls. Make sure gnutls-config is in your path.\n";
867         exit(0);
868 }
869 if (($config{USE_OPENSSL} eq "y") && ($config{HAS_OPENSSL} ne "y"))
870 {
871         print "Sorry, but i couldn't detect openssl. Make sure openssl is in your path.\n";
872         exit(0);
873 }
874 our $failed = 0;
875
876 $config{CERTGEN} ||= 'y';
877 yesno('CERTGEN',"Would you like generate SSL certificates now?") if ($interactive && ($config{USE_GNUTLS} eq "y" || $config{USE_OPENSSL} eq "y"));
878
879 if ($config{USE_GNUTLS} eq "y") {
880         unless (-r "src/modules/m_ssl_gnutls.cpp") {
881                 print "Symlinking src/modules/m_ssl_gnutls.cpp from extra/\n";
882                 symlink "extra/m_ssl_gnutls.cpp", "src/modules/m_ssl_gnutls.cpp" or print STDERR "Symlink failed: $!";
883         }
884         if ($interactive && $config{CERTGEN} eq 'y')
885         {
886                 unless (-r "$config{CONFIG_DIR}/key.pem" && -r "$config{CONFIG_DIR}/cert.pem") {
887                         print "SSL Certificates Not found, Generating.. \n\n
888 *************************************************************
889 * Generating the Private Key may take some time, go grab a  *
890 * Coffee. Even better, to generate some more entropy if it  *
891 * is taking a while, open another console and type du / a   *
892 * few times and get that HD going :) Then answer the        *
893 * Questions which follow. If you are unsure, just hit enter *
894 *************************************************************\n\n";
895                         $failed = make_gnutls_cert();
896                         if ($failed) {
897                                 print "\n\e[1;32mCertificate generation failed!\e[0m\n\n";
898                         } else {
899                                 print "\nCertificate generation complete, copying to config directory... ";
900                                 File::Copy::move("key.pem", "$config{CONFIG_DIR}/key.pem") or print STDERR "Could not copy key.pem!\n";
901                                 File::Copy::move("cert.pem", "$config{CONFIG_DIR}/cert.pem") or print STDERR "Could not copy cert.pem!\n";
902                                 print "Done.\n\n";
903                         }
904                 }
905                 else {
906                         print "SSL Certificates found, skipping.\n\n";
907                 }
908         }
909         else
910         {
911                 print "Skipping SSL certificate generation\nin non-interactive mode.\n\n";
912         }
913 }
914
915 if ($config{USE_OPENSSL} eq "y") {
916         unless (-r "src/modules/m_ssl_openssl.cpp") {
917                 print "Symlinking src/modules/m_ssl_openssl.cpp from extra/\n";
918                 symlink "extra/m_ssl_openssl.cpp", "src/modules/m_ssl_openssl.cpp" or print STDERR "Symlink failed: $!";
919         }
920         $failed = 0;
921         if ($interactive && $config{CERTGEN} eq 'y')
922         {
923                 unless (-r "$config{CONFIG_DIR}/key.pem" && -r "$config{CONFIG_DIR}/cert.pem") {
924                         print "SSL Certificates Not found, Generating.. \n\n
925 *************************************************************
926 * Generating the certificates may take some time, go grab a *
927 * coffee, or something.                                     *
928 *************************************************************\n\n";
929                         make_openssl_cert();
930                         print "\nCertificate generation complete, copying to config directory... ";
931                         File::Copy::move("key.pem", "$config{CONFIG_DIR}/key.pem") or print STDERR "Could not copy key.pem!\n";
932                         File::Copy::move("cert.pem", "$config{CONFIG_DIR}/cert.pem") or print STDERR "Could not copy cert.pem!\n";
933                         File::Copy::move("dhparams.pem", "$config{CONFIG_DIR}/dhparams.pem") or print STDERR "Could not copy dhparams.pem!\n";
934                         print "Done.\n\n";
935                 } else {
936                         print "SSL Certificates found, skipping.\n\n"
937                 }
938         }
939         else
940         {
941                 print "Skipping SSL certificate generation\nin non-interactive mode.\n\n";
942         }
943 }
944 if (($config{USE_GNUTLS} eq "n") && ($config{USE_OPENSSL} eq "n")) {
945         print "Skipping SSL Certificate generation, SSL support is not available.\n\n";
946 }
947
948 getosflags();
949 writefiles(1);
950 makecache();
951
952 print "\n\n";
953 print "To build your server with these settings, please type '\e[1;32m$config{MAKEPROG}\e[0m' now.\n";
954 if (($config{USE_GNUTLS} eq "y") || ($config{USE_OPENSSL} eq "y")) {
955         print "Please note: for \e[1;32mSSL support\e[0m you will need to load required\n";
956         print "modules in your config. This configure script has added those modules to the\n";
957         print "build process. For more info please refer to:\n";
958         print "\e[1;32mhttp://wiki.inspircd.org/Installation_From_Tarball\e[0m\n";
959 }
960 print "*** \e[1;32mRemember to edit your configuration files!!!\e[0m ***\n\n\n";
961 if (($config{OSNAME} eq "OpenBSD") && ($config{CC} ne "eg++")) {
962         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";
963 }
964
965 if ($config{GCCVER} < "3") {
966         print <<FOO2;
967 \e[1;32mWARNING!\e[0m You are attempting to compile InspIRCd on GCC 2.x!
968 GCC 2.x series compilers only had partial (read as broken) C++ support, and
969 your compile will most likely fail horribly! If you have any problems, do NOT
970 report them to the bugtracker or forums without first upgrading your compiler
971 to a newer 3.x or 4.x (or whatever is available currently) version.
972 FOO2
973 }
974
975 ################################################################################
976 #                             HELPER FUNCTIONS                          #
977 ################################################################################
978 sub getcache {
979         # Retrieves the .config.cache file, and loads values into the main config hash.
980         open(CACHE, ".config.cache") or return 0;
981         while (<CACHE>) {
982                 chomp;
983                 # Ignore Blank lines, and comments..
984                 next if /^\s*$/;
985                 next if /^\s*#/;
986                 my ($key, $value) = split("=", $_, 2);
987                 $value =~ /^\"(.*)\"$/;
988                 # Do something with data here!
989                 $config{$key} = $1;
990         }
991         close(CACHE);
992         return 1;
993 }
994
995 sub makecache {
996         # Dump the contents of %config
997         print "Writing \e[1;32mcache file\e[0m for future ./configures ...\n";
998         open(FILEHANDLE, ">.config.cache");
999         foreach my $key (keys %config) {
1000                 print FILEHANDLE "$key=\"$config{$key}\"\n";
1001         }
1002         close(FILEHANDLE);
1003 }
1004
1005 sub dir_check {
1006         my ($desc, $hash_key) = @_;
1007         my $complete = 0;
1008         while (!$complete) {
1009                 print "In what directory $desc?\n";
1010                 print "[\e[1;32m$config{$hash_key}\e[0m] -> ";
1011                 chomp(my $var = <STDIN>);
1012                 if ($var eq "") {
1013                         $var = $config{$hash_key};
1014                 }
1015                 if ($var =~ /^\~\/(.+)$/) {
1016                         # Convert it to a full path..
1017                         $var = resolve_directory($ENV{HOME} . "/" . $1);
1018                 }
1019                 elsif ((($config{OSNAME} =~ /MINGW32/i) and ($var !~ /^[A-Z]{1}:\\.*/)) and (substr($var,0,1) ne "/"))
1020                 {
1021                         # Assume relative Path was given.. fill in the rest.
1022                         $var = $this . "/$var";
1023                 }
1024
1025                 $var = resolve_directory($var);
1026                 if (! -e $var) {
1027                         print "$var does not exist. Create it?\n[\e[1;32my\e[0m] ";
1028                         chomp(my $tmp = <STDIN>);
1029                         if (($tmp eq "") || ($tmp =~ /^y/i)) {
1030                                 # Attempt to Create the Dir..
1031                                 my $chk = eval {
1032                                         use File::Path ();
1033                                         File::Path::mkpath($var, 0, 0777);
1034                                         1;
1035                                 };
1036                                 unless (defined($chk) && -d $var) {
1037                                         print "Unable to create directory. ($var)\n\n";
1038                                         # Restart Loop..
1039                                         next;
1040                                 }
1041                         } else {
1042                                 # They said they don't want to create, and we can't install there.
1043                                 print "\n\n";
1044                                 next;
1045                         }
1046                 } else {
1047                         if (!is_dir($var)) {
1048                                 # Target exists, but is not a directory.
1049                                 print "File $var exists, but is not a directory.\n\n";
1050                                 next;
1051                         }
1052                 }
1053                 # Either Dir Exists, or was created fine.
1054                 $config{$hash_key} = $var;
1055                 $complete = 1;
1056                 print "\n";
1057         }
1058 }
1059
1060 our $SHARED = "";
1061
1062 sub getosflags {
1063
1064         # Beware: Linux sets it's own cflags below for some retarded reason
1065         $config{LDLIBS} = "-pthread -lstdc++";
1066         $config{FLAGS}  = "-pipe -fPIC -Woverloaded-virtual -Wshadow -Wformat=2 -Wmissing-format-attribute -Wall $config{OPTIMISATI}";
1067         $config{DEVELOPER} = "-pipe -fPIC -Woverloaded-virtual -Wshadow -Wall -Wformat=2 -Wmissing-format-attribute -g";
1068         $SHARED = "-shared -export-dynamic";
1069         $config{MAKEPROG} = "make";
1070
1071         if ($config{OSNAME} =~ /darwin/i) {
1072                 $config{FLAGS}  = "-pipe -DDARWIN -frtti -fPIC -Wall $config{OPTIMISATI}";
1073                 $SHARED = "-bundle -twolevel_namespace -undefined dynamic_lookup";
1074                 $config{LDLIBS} = "-ldl -pthread -lstdc++";
1075         }
1076
1077         if ($config{OSNAME} =~ /OpenBSD/i) {
1078                 $config{MAKEPROG} = "gmake";
1079 # apparantly (Dagonet says) that this causes problems, so let's try without it.
1080 #               $config{LDLIBS} = $config{LDLIBS} . " -lunwind";
1081                 chomp(my $foo = `eg++ -dumpversion | cut -c 1`);
1082                 # theyre running the package version of gcc (eg++)... detect it and set up its version numbers.
1083                 # if theyre not running this, configure lets the build continue but they probably wont manage to
1084                 # compile as this standard version is 2.95.3!
1085                 if ($foo ne "") {
1086                         $config{CC} = "eg++";
1087                         chomp($config{GCCVER}       = `eg++ -dumpversion | cut -c 1`); # we must redo these if we change the compiler path
1088                         chomp($config{GCCMINOR}     = `eg++ -dumpversion | cut -c 3`);
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 #define ENTRYPOINT int main(int argc, char** argv)
1159
1160 EOF
1161 print FILEHANDLE "#define MAXBUF " . ($config{MAXBUF}+2) . "\n";
1162
1163                 if ($config{OSNAME} =~ /SunOS/i) {
1164                         print FILEHANDLE "#define IS_SOLARIS\n";
1165                 }
1166                 if ($config{OSNAME} =~ /MINGW32/i) {
1167                         print FILEHANDLE "#define IS_MINGW\n";
1168                 }
1169                 if ($config{GCCVER} >= 3) {
1170                         print FILEHANDLE "#define GCC3\n";
1171                 }
1172                 if (
1173                         (($config{GCCVER} == 4) && ($config{GCCMINOR} >= 3))
1174                                 ||
1175                         ($config{GCCVER} > 4)
1176                 ) {
1177                         print FILEHANDLE "#define HASHMAP_DEPRECATED\n";
1178                 }
1179                 if ($config{HAS_STRLCPY} eq "true") {
1180                         print FILEHANDLE "#define HAS_STRLCPY\n";
1181                 }
1182                 if ($config{HAS_STDINT} eq "true") {
1183                         print FILEHANDLE "#define HAS_STDINT\n";
1184                 }
1185                 if ($config{IPV6} =~ /y/i) {
1186                         print FILEHANDLE "#define IPV6\n";
1187                 }
1188                 if ($config{SUPPORT_IP6LINKS} =~ /y/i) {
1189                         print FILEHANDLE "#define SUPPORT_IP6LINKS\n";
1190                 }
1191                 if ($config{HAS_EVENTFD} eq 'true') {
1192                         print FILEHANDLE "#define HAS_EVENTFD\n";
1193                 }
1194                 my $use_hiperf = 0;
1195                 if (($has_kqueue) && ($config{USE_KQUEUE} eq "y")) {
1196                         print FILEHANDLE "#define USE_KQUEUE\n";
1197                         $se = "socketengine_kqueue";
1198                         $use_hiperf = 1;
1199                 }
1200                 if (($has_epoll) && ($config{USE_EPOLL} eq "y")) {
1201                         print FILEHANDLE "#define USE_EPOLL\n";
1202                         $se = "socketengine_epoll";
1203                         $use_hiperf = 1;
1204                 }
1205                 if (($has_ports) && ($config{USE_PORTS} eq "y")) {
1206                         print FILEHANDLE "#define USE_PORTS\n";
1207                         $se = "socketengine_ports";
1208                         $use_hiperf = 1;
1209                 }
1210                 # user didn't choose either epoll or select for their OS.
1211                 # default them to USE_SELECT (ewwy puke puke)
1212                 if (!$use_hiperf) {
1213                         print "no hi-perf, " . $config{USE_POLL};
1214                         if ($config{USE_POLL} eq "y")
1215                         {
1216                                 print FILEHANDLE "#define USE_POLL\n";
1217                                 $se = "socketengine_poll";
1218                         }
1219                         else
1220                         {
1221                                 print FILEHANDLE "#define USE_SELECT\n";
1222                                 $se = "socketengine_select";
1223                         }
1224                 }
1225                 print FILEHANDLE "\n#include \"threadengines/threadengine_pthread.h\"\n\n#endif\n";
1226                 close(FILEHANDLE);
1227         }
1228
1229         if ($writeheader)
1230         {
1231                 open(FILEHANDLE, ">include/inspircd_se_config.h");
1232                 print FILEHANDLE <<EOF;
1233 /* Auto generated by configure, do not modify or commit to svn! */
1234 #ifndef __CONFIGURATION_SOCKETENGINE__
1235 #define __CONFIGURATION_SOCKETENGINE__
1236
1237 #include "socketengines/$se.h"
1238
1239 #endif
1240 EOF
1241                 close(FILEHANDLE);
1242         }
1243
1244
1245         # Create a Modules List..
1246         my $modules = "";
1247         foreach my $i (@modlist)
1248         {
1249                 $modules .= "m_".$i.".so ";
1250         }
1251         chomp($modules);   # Remove Redundant whitespace..
1252
1253         opendir(DIRHANDLE, "src/modules");
1254         foreach my $name2 (sort readdir(DIRHANDLE)) {
1255                 if ($name2 =~ /^m_(.+?)$/) {
1256                         if (defined(opendir(MDIRHANDLE, "src/modules/$name2"))) {
1257                                 closedir(MDIRHANDLE);
1258                                 $modules .= "$name2.so ";
1259                                 $uninstall_list = $uninstall_list . "   -rm \$(MODPATH)/$name2.so\n";
1260                         }
1261                 }
1262         }
1263         closedir(DIRHANDLE);
1264
1265
1266         # Write all .in files.
1267         my $tmp = "";
1268         my $file = "";
1269         my $exe = "inspircd";
1270
1271         # Do this once here, and cache it in the .*.inc files,
1272         # rather than attempting to read src/version.sh from
1273         # compiled code -- we might not have the source to hand.
1274         # Fix for bug#177 by Brain.
1275
1276         chomp($version = `sh ./src/version.sh`);
1277         chomp(my $revision = getrevision());
1278         $version = "$version(r$revision)";
1279
1280         # We can actually parse any file starting with . and ending with .inc,
1281         # but right now we only parse .inspircd.inc to form './inspircd'
1282
1283         print "Writing \e[1;32mMakefiles\e[0m\n";
1284         write_dynamic_modules_makefile();
1285         write_dynamic_makefile();
1286
1287         opendir(DIRHANDLE, $this);
1288
1289         foreach my $name (sort readdir(DIRHANDLE)) {
1290                 if ($name =~ /^\.(.+)\.inc$/) {
1291                         $file = $1;
1292
1293                         # Bug #353, omit this on non-darwin
1294                         next if (($config{OSNAME} !~ /darwin/) && ($file eq "org.inspircd.plist"));
1295
1296                         # All .name.inc files need parsing!
1297                         open(FILEHANDLE, ".$file.inc") or die ("Can't open .$file.inc");
1298                         $_ = join '', <FILEHANDLE>;
1299                         close(FILEHANDLE);
1300
1301                         print "Writing \e[1;32m$file\e[0m ...\n";
1302                         for my $var (qw(
1303                                 CC FLAGS DEVELOPER LDLIBS BASE_DIR CONFIG_DIR MODULE_DIR BINARY_DIR LIBRARY_DIR
1304                                 STARTSCRIPT DESTINATION EXTRA_DIR
1305                         )) {
1306                                 s/\@$var\@/$config{$var}/g;
1307                         }
1308                         s/\@MODULES\@/$modules/ if defined $modules;
1309                         s/\@EXECUTABLE\@/$exe/ if defined $exe;
1310                         s/\@VERSION\@/$version/ if defined $version;
1311                         s/\@INSTALL_LIST\@/$install_list/ if defined $install_list;
1312                         s/\@UNINSTALL_LIST\@/$uninstall_list/ if defined $uninstall_list;
1313
1314                         if ($file eq 'Makefile') {
1315                                 my $mk_tmp = $_;
1316                                 s/\@IFDEF (\S+)/ifdef $1/g;
1317                                 s/\@IFNDEF (\S+)/ifndef $1/g;
1318                                 s/\@ELSE/else/g;
1319                                 s/\@ENDIF/endif/g;
1320                                 s/\@BSD_ONLY .*\n//g;
1321                                 s/\@GNU_ONLY //g;
1322                                 open MKF, '>GNUmakefile' or die "Can't write to GNUmakefile: $!";
1323                                 print MKF $_;
1324                                 close MKF;
1325                                 $_ = $mk_tmp;
1326                                 s/\@IFDEF (\S+)/.if defined($1)/g;
1327                                 s/\@IFNDEF (\S+)/.if !defined($1)/g;
1328                                 s/\@ELSE/.else/g;
1329                                 s/\@ENDIF/.endif/g;
1330                                 s/\@BSD_ONLY //g;
1331                                 s/\@GNU_ONLY .*\n//g;
1332                                 open MKF, '>BSDmakefile' or die "Can't write to BSDmakefile: $!";
1333                                 print MKF $_;
1334                                 close MKF;
1335                         } else {
1336                                 open(FILEHANDLE, ">$file") or die("Can't write to $file: $!\n");
1337                                 print FILEHANDLE $_;
1338                                 close(FILEHANDLE);
1339                         }
1340                 }
1341         }
1342         closedir(DIRHANDLE);
1343
1344         # Make inspircd executable!
1345         chmod 0744, 'inspircd';
1346 }
1347
1348 sub write_dynamic_modules_makefile {
1349         # Modules Makefile..
1350         print "Writing \e[1;32msrc/modules/Makefile\e[0m\n";
1351         open(FILEHANDLE, ">src/modules/Makefile");
1352
1353 ###
1354 # Module Makefile Header
1355 ###
1356         print FILEHANDLE <<EOF;
1357 ###################################################
1358 # Copyright 2002-2009 The InspIRCd Development Team
1359 #  http://wiki.inspircd.org/Credits
1360 #
1361 # Thanks to Andrew Church <achurch\@achurch.org>
1362 #   for assisting with making this work right.
1363 #
1364 # Automatically Generated by ./configure to add a
1365 #  modules please run ./configure -modupdate
1366 ###################################################
1367
1368 all: \$(MODULES)
1369
1370 EOF
1371
1372 if ($config{OSNAME} =~ /darwin/) {
1373                 print FILEHANDLE <<EOCHEESE;
1374
1375 PICLDFLAGS = -twolevel_namespace -undefined dynamic_lookup -bundle
1376
1377 EOCHEESE
1378 } else {
1379                 print FILEHANDLE <<EOCHEESE;
1380
1381 PICLDFLAGS = -fPIC -DPIC -shared
1382
1383 EOCHEESE
1384 }
1385
1386         ###
1387         # End Module Makefile Header
1388         ###
1389
1390         # Create a Modules List..
1391         my $modules = "";
1392         my $cmflags = "";
1393         my $liflags = "";
1394         foreach my $i (@modlist) {
1395                 ###
1396                 # Write Entry to the MakeFile
1397                 ###
1398                 $cmflags = getcompilerflags("src/modules/m_".$i.".cpp");
1399                 $liflags = getlinkerflags("src/modules/m_".$i.".cpp");
1400                 my $deps = getdependencies("src/modules/m_".$i.".cpp");
1401
1402                 #print "file: $i: cmflags=$cmflags; liflags=$liflags; deps=$deps\n";
1403
1404
1405                 if (nopedantic("src/modules/m_".$i.".cpp"))
1406                 {
1407                         print FILEHANDLE "
1408 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
1409         \$(RUNCC) \$(NICEFLAGS) $cmflags \$(PICLDFLAGS) $liflags $SHARED -o m_$i.so m_$i.cpp
1410 ";
1411                 }
1412                 else
1413                 {
1414                         print FILEHANDLE "
1415 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
1416         \$(RUNCC) \$(FLAGS) $cmflags \$(PICLDFLAGS) $liflags $SHARED -o m_$i.so m_$i.cpp
1417 ";
1418                 }
1419                 $install_list = $install_list . "       install -m \$(INSTMODE) src/modules/m_$i.so \$(MODPATH)\n";
1420                 $uninstall_list = $uninstall_list . "   -rm \$(MODULES)/m_$i.so\n";
1421                 ###
1422                 # End Write Entry to the MakeFile
1423                 ###
1424         }
1425
1426         opendir(DIRHANDLE, "src/modules");
1427         foreach my $name (sort readdir(DIRHANDLE)) {
1428                 if ($name =~ /^m_(.+?)$/) {
1429                         $mfrules = "";
1430                         $mobjs = "";
1431                         $mliflags = "";
1432                         $mfcount = 0;
1433                         # A module made of multiple files, in a dir, e.g. src/modules/m_spanningtree/
1434                         if (defined(opendir(MDIRHANDLE, "src/modules/$name"))) {
1435                                 read_module_directory("src/modules/$name", $name);
1436                                 print "Composing Makefile rules for directory \e[1;32m$name\e[0m... (\e[1;32m$mfcount files found\e[0m)\n";
1437                                 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";
1438                                 print FILEHANDLE "      \$(RUNCC) \$(FLAGS) $SHARED $mliflags -o $name.so $mobjs\n";
1439                                 print FILEHANDLE "\n$mfrules\n";
1440                                 closedir(MDIRHANDLE);
1441                                 $install_list = $install_list . "       install -m \$(INSTMODE) src/modules/$name.so \$(MODPATH)\n";
1442                         }
1443                 }
1444         }
1445         closedir(DIRHANDLE);
1446 }
1447
1448 sub read_module_directory {
1449         my ($dpath, $reldpath) = @_;
1450
1451         if (opendir(MDIRHANDLE, $dpath) == 0) {
1452                 return;
1453         }
1454
1455         foreach my $fname (sort readdir(MDIRHANDLE)) {
1456                 if ($fname =~ /\.cpp$/) {
1457                         my $cmflags = getcompilerflags("$dpath/$fname");
1458                         $mliflags = $mliflags . " " . getlinkerflags("$dpath/$fname");
1459                         my $deps = getdependencies("$dpath/$fname");
1460                         my $oname = $fname;
1461                         $oname =~ s/\.cpp$/.o/g;
1462                         $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";
1463                         $mfrules = $mfrules .  "        \$(RUNCC) -I. \$(FLAGS) $cmflags $SHARED -o $reldpath/$oname -c $reldpath/$fname\n\n";
1464                         $mobjs = $mobjs . " $reldpath/$oname";
1465                         $mfcount++;
1466                 }
1467                 elsif ((-d "$dpath/$fname") && !($fname eq ".") && !($fname eq "..")) {
1468                         read_module_directory($dpath."/".$fname, $reldpath."/".$fname);
1469                 }
1470         }
1471 }
1472
1473 sub calcdeps($)
1474 {
1475         # Yes i know we could use gcc -M but it seems to ideneify a lot of 'deep'
1476         # dependencies which are not relevent in C++.
1477
1478         my $file = $_[0];
1479
1480         open (CPP, "<$file") or die("Can't open $file for reading!");
1481
1482         my %dupe = ();
1483         my $retlist = "";
1484
1485         foreach my $d (@ignoredeps)
1486         {
1487                 $dupe{$d} = 1;
1488         }
1489
1490         my $immutable = "";
1491         foreach my $dep (@immutabledeps)
1492         {
1493                 $immutable = $immutable . "../include/$dep ";
1494         }
1495         $immutable =~ s/ $//g;
1496
1497         while (defined(my $line = <CPP>))
1498         {
1499                 chomp($line);
1500                 if ($line =~ /#include "(.+\.h)"/)
1501                 {
1502                         if (!exists($dupe{$1}))
1503                         {
1504                                 $retlist = $retlist . "../include/$1 ";
1505                                 $dupe{$1} = 1;
1506                         }
1507                 }
1508         }
1509         close CPP;
1510         return length($immutable) ? $immutable . " " . $retlist : $retlist;
1511 }
1512
1513 sub write_dynamic_makefile
1514 {
1515         my $i = 0;
1516         my @cmdlist = ();
1517         my %existing_install_list = ();
1518         my %core_files_list = ();
1519
1520         opendir(DIRHANDLE, "src/commands");
1521         foreach my $name (sort readdir(DIRHANDLE))
1522         {
1523                 if ($name =~ /^cmd_(.+)\.cpp$/)
1524                 {
1525                         $cmdlist[$i++] = $1;
1526                         $install_list = $install_list . "       -install -m \$(INSTMODE) src/commands/cmd_" . $1 . ".so \$(LIBPATH)\n";
1527                         $uninstall_list = $uninstall_list . "   -rm \$(LIBPATH)/cmd_$1.so\n";
1528                 }
1529         }
1530         closedir(DIRHANDLE);
1531
1532         if (!$has_epoll)
1533         {
1534                 $config{USE_EPOLL} = 0;
1535         }
1536         if (!$has_kqueue)
1537         {
1538                 $config{USE_KQUEUE} = 0;
1539         }
1540         if (!$has_ports)
1541         {
1542                 $config{USE_PORTS} = 0;
1543         }
1544
1545         # formerly generated below this foreach, now it's not! magic.
1546         my $all_core = "";
1547
1548         foreach my $dir (("src","src/commands","src/modes","src/socketengines","src/modules"))
1549         {
1550                 print "Scanning \e[1;32m$dir\e[0m for core files ";
1551                 opendir(DIRHANDLE, $dir);
1552                 foreach my $name (sort readdir(DIRHANDLE))
1553                 {
1554                         if ($name =~ /\.cpp$/)
1555                         {
1556                                 open (CPP, "<$dir/$name") or die("Can't open $dir/$name to scan it! oh bugger");
1557                                 print ".";
1558                                 while (defined(my $line = <CPP>))
1559                                 {
1560                                         chomp($line);
1561                                         if ($line =~ /\/\* \$Core \*\//i)
1562                                         {
1563                                                 my $sname = $name;
1564                                                 $sname =~ s/\.cpp$/.o/;
1565
1566                                                 # append it to list to be built
1567                                                 $all_core = $all_core . $sname . " ";
1568                                                 $filelist{$name} = $sname;
1569
1570                                                 # mark it as a core file, so it won't get shared object cflags
1571                                                 if (!exists($core_files_list{$name}))
1572                                                 {
1573                                                         $core_files_list{$name} = 1;
1574                                                 }
1575                                         }
1576                                         elsif ($line =~ /\/\* \$ExtraDeps: (.*?) \*\//i)
1577                                         {
1578                                                 $specialdeps{$name} = $1;
1579                                         }
1580                                         elsif ($line =~ /\/\* \$ExtraObjects: (.*?) \*\//i)
1581                                         {
1582                                                 $extraobjects{$name} = $1;
1583                                         }
1584                                         elsif ($line =~ /\/\* \$ExtraBuild: (.*?) \*\//i)
1585                                         {
1586                                                 $extrabuildlines{$name} = $1;
1587                                         }
1588                                         elsif ($line =~ /\/\* \$ExtraSources: (.*?) \*\//i)
1589                                         {
1590                                                 $extrasources{$name} = $1;
1591                                                 }
1592                                         elsif ($line =~ /\/\* \$If: (\w+) \*\//i)
1593                                         {
1594                                                 if (defined $config{$1})
1595                                                 {
1596                                                         if (($config{$1} !~ /y/i) and ($config{$1} ne "1"))
1597                                                         {
1598                                                                 # Skip to 'endif'
1599                                                                 while (defined($line = <CPP>))
1600                                                                 {
1601                                                                         chomp($line);
1602                                                                         die ("\$If buildsystem instruction within another \$If in file $dir/$name") if ($line =~ /\/\* \$If: (\w+) \*\//i);
1603                                                                         last if ($line =~ /\/\* \$EndIf \*\//i);
1604                                                                 }
1605                                                         }
1606                                                 }
1607                                         }
1608                                         elsif ($line =~ /\/\* \$Install: (.*?) \*\//i)
1609                                         {
1610                                                 if (!exists($existing_install_list{$1}))
1611                                                 {
1612                                                         $existing_install_list{$1} = 1;
1613                                                         my $idir = (split(' ',$1))[1];
1614                                                         my $ifile = (split(' ',$1))[0];
1615                                                         $install_list = $install_list . "       -install -m \$(INSTMODE) $1\n";
1616                                                         $ifile =~ s/.*\///g;
1617                                                         $uninstall_list = $uninstall_list . "   -rm $idir/$ifile\n";
1618                                                 }
1619                                         }
1620                                         elsif ($line =~ /\/\* \$CopyInstall: (.*?) \*\//i)
1621                                         {
1622                                                 if (!exists($existing_install_list{$1}))
1623                                                 {
1624                                                         $existing_install_list{$1} = 1;
1625                                                         my $idir = (split(' ',$1))[1];
1626                                                         my $ifile = (split(' ',$1))[0];
1627                                                         $install_list = $install_list . "       -cp $1\n";
1628                                                         $ifile =~ s/.*\///g;
1629                                                         $uninstall_list = $uninstall_list . "   -rm $idir/$ifile\n";
1630                                                 }
1631                                         }
1632                                 }
1633                                 close CPP;
1634                         }
1635                 }
1636                 closedir(DIRHANDLE);
1637                 print " done!\n";
1638         }
1639
1640         # modes need to be compiled in too
1641         $all_core = $all_core . "modes/modeclasses.a";
1642
1643         my $freebsd4libs = (defined $config{CRAQ} ? $config{CRAQ} : "");
1644
1645         my $libraryext = "";
1646         my $binary_rule = "";
1647
1648         if ($config{IS_DARWIN} eq "YES")
1649         {
1650                 $libraryext = "dylib";
1651                 $binary_rule = "        \$(RUNCC) -dynamic -bind_at_load -L. -o inspircd \$(LDLIBS) inspircd.o "
1652         }
1653         else
1654         {
1655                 $libraryext = "so";
1656                 $binary_rule = "        \$(RUNCC) \$(FLAGS) $freebsd4libs -rdynamic -L. -o inspircd \$(LDLIBS) ";
1657         }
1658
1659         open(FH,">src/Makefile") or die("Could not write src/Makefile");
1660         print FH <<'EOM';
1661
1662 CXXFLAGS = ${FLAGS}
1663 CPPFILES = $(shell /bin/ls -l modes/ | grep '\.cpp' | sed 's/^.* //' | grep -v svn)
1664 RELCPPFILES = $(shell /bin/ls -l modes/ | grep '\.cpp' | sed 's/^.* /modes\//' | grep -v svn)
1665
1666 all:
1667         @echo "Don't run make here! Run it in the parent directory"
1668         false
1669
1670 EOM
1671
1672         my $buildstring = "";
1673         my $deps = "";
1674
1675         foreach my $cpp (sort keys %filelist)
1676         {
1677                 my $objs = $cpp;
1678                 my $rawcpp = $cpp;
1679                 $objs =~ s/\.cpp$/.o/;
1680                 if (exists($extraobjects{$cpp}))
1681                 {
1682                         $objs = $objs . " " . $extraobjects{$cpp};
1683                         $all_core = $all_core . " " . $extraobjects{$cpp};
1684                 }
1685                 if (exists($extrasources{$cpp}))
1686                 {
1687                         $rawcpp = $rawcpp . " " . $extrasources{$cpp};
1688                 }
1689
1690                 $deps = calcdeps("src/$cpp");
1691                 if (exists($extrasources{$cpp}))
1692                 {
1693                         foreach my $seperate (sort split(' ',$extrasources{$cpp}))
1694                         {
1695                                 my $d = calcdeps("src/$extrasources{$cpp}") . " ";
1696                                 if ($d ne "")
1697                                 {
1698                                         $deps = $deps . $d . " ";
1699                                 }
1700                         }
1701                 }
1702                 $buildstring = $buildstring . $objs . ": $cpp $deps ". (defined($specialdeps{$cpp}) ? $specialdeps{$cpp} : "") . "\n";
1703
1704                 if (exists($core_files_list{$cpp}))
1705                 {
1706                         # core files are statically linked into the binary and do not require $SHARED shared libs switches
1707                         $buildstring = $buildstring . " \$(RUNCC) \$(FLAGS) -c $rawcpp\n";
1708                 }
1709                 else
1710                 {
1711                         $buildstring = $buildstring . " \$(RUNCC) \$(FLAGS) $SHARED -c $rawcpp\n";
1712                 }
1713
1714                 if (exists($extrabuildlines{$cpp}))
1715                 {
1716                         $buildstring = $buildstring . " " . $extrabuildlines{$cpp} . "\n";
1717                 }
1718         }
1719
1720         print FH "inspircd: $all_core\n";
1721         print FH "$binary_rule $all_core\n\n";
1722
1723         print FH $buildstring;
1724         print FH <<'EOM';
1725
1726 .PHONY: all commands
1727
1728 commands:
1729         @${MAKE} -C commands $(MAKEARGS) commands
1730
1731 modes/modeclasses.a: $(RELCPPFILES) ../include/inspircd.h ../include/inspircd_config.h
1732         @${MAKE} -C modes $(MAKEARGS) CPPFILES="$(CPPFILES)" modeclasses.a
1733
1734 EOM
1735
1736         # close main makefile
1737         close(FH);
1738
1739         my $cmdobjs = "";
1740         # generate a list of .so
1741         foreach my $cmd (@cmdlist) {
1742                 $cmdobjs = $cmdobjs . "cmd_$cmd.so ";
1743         }
1744
1745         # and now reopen the commands makefile
1746         open(FH,">src/commands/Makefile") or die("Could not write src/commands/Makefile");
1747         print FH <<ITEM;
1748 CXXFLAGS = \${FLAGS}
1749
1750 all:
1751         \@echo "Don't run make here! Run it in the root directory"
1752         false
1753
1754 .PHONY: all commands
1755
1756 commands: $cmdobjs
1757
1758 ITEM
1759
1760         # now print the command file detail
1761         foreach my $cmd (@cmdlist) {
1762                 print FH <<ITEM;
1763 cmd_$cmd.so: cmd_$cmd.cpp ../../include/base.h ../../include/modules.h ../../include/inspircd.h ../../include/channels.h ../../include/users.h ../../include/inspircd_config.h ../../include/commands/cmd_$cmd.h
1764         \$(RUNCC) \$(FLAGS) $SHARED -o cmd_$cmd.so cmd_$cmd.cpp
1765
1766 ITEM
1767         }
1768 }
1769
1770 # Routine to list out the extra/ modules that have been enabled.
1771 # Note: when getting any filenames out and comparing, it's important to lc it if the
1772 # file system is not case-sensitive (== Epoc, MacOS, OS/2 (incl DOS/DJGPP), VMS, Win32
1773 # (incl NetWare, Symbian)). Cygwin may or may not be case-sensitive, depending on
1774 # configuration, however, File::Spec does not currently tell us (it assumes Unix behavior).
1775 sub list_extras () {
1776         use File::Spec;
1777         # @_ not used
1778         my $srcdir = File::Spec->catdir("src", "modules");
1779         my $abs_srcdir = File::Spec->rel2abs($srcdir);
1780         local $_;
1781         my $dd;
1782         opendir $dd, File::Spec->catdir($abs_srcdir, "extra") or die (File::Spec->catdir($abs_srcdir, "extra") . ": $!\n");
1783         my @extras = map { File::Spec->case_tolerant() ? lc($_) : $_ } (readdir($dd));
1784         closedir $dd;
1785         undef $dd;
1786         opendir $dd, $abs_srcdir or die "$abs_srcdir: $!\n";
1787         my @sources = map { File::Spec->case_tolerant() ? lc($_) : $_ } (readdir($dd));
1788         closedir $dd;
1789         undef $dd;
1790         my $maxlen = (sort { $b <=> $a } (map {length($_)} (@extras)))[0];
1791         my %extras = ();
1792 EXTRA:  for my $extra (@extras) {
1793                 next if (File::Spec->curdir() eq $extra || File::Spec->updir() eq $extra);
1794                 next if ($extra eq '.svn');
1795                 my $abs_extra = File::Spec->catfile($abs_srcdir, "extra", $extra);
1796                 my $abs_source = File::Spec->catfile($abs_srcdir, $extra);
1797                 next unless ($extra =~ m/\.(cpp|h)$/ || (-d $abs_extra)); # C++ Source/Header, or directory
1798                 if (-l $abs_source) {
1799                         # Symlink, is it in the right place?
1800                         my $targ = readlink($abs_source);
1801                         my $abs_targ = File::Spec->rel2abs($targ, $abs_srcdir);
1802                         if ($abs_targ eq $abs_extra) {
1803                                 $extras{$extra} = "\e[32;1menabled\e[0m";
1804                         } else {
1805                                 $extras{$extra} = sprintf("\e[31;1mwrong symlink target (%s)\e[0m", $abs_targ);
1806                         }
1807                 } elsif (-e $abs_source) {
1808                         my ($devext, $inoext) = stat($abs_extra);
1809                         my ($devsrc, $inosrc, undef, $lnksrc) = stat($abs_source);
1810                         if ($lnksrc > 1) {
1811                                 if ($devsrc == $devext && $inosrc == $inoext) {
1812                                         $extras{$extra} = "\e[32;1menabled\e[0m";
1813                                 } else {
1814                                         $extras{$extra} = sprintf("\e[31;1mwrong hardlink target (%d:%d)\e[0m", $devsrc, $inosrc);
1815                                 }
1816                         } else {
1817                                 open my $extfd, "<", $abs_extra;
1818                                 open my $srcfd, "<", $abs_source;
1819                                 local $/ = undef;
1820                                 if (scalar(<$extfd>) eq scalar(<$srcfd>)) {
1821                                         $extras{$extra} = "\e[32;1menabled\e[0m";
1822                                 } else {
1823                                         $extras{$extra} = sprintf("\e[31;1mout of synch (re-copy)\e[0m");
1824                                 }
1825                         }
1826                 } else {
1827                         $extras{$extra} = "\e[33;1mdisabled\e[0m";
1828                 }
1829         }
1830         # Now let's add dependency info
1831         for my $extra (keys(%extras)) {
1832                 next unless $extras{$extra} =~ m/enabled/; # only process enabled extras.
1833                 my $abs_extra = File::Spec->catfile($abs_srcdir, "extra", $extra);
1834                 my @deps = split / +/, getdependencies($abs_extra);
1835                 for my $dep (@deps) {
1836                         if (exists($extras{$dep})) {
1837                                 my $ref = \$extras{$dep}; # Take reference.
1838                                 if ($$ref !~ m/needed by/) {
1839                                         # First dependency found.
1840                                         if ($$ref =~ m/enabled/) {
1841                                                 $$ref .= " (needed by \e[32;1m$extra\e[0m";
1842                                         } else {
1843                                                 $$ref =~ s/\e\[.*?m//g; # Strip out previous coloring. Will be set in bold+red+blink later.
1844                                                 $$ref .= " (needed by \e[0;32;1;5m$extra\e[0;31;1;5m";
1845                                         }
1846                                 } else {
1847                                         if ($$ref =~ m/enabled/) {
1848                                                 $$ref .= ", \e[32;1m$extra\e[0m";
1849                                         } else {
1850                                                 $$ref .= ", \e[0;32;1;5m$extra\e[0;31;1;5m";
1851                                         }
1852                                 }
1853                         }
1854                 }
1855         }
1856         for my $extra (sort {$a cmp $b} keys(%extras)) {
1857                 my $text = $extras{$extra};
1858                 if ($text =~ m/needed by/ && $text !~ m/enabled/) {
1859                         printf "\e[31;1;5m%-*s = %s%s\e[0m\n", $maxlen, $extra, $text, ($text =~ m/needed by/ ? ")" : "");
1860                 } else {
1861                         printf "%-*s = %s%s\n", $maxlen, $extra, $text, ($text =~ m/needed by/ ? "\e[0m)" : "");
1862                 }
1863         }
1864         return keys(%extras) if wantarray; # Can be used by manage_extras.
1865 }
1866
1867 sub enable_extras (@) {
1868         my (@extras) = @_;
1869         for my $extra (@extras) {
1870                 my $extrapath = "src/modules/extra/$extra";
1871                 if (!-e $extrapath) {
1872                         print STDERR "Cannot enable \e[32;1m$extra\e[0m : No such file or directory in src/modules/extra\n";
1873                         next;
1874                 }
1875                 my $source = "src/modules/$extra";
1876                 if (-e $source) {
1877                         print STDERR "Cannot enable \e[32;1m$extra\e[0m : destination in src/modules exists (might already be enabled?)\n";
1878                         next;
1879                 }
1880                 # Get dependencies, and add them to be processed.
1881                 my @deps = split / +/, getdependencies($extrapath);
1882                 for my $dep (@deps) {
1883                         next if scalar(grep { $_ eq $dep } (@extras)) > 0; # Skip if we're going to be enabling it anyway.
1884                         if (!-e "src/modules/$dep") {
1885                                 if (-e "src/modules/extra/$dep") {
1886                                         print STDERR "Will also enable extra \e[32;1m$dep\e[0m (needed by \e[32;1m$extra\e[0m)\n";
1887                                         push @extras, $dep;
1888                                 } else {
1889                                         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";
1890                                 }
1891                         }
1892                 }
1893                 print "Enabling $extra ... \n";
1894                 symlink "extra/$extra", $source or print STDERR "$source: Cannot link to 'extra/$extra': $!\n";
1895         }
1896 }
1897
1898 sub disable_extras (@)
1899 {
1900         opendir my $dd, "src/modules/extra/";
1901         my @files = readdir($dd);
1902         closedir $dd;
1903         my (@extras) = @_;
1904 EXTRA:  for my $extra (@extras) {
1905                 my $extrapath = "src/modules/extra/$extra";
1906                 my $source = "src/modules/$extra";
1907                 if (!-e $extrapath) {
1908                         print STDERR "Cannot disable \e[32;1m$extra\e[0m : Is not an extra\n";
1909                         next;
1910                 }
1911                 if ((! -l $source) || readlink($source) ne "extra/$extra") {
1912                         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";
1913                         next;
1914                 }
1915                 # Check if anything needs this.
1916                 for my $file (@files) {
1917                         my @deps = split / +/, getdependencies("src/modules/extra/$file");
1918                         # File depends on this extra...
1919                         if (scalar(grep { $_ eq $extra } @deps) > 0) {
1920                                 # And is both enabled and not about to be disabled.
1921                                 if (-e "src/modules/$file" && scalar(grep { $_ eq $file } @extras) < 1) {
1922                                         print STDERR "Cannot disable \e[32;1m$extra\e[0m : is needed by \e[32;1m$file\e[0m\n";
1923                                         next EXTRA;
1924                                 }
1925                         }
1926                 }
1927                 # Now remove.
1928                 print "Disabling $extra ... \n";
1929                 unlink "src/modules/$extra" or print STDERR "Cannot disable \e[32;1m$extra\e[0m : $!\n";
1930         }
1931 }