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