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