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