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