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