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