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