]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - configure
I was told that a new dev's first action must be adding himself to /info, so
[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 # apparantly (Dagonet says) that this causes problems, so let's try without it.
1110 #               $config{LDLIBS} = $config{LDLIBS} . " -lunwind";
1111                 chomp(my $foo = `eg++ -dumpversion | cut -c 1`);
1112                 # theyre running the package version of gcc (eg++)... detect it and set up its version numbers.
1113                 # if theyre not running this, configure lets the build continue but they probably wont manage to
1114                 # compile as this standard version is 2.95.3!
1115                 if ($foo ne "") {
1116                         $config{CC} = "eg++";
1117                         chomp($config{GCCVER}       = `eg++ -dumpversion | cut -c 1`); # we must redo these if we change the compiler path
1118                         chomp($config{GCCMINOR}     = `eg++ -dumpversion | cut -c 3`);
1119                 }
1120                 return "OpenBSD";
1121         }
1122
1123         if ($config{OSNAME} =~ /Linux/i) {
1124                 $config{LDLIBS} = "-ldl -lstdc++ -pthread";
1125 #               $config{FLAGS}  = "-fPIC -Woverloaded-virtual -Wshadow -Wall $config{OPTIMISATI}";
1126                 $config{FLAGS}  .= " " . $ENV{CXXFLAGS} if exists($ENV{CXXFLAGS});
1127                 $config{LDLIBS} .= " " . $ENV{LDLIBS} if exists($ENV{LDLIBS});
1128                 $config{MAKEPROG} = "make";
1129         }
1130
1131         if ($config{OSNAME} =~ /FreeBSD/i) {
1132                 $config{FLAGS}  .= " " . $ENV{CXXFLAGS} if exists($ENV{CXXFLAGS});
1133                 $config{LDLIBS} .= " " . $ENV{LDLIBS} if exists($ENV{LDLIBS});
1134         }
1135
1136         if ($config{OSNAME} =~ /SunOS/i or $config{OSNAME} =~ /solaris/i)
1137         {
1138                 # solaris/sunos needs these
1139                 # socket = bsd sockets api
1140                 # nsl = dns stuff
1141                 # rt = POSIX realtime extensions
1142                 # resolv = inet_aton only (why isnt this in nsl?!)
1143                 $config{MAKEPROG} = "gmake";
1144                 $config{LDLIBS} .= " -lsocket -lnsl -lrt -lresolv -pthread";
1145                 return "Solaris";
1146         }
1147         
1148         if($config{OSNAME} =~ /MINGW32/i)
1149         {
1150                 # All code is position-independent on windows
1151                 $config{FLAGS} =~ s/-fPIC //;
1152                 return "MinGW";
1153         }
1154
1155         return $config{OSNAME};
1156 }
1157
1158 my ($mliflags, $mfrules, $mobjs, $mfcount) = ("", "", "", 0);
1159
1160 sub writefiles {
1161         my($writeheader) = @_;
1162         my $se = "";
1163         # First File.. inspircd_config.h
1164         chomp(my $incos = `uname -n -s -r`);
1165         chomp(my $version = `sh src/version.sh`);
1166         chomp(my $revision2 = getrevision());
1167         if ($writeheader == 1)
1168         {
1169                 print "Writing \e[1;32minspircd_config.h\e[0m\n";
1170                 open(FILEHANDLE, ">include/inspircd_config.h");
1171                 print FILEHANDLE <<EOF;
1172 /* Auto generated by configure, do not modify! */
1173 #ifndef __CONFIGURATION_AUTO__
1174 #define __CONFIGURATION_AUTO__
1175
1176 /* this is for windows support. */
1177 #define CoreExport /**/
1178 #define DllExport /**/
1179
1180 #define CONFIG_FILE "$config{CONFIG_DIR}/inspircd.conf"
1181 #define MOD_PATH "$config{MODULE_DIR}"
1182 #define VERSION "$version"
1183 #define REVISION "$revision2"
1184 #define SOMAXCONN_S "$config{_SOMAXCONN}"
1185 #define OPTIMISATION $config{OPTIMITEMP}
1186 #define LIBRARYDIR "$config{LIBRARY_DIR}"
1187 #define SYSTEM "$incos"
1188 #define ENTRYPOINT int main(int argc, char** argv)
1189
1190 EOF
1191 print FILEHANDLE "#define MAXBUF " . ($config{MAXBUF}+2) . "\n";
1192
1193                 if ($config{OSNAME} =~ /SunOS/i) {
1194                         print FILEHANDLE "#define IS_SOLARIS\n";
1195                 }
1196                 if ($config{OSNAME} =~ /MINGW32/i) {
1197                         print FILEHANDLE "#define IS_MINGW\n";
1198                 }
1199                 if ($config{GCCVER} >= 3) {
1200                         print FILEHANDLE "#define GCC3\n";
1201                 }
1202                 if (
1203                         (($config{GCCVER} == 4) && ($config{GCCMINOR} >= 3))
1204                                 ||
1205                         ($config{GCCVER} > 4)
1206                 ) {
1207                         print FILEHANDLE "#define HASHMAP_DEPRECATED\n";
1208                 }
1209                 if ($config{HAS_STRLCPY} eq "true") {
1210                         print FILEHANDLE "#define HAS_STRLCPY\n";
1211                 }
1212                 if ($config{HAS_STDINT} eq "true") {
1213                         print FILEHANDLE "#define HAS_STDINT\n";
1214                 }
1215                 if ($config{IPV6} =~ /y/i) {
1216                         print FILEHANDLE "#define IPV6\n";
1217                 }
1218                 if ($config{SUPPORT_IP6LINKS} =~ /y/i) {
1219                         print FILEHANDLE "#define SUPPORT_IP6LINKS\n";
1220                 }
1221                 my $use_hiperf = 0;
1222                 if (($has_kqueue) && ($config{USE_KQUEUE} eq "y")) {
1223                         print FILEHANDLE "#define USE_KQUEUE\n";
1224                         $se = "socketengine_kqueue";
1225                         $use_hiperf = 1;
1226                 }
1227                 if (($has_epoll) && ($config{USE_EPOLL} eq "y")) {
1228                         print FILEHANDLE "#define USE_EPOLL\n";
1229                         $se = "socketengine_epoll";
1230                         $use_hiperf = 1;
1231                 }
1232                 if (($has_ports) && ($config{USE_PORTS} eq "y")) {
1233                         print FILEHANDLE "#define USE_PORTS\n";
1234                         $se = "socketengine_ports";
1235                         $use_hiperf = 1;
1236                 }
1237                 # user didn't choose either epoll or select for their OS.
1238                 # default them to USE_SELECT (ewwy puke puke)
1239                 if (!$use_hiperf) {
1240                         print "no hi-perf, " . $config{USE_POLL};
1241                         if ($config{USE_POLL} eq "y")
1242                         {
1243                                 print FILEHANDLE "#define USE_POLL\n";
1244                                 $se = "socketengine_poll";
1245                         }
1246                         else
1247                         {
1248                                 print FILEHANDLE "#define USE_SELECT\n";
1249                                 $se = "socketengine_select";
1250                         }
1251                 }
1252                 print FILEHANDLE "\n#include \"threadengines/threadengine_pthread.h\"\n\n#endif\n";
1253                 close(FILEHANDLE);
1254         }
1255
1256         if ($writeheader)
1257         {
1258                 open(FILEHANDLE, ">include/inspircd_se_config.h");
1259                 print FILEHANDLE <<EOF;
1260 /* Auto generated by configure, do not modify or commit to svn! */
1261 #ifndef __CONFIGURATION_SOCKETENGINE__
1262 #define __CONFIGURATION_SOCKETENGINE__
1263
1264 #include "socketengines/$se.h"
1265
1266 #endif
1267 EOF
1268                 close(FILEHANDLE);
1269         }
1270
1271
1272         # Create a Modules List..
1273         my $modules = "";
1274         foreach my $i (@modlist)
1275         {
1276                 $modules .= "m_".$i.".so ";
1277         }
1278         chomp($modules);   # Remove Redundant whitespace..
1279
1280         opendir(DIRHANDLE, "src/modules");
1281         foreach my $name2 (sort readdir(DIRHANDLE)) {
1282                 if ($name2 =~ /^m_(.+?)$/) {
1283                         if (defined(opendir(MDIRHANDLE, "src/modules/$name2"))) {
1284                                 closedir(MDIRHANDLE);
1285                                 $modules .= "$name2.so ";
1286                                 $uninstall_list = $uninstall_list . "   -rm \$(MODULES)/$name2.so\n";
1287                         }
1288                 }
1289         }
1290         closedir(DIRHANDLE);
1291
1292
1293         # Write all .in files.
1294         my $tmp = "";
1295         my $file = "";
1296         my $exe = "inspircd";
1297
1298         # Do this once here, and cache it in the .*.inc files,
1299         # rather than attempting to read src/version.sh from
1300         # compiled code -- we might not have the source to hand.
1301         # Fix for bug#177 by Brain.
1302
1303         chomp($version = `sh ./src/version.sh`);
1304         chomp(my $revision = getrevision());
1305         $version = "$version(r$revision)";
1306
1307         # We can actually parse any file starting with . and ending with .inc,
1308         # but right now we only parse .inspircd.inc to form './inspircd'
1309
1310         print "Writing \e[1;32mMakefiles\e[0m\n";
1311         write_dynamic_modules_makefile();
1312         write_dynamic_makefile();
1313
1314         opendir(DIRHANDLE, $this);
1315
1316         foreach my $name (sort readdir(DIRHANDLE)) {
1317                 if ($name =~ /^\.(.+)\.inc$/) {
1318                         $file = $1;
1319
1320                         # Bug #353, omit this on non-darwin
1321                         next if (($config{OSNAME} !~ /darwin/) && ($file eq "org.inspircd.plist"));
1322
1323                         # All .name.inc files need parsing!
1324                         $tmp = "";
1325                         open(FILEHANDLE, ".$file.inc") or die ("Can't open .$file.inc");
1326                         while (<FILEHANDLE>) {
1327                                 $tmp .= $_;
1328                         }
1329                         close(FILEHANDLE);
1330
1331                         print "Writing \e[1;32m$file\e[0m ...\n";
1332                         $tmp =~ s/\@CC\@/$config{CC}/ if defined $config{CC};
1333                         $tmp =~ s/\@MAKEPROG\@/$config{MAKEPROG}/ if defined $config{MAKEPROG};
1334                         $tmp =~ s/\@FLAGS\@/$config{FLAGS}/ if defined $config{FLAGS};
1335                         $tmp =~ s/\@DEVELOPER\@/$config{DEVELOPER}/ if defined $config{DEVELOPER};
1336                         $tmp =~ s/\@LDLIBS\@/$config{LDLIBS}/ if defined $config{LDLIBS};
1337                         $tmp =~ s/\@BASE_DIR\@/$config{BASE_DIR}/ if defined $config{BASE_DIR};
1338                         $tmp =~ s/\@CONFIG_DIR\@/$config{CONFIG_DIR}/ if defined $config{CONFIG_DIR};
1339                         $tmp =~ s/\@MODULE_DIR\@/$config{MODULE_DIR}/ if defined $config{MODULE_DIR};
1340                         $tmp =~ s/\@BINARY_DIR\@/$config{BINARY_DIR}/ if defined $config{BINARY_DIR};
1341                         $tmp =~ s/\@LIBRARY_DIR\@/$config{LIBRARY_DIR}/ if defined $config{LIBRARY_DIR};
1342                         $tmp =~ s/\@MODULES\@/$modules/ if defined $modules;
1343                         $tmp =~ s/\@STARTSCRIPT\@/$config{STARTSCRIPT}/ if defined $config{STARTSCRIPT};
1344                         $tmp =~ s/\@DESTINATION\@/$config{DESTINATION}/ if defined $config{DESTINATION};
1345                         $tmp =~ s/\@EXTRA_DIR\@/$config{EXTRA_DIR}/ if defined $config{EXTRA_DIR};
1346                         $tmp =~ s/\@EXECUTABLE\@/$exe/ if defined $exe;
1347                         $tmp =~ s/\@MAKEORDER\@/$config{MAKEORDER}/ if defined $config{MAKEORDER};
1348                         $tmp =~ s/\@VERSION\@/$version/ if defined $version;
1349                         $tmp =~ s/\@INSTALL_LIST\@/$install_list/ if defined $install_list;
1350                         $tmp =~ s/\@UNINSTALL_LIST\@/$uninstall_list/ if defined $uninstall_list;
1351
1352                         open(FILEHANDLE, ">$file");
1353                         print FILEHANDLE $tmp;
1354                 }
1355         }
1356         closedir(DIRHANDLE);
1357
1358         # Make inspircd executable!
1359         chmod 0744, 'inspircd';
1360 }
1361
1362 sub write_dynamic_modules_makefile {
1363         # Modules Makefile..
1364         print "Writing \e[1;32msrc/modules/Makefile\e[0m\n";
1365         open(FILEHANDLE, ">src/modules/Makefile");
1366
1367 ###
1368 # Module Makefile Header
1369 ###
1370         print FILEHANDLE <<EOF;
1371 ###################################################
1372 # Copyright 2002-2007 The InspIRCd Development Team
1373 #  http://www.inspircd.org/wiki/index.php/Credits
1374 #
1375 # Thanks to Andrew Church <achurch\@achurch.org>
1376 #   for assisting with making this work right.
1377 #
1378 # Automatically Generated by ./configure to add a
1379 #  modules please run ./configure -modupdate
1380 ###################################################
1381
1382 all: \$(MODULES)
1383
1384 EOF
1385
1386 if ($config{OSNAME} =~ /darwin/) {
1387                 print FILEHANDLE <<EOCHEESE;
1388
1389 PICLDFLAGS = -twolevel_namespace -undefined dynamic_lookup -bundle
1390
1391 EOCHEESE
1392 } else {
1393                 print FILEHANDLE <<EOCHEESE;
1394
1395 PICLDFLAGS = -fPIC -DPIC -shared
1396
1397 EOCHEESE
1398 }
1399
1400         ###
1401         # End Module Makefile Header
1402         ###
1403
1404         # Create a Modules List..
1405         my $modules = "";
1406         my $cmflags = "";
1407         my $liflags = "";
1408         foreach my $i (@modlist) {
1409                 ###
1410                 # Write Entry to the MakeFile
1411                 ###
1412                 $cmflags = getcompilerflags("src/modules/m_".$i.".cpp");
1413                 $liflags = getlinkerflags("src/modules/m_".$i.".cpp");
1414                 my $deps = getdependencies("src/modules/m_".$i.".cpp");
1415         
1416                 #print "file: $i: cmflags=$cmflags; liflags=$liflags; deps=$deps\n";
1417         
1418
1419                 if (nopedantic("src/modules/m_".$i.".cpp"))
1420                 {
1421                         print FILEHANDLE "
1422 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
1423         \@../../make/run-cc.pl \$(CC) -pipe -I../../include \$(NICEFLAGS) $cmflags \$(PICLDFLAGS) $liflags -export-dynamic -o m_$i.so m_$i.cpp
1424 "
1425                 }
1426                 else
1427                 {
1428                         print FILEHANDLE "
1429 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
1430         \@../../make/run-cc.pl \$(CC) -pipe -I../../include \$(FLAGS) $cmflags \$(PICLDFLAGS) $liflags -export-dynamic -o m_$i.so m_$i.cpp
1431 ";
1432                 }
1433                 $install_list = $install_list . "       install -m \$(INSTMODE) src/modules/m_$i.so \$(MODPATH)\n";
1434                 $uninstall_list = $uninstall_list . "   -rm \$(MODULES)/m_$i.so\n";
1435 ###
1436                 # End Write Entry to the MakeFile
1437                 ###
1438         }
1439
1440         opendir(DIRHANDLE, "src/modules");
1441         foreach my $name (sort readdir(DIRHANDLE)) {
1442                 if ($name =~ /^m_(.+?)$/) {
1443                         $mfrules = "";
1444                         $mobjs = "";
1445                         $mliflags = "";
1446                         $mfcount = 0;
1447                         # A module made of multiple files, in a dir, e.g. src/modules/m_spanningtree/
1448                         if (defined(opendir(MDIRHANDLE, "src/modules/$name"))) {
1449                                 read_module_directory("src/modules/$name", $name);
1450                                 print "Composing Makefile rules for directory \e[1;32m$name\e[0m... (\e[1;32m$mfcount files found\e[0m)\n";
1451                                 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"; 
1452                                 if ($config{IS_DARWIN} eq "YES") {
1453                                         print FILEHANDLE "      \@../../make/run-cc.pl \$(CC) -pipe -twolevel_namespace -undefined dynamic_lookup \$(FLAGS) $mliflags -bundle -o $name.so $mobjs\n"; 
1454                                 } else {
1455                                         print FILEHANDLE "      \@../../make/run-cc.pl \$(CC) -pipe \$(FLAGS) -shared $mliflags -o $name.so $mobjs\n";
1456                                 }
1457                                 print FILEHANDLE "\n$mfrules\n";
1458                                 closedir(MDIRHANDLE);
1459                                 $install_list = $install_list . "       install -m \$(INSTMODE) src/modules/$name.so \$(MODPATH)\n";
1460                         }
1461                 }
1462         }
1463         closedir(DIRHANDLE);
1464 }
1465
1466 sub read_module_directory {
1467         my ($dpath, $reldpath) = @_;
1468         
1469         if (opendir(MDIRHANDLE, $dpath) == 0) {
1470                 return;
1471         }
1472         
1473         foreach my $fname (sort readdir(MDIRHANDLE)) {
1474                 if ($fname =~ /\.cpp$/) {
1475                         my $cmflags = getcompilerflags("$dpath/$fname");
1476                         $mliflags = $mliflags . " " . getlinkerflags("$dpath/$fname");
1477                         my $deps = getdependencies("$dpath/$fname");
1478                         my $oname = $fname;
1479                         $oname =~ s/\.cpp$/.o/g;
1480                         $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";
1481                         $mfrules = $mfrules .  "        \@../../make/run-cc.pl \$(CC) -pipe -I../../include -I. \$(FLAGS) $cmflags -export-dynamic -o $reldpath/$oname -c $reldpath/$fname\n\n";
1482                         $mobjs = $mobjs . " $reldpath/$oname";
1483                         $mfcount++;
1484                 }
1485                 elsif ((-d "$dpath/$fname") && !($fname eq ".") && !($fname eq "..")) {
1486                         read_module_directory($dpath."/".$fname, $reldpath."/".$fname);
1487                 }
1488         }
1489 }
1490
1491 sub calcdeps($)
1492 {
1493         # Yes i know we could use gcc -M but it seems to ideneify a lot of 'deep'
1494         # dependencies which are not relevent in C++.
1495
1496         my $file = $_[0];
1497
1498         open (CPP, "<$file") or die("Can't open $file for reading!");
1499
1500         my %dupe = ();
1501         my $retlist = "";
1502
1503         foreach my $d (@ignoredeps)
1504         {
1505                 $dupe{$d} = 1;
1506         }
1507
1508         my $immutable = "";
1509         foreach my $dep (@immutabledeps)
1510         {
1511                 $immutable = $immutable . "../include/$dep ";
1512         }
1513         $immutable =~ s/ $//g;
1514
1515         while (defined(my $line = <CPP>))
1516         {
1517                 chomp($line);
1518                 if ($line =~ /#include "(.+\.h)"/)
1519                 {
1520                         if (!exists($dupe{$1}))
1521                         {
1522                                 $retlist = $retlist . "../include/$1 ";
1523                                 $dupe{$1} = 1;
1524                         }
1525                 }
1526         }
1527         close CPP;
1528         return length($immutable) ? $immutable . " " . $retlist : $retlist;
1529 }
1530
1531 sub write_dynamic_makefile
1532 {
1533         my $i = 0;
1534         my @cmdlist = ();
1535         my %existing_install_list = ();
1536         my %core_files_list = ();
1537
1538         opendir(DIRHANDLE, "src/commands");
1539         foreach my $name (sort readdir(DIRHANDLE))
1540         {
1541                 if ($name =~ /^cmd_(.+)\.cpp$/)
1542                 {
1543                         $cmdlist[$i++] = $1;
1544                         $install_list = $install_list . "       -install -m \$(INSTMODE) src/commands/cmd_" . $1 . ".so \$(LIBPATH)\n";
1545                         $uninstall_list = $uninstall_list . "   -rm \$(LIBPATH)/cmd_$1.so\n";
1546                 }
1547         }
1548         closedir(DIRHANDLE);
1549
1550         if (!$has_epoll)
1551         {
1552                 $config{USE_EPOLL} = 0;
1553         }
1554         if (!$has_kqueue)
1555         {
1556                 $config{USE_KQUEUE} = 0;
1557         }
1558         if (!$has_ports)
1559         {
1560                 $config{USE_PORTS} = 0;
1561         }
1562
1563         # formerly generated below this foreach, now it's not! magic.
1564         my $all_core = "";
1565
1566         foreach my $dir (("src","src/commands","src/modes","src/socketengines","src/modules"))
1567         {
1568                 print "Scanning \e[1;32m$dir\e[0m for core files ";
1569                 opendir(DIRHANDLE, $dir);
1570                 foreach my $name (sort readdir(DIRHANDLE))
1571                 {
1572                         if ($name =~ /\.cpp$/)
1573                         {
1574                                 open (CPP, "<$dir/$name") or die("Can't open $dir/$name to scan it! oh bugger");
1575                                 print ".";
1576                                 while (defined(my $line = <CPP>))
1577                                 {
1578                                         chomp($line);
1579                                         if ($line =~ /\/\* \$Core \*\//i)
1580                                         {
1581                                                 my $sname = $name;
1582                                                 $sname =~ s/\.cpp$/.o/;
1583
1584                                                 # append it to list to be built
1585                                                 $all_core = $all_core . $sname . " ";
1586                                                 $filelist{$name} = $sname;
1587
1588                                                 # mark it as a core file, so it won't get shared object cflags
1589                                                 if (!exists($core_files_list{$name}))
1590                                                 {
1591                                                         $core_files_list{$name} = 1;
1592                                                 }
1593                                         }
1594                                         elsif ($line =~ /\/\* \$ExtraDeps: (.*?) \*\//i)
1595                                         {
1596                                                 $specialdeps{$name} = $1;
1597                                         }
1598                                         elsif ($line =~ /\/\* \$ExtraObjects: (.*?) \*\//i)
1599                                         {
1600                                                 $extraobjects{$name} = $1;
1601                                         }
1602                                         elsif ($line =~ /\/\* \$ExtraBuild: (.*?) \*\//i)
1603                                         {
1604                                                 $extrabuildlines{$name} = $1;
1605                                         }
1606                                         elsif ($line =~ /\/\* \$ExtraSources: (.*?) \*\//i)
1607                                         {
1608                                                 $extrasources{$name} = $1;
1609                                                 }
1610                                         elsif ($line =~ /\/\* \$If: (\w+) \*\//i)
1611                                         {
1612                                                 if (defined $config{$1})
1613                                                 {
1614                                                         if (($config{$1} !~ /y/i) and ($config{$1} ne "1"))
1615                                                         {
1616                                                                 # Skip to 'endif'
1617                                                                 while (defined($line = <CPP>))
1618                                                                 {
1619                                                                         chomp($line);
1620                                                                         die ("\$If buildsystem instruction within another \$If in file $dir/$name") if ($line =~ /\/\* \$If: (\w+) \*\//i);
1621                                                                         last if ($line =~ /\/\* \$EndIf \*\//i);
1622                                                                 }
1623                                                         }
1624                                                 }
1625                                         }
1626                                         elsif ($line =~ /\/\* \$Install: (.*?) \*\//i)
1627                                         {
1628                                                 if (!exists($existing_install_list{$1}))
1629                                                 {
1630                                                         $existing_install_list{$1} = 1;
1631                                                         my $idir = (split(' ',$1))[1];
1632                                                         my $ifile = (split(' ',$1))[0];
1633                                                         $install_list = $install_list . "       -install -m \$(INSTMODE) $1\n";
1634                                                         $ifile =~ s/.*\///g;
1635                                                         $uninstall_list = $uninstall_list . "   -rm $idir/$ifile\n";
1636                                                 }
1637                                         }
1638                                         elsif ($line =~ /\/\* \$CopyInstall: (.*?) \*\//i)
1639                                         {
1640                                                 if (!exists($existing_install_list{$1}))
1641                                                 {
1642                                                         $existing_install_list{$1} = 1;
1643                                                         my $idir = (split(' ',$1))[1];
1644                                                         my $ifile = (split(' ',$1))[0];
1645                                                         $install_list = $install_list . "       -cp $1\n";
1646                                                         $ifile =~ s/.*\///g;
1647                                                         $uninstall_list = $uninstall_list . "   -rm $idir/$ifile\n";
1648                                                 }
1649                                         }
1650                                 }
1651                                 close CPP;
1652                         }
1653                 }
1654                 closedir(DIRHANDLE);
1655                 print " done!\n";
1656         }
1657
1658         # modes need to be compiled in too
1659         $all_core = $all_core . "modes/modeclasses.a";
1660
1661         my $freebsd4libs = (defined $config{CRAQ} ? $config{CRAQ} : "");
1662
1663         my $libraryext = "";
1664         my $binary_rule = "";
1665
1666         if ($config{IS_DARWIN} eq "YES")
1667         {
1668                 $libraryext = "dylib";
1669                 $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 "
1670         }
1671         else
1672         {
1673                 $libraryext = "so";
1674                 $binary_rule = "        \@../make/run-cc.pl \$(CC) -pipe -I../include \$(FLAGS) $freebsd4libs -rdynamic -L. inspircd.cpp -o inspircd \$(LDLIBS) ";
1675         }
1676
1677         open(FH,">src/Makefile") or die("Could not write src/Makefile");
1678         print FH <<EOM;
1679
1680 CC = im a cheezeball
1681 CXXFLAGS = -I../include \${FLAGS}
1682 CPPFILES = \$(shell /bin/ls -l modes/ | grep '\\.cpp' | sed 's/^.* //' | grep -v svn)
1683 RELCPPFILES = \$(shell /bin/ls -l modes/ | grep '\\.cpp' | sed 's/^.* /modes\\//' | grep -v svn)
1684
1685 EOM
1686
1687         my $buildstring = "";
1688         my $deps = "";
1689
1690         foreach my $cpp (sort keys %filelist)
1691         {
1692                 my $objs = $cpp;
1693                 my $rawcpp = $cpp;
1694                 $objs =~ s/\.cpp$/.o/;
1695                 if (exists($extraobjects{$cpp}))
1696                 {
1697                         $objs = $objs . " " . $extraobjects{$cpp};
1698                         $all_core = $all_core . " " . $extraobjects{$cpp};
1699                 }
1700                 if (exists($extrasources{$cpp}))
1701                 {
1702                         $rawcpp = $rawcpp . " " . $extrasources{$cpp};
1703                 }
1704
1705                 $deps = calcdeps("src/$cpp");
1706                 if (exists($extrasources{$cpp}))
1707                 {
1708                         foreach my $seperate (sort split(' ',$extrasources{$cpp}))
1709                         {
1710                                 my $d = calcdeps("src/$extrasources{$cpp}") . " ";
1711                                 if ($d ne "")
1712                                 {
1713                                         $deps = $deps . $d . " ";
1714                                 }
1715                         }
1716                 }
1717                 $buildstring = $buildstring . $objs . ": $cpp $deps ". (defined($specialdeps{$cpp}) ? $specialdeps{$cpp} : "") . "\n";
1718
1719                 if (exists($core_files_list{$cpp}))
1720                 {
1721                         # core files are statically linked into the binary and do not require -export-dynamic
1722                         $buildstring = $buildstring . " \@../make/run-cc.pl \$(CC) -pipe -I../include \$(FLAGS) -c $rawcpp\n";
1723                 }
1724                 else
1725                 {
1726                         $buildstring = $buildstring . " \@../make/run-cc.pl \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c $rawcpp\n";
1727                 }
1728
1729                 if (exists($extrabuildlines{$cpp}))
1730                 {
1731                         $buildstring = $buildstring . " " . $extrabuildlines{$cpp} . "\n";
1732                 }
1733         }
1734
1735         print FH "all: inspircd moo\n\n\n";
1736
1737         $deps = calcdeps("src/inspircd.cpp");
1738         print FH "inspircd: inspircd.cpp $deps $all_core\n";
1739         print FH "$binary_rule $all_core\n\n";
1740
1741         print FH $buildstring;
1742         print FH "moo:\n        \@\${MAKE} -C \"commands\" DIRNAME=\"src/commands\" CC=\"\$(CC)\" \$(MAKEARGS)\n\n";
1743
1744         # close main makefile
1745         close(FH);
1746
1747         my $cmdobjs = "";
1748         # generate a list of .so
1749         foreach my $cmd (@cmdlist) {
1750                 $cmdobjs = $cmdobjs . "cmd_$cmd.so ";
1751         }
1752
1753         # and now reopen the commands makefile
1754         open(FH,">src/commands/Makefile") or die("Could not write src/commands/Makefile");
1755         print FH <<ITEM;
1756 CC = i am cornholio
1757 CXXFLAGS = -I../../include \${FLAGS}
1758
1759 all: $cmdobjs
1760
1761
1762 ITEM
1763
1764         # now print the command file details.
1765         foreach my $cmd (@cmdlist) {
1766                 print FH <<ITEM;
1767 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
1768         \@../../make/run-cc.pl \$(CC) -pipe -I../../include \$(FLAGS) -export-dynamic $SHARED -o cmd_$cmd.so cmd_$cmd.cpp
1769
1770 ITEM
1771         }
1772 }
1773
1774 # Routine to list out the extra/ modules that have been enabled.
1775 # Note: when getting any filenames out and comparing, it's important to lc it if the
1776 # file system is not case-sensitive (== Epoc, MacOS, OS/2 (incl DOS/DJGPP), VMS, Win32
1777 # (incl NetWare, Symbian)). Cygwin may or may not be case-sensitive, depending on
1778 # configuration, however, File::Spec does not currently tell us (it assumes Unix behavior).
1779 sub list_extras () {
1780         use File::Spec;
1781         # @_ not used
1782         my $srcdir = File::Spec->catdir("src", "modules");
1783         my $abs_srcdir = File::Spec->rel2abs($srcdir);
1784         local $_;
1785         my $dd;
1786         opendir $dd, File::Spec->catdir($abs_srcdir, "extra") or die (File::Spec->catdir($abs_srcdir, "extra") . ": $!\n");
1787         my @extras = map { File::Spec->case_tolerant() ? lc($_) : $_ } (readdir($dd));
1788         closedir $dd;
1789         undef $dd;
1790         opendir $dd, $abs_srcdir or die "$abs_srcdir: $!\n";
1791         my @sources = map { File::Spec->case_tolerant() ? lc($_) : $_ } (readdir($dd));
1792         closedir $dd;
1793         undef $dd;
1794         my $maxlen = (sort { $b <=> $a } (map {length($_)} (@extras)))[0];
1795         my %extras = ();
1796 EXTRA:  for my $extra (@extras) {
1797                 next if (File::Spec->curdir() eq $extra || File::Spec->updir() eq $extra);
1798                 next if ($extra eq '.svn');
1799                 my $abs_extra = File::Spec->catfile($abs_srcdir, "extra", $extra);
1800                 my $abs_source = File::Spec->catfile($abs_srcdir, $extra);
1801                 next unless ($extra =~ m/\.(cpp|h)$/ || (-d $abs_extra)); # C++ Source/Header, or directory
1802                 if (-l $abs_source) {
1803                         # Symlink, is it in the right place?
1804                         my $targ = readlink($abs_source);
1805                         my $abs_targ = File::Spec->rel2abs($targ, $abs_srcdir);
1806                         if ($abs_targ eq $abs_extra) {
1807                                 $extras{$extra} = "\e[32;1menabled\e[0m";
1808                         } else {
1809                                 $extras{$extra} = sprintf("\e[31;1mwrong symlink target (%s)\e[0m", $abs_targ);
1810                         }
1811                 } elsif (-e $abs_source) {
1812                         my ($devext, $inoext) = stat($abs_extra);
1813                         my ($devsrc, $inosrc, undef, $lnksrc) = stat($abs_source);
1814                         if ($lnksrc > 1) {
1815                                 if ($devsrc == $devext && $inosrc == $inoext) {
1816                                         $extras{$extra} = "\e[32;1menabled\e[0m";
1817                                 } else {
1818                                         $extras{$extra} = sprintf("\e[31;1mwrong hardlink target (%d:%d)\e[0m", $devsrc, $inosrc);
1819                                 }
1820                         } else {
1821                                 open my $extfd, "<", $abs_extra;
1822                                 open my $srcfd, "<", $abs_source;
1823                                 local $/ = undef;
1824                                 if (scalar(<$extfd>) eq scalar(<$srcfd>)) {
1825                                         $extras{$extra} = "\e[32;1menabled\e[0m";
1826                                 } else {
1827                                         $extras{$extra} = sprintf("\e[31;1mout of synch (re-copy)\e[0m");
1828                                 }
1829                         }
1830                 } else {
1831                         $extras{$extra} = "\e[33;1mdisabled\e[0m";
1832                 }
1833         }
1834         # Now let's add dependency info
1835         for my $extra (keys(%extras)) {
1836                 next unless $extras{$extra} =~ m/enabled/; # only process enabled extras.
1837                 my $abs_extra = File::Spec->catfile($abs_srcdir, "extra", $extra);
1838                 my @deps = split / +/, getdependencies($abs_extra);
1839                 for my $dep (@deps) {
1840                         if (exists($extras{$dep})) {
1841                                 my $ref = \$extras{$dep}; # Take reference.
1842                                 if ($$ref !~ m/needed by/) {
1843                                         # First dependency found.
1844                                         if ($$ref =~ m/enabled/) {
1845                                                 $$ref .= " (needed by \e[32;1m$extra\e[0m";
1846                                         } else {
1847                                                 $$ref =~ s/\e\[.*?m//g; # Strip out previous coloring. Will be set in bold+red+blink later.
1848                                                 $$ref .= " (needed by \e[0;32;1;5m$extra\e[0;31;1;5m";
1849                                         }
1850                                 } else {
1851                                         if ($$ref =~ m/enabled/) {
1852                                                 $$ref .= ", \e[32;1m$extra\e[0m";
1853                                         } else {
1854                                                 $$ref .= ", \e[0;32;1;5m$extra\e[0;31;1;5m";
1855                                         }
1856                                 }
1857                         }
1858                 }
1859         }
1860         for my $extra (sort {$a cmp $b} keys(%extras)) {
1861                 my $text = $extras{$extra};
1862                 if ($text =~ m/needed by/ && $text !~ m/enabled/) {
1863                         printf "\e[31;1;5m%-*s = %s%s\e[0m\n", $maxlen, $extra, $text, ($text =~ m/needed by/ ? ")" : "");
1864                 } else {
1865                         printf "%-*s = %s%s\n", $maxlen, $extra, $text, ($text =~ m/needed by/ ? "\e[0m)" : "");
1866                 }
1867         }
1868         return keys(%extras) if wantarray; # Can be used by manage_extras.
1869 }
1870
1871 sub enable_extras (@) {
1872         my (@extras) = @_;
1873         for my $extra (@extras) {
1874                 my $extrapath = "src/modules/extra/$extra";
1875                 if (!-e $extrapath) {
1876                         print STDERR "Cannot enable \e[32;1m$extra\e[0m : No such file or directory in src/modules/extra\n";
1877                         next;
1878                 }
1879                 my $source = "src/modules/$extra";
1880                 if (-e $source) {
1881                         print STDERR "Cannot enable \e[32;1m$extra\e[0m : destination in src/modules exists (might already be enabled?)\n";
1882                         next;
1883                 }
1884                 # Get dependencies, and add them to be processed.
1885                 my @deps = split / +/, getdependencies($extrapath);
1886                 for my $dep (@deps) {
1887                         next if scalar(grep { $_ eq $dep } (@extras)) > 0; # Skip if we're going to be enabling it anyway.
1888                         if (!-e "src/modules/$dep") {
1889                                 if (-e "src/modules/extra/$dep") {
1890                                         print STDERR "Will also enable extra \e[32;1m$dep\e[0m (needed by \e[32;1m$extra\e[0m)\n";
1891                                         push @extras, $dep;
1892                                 } else {
1893                                         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";
1894                                 }
1895                         }
1896                 }
1897                 print "Enabling $extra ... \n";
1898                 symlink "extra/$extra", $source or print STDERR "$source: Cannot link to 'extra/$extra': $!\n";
1899         }
1900 }
1901
1902 sub disable_extras (@)
1903 {
1904         opendir my $dd, "src/modules/extra/";
1905         my @files = readdir($dd);
1906         closedir $dd;
1907         my (@extras) = @_;
1908 EXTRA:  for my $extra (@extras) {
1909                 my $extrapath = "src/modules/extra/$extra";
1910                 my $source = "src/modules/$extra";
1911                 if (!-e $extrapath) {
1912                         print STDERR "Cannot disable \e[32;1m$extra\e[0m : Is not an extra\n";
1913                         next;
1914                 }
1915                 if ((! -l $source) || readlink($source) ne "extra/$extra") {
1916                         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";
1917                         next;
1918                 }
1919                 # Check if anything needs this.
1920                 for my $file (@files) {
1921                         my @deps = split / +/, getdependencies("src/modules/extra/$file");
1922                         # File depends on this extra...
1923                         if (scalar(grep { $_ eq $extra } @deps) > 0) {
1924                                 # And is both enabled and not about to be disabled.
1925                                 if (-e "src/modules/$file" && scalar(grep { $_ eq $file } @extras) < 1) {
1926                                         print STDERR "Cannot disable \e[32;1m$extra\e[0m : is needed by \e[32;1m$file\e[0m\n";
1927                                         next EXTRA;
1928                                 }
1929                         }
1930                 }
1931                 # Now remove.
1932                 print "Disabling $extra ... \n";
1933                 unlink "src/modules/$extra" or print STDERR "Cannot disable \e[32;1m$extra\e[0m : $!\n";
1934         }
1935 }