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