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