]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - configure
Win32ThreadEngine makes sense now. No gaurantees it compiles yet.
[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 note: for \e[1;32mSSL support\e[0m you will need to load required\n";
942         print "modules in your config. This configure script has added those modules to the\n";
943         print "build process. For more info please refer to:\n";
944         print "\e[1;32mhttp://www.inspircd.org/wiki/Installation_From_Tarball\e[0m\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         # Beware: Linux sets it's own cflags below for some retarded reason
1051         $config{LDLIBS} = "-pthread -lstdc++";
1052         $config{FLAGS}  = "-fPIC -Woverloaded-virtual -Wshadow -Wall $config{OPTIMISATI}";
1053         $config{DEVELOPER} = "-fPIC -Woverloaded-virtual -Wshadow -Wall -g";
1054         $SHARED = "-Wl,--rpath -Wl,$config{LIBRARY_DIR} -shared" unless defined $opt_disablerpath;
1055         $config{MAKEPROG} = "make";
1056
1057         if ($config{OSNAME} =~ /darwin/i) {
1058                 $config{FLAGS}  = "-DDARWIN -frtti -fPIC -Wall $config{OPTIMISATI}";
1059                 $SHARED = "-bundle -twolevel_namespace -undefined dynamic_lookup";
1060                 $config{LDLIBS} = "-ldl -pthread -lstdc++";
1061         }
1062
1063         if ($config{OSNAME} =~ /OpenBSD/i) {
1064                 $config{MAKEPROG} = "gmake";
1065                 $config{LDLIBS} = $config{LDLIBS} . " -lunwind";
1066                 chomp(my $foo = `eg++ -dumpversion | cut -c 1`);
1067                 # theyre running the package version of gcc (eg++)... detect it and set up its version numbers.
1068                 # if theyre not running this, configure lets the build continue but they probably wont manage to
1069                 # compile as this standard version is 2.95.3!
1070                 if ($foo ne "") {
1071                         $config{CC} = "eg++";
1072                         chomp($config{GCCVER}       = `eg++ -dumpversion | cut -c 1`); # we must redo these if we change the compiler path
1073                 }
1074                 return "OpenBSD";
1075         }
1076
1077         if ($config{OSNAME} =~ /Linux/i) {
1078                 $config{LDLIBS} = "-ldl -lstdc++ -pthread";
1079                 $config{FLAGS}  = "-fPIC -Woverloaded-virtual -Wshadow -Wall $config{OPTIMISATI}";
1080                 $config{FLAGS}  .= " " . $ENV{CXXFLAGS} if exists($ENV{CXXFLAGS});
1081                 $config{LDLIBS} .= " " . $ENV{LDLIBS} if exists($ENV{LDLIBS});
1082                 $config{MAKEPROG} = "make";
1083         }
1084
1085         if ($config{OSNAME} =~ /FreeBSD/i) {
1086                 $config{FLAGS}  .= " " . $ENV{CXXFLAGS} if exists($ENV{CXXFLAGS});
1087                 $config{LDLIBS} .= " " . $ENV{LDLIBS} if exists($ENV{LDLIBS});
1088         }
1089
1090         if ($config{OSNAME} =~ /SunOS/i or $config{OSNAME} =~ /solaris/i)
1091         {
1092                 # solaris/sunos needs these
1093                 # socket = bsd sockets api
1094                 # nsl = dns stuff
1095                 # rt = POSIX realtime extensions
1096                 # resolv = inet_aton only (why isnt this in nsl?!)
1097                 $config{MAKEPROG} = "gmake";
1098                 $config{LDLIBS} .= " -lsocket -lnsl -lrt -lresolv -pthread";
1099                 return "Solaris";
1100         }
1101         
1102         if($config{OSNAME} =~ /MINGW32/i)
1103         {
1104                 # All code is position-independent on windows
1105                 $config{FLAGS} =~ s/-fPIC //;
1106                 return "MinGW";
1107         }
1108
1109         return $config{OSNAME};
1110 }
1111
1112 my ($mliflags, $mfrules, $mobjs, $mfcount) = ("", "", "", 0);
1113
1114 sub writefiles {
1115         my($writeheader) = @_;
1116         my $se = "";
1117         # First File.. inspircd_config.h
1118         chomp(my $incos = `uname -n -s -r`);
1119         chomp(my $version = `sh src/version.sh`);
1120         chomp(my $revision2 = getrevision());
1121         if ($writeheader == 1)
1122         {
1123                 print "Writing \e[1;32minspircd_config.h\e[0m\n";
1124                 open(FILEHANDLE, ">include/inspircd_config.h");
1125                 my $NL = $config{NICK_LENGT}+1;
1126                 my $CL = $config{CHAN_LENGT}+1;
1127                 print FILEHANDLE <<EOF;
1128 /* Auto generated by configure, do not modify! */
1129 #ifndef __CONFIGURATION_AUTO__
1130 #define __CONFIGURATION_AUTO__
1131
1132 /* this is for windows support. */
1133 #define CoreExport /**/
1134 #define DllExport /**/
1135
1136 #define CONFIG_FILE "$config{CONFIG_DIR}/inspircd.conf"
1137 #define MOD_PATH "$config{MODULE_DIR}"
1138 #define VERSION "$version"
1139 #define REVISION "$revision2"
1140 #define MAXCLIENTS $config{MAX_CLIENT}
1141 #define MAXCLIENTS_S "$config{MAX_CLIENT}"
1142 #define SOMAXCONN_S "$config{_SOMAXCONN}"
1143 #define MAX_DESCRIPTORS $config{MAX_DESCRIPTORS}
1144 #define NICKMAX $NL
1145 #define CHANMAX $CL
1146 #define MAXMODES $config{MAXI_MODES}
1147 #define IDENTMAX $config{MAX_IDENT}
1148 #define MAXQUIT $config{MAX_QUIT}
1149 #define MAXTOPIC $config{MAX_TOPIC}
1150 #define MAXKICK $config{MAX_KICK}
1151 #define MAXGECOS $config{MAX_GECOS}
1152 #define MAXAWAY $config{MAX_AWAY}
1153 #define OPTIMISATION $config{OPTIMITEMP}
1154 #define LIBRARYDIR "$config{LIBRARY_DIR}"
1155 #define SYSTEM "$incos"
1156
1157 EOF
1158 print FILEHANDLE "#define MAXBUF " . ($config{MAXBUF}+2) . "\n";
1159
1160                 if ($config{OSNAME} =~ /SunOS/i) {
1161                         print FILEHANDLE "#define IS_SOLARIS\n";
1162                 }
1163                 if ($config{OSNAME} =~ /MINGW32/i) {
1164                         print FILEHANDLE "#define IS_MINGW\n";
1165                 }
1166                 if ($config{GCCVER} >= 3) {
1167                         print FILEHANDLE "#define GCC3\n";
1168                 }
1169                 if ($config{HAS_STRLCPY} eq "true") {
1170                         print FILEHANDLE "#define HAS_STRLCPY\n";
1171                 }
1172                 if ($config{HAS_STDINT} eq "true") {
1173                         print FILEHANDLE "#define HAS_STDINT\n";
1174                 }
1175                 if ($config{IPV6} =~ /y/i) {
1176                         print FILEHANDLE "#define IPV6\n";
1177                 }
1178                 if ($config{SUPPORT_IP6LINKS} =~ /y/i) {
1179                         print FILEHANDLE "#define SUPPORT_IP6LINKS\n";
1180                 }
1181                 my $use_hiperf = 0;
1182                 if (($has_kqueue) && ($config{USE_KQUEUE} eq "y")) {
1183                         print FILEHANDLE "#define USE_KQUEUE\n";
1184                         $se = "socketengine_kqueue";
1185                         $use_hiperf = 1;
1186                 }
1187                 if (($has_epoll) && ($config{USE_EPOLL} eq "y")) {
1188                         print FILEHANDLE "#define USE_EPOLL\n";
1189                         $se = "socketengine_epoll";
1190                         $use_hiperf = 1;
1191                 }
1192                 if (($has_ports) && ($config{USE_PORTS} eq "y")) {
1193                         print FILEHANDLE "#define USE_PORTS\n";
1194                         $se = "socketengine_ports";
1195                         $use_hiperf = 1;
1196                 }
1197                 # user didn't choose either epoll or select for their OS.
1198                 # default them to USE_SELECT (ewwy puke puke)
1199                 if (!$use_hiperf) {
1200                         print FILEHANDLE "#define USE_SELECT\n";
1201                         $se = "socketengine_select";
1202                 }
1203                 print FILEHANDLE "\n#include \"threadengines/threadengine_pthread.h\"\n\n#endif\n";
1204                 close(FILEHANDLE);
1205         }
1206
1207         if ($writeheader)
1208         {
1209                 open(FILEHANDLE, ">include/inspircd_se_config.h");
1210                 print FILEHANDLE <<EOF;
1211 /* Auto generated by configure, do not modify or commit to svn! */
1212 #ifndef __CONFIGURATION_SOCKETENGINE__
1213 #define __CONFIGURATION_SOCKETENGINE__
1214
1215 #include "socketengines/$se.h"
1216
1217 #endif
1218 EOF
1219                 close(FILEHANDLE);
1220         }
1221
1222
1223         # Create a Modules List..
1224         my $modules = "";
1225         foreach my $i (@modlist)
1226         {
1227                 $modules .= "m_".$i.".so ";
1228         }
1229         chomp($modules);   # Remove Redundant whitespace..
1230
1231         opendir(DIRHANDLE, "src/modules");
1232         foreach my $name (sort readdir(DIRHANDLE)) {
1233                 if ($name =~ /^m_(.+?)$/) {
1234                         if (defined(opendir(MDIRHANDLE, "src/modules/$name"))) {
1235                                 closedir(MDIRHANDLE);
1236                                 $modules .= "$name.so ";
1237                                 $uninstall_list = $uninstall_list . "   -rm \$(MODULES)/$name.so\n";
1238                         }
1239                 }
1240         }
1241         closedir(DIRHANDLE);
1242
1243
1244         # Write all .in files.
1245         my $tmp = "";
1246         my $file = "";
1247         my $exe = "inspircd";
1248
1249         # Do this once here, and cache it in the .*.inc files,
1250         # rather than attempting to read src/version.sh from
1251         # compiled code -- we might not have the source to hand.
1252         # Fix for bug#177 by Brain.
1253
1254         chomp($version = `sh ./src/version.sh`);
1255         chomp(my $revision = getrevision());
1256         $version = "$version(r$revision)";
1257
1258         # We can actually parse any file starting with . and ending with .inc,
1259         # but right now we only parse .inspircd.inc to form './inspircd'
1260
1261         print "Writing \e[1;32mMakefiles\e[0m\n";
1262         write_dynamic_modules_makefile();
1263         write_dynamic_makefile();
1264
1265         opendir(DIRHANDLE, $this);
1266
1267         foreach my $name (sort readdir(DIRHANDLE)) {
1268                 if ($name =~ /^\.(.+)\.inc$/) {
1269                         $file = $1;
1270
1271                         # Bug #353, omit this on non-darwin
1272                         next if (($config{OSNAME} !~ /darwin/) && ($file eq "org.inspircd.plist"));
1273
1274                         # All .name.inc files need parsing!
1275                         $tmp = "";
1276                         open(FILEHANDLE, ".$file.inc") or die ("Can't open .$file.inc");
1277                         while (<FILEHANDLE>) {
1278                                 $tmp .= $_;
1279                         }
1280                         close(FILEHANDLE);
1281
1282                         print "Writing \e[1;32m$file\e[0m ...\n";
1283                         $tmp =~ s/\@CC\@/$config{CC}/ if defined $config{CC};
1284                         $tmp =~ s/\@MAKEPROG\@/$config{MAKEPROG}/ if defined $config{MAKEPROG};
1285                         $tmp =~ s/\@FLAGS\@/$config{FLAGS}/ if defined $config{FLAGS};
1286                         $tmp =~ s/\@DEVELOPER\@/$config{DEVELOPER}/ if defined $config{DEVELOPER};
1287                         $tmp =~ s/\@LDLIBS\@/$config{LDLIBS}/ if defined $config{LDLIBS};
1288                         $tmp =~ s/\@BASE_DIR\@/$config{BASE_DIR}/ if defined $config{BASE_DIR};
1289                         $tmp =~ s/\@CONFIG_DIR\@/$config{CONFIG_DIR}/ if defined $config{CONFIG_DIR};
1290                         $tmp =~ s/\@MODULE_DIR\@/$config{MODULE_DIR}/ if defined $config{MODULE_DIR};
1291                         $tmp =~ s/\@BINARY_DIR\@/$config{BINARY_DIR}/ if defined $config{BINARY_DIR};
1292                         $tmp =~ s/\@LIBRARY_DIR\@/$config{LIBRARY_DIR}/ if defined $config{LIBRARY_DIR};
1293                         $tmp =~ s/\@MODULES\@/$modules/ if defined $modules;
1294                         $tmp =~ s/\@STARTSCRIPT\@/$config{STARTSCRIPT}/ if defined $config{STARTSCRIPT};
1295                         $tmp =~ s/\@DESTINATION\@/$config{DESTINATION}/ if defined $config{DESTINATION};
1296                         $tmp =~ s/\@EXTRA_DIR\@/$config{EXTRA_DIR}/ if defined $config{EXTRA_DIR};
1297                         $tmp =~ s/\@EXECUTABLE\@/$exe/ if defined $exe;
1298                         $tmp =~ s/\@MAKEORDER\@/$config{MAKEORDER}/ if defined $config{MAKEORDER};
1299                         $tmp =~ s/\@VERSION\@/$version/ if defined $version;
1300                         $tmp =~ s/\@INSTALL_LIST\@/$install_list/ if defined $install_list;
1301                         $tmp =~ s/\@UNINSTALL_LIST\@/$uninstall_list/ if defined $uninstall_list;
1302
1303                         open(FILEHANDLE, ">$file");
1304                         print FILEHANDLE $tmp;
1305                 }
1306         }
1307         closedir(DIRHANDLE);
1308
1309         # Make inspircd executable!
1310         chmod 0744, 'inspircd';
1311 }
1312
1313 sub write_dynamic_modules_makefile {
1314         # Modules Makefile..
1315         print "Writing \e[1;32msrc/modules/Makefile\e[0m\n";
1316         open(FILEHANDLE, ">src/modules/Makefile");
1317
1318 ###
1319 # Module Makefile Header
1320 ###
1321         print FILEHANDLE <<EOF;
1322 ###################################################
1323 # Copyright 2002-2007 The InspIRCd Development Team
1324 #  http://www.inspircd.org/wiki/index.php/Credits
1325 #
1326 # Thanks to Andrew Church <achurch\@achurch.org>
1327 #   for assisting with making this work right.
1328 #
1329 # Automatically Generated by ./configure to add a
1330 #  modules please run ./configure -modupdate
1331 ###################################################
1332
1333 all: \$(MODULES)
1334
1335 EOF
1336
1337 if ($config{OSNAME} =~ /darwin/) {
1338                 print FILEHANDLE <<EOCHEESE;
1339
1340 PICLDFLAGS = -twolevel_namespace -undefined dynamic_lookup -bundle
1341
1342 EOCHEESE
1343 } else {
1344                 print FILEHANDLE <<EOCHEESE;
1345
1346 PICLDFLAGS = -fPIC -DPIC -shared
1347
1348 EOCHEESE
1349 }
1350
1351         ###
1352         # End Module Makefile Header
1353         ###
1354
1355         # Create a Modules List..
1356         my $modules = "";
1357         my $cmflags = "";
1358         my $liflags = "";
1359         foreach my $i (@modlist) {
1360                 ###
1361                 # Write Entry to the MakeFile
1362                 ###
1363                 $cmflags = getcompilerflags("src/modules/m_".$i.".cpp");
1364                 $liflags = getlinkerflags("src/modules/m_".$i.".cpp");
1365                 my $deps = getdependencies("src/modules/m_".$i.".cpp");
1366         
1367                 #print "file: $i: cmflags=$cmflags; liflags=$liflags; deps=$deps\n";
1368         
1369
1370                 if (nopedantic("src/modules/m_".$i.".cpp"))
1371                 {
1372                         print FILEHANDLE "
1373 m_$i.so: m_$i.cpp ../../include/modules.h ../../include/users.h ../../include/channels.h ../../include/base.h ../../include/inspircd_config.h ../../include/inspircd.h ../../include/configreader.h $deps
1374         \@../../make/run-cc.pl \$(CC) -pipe -I../../include \$(NICEFLAGS) $cmflags \$(PICLDFLAGS) $liflags -export-dynamic -o m_$i.so m_$i.cpp
1375 "
1376                 }
1377                 else
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         \@../../make/run-cc.pl \$(CC) -pipe -I../../include \$(FLAGS) $cmflags \$(PICLDFLAGS) $liflags -export-dynamic -o m_$i.so m_$i.cpp
1382 ";
1383                 }
1384                 $install_list = $install_list . "       install -m \$(INSTMODE) src/modules/m_$i.so \$(MODPATH)\n";
1385                 $uninstall_list = $uninstall_list . "   -rm \$(MODULES)/m_$i.so\n";
1386 ###
1387                 # End Write Entry to the MakeFile
1388                 ###
1389         }
1390
1391         opendir(DIRHANDLE, "src/modules");
1392         foreach my $name (sort readdir(DIRHANDLE)) {
1393                 if ($name =~ /^m_(.+?)$/) {
1394                         $mfrules = "";
1395                         $mobjs = "";
1396                         $mliflags = "";
1397                         $mfcount = 0;
1398                         # A module made of multiple files, in a dir, e.g. src/modules/m_spanningtree/
1399                         if (defined(opendir(MDIRHANDLE, "src/modules/$name"))) {
1400                                 read_module_directory("src/modules/$name", $name);
1401                                 print "Composing Makefile rules for directory \e[1;32m$name\e[0m... (\e[1;32m$mfcount files found\e[0m)\n";
1402                                 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"; 
1403                                 if ($config{IS_DARWIN} eq "YES") {
1404                                         print FILEHANDLE "      \@../../make/run-cc.pl \$(CC) -pipe -twolevel_namespace -undefined dynamic_lookup \$(FLAGS) $mliflags -bundle -o $name.so $mobjs\n"; 
1405                                 } else {
1406                                         print FILEHANDLE "      \@../../make/run-cc.pl \$(CC) -pipe \$(FLAGS) -shared $mliflags -o $name.so $mobjs\n";
1407                                 }
1408                                 print FILEHANDLE "\n$mfrules\n";
1409                                 closedir(MDIRHANDLE);
1410                                 $install_list = $install_list . "       install -m \$(INSTMODE) src/modules/$name.so \$(MODPATH)\n";
1411                         }
1412                 }
1413         }
1414         closedir(DIRHANDLE);
1415 }
1416
1417 sub read_module_directory {
1418         my ($dpath, $reldpath) = @_;
1419         
1420         if (opendir(MDIRHANDLE, $dpath) == 0) {
1421                 return;
1422         }
1423         
1424         foreach my $fname (sort readdir(MDIRHANDLE)) {
1425                 if ($fname =~ /\.cpp$/) {
1426                         my $cmflags = getcompilerflags("$dpath/$fname");
1427                         $mliflags = $mliflags . " " . getlinkerflags("$dpath/$fname");
1428                         my $deps = getdependencies("$dpath/$fname");
1429                         my $oname = $fname;
1430                         $oname =~ s/\.cpp$/.o/g;
1431                         $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";
1432                         $mfrules = $mfrules .  "        \@../../make/run-cc.pl \$(CC) -pipe -I../../include -I. \$(FLAGS) $cmflags -export-dynamic -o $reldpath/$oname -c $reldpath/$fname\n\n";
1433                         $mobjs = $mobjs . " $reldpath/$oname";
1434                         $mfcount++;
1435                 }
1436                 elsif ((-d "$dpath/$fname") && !($fname eq ".") && !($fname eq "..")) {
1437                         read_module_directory($dpath."/".$fname, $reldpath."/".$fname);
1438                 }
1439         }
1440 }
1441
1442 sub calcdeps($)
1443 {
1444         # Yes i know we could use gcc -M but it seems to ideneify a lot of 'deep'
1445         # dependencies which are not relevent in C++.
1446
1447         my $file = $_[0];
1448
1449         open (CPP, "<$file") or die("Can't open $file for reading!");
1450
1451         my %dupe = ();
1452         my $retlist = "";
1453
1454         foreach my $d (@ignoredeps)
1455         {
1456                 $dupe{$d} = 1;
1457         }
1458
1459         my $immutable = "";
1460         foreach my $dep (@immutabledeps)
1461         {
1462                 $immutable = $immutable . "../include/$dep ";
1463         }
1464         $immutable =~ s/ $//g;
1465
1466         while (defined(my $line = <CPP>))
1467         {
1468                 chomp($line);
1469                 if ($line =~ /#include "(.+\.h)"/)
1470                 {
1471                         if (!exists($dupe{$1}))
1472                         {
1473                                 $retlist = $retlist . "../include/$1 ";
1474                                 $dupe{$1} = 1;
1475                         }
1476                 }
1477         }
1478         close CPP;
1479         return length($immutable) ? $immutable . " " . $retlist : $retlist;
1480 }
1481
1482 sub write_dynamic_makefile
1483 {
1484         my $i = 0;
1485         my @cmdlist = ();
1486         my %existing_install_list = ();
1487         opendir(DIRHANDLE, "src/commands");
1488         foreach my $name (sort readdir(DIRHANDLE))
1489         {
1490                 if ($name =~ /^cmd_(.+)\.cpp$/)
1491                 {
1492                         $cmdlist[$i++] = $1;
1493                         $install_list = $install_list . "       -install -m \$(INSTMODE) src/commands/cmd_" . $1 . ".so \$(LIBPATH)\n";
1494                         $uninstall_list = $uninstall_list . "   -rm \$(LIBPATH)/cmd_$1.so\n";
1495                 }
1496         }
1497         closedir(DIRHANDLE);
1498
1499         if (!$has_epoll)
1500         {
1501                 $config{USE_EPOLL} = 0;
1502         }
1503         if (!$has_kqueue)
1504         {
1505                 $config{USE_KQUEUE} = 0;
1506         }
1507         if (!$has_ports)
1508         {
1509                 $config{USE_PORTS} = 0;
1510         }
1511
1512         foreach my $dir (("src","src/commands","src/modes","src/socketengines","src/modules"))
1513         {
1514                 print "Scanning \e[1;32m$dir\e[0m for core files ";
1515                 opendir(DIRHANDLE, $dir);
1516                 foreach my $name (sort readdir(DIRHANDLE))
1517                 {
1518                         if ($name =~ /\.cpp$/)
1519                         {
1520                                 open (CPP, "<$dir/$name") or die("Can't open $dir/$name to scan it! oh bugger");
1521                                 print ".";
1522                                 while (defined(my $line = <CPP>))
1523                                 {
1524                                         chomp($line);
1525                                         if ($line =~ /\/\* \$Core: (\w+) \*\//i)
1526                                         {
1527                                                 $filelist{$name} = $1;
1528                                         }
1529                                         elsif ($line =~ /\/\* \$ExtraDeps: (.*?) \*\//i)
1530                                         {
1531                                                 $specialdeps{$name} = $1;
1532                                         }
1533                                         elsif ($line =~ /\/\* \$ExtraObjects: (.*?) \*\//i)
1534                                         {
1535                                                 $extraobjects{$name} = $1;
1536                                         }
1537                                         elsif ($line =~ /\/\* \$ExtraBuild: (.*?) \*\//i)
1538                                         {
1539                                                 $extrabuildlines{$name} = $1;
1540                                         }
1541                                         elsif ($line =~ /\/\* \$ExtraSources: (.*?) \*\//i)
1542                                         {
1543                                                 $extrasources{$name} = $1;
1544                                                 }
1545                                         elsif ($line =~ /\/\* \$If: (\w+) \*\//i)
1546                                         {
1547                                                 if (defined $config{$1})
1548                                                 {
1549                                                         if (($config{$1} !~ /y/i) and ($config{$1} ne "1"))
1550                                                         {
1551                                                                 # Skip to 'endif'
1552                                                                 while (defined($line = <CPP>))
1553                                                                 {
1554                                                                         chomp($line);
1555                                                                         die ("\$If buildsystem instruction within another \$If in file $dir/$name") if ($line =~ /\/\* \$If: (\w+) \*\//i);
1556                                                                         last if ($line =~ /\/\* \$EndIf \*\//i);
1557                                                                 }
1558                                                         }
1559                                                 }
1560                                         }
1561                                         elsif ($line =~ /\/\* \$Install: (.*?) \*\//i)
1562                                         {
1563                                                 if (!exists($existing_install_list{$1}))
1564                                                 {
1565                                                         $existing_install_list{$1} = 1;
1566                                                         my $idir = (split(' ',$1))[1];
1567                                                         my $ifile = (split(' ',$1))[0];
1568                                                         $install_list = $install_list . "       -install -m \$(INSTMODE) $1\n";
1569                                                         $ifile =~ s/.*\///g;
1570                                                         $uninstall_list = $uninstall_list . "   -rm $idir/$ifile\n";
1571                                                 }
1572                                         }
1573                                         elsif ($line =~ /\/\* \$CopyInstall: (.*?) \*\//i)
1574                                         {
1575                                                 if (!exists($existing_install_list{$1}))
1576                                                 {
1577                                                         $existing_install_list{$1} = 1;
1578                                                         my $idir = (split(' ',$1))[1];
1579                                                         my $ifile = (split(' ',$1))[0];
1580                                                         $install_list = $install_list . "       -cp $1\n";
1581                                                         $ifile =~ s/.*\///g;
1582                                                         $uninstall_list = $uninstall_list . "   -rm $idir/$ifile\n";
1583                                                 }
1584                                         }
1585                                 }
1586                                 close CPP;
1587                         }
1588                 }
1589                 closedir(DIRHANDLE);
1590                 print " done!\n";
1591         }
1592
1593         my $freebsd4libs = (defined $config{CRAQ} ? $config{CRAQ} : "");
1594
1595         my $all = "all: ";
1596         my $all_libsonly = "";
1597
1598         my $libraryext = "";
1599         my $othercrap = "";
1600         my $RPATH = "";
1601
1602         if ($config{IS_DARWIN} eq "YES")
1603         {
1604                 $libraryext = "dylib";
1605                 $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 "
1606         }
1607         else
1608         {
1609                 $libraryext = "so";
1610                 $RPATH = "-Wl,--rpath -Wl,$config{LIBRARY_DIR}" unless defined $opt_disablerpath;
1611                 $othercrap = "  \@../make/run-cc.pl \$(CC) -pipe -I../include $RPATH \$(FLAGS) $freebsd4libs -rdynamic -L. inspircd.cpp -o inspircd \$(LDLIBS) ";
1612         }
1613
1614         foreach my $cpp (sort keys %filelist)
1615         {
1616                 $all = $all . $filelist{$cpp} . "." . $libraryext . " ";
1617                 $all_libsonly = $all_libsonly . $filelist{$cpp} . "." . $libraryext . " ";
1618                 $install_list = $install_list . "       -install -m \$(INSTMODE) src/" . $filelist{$cpp} . "." . $libraryext . " \$(LIBPATH)\n";
1619                 $uninstall_list = $uninstall_list . "   -rm \$(LIBPATH)/" . $filelist{$cpp} . "." . $libraryext . "\n";
1620         }
1621         $all = $all . "moo inspircd\n";
1622
1623         $othercrap = $othercrap . " $all_libsonly\n\n";
1624
1625         open(FH,">src/Makefile") or die("Could not write src/Makefile");
1626         print FH <<EOM;
1627
1628 CC = im a cheezeball
1629 CXXFLAGS = -I../include \${FLAGS}
1630 CPPFILES = \$(shell /bin/ls -l modes/ | grep '\\.cpp' | sed 's/^.* //' | grep -v svn)
1631 RELCPPFILES = \$(shell /bin/ls -l modes/ | grep '\\.cpp' | sed 's/^.* /modes\\//' | grep -v svn)
1632
1633 EOM
1634
1635         print FH "$all\n\n";
1636
1637         my $deps = calcdeps("src/inspircd.cpp");
1638         print FH "inspircd: inspircd.cpp $deps $all_libsonly\n";
1639         print FH "$othercrap\n";
1640
1641         foreach my $cpp (sort keys %filelist)
1642         {
1643                 my $thislib = $filelist{$cpp} . "." . $libraryext; 
1644                 my $objs = $cpp;
1645                 my $rawcpp = $cpp;
1646                 my $libcrap = "";
1647                 $objs =~ s/\.cpp$/.o/;
1648                 if (exists($extraobjects{$cpp}))
1649                 {
1650                         $objs = $objs . " " . $extraobjects{$cpp};
1651                 }
1652                 if (exists($extrasources{$cpp}))
1653                 {
1654                         $rawcpp = $rawcpp . " " . $extrasources{$cpp};
1655                 }
1656                 if ($config{IS_DARWIN} eq "YES")
1657                 {
1658                         $libcrap = "-install_name " . $config{LIBRARY_DIR} . "/" . $thislib . " -dynamiclib -twolevel_namespace -undefined dynamic_lookup";
1659                 }
1660                 else
1661                 {
1662                         if (defined $opt_disablerpath)
1663                         {
1664                                 $libcrap = " -shared";
1665                         }
1666                         else
1667                         {
1668                                 $libcrap = "-Wl,--rpath -Wl," . $config{LIBRARY_DIR} . " -shared";
1669                         }
1670                 }
1671                 $deps = calcdeps("src/$cpp");
1672                 if (exists($extrasources{$cpp}))
1673                 {
1674                         foreach my $seperate (sort split(' ',$extrasources{$cpp}))
1675                         {
1676                                 my $d = calcdeps("src/$extrasources{$cpp}") . " ";
1677                                 if ($d ne "")
1678                                 {
1679                                         $deps = $deps . $d . " ";
1680                                 }
1681                         }
1682                 }
1683                 print FH $thislib . ": $cpp $deps ". (defined($specialdeps{$cpp}) ? $specialdeps{$cpp} : "") . "\n";
1684                 print FH "      \@../make/run-cc.pl \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c $rawcpp\n";
1685                 if (exists($extrabuildlines{$cpp}))
1686                 {
1687                         print FH "      " . $extrabuildlines{$cpp} . "\n";
1688                 }
1689                 print FH "      \@../make/run-cc.pl \$(CC) -pipe $libcrap -o " . $thislib . " " . $objs . "\n\n";
1690         }
1691
1692         print FH "moo:\n        \@\${MAKE} -C \"commands\" DIRNAME=\"src/commands\" CC=\"\$(CC)\" \$(MAKEARGS)\n\n";
1693
1694         # close main makefile
1695         close(FH);
1696
1697         my $cmdobjs = "";
1698         # generate a list of .so
1699         foreach my $cmd (@cmdlist) {
1700                 $cmdobjs = $cmdobjs . "cmd_$cmd.so ";
1701         }
1702
1703         # and now reopen the commands makefile
1704         open(FH,">src/commands/Makefile") or die("Could not write src/commands/Makefile");
1705         print FH <<ITEM;
1706 CC = i am cornholio
1707 CXXFLAGS = -I../../include \${FLAGS}
1708
1709 all: $cmdobjs
1710
1711
1712 ITEM
1713
1714         # now print the command file details.
1715         foreach my $cmd (@cmdlist) {
1716                 print FH <<ITEM;
1717 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
1718         \@../../make/run-cc.pl \$(CC) -pipe -I../../include \$(FLAGS) -export-dynamic -c cmd_$cmd.cpp
1719         \@../../make/run-cc.pl \$(CC) -pipe $SHARED -o cmd_$cmd.so cmd_$cmd.o
1720
1721 ITEM
1722         }
1723 #try build a .so, no intermediate .o
1724 #       @../../make/run-cc.pl \$(CC) -pipe -I../../include \$(FLAGS) -export-dynamic $SHARED -o cmd_$cmd.so
1725
1726 #this works for sure
1727 #       @../../make/run-cc.pl \$(CC) -pipe -I../../include \$(FLAGS) -export-dynamic -c cmd_$cmd.cpp
1728 #       @../../make/run-cc.pl \$(CC) -pipe $SHARED -o cmd_$cmd.so cmd_$cmd.o
1729 }
1730
1731 # Routine to list out the extra/ modules that have been enabled.
1732 # Note: when getting any filenames out and comparing, it's important to lc it if the
1733 # file system is not case-sensitive (== Epoc, MacOS, OS/2 (incl DOS/DJGPP), VMS, Win32
1734 # (incl NetWare, Symbian)). Cygwin may or may not be case-sensitive, depending on
1735 # configuration, however, File::Spec does not currently tell us (it assumes Unix behavior).
1736 sub list_extras () {
1737         use File::Spec;
1738         # @_ not used
1739         my $srcdir = File::Spec->catdir("src", "modules");
1740         my $abs_srcdir = File::Spec->rel2abs($srcdir);
1741         local $_;
1742         my $dd;
1743         opendir $dd, File::Spec->catdir($abs_srcdir, "extra") or die (File::Spec->catdir($abs_srcdir, "extra") . ": $!\n");
1744         my @extras = map { File::Spec->case_tolerant() ? lc($_) : $_ } (readdir($dd));
1745         closedir $dd;
1746         undef $dd;
1747         opendir $dd, $abs_srcdir or die "$abs_srcdir: $!\n";
1748         my @sources = map { File::Spec->case_tolerant() ? lc($_) : $_ } (readdir($dd));
1749         closedir $dd;
1750         undef $dd;
1751         my $maxlen = (sort { $b <=> $a } (map {length($_)} (@extras)))[0];
1752         my %extras = ();
1753 EXTRA:  for my $extra (@extras) {
1754                 next if (File::Spec->curdir() eq $extra || File::Spec->updir() eq $extra);
1755                 next if ($extra eq '.svn');
1756                 my $abs_extra = File::Spec->catfile($abs_srcdir, "extra", $extra);
1757                 my $abs_source = File::Spec->catfile($abs_srcdir, $extra);
1758                 next unless ($extra =~ m/\.(cpp|h)$/ || (-d $abs_extra)); # C++ Source/Header, or directory
1759                 if (-l $abs_source) {
1760                         # Symlink, is it in the right place?
1761                         my $targ = readlink($abs_source);
1762                         my $abs_targ = File::Spec->rel2abs($targ, $abs_srcdir);
1763                         if ($abs_targ eq $abs_extra) {
1764                                 $extras{$extra} = "\e[32;1menabled\e[0m";
1765                         } else {
1766                                 $extras{$extra} = sprintf("\e[31;1mwrong symlink target (%s)\e[0m", $abs_targ);
1767                         }
1768                 } elsif (-e $abs_source) {
1769                         my ($devext, $inoext) = stat($abs_extra);
1770                         my ($devsrc, $inosrc, undef, $lnksrc) = stat($abs_source);
1771                         if ($lnksrc > 1) {
1772                                 if ($devsrc == $devext && $inosrc == $inoext) {
1773                                         $extras{$extra} = "\e[32;1menabled\e[0m";
1774                                 } else {
1775                                         $extras{$extra} = sprintf("\e[31;1mwrong hardlink target (%d:%d)\e[0m", $devsrc, $inosrc);
1776                                 }
1777                         } else {
1778                                 open my $extfd, "<", $abs_extra;
1779                                 open my $srcfd, "<", $abs_source;
1780                                 local $/ = undef;
1781                                 if (scalar(<$extfd>) eq scalar(<$srcfd>)) {
1782                                         $extras{$extra} = "\e[32;1menabled\e[0m";
1783                                 } else {
1784                                         $extras{$extra} = sprintf("\e[31;1mout of synch (re-copy)\e[0m");
1785                                 }
1786                         }
1787                 } else {
1788                         $extras{$extra} = "\e[33;1mdisabled\e[0m";
1789                 }
1790         }
1791         # Now let's add dependency info
1792         for my $extra (keys(%extras)) {
1793                 next unless $extras{$extra} =~ m/enabled/; # only process enabled extras.
1794                 my $abs_extra = File::Spec->catfile($abs_srcdir, "extra", $extra);
1795                 my @deps = split / +/, getdependencies($abs_extra);
1796                 for my $dep (@deps) {
1797                         if (exists($extras{$dep})) {
1798                                 my $ref = \$extras{$dep}; # Take reference.
1799                                 if ($$ref !~ m/needed by/) {
1800                                         # First dependency found.
1801                                         if ($$ref =~ m/enabled/) {
1802                                                 $$ref .= " (needed by \e[32;1m$extra\e[0m";
1803                                         } else {
1804                                                 $$ref =~ s/\e\[.*?m//g; # Strip out previous coloring. Will be set in bold+red+blink later.
1805                                                 $$ref .= " (needed by \e[0;32;1;5m$extra\e[0;31;1;5m";
1806                                         }
1807                                 } else {
1808                                         if ($$ref =~ m/enabled/) {
1809                                                 $$ref .= ", \e[32;1m$extra\e[0m";
1810                                         } else {
1811                                                 $$ref .= ", \e[0;32;1;5m$extra\e[0;31;1;5m";
1812                                         }
1813                                 }
1814                         }
1815                 }
1816         }
1817         for my $extra (sort {$a cmp $b} keys(%extras)) {
1818                 my $text = $extras{$extra};
1819                 if ($text =~ m/needed by/ && $text !~ m/enabled/) {
1820                         printf "\e[31;1;5m%-*s = %s%s\e[0m\n", $maxlen, $extra, $text, ($text =~ m/needed by/ ? ")" : "");
1821                 } else {
1822                         printf "%-*s = %s%s\n", $maxlen, $extra, $text, ($text =~ m/needed by/ ? "\e[0m)" : "");
1823                 }
1824         }
1825         return keys(%extras) if wantarray; # Can be used by manage_extras.
1826 }
1827
1828 sub enable_extras (@) {
1829         my (@extras) = @_;
1830         for my $extra (@extras) {
1831                 my $extrapath = "src/modules/extra/$extra";
1832                 if (!-e $extrapath) {
1833                         print STDERR "Cannot enable \e[32;1m$extra\e[0m : No such file or directory in src/modules/extra\n";
1834                         next;
1835                 }
1836                 my $source = "src/modules/$extra";
1837                 if (-e $source) {
1838                         print STDERR "Cannot enable \e[32;1m$extra\e[0m : destination in src/modules exists (might already be enabled?)\n";
1839                         next;
1840                 }
1841                 # Get dependencies, and add them to be processed.
1842                 my @deps = split / +/, getdependencies($extrapath);
1843                 for my $dep (@deps) {
1844                         next if scalar(grep { $_ eq $dep } (@extras)) > 0; # Skip if we're going to be enabling it anyway.
1845                         if (!-e "src/modules/$dep") {
1846                                 if (-e "src/modules/extra/$dep") {
1847                                         print STDERR "Will also enable extra \e[32;1m$dep\e[0m (needed by \e[32;1m$extra\e[0m)\n";
1848                                         push @extras, $dep;
1849                                 } else {
1850                                         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";
1851                                 }
1852                         }
1853                 }
1854                 print "Enabling $extra ... \n";
1855                 symlink "extra/$extra", $source or print STDERR "$source: Cannot link to 'extra/$extra': $!\n";
1856         }
1857 }
1858
1859 sub disable_extras (@)
1860 {
1861         opendir my $dd, "src/modules/extra/";
1862         my @files = readdir($dd);
1863         closedir $dd;
1864         my (@extras) = @_;
1865 EXTRA:  for my $extra (@extras) {
1866                 my $extrapath = "src/modules/extra/$extra";
1867                 my $source = "src/modules/$extra";
1868                 if (!-e $extrapath) {
1869                         print STDERR "Cannot disable \e[32;1m$extra\e[0m : Is not an extra\n";
1870                         next;
1871                 }
1872                 if ((! -l $source) || readlink($source) ne "extra/$extra") {
1873                         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";
1874                         next;
1875                 }
1876                 # Check if anything needs this.
1877                 for my $file (@files) {
1878                         my @deps = split / +/, getdependencies("src/modules/extra/$file");
1879                         # File depends on this extra...
1880                         if (scalar(grep { $_ eq $extra } @deps) > 0) {
1881                                 # And is both enabled and not about to be disabled.
1882                                 if (-e "src/modules/$file" && scalar(grep { $_ eq $file } @extras) < 1) {
1883                                         print STDERR "Cannot disable \e[32;1m$extra\e[0m : is needed by \e[32;1m$file\e[0m\n";
1884                                         next EXTRA;
1885                                 }
1886                         }
1887                 }
1888                 # Now remove.
1889                 print "Disabling $extra ... \n";
1890                 unlink "src/modules/$extra" or print STDERR "Cannot disable \e[32;1m$extra\e[0m : $!\n";
1891         }
1892 }