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