]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - configure
e47512a9717308530d758c4944cc93c7da55a4ff
[user/henk/code/inspircd.git] / configure
1 #!/usr/bin/perl
2 ###################################################
3 # InspIRCd Configuration Script
4 #
5 # Copyright 2002-2008 The InspIRCd Development Team
6 #  http://www.inspircd.org/wiki/index.php/Credits
7 #
8 # Licensed under GPL, please see the COPYING file
9 # for more information
10 #
11 # $Id$
12 #
13 ###################################################
14
15 BEGIN {
16         require 5.8.0;
17 }
18
19 use strict;
20 use warnings FATAL => qw(all);
21
22 use Data::Dumper;
23 BEGIN {
24         $Data::Dumper::Sortkeys = 1;
25         $Data::Dumper::Useqq = 1;
26 };
27
28 use File::Copy ();
29
30 use Socket;
31 use Cwd;
32 use Getopt::Long;
33
34 # Utility functions for our buildsystem
35 use make::utilities;
36 use make::configure;
37 use make::gnutlscert;
38 use make::opensslcert;
39
40 ###############################################################################################
41 #
42 #                                   EDITABLE VARIABLES
43 #
44 ###############################################################################################
45
46 # If you wish to ignore a dependency throughout the entire core, add it here.
47
48 our @ignoredeps = (
49         "inspircd_win32wrapper.h",      # windows has its own configure program
50 );
51
52 # If you wish for all files in the entire core to have a given dependency, insert it here.
53 # You should keep this to an absolute minimum to avoid rebuilds that are not neccessary.
54
55 our @immutabledeps = (
56         "inspircd_config.h",            # auto re-generated by configure
57         "inspircd.h",
58 );
59
60 ###############################################################################################
61 #
62 #                                 NON-EDITABLE VARIABLES
63 #
64 ###############################################################################################
65
66 # List of commands that make up 'make install' and 'make deinstall'
67
68 our $install_list = "";
69 our $uninstall_list = "";
70
71 # This is a list of all files in the core. Each cpp file is mapped to a shared object file,
72 # whos file extension is omitted (these can vary from system to system). Auto detected by
73 # scanning the src/*.cpp files for files containing /* $Core */ identifiers.
74
75 our %filelist = ();
76
77 # If you wish for a file to have special dependencies in the makefile, add an entry here.
78 # Auto populated by /* $ExtraDeps: */ instruction
79
80 our %specialdeps = ();
81
82 # If you wish for a file to have extra make lines (in between the compile and link steps)
83 # then insert them here.
84 # Auto populated by /* $ExtraBuild: */ instruction
85         
86 our %extrabuildlines = ();
87
88 # If you wish for a file to be linked against extra objects or arctives, insert them here.
89 # Auto populated by /* $ExtraObjects: */ instruction
90
91 our %extraobjects = ();
92
93 # If you wish to compile extra cpp sources into an object, define them here.
94 # NOTE: Certain cpp files such as the socket engines have a value auto calculated
95 # for this table so that their derived class is built.
96 # Auto populated by /* $ExtraSources: */ instruction
97
98 our %extrasources = ();
99
100 our ($opt_use_gnutls, $opt_rebuild, $opt_use_openssl, $opt_nointeractive, $opt_ports,
101     $opt_epoll, $opt_kqueue, $opt_noports, $opt_noepoll, $opt_nokqueue,
102     $opt_ipv6, $opt_ipv6links, $opt_noipv6links, $opt_maxbuf, $opt_disable_debug,
103     $opt_freebsd_port);
104
105 our ($opt_cc, $opt_base_dir, $opt_config_dir, $opt_module_dir, $opt_binary_dir,
106     $opt_library_dir);
107
108 sub list_extras ();
109
110 sub enable_extras (@);
111
112 sub disable_extras (@);
113
114 my @opt_enableextras;
115 my @opt_disableextras;
116
117 GetOptions (
118         'enable-gnutls' => \$opt_use_gnutls,
119         'rebuild' => \$opt_rebuild,
120         'enable-openssl' => \$opt_use_openssl,
121         'disable-interactive' => \$opt_nointeractive,
122         'enable-ports' => \$opt_ports,
123         'enable-epoll' => \$opt_epoll,
124         'enable-kqueue' => \$opt_kqueue,
125         'disable-ports' => \$opt_noports,
126         'disable-epoll' => \$opt_noepoll,
127         'disable-kqueue' => \$opt_nokqueue,
128         'enable-ipv6' => \$opt_ipv6,
129         'enable-remote-ipv6' => \$opt_ipv6links,
130         'disable-remote-ipv6' => \$opt_noipv6links,
131         'with-cc=s' => \$opt_cc,
132         'with-maxbuf=i' => \$opt_maxbuf,
133         'enable-freebsd-ports-openssl' => \$opt_freebsd_port,
134         'prefix=s' => \$opt_base_dir,
135         'config-dir=s' => \$opt_config_dir,
136         'module-dir=s' => \$opt_module_dir,
137         'binary-dir=s' => \$opt_binary_dir,
138         'library-dir=s' => \$opt_library_dir,
139         'disable-debuginfo' => sub { $opt_disable_debug = 1 },
140         'help'  => sub { showhelp(); },
141         'modupdate' => sub { modupdate(); },
142         'update' => sub { update(); },
143         'svnupdate' => sub { svnupdate(); },
144         'clean' => sub { clean(); },
145         'list-extras' => sub { list_extras; exit 0; }, # This, --enable-extras, and --disable-extras are for non-interactive managing.
146         'enable-extras=s@' => \@opt_enableextras, # ^
147         'disable-extras=s@' => \@opt_disableextras, # ^
148 );
149
150 if (scalar(@opt_enableextras) + scalar(@opt_disableextras) > 0) {
151         @opt_enableextras = split /,/, join(',', @opt_enableextras);
152         @opt_disableextras = split /,/, join(',', @opt_disableextras);
153         enable_extras(@opt_enableextras);
154         disable_extras(@opt_disableextras);
155         list_extras;
156         print "Remember: YOU are responsible for making sure any libraries needed have been installed!\n";
157         print "Run $0 -modupdate after you've done this to update the makefiles.\n";
158         exit 0;
159 }
160
161 our $non_interactive = (
162         (defined $opt_library_dir) ||
163         (defined $opt_base_dir) ||
164         (defined $opt_config_dir) ||
165         (defined $opt_module_dir) ||
166         (defined $opt_base_dir) ||
167         (defined $opt_binary_dir) ||
168         (defined $opt_nointeractive) ||
169         (defined $opt_cc) ||
170         (defined $opt_ipv6) ||
171         (defined $opt_ipv6links) ||
172         (defined $opt_noipv6links) ||
173         (defined $opt_kqueue) ||
174         (defined $opt_epoll) ||
175         (defined $opt_ports) ||
176         (defined $opt_use_openssl) ||
177         (defined $opt_nokqueue) ||
178         (defined $opt_noepoll) ||
179         (defined $opt_noports) ||
180         (defined $opt_maxbuf) ||
181         (defined $opt_use_gnutls) ||
182         (defined $opt_freebsd_port)
183 );
184 our $interactive = !$non_interactive;
185
186 chomp(our $topdir = getcwd());
187 our $this = resolve_directory($topdir);                                         # PWD, Regardless.
188 our @modlist = ();                                                                      # Declare for Module List..
189 our %config = ();                                                                       # Initiate Configuration Hash..
190 $config{ME}              = resolve_directory($topdir);                          # Present Working Directory
191
192 $config{BASE_DIR}          = $config{ME};
193
194 if (defined $opt_base_dir)
195 {
196         $config{BASE_DIR} = $opt_base_dir;
197 }
198
199 $config{CONFIG_DIR}      = resolve_directory($config{BASE_DIR}."/conf");        # Configuration Directory
200 $config{MODULE_DIR}      = resolve_directory($config{BASE_DIR}."/modules");     # Modules Directory
201 $config{BINARY_DIR}      = resolve_directory($config{BASE_DIR}."/bin");         # Binary Directory
202 $config{LIBRARY_DIR}    = resolve_directory($config{BASE_DIR}."/lib");          # Library Directory
203
204 if (defined $opt_config_dir)
205 {
206         $config{CONFIG_DIR} = $opt_config_dir;
207 }
208 if (defined $opt_module_dir)
209 {
210         $config{MODULE_DIR} = $opt_module_dir;
211 }
212 if (defined $opt_binary_dir)
213 {
214         $config{BINARY_DIR} = $opt_binary_dir;
215 }
216 if (defined $opt_library_dir)
217 {
218         $config{LIBRARY_DIR} = $opt_library_dir;
219 }
220 chomp($config{HAS_GNUTLS}   = `libgnutls-config --version 2>/dev/null | cut -c 1,2,3`); # GNUTLS Version.
221
222 if (defined $opt_freebsd_port)
223 {
224         chomp($config{HAS_OPENSSL} = `pkg-config --modversion openssl 2>/dev/null`);
225         chomp($config{HAS_OPENSSL_PORT}  = `pkg-config --modversion openssl 2>/dev/null`);
226         $config{USE_FREEBSD_BASE_SSL} = "n";
227 }
228 else
229 {
230         if ($^O eq "freebsd")
231         {
232                 # default: use base ssl
233                 chomp($config{HAS_OPENSSL} = `openssl version | cut -d ' ' -f 2`);                      # OpenSSL version, freebsd specific
234                 chomp($config{HAS_OPENSSL_PORT}  = `pkg-config --modversion openssl 2>/dev/null`);      # Port version, may be different
235         }
236         else
237         {
238                 chomp($config{HAS_OPENSSL}  = `pkg-config --modversion openssl 2>/dev/null`);           # Openssl version, others
239                 $config{HAS_OPENSSL_PORT} = "";
240         }
241 }
242
243 chomp(our $gnutls_ver = $config{HAS_GNUTLS});
244 chomp(our $openssl_ver = $config{HAS_OPENSSL});
245 $config{USE_GNUTLS}         = "n";
246 if (defined $opt_use_gnutls)
247 {
248         $config{USE_GNUTLS} = "y";                                      # Use gnutls.
249 }
250 $config{USE_OPENSSL}    = "n";                                          # Use openssl.
251 if (defined $opt_use_openssl)
252 {
253         $config{USE_OPENSSL} = "y";
254 }
255
256 # no, let's not change these.
257 $config{OPTIMITEMP}      = "0";                                         # Default Optimisation Value
258 if (!defined $opt_disable_debug)
259 {
260         $config{OPTIMISATI}      = "-g1";                               # Optimisation Flag
261 }
262 else
263 {
264         $config{OPTIMISATI}      = "-O2";                               # DEBUGGING OFF!
265 }
266
267 $config{HAS_STRLCPY}    = "false";                                      # strlcpy Check.
268 $config{HAS_STDINT}      = "false";                                     # stdint.h check
269 $config{USE_KQUEUE}      = "y";                                         # kqueue enabled
270 if (defined $opt_kqueue)
271 {
272         $config{USE_KQUEUE} = "y";
273 }
274 if (defined $opt_nokqueue)
275 {
276         $config{USE_KQUEUE} = "n";
277 }
278 $config{USE_EPOLL}        = "y";                                        # epoll enabled
279 if (defined $opt_epoll)
280 {
281         $config{USE_EPOLL} = "y";
282 }
283 if (defined $opt_noepoll)
284 {
285         $config{USE_EPOLL} = "n";
286 }
287 $config{USE_PORTS}        = "y";                                        # epoll enabled
288 if (defined $opt_ports)
289 {
290         $config{USE_PORTS} = "y";
291 }
292 if (defined $opt_noports)
293 {
294         $config{USE_PORTS} = "n";
295 }
296 $config{IPV6}          = "n";                                           # IPv6 support (experimental)
297 if (defined $opt_ipv6)
298 {
299         $config{IPV6} = "y";
300 }
301 $config{SUPPORT_IP6LINKS}   = "y";                                      # IPv4 supporting IPv6 links (experimental)
302 if (defined $opt_ipv6links)
303 {
304         $config{SUPPORT_IP6LINKS} = "y";
305 }
306 if (defined $opt_noipv6links)
307 {
308         $config{SUPPORT_IP6LINKS} = "n";
309 }
310 chomp($config{GCCVER}       = `g++ -dumpversion | cut -c 1`);           # Major GCC Version
311 chomp($config{GCCMINOR}     = `g++ -dumpversion | cut -c 3`);
312 $config{_SOMAXCONN} = SOMAXCONN;                                        # Max connections in accept queue
313 $config{OSNAME}             = $^O;                                      # Operating System Name
314 $config{IS_DARWIN}        = "NO";                                       # Is OSX?
315 $config{STARTSCRIPT}      = "inspircd";                 # start script?
316 $config{DESTINATION}      = "BASE";                             # Is target path.
317 $config{EXTRA_DIR}        = "";                                         # Is empty.
318 if ($config{OSNAME} =~ /darwin/i)
319 {
320         $config{IS_DARWIN} = "YES";
321         $config{STARTSCRIPT}      = "org.inspircd.plist";               # start script for OSX.
322         $config{DESTINATION}      = "LAUNCHDPATH";                              # Is OSX target.
323         $config{EXTRA_DIR}          = " launchd_dir";                           # Is OSX specific path.
324 }
325 $config{CC}                 = "g++";                                            # C++ compiler
326 if (defined $opt_cc)
327 {
328         $config{CC} = $opt_cc;
329 }
330 our $exec = $config{CC} . " -dumpversion | cut -c 1";
331 chomp($config{GCCVER}           = `$exec`);                             # Major GCC Version
332 $exec = $config{CC} . " -dumpversion | cut -c 3";
333 chomp($config{GCCMINOR}         = `$exec`);
334 $config{MAKEORDER}              = "ircd mods";                          # build order
335 $config{MAXBUF}                 = "512";                                # Max buffer size
336
337 if ($config{HAS_OPENSSL} =~ /^([-[:digit:].]+)([a-z])?(\-[a-z][0-9])?$/) {
338         $config{HAS_OPENSSL} = $1;
339 } else {
340         $config{HAS_OPENSSL} = "";
341 }
342
343 if (($config{GCCVER} eq "") || ($config{GCCMINOR} eq "")) {
344         print $config{CC} . " was not found! You require g++ (the GNU C++ compiler, part of GCC) to build InspIRCd!\n";
345         exit;
346 }
347
348 # Get and Set some important vars..
349 getmodules();
350
351 sub clean
352 {
353         unlink(".config.cache");
354 }
355
356 our ($has_epoll, $has_ports, $has_kqueue) = (0, 0, 0);
357
358 sub update
359 {
360         eval {
361                 chomp($topdir = getcwd());
362                 $this = resolve_directory($topdir);                                          # PWD, Regardless.
363                 getmodules();
364                 # Does the cache file exist?
365                 if (!getcache()) {
366                         # No, No it doesn't.. *BASH*
367                         print "You have not run ./configure before. Please do this before trying to run the update script.\n";
368                         exit 0;
369                 } else {
370                         # We've Loaded the cache file and all our variables..
371                         print "Updating files...\n";
372                         getosflags();
373                         if (defined($opt_disable_debug) && $opt_disable_debug == 1)
374                         {
375                                 print "Disabling debug information (-g).\n";
376                                 $config{OPTIMISATI} = "";
377                                 getosflags();
378                         }
379                         $has_epoll = $config{HAS_EPOLL};
380                         $has_ports = $config{HAS_PORTS};
381                         $has_kqueue = $config{HAS_KQUEUE};
382                         writefiles(1);
383                         makecache();
384                         print "Complete.\n";
385                         exit;
386                 }
387         };
388         if ($@)
389         {
390                 print "Configure update failed: $@\n";
391         }
392         exit;
393 }
394
395 sub modupdate
396 {
397         eval {
398                 chomp($topdir = getcwd());
399                 $this = resolve_directory($topdir);                                          # PWD, Regardless.
400                 getmodules();
401                 # Does the cache file exist?
402                 if (!getcache()) {
403                         # No, No it doesn't.. *BASH*
404                         print "You have not run ./configure before. Please do this before trying to run the update script.\n";
405                         exit 0;
406                 } else {
407                         # We've Loaded the cache file and all our variables..
408                         print "Updating files...\n";
409                         getosflags();
410                         $has_epoll = $config{HAS_EPOLL};
411                         $has_ports = $config{HAS_PORTS};
412                         $has_kqueue = $config{HAS_KQUEUE};
413                         writefiles(0);
414                         makecache();
415                         print "Complete.\n";
416                         exit;
417                 }
418         };
419         if ($@)
420         {
421                 print "Module update failed: $@\n";
422         }
423         exit;
424 }
425
426
427
428 sub svnupdate
429 {
430         my $fail = 0;
431         open(FH,"<.svn/entries") or $fail = 1;
432         if ($fail) {
433                 print "This is not an SVN copy of InspIRCd.\n";
434                 exit 1;
435         }
436         else
437         {
438                 close(FH);
439         }
440         open my $fd, "-|", "svn update";
441         my $configurechanged = 0; # Needs ./configure -update
442         my $coredirchanged = 0; # Needs ./configure -update
443         my $moduledirchanged = 0; # Needs ./configure -modupdate
444         my $rootincchanged = 0;
445         my @conflicted = ();
446         while (defined(my $line = <$fd>))
447         {
448                 my ($action, $file);
449                 print $line;
450                 $line =~ m/^([ADUCG])\s+(.*)$/ or next;
451                 ($action, $file) = ($1, $2);
452                 if ($action eq "C")
453                 {
454                         push @conflicted, $file;
455                         if ($file eq "configure")
456                         {
457                                 $configurechanged = 1;
458                         }
459                         elsif ($file =~ m#^src/modules#)
460                         {
461                                 $moduledirchanged = 1;
462                         }
463                         elsif ($file =~ m#^src/#)
464                         {
465                                 $coredirchanged = 1;
466                         }
467                         elsif ($file =~ m/^\..*\.inc$/)
468                         {
469                                 $rootincchanged = 1;
470                         }
471                 }
472                 elsif ($action eq "U" || $action eq "G")
473                 {
474                         if ($file eq "configure")
475                         {
476                                 $configurechanged = 1;
477                         }
478                         elsif ($file =~ m/^\..*\.inc$/)
479                         {
480                                 $rootincchanged = 1;
481                         }
482                 }
483                 elsif ($action eq "A" || $action eq "D")
484                 {
485                         if ($file =~ m#^src/modules#)
486                         {
487                                 $moduledirchanged = 1;
488                         }
489                         elsif ($file =~ m#^src/#)
490                         {
491                                 $coredirchanged = 1;
492                         }
493                 }
494         }
495         unless (close $fd) # close() waits for exit and returns false if the command failed
496         {
497                 if ($! == 0)
498                 {
499                         print STDERR "Problem updating from SVN, please check above for errors\n";
500                 }
501                 else
502                 {
503                         print STDERR "Failed to run SVN: $!\n";
504                 }
505                 exit 1;
506         }
507         if (scalar(@conflicted) > 0)
508         {
509                 print STDERR "\e[0;33;1mERROR:\e[0m You have local modifications which conflicted with the updates from SVN\n";
510                 printf STDERR "Configure is not able to complete the update. Please resolve these conflicts, then run ./configure -%supdate\n", (($coredirchanged || $configurechanged) ? "" : "mod");
511                 print "Conflicted files: " . join ", ", @conflicted . "\n";
512                 exit 1;
513         }
514         if ($configurechanged || $coredirchanged)
515         {
516                 system("perl configure -update");
517         }
518         elsif ($moduledirchanged || $rootincchanged)
519         {
520                 system("perl configure -modupdate");
521         }
522         else
523         {
524                 print "No need to update Makefiles.\n";
525         }
526         if (defined $opt_rebuild) {
527                 system("make install");
528         }
529         exit;
530 }
531
532 print "Running non-interactive configure...\n" unless $interactive;
533 print "Checking for cache from previous configure... ";
534 print ((!getcache()) ? "not found\n" : "found\n");
535 print "Checking operating system version... ";
536 print getosflags() . "\n";
537
538 printf "Checking if stdint.h exists... ";
539 $config{HAS_STDINT} = "true";
540 our $fail = 0;
541 open(STDINT, "</usr/include/stdint.h") or $config{HAS_STDINT} = "false";
542 if ($config{HAS_STDINT} eq "true") {
543         close(STDINT);
544 }
545 print "yes\n" if $config{HAS_STDINT} eq "true";
546 print "no\n" if $config{HAS_STDINT} eq "false";
547
548 printf "Checking if strlcpy exists... ";
549 # Perform the strlcpy() test..
550 $config{HAS_STRLCPY} = "false";
551 $fail = 0;
552 open(STRLCPY, "</usr/include/string.h") or $fail = 1;
553 if (!$fail) {
554         while (defined(my $line = <STRLCPY>)) {
555                 chomp($line);
556                 # try and find the delcaration of:
557                 # size_t strlcpy(...)
558                 if ($line =~ /size_t(\0x9|\s)+strlcpy/) {
559                         $config{HAS_STRLCPY} = "true";
560                 }
561         }
562         close(STRLCPY);
563 }
564 print "yes\n" if $config{HAS_STRLCPY} eq "true";
565 print "no\n" if $config{HAS_STRLCPY} eq "false";
566
567 printf "Checking if kqueue exists... ";
568 $has_kqueue = 0;
569 $fail = 0;
570 open(KQUEUE, "</usr/include/sys/event.h") or $fail = 1;
571 if (!$fail) {
572         while (defined(my $line = <KQUEUE>)) {
573                 chomp($line);
574                 # try and find the delcaration of:
575                 # int kqueue(void);
576                 if ($line =~ /int(\0x9|\s)+kqueue/) {
577                         $has_kqueue = 1;
578                 }
579         }
580         close(KQUEUE);
581 }
582 print "yes\n" if $has_kqueue == 1;
583 print "no\n" if $has_kqueue == 0;
584
585 printf "Checking if epoll exists... ";
586 $has_epoll = 0;
587 $fail = 0;
588 open(EPOLL, "</usr/include/sys/epoll.h") or $fail = 1;
589 if (!$fail) {
590         $has_epoll = 1;
591         close(EPOLL);
592 }
593 if ($has_epoll) {
594         my $kernel = `uname -r`;
595         chomp($kernel);
596         if (($kernel =~ /^2\.0\./) || ($kernel =~ /^2\.2\./) || ($kernel =~ /^2\.4\./)) {
597                 $has_epoll = 0;
598         }
599         else
600         {
601                 # Suggestion from nenolod, weed out odd systems which have glibc built
602                 # against 2.4 kernels (ick)
603                 my $kernel_arch = `uname -p`;
604                 chomp($kernel_arch);
605                 my $libcv = 0.0;
606                 my $kernelv = 0.0;
607                 if ($kernel_arch =~ /x86_64/) {
608                         open (FH,"/lib64/libc.so.6|") or $has_epoll = 0;
609                 }
610                 else {
611                         open (FH,"/lib/libc.so.6|") or $has_epoll = 0;
612                 }
613                 if ($has_epoll)
614                 {
615                         while (defined(my $line = <FH>))
616                         {
617                                 chomp($line);
618                                 if ($line =~ /GNU C Library .* version (.*?) /)
619                                 {
620                                         $libcv = $1;
621                                         $libcv =~  /(\d+\.\d+)/;
622                                         $libcv = $1;
623                                 }
624                                 elsif ($line =~ /Compiled on a Linux (.*?\..*?)\.* system/)
625                                 {
626                                         $kernelv = $1;
627                                         # Fix for some retarded libc builds, strip off >> and << etc.
628                                         $kernelv =~ /(\d+\.\d+)/;
629                                         $kernelv = $1;
630                                 }
631                         }
632                         close FH;
633                         if ($libcv < 2.3)
634                         {
635                                 $has_epoll = 0;
636                                 printf "libc too old: $libcv... ";
637                         }
638                         if ($kernelv < 2.6)
639                         {
640                                 $has_epoll = 0;
641                                 printf "libc built against older kernel $kernelv... ";
642                         }
643                 }
644         }
645 }
646 print "yes\n" if $has_epoll == 1;
647 print "no\n" if $has_epoll == 0;
648
649 printf "Checking if Solaris I/O completion ports are available... ";
650 $has_ports = 0;
651 our $system = `uname -s`;
652 chomp ($system);
653 $has_ports = 1 if ($system eq "SunOS");
654
655 if ($has_ports) {
656         my $kernel = `uname -r`;
657         chomp($kernel);
658         if (($kernel !~ /^5\.1./)) {
659                 $has_ports = 0;
660         }
661 }
662 print "yes\n" if $has_ports == 1;
663 print "no\n" if $has_ports == 0;
664
665 $config{HAS_EPOLL} = $has_epoll;
666 $config{HAS_KQUEUE} = $has_kqueue; 
667
668 printf "Checking for libgnutls... ";
669 if (defined($config{HAS_GNUTLS}) && (($config{HAS_GNUTLS}) || ($config{HAS_GNUTLS} eq "y"))) {
670         print "yes\n";
671         $config{HAS_GNUTLS} = "y";
672 } else {
673         print "no\n";
674         $config{HAS_GNUTLS} = "n";
675 }
676
677 printf "Checking for openssl... ";
678 if (defined($config{HAS_OPENSSL}) && (($config{HAS_OPENSSL}) || ($config{HAS_OPENSSL} eq "y"))) {
679         print "yes\n";
680         $config{HAS_OPENSSL} = "y";
681 } else {
682         print "no\n";
683         $config{HAS_OPENSSL} = "n";
684 }
685
686 printf "Checking if you are running an ancient, unsupported OS... ";
687 if ($config{OSNAME} =~ /FreeBSD/i)
688 {
689         my $version = `uname -r`;
690         if ($version =~ /^4\./)
691         {
692                 my $foundit = `ls -l /usr/local/lib/libgnugetopt* | wc -l`;
693                 if ($foundit > 0)
694                 {
695                         # ICKY ICKY ICK, FREEBSD 4.x! GET AN UPGRADE!
696                         $config{CRAQ} = "-L/usr/local/lib -lgnugetopt -DHAVE_DECL_GETOPT=1";
697                         print "yes\n";
698                 }
699                 else
700                 {
701                         print "\n\nERROR: You require libgnugetopt (from ports or packages) to build InspIRCd on FreeBSD 4.11.\n";
702                 }
703         }
704         else
705         {
706                 $config{CRAQ} = " ";
707                 print "no ($version)\n";
708         }
709 }
710 else
711 {
712         $config{CRAQ} = " ";
713         print "no ($config{OSNAME})\n";
714 }
715
716 ################################################################################
717 #                         BEGIN INTERACTIVE PART                              #
718 ################################################################################
719
720 # Clear the Screen..
721 if ($interactive)
722 {
723         print "\e[2J\e[0G\e[0d"; # J = Erase in Display, 2 = Entire Screen, (G, d) = Move cursor to (..,..)
724         my $wholeos = $^O;
725
726         my $rev = getrevision();
727         # Display Introduction Message..
728         print <<"STOP" ;
729 Welcome to the \e[1mInspIRCd\e[0m Configuration program! (\e[1minteractive mode\e[0m)
730 \e[1mPackage maintainers: Type ./configure --help for non-interactive help\e[0m
731
732 *** If you are unsure of any of these values, leave it blank for    ***
733 *** standard settings that will work, and your server will run      ***
734 *** using them. Please consult your IRC network admin if in doubt.  ***
735
736 Press \e[1m<RETURN>\e[0m to accept the default for any option, or enter
737 a new value. Please note: You will \e[1mHAVE\e[0m to read the docs
738 dir, otherwise you won't have a config file!
739
740 Your operating system is: \e[1;32m$config{OSNAME}\e[0m ($wholeos)
741 Your InspIRCd revision ID is \e[1;32mr$rev\e[0m
742 STOP
743         if ($rev eq "r0") {
744                 print " (Non-SVN build)";
745         }
746         print ".\n\n";
747
748         $config{CHANGE_COMPILER} = "n";
749         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";
750
751         while (($config{GCCVER} < 3) || ($config{GCCVER} eq "")) {
752                 print "\e[1;32mIMPORTANT!\e[0m A GCC 2.x compiler has been detected, and
753 should NOT be used. You should probably specify a newer compiler.\n\n";
754                 yesno('CHANGE_COMPILER',"Do you want to change the compiler?");
755                 if ($config{CHANGE_COMPILER} =~ /y/i) {
756                         print "What command do you want to use to invoke your compiler?\n";
757                         print "[\e[1;32m$config{CC}\e[0m] -> ";
758                         chomp($config{CC} = <STDIN>);
759                         if ($config{CC} eq "") {
760                                 $config{CC} = "g++";
761                         }
762                         chomp(my $foo = `$config{CC} -dumpversion | cut -c 1`);
763                         if ($foo ne "") {
764                                 chomp($config{GCCVER}       = `$config{CC} -dumpversion | cut -c 1`); # we must redo these if we change compilers
765                                 chomp($config{GCCMINOR}     = `$config{CC} -dumpversion | cut -c 3`);
766                                 print "Queried compiler: \e[1;32m$config{CC}\e[0m (version \e[1;32m$config{GCCVER}.$config{GCCMINOR}\e[0m)\n";
767                                 if ($config{GCCVER} < 3) {
768                                         print "\e[1;32mGCC 2.x WILL NOT WORK!\e[0m. Let's try that again, shall we?\n";
769                                 }
770                         }
771                         else {
772                                 print "\e[1;32mWARNING!\e[0m Could not execute the compiler you specified. You may want to try again.\n";
773                         }
774                 }
775         }
776
777         print "\n";
778
779         # Directory Settings..
780         my $tmpbase = $config{BASE_DIR};
781         dir_check("do you wish to install the InspIRCd base", "BASE_DIR");
782         if ($tmpbase ne $config{BASE_DIR}) {
783                 $config{CONFIG_DIR}      = resolve_directory($config{BASE_DIR}."/conf");           # Configuration Dir
784                 $config{MODULE_DIR}      = resolve_directory($config{BASE_DIR}."/modules");     # Modules Directory
785                 $config{BINARY_DIR}      = resolve_directory($config{BASE_DIR}."/bin");     # Binary Directory
786                 $config{LIBRARY_DIR}    = resolve_directory($config{BASE_DIR}."/lib");      # Library Directory
787         }
788
789         dir_check("are the configuration files", "CONFIG_DIR");
790         dir_check("are the modules to be compiled to", "MODULE_DIR");
791         dir_check("is the IRCd binary to be placed", "BINARY_DIR");
792         dir_check("are the IRCd libraries to be placed", "LIBRARY_DIR");
793
794         if ($has_kqueue) {
795                 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?");
796                 print "\n";
797         }
798         if ($has_epoll) {
799                 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?");
800                 print "\n";
801         }
802         if ($has_ports) {
803                 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?");
804                 print "\n";
805         }
806         my $chose_hiperf = (($config{USE_EPOLL} eq "y") || ($config{USE_KQUEUE} eq "y") || ($config{USE_PORTS} eq "y"));
807         if (!$chose_hiperf) {
808                 print "No high-performance socket engines are available, or you chose\n";
809                 print "not to enable one. Defaulting to select() engine.\n\n";
810         }
811
812         yesno('IPV6',"Would you like to build InspIRCd with IPv6 support?");
813         print "\n";
814
815         if ($config{IPV6} eq "y") {
816                 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";
817                 $config{SUPPORT_IP6LINKS} = "y";
818         } else {
819                 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?");
820                 print "\n";
821         }
822
823         $config{USE_FREEBSD_BASE_SSL} = "n";
824         $config{USE_FREEBSD_PORTS_SSL} = "n";
825         if ($config{HAS_OPENSSL_PORT} ne "")
826         {
827                 $config{USE_FREEBSD_PORTS_SSL} = "y";
828                 print "I have detected the OpenSSL FreeBSD port installed on your system,\n";
829                 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";
830                 yesno('USE_FREEBSD_PORTS_SSL', "Do you want to use the FreeBSD ports version?");
831                 print "\n";
832                 $config{USE_FREEBSD_BASE_SSL} = "y" if ($config{USE_FREEBSD_PORTS_SSL} eq "n");
833
834                 if ($config{USE_FREEBSD_BASE_SSL} eq "n")
835                 {
836                         # update to port version
837                         $openssl_ver = $config{HAS_OPENSSL_PORT};
838                 }
839         }
840         else
841         {
842                 $config{USE_FREEBSD_BASE_SSL} = "y" if ($^O eq "freebsd");
843         }
844
845         if (($config{HAS_GNUTLS} eq "y") && ($config{HAS_OPENSSL} eq "y")) {
846                 print "I have detected both \e[1;32mGnuTLS\e[0m and \e[1;32mOpenSSL\e[0m on your system.\n";
847                 print "I will default to GnuTLS. If you wish to use OpenSSL\n";
848                 print "instead, you should enable the OpenSSL module yourself\n";
849                 print "by copying it from src/modules/extra to src/modules.\n\n";
850                 print "Detected GnuTLS version: \e[1;32m" . $gnutls_ver . "\e[0m\n";
851                 print "Detected OpenSSL version: \e[1;32m" . $openssl_ver . "\e[0m\n\n";
852         }
853
854         if ($config{HAS_GNUTLS} eq "y") {
855                 yesno('USE_GNUTLS', "Would you like to enable SSL Support?");
856                 if ($config{USE_GNUTLS} eq "y") {
857                         print "\nUsing GnuTLS SSL module.\n";
858                 }
859         } elsif ($config{HAS_OPENSSL} eq "y") {
860                         yesno('USE_OPENSSL', "Would you like to enable SSL Support?");
861         if ($config{USE_OPENSSL} eq "y") {
862                         print "\nUsing OpenSSL SSL module.\nYou will get better performance if you move to GnuTLS in the future.\n";
863                 }
864         }
865         else {
866                 print "\nCould not detect OpenSSL or GnuTLS. Make sure pkg-config is installed if\nyou intend to use OpenSSL, or that GnuTLS is in your path if you intend\nto use GnuTLS.\n\n";
867         }
868 }
869
870 dumphash();
871
872 if (($config{USE_GNUTLS} eq "y") && ($config{HAS_GNUTLS} ne "y"))
873 {
874         print "Sorry, but i couldn't detect gnutls. Make sure gnutls-config is in your path.\n";
875         exit(0);
876 }
877 if (($config{USE_OPENSSL} eq "y") && ($config{HAS_OPENSSL} ne "y"))
878 {
879         print "Sorry, but i couldn't detect openssl. Make sure openssl is in your path.\n";
880         exit(0);
881 }
882 our $failed = 0;
883
884 if ($config{USE_GNUTLS} eq "y") {
885         unless (-r "src/modules/m_ssl_gnutls.cpp") {
886                 print "Symlinking src/modules/m_ssl_gnutls.cpp from extra/\n";
887                 symlink "extra/m_ssl_gnutls.cpp", "src/modules/m_ssl_gnutls.cpp" or print STDERR "Symlink failed: $!";
888         }
889         getmodules();
890         if ($interactive)
891         {
892                 unless (-r "$config{CONFIG_DIR}/key.pem" && -r "$config{CONFIG_DIR}/cert.pem") {
893                         print "SSL Certificates Not found, Generating.. \n\n
894 *************************************************************
895 * Generating the Private Key may take some time, go grab a  *
896 * Coffee. Even better, to generate some more entropy if it  *
897 * is taking a while, open another console and type du / a   *
898 * few times and get that HD going :) Then answer the        *
899 * Questions which follow. If you are unsure, just hit enter *
900 *************************************************************\n\n";
901                         $failed = make_gnutls_cert();
902                         if ($failed) {
903                                 print "\n\e[1;32mCertificate generation failed!\e[0m\n\n";
904                         } else {
905                                 print "\nCertificate generation complete, copying to config directory... ";
906                                 File::Copy::move("key.pem", "$config{CONFIG_DIR}/key.pem") or print STDERR "Could not copy key.pem!\n";
907                                 File::Copy::move("cert.pem", "$config{CONFIG_DIR}/cert.pem") or print STDERR "Could not copy cert.pem!\n";
908                                 print "Done.\n\n";
909                         }
910                 }
911                 else {
912                         print "SSL Certificates found, skipping.\n\n";
913                 }
914         }
915         else
916         {
917                 print "Skipping SSL certificate generation\nin non-interactive mode.\n\n";
918         }
919 } elsif ($config{USE_OPENSSL} eq "y") {
920         unless (-r "src/modules/m_ssl_openssl.cpp") {
921                 print "Symlinking src/modules/m_ssl_openssl.cpp from extra/\n";
922                 symlink "extra/m_ssl_openssl.cpp", "src/modules/m_ssl_openssl.cpp" or print STDERR "Symlink failed: $!";
923         }
924         getmodules();
925         $failed = 0;
926         if ($interactive)
927         {
928                 unless (-r "$config{CONFIG_DIR}/key.pem" && -r "$config{CONFIG_DIR}/cert.pem") {
929                         print "SSL Certificates Not found, Generating.. \n\n
930 *************************************************************
931 * Generating the certificates may take some time, go grab a *
932 * coffee, or something.                                     *
933 *************************************************************\n\n";
934                         make_openssl_cert();
935                         print "\nCertificate generation complete, copying to config directory... ";
936                         File::Copy::move("key.pem", "$config{CONFIG_DIR}/key.pem") or print STDERR "Could not copy key.pem!\n";
937                         File::Copy::move("cert.pem", "$config{CONFIG_DIR}/cert.pem") or print STDERR "Could not copy cert.pem!\n";
938                         File::Copy::move("dhparams.pem", "$config{CONFIG_DIR}/dhparams.pem") or print STDERR "Could not copy dhparams.pem!\n";
939                         print "Done.\n\n";
940                 } else {
941                         print "SSL Certificates found, skipping.\n\n"
942                 }
943         }
944         else
945         {
946                 print "Skipping SSL certificate generation\nin non-interactive mode.\n\n";
947         }
948 }
949 if (($config{USE_GNUTLS} eq "n") && ($config{USE_OPENSSL} eq "n")) {
950         print "Skipping SSL Certificate generation, SSL support is not available.\n\n";
951 }
952
953 getosflags();
954 writefiles(1);
955 makecache();
956
957 print "\n\n";
958 print "To build your server with these settings, please type '\e[1;32m$config{MAKEPROG}\e[0m' now.\n";
959 if (($config{USE_GNUTLS} eq "y") || ($config{USE_OPENSSL} eq "y")) {
960         print "Please note: for \e[1;32mSSL support\e[0m you will need to load required\n";
961         print "modules in your config. This configure script has added those modules to the\n";
962         print "build process. For more info please refer to:\n";
963         print "\e[1;32mhttp://www.inspircd.org/wiki/Installation_From_Tarball\e[0m\n";
964 }
965 print "*** \e[1;32mRemember to edit your configuration files!!!\e[0m ***\n\n\n";
966 if (($config{OSNAME} eq "OpenBSD") && ($config{CC} ne "eg++")) {
967         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";
968 }
969
970 if ($config{GCCVER} < "3") {
971         print <<FOO2;
972 \e[1;32mWARNING!\e[0m You are attempting to compile InspIRCd on GCC 2.x!
973 GCC 2.x series compilers only had partial (read as broken) C++ support, and
974 your compile will most likely fail horribly! If you have any problems, do NOT
975 report them to the bugtracker or forums without first upgrading your compiler
976 to a newer 3.x or 4.x (or whatever is available currently) version.
977 FOO2
978 }
979
980 ################################################################################
981 #                             HELPER FUNCTIONS                          #
982 ################################################################################
983 sub getcache {
984         # Retrieves the .config.cache file, and loads values into the main config hash.
985         open(CACHE, ".config.cache") or return 0;
986         while (<CACHE>) {
987                 chomp;
988                 # Ignore Blank lines, and comments..
989                 next if /^\s*$/;
990                 next if /^\s*#/;
991                 my ($key, $value) = split("=", $_, 2);
992                 $value =~ /^\"(.*)\"$/;
993                 # Do something with data here!
994                 $config{$key} = $1;
995         }
996         close(CACHE);
997         return 1;
998 }
999
1000 sub makecache {
1001         # Dump the contents of %config
1002         print "Writing \e[1;32mcache file\e[0m for future ./configures ...\n";
1003         open(FILEHANDLE, ">.config.cache");
1004         foreach my $key (keys %config) {
1005                 print FILEHANDLE "$key=\"$config{$key}\"\n";
1006         }
1007         close(FILEHANDLE);
1008 }
1009
1010 sub dir_check {
1011         my ($desc, $hash_key) = @_;
1012         my $complete = 0;
1013         while (!$complete) {
1014                 print "In what directory $desc?\n";
1015                 print "[\e[1;32m$config{$hash_key}\e[0m] -> ";
1016                 chomp(my $var = <STDIN>);
1017                 if ($var eq "") {
1018                         $var = $config{$hash_key};
1019                 }
1020                 if ($var =~ /^\~\/(.+)$/) {
1021                         # Convert it to a full path..
1022                         $var = resolve_directory($ENV{HOME} . "/" . $1);
1023                 }
1024                 elsif ((($config{OSNAME} =~ /MINGW32/i) and ($var !~ /^[A-Z]{1}:\\.*/)) and (substr($var,0,1) ne "/"))
1025                 {
1026                         # Assume relative Path was given.. fill in the rest.
1027                         $var = $this . "/$var";
1028                 }
1029                 
1030                 $var = resolve_directory($var); 
1031                 if (! -e $var) {
1032                         print "$var does not exist. Create it?\n[\e[1;32my\e[0m] ";
1033                         chomp(my $tmp = <STDIN>);
1034                         if (($tmp eq "") || ($tmp =~ /^y/i)) {
1035                                 # Attempt to Create the Dir..
1036                                 my $chk = eval {
1037                                         use File::Path ();
1038                                         File::Path::mkpath($var, 0, 0777);
1039                                         1;
1040                                 };
1041                                 unless (defined($chk) && -d $var) {
1042                                         print "Unable to create directory. ($var)\n\n";
1043                                         # Restart Loop..
1044                                         next;
1045                                 }
1046                         } else {
1047                                 # They said they don't want to create, and we can't install there.
1048                                 print "\n\n";
1049                                 next;
1050                         }
1051                 } else {
1052                         if (!is_dir($var)) {
1053                                 # Target exists, but is not a directory.
1054                                 print "File $var exists, but is not a directory.\n\n";
1055                                 next;
1056                         }
1057                 }
1058                 # Either Dir Exists, or was created fine.
1059                 $config{$hash_key} = $var;
1060                 $complete = 1;
1061                 print "\n";
1062         }
1063 }
1064
1065 our $SHARED = "";
1066
1067 sub getosflags {
1068
1069         # Beware: Linux sets it's own cflags below for some retarded reason
1070         $config{LDLIBS} = "-pthread -lstdc++";
1071         $config{FLAGS}  = "-fPIC -Woverloaded-virtual -Wshadow -Wformat=2 -Wmissing-format-attribute -Wall $config{OPTIMISATI}";
1072         $config{DEVELOPER} = "-fPIC -Woverloaded-virtual -Wshadow -Wall -Wformat=2 -Wmissing-format-attribute -g";
1073         $SHARED = "-shared";
1074         $config{MAKEPROG} = "make";
1075
1076         if ($config{OSNAME} =~ /darwin/i) {
1077                 $config{FLAGS}  = "-DDARWIN -frtti -fPIC -Wall $config{OPTIMISATI}";
1078                 $SHARED = "-bundle -twolevel_namespace -undefined dynamic_lookup";
1079                 $config{LDLIBS} = "-ldl -pthread -lstdc++";
1080         }
1081
1082         if ($config{OSNAME} =~ /OpenBSD/i) {
1083                 $config{MAKEPROG} = "gmake";
1084                 $config{LDLIBS} = $config{LDLIBS} . " -lunwind";
1085                 chomp(my $foo = `eg++ -dumpversion | cut -c 1`);
1086                 # theyre running the package version of gcc (eg++)... detect it and set up its version numbers.
1087                 # if theyre not running this, configure lets the build continue but they probably wont manage to
1088                 # compile as this standard version is 2.95.3!
1089                 if ($foo ne "") {
1090                         $config{CC} = "eg++";
1091                         chomp($config{GCCVER}       = `eg++ -dumpversion | cut -c 1`); # we must redo these if we change the compiler path
1092                         chomp($config{GCCMINOR}     = `eg++ -dumpversion | cut -c 3`);
1093                 }
1094                 return "OpenBSD";
1095         }
1096
1097         if ($config{OSNAME} =~ /Linux/i) {
1098                 $config{LDLIBS} = "-ldl -lstdc++ -pthread";
1099 #               $config{FLAGS}  = "-fPIC -Woverloaded-virtual -Wshadow -Wall $config{OPTIMISATI}";
1100                 $config{FLAGS}  .= " " . $ENV{CXXFLAGS} if exists($ENV{CXXFLAGS});
1101                 $config{LDLIBS} .= " " . $ENV{LDLIBS} if exists($ENV{LDLIBS});
1102                 $config{MAKEPROG} = "make";
1103         }
1104
1105         if ($config{OSNAME} =~ /FreeBSD/i) {
1106                 $config{FLAGS}  .= " " . $ENV{CXXFLAGS} if exists($ENV{CXXFLAGS});
1107                 $config{LDLIBS} .= " " . $ENV{LDLIBS} if exists($ENV{LDLIBS});
1108         }
1109
1110         if ($config{OSNAME} =~ /SunOS/i or $config{OSNAME} =~ /solaris/i)
1111         {
1112                 # solaris/sunos needs these
1113                 # socket = bsd sockets api
1114                 # nsl = dns stuff
1115                 # rt = POSIX realtime extensions
1116                 # resolv = inet_aton only (why isnt this in nsl?!)
1117                 $config{MAKEPROG} = "gmake";
1118                 $config{LDLIBS} .= " -lsocket -lnsl -lrt -lresolv -pthread";
1119                 return "Solaris";
1120         }
1121         
1122         if($config{OSNAME} =~ /MINGW32/i)
1123         {
1124                 # All code is position-independent on windows
1125                 $config{FLAGS} =~ s/-fPIC //;
1126                 return "MinGW";
1127         }
1128
1129         return $config{OSNAME};
1130 }
1131
1132 my ($mliflags, $mfrules, $mobjs, $mfcount) = ("", "", "", 0);
1133
1134 sub writefiles {
1135         my($writeheader) = @_;
1136         my $se = "";
1137         # First File.. inspircd_config.h
1138         chomp(my $incos = `uname -n -s -r`);
1139         chomp(my $version = `sh src/version.sh`);
1140         chomp(my $revision2 = getrevision());
1141         if ($writeheader == 1)
1142         {
1143                 print "Writing \e[1;32minspircd_config.h\e[0m\n";
1144                 open(FILEHANDLE, ">include/inspircd_config.h");
1145                 print FILEHANDLE <<EOF;
1146 /* Auto generated by configure, do not modify! */
1147 #ifndef __CONFIGURATION_AUTO__
1148 #define __CONFIGURATION_AUTO__
1149
1150 /* this is for windows support. */
1151 #define CoreExport /**/
1152 #define DllExport /**/
1153
1154 #define CONFIG_FILE "$config{CONFIG_DIR}/inspircd.conf"
1155 #define MOD_PATH "$config{MODULE_DIR}"
1156 #define VERSION "$version"
1157 #define REVISION "$revision2"
1158 #define SOMAXCONN_S "$config{_SOMAXCONN}"
1159 #define OPTIMISATION $config{OPTIMITEMP}
1160 #define LIBRARYDIR "$config{LIBRARY_DIR}"
1161 #define SYSTEM "$incos"
1162
1163 EOF
1164 print FILEHANDLE "#define MAXBUF " . ($config{MAXBUF}+2) . "\n";
1165
1166                 if ($config{OSNAME} =~ /SunOS/i) {
1167                         print FILEHANDLE "#define IS_SOLARIS\n";
1168                 }
1169                 if ($config{OSNAME} =~ /MINGW32/i) {
1170                         print FILEHANDLE "#define IS_MINGW\n";
1171                 }
1172                 if ($config{GCCVER} >= 3) {
1173                         print FILEHANDLE "#define GCC3\n";
1174                 }
1175                 if (
1176                         (($config{GCCVER} == 4) && ($config{GCCMINOR} >= 3))
1177                                 ||
1178                         ($config{GCCVER} > 4)
1179                 ) {
1180                         print FILEHANDLE "#define HASHMAP_DEPRECATED\n";
1181                 }
1182                 if ($config{HAS_STRLCPY} eq "true") {
1183                         print FILEHANDLE "#define HAS_STRLCPY\n";
1184                 }
1185                 if ($config{HAS_STDINT} eq "true") {
1186                         print FILEHANDLE "#define HAS_STDINT\n";
1187                 }
1188                 if ($config{IPV6} =~ /y/i) {
1189                         print FILEHANDLE "#define IPV6\n";
1190                 }
1191                 if ($config{SUPPORT_IP6LINKS} =~ /y/i) {
1192                         print FILEHANDLE "#define SUPPORT_IP6LINKS\n";
1193                 }
1194                 my $use_hiperf = 0;
1195                 if (($has_kqueue) && ($config{USE_KQUEUE} eq "y")) {
1196                         print FILEHANDLE "#define USE_KQUEUE\n";
1197                         $se = "socketengine_kqueue";
1198                         $use_hiperf = 1;
1199                 }
1200                 if (($has_epoll) && ($config{USE_EPOLL} eq "y")) {
1201                         print FILEHANDLE "#define USE_EPOLL\n";
1202                         $se = "socketengine_epoll";
1203                         $use_hiperf = 1;
1204                 }
1205                 if (($has_ports) && ($config{USE_PORTS} eq "y")) {
1206                         print FILEHANDLE "#define USE_PORTS\n";
1207                         $se = "socketengine_ports";
1208                         $use_hiperf = 1;
1209                 }
1210                 # user didn't choose either epoll or select for their OS.
1211                 # default them to USE_SELECT (ewwy puke puke)
1212                 if (!$use_hiperf) {
1213                         print FILEHANDLE "#define USE_SELECT\n";
1214                         $se = "socketengine_select";
1215                 }
1216                 print FILEHANDLE "\n#include \"threadengines/threadengine_pthread.h\"\n\n#endif\n";
1217                 close(FILEHANDLE);
1218         }
1219
1220         if ($writeheader)
1221         {
1222                 open(FILEHANDLE, ">include/inspircd_se_config.h");
1223                 print FILEHANDLE <<EOF;
1224 /* Auto generated by configure, do not modify or commit to svn! */
1225 #ifndef __CONFIGURATION_SOCKETENGINE__
1226 #define __CONFIGURATION_SOCKETENGINE__
1227
1228 #include "socketengines/$se.h"
1229
1230 #endif
1231 EOF
1232                 close(FILEHANDLE);
1233         }
1234
1235
1236         # Create a Modules List..
1237         my $modules = "";
1238         foreach my $i (@modlist)
1239         {
1240                 $modules .= "m_".$i.".so ";
1241         }
1242         chomp($modules);   # Remove Redundant whitespace..
1243
1244         opendir(DIRHANDLE, "src/modules");
1245         foreach my $name2 (sort readdir(DIRHANDLE)) {
1246                 if ($name2 =~ /^m_(.+?)$/) {
1247                         if (defined(opendir(MDIRHANDLE, "src/modules/$name2"))) {
1248                                 closedir(MDIRHANDLE);
1249                                 $modules .= "$name2.so ";
1250                                 $uninstall_list = $uninstall_list . "   -rm \$(MODULES)/$name2.so\n";
1251                         }
1252                 }
1253         }
1254         closedir(DIRHANDLE);
1255
1256
1257         # Write all .in files.
1258         my $tmp = "";
1259         my $file = "";
1260         my $exe = "inspircd";
1261
1262         # Do this once here, and cache it in the .*.inc files,
1263         # rather than attempting to read src/version.sh from
1264         # compiled code -- we might not have the source to hand.
1265         # Fix for bug#177 by Brain.
1266
1267         chomp($version = `sh ./src/version.sh`);
1268         chomp(my $revision = getrevision());
1269         $version = "$version(r$revision)";
1270
1271         # We can actually parse any file starting with . and ending with .inc,
1272         # but right now we only parse .inspircd.inc to form './inspircd'
1273
1274         print "Writing \e[1;32mMakefiles\e[0m\n";
1275         write_dynamic_modules_makefile();
1276         write_dynamic_makefile();
1277
1278         opendir(DIRHANDLE, $this);
1279
1280         foreach my $name (sort readdir(DIRHANDLE)) {
1281                 if ($name =~ /^\.(.+)\.inc$/) {
1282                         $file = $1;
1283
1284                         # Bug #353, omit this on non-darwin
1285                         next if (($config{OSNAME} !~ /darwin/) && ($file eq "org.inspircd.plist"));
1286
1287                         # All .name.inc files need parsing!
1288                         $tmp = "";
1289                         open(FILEHANDLE, ".$file.inc") or die ("Can't open .$file.inc");
1290                         while (<FILEHANDLE>) {
1291                                 $tmp .= $_;
1292                         }
1293                         close(FILEHANDLE);
1294
1295                         print "Writing \e[1;32m$file\e[0m ...\n";
1296                         $tmp =~ s/\@CC\@/$config{CC}/ if defined $config{CC};
1297                         $tmp =~ s/\@MAKEPROG\@/$config{MAKEPROG}/ if defined $config{MAKEPROG};
1298                         $tmp =~ s/\@FLAGS\@/$config{FLAGS}/ if defined $config{FLAGS};
1299                         $tmp =~ s/\@DEVELOPER\@/$config{DEVELOPER}/ if defined $config{DEVELOPER};
1300                         $tmp =~ s/\@LDLIBS\@/$config{LDLIBS}/ if defined $config{LDLIBS};
1301                         $tmp =~ s/\@BASE_DIR\@/$config{BASE_DIR}/ if defined $config{BASE_DIR};
1302                         $tmp =~ s/\@CONFIG_DIR\@/$config{CONFIG_DIR}/ if defined $config{CONFIG_DIR};
1303                         $tmp =~ s/\@MODULE_DIR\@/$config{MODULE_DIR}/ if defined $config{MODULE_DIR};
1304                         $tmp =~ s/\@BINARY_DIR\@/$config{BINARY_DIR}/ if defined $config{BINARY_DIR};
1305                         $tmp =~ s/\@LIBRARY_DIR\@/$config{LIBRARY_DIR}/ if defined $config{LIBRARY_DIR};
1306                         $tmp =~ s/\@MODULES\@/$modules/ if defined $modules;
1307                         $tmp =~ s/\@STARTSCRIPT\@/$config{STARTSCRIPT}/ if defined $config{STARTSCRIPT};
1308                         $tmp =~ s/\@DESTINATION\@/$config{DESTINATION}/ if defined $config{DESTINATION};
1309                         $tmp =~ s/\@EXTRA_DIR\@/$config{EXTRA_DIR}/ if defined $config{EXTRA_DIR};
1310                         $tmp =~ s/\@EXECUTABLE\@/$exe/ if defined $exe;
1311                         $tmp =~ s/\@MAKEORDER\@/$config{MAKEORDER}/ if defined $config{MAKEORDER};
1312                         $tmp =~ s/\@VERSION\@/$version/ if defined $version;
1313                         $tmp =~ s/\@INSTALL_LIST\@/$install_list/ if defined $install_list;
1314                         $tmp =~ s/\@UNINSTALL_LIST\@/$uninstall_list/ if defined $uninstall_list;
1315
1316                         open(FILEHANDLE, ">$file");
1317                         print FILEHANDLE $tmp;
1318                 }
1319         }
1320         closedir(DIRHANDLE);
1321
1322         # Make inspircd executable!
1323         chmod 0744, 'inspircd';
1324 }
1325
1326 sub write_dynamic_modules_makefile {
1327         # Modules Makefile..
1328         print "Writing \e[1;32msrc/modules/Makefile\e[0m\n";
1329         open(FILEHANDLE, ">src/modules/Makefile");
1330
1331 ###
1332 # Module Makefile Header
1333 ###
1334         print FILEHANDLE <<EOF;
1335 ###################################################
1336 # Copyright 2002-2007 The InspIRCd Development Team
1337 #  http://www.inspircd.org/wiki/index.php/Credits
1338 #
1339 # Thanks to Andrew Church <achurch\@achurch.org>
1340 #   for assisting with making this work right.
1341 #
1342 # Automatically Generated by ./configure to add a
1343 #  modules please run ./configure -modupdate
1344 ###################################################
1345
1346 all: \$(MODULES)
1347
1348 EOF
1349
1350 if ($config{OSNAME} =~ /darwin/) {
1351                 print FILEHANDLE <<EOCHEESE;
1352
1353 PICLDFLAGS = -twolevel_namespace -undefined dynamic_lookup -bundle
1354
1355 EOCHEESE
1356 } else {
1357                 print FILEHANDLE <<EOCHEESE;
1358
1359 PICLDFLAGS = -fPIC -DPIC -shared
1360
1361 EOCHEESE
1362 }
1363
1364         ###
1365         # End Module Makefile Header
1366         ###
1367
1368         # Create a Modules List..
1369         my $modules = "";
1370         my $cmflags = "";
1371         my $liflags = "";
1372         foreach my $i (@modlist) {
1373                 ###
1374                 # Write Entry to the MakeFile
1375                 ###
1376                 $cmflags = getcompilerflags("src/modules/m_".$i.".cpp");
1377                 $liflags = getlinkerflags("src/modules/m_".$i.".cpp");
1378                 my $deps = getdependencies("src/modules/m_".$i.".cpp");
1379         
1380                 #print "file: $i: cmflags=$cmflags; liflags=$liflags; deps=$deps\n";
1381         
1382
1383                 if (nopedantic("src/modules/m_".$i.".cpp"))
1384                 {
1385                         print FILEHANDLE "
1386 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
1387         \@../../make/run-cc.pl \$(CC) -pipe -I../../include \$(NICEFLAGS) $cmflags \$(PICLDFLAGS) $liflags -export-dynamic -o m_$i.so m_$i.cpp
1388 "
1389                 }
1390                 else
1391                 {
1392                         print FILEHANDLE "
1393 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
1394         \@../../make/run-cc.pl \$(CC) -pipe -I../../include \$(FLAGS) $cmflags \$(PICLDFLAGS) $liflags -export-dynamic -o m_$i.so m_$i.cpp
1395 ";
1396                 }
1397                 $install_list = $install_list . "       install -m \$(INSTMODE) src/modules/m_$i.so \$(MODPATH)\n";
1398                 $uninstall_list = $uninstall_list . "   -rm \$(MODULES)/m_$i.so\n";
1399 ###
1400                 # End Write Entry to the MakeFile
1401                 ###
1402         }
1403
1404         opendir(DIRHANDLE, "src/modules");
1405         foreach my $name (sort readdir(DIRHANDLE)) {
1406                 if ($name =~ /^m_(.+?)$/) {
1407                         $mfrules = "";
1408                         $mobjs = "";
1409                         $mliflags = "";
1410                         $mfcount = 0;
1411                         # A module made of multiple files, in a dir, e.g. src/modules/m_spanningtree/
1412                         if (defined(opendir(MDIRHANDLE, "src/modules/$name"))) {
1413                                 read_module_directory("src/modules/$name", $name);
1414                                 print "Composing Makefile rules for directory \e[1;32m$name\e[0m... (\e[1;32m$mfcount files found\e[0m)\n";
1415                                 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"; 
1416                                 if ($config{IS_DARWIN} eq "YES") {
1417                                         print FILEHANDLE "      \@../../make/run-cc.pl \$(CC) -pipe -twolevel_namespace -undefined dynamic_lookup \$(FLAGS) $mliflags -bundle -o $name.so $mobjs\n"; 
1418                                 } else {
1419                                         print FILEHANDLE "      \@../../make/run-cc.pl \$(CC) -pipe \$(FLAGS) -shared $mliflags -o $name.so $mobjs\n";
1420                                 }
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 -export-dynamic -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) -export-dynamic -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 -export-dynamic
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) -export-dynamic -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 details.
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) -export-dynamic $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 }