]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - configure
work in progress
[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         if (defined($gnutls_ver) && ($gnutls_ver ne "")) {
671                 print "yes\n";
672                 $config{HAS_GNUTLS} = "y";
673         } else {
674                 print "no\n";
675                 $config{HAS_GNUTLS} = "n";
676         }
677 } else {
678         print "no\n";
679         $config{HAS_GNUTLS} = "n";
680 }
681
682 printf "Checking for openssl... ";
683 if (defined($config{HAS_OPENSSL}) && (($config{HAS_OPENSSL}) || ($config{HAS_OPENSSL} eq "y"))) {
684         if (defined($openssl_ver) && ($openssl_ver ne "")) {
685                 print "yes\n";
686                 $config{HAS_OPENSSL} = "y";
687         } else {
688                 print "no\n";
689                 $config{HAS_OPENSSL} = "n";
690         }
691 } else {
692         print "no\n";
693         $config{HAS_OPENSSL} = "n";
694 }
695
696 printf "Checking if you are running an ancient, unsupported OS... ";
697 if ($config{OSNAME} =~ /FreeBSD/i)
698 {
699         my $version = `uname -r`;
700         if ($version =~ /^4\./)
701         {
702                 my $foundit = `ls -l /usr/local/lib/libgnugetopt* | wc -l`;
703                 if ($foundit > 0)
704                 {
705                         # ICKY ICKY ICK, FREEBSD 4.x! GET AN UPGRADE!
706                         $config{CRAQ} = "-L/usr/local/lib -lgnugetopt -DHAVE_DECL_GETOPT=1";
707                         print "yes\n";
708                 }
709                 else
710                 {
711                         print "\n\nERROR: You require libgnugetopt (from ports or packages) to build InspIRCd on FreeBSD 4.11.\n";
712                 }
713         }
714         else
715         {
716                 $config{CRAQ} = " ";
717                 print "no ($version)\n";
718         }
719 }
720 else
721 {
722         $config{CRAQ} = " ";
723         print "no ($config{OSNAME})\n";
724 }
725
726 ################################################################################
727 #                         BEGIN INTERACTIVE PART                              #
728 ################################################################################
729
730 # Clear the Screen..
731 if ($interactive)
732 {
733         print "\e[2J\e[0G\e[0d"; # J = Erase in Display, 2 = Entire Screen, (G, d) = Move cursor to (..,..)
734         my $wholeos = $^O;
735
736         my $rev = getrevision();
737         # Display Introduction Message..
738         print <<"STOP" ;
739 Welcome to the \e[1mInspIRCd\e[0m Configuration program! (\e[1minteractive mode\e[0m)
740 \e[1mPackage maintainers: Type ./configure --help for non-interactive help\e[0m
741
742 *** If you are unsure of any of these values, leave it blank for    ***
743 *** standard settings that will work, and your server will run      ***
744 *** using them. Please consult your IRC network admin if in doubt.  ***
745
746 Press \e[1m<RETURN>\e[0m to accept the default for any option, or enter
747 a new value. Please note: You will \e[1mHAVE\e[0m to read the docs
748 dir, otherwise you won't have a config file!
749
750 Your operating system is: \e[1;32m$config{OSNAME}\e[0m ($wholeos)
751 Your InspIRCd revision ID is \e[1;32mr$rev\e[0m
752 STOP
753         if ($rev eq "r0") {
754                 print " (Non-SVN build)";
755         }
756         print ".\n\n";
757
758         $config{CHANGE_COMPILER} = "n";
759         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";
760
761         while (($config{GCCVER} < 3) || ($config{GCCVER} eq "")) {
762                 print "\e[1;32mIMPORTANT!\e[0m A GCC 2.x compiler has been detected, and
763 should NOT be used. You should probably specify a newer compiler.\n\n";
764                 yesno('CHANGE_COMPILER',"Do you want to change the compiler?");
765                 if ($config{CHANGE_COMPILER} =~ /y/i) {
766                         print "What command do you want to use to invoke your compiler?\n";
767                         print "[\e[1;32m$config{CC}\e[0m] -> ";
768                         chomp($config{CC} = <STDIN>);
769                         if ($config{CC} eq "") {
770                                 $config{CC} = "g++";
771                         }
772                         chomp(my $foo = `$config{CC} -dumpversion | cut -c 1`);
773                         if ($foo ne "") {
774                                 chomp($config{GCCVER}       = `$config{CC} -dumpversion | cut -c 1`); # we must redo these if we change compilers
775                                 chomp($config{GCCMINOR}     = `$config{CC} -dumpversion | cut -c 3`);
776                                 print "Queried compiler: \e[1;32m$config{CC}\e[0m (version \e[1;32m$config{GCCVER}.$config{GCCMINOR}\e[0m)\n";
777                                 if ($config{GCCVER} < 3) {
778                                         print "\e[1;32mGCC 2.x WILL NOT WORK!\e[0m. Let's try that again, shall we?\n";
779                                 }
780                         }
781                         else {
782                                 print "\e[1;32mWARNING!\e[0m Could not execute the compiler you specified. You may want to try again.\n";
783                         }
784                 }
785         }
786
787         print "\n";
788
789         # Directory Settings..
790         my $tmpbase = $config{BASE_DIR};
791         dir_check("do you wish to install the InspIRCd base", "BASE_DIR");
792         if ($tmpbase ne $config{BASE_DIR}) {
793                 $config{CONFIG_DIR}      = resolve_directory($config{BASE_DIR}."/conf");           # Configuration Dir
794                 $config{MODULE_DIR}      = resolve_directory($config{BASE_DIR}."/modules");     # Modules Directory
795                 $config{BINARY_DIR}      = resolve_directory($config{BASE_DIR}."/bin");     # Binary Directory
796                 $config{LIBRARY_DIR}    = resolve_directory($config{BASE_DIR}."/lib");      # Library Directory
797         }
798
799         dir_check("are the configuration files", "CONFIG_DIR");
800         dir_check("are the modules to be compiled to", "MODULE_DIR");
801         dir_check("is the IRCd binary to be placed", "BINARY_DIR");
802         dir_check("are the IRCd libraries to be placed", "LIBRARY_DIR");
803
804         if ($has_kqueue) {
805                 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?");
806                 print "\n";
807         }
808         if ($has_epoll) {
809                 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?");
810                 print "\n";
811         }
812         if ($has_ports) {
813                 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?");
814                 print "\n";
815         }
816         my $chose_hiperf = (($config{USE_EPOLL} eq "y") || ($config{USE_KQUEUE} eq "y") || ($config{USE_PORTS} eq "y"));
817         if (!$chose_hiperf) {
818                 print "No high-performance socket engines are available, or you chose\n";
819                 print "not to enable one. Defaulting to select() engine.\n\n";
820         }
821
822         yesno('IPV6',"Would you like to build InspIRCd with IPv6 support?");
823         print "\n";
824
825         if ($config{IPV6} eq "y") {
826                 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";
827                 $config{SUPPORT_IP6LINKS} = "y";
828         } else {
829                 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?");
830                 print "\n";
831         }
832
833         $config{USE_FREEBSD_BASE_SSL} = "n";
834         $config{USE_FREEBSD_PORTS_SSL} = "n";
835         if ($config{HAS_OPENSSL_PORT} ne "")
836         {
837                 $config{USE_FREEBSD_PORTS_SSL} = "y";
838                 print "I have detected the OpenSSL FreeBSD port installed on your system,\n";
839                 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";
840                 yesno('USE_FREEBSD_PORTS_SSL', "Do you want to use the FreeBSD ports version?");
841                 print "\n";
842                 $config{USE_FREEBSD_BASE_SSL} = "y" if ($config{USE_FREEBSD_PORTS_SSL} eq "n");
843
844                 if ($config{USE_FREEBSD_BASE_SSL} eq "n")
845                 {
846                         # update to port version
847                         $openssl_ver = $config{HAS_OPENSSL_PORT};
848                 }
849         }
850         else
851         {
852                 $config{USE_FREEBSD_BASE_SSL} = "y" if ($^O eq "freebsd");
853         }
854
855         if (($config{HAS_GNUTLS} eq "y") && ($config{HAS_OPENSSL} eq "y")) {
856                 print "I have detected both \e[1;32mGnuTLS\e[0m and \e[1;32mOpenSSL\e[0m on your system.\n";
857                 print "I will default to GnuTLS. If you wish to use OpenSSL\n";
858                 print "instead, you should enable the OpenSSL module yourself\n";
859                 print "by copying it from src/modules/extra to src/modules.\n\n";
860                 print "Detected GnuTLS version: \e[1;32m" . $gnutls_ver . "\e[0m\n";
861                 print "Detected OpenSSL version: \e[1;32m" . $openssl_ver . "\e[0m\n\n";
862         }
863
864         if ($config{HAS_GNUTLS} eq "y") {
865                 yesno('USE_GNUTLS', "Would you like to enable SSL Support?");
866                 if ($config{USE_GNUTLS} eq "y") {
867                         print "\nUsing GnuTLS SSL module.\n";
868                 }
869         } elsif ($config{HAS_OPENSSL} eq "y") {
870                         yesno('USE_OPENSSL', "Would you like to enable SSL Support?");
871         if ($config{USE_OPENSSL} eq "y") {
872                         print "\nUsing OpenSSL SSL module.\nYou will get better performance if you move to GnuTLS in the future.\n";
873                 }
874         }
875         else {
876                 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";
877         }
878 }
879
880 dumphash();
881
882 if (($config{USE_GNUTLS} eq "y") && ($config{HAS_GNUTLS} ne "y"))
883 {
884         print "Sorry, but i couldn't detect gnutls. Make sure gnutls-config is in your path.\n";
885         exit(0);
886 }
887 if (($config{USE_OPENSSL} eq "y") && ($config{HAS_OPENSSL} ne "y"))
888 {
889         print "Sorry, but i couldn't detect openssl. Make sure openssl is in your path.\n";
890         exit(0);
891 }
892 our $failed = 0;
893
894 if ($config{USE_GNUTLS} eq "y") {
895         unless (-r "src/modules/m_ssl_gnutls.cpp") {
896                 print "Symlinking src/modules/m_ssl_gnutls.cpp from extra/\n";
897                 symlink "extra/m_ssl_gnutls.cpp", "src/modules/m_ssl_gnutls.cpp" or print STDERR "Symlink failed: $!";
898         }
899         getmodules();
900         if ($interactive)
901         {
902                 unless (-r "$config{CONFIG_DIR}/key.pem" && -r "$config{CONFIG_DIR}/cert.pem") {
903                         print "SSL Certificates Not found, Generating.. \n\n
904 *************************************************************
905 * Generating the Private Key may take some time, go grab a  *
906 * Coffee. Even better, to generate some more entropy if it  *
907 * is taking a while, open another console and type du / a   *
908 * few times and get that HD going :) Then answer the        *
909 * Questions which follow. If you are unsure, just hit enter *
910 *************************************************************\n\n";
911                         $failed = make_gnutls_cert();
912                         if ($failed) {
913                                 print "\n\e[1;32mCertificate generation failed!\e[0m\n\n";
914                         } else {
915                                 print "\nCertificate generation complete, copying to config directory... ";
916                                 File::Copy::move("key.pem", "$config{CONFIG_DIR}/key.pem") or print STDERR "Could not copy key.pem!\n";
917                                 File::Copy::move("cert.pem", "$config{CONFIG_DIR}/cert.pem") or print STDERR "Could not copy cert.pem!\n";
918                                 print "Done.\n\n";
919                         }
920                 }
921                 else {
922                         print "SSL Certificates found, skipping.\n\n";
923                 }
924         }
925         else
926         {
927                 print "Skipping SSL certificate generation\nin non-interactive mode.\n\n";
928         }
929 } elsif ($config{USE_OPENSSL} eq "y") {
930         unless (-r "src/modules/m_ssl_openssl.cpp") {
931                 print "Symlinking src/modules/m_ssl_openssl.cpp from extra/\n";
932                 symlink "extra/m_ssl_openssl.cpp", "src/modules/m_ssl_openssl.cpp" or print STDERR "Symlink failed: $!";
933         }
934         getmodules();
935         $failed = 0;
936         if ($interactive)
937         {
938                 unless (-r "$config{CONFIG_DIR}/key.pem" && -r "$config{CONFIG_DIR}/cert.pem") {
939                         print "SSL Certificates Not found, Generating.. \n\n
940 *************************************************************
941 * Generating the certificates may take some time, go grab a *
942 * coffee, or something.                                     *
943 *************************************************************\n\n";
944                         make_openssl_cert();
945                         print "\nCertificate generation complete, copying to config directory... ";
946                         File::Copy::move("key.pem", "$config{CONFIG_DIR}/key.pem") or print STDERR "Could not copy key.pem!\n";
947                         File::Copy::move("cert.pem", "$config{CONFIG_DIR}/cert.pem") or print STDERR "Could not copy cert.pem!\n";
948                         File::Copy::move("dhparams.pem", "$config{CONFIG_DIR}/dhparams.pem") or print STDERR "Could not copy dhparams.pem!\n";
949                         print "Done.\n\n";
950                 } else {
951                         print "SSL Certificates found, skipping.\n\n"
952                 }
953         }
954         else
955         {
956                 print "Skipping SSL certificate generation\nin non-interactive mode.\n\n";
957         }
958 }
959 if (($config{USE_GNUTLS} eq "n") && ($config{USE_OPENSSL} eq "n")) {
960         print "Skipping SSL Certificate generation, SSL support is not available.\n\n";
961 }
962
963 getosflags();
964 writefiles(1);
965 makecache();
966
967 print "\n\n";
968 print "To build your server with these settings, please type '\e[1;32m$config{MAKEPROG}\e[0m' now.\n";
969 if (($config{USE_GNUTLS} eq "y") || ($config{USE_OPENSSL} eq "y")) {
970         print "Please note: for \e[1;32mSSL support\e[0m you will need to load required\n";
971         print "modules in your config. This configure script has added those modules to the\n";
972         print "build process. For more info please refer to:\n";
973         print "\e[1;32mhttp://www.inspircd.org/wiki/Installation_From_Tarball\e[0m\n";
974 }
975 print "*** \e[1;32mRemember to edit your configuration files!!!\e[0m ***\n\n\n";
976 if (($config{OSNAME} eq "OpenBSD") && ($config{CC} ne "eg++")) {
977         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";
978 }
979
980 if ($config{GCCVER} < "3") {
981         print <<FOO2;
982 \e[1;32mWARNING!\e[0m You are attempting to compile InspIRCd on GCC 2.x!
983 GCC 2.x series compilers only had partial (read as broken) C++ support, and
984 your compile will most likely fail horribly! If you have any problems, do NOT
985 report them to the bugtracker or forums without first upgrading your compiler
986 to a newer 3.x or 4.x (or whatever is available currently) version.
987 FOO2
988 }
989
990 ################################################################################
991 #                             HELPER FUNCTIONS                          #
992 ################################################################################
993 sub getcache {
994         # Retrieves the .config.cache file, and loads values into the main config hash.
995         open(CACHE, ".config.cache") or return 0;
996         while (<CACHE>) {
997                 chomp;
998                 # Ignore Blank lines, and comments..
999                 next if /^\s*$/;
1000                 next if /^\s*#/;
1001                 my ($key, $value) = split("=", $_, 2);
1002                 $value =~ /^\"(.*)\"$/;
1003                 # Do something with data here!
1004                 $config{$key} = $1;
1005         }
1006         close(CACHE);
1007         return 1;
1008 }
1009
1010 sub makecache {
1011         # Dump the contents of %config
1012         print "Writing \e[1;32mcache file\e[0m for future ./configures ...\n";
1013         open(FILEHANDLE, ">.config.cache");
1014         foreach my $key (keys %config) {
1015                 print FILEHANDLE "$key=\"$config{$key}\"\n";
1016         }
1017         close(FILEHANDLE);
1018 }
1019
1020 sub dir_check {
1021         my ($desc, $hash_key) = @_;
1022         my $complete = 0;
1023         while (!$complete) {
1024                 print "In what directory $desc?\n";
1025                 print "[\e[1;32m$config{$hash_key}\e[0m] -> ";
1026                 chomp(my $var = <STDIN>);
1027                 if ($var eq "") {
1028                         $var = $config{$hash_key};
1029                 }
1030                 if ($var =~ /^\~\/(.+)$/) {
1031                         # Convert it to a full path..
1032                         $var = resolve_directory($ENV{HOME} . "/" . $1);
1033                 }
1034                 elsif ((($config{OSNAME} =~ /MINGW32/i) and ($var !~ /^[A-Z]{1}:\\.*/)) and (substr($var,0,1) ne "/"))
1035                 {
1036                         # Assume relative Path was given.. fill in the rest.
1037                         $var = $this . "/$var";
1038                 }
1039                 
1040                 $var = resolve_directory($var); 
1041                 if (! -e $var) {
1042                         print "$var does not exist. Create it?\n[\e[1;32my\e[0m] ";
1043                         chomp(my $tmp = <STDIN>);
1044                         if (($tmp eq "") || ($tmp =~ /^y/i)) {
1045                                 # Attempt to Create the Dir..
1046                                 my $chk = eval {
1047                                         use File::Path ();
1048                                         File::Path::mkpath($var, 0, 0777);
1049                                         1;
1050                                 };
1051                                 unless (defined($chk) && -d $var) {
1052                                         print "Unable to create directory. ($var)\n\n";
1053                                         # Restart Loop..
1054                                         next;
1055                                 }
1056                         } else {
1057                                 # They said they don't want to create, and we can't install there.
1058                                 print "\n\n";
1059                                 next;
1060                         }
1061                 } else {
1062                         if (!is_dir($var)) {
1063                                 # Target exists, but is not a directory.
1064                                 print "File $var exists, but is not a directory.\n\n";
1065                                 next;
1066                         }
1067                 }
1068                 # Either Dir Exists, or was created fine.
1069                 $config{$hash_key} = $var;
1070                 $complete = 1;
1071                 print "\n";
1072         }
1073 }
1074
1075 our $SHARED = "";
1076
1077 sub getosflags {
1078
1079         # Beware: Linux sets it's own cflags below for some retarded reason
1080         $config{LDLIBS} = "-pthread -lstdc++";
1081         $config{FLAGS}  = "-fPIC -Woverloaded-virtual -Wshadow -Wformat=2 -Wmissing-format-attribute -Wall $config{OPTIMISATI}";
1082         $config{DEVELOPER} = "-fPIC -Woverloaded-virtual -Wshadow -Wall -Wformat=2 -Wmissing-format-attribute -g";
1083         $SHARED = "-shared";
1084         $config{MAKEPROG} = "make";
1085
1086         if ($config{OSNAME} =~ /darwin/i) {
1087                 $config{FLAGS}  = "-DDARWIN -frtti -fPIC -Wall $config{OPTIMISATI}";
1088                 $SHARED = "-bundle -twolevel_namespace -undefined dynamic_lookup";
1089                 $config{LDLIBS} = "-ldl -pthread -lstdc++";
1090         }
1091
1092         if ($config{OSNAME} =~ /OpenBSD/i) {
1093                 $config{MAKEPROG} = "gmake";
1094                 $config{LDLIBS} = $config{LDLIBS} . " -lunwind";
1095                 chomp(my $foo = `eg++ -dumpversion | cut -c 1`);
1096                 # theyre running the package version of gcc (eg++)... detect it and set up its version numbers.
1097                 # if theyre not running this, configure lets the build continue but they probably wont manage to
1098                 # compile as this standard version is 2.95.3!
1099                 if ($foo ne "") {
1100                         $config{CC} = "eg++";
1101                         chomp($config{GCCVER}       = `eg++ -dumpversion | cut -c 1`); # we must redo these if we change the compiler path
1102                         chomp($config{GCCMINOR}     = `eg++ -dumpversion | cut -c 3`);
1103                 }
1104                 return "OpenBSD";
1105         }
1106
1107         if ($config{OSNAME} =~ /Linux/i) {
1108                 $config{LDLIBS} = "-ldl -lstdc++ -pthread";
1109 #               $config{FLAGS}  = "-fPIC -Woverloaded-virtual -Wshadow -Wall $config{OPTIMISATI}";
1110                 $config{FLAGS}  .= " " . $ENV{CXXFLAGS} if exists($ENV{CXXFLAGS});
1111                 $config{LDLIBS} .= " " . $ENV{LDLIBS} if exists($ENV{LDLIBS});
1112                 $config{MAKEPROG} = "make";
1113         }
1114
1115         if ($config{OSNAME} =~ /FreeBSD/i) {
1116                 $config{FLAGS}  .= " " . $ENV{CXXFLAGS} if exists($ENV{CXXFLAGS});
1117                 $config{LDLIBS} .= " " . $ENV{LDLIBS} if exists($ENV{LDLIBS});
1118         }
1119
1120         if ($config{OSNAME} =~ /SunOS/i or $config{OSNAME} =~ /solaris/i)
1121         {
1122                 # solaris/sunos needs these
1123                 # socket = bsd sockets api
1124                 # nsl = dns stuff
1125                 # rt = POSIX realtime extensions
1126                 # resolv = inet_aton only (why isnt this in nsl?!)
1127                 $config{MAKEPROG} = "gmake";
1128                 $config{LDLIBS} .= " -lsocket -lnsl -lrt -lresolv -pthread";
1129                 return "Solaris";
1130         }
1131         
1132         if($config{OSNAME} =~ /MINGW32/i)
1133         {
1134                 # All code is position-independent on windows
1135                 $config{FLAGS} =~ s/-fPIC //;
1136                 return "MinGW";
1137         }
1138
1139         return $config{OSNAME};
1140 }
1141
1142 my ($mliflags, $mfrules, $mobjs, $mfcount) = ("", "", "", 0);
1143
1144 sub writefiles {
1145         my($writeheader) = @_;
1146         my $se = "";
1147         # First File.. inspircd_config.h
1148         chomp(my $incos = `uname -n -s -r`);
1149         chomp(my $version = `sh src/version.sh`);
1150         chomp(my $revision2 = getrevision());
1151         if ($writeheader == 1)
1152         {
1153                 print "Writing \e[1;32minspircd_config.h\e[0m\n";
1154                 open(FILEHANDLE, ">include/inspircd_config.h");
1155                 print FILEHANDLE <<EOF;
1156 /* Auto generated by configure, do not modify! */
1157 #ifndef __CONFIGURATION_AUTO__
1158 #define __CONFIGURATION_AUTO__
1159
1160 /* this is for windows support. */
1161 #define CoreExport /**/
1162 #define DllExport /**/
1163
1164 #define CONFIG_FILE "$config{CONFIG_DIR}/inspircd.conf"
1165 #define MOD_PATH "$config{MODULE_DIR}"
1166 #define VERSION "$version"
1167 #define REVISION "$revision2"
1168 #define SOMAXCONN_S "$config{_SOMAXCONN}"
1169 #define OPTIMISATION $config{OPTIMITEMP}
1170 #define LIBRARYDIR "$config{LIBRARY_DIR}"
1171 #define SYSTEM "$incos"
1172 #define ENTRYPOINT int main(int argc, char** argv)
1173
1174 EOF
1175 print FILEHANDLE "#define MAXBUF " . ($config{MAXBUF}+2) . "\n";
1176
1177                 if ($config{OSNAME} =~ /SunOS/i) {
1178                         print FILEHANDLE "#define IS_SOLARIS\n";
1179                 }
1180                 if ($config{OSNAME} =~ /MINGW32/i) {
1181                         print FILEHANDLE "#define IS_MINGW\n";
1182                 }
1183                 if ($config{GCCVER} >= 3) {
1184                         print FILEHANDLE "#define GCC3\n";
1185                 }
1186                 if (
1187                         (($config{GCCVER} == 4) && ($config{GCCMINOR} >= 3))
1188                                 ||
1189                         ($config{GCCVER} > 4)
1190                 ) {
1191                         print FILEHANDLE "#define HASHMAP_DEPRECATED\n";
1192                 }
1193                 if ($config{HAS_STRLCPY} eq "true") {
1194                         print FILEHANDLE "#define HAS_STRLCPY\n";
1195                 }
1196                 if ($config{HAS_STDINT} eq "true") {
1197                         print FILEHANDLE "#define HAS_STDINT\n";
1198                 }
1199                 if ($config{IPV6} =~ /y/i) {
1200                         print FILEHANDLE "#define IPV6\n";
1201                 }
1202                 if ($config{SUPPORT_IP6LINKS} =~ /y/i) {
1203                         print FILEHANDLE "#define SUPPORT_IP6LINKS\n";
1204                 }
1205                 my $use_hiperf = 0;
1206                 if (($has_kqueue) && ($config{USE_KQUEUE} eq "y")) {
1207                         print FILEHANDLE "#define USE_KQUEUE\n";
1208                         $se = "socketengine_kqueue";
1209                         $use_hiperf = 1;
1210                 }
1211                 if (($has_epoll) && ($config{USE_EPOLL} eq "y")) {
1212                         print FILEHANDLE "#define USE_EPOLL\n";
1213                         $se = "socketengine_epoll";
1214                         $use_hiperf = 1;
1215                 }
1216                 if (($has_ports) && ($config{USE_PORTS} eq "y")) {
1217                         print FILEHANDLE "#define USE_PORTS\n";
1218                         $se = "socketengine_ports";
1219                         $use_hiperf = 1;
1220                 }
1221                 # user didn't choose either epoll or select for their OS.
1222                 # default them to USE_SELECT (ewwy puke puke)
1223                 if (!$use_hiperf) {
1224                         print FILEHANDLE "#define USE_SELECT\n";
1225                         $se = "socketengine_select";
1226                 }
1227                 print FILEHANDLE "\n#include \"threadengines/threadengine_pthread.h\"\n\n#endif\n";
1228                 close(FILEHANDLE);
1229         }
1230
1231         if ($writeheader)
1232         {
1233                 open(FILEHANDLE, ">include/inspircd_se_config.h");
1234                 print FILEHANDLE <<EOF;
1235 /* Auto generated by configure, do not modify or commit to svn! */
1236 #ifndef __CONFIGURATION_SOCKETENGINE__
1237 #define __CONFIGURATION_SOCKETENGINE__
1238
1239 #include "socketengines/$se.h"
1240
1241 #endif
1242 EOF
1243                 close(FILEHANDLE);
1244         }
1245
1246
1247         # Create a Modules List..
1248         my $modules = "";
1249         foreach my $i (@modlist)
1250         {
1251                 $modules .= "m_".$i.".so ";
1252         }
1253         chomp($modules);   # Remove Redundant whitespace..
1254
1255         opendir(DIRHANDLE, "src/modules");
1256         foreach my $name2 (sort readdir(DIRHANDLE)) {
1257                 if ($name2 =~ /^m_(.+?)$/) {
1258                         if (defined(opendir(MDIRHANDLE, "src/modules/$name2"))) {
1259                                 closedir(MDIRHANDLE);
1260                                 $modules .= "$name2.so ";
1261                                 $uninstall_list = $uninstall_list . "   -rm \$(MODULES)/$name2.so\n";
1262                         }
1263                 }
1264         }
1265         closedir(DIRHANDLE);
1266
1267
1268         # Write all .in files.
1269         my $tmp = "";
1270         my $file = "";
1271         my $exe = "inspircd";
1272
1273         # Do this once here, and cache it in the .*.inc files,
1274         # rather than attempting to read src/version.sh from
1275         # compiled code -- we might not have the source to hand.
1276         # Fix for bug#177 by Brain.
1277
1278         chomp($version = `sh ./src/version.sh`);
1279         chomp(my $revision = getrevision());
1280         $version = "$version(r$revision)";
1281
1282         # We can actually parse any file starting with . and ending with .inc,
1283         # but right now we only parse .inspircd.inc to form './inspircd'
1284
1285         print "Writing \e[1;32mMakefiles\e[0m\n";
1286         write_dynamic_modules_makefile();
1287         write_dynamic_makefile();
1288
1289         opendir(DIRHANDLE, $this);
1290
1291         foreach my $name (sort readdir(DIRHANDLE)) {
1292                 if ($name =~ /^\.(.+)\.inc$/) {
1293                         $file = $1;
1294
1295                         # Bug #353, omit this on non-darwin
1296                         next if (($config{OSNAME} !~ /darwin/) && ($file eq "org.inspircd.plist"));
1297
1298                         # All .name.inc files need parsing!
1299                         $tmp = "";
1300                         open(FILEHANDLE, ".$file.inc") or die ("Can't open .$file.inc");
1301                         while (<FILEHANDLE>) {
1302                                 $tmp .= $_;
1303                         }
1304                         close(FILEHANDLE);
1305
1306                         print "Writing \e[1;32m$file\e[0m ...\n";
1307                         $tmp =~ s/\@CC\@/$config{CC}/ if defined $config{CC};
1308                         $tmp =~ s/\@MAKEPROG\@/$config{MAKEPROG}/ if defined $config{MAKEPROG};
1309                         $tmp =~ s/\@FLAGS\@/$config{FLAGS}/ if defined $config{FLAGS};
1310                         $tmp =~ s/\@DEVELOPER\@/$config{DEVELOPER}/ if defined $config{DEVELOPER};
1311                         $tmp =~ s/\@LDLIBS\@/$config{LDLIBS}/ if defined $config{LDLIBS};
1312                         $tmp =~ s/\@BASE_DIR\@/$config{BASE_DIR}/ if defined $config{BASE_DIR};
1313                         $tmp =~ s/\@CONFIG_DIR\@/$config{CONFIG_DIR}/ if defined $config{CONFIG_DIR};
1314                         $tmp =~ s/\@MODULE_DIR\@/$config{MODULE_DIR}/ if defined $config{MODULE_DIR};
1315                         $tmp =~ s/\@BINARY_DIR\@/$config{BINARY_DIR}/ if defined $config{BINARY_DIR};
1316                         $tmp =~ s/\@LIBRARY_DIR\@/$config{LIBRARY_DIR}/ if defined $config{LIBRARY_DIR};
1317                         $tmp =~ s/\@MODULES\@/$modules/ if defined $modules;
1318                         $tmp =~ s/\@STARTSCRIPT\@/$config{STARTSCRIPT}/ if defined $config{STARTSCRIPT};
1319                         $tmp =~ s/\@DESTINATION\@/$config{DESTINATION}/ if defined $config{DESTINATION};
1320                         $tmp =~ s/\@EXTRA_DIR\@/$config{EXTRA_DIR}/ if defined $config{EXTRA_DIR};
1321                         $tmp =~ s/\@EXECUTABLE\@/$exe/ if defined $exe;
1322                         $tmp =~ s/\@MAKEORDER\@/$config{MAKEORDER}/ if defined $config{MAKEORDER};
1323                         $tmp =~ s/\@VERSION\@/$version/ if defined $version;
1324                         $tmp =~ s/\@INSTALL_LIST\@/$install_list/ if defined $install_list;
1325                         $tmp =~ s/\@UNINSTALL_LIST\@/$uninstall_list/ if defined $uninstall_list;
1326
1327                         open(FILEHANDLE, ">$file");
1328                         print FILEHANDLE $tmp;
1329                 }
1330         }
1331         closedir(DIRHANDLE);
1332
1333         # Make inspircd executable!
1334         chmod 0744, 'inspircd';
1335 }
1336
1337 sub write_dynamic_modules_makefile {
1338         # Modules Makefile..
1339         print "Writing \e[1;32msrc/modules/Makefile\e[0m\n";
1340         open(FILEHANDLE, ">src/modules/Makefile");
1341
1342 ###
1343 # Module Makefile Header
1344 ###
1345         print FILEHANDLE <<EOF;
1346 ###################################################
1347 # Copyright 2002-2007 The InspIRCd Development Team
1348 #  http://www.inspircd.org/wiki/index.php/Credits
1349 #
1350 # Thanks to Andrew Church <achurch\@achurch.org>
1351 #   for assisting with making this work right.
1352 #
1353 # Automatically Generated by ./configure to add a
1354 #  modules please run ./configure -modupdate
1355 ###################################################
1356
1357 all: \$(MODULES)
1358
1359 EOF
1360
1361 if ($config{OSNAME} =~ /darwin/) {
1362                 print FILEHANDLE <<EOCHEESE;
1363
1364 PICLDFLAGS = -twolevel_namespace -undefined dynamic_lookup -bundle
1365
1366 EOCHEESE
1367 } else {
1368                 print FILEHANDLE <<EOCHEESE;
1369
1370 PICLDFLAGS = -fPIC -DPIC -shared
1371
1372 EOCHEESE
1373 }
1374
1375         ###
1376         # End Module Makefile Header
1377         ###
1378
1379         # Create a Modules List..
1380         my $modules = "";
1381         my $cmflags = "";
1382         my $liflags = "";
1383         foreach my $i (@modlist) {
1384                 ###
1385                 # Write Entry to the MakeFile
1386                 ###
1387                 $cmflags = getcompilerflags("src/modules/m_".$i.".cpp");
1388                 $liflags = getlinkerflags("src/modules/m_".$i.".cpp");
1389                 my $deps = getdependencies("src/modules/m_".$i.".cpp");
1390         
1391                 #print "file: $i: cmflags=$cmflags; liflags=$liflags; deps=$deps\n";
1392         
1393
1394                 if (nopedantic("src/modules/m_".$i.".cpp"))
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 \$(NICEFLAGS) $cmflags \$(PICLDFLAGS) $liflags -export-dynamic -o m_$i.so m_$i.cpp
1399 "
1400                 }
1401                 else
1402                 {
1403                         print FILEHANDLE "
1404 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
1405         \@../../make/run-cc.pl \$(CC) -pipe -I../../include \$(FLAGS) $cmflags \$(PICLDFLAGS) $liflags -export-dynamic -o m_$i.so m_$i.cpp
1406 ";
1407                 }
1408                 $install_list = $install_list . "       install -m \$(INSTMODE) src/modules/m_$i.so \$(MODPATH)\n";
1409                 $uninstall_list = $uninstall_list . "   -rm \$(MODULES)/m_$i.so\n";
1410 ###
1411                 # End Write Entry to the MakeFile
1412                 ###
1413         }
1414
1415         opendir(DIRHANDLE, "src/modules");
1416         foreach my $name (sort readdir(DIRHANDLE)) {
1417                 if ($name =~ /^m_(.+?)$/) {
1418                         $mfrules = "";
1419                         $mobjs = "";
1420                         $mliflags = "";
1421                         $mfcount = 0;
1422                         # A module made of multiple files, in a dir, e.g. src/modules/m_spanningtree/
1423                         if (defined(opendir(MDIRHANDLE, "src/modules/$name"))) {
1424                                 read_module_directory("src/modules/$name", $name);
1425                                 print "Composing Makefile rules for directory \e[1;32m$name\e[0m... (\e[1;32m$mfcount files found\e[0m)\n";
1426                                 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"; 
1427                                 if ($config{IS_DARWIN} eq "YES") {
1428                                         print FILEHANDLE "      \@../../make/run-cc.pl \$(CC) -pipe -twolevel_namespace -undefined dynamic_lookup \$(FLAGS) $mliflags -bundle -o $name.so $mobjs\n"; 
1429                                 } else {
1430                                         print FILEHANDLE "      \@../../make/run-cc.pl \$(CC) -pipe \$(FLAGS) -shared $mliflags -o $name.so $mobjs\n";
1431                                 }
1432                                 print FILEHANDLE "\n$mfrules\n";
1433                                 closedir(MDIRHANDLE);
1434                                 $install_list = $install_list . "       install -m \$(INSTMODE) src/modules/$name.so \$(MODPATH)\n";
1435                         }
1436                 }
1437         }
1438         closedir(DIRHANDLE);
1439 }
1440
1441 sub read_module_directory {
1442         my ($dpath, $reldpath) = @_;
1443         
1444         if (opendir(MDIRHANDLE, $dpath) == 0) {
1445                 return;
1446         }
1447         
1448         foreach my $fname (sort readdir(MDIRHANDLE)) {
1449                 if ($fname =~ /\.cpp$/) {
1450                         my $cmflags = getcompilerflags("$dpath/$fname");
1451                         $mliflags = $mliflags . " " . getlinkerflags("$dpath/$fname");
1452                         my $deps = getdependencies("$dpath/$fname");
1453                         my $oname = $fname;
1454                         $oname =~ s/\.cpp$/.o/g;
1455                         $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";
1456                         $mfrules = $mfrules .  "        \@../../make/run-cc.pl \$(CC) -pipe -I../../include -I. \$(FLAGS) $cmflags -export-dynamic -o $reldpath/$oname -c $reldpath/$fname\n\n";
1457                         $mobjs = $mobjs . " $reldpath/$oname";
1458                         $mfcount++;
1459                 }
1460                 elsif ((-d "$dpath/$fname") && !($fname eq ".") && !($fname eq "..")) {
1461                         read_module_directory($dpath."/".$fname, $reldpath."/".$fname);
1462                 }
1463         }
1464 }
1465
1466 sub calcdeps($)
1467 {
1468         # Yes i know we could use gcc -M but it seems to ideneify a lot of 'deep'
1469         # dependencies which are not relevent in C++.
1470
1471         my $file = $_[0];
1472
1473         open (CPP, "<$file") or die("Can't open $file for reading!");
1474
1475         my %dupe = ();
1476         my $retlist = "";
1477
1478         foreach my $d (@ignoredeps)
1479         {
1480                 $dupe{$d} = 1;
1481         }
1482
1483         my $immutable = "";
1484         foreach my $dep (@immutabledeps)
1485         {
1486                 $immutable = $immutable . "../include/$dep ";
1487         }
1488         $immutable =~ s/ $//g;
1489
1490         while (defined(my $line = <CPP>))
1491         {
1492                 chomp($line);
1493                 if ($line =~ /#include "(.+\.h)"/)
1494                 {
1495                         if (!exists($dupe{$1}))
1496                         {
1497                                 $retlist = $retlist . "../include/$1 ";
1498                                 $dupe{$1} = 1;
1499                         }
1500                 }
1501         }
1502         close CPP;
1503         return length($immutable) ? $immutable . " " . $retlist : $retlist;
1504 }
1505
1506 sub write_dynamic_makefile
1507 {
1508         my $i = 0;
1509         my @cmdlist = ();
1510         my %existing_install_list = ();
1511         my %core_files_list = ();
1512
1513         opendir(DIRHANDLE, "src/commands");
1514         foreach my $name (sort readdir(DIRHANDLE))
1515         {
1516                 if ($name =~ /^cmd_(.+)\.cpp$/)
1517                 {
1518                         $cmdlist[$i++] = $1;
1519                         $install_list = $install_list . "       -install -m \$(INSTMODE) src/commands/cmd_" . $1 . ".so \$(LIBPATH)\n";
1520                         $uninstall_list = $uninstall_list . "   -rm \$(LIBPATH)/cmd_$1.so\n";
1521                 }
1522         }
1523         closedir(DIRHANDLE);
1524
1525         if (!$has_epoll)
1526         {
1527                 $config{USE_EPOLL} = 0;
1528         }
1529         if (!$has_kqueue)
1530         {
1531                 $config{USE_KQUEUE} = 0;
1532         }
1533         if (!$has_ports)
1534         {
1535                 $config{USE_PORTS} = 0;
1536         }
1537
1538         # formerly generated below this foreach, now it's not! magic.
1539         my $all_core = "";
1540
1541         foreach my $dir (("src","src/commands","src/modes","src/socketengines","src/modules"))
1542         {
1543                 print "Scanning \e[1;32m$dir\e[0m for core files ";
1544                 opendir(DIRHANDLE, $dir);
1545                 foreach my $name (sort readdir(DIRHANDLE))
1546                 {
1547                         if ($name =~ /\.cpp$/)
1548                         {
1549                                 open (CPP, "<$dir/$name") or die("Can't open $dir/$name to scan it! oh bugger");
1550                                 print ".";
1551                                 while (defined(my $line = <CPP>))
1552                                 {
1553                                         chomp($line);
1554                                         if ($line =~ /\/\* \$Core \*\//i)
1555                                         {
1556                                                 my $sname = $name;
1557                                                 $sname =~ s/\.cpp$/.o/;
1558
1559                                                 # append it to list to be built
1560                                                 $all_core = $all_core . $sname . " ";
1561                                                 $filelist{$name} = $sname;
1562
1563                                                 # mark it as a core file, so it won't get shared object cflags
1564                                                 if (!exists($core_files_list{$name}))
1565                                                 {
1566                                                         $core_files_list{$name} = 1;
1567                                                 }
1568                                         }
1569                                         elsif ($line =~ /\/\* \$ExtraDeps: (.*?) \*\//i)
1570                                         {
1571                                                 $specialdeps{$name} = $1;
1572                                         }
1573                                         elsif ($line =~ /\/\* \$ExtraObjects: (.*?) \*\//i)
1574                                         {
1575                                                 $extraobjects{$name} = $1;
1576                                         }
1577                                         elsif ($line =~ /\/\* \$ExtraBuild: (.*?) \*\//i)
1578                                         {
1579                                                 $extrabuildlines{$name} = $1;
1580                                         }
1581                                         elsif ($line =~ /\/\* \$ExtraSources: (.*?) \*\//i)
1582                                         {
1583                                                 $extrasources{$name} = $1;
1584                                                 }
1585                                         elsif ($line =~ /\/\* \$If: (\w+) \*\//i)
1586                                         {
1587                                                 if (defined $config{$1})
1588                                                 {
1589                                                         if (($config{$1} !~ /y/i) and ($config{$1} ne "1"))
1590                                                         {
1591                                                                 # Skip to 'endif'
1592                                                                 while (defined($line = <CPP>))
1593                                                                 {
1594                                                                         chomp($line);
1595                                                                         die ("\$If buildsystem instruction within another \$If in file $dir/$name") if ($line =~ /\/\* \$If: (\w+) \*\//i);
1596                                                                         last if ($line =~ /\/\* \$EndIf \*\//i);
1597                                                                 }
1598                                                         }
1599                                                 }
1600                                         }
1601                                         elsif ($line =~ /\/\* \$Install: (.*?) \*\//i)
1602                                         {
1603                                                 if (!exists($existing_install_list{$1}))
1604                                                 {
1605                                                         $existing_install_list{$1} = 1;
1606                                                         my $idir = (split(' ',$1))[1];
1607                                                         my $ifile = (split(' ',$1))[0];
1608                                                         $install_list = $install_list . "       -install -m \$(INSTMODE) $1\n";
1609                                                         $ifile =~ s/.*\///g;
1610                                                         $uninstall_list = $uninstall_list . "   -rm $idir/$ifile\n";
1611                                                 }
1612                                         }
1613                                         elsif ($line =~ /\/\* \$CopyInstall: (.*?) \*\//i)
1614                                         {
1615                                                 if (!exists($existing_install_list{$1}))
1616                                                 {
1617                                                         $existing_install_list{$1} = 1;
1618                                                         my $idir = (split(' ',$1))[1];
1619                                                         my $ifile = (split(' ',$1))[0];
1620                                                         $install_list = $install_list . "       -cp $1\n";
1621                                                         $ifile =~ s/.*\///g;
1622                                                         $uninstall_list = $uninstall_list . "   -rm $idir/$ifile\n";
1623                                                 }
1624                                         }
1625                                 }
1626                                 close CPP;
1627                         }
1628                 }
1629                 closedir(DIRHANDLE);
1630                 print " done!\n";
1631         }
1632
1633         # modes need to be compiled in too
1634         $all_core = $all_core . "modes/modeclasses.a";
1635
1636         my $freebsd4libs = (defined $config{CRAQ} ? $config{CRAQ} : "");
1637
1638         my $libraryext = "";
1639         my $binary_rule = "";
1640
1641         if ($config{IS_DARWIN} eq "YES")
1642         {
1643                 $libraryext = "dylib";
1644                 $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 "
1645         }
1646         else
1647         {
1648                 $libraryext = "so";
1649                 $binary_rule = "        \@../make/run-cc.pl \$(CC) -pipe -I../include \$(FLAGS) $freebsd4libs -rdynamic -L. inspircd.cpp -o inspircd \$(LDLIBS) ";
1650         }
1651
1652         open(FH,">src/Makefile") or die("Could not write src/Makefile");
1653         print FH <<EOM;
1654
1655 CC = im a cheezeball
1656 CXXFLAGS = -I../include \${FLAGS}
1657 CPPFILES = \$(shell /bin/ls -l modes/ | grep '\\.cpp' | sed 's/^.* //' | grep -v svn)
1658 RELCPPFILES = \$(shell /bin/ls -l modes/ | grep '\\.cpp' | sed 's/^.* /modes\\//' | grep -v svn)
1659
1660 EOM
1661
1662         my $buildstring = "";
1663         my $deps = "";
1664
1665         foreach my $cpp (sort keys %filelist)
1666         {
1667                 my $objs = $cpp;
1668                 my $rawcpp = $cpp;
1669                 $objs =~ s/\.cpp$/.o/;
1670                 if (exists($extraobjects{$cpp}))
1671                 {
1672                         $objs = $objs . " " . $extraobjects{$cpp};
1673                         $all_core = $all_core . " " . $extraobjects{$cpp};
1674                 }
1675                 if (exists($extrasources{$cpp}))
1676                 {
1677                         $rawcpp = $rawcpp . " " . $extrasources{$cpp};
1678                 }
1679
1680                 $deps = calcdeps("src/$cpp");
1681                 if (exists($extrasources{$cpp}))
1682                 {
1683                         foreach my $seperate (sort split(' ',$extrasources{$cpp}))
1684                         {
1685                                 my $d = calcdeps("src/$extrasources{$cpp}") . " ";
1686                                 if ($d ne "")
1687                                 {
1688                                         $deps = $deps . $d . " ";
1689                                 }
1690                         }
1691                 }
1692                 $buildstring = $buildstring . $objs . ": $cpp $deps ". (defined($specialdeps{$cpp}) ? $specialdeps{$cpp} : "") . "\n";
1693
1694                 if (exists($core_files_list{$cpp}))
1695                 {
1696                         # core files are statically linked into the binary and do not require -export-dynamic
1697                         $buildstring = $buildstring . " \@../make/run-cc.pl \$(CC) -pipe -I../include \$(FLAGS) -c $rawcpp\n";
1698                 }
1699                 else
1700                 {
1701                         $buildstring = $buildstring . " \@../make/run-cc.pl \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c $rawcpp\n";
1702                 }
1703
1704                 if (exists($extrabuildlines{$cpp}))
1705                 {
1706                         $buildstring = $buildstring . " " . $extrabuildlines{$cpp} . "\n";
1707                 }
1708         }
1709
1710         print FH "all: inspircd moo\n\n\n";
1711
1712         $deps = calcdeps("src/inspircd.cpp");
1713         print FH "inspircd: inspircd.cpp $deps $all_core\n";
1714         print FH "$binary_rule $all_core\n\n";
1715
1716         print FH $buildstring;
1717         print FH "moo:\n        \@\${MAKE} -C \"commands\" DIRNAME=\"src/commands\" CC=\"\$(CC)\" \$(MAKEARGS)\n\n";
1718
1719         # close main makefile
1720         close(FH);
1721
1722         my $cmdobjs = "";
1723         # generate a list of .so
1724         foreach my $cmd (@cmdlist) {
1725                 $cmdobjs = $cmdobjs . "cmd_$cmd.so ";
1726         }
1727
1728         # and now reopen the commands makefile
1729         open(FH,">src/commands/Makefile") or die("Could not write src/commands/Makefile");
1730         print FH <<ITEM;
1731 CC = i am cornholio
1732 CXXFLAGS = -I../../include \${FLAGS}
1733
1734 all: $cmdobjs
1735
1736
1737 ITEM
1738
1739         # now print the command file details.
1740         foreach my $cmd (@cmdlist) {
1741                 print FH <<ITEM;
1742 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
1743         \@../../make/run-cc.pl \$(CC) -pipe -I../../include \$(FLAGS) -export-dynamic $SHARED -o cmd_$cmd.so cmd_$cmd.cpp
1744
1745 ITEM
1746         }
1747 }
1748
1749 # Routine to list out the extra/ modules that have been enabled.
1750 # Note: when getting any filenames out and comparing, it's important to lc it if the
1751 # file system is not case-sensitive (== Epoc, MacOS, OS/2 (incl DOS/DJGPP), VMS, Win32
1752 # (incl NetWare, Symbian)). Cygwin may or may not be case-sensitive, depending on
1753 # configuration, however, File::Spec does not currently tell us (it assumes Unix behavior).
1754 sub list_extras () {
1755         use File::Spec;
1756         # @_ not used
1757         my $srcdir = File::Spec->catdir("src", "modules");
1758         my $abs_srcdir = File::Spec->rel2abs($srcdir);
1759         local $_;
1760         my $dd;
1761         opendir $dd, File::Spec->catdir($abs_srcdir, "extra") or die (File::Spec->catdir($abs_srcdir, "extra") . ": $!\n");
1762         my @extras = map { File::Spec->case_tolerant() ? lc($_) : $_ } (readdir($dd));
1763         closedir $dd;
1764         undef $dd;
1765         opendir $dd, $abs_srcdir or die "$abs_srcdir: $!\n";
1766         my @sources = map { File::Spec->case_tolerant() ? lc($_) : $_ } (readdir($dd));
1767         closedir $dd;
1768         undef $dd;
1769         my $maxlen = (sort { $b <=> $a } (map {length($_)} (@extras)))[0];
1770         my %extras = ();
1771 EXTRA:  for my $extra (@extras) {
1772                 next if (File::Spec->curdir() eq $extra || File::Spec->updir() eq $extra);
1773                 next if ($extra eq '.svn');
1774                 my $abs_extra = File::Spec->catfile($abs_srcdir, "extra", $extra);
1775                 my $abs_source = File::Spec->catfile($abs_srcdir, $extra);
1776                 next unless ($extra =~ m/\.(cpp|h)$/ || (-d $abs_extra)); # C++ Source/Header, or directory
1777                 if (-l $abs_source) {
1778                         # Symlink, is it in the right place?
1779                         my $targ = readlink($abs_source);
1780                         my $abs_targ = File::Spec->rel2abs($targ, $abs_srcdir);
1781                         if ($abs_targ eq $abs_extra) {
1782                                 $extras{$extra} = "\e[32;1menabled\e[0m";
1783                         } else {
1784                                 $extras{$extra} = sprintf("\e[31;1mwrong symlink target (%s)\e[0m", $abs_targ);
1785                         }
1786                 } elsif (-e $abs_source) {
1787                         my ($devext, $inoext) = stat($abs_extra);
1788                         my ($devsrc, $inosrc, undef, $lnksrc) = stat($abs_source);
1789                         if ($lnksrc > 1) {
1790                                 if ($devsrc == $devext && $inosrc == $inoext) {
1791                                         $extras{$extra} = "\e[32;1menabled\e[0m";
1792                                 } else {
1793                                         $extras{$extra} = sprintf("\e[31;1mwrong hardlink target (%d:%d)\e[0m", $devsrc, $inosrc);
1794                                 }
1795                         } else {
1796                                 open my $extfd, "<", $abs_extra;
1797                                 open my $srcfd, "<", $abs_source;
1798                                 local $/ = undef;
1799                                 if (scalar(<$extfd>) eq scalar(<$srcfd>)) {
1800                                         $extras{$extra} = "\e[32;1menabled\e[0m";
1801                                 } else {
1802                                         $extras{$extra} = sprintf("\e[31;1mout of synch (re-copy)\e[0m");
1803                                 }
1804                         }
1805                 } else {
1806                         $extras{$extra} = "\e[33;1mdisabled\e[0m";
1807                 }
1808         }
1809         # Now let's add dependency info
1810         for my $extra (keys(%extras)) {
1811                 next unless $extras{$extra} =~ m/enabled/; # only process enabled extras.
1812                 my $abs_extra = File::Spec->catfile($abs_srcdir, "extra", $extra);
1813                 my @deps = split / +/, getdependencies($abs_extra);
1814                 for my $dep (@deps) {
1815                         if (exists($extras{$dep})) {
1816                                 my $ref = \$extras{$dep}; # Take reference.
1817                                 if ($$ref !~ m/needed by/) {
1818                                         # First dependency found.
1819                                         if ($$ref =~ m/enabled/) {
1820                                                 $$ref .= " (needed by \e[32;1m$extra\e[0m";
1821                                         } else {
1822                                                 $$ref =~ s/\e\[.*?m//g; # Strip out previous coloring. Will be set in bold+red+blink later.
1823                                                 $$ref .= " (needed by \e[0;32;1;5m$extra\e[0;31;1;5m";
1824                                         }
1825                                 } else {
1826                                         if ($$ref =~ m/enabled/) {
1827                                                 $$ref .= ", \e[32;1m$extra\e[0m";
1828                                         } else {
1829                                                 $$ref .= ", \e[0;32;1;5m$extra\e[0;31;1;5m";
1830                                         }
1831                                 }
1832                         }
1833                 }
1834         }
1835         for my $extra (sort {$a cmp $b} keys(%extras)) {
1836                 my $text = $extras{$extra};
1837                 if ($text =~ m/needed by/ && $text !~ m/enabled/) {
1838                         printf "\e[31;1;5m%-*s = %s%s\e[0m\n", $maxlen, $extra, $text, ($text =~ m/needed by/ ? ")" : "");
1839                 } else {
1840                         printf "%-*s = %s%s\n", $maxlen, $extra, $text, ($text =~ m/needed by/ ? "\e[0m)" : "");
1841                 }
1842         }
1843         return keys(%extras) if wantarray; # Can be used by manage_extras.
1844 }
1845
1846 sub enable_extras (@) {
1847         my (@extras) = @_;
1848         for my $extra (@extras) {
1849                 my $extrapath = "src/modules/extra/$extra";
1850                 if (!-e $extrapath) {
1851                         print STDERR "Cannot enable \e[32;1m$extra\e[0m : No such file or directory in src/modules/extra\n";
1852                         next;
1853                 }
1854                 my $source = "src/modules/$extra";
1855                 if (-e $source) {
1856                         print STDERR "Cannot enable \e[32;1m$extra\e[0m : destination in src/modules exists (might already be enabled?)\n";
1857                         next;
1858                 }
1859                 # Get dependencies, and add them to be processed.
1860                 my @deps = split / +/, getdependencies($extrapath);
1861                 for my $dep (@deps) {
1862                         next if scalar(grep { $_ eq $dep } (@extras)) > 0; # Skip if we're going to be enabling it anyway.
1863                         if (!-e "src/modules/$dep") {
1864                                 if (-e "src/modules/extra/$dep") {
1865                                         print STDERR "Will also enable extra \e[32;1m$dep\e[0m (needed by \e[32;1m$extra\e[0m)\n";
1866                                         push @extras, $dep;
1867                                 } else {
1868                                         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";
1869                                 }
1870                         }
1871                 }
1872                 print "Enabling $extra ... \n";
1873                 symlink "extra/$extra", $source or print STDERR "$source: Cannot link to 'extra/$extra': $!\n";
1874         }
1875 }
1876
1877 sub disable_extras (@)
1878 {
1879         opendir my $dd, "src/modules/extra/";
1880         my @files = readdir($dd);
1881         closedir $dd;
1882         my (@extras) = @_;
1883 EXTRA:  for my $extra (@extras) {
1884                 my $extrapath = "src/modules/extra/$extra";
1885                 my $source = "src/modules/$extra";
1886                 if (!-e $extrapath) {
1887                         print STDERR "Cannot disable \e[32;1m$extra\e[0m : Is not an extra\n";
1888                         next;
1889                 }
1890                 if ((! -l $source) || readlink($source) ne "extra/$extra") {
1891                         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";
1892                         next;
1893                 }
1894                 # Check if anything needs this.
1895                 for my $file (@files) {
1896                         my @deps = split / +/, getdependencies("src/modules/extra/$file");
1897                         # File depends on this extra...
1898                         if (scalar(grep { $_ eq $extra } @deps) > 0) {
1899                                 # And is both enabled and not about to be disabled.
1900                                 if (-e "src/modules/$file" && scalar(grep { $_ eq $file } @extras) < 1) {
1901                                         print STDERR "Cannot disable \e[32;1m$extra\e[0m : is needed by \e[32;1m$file\e[0m\n";
1902                                         next EXTRA;
1903                                 }
1904                         }
1905                 }
1906                 # Now remove.
1907                 print "Disabling $extra ... \n";
1908                 unlink "src/modules/$extra" or print STDERR "Cannot disable \e[32;1m$extra\e[0m : $!\n";
1909         }
1910 }