]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - configure
edea764f1b36242489f5f01b57f14373d68e61fd
[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{LDLIBS} .= " " . $ENV{LDFLAGS} if exists($ENV{LDFLAGS});
1099                 $config{MAKEPROG} = "make";
1100         }
1101
1102         if ($config{OSNAME} =~ /FreeBSD/i) {
1103                 $config{FLAGS}  .= " " . $ENV{CXXFLAGS} if exists($ENV{CXXFLAGS});
1104                 $config{LDLIBS} .= " " . $ENV{LDLIBS} if exists($ENV{LDLIBS});
1105                 $config{LDLIBS} .= " " . $ENV{LDFLAGS} if exists($ENV{LDFLAGS});
1106         }
1107
1108         if ($config{OSNAME} =~ /SunOS/i or $config{OSNAME} =~ /solaris/i)
1109         {
1110                 # solaris/sunos needs these
1111                 # socket = bsd sockets api
1112                 # nsl = dns stuff
1113                 # rt = POSIX realtime extensions
1114                 # resolv = inet_aton only (why isnt this in nsl?!)
1115                 $config{MAKEPROG} = "gmake";
1116                 $config{LDLIBS} .= " -lsocket -lnsl -lrt -lresolv -pthread";
1117                 return "Solaris";
1118         }
1119
1120         if($config{OSNAME} =~ /MINGW32/i)
1121         {
1122                 # All code is position-independent on windows
1123                 $config{FLAGS} =~ s/-fPIC //;
1124                 return "MinGW";
1125         }
1126
1127         return $config{OSNAME};
1128 }
1129
1130 my ($mliflags, $mfrules, $mobjs, $mfcount) = ("", "", "", 0);
1131
1132 sub writefiles {
1133         my($writeheader) = @_;
1134         my $se = "";
1135         # First File.. inspircd_config.h
1136         chomp(my $incos = `uname -n -s -r`);
1137         chomp(my $version = `sh src/version.sh`);
1138         chomp(my $revision2 = getrevision());
1139         if ($writeheader == 1)
1140         {
1141                 print "Writing \e[1;32minspircd_config.h\e[0m\n";
1142                 open(FILEHANDLE, ">include/inspircd_config.h");
1143                 print FILEHANDLE <<EOF;
1144 /* Auto generated by configure, do not modify! */
1145 #ifndef __CONFIGURATION_AUTO__
1146 #define __CONFIGURATION_AUTO__
1147
1148 /* this is for windows support. */
1149 #define CoreExport /**/
1150 #define DllExport /**/
1151
1152 #define CONFIG_FILE "$config{CONFIG_DIR}/inspircd.conf"
1153 #define MOD_PATH "$config{MODULE_DIR}"
1154 #define VERSION "$version"
1155 #define REVISION "$revision2"
1156 #define SOMAXCONN_S "$config{_SOMAXCONN}"
1157 #define OPTIMISATION $config{OPTIMITEMP}
1158 #define LIBRARYDIR "$config{LIBRARY_DIR}"
1159 #define SYSTEM "$incos"
1160 #define ENTRYPOINT int main(int argc, char** argv)
1161
1162 EOF
1163 print FILEHANDLE "#define MAXBUF " . ($config{MAXBUF}+2) . "\n";
1164
1165                 if ($config{OSNAME} =~ /SunOS/i) {
1166                         print FILEHANDLE "#define IS_SOLARIS\n";
1167                 }
1168                 if ($config{OSNAME} =~ /MINGW32/i) {
1169                         print FILEHANDLE "#define IS_MINGW\n";
1170                 }
1171                 if ($config{GCCVER} >= 3) {
1172                         print FILEHANDLE "#define GCC3\n";
1173                 }
1174                 if (
1175                         (($config{GCCVER} == 4) && ($config{GCCMINOR} >= 3))
1176                                 ||
1177                         ($config{GCCVER} > 4)
1178                 ) {
1179                         print FILEHANDLE "#define HASHMAP_DEPRECATED\n";
1180                 }
1181                 if ($config{HAS_STRLCPY} eq "true") {
1182                         print FILEHANDLE "#define HAS_STRLCPY\n";
1183                 }
1184                 if ($config{HAS_STDINT} eq "true") {
1185                         print FILEHANDLE "#define HAS_STDINT\n";
1186                 }
1187                 if ($config{IPV6} =~ /y/i) {
1188                         print FILEHANDLE "#define IPV6\n";
1189                 }
1190                 if ($config{SUPPORT_IP6LINKS} =~ /y/i) {
1191                         print FILEHANDLE "#define SUPPORT_IP6LINKS\n";
1192                 }
1193                 if ($config{HAS_EVENTFD} eq 'true') {
1194                         print FILEHANDLE "#define HAS_EVENTFD\n";
1195                 }
1196                 my $use_hiperf = 0;
1197                 if (($has_kqueue) && ($config{USE_KQUEUE} eq "y")) {
1198                         print FILEHANDLE "#define USE_KQUEUE\n";
1199                         $se = "socketengine_kqueue";
1200                         $use_hiperf = 1;
1201                 }
1202                 if (($has_epoll) && ($config{USE_EPOLL} eq "y")) {
1203                         print FILEHANDLE "#define USE_EPOLL\n";
1204                         $se = "socketengine_epoll";
1205                         $use_hiperf = 1;
1206                 }
1207                 if (($has_ports) && ($config{USE_PORTS} eq "y")) {
1208                         print FILEHANDLE "#define USE_PORTS\n";
1209                         $se = "socketengine_ports";
1210                         $use_hiperf = 1;
1211                 }
1212                 # user didn't choose either epoll or select for their OS.
1213                 # default them to USE_SELECT (ewwy puke puke)
1214                 if (!$use_hiperf) {
1215                         print "no hi-perf, " . $config{USE_POLL};
1216                         if ($config{USE_POLL} eq "y")
1217                         {
1218                                 print FILEHANDLE "#define USE_POLL\n";
1219                                 $se = "socketengine_poll";
1220                         }
1221                         else
1222                         {
1223                                 print FILEHANDLE "#define USE_SELECT\n";
1224                                 $se = "socketengine_select";
1225                         }
1226                 }
1227                 print FILEHANDLE "\n#include \"threadengines/threadengine_pthread.h\"\n\n#endif\n";
1228                 close(FILEHANDLE);
1229         }
1230
1231         if ($writeheader)
1232         {
1233                 open(FILEHANDLE, ">include/inspircd_se_config.h");
1234                 print FILEHANDLE <<EOF;
1235 /* Auto generated by configure, do not modify or commit to svn! */
1236 #ifndef __CONFIGURATION_SOCKETENGINE__
1237 #define __CONFIGURATION_SOCKETENGINE__
1238
1239 #include "socketengines/$se.h"
1240
1241 #endif
1242 EOF
1243                 close(FILEHANDLE);
1244         }
1245
1246
1247         # Create a Modules List..
1248         my $modules = "";
1249         foreach my $i (@modlist)
1250         {
1251                 $modules .= "m_".$i.".so ";
1252         }
1253         chomp($modules);   # Remove Redundant whitespace..
1254
1255         opendir(DIRHANDLE, "src/modules");
1256         foreach my $name2 (sort readdir(DIRHANDLE)) {
1257                 if ($name2 =~ /^m_(.+?)$/) {
1258                         if (defined(opendir(MDIRHANDLE, "src/modules/$name2"))) {
1259                                 closedir(MDIRHANDLE);
1260                                 $modules .= "$name2.so ";
1261                                 $uninstall_list = $uninstall_list . "   -rm \$(MODPATH)/$name2.so\n";
1262                         }
1263                 }
1264         }
1265         closedir(DIRHANDLE);
1266
1267
1268         # Write all .in files.
1269         my $tmp = "";
1270         my $file = "";
1271         my $exe = "inspircd";
1272
1273         # Do this once here, and cache it in the .*.inc files,
1274         # rather than attempting to read src/version.sh from
1275         # compiled code -- we might not have the source to hand.
1276         # Fix for bug#177 by Brain.
1277
1278         chomp($version = `sh ./src/version.sh`);
1279         chomp(my $revision = getrevision());
1280         $version = "$version(r$revision)";
1281
1282         # We can actually parse any file starting with . and ending with .inc,
1283         # but right now we only parse .inspircd.inc to form './inspircd'
1284
1285         print "Writing \e[1;32mMakefiles\e[0m\n";
1286         write_dynamic_modules_makefile();
1287         write_dynamic_makefile();
1288
1289         opendir(DIRHANDLE, $this);
1290
1291         foreach my $name (sort readdir(DIRHANDLE)) {
1292                 if ($name =~ /^\.(.+)\.inc$/) {
1293                         $file = $1;
1294
1295                         # Bug #353, omit this on non-darwin
1296                         next if (($config{OSNAME} !~ /darwin/) && ($file eq "org.inspircd.plist"));
1297
1298                         # All .name.inc files need parsing!
1299                         open(FILEHANDLE, ".$file.inc") or die ("Can't open .$file.inc");
1300                         $_ = join '', <FILEHANDLE>;
1301                         close(FILEHANDLE);
1302
1303                         print "Writing \e[1;32m$file\e[0m ...\n";
1304                         for my $var (qw(
1305                                 CC FLAGS DEVELOPER LDLIBS BASE_DIR CONFIG_DIR MODULE_DIR BINARY_DIR LIBRARY_DIR
1306                                 STARTSCRIPT DESTINATION EXTRA_DIR
1307                         )) {
1308                                 s/\@$var\@/$config{$var}/g;
1309                         }
1310                         s/\@MODULES\@/$modules/ if defined $modules;
1311                         s/\@EXECUTABLE\@/$exe/ if defined $exe;
1312                         s/\@VERSION\@/$version/ if defined $version;
1313                         s/\@INSTALL_LIST\@/$install_list/ if defined $install_list;
1314                         s/\@UNINSTALL_LIST\@/$uninstall_list/ if defined $uninstall_list;
1315
1316                         if ($file eq 'Makefile') {
1317                                 my $mk_tmp = $_;
1318                                 s/\@IFDEF (\S+)/ifdef $1/g;
1319                                 s/\@IFNDEF (\S+)/ifndef $1/g;
1320                                 s/\@ELSE/else/g;
1321                                 s/\@ENDIF/endif/g;
1322                                 s/\@BSD_ONLY .*\n//g;
1323                                 s/\@GNU_ONLY //g;
1324                                 open MKF, '>GNUmakefile' or die "Can't write to GNUmakefile: $!";
1325                                 print MKF $_;
1326                                 close MKF;
1327                                 $_ = $mk_tmp;
1328                                 s/\@IFDEF (\S+)/.if defined($1)/g;
1329                                 s/\@IFNDEF (\S+)/.if !defined($1)/g;
1330                                 s/\@ELSE/.else/g;
1331                                 s/\@ENDIF/.endif/g;
1332                                 s/\@BSD_ONLY //g;
1333                                 s/\@GNU_ONLY .*\n//g;
1334                                 open MKF, '>BSDmakefile' or die "Can't write to BSDmakefile: $!";
1335                                 print MKF $_;
1336                                 close MKF;
1337                         } else {
1338                                 open(FILEHANDLE, ">$file") or die("Can't write to $file: $!\n");
1339                                 print FILEHANDLE $_;
1340                                 close(FILEHANDLE);
1341                         }
1342                 }
1343         }
1344         closedir(DIRHANDLE);
1345
1346         # Make inspircd executable!
1347         chmod 0744, 'inspircd';
1348 }
1349
1350 sub write_dynamic_modules_makefile {
1351         # Modules Makefile..
1352         print "Writing \e[1;32msrc/modules/Makefile\e[0m\n";
1353         open(FILEHANDLE, ">src/modules/Makefile");
1354
1355 ###
1356 # Module Makefile Header
1357 ###
1358         print FILEHANDLE <<EOF;
1359 ###################################################
1360 # Copyright 2002-2009 The InspIRCd Development Team
1361 #  http://wiki.inspircd.org/Credits
1362 #
1363 # Thanks to Andrew Church <achurch\@achurch.org>
1364 #   for assisting with making this work right.
1365 #
1366 # Automatically Generated by ./configure to add a
1367 #  modules please run ./configure -modupdate
1368 ###################################################
1369
1370 all: \$(MODULES)
1371
1372 EOF
1373
1374 if ($config{OSNAME} =~ /darwin/) {
1375                 print FILEHANDLE <<EOCHEESE;
1376
1377 PICLDFLAGS = -twolevel_namespace -undefined dynamic_lookup -bundle
1378
1379 EOCHEESE
1380 } else {
1381                 print FILEHANDLE <<EOCHEESE;
1382
1383 PICLDFLAGS = -fPIC -DPIC -shared
1384
1385 EOCHEESE
1386 }
1387
1388         ###
1389         # End Module Makefile Header
1390         ###
1391
1392         # Create a Modules List..
1393         my $modules = "";
1394         my $cmflags = "";
1395         my $liflags = "";
1396         foreach my $i (@modlist) {
1397                 ###
1398                 # Write Entry to the MakeFile
1399                 ###
1400                 $cmflags = getcompilerflags("src/modules/m_".$i.".cpp");
1401                 $liflags = getlinkerflags("src/modules/m_".$i.".cpp");
1402                 my $deps = getdependencies("src/modules/m_".$i.".cpp");
1403
1404                 #print "file: $i: cmflags=$cmflags; liflags=$liflags; deps=$deps\n";
1405
1406
1407                 if (nopedantic("src/modules/m_".$i.".cpp"))
1408                 {
1409                         print FILEHANDLE "
1410 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
1411         \$(RUNCC) \$(NICEFLAGS) $cmflags \$(PICLDFLAGS) $liflags $SHARED -o m_$i.so m_$i.cpp
1412 ";
1413                 }
1414                 else
1415                 {
1416                         print FILEHANDLE "
1417 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
1418         \$(RUNCC) \$(FLAGS) $cmflags \$(PICLDFLAGS) $liflags $SHARED -o m_$i.so m_$i.cpp
1419 ";
1420                 }
1421                 $install_list = $install_list . "       install -m \$(INSTMODE) src/modules/m_$i.so \$(MODPATH)\n";
1422                 $uninstall_list = $uninstall_list . "   -rm \$(MODULES)/m_$i.so\n";
1423                 ###
1424                 # End Write Entry to the MakeFile
1425                 ###
1426         }
1427
1428         opendir(DIRHANDLE, "src/modules");
1429         foreach my $name (sort readdir(DIRHANDLE)) {
1430                 if ($name =~ /^m_(.+?)$/) {
1431                         $mfrules = "";
1432                         $mobjs = "";
1433                         $mliflags = "";
1434                         $mfcount = 0;
1435                         # A module made of multiple files, in a dir, e.g. src/modules/m_spanningtree/
1436                         if (defined(opendir(MDIRHANDLE, "src/modules/$name"))) {
1437                                 read_module_directory("src/modules/$name", $name);
1438                                 print "Composing Makefile rules for directory \e[1;32m$name\e[0m... (\e[1;32m$mfcount files found\e[0m)\n";
1439                                 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";
1440                                 print FILEHANDLE "      \$(RUNCC) \$(FLAGS) $SHARED $mliflags -o $name.so $mobjs\n";
1441                                 print FILEHANDLE "\n$mfrules\n";
1442                                 closedir(MDIRHANDLE);
1443                                 $install_list = $install_list . "       install -m \$(INSTMODE) src/modules/$name.so \$(MODPATH)\n";
1444                         }
1445                 }
1446         }
1447         closedir(DIRHANDLE);
1448 }
1449
1450 sub read_module_directory {
1451         my ($dpath, $reldpath) = @_;
1452
1453         if (opendir(MDIRHANDLE, $dpath) == 0) {
1454                 return;
1455         }
1456
1457         foreach my $fname (sort readdir(MDIRHANDLE)) {
1458                 if ($fname =~ /\.cpp$/) {
1459                         my $cmflags = getcompilerflags("$dpath/$fname");
1460                         $mliflags = $mliflags . " " . getlinkerflags("$dpath/$fname");
1461                         my $deps = getdependencies("$dpath/$fname");
1462                         my $oname = $fname;
1463                         $oname =~ s/\.cpp$/.o/g;
1464                         $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";
1465                         $mfrules = $mfrules .  "        \$(RUNCC) -I. \$(FLAGS) $cmflags $SHARED -o $reldpath/$oname -c $reldpath/$fname\n\n";
1466                         $mobjs = $mobjs . " $reldpath/$oname";
1467                         $mfcount++;
1468                 }
1469                 elsif ((-d "$dpath/$fname") && !($fname eq ".") && !($fname eq "..")) {
1470                         read_module_directory($dpath."/".$fname, $reldpath."/".$fname);
1471                 }
1472         }
1473 }
1474
1475 sub calcdeps($)
1476 {
1477         # Yes i know we could use gcc -M but it seems to ideneify a lot of 'deep'
1478         # dependencies which are not relevent in C++.
1479
1480         my $file = $_[0];
1481
1482         open (CPP, "<$file") or die("Can't open $file for reading!");
1483
1484         my %dupe = ();
1485         my $retlist = "";
1486
1487         foreach my $d (@ignoredeps)
1488         {
1489                 $dupe{$d} = 1;
1490         }
1491
1492         my $immutable = "";
1493         foreach my $dep (@immutabledeps)
1494         {
1495                 $immutable = $immutable . "../include/$dep ";
1496         }
1497         $immutable =~ s/ $//g;
1498
1499         while (defined(my $line = <CPP>))
1500         {
1501                 chomp($line);
1502                 if ($line =~ /#include "(.+\.h)"/)
1503                 {
1504                         if (!exists($dupe{$1}))
1505                         {
1506                                 $retlist = $retlist . "../include/$1 ";
1507                                 $dupe{$1} = 1;
1508                         }
1509                 }
1510         }
1511         close CPP;
1512         return length($immutable) ? $immutable . " " . $retlist : $retlist;
1513 }
1514
1515 sub write_dynamic_makefile
1516 {
1517         my $i = 0;
1518         my @cmdlist = ();
1519         my %existing_install_list = ();
1520         my %core_files_list = ();
1521
1522         opendir(DIRHANDLE, "src/commands");
1523         foreach my $name (sort readdir(DIRHANDLE))
1524         {
1525                 if ($name =~ /^cmd_(.+)\.cpp$/)
1526                 {
1527                         $cmdlist[$i++] = $1;
1528                         $install_list = $install_list . "       -install -m \$(INSTMODE) src/commands/cmd_" . $1 . ".so \$(LIBPATH)\n";
1529                         $uninstall_list = $uninstall_list . "   -rm \$(LIBPATH)/cmd_$1.so\n";
1530                 }
1531         }
1532         closedir(DIRHANDLE);
1533
1534         if (!$has_epoll)
1535         {
1536                 $config{USE_EPOLL} = 0;
1537         }
1538         if (!$has_kqueue)
1539         {
1540                 $config{USE_KQUEUE} = 0;
1541         }
1542         if (!$has_ports)
1543         {
1544                 $config{USE_PORTS} = 0;
1545         }
1546
1547         # formerly generated below this foreach, now it's not! magic.
1548         my $all_core = "";
1549
1550         foreach my $dir (("src","src/commands","src/modes","src/socketengines","src/modules"))
1551         {
1552                 print "Scanning \e[1;32m$dir\e[0m for core files ";
1553                 opendir(DIRHANDLE, $dir);
1554                 foreach my $name (sort readdir(DIRHANDLE))
1555                 {
1556                         if ($name =~ /\.cpp$/)
1557                         {
1558                                 open (CPP, "<$dir/$name") or die("Can't open $dir/$name to scan it! oh bugger");
1559                                 print ".";
1560                                 while (defined(my $line = <CPP>))
1561                                 {
1562                                         chomp($line);
1563                                         if ($line =~ /\/\* \$Core \*\//i)
1564                                         {
1565                                                 my $sname = $name;
1566                                                 $sname =~ s/\.cpp$/.o/;
1567
1568                                                 # append it to list to be built
1569                                                 $all_core = $all_core . $sname . " ";
1570                                                 $filelist{$name} = $sname;
1571
1572                                                 # mark it as a core file, so it won't get shared object cflags
1573                                                 if (!exists($core_files_list{$name}))
1574                                                 {
1575                                                         $core_files_list{$name} = 1;
1576                                                 }
1577                                         }
1578                                         elsif ($line =~ /\/\* \$ExtraDeps: (.*?) \*\//i)
1579                                         {
1580                                                 $specialdeps{$name} = $1;
1581                                         }
1582                                         elsif ($line =~ /\/\* \$ExtraObjects: (.*?) \*\//i)
1583                                         {
1584                                                 $extraobjects{$name} = $1;
1585                                         }
1586                                         elsif ($line =~ /\/\* \$ExtraBuild: (.*?) \*\//i)
1587                                         {
1588                                                 $extrabuildlines{$name} = $1;
1589                                         }
1590                                         elsif ($line =~ /\/\* \$ExtraSources: (.*?) \*\//i)
1591                                         {
1592                                                 $extrasources{$name} = $1;
1593                                                 }
1594                                         elsif ($line =~ /\/\* \$If: (\w+) \*\//i)
1595                                         {
1596                                                 if (defined $config{$1})
1597                                                 {
1598                                                         if (($config{$1} !~ /y/i) and ($config{$1} ne "1"))
1599                                                         {
1600                                                                 # Skip to 'endif'
1601                                                                 while (defined($line = <CPP>))
1602                                                                 {
1603                                                                         chomp($line);
1604                                                                         die ("\$If buildsystem instruction within another \$If in file $dir/$name") if ($line =~ /\/\* \$If: (\w+) \*\//i);
1605                                                                         last if ($line =~ /\/\* \$EndIf \*\//i);
1606                                                                 }
1607                                                         }
1608                                                 }
1609                                         }
1610                                         elsif ($line =~ /\/\* \$Install: (.*?) \*\//i)
1611                                         {
1612                                                 if (!exists($existing_install_list{$1}))
1613                                                 {
1614                                                         $existing_install_list{$1} = 1;
1615                                                         my $idir = (split(' ',$1))[1];
1616                                                         my $ifile = (split(' ',$1))[0];
1617                                                         $install_list = $install_list . "       -install -m \$(INSTMODE) $1\n";
1618                                                         $ifile =~ s/.*\///g;
1619                                                         $uninstall_list = $uninstall_list . "   -rm $idir/$ifile\n";
1620                                                 }
1621                                         }
1622                                         elsif ($line =~ /\/\* \$CopyInstall: (.*?) \*\//i)
1623                                         {
1624                                                 if (!exists($existing_install_list{$1}))
1625                                                 {
1626                                                         $existing_install_list{$1} = 1;
1627                                                         my $idir = (split(' ',$1))[1];
1628                                                         my $ifile = (split(' ',$1))[0];
1629                                                         $install_list = $install_list . "       -cp $1\n";
1630                                                         $ifile =~ s/.*\///g;
1631                                                         $uninstall_list = $uninstall_list . "   -rm $idir/$ifile\n";
1632                                                 }
1633                                         }
1634                                 }
1635                                 close CPP;
1636                         }
1637                 }
1638                 closedir(DIRHANDLE);
1639                 print " done!\n";
1640         }
1641
1642         # modes need to be compiled in too
1643         $all_core = $all_core . "modes/modeclasses.a";
1644
1645         my $freebsd4libs = (defined $config{CRAQ} ? $config{CRAQ} : "");
1646
1647         my $libraryext = "";
1648         my $binary_rule = "";
1649
1650         if ($config{IS_DARWIN} eq "YES")
1651         {
1652                 $libraryext = "dylib";
1653                 $binary_rule = "        \$(RUNCC) -dynamic -bind_at_load -L. -o inspircd \$(LDLIBS) inspircd.o "
1654         }
1655         else
1656         {
1657                 $libraryext = "so";
1658                 $binary_rule = "        \$(RUNCC) \$(FLAGS) $freebsd4libs -rdynamic -L. -o inspircd \$(LDLIBS) ";
1659         }
1660
1661         open(FH,">src/Makefile") or die("Could not write src/Makefile");
1662         print FH <<'EOM';
1663
1664 CXXFLAGS = ${FLAGS}
1665 CPPFILES = $(shell /bin/ls -l modes/ | grep '\.cpp' | sed 's/^.* //' | grep -v svn)
1666 RELCPPFILES = $(shell /bin/ls -l modes/ | grep '\.cpp' | sed 's/^.* /modes\//' | grep -v svn)
1667
1668 all:
1669         @echo "Don't run make here! Run it in the parent directory"
1670         false
1671
1672 EOM
1673
1674         my $buildstring = "";
1675         my $deps = "";
1676
1677         foreach my $cpp (sort keys %filelist)
1678         {
1679                 my $objs = $cpp;
1680                 my $rawcpp = $cpp;
1681                 $objs =~ s/\.cpp$/.o/;
1682                 if (exists($extraobjects{$cpp}))
1683                 {
1684                         $objs = $objs . " " . $extraobjects{$cpp};
1685                         $all_core = $all_core . " " . $extraobjects{$cpp};
1686                 }
1687                 if (exists($extrasources{$cpp}))
1688                 {
1689                         $rawcpp = $rawcpp . " " . $extrasources{$cpp};
1690                 }
1691
1692                 $deps = calcdeps("src/$cpp");
1693                 if (exists($extrasources{$cpp}))
1694                 {
1695                         foreach my $seperate (sort split(' ',$extrasources{$cpp}))
1696                         {
1697                                 my $d = calcdeps("src/$extrasources{$cpp}") . " ";
1698                                 if ($d ne "")
1699                                 {
1700                                         $deps = $deps . $d . " ";
1701                                 }
1702                         }
1703                 }
1704                 $buildstring = $buildstring . $objs . ": $cpp $deps ". (defined($specialdeps{$cpp}) ? $specialdeps{$cpp} : "") . "\n";
1705
1706                 if (exists($core_files_list{$cpp}))
1707                 {
1708                         # core files are statically linked into the binary and do not require $SHARED shared libs switches
1709                         $buildstring = $buildstring . " \$(RUNCC) \$(FLAGS) -c $rawcpp\n";
1710                 }
1711                 else
1712                 {
1713                         $buildstring = $buildstring . " \$(RUNCC) \$(FLAGS) $SHARED -c $rawcpp\n";
1714                 }
1715
1716                 if (exists($extrabuildlines{$cpp}))
1717                 {
1718                         $buildstring = $buildstring . " " . $extrabuildlines{$cpp} . "\n";
1719                 }
1720         }
1721
1722         print FH "inspircd: $all_core\n";
1723         print FH "$binary_rule $all_core\n\n";
1724
1725         print FH $buildstring;
1726         print FH <<'EOM';
1727
1728 .PHONY: all commands
1729
1730 commands:
1731         @${MAKE} -C commands $(MAKEARGS) commands
1732
1733 modes/modeclasses.a: $(RELCPPFILES) ../include/inspircd.h ../include/inspircd_config.h
1734         @${MAKE} -C modes $(MAKEARGS) CPPFILES="$(CPPFILES)" modeclasses.a
1735
1736 EOM
1737
1738         # close main makefile
1739         close(FH);
1740
1741         my $cmdobjs = "";
1742         # generate a list of .so
1743         foreach my $cmd (@cmdlist) {
1744                 $cmdobjs = $cmdobjs . "cmd_$cmd.so ";
1745         }
1746
1747         # and now reopen the commands makefile
1748         open(FH,">src/commands/Makefile") or die("Could not write src/commands/Makefile");
1749         print FH <<ITEM;
1750 CXXFLAGS = \${FLAGS}
1751
1752 all:
1753         \@echo "Don't run make here! Run it in the root directory"
1754         false
1755
1756 .PHONY: all commands
1757
1758 commands: $cmdobjs
1759
1760 ITEM
1761
1762         # now print the command file detail
1763         foreach my $cmd (@cmdlist) {
1764                 print FH <<ITEM;
1765 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
1766         \$(RUNCC) \$(FLAGS) $SHARED -o cmd_$cmd.so cmd_$cmd.cpp
1767
1768 ITEM
1769         }
1770 }
1771
1772 # Routine to list out the extra/ modules that have been enabled.
1773 # Note: when getting any filenames out and comparing, it's important to lc it if the
1774 # file system is not case-sensitive (== Epoc, MacOS, OS/2 (incl DOS/DJGPP), VMS, Win32
1775 # (incl NetWare, Symbian)). Cygwin may or may not be case-sensitive, depending on
1776 # configuration, however, File::Spec does not currently tell us (it assumes Unix behavior).
1777 sub list_extras () {
1778         use File::Spec;
1779         # @_ not used
1780         my $srcdir = File::Spec->catdir("src", "modules");
1781         my $abs_srcdir = File::Spec->rel2abs($srcdir);
1782         local $_;
1783         my $dd;
1784         opendir $dd, File::Spec->catdir($abs_srcdir, "extra") or die (File::Spec->catdir($abs_srcdir, "extra") . ": $!\n");
1785         my @extras = map { File::Spec->case_tolerant() ? lc($_) : $_ } (readdir($dd));
1786         closedir $dd;
1787         undef $dd;
1788         opendir $dd, $abs_srcdir or die "$abs_srcdir: $!\n";
1789         my @sources = map { File::Spec->case_tolerant() ? lc($_) : $_ } (readdir($dd));
1790         closedir $dd;
1791         undef $dd;
1792         my $maxlen = (sort { $b <=> $a } (map {length($_)} (@extras)))[0];
1793         my %extras = ();
1794 EXTRA:  for my $extra (@extras) {
1795                 next if (File::Spec->curdir() eq $extra || File::Spec->updir() eq $extra);
1796                 next if ($extra eq '.svn');
1797                 my $abs_extra = File::Spec->catfile($abs_srcdir, "extra", $extra);
1798                 my $abs_source = File::Spec->catfile($abs_srcdir, $extra);
1799                 next unless ($extra =~ m/\.(cpp|h)$/ || (-d $abs_extra)); # C++ Source/Header, or directory
1800                 if (-l $abs_source) {
1801                         # Symlink, is it in the right place?
1802                         my $targ = readlink($abs_source);
1803                         my $abs_targ = File::Spec->rel2abs($targ, $abs_srcdir);
1804                         if ($abs_targ eq $abs_extra) {
1805                                 $extras{$extra} = "\e[32;1menabled\e[0m";
1806                         } else {
1807                                 $extras{$extra} = sprintf("\e[31;1mwrong symlink target (%s)\e[0m", $abs_targ);
1808                         }
1809                 } elsif (-e $abs_source) {
1810                         my ($devext, $inoext) = stat($abs_extra);
1811                         my ($devsrc, $inosrc, undef, $lnksrc) = stat($abs_source);
1812                         if ($lnksrc > 1) {
1813                                 if ($devsrc == $devext && $inosrc == $inoext) {
1814                                         $extras{$extra} = "\e[32;1menabled\e[0m";
1815                                 } else {
1816                                         $extras{$extra} = sprintf("\e[31;1mwrong hardlink target (%d:%d)\e[0m", $devsrc, $inosrc);
1817                                 }
1818                         } else {
1819                                 open my $extfd, "<", $abs_extra;
1820                                 open my $srcfd, "<", $abs_source;
1821                                 local $/ = undef;
1822                                 if (scalar(<$extfd>) eq scalar(<$srcfd>)) {
1823                                         $extras{$extra} = "\e[32;1menabled\e[0m";
1824                                 } else {
1825                                         $extras{$extra} = sprintf("\e[31;1mout of synch (re-copy)\e[0m");
1826                                 }
1827                         }
1828                 } else {
1829                         $extras{$extra} = "\e[33;1mdisabled\e[0m";
1830                 }
1831         }
1832         # Now let's add dependency info
1833         for my $extra (keys(%extras)) {
1834                 next unless $extras{$extra} =~ m/enabled/; # only process enabled extras.
1835                 my $abs_extra = File::Spec->catfile($abs_srcdir, "extra", $extra);
1836                 my @deps = split / +/, getdependencies($abs_extra);
1837                 for my $dep (@deps) {
1838                         if (exists($extras{$dep})) {
1839                                 my $ref = \$extras{$dep}; # Take reference.
1840                                 if ($$ref !~ m/needed by/) {
1841                                         # First dependency found.
1842                                         if ($$ref =~ m/enabled/) {
1843                                                 $$ref .= " (needed by \e[32;1m$extra\e[0m";
1844                                         } else {
1845                                                 $$ref =~ s/\e\[.*?m//g; # Strip out previous coloring. Will be set in bold+red+blink later.
1846                                                 $$ref .= " (needed by \e[0;32;1;5m$extra\e[0;31;1;5m";
1847                                         }
1848                                 } else {
1849                                         if ($$ref =~ m/enabled/) {
1850                                                 $$ref .= ", \e[32;1m$extra\e[0m";
1851                                         } else {
1852                                                 $$ref .= ", \e[0;32;1;5m$extra\e[0;31;1;5m";
1853                                         }
1854                                 }
1855                         }
1856                 }
1857         }
1858         for my $extra (sort {$a cmp $b} keys(%extras)) {
1859                 my $text = $extras{$extra};
1860                 if ($text =~ m/needed by/ && $text !~ m/enabled/) {
1861                         printf "\e[31;1;5m%-*s = %s%s\e[0m\n", $maxlen, $extra, $text, ($text =~ m/needed by/ ? ")" : "");
1862                 } else {
1863                         printf "%-*s = %s%s\n", $maxlen, $extra, $text, ($text =~ m/needed by/ ? "\e[0m)" : "");
1864                 }
1865         }
1866         return keys(%extras) if wantarray; # Can be used by manage_extras.
1867 }
1868
1869 sub enable_extras (@) {
1870         my (@extras) = @_;
1871         for my $extra (@extras) {
1872                 my $extrapath = "src/modules/extra/$extra";
1873                 if (!-e $extrapath) {
1874                         print STDERR "Cannot enable \e[32;1m$extra\e[0m : No such file or directory in src/modules/extra\n";
1875                         next;
1876                 }
1877                 my $source = "src/modules/$extra";
1878                 if (-e $source) {
1879                         print STDERR "Cannot enable \e[32;1m$extra\e[0m : destination in src/modules exists (might already be enabled?)\n";
1880                         next;
1881                 }
1882                 # Get dependencies, and add them to be processed.
1883                 my @deps = split / +/, getdependencies($extrapath);
1884                 for my $dep (@deps) {
1885                         next if scalar(grep { $_ eq $dep } (@extras)) > 0; # Skip if we're going to be enabling it anyway.
1886                         if (!-e "src/modules/$dep") {
1887                                 if (-e "src/modules/extra/$dep") {
1888                                         print STDERR "Will also enable extra \e[32;1m$dep\e[0m (needed by \e[32;1m$extra\e[0m)\n";
1889                                         push @extras, $dep;
1890                                 } else {
1891                                         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";
1892                                 }
1893                         }
1894                 }
1895                 print "Enabling $extra ... \n";
1896                 symlink "extra/$extra", $source or print STDERR "$source: Cannot link to 'extra/$extra': $!\n";
1897         }
1898 }
1899
1900 sub disable_extras (@)
1901 {
1902         opendir my $dd, "src/modules/extra/";
1903         my @files = readdir($dd);
1904         closedir $dd;
1905         my (@extras) = @_;
1906 EXTRA:  for my $extra (@extras) {
1907                 my $extrapath = "src/modules/extra/$extra";
1908                 my $source = "src/modules/$extra";
1909                 if (!-e $extrapath) {
1910                         print STDERR "Cannot disable \e[32;1m$extra\e[0m : Is not an extra\n";
1911                         next;
1912                 }
1913                 if ((! -l $source) || readlink($source) ne "extra/$extra") {
1914                         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";
1915                         next;
1916                 }
1917                 # Check if anything needs this.
1918                 for my $file (@files) {
1919                         my @deps = split / +/, getdependencies("src/modules/extra/$file");
1920                         # File depends on this extra...
1921                         if (scalar(grep { $_ eq $extra } @deps) > 0) {
1922                                 # And is both enabled and not about to be disabled.
1923                                 if (-e "src/modules/$file" && scalar(grep { $_ eq $file } @extras) < 1) {
1924                                         print STDERR "Cannot disable \e[32;1m$extra\e[0m : is needed by \e[32;1m$file\e[0m\n";
1925                                         next EXTRA;
1926                                 }
1927                         }
1928                 }
1929                 # Now remove.
1930                 print "Disabling $extra ... \n";
1931                 unlink "src/modules/$extra" or print STDERR "Cannot disable \e[32;1m$extra\e[0m : $!\n";
1932         }
1933 }