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