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