]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - configure
Makefile updates: Fix BSD make conditionals
[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}   = `libgnutls-config --version 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 if ($config{USE_GNUTLS} eq "y") {
874         unless (-r "src/modules/m_ssl_gnutls.cpp") {
875                 print "Symlinking src/modules/m_ssl_gnutls.cpp from extra/\n";
876                 symlink "extra/m_ssl_gnutls.cpp", "src/modules/m_ssl_gnutls.cpp" or print STDERR "Symlink failed: $!";
877         }
878         getmodules();
879         if ($interactive)
880         {
881                 unless (-r "$config{CONFIG_DIR}/key.pem" && -r "$config{CONFIG_DIR}/cert.pem") {
882                         print "SSL Certificates Not found, Generating.. \n\n
883 *************************************************************
884 * Generating the Private Key may take some time, go grab a  *
885 * Coffee. Even better, to generate some more entropy if it  *
886 * is taking a while, open another console and type du / a   *
887 * few times and get that HD going :) Then answer the        *
888 * Questions which follow. If you are unsure, just hit enter *
889 *************************************************************\n\n";
890                         $failed = make_gnutls_cert();
891                         if ($failed) {
892                                 print "\n\e[1;32mCertificate generation failed!\e[0m\n\n";
893                         } else {
894                                 print "\nCertificate generation complete, copying to config directory... ";
895                                 File::Copy::move("key.pem", "$config{CONFIG_DIR}/key.pem") or print STDERR "Could not copy key.pem!\n";
896                                 File::Copy::move("cert.pem", "$config{CONFIG_DIR}/cert.pem") or print STDERR "Could not copy cert.pem!\n";
897                                 print "Done.\n\n";
898                         }
899                 }
900                 else {
901                         print "SSL Certificates found, skipping.\n\n";
902                 }
903         }
904         else
905         {
906                 print "Skipping SSL certificate generation\nin non-interactive mode.\n\n";
907         }
908 } elsif ($config{USE_OPENSSL} eq "y") {
909         unless (-r "src/modules/m_ssl_openssl.cpp") {
910                 print "Symlinking src/modules/m_ssl_openssl.cpp from extra/\n";
911                 symlink "extra/m_ssl_openssl.cpp", "src/modules/m_ssl_openssl.cpp" or print STDERR "Symlink failed: $!";
912         }
913         getmodules();
914         $failed = 0;
915         if ($interactive)
916         {
917                 unless (-r "$config{CONFIG_DIR}/key.pem" && -r "$config{CONFIG_DIR}/cert.pem") {
918                         print "SSL Certificates Not found, Generating.. \n\n
919 *************************************************************
920 * Generating the certificates may take some time, go grab a *
921 * coffee, or something.                                     *
922 *************************************************************\n\n";
923                         make_openssl_cert();
924                         print "\nCertificate generation complete, copying to config directory... ";
925                         File::Copy::move("key.pem", "$config{CONFIG_DIR}/key.pem") or print STDERR "Could not copy key.pem!\n";
926                         File::Copy::move("cert.pem", "$config{CONFIG_DIR}/cert.pem") or print STDERR "Could not copy cert.pem!\n";
927                         File::Copy::move("dhparams.pem", "$config{CONFIG_DIR}/dhparams.pem") or print STDERR "Could not copy dhparams.pem!\n";
928                         print "Done.\n\n";
929                 } else {
930                         print "SSL Certificates found, skipping.\n\n"
931                 }
932         }
933         else
934         {
935                 print "Skipping SSL certificate generation\nin non-interactive mode.\n\n";
936         }
937 }
938 if (($config{USE_GNUTLS} eq "n") && ($config{USE_OPENSSL} eq "n")) {
939         print "Skipping SSL Certificate generation, SSL support is not available.\n\n";
940 }
941
942 getosflags();
943 writefiles(1);
944 makecache();
945
946 print "\n\n";
947 print "To build your server with these settings, please type '\e[1;32m$config{MAKEPROG}\e[0m' now.\n";
948 if (($config{USE_GNUTLS} eq "y") || ($config{USE_OPENSSL} eq "y")) {
949         print "Please note: for \e[1;32mSSL support\e[0m you will need to load required\n";
950         print "modules in your config. This configure script has added those modules to the\n";
951         print "build process. For more info please refer to:\n";
952         print "\e[1;32mhttp://wiki.inspircd.org/Installation_From_Tarball\e[0m\n";
953 }
954 print "*** \e[1;32mRemember to edit your configuration files!!!\e[0m ***\n\n\n";
955 if (($config{OSNAME} eq "OpenBSD") && ($config{CC} ne "eg++")) {
956         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";
957 }
958
959 if ($config{GCCVER} < "3") {
960         print <<FOO2;
961 \e[1;32mWARNING!\e[0m You are attempting to compile InspIRCd on GCC 2.x!
962 GCC 2.x series compilers only had partial (read as broken) C++ support, and
963 your compile will most likely fail horribly! If you have any problems, do NOT
964 report them to the bugtracker or forums without first upgrading your compiler
965 to a newer 3.x or 4.x (or whatever is available currently) version.
966 FOO2
967 }
968
969 ################################################################################
970 #                             HELPER FUNCTIONS                          #
971 ################################################################################
972 sub getcache {
973         # Retrieves the .config.cache file, and loads values into the main config hash.
974         open(CACHE, ".config.cache") or return 0;
975         while (<CACHE>) {
976                 chomp;
977                 # Ignore Blank lines, and comments..
978                 next if /^\s*$/;
979                 next if /^\s*#/;
980                 my ($key, $value) = split("=", $_, 2);
981                 $value =~ /^\"(.*)\"$/;
982                 # Do something with data here!
983                 $config{$key} = $1;
984         }
985         close(CACHE);
986         return 1;
987 }
988
989 sub makecache {
990         # Dump the contents of %config
991         print "Writing \e[1;32mcache file\e[0m for future ./configures ...\n";
992         open(FILEHANDLE, ">.config.cache");
993         foreach my $key (keys %config) {
994                 print FILEHANDLE "$key=\"$config{$key}\"\n";
995         }
996         close(FILEHANDLE);
997 }
998
999 sub dir_check {
1000         my ($desc, $hash_key) = @_;
1001         my $complete = 0;
1002         while (!$complete) {
1003                 print "In what directory $desc?\n";
1004                 print "[\e[1;32m$config{$hash_key}\e[0m] -> ";
1005                 chomp(my $var = <STDIN>);
1006                 if ($var eq "") {
1007                         $var = $config{$hash_key};
1008                 }
1009                 if ($var =~ /^\~\/(.+)$/) {
1010                         # Convert it to a full path..
1011                         $var = resolve_directory($ENV{HOME} . "/" . $1);
1012                 }
1013                 elsif ((($config{OSNAME} =~ /MINGW32/i) and ($var !~ /^[A-Z]{1}:\\.*/)) and (substr($var,0,1) ne "/"))
1014                 {
1015                         # Assume relative Path was given.. fill in the rest.
1016                         $var = $this . "/$var";
1017                 }
1018
1019                 $var = resolve_directory($var);
1020                 if (! -e $var) {
1021                         print "$var does not exist. Create it?\n[\e[1;32my\e[0m] ";
1022                         chomp(my $tmp = <STDIN>);
1023                         if (($tmp eq "") || ($tmp =~ /^y/i)) {
1024                                 # Attempt to Create the Dir..
1025                                 my $chk = eval {
1026                                         use File::Path ();
1027                                         File::Path::mkpath($var, 0, 0777);
1028                                         1;
1029                                 };
1030                                 unless (defined($chk) && -d $var) {
1031                                         print "Unable to create directory. ($var)\n\n";
1032                                         # Restart Loop..
1033                                         next;
1034                                 }
1035                         } else {
1036                                 # They said they don't want to create, and we can't install there.
1037                                 print "\n\n";
1038                                 next;
1039                         }
1040                 } else {
1041                         if (!is_dir($var)) {
1042                                 # Target exists, but is not a directory.
1043                                 print "File $var exists, but is not a directory.\n\n";
1044                                 next;
1045                         }
1046                 }
1047                 # Either Dir Exists, or was created fine.
1048                 $config{$hash_key} = $var;
1049                 $complete = 1;
1050                 print "\n";
1051         }
1052 }
1053
1054 our $SHARED = "";
1055
1056 sub getosflags {
1057
1058         # Beware: Linux sets it's own cflags below for some retarded reason
1059         $config{LDLIBS} = "-pthread -lstdc++";
1060         $config{FLAGS}  = "-pipe -fPIC -Woverloaded-virtual -Wshadow -Wformat=2 -Wmissing-format-attribute -Wall $config{OPTIMISATI}";
1061         $config{DEVELOPER} = "-pipe -fPIC -Woverloaded-virtual -Wshadow -Wall -Wformat=2 -Wmissing-format-attribute -g";
1062         $SHARED = "-shared -export-dynamic";
1063         $config{MAKEPROG} = "make";
1064
1065         if ($config{OSNAME} =~ /darwin/i) {
1066                 $config{FLAGS}  = "-pipe -DDARWIN -frtti -fPIC -Wall $config{OPTIMISATI}";
1067                 $SHARED = "-bundle -twolevel_namespace -undefined dynamic_lookup";
1068                 $config{LDLIBS} = "-ldl -pthread -lstdc++";
1069         }
1070
1071         if ($config{OSNAME} =~ /OpenBSD/i) {
1072                 $config{MAKEPROG} = "gmake";
1073 # apparantly (Dagonet says) that this causes problems, so let's try without it.
1074 #               $config{LDLIBS} = $config{LDLIBS} . " -lunwind";
1075                 chomp(my $foo = `eg++ -dumpversion | cut -c 1`);
1076                 # theyre running the package version of gcc (eg++)... detect it and set up its version numbers.
1077                 # if theyre not running this, configure lets the build continue but they probably wont manage to
1078                 # compile as this standard version is 2.95.3!
1079                 if ($foo ne "") {
1080                         $config{CC} = "eg++";
1081                         chomp($config{GCCVER}       = `eg++ -dumpversion | cut -c 1`); # we must redo these if we change the compiler path
1082                         chomp($config{GCCMINOR}     = `eg++ -dumpversion | cut -c 3`);
1083                 }
1084                 return "OpenBSD";
1085         }
1086
1087         if ($config{OSNAME} =~ /Linux/i) {
1088                 $config{LDLIBS} = "-ldl -lstdc++ -pthread";
1089 #               $config{FLAGS}  = "-fPIC -Woverloaded-virtual -Wshadow -Wall $config{OPTIMISATI}";
1090                 $config{FLAGS}  .= " " . $ENV{CXXFLAGS} if exists($ENV{CXXFLAGS});
1091                 $config{LDLIBS} .= " " . $ENV{LDLIBS} if exists($ENV{LDLIBS});
1092                 $config{MAKEPROG} = "make";
1093         }
1094
1095         if ($config{OSNAME} =~ /FreeBSD/i) {
1096                 $config{FLAGS}  .= " " . $ENV{CXXFLAGS} if exists($ENV{CXXFLAGS});
1097                 $config{LDLIBS} .= " " . $ENV{LDLIBS} if exists($ENV{LDLIBS});
1098         }
1099
1100         if ($config{OSNAME} =~ /SunOS/i or $config{OSNAME} =~ /solaris/i)
1101         {
1102                 # solaris/sunos needs these
1103                 # socket = bsd sockets api
1104                 # nsl = dns stuff
1105                 # rt = POSIX realtime extensions
1106                 # resolv = inet_aton only (why isnt this in nsl?!)
1107                 $config{MAKEPROG} = "gmake";
1108                 $config{LDLIBS} .= " -lsocket -lnsl -lrt -lresolv -pthread";
1109                 return "Solaris";
1110         }
1111
1112         if($config{OSNAME} =~ /MINGW32/i)
1113         {
1114                 # All code is position-independent on windows
1115                 $config{FLAGS} =~ s/-fPIC //;
1116                 return "MinGW";
1117         }
1118
1119         return $config{OSNAME};
1120 }
1121
1122 my ($mliflags, $mfrules, $mobjs, $mfcount) = ("", "", "", 0);
1123
1124 sub writefiles {
1125         my($writeheader) = @_;
1126         my $se = "";
1127         # First File.. inspircd_config.h
1128         chomp(my $incos = `uname -n -s -r`);
1129         chomp(my $version = `sh src/version.sh`);
1130         chomp(my $revision2 = getrevision());
1131         if ($writeheader == 1)
1132         {
1133                 print "Writing \e[1;32minspircd_config.h\e[0m\n";
1134                 open(FILEHANDLE, ">include/inspircd_config.h");
1135                 print FILEHANDLE <<EOF;
1136 /* Auto generated by configure, do not modify! */
1137 #ifndef __CONFIGURATION_AUTO__
1138 #define __CONFIGURATION_AUTO__
1139
1140 /* this is for windows support. */
1141 #define CoreExport /**/
1142 #define DllExport /**/
1143
1144 #define CONFIG_FILE "$config{CONFIG_DIR}/inspircd.conf"
1145 #define MOD_PATH "$config{MODULE_DIR}"
1146 #define VERSION "$version"
1147 #define REVISION "$revision2"
1148 #define SOMAXCONN_S "$config{_SOMAXCONN}"
1149 #define OPTIMISATION $config{OPTIMITEMP}
1150 #define LIBRARYDIR "$config{LIBRARY_DIR}"
1151 #define SYSTEM "$incos"
1152 #define ENTRYPOINT int main(int argc, char** argv)
1153
1154 EOF
1155 print FILEHANDLE "#define MAXBUF " . ($config{MAXBUF}+2) . "\n";
1156
1157                 if ($config{OSNAME} =~ /SunOS/i) {
1158                         print FILEHANDLE "#define IS_SOLARIS\n";
1159                 }
1160                 if ($config{OSNAME} =~ /MINGW32/i) {
1161                         print FILEHANDLE "#define IS_MINGW\n";
1162                 }
1163                 if ($config{GCCVER} >= 3) {
1164                         print FILEHANDLE "#define GCC3\n";
1165                 }
1166                 if (
1167                         (($config{GCCVER} == 4) && ($config{GCCMINOR} >= 3))
1168                                 ||
1169                         ($config{GCCVER} > 4)
1170                 ) {
1171                         print FILEHANDLE "#define HASHMAP_DEPRECATED\n";
1172                 }
1173                 if ($config{HAS_STRLCPY} eq "true") {
1174                         print FILEHANDLE "#define HAS_STRLCPY\n";
1175                 }
1176                 if ($config{HAS_STDINT} eq "true") {
1177                         print FILEHANDLE "#define HAS_STDINT\n";
1178                 }
1179                 if ($config{IPV6} =~ /y/i) {
1180                         print FILEHANDLE "#define IPV6\n";
1181                 }
1182                 if ($config{SUPPORT_IP6LINKS} =~ /y/i) {
1183                         print FILEHANDLE "#define SUPPORT_IP6LINKS\n";
1184                 }
1185                 if ($config{HAS_EVENTFD} eq 'true') {
1186                         print FILEHANDLE "#define HAS_EVENTFD\n";
1187                 }
1188                 my $use_hiperf = 0;
1189                 if (($has_kqueue) && ($config{USE_KQUEUE} eq "y")) {
1190                         print FILEHANDLE "#define USE_KQUEUE\n";
1191                         $se = "socketengine_kqueue";
1192                         $use_hiperf = 1;
1193                 }
1194                 if (($has_epoll) && ($config{USE_EPOLL} eq "y")) {
1195                         print FILEHANDLE "#define USE_EPOLL\n";
1196                         $se = "socketengine_epoll";
1197                         $use_hiperf = 1;
1198                 }
1199                 if (($has_ports) && ($config{USE_PORTS} eq "y")) {
1200                         print FILEHANDLE "#define USE_PORTS\n";
1201                         $se = "socketengine_ports";
1202                         $use_hiperf = 1;
1203                 }
1204                 # user didn't choose either epoll or select for their OS.
1205                 # default them to USE_SELECT (ewwy puke puke)
1206                 if (!$use_hiperf) {
1207                         print "no hi-perf, " . $config{USE_POLL};
1208                         if ($config{USE_POLL} eq "y")
1209                         {
1210                                 print FILEHANDLE "#define USE_POLL\n";
1211                                 $se = "socketengine_poll";
1212                         }
1213                         else
1214                         {
1215                                 print FILEHANDLE "#define USE_SELECT\n";
1216                                 $se = "socketengine_select";
1217                         }
1218                 }
1219                 print FILEHANDLE "\n#include \"threadengines/threadengine_pthread.h\"\n\n#endif\n";
1220                 close(FILEHANDLE);
1221         }
1222
1223         if ($writeheader)
1224         {
1225                 open(FILEHANDLE, ">include/inspircd_se_config.h");
1226                 print FILEHANDLE <<EOF;
1227 /* Auto generated by configure, do not modify or commit to svn! */
1228 #ifndef __CONFIGURATION_SOCKETENGINE__
1229 #define __CONFIGURATION_SOCKETENGINE__
1230
1231 #include "socketengines/$se.h"
1232
1233 #endif
1234 EOF
1235                 close(FILEHANDLE);
1236         }
1237
1238
1239         # Create a Modules List..
1240         my $modules = "";
1241         foreach my $i (@modlist)
1242         {
1243                 $modules .= "m_".$i.".so ";
1244         }
1245         chomp($modules);   # Remove Redundant whitespace..
1246
1247         opendir(DIRHANDLE, "src/modules");
1248         foreach my $name2 (sort readdir(DIRHANDLE)) {
1249                 if ($name2 =~ /^m_(.+?)$/) {
1250                         if (defined(opendir(MDIRHANDLE, "src/modules/$name2"))) {
1251                                 closedir(MDIRHANDLE);
1252                                 $modules .= "$name2.so ";
1253                                 $uninstall_list = $uninstall_list . "   -rm \$(MODULES)/$name2.so\n";
1254                         }
1255                 }
1256         }
1257         closedir(DIRHANDLE);
1258
1259
1260         # Write all .in files.
1261         my $tmp = "";
1262         my $file = "";
1263         my $exe = "inspircd";
1264
1265         # Do this once here, and cache it in the .*.inc files,
1266         # rather than attempting to read src/version.sh from
1267         # compiled code -- we might not have the source to hand.
1268         # Fix for bug#177 by Brain.
1269
1270         chomp($version = `sh ./src/version.sh`);
1271         chomp(my $revision = getrevision());
1272         $version = "$version(r$revision)";
1273
1274         # We can actually parse any file starting with . and ending with .inc,
1275         # but right now we only parse .inspircd.inc to form './inspircd'
1276
1277         print "Writing \e[1;32mMakefiles\e[0m\n";
1278         write_dynamic_modules_makefile();
1279         write_dynamic_makefile();
1280
1281         opendir(DIRHANDLE, $this);
1282
1283         foreach my $name (sort readdir(DIRHANDLE)) {
1284                 if ($name =~ /^\.(.+)\.inc$/) {
1285                         $file = $1;
1286
1287                         # Bug #353, omit this on non-darwin
1288                         next if (($config{OSNAME} !~ /darwin/) && ($file eq "org.inspircd.plist"));
1289
1290                         # All .name.inc files need parsing!
1291                         open(FILEHANDLE, ".$file.inc") or die ("Can't open .$file.inc");
1292                         $_ = join '', <FILEHANDLE>;
1293                         close(FILEHANDLE);
1294
1295                         print "Writing \e[1;32m$file\e[0m ...\n";
1296                         for my $var (qw(
1297                                 CC FLAGS DEVELOPER LDLIBS BASE_DIR CONFIG_DIR MODULE_DIR BINARY_DIR LIBRARY_DIR
1298                                 STARTSCRIPT DESTINATION EXTRA_DIR
1299                         )) {
1300                                 s/\@$var\@/$config{$var}/g;
1301                         }
1302                         s/\@MODULES\@/$modules/ if defined $modules;
1303                         s/\@EXECUTABLE\@/$exe/ if defined $exe;
1304                         s/\@VERSION\@/$version/ if defined $version;
1305                         s/\@INSTALL_LIST\@/$install_list/ if defined $install_list;
1306                         s/\@UNINSTALL_LIST\@/$uninstall_list/ if defined $uninstall_list;
1307
1308                         if ($file eq 'Makefile') {
1309                                 my $mk_tmp = $_;
1310                                 s/\@IFDEF (\S+)/ifdef $1/g;
1311                                 s/\@IFNDEF (\S+)/ifndef $1/g;
1312                                 s/\@ELSE/else/g;
1313                                 s/\@ENDIF/endif/g;
1314                                 s/\@BSD_ONLY .*\n//g;
1315                                 s/\@GNU_ONLY //g;
1316                                 open MKF, '>GNUmakefile' or die "Can't write to GNUmakefile: $!";
1317                                 print MKF $_;
1318                                 close MKF;
1319                                 $_ = $mk_tmp;
1320                                 s/\@IFDEF (\S+)/.if defined($1)/g;
1321                                 s/\@IFNDEF (\S+)/.if !defined($1)/g;
1322                                 s/\@ELSE/.else/g;
1323                                 s/\@ENDIF/.endif/g;
1324                                 s/\@BSD_ONLY //g;
1325                                 s/\@GNU_ONLY .*\n//g;
1326                                 open MKF, '>BSDmakefile' or die "Can't write to BSDmakefile: $!";
1327                                 print MKF $_;
1328                                 close MKF;
1329                         } else {
1330                                 open(FILEHANDLE, ">$file") or die("Can't write to $file: $!\n");
1331                                 print FILEHANDLE $_;
1332                                 close(FILEHANDLE);
1333                         }
1334                 }
1335         }
1336         closedir(DIRHANDLE);
1337
1338         # Make inspircd executable!
1339         chmod 0744, 'inspircd';
1340 }
1341
1342 sub write_dynamic_modules_makefile {
1343         # Modules Makefile..
1344         print "Writing \e[1;32msrc/modules/Makefile\e[0m\n";
1345         open(FILEHANDLE, ">src/modules/Makefile");
1346
1347 ###
1348 # Module Makefile Header
1349 ###
1350         print FILEHANDLE <<EOF;
1351 ###################################################
1352 # Copyright 2002-2009 The InspIRCd Development Team
1353 #  http://wiki.inspircd.org/Credits
1354 #
1355 # Thanks to Andrew Church <achurch\@achurch.org>
1356 #   for assisting with making this work right.
1357 #
1358 # Automatically Generated by ./configure to add a
1359 #  modules please run ./configure -modupdate
1360 ###################################################
1361
1362 all: \$(MODULES)
1363
1364 EOF
1365
1366 if ($config{OSNAME} =~ /darwin/) {
1367                 print FILEHANDLE <<EOCHEESE;
1368
1369 PICLDFLAGS = -twolevel_namespace -undefined dynamic_lookup -bundle
1370
1371 EOCHEESE
1372 } else {
1373                 print FILEHANDLE <<EOCHEESE;
1374
1375 PICLDFLAGS = -fPIC -DPIC -shared
1376
1377 EOCHEESE
1378 }
1379
1380         ###
1381         # End Module Makefile Header
1382         ###
1383
1384         # Create a Modules List..
1385         my $modules = "";
1386         my $cmflags = "";
1387         my $liflags = "";
1388         foreach my $i (@modlist) {
1389                 ###
1390                 # Write Entry to the MakeFile
1391                 ###
1392                 $cmflags = getcompilerflags("src/modules/m_".$i.".cpp");
1393                 $liflags = getlinkerflags("src/modules/m_".$i.".cpp");
1394                 my $deps = getdependencies("src/modules/m_".$i.".cpp");
1395
1396                 #print "file: $i: cmflags=$cmflags; liflags=$liflags; deps=$deps\n";
1397
1398
1399                 if (nopedantic("src/modules/m_".$i.".cpp"))
1400                 {
1401                         print FILEHANDLE "
1402 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
1403         \$(RUNCC) \$(NICEFLAGS) $cmflags \$(PICLDFLAGS) $liflags $SHARED -o m_$i.so m_$i.cpp
1404 ";
1405                 }
1406                 else
1407                 {
1408                         print FILEHANDLE "
1409 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
1410         \$(RUNCC) \$(FLAGS) $cmflags \$(PICLDFLAGS) $liflags $SHARED -o m_$i.so m_$i.cpp
1411 ";
1412                 }
1413                 $install_list = $install_list . "       install -m \$(INSTMODE) src/modules/m_$i.so \$(MODPATH)\n";
1414                 $uninstall_list = $uninstall_list . "   -rm \$(MODULES)/m_$i.so\n";
1415                 ###
1416                 # End Write Entry to the MakeFile
1417                 ###
1418         }
1419
1420         opendir(DIRHANDLE, "src/modules");
1421         foreach my $name (sort readdir(DIRHANDLE)) {
1422                 if ($name =~ /^m_(.+?)$/) {
1423                         $mfrules = "";
1424                         $mobjs = "";
1425                         $mliflags = "";
1426                         $mfcount = 0;
1427                         # A module made of multiple files, in a dir, e.g. src/modules/m_spanningtree/
1428                         if (defined(opendir(MDIRHANDLE, "src/modules/$name"))) {
1429                                 read_module_directory("src/modules/$name", $name);
1430                                 print "Composing Makefile rules for directory \e[1;32m$name\e[0m... (\e[1;32m$mfcount files found\e[0m)\n";
1431                                 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";
1432                                 print FILEHANDLE "      \$(RUNCC) \$(FLAGS) $SHARED $mliflags -o $name.so $mobjs\n";
1433                                 print FILEHANDLE "\n$mfrules\n";
1434                                 closedir(MDIRHANDLE);
1435                                 $install_list = $install_list . "       install -m \$(INSTMODE) src/modules/$name.so \$(MODPATH)\n";
1436                         }
1437                 }
1438         }
1439         closedir(DIRHANDLE);
1440 }
1441
1442 sub read_module_directory {
1443         my ($dpath, $reldpath) = @_;
1444
1445         if (opendir(MDIRHANDLE, $dpath) == 0) {
1446                 return;
1447         }
1448
1449         foreach my $fname (sort readdir(MDIRHANDLE)) {
1450                 if ($fname =~ /\.cpp$/) {
1451                         my $cmflags = getcompilerflags("$dpath/$fname");
1452                         $mliflags = $mliflags . " " . getlinkerflags("$dpath/$fname");
1453                         my $deps = getdependencies("$dpath/$fname");
1454                         my $oname = $fname;
1455                         $oname =~ s/\.cpp$/.o/g;
1456                         $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";
1457                         $mfrules = $mfrules .  "        \$(RUNCC) -I. \$(FLAGS) $cmflags $SHARED -o $reldpath/$oname -c $reldpath/$fname\n\n";
1458                         $mobjs = $mobjs . " $reldpath/$oname";
1459                         $mfcount++;
1460                 }
1461                 elsif ((-d "$dpath/$fname") && !($fname eq ".") && !($fname eq "..")) {
1462                         read_module_directory($dpath."/".$fname, $reldpath."/".$fname);
1463                 }
1464         }
1465 }
1466
1467 sub calcdeps($)
1468 {
1469         # Yes i know we could use gcc -M but it seems to ideneify a lot of 'deep'
1470         # dependencies which are not relevent in C++.
1471
1472         my $file = $_[0];
1473
1474         open (CPP, "<$file") or die("Can't open $file for reading!");
1475
1476         my %dupe = ();
1477         my $retlist = "";
1478
1479         foreach my $d (@ignoredeps)
1480         {
1481                 $dupe{$d} = 1;
1482         }
1483
1484         my $immutable = "";
1485         foreach my $dep (@immutabledeps)
1486         {
1487                 $immutable = $immutable . "../include/$dep ";
1488         }
1489         $immutable =~ s/ $//g;
1490
1491         while (defined(my $line = <CPP>))
1492         {
1493                 chomp($line);
1494                 if ($line =~ /#include "(.+\.h)"/)
1495                 {
1496                         if (!exists($dupe{$1}))
1497                         {
1498                                 $retlist = $retlist . "../include/$1 ";
1499                                 $dupe{$1} = 1;
1500                         }
1501                 }
1502         }
1503         close CPP;
1504         return length($immutable) ? $immutable . " " . $retlist : $retlist;
1505 }
1506
1507 sub write_dynamic_makefile
1508 {
1509         my $i = 0;
1510         my @cmdlist = ();
1511         my %existing_install_list = ();
1512         my %core_files_list = ();
1513
1514         opendir(DIRHANDLE, "src/commands");
1515         foreach my $name (sort readdir(DIRHANDLE))
1516         {
1517                 if ($name =~ /^cmd_(.+)\.cpp$/)
1518                 {
1519                         $cmdlist[$i++] = $1;
1520                         $install_list = $install_list . "       -install -m \$(INSTMODE) src/commands/cmd_" . $1 . ".so \$(LIBPATH)\n";
1521                         $uninstall_list = $uninstall_list . "   -rm \$(LIBPATH)/cmd_$1.so\n";
1522                 }
1523         }
1524         closedir(DIRHANDLE);
1525
1526         if (!$has_epoll)
1527         {
1528                 $config{USE_EPOLL} = 0;
1529         }
1530         if (!$has_kqueue)
1531         {
1532                 $config{USE_KQUEUE} = 0;
1533         }
1534         if (!$has_ports)
1535         {
1536                 $config{USE_PORTS} = 0;
1537         }
1538
1539         # formerly generated below this foreach, now it's not! magic.
1540         my $all_core = "";
1541
1542         foreach my $dir (("src","src/commands","src/modes","src/socketengines","src/modules"))
1543         {
1544                 print "Scanning \e[1;32m$dir\e[0m for core files ";
1545                 opendir(DIRHANDLE, $dir);
1546                 foreach my $name (sort readdir(DIRHANDLE))
1547                 {
1548                         if ($name =~ /\.cpp$/)
1549                         {
1550                                 open (CPP, "<$dir/$name") or die("Can't open $dir/$name to scan it! oh bugger");
1551                                 print ".";
1552                                 while (defined(my $line = <CPP>))
1553                                 {
1554                                         chomp($line);
1555                                         if ($line =~ /\/\* \$Core \*\//i)
1556                                         {
1557                                                 my $sname = $name;
1558                                                 $sname =~ s/\.cpp$/.o/;
1559
1560                                                 # append it to list to be built
1561                                                 $all_core = $all_core . $sname . " ";
1562                                                 $filelist{$name} = $sname;
1563
1564                                                 # mark it as a core file, so it won't get shared object cflags
1565                                                 if (!exists($core_files_list{$name}))
1566                                                 {
1567                                                         $core_files_list{$name} = 1;
1568                                                 }
1569                                         }
1570                                         elsif ($line =~ /\/\* \$ExtraDeps: (.*?) \*\//i)
1571                                         {
1572                                                 $specialdeps{$name} = $1;
1573                                         }
1574                                         elsif ($line =~ /\/\* \$ExtraObjects: (.*?) \*\//i)
1575                                         {
1576                                                 $extraobjects{$name} = $1;
1577                                         }
1578                                         elsif ($line =~ /\/\* \$ExtraBuild: (.*?) \*\//i)
1579                                         {
1580                                                 $extrabuildlines{$name} = $1;
1581                                         }
1582                                         elsif ($line =~ /\/\* \$ExtraSources: (.*?) \*\//i)
1583                                         {
1584                                                 $extrasources{$name} = $1;
1585                                                 }
1586                                         elsif ($line =~ /\/\* \$If: (\w+) \*\//i)
1587                                         {
1588                                                 if (defined $config{$1})
1589                                                 {
1590                                                         if (($config{$1} !~ /y/i) and ($config{$1} ne "1"))
1591                                                         {
1592                                                                 # Skip to 'endif'
1593                                                                 while (defined($line = <CPP>))
1594                                                                 {
1595                                                                         chomp($line);
1596                                                                         die ("\$If buildsystem instruction within another \$If in file $dir/$name") if ($line =~ /\/\* \$If: (\w+) \*\//i);
1597                                                                         last if ($line =~ /\/\* \$EndIf \*\//i);
1598                                                                 }
1599                                                         }
1600                                                 }
1601                                         }
1602                                         elsif ($line =~ /\/\* \$Install: (.*?) \*\//i)
1603                                         {
1604                                                 if (!exists($existing_install_list{$1}))
1605                                                 {
1606                                                         $existing_install_list{$1} = 1;
1607                                                         my $idir = (split(' ',$1))[1];
1608                                                         my $ifile = (split(' ',$1))[0];
1609                                                         $install_list = $install_list . "       -install -m \$(INSTMODE) $1\n";
1610                                                         $ifile =~ s/.*\///g;
1611                                                         $uninstall_list = $uninstall_list . "   -rm $idir/$ifile\n";
1612                                                 }
1613                                         }
1614                                         elsif ($line =~ /\/\* \$CopyInstall: (.*?) \*\//i)
1615                                         {
1616                                                 if (!exists($existing_install_list{$1}))
1617                                                 {
1618                                                         $existing_install_list{$1} = 1;
1619                                                         my $idir = (split(' ',$1))[1];
1620                                                         my $ifile = (split(' ',$1))[0];
1621                                                         $install_list = $install_list . "       -cp $1\n";
1622                                                         $ifile =~ s/.*\///g;
1623                                                         $uninstall_list = $uninstall_list . "   -rm $idir/$ifile\n";
1624                                                 }
1625                                         }
1626                                 }
1627                                 close CPP;
1628                         }
1629                 }
1630                 closedir(DIRHANDLE);
1631                 print " done!\n";
1632         }
1633
1634         # modes need to be compiled in too
1635         $all_core = $all_core . "modes/modeclasses.a";
1636
1637         my $freebsd4libs = (defined $config{CRAQ} ? $config{CRAQ} : "");
1638
1639         my $libraryext = "";
1640         my $binary_rule = "";
1641
1642         if ($config{IS_DARWIN} eq "YES")
1643         {
1644                 $libraryext = "dylib";
1645                 $binary_rule = "        \$(RUNCC) -dynamic -bind_at_load -L. -o inspircd \$(LDLIBS) inspircd.o "
1646         }
1647         else
1648         {
1649                 $libraryext = "so";
1650                 $binary_rule = "        \$(RUNCC) \$(FLAGS) $freebsd4libs -rdynamic -L. -o inspircd \$(LDLIBS) ";
1651         }
1652
1653         open(FH,">src/Makefile") or die("Could not write src/Makefile");
1654         print FH <<'EOM';
1655
1656 CXXFLAGS = ${FLAGS}
1657 CPPFILES = $(shell /bin/ls -l modes/ | grep '\.cpp' | sed 's/^.* //' | grep -v svn)
1658 RELCPPFILES = $(shell /bin/ls -l modes/ | grep '\.cpp' | sed 's/^.* /modes\//' | grep -v svn)
1659
1660 all:
1661         @echo "Don't run make here! Run it in the parent directory"
1662         false
1663
1664 EOM
1665
1666         my $buildstring = "";
1667         my $deps = "";
1668
1669         foreach my $cpp (sort keys %filelist)
1670         {
1671                 my $objs = $cpp;
1672                 my $rawcpp = $cpp;
1673                 $objs =~ s/\.cpp$/.o/;
1674                 if (exists($extraobjects{$cpp}))
1675                 {
1676                         $objs = $objs . " " . $extraobjects{$cpp};
1677                         $all_core = $all_core . " " . $extraobjects{$cpp};
1678                 }
1679                 if (exists($extrasources{$cpp}))
1680                 {
1681                         $rawcpp = $rawcpp . " " . $extrasources{$cpp};
1682                 }
1683
1684                 $deps = calcdeps("src/$cpp");
1685                 if (exists($extrasources{$cpp}))
1686                 {
1687                         foreach my $seperate (sort split(' ',$extrasources{$cpp}))
1688                         {
1689                                 my $d = calcdeps("src/$extrasources{$cpp}") . " ";
1690                                 if ($d ne "")
1691                                 {
1692                                         $deps = $deps . $d . " ";
1693                                 }
1694                         }
1695                 }
1696                 $buildstring = $buildstring . $objs . ": $cpp $deps ". (defined($specialdeps{$cpp}) ? $specialdeps{$cpp} : "") . "\n";
1697
1698                 if (exists($core_files_list{$cpp}))
1699                 {
1700                         # core files are statically linked into the binary and do not require $SHARED shared libs switches
1701                         $buildstring = $buildstring . " \$(RUNCC) \$(FLAGS) -c $rawcpp\n";
1702                 }
1703                 else
1704                 {
1705                         $buildstring = $buildstring . " \$(RUNCC) \$(FLAGS) $SHARED -c $rawcpp\n";
1706                 }
1707
1708                 if (exists($extrabuildlines{$cpp}))
1709                 {
1710                         $buildstring = $buildstring . " " . $extrabuildlines{$cpp} . "\n";
1711                 }
1712         }
1713
1714         print FH "inspircd: $all_core\n";
1715         print FH "$binary_rule $all_core\n\n";
1716
1717         print FH $buildstring;
1718         print FH <<'EOM';
1719
1720 .PHONY: all commands
1721
1722 commands:
1723         @${MAKE} -C commands $(MAKEARGS) commands
1724
1725 modes/modeclasses.a: $(RELCPPFILES)
1726         @${MAKE} -C modes $(MAKEARGS) CPPFILES="$(CPPFILES)" modeclasses.a
1727
1728 EOM
1729
1730         # close main makefile
1731         close(FH);
1732
1733         my $cmdobjs = "";
1734         # generate a list of .so
1735         foreach my $cmd (@cmdlist) {
1736                 $cmdobjs = $cmdobjs . "cmd_$cmd.so ";
1737         }
1738
1739         # and now reopen the commands makefile
1740         open(FH,">src/commands/Makefile") or die("Could not write src/commands/Makefile");
1741         print FH <<ITEM;
1742 CXXFLAGS = \${FLAGS}
1743
1744 all:
1745         \@echo "Don't run make here! Run it in the root directory"
1746         false
1747
1748 .PHONY: all commands
1749
1750 commands: $cmdobjs
1751
1752 ITEM
1753
1754         # now print the command file detail
1755         foreach my $cmd (@cmdlist) {
1756                 print FH <<ITEM;
1757 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
1758         \$(RUNCC) \$(FLAGS) $SHARED -o cmd_$cmd.so cmd_$cmd.cpp
1759
1760 ITEM
1761         }
1762 }
1763
1764 # Routine to list out the extra/ modules that have been enabled.
1765 # Note: when getting any filenames out and comparing, it's important to lc it if the
1766 # file system is not case-sensitive (== Epoc, MacOS, OS/2 (incl DOS/DJGPP), VMS, Win32
1767 # (incl NetWare, Symbian)). Cygwin may or may not be case-sensitive, depending on
1768 # configuration, however, File::Spec does not currently tell us (it assumes Unix behavior).
1769 sub list_extras () {
1770         use File::Spec;
1771         # @_ not used
1772         my $srcdir = File::Spec->catdir("src", "modules");
1773         my $abs_srcdir = File::Spec->rel2abs($srcdir);
1774         local $_;
1775         my $dd;
1776         opendir $dd, File::Spec->catdir($abs_srcdir, "extra") or die (File::Spec->catdir($abs_srcdir, "extra") . ": $!\n");
1777         my @extras = map { File::Spec->case_tolerant() ? lc($_) : $_ } (readdir($dd));
1778         closedir $dd;
1779         undef $dd;
1780         opendir $dd, $abs_srcdir or die "$abs_srcdir: $!\n";
1781         my @sources = map { File::Spec->case_tolerant() ? lc($_) : $_ } (readdir($dd));
1782         closedir $dd;
1783         undef $dd;
1784         my $maxlen = (sort { $b <=> $a } (map {length($_)} (@extras)))[0];
1785         my %extras = ();
1786 EXTRA:  for my $extra (@extras) {
1787                 next if (File::Spec->curdir() eq $extra || File::Spec->updir() eq $extra);
1788                 next if ($extra eq '.svn');
1789                 my $abs_extra = File::Spec->catfile($abs_srcdir, "extra", $extra);
1790                 my $abs_source = File::Spec->catfile($abs_srcdir, $extra);
1791                 next unless ($extra =~ m/\.(cpp|h)$/ || (-d $abs_extra)); # C++ Source/Header, or directory
1792                 if (-l $abs_source) {
1793                         # Symlink, is it in the right place?
1794                         my $targ = readlink($abs_source);
1795                         my $abs_targ = File::Spec->rel2abs($targ, $abs_srcdir);
1796                         if ($abs_targ eq $abs_extra) {
1797                                 $extras{$extra} = "\e[32;1menabled\e[0m";
1798                         } else {
1799                                 $extras{$extra} = sprintf("\e[31;1mwrong symlink target (%s)\e[0m", $abs_targ);
1800                         }
1801                 } elsif (-e $abs_source) {
1802                         my ($devext, $inoext) = stat($abs_extra);
1803                         my ($devsrc, $inosrc, undef, $lnksrc) = stat($abs_source);
1804                         if ($lnksrc > 1) {
1805                                 if ($devsrc == $devext && $inosrc == $inoext) {
1806                                         $extras{$extra} = "\e[32;1menabled\e[0m";
1807                                 } else {
1808                                         $extras{$extra} = sprintf("\e[31;1mwrong hardlink target (%d:%d)\e[0m", $devsrc, $inosrc);
1809                                 }
1810                         } else {
1811                                 open my $extfd, "<", $abs_extra;
1812                                 open my $srcfd, "<", $abs_source;
1813                                 local $/ = undef;
1814                                 if (scalar(<$extfd>) eq scalar(<$srcfd>)) {
1815                                         $extras{$extra} = "\e[32;1menabled\e[0m";
1816                                 } else {
1817                                         $extras{$extra} = sprintf("\e[31;1mout of synch (re-copy)\e[0m");
1818                                 }
1819                         }
1820                 } else {
1821                         $extras{$extra} = "\e[33;1mdisabled\e[0m";
1822                 }
1823         }
1824         # Now let's add dependency info
1825         for my $extra (keys(%extras)) {
1826                 next unless $extras{$extra} =~ m/enabled/; # only process enabled extras.
1827                 my $abs_extra = File::Spec->catfile($abs_srcdir, "extra", $extra);
1828                 my @deps = split / +/, getdependencies($abs_extra);
1829                 for my $dep (@deps) {
1830                         if (exists($extras{$dep})) {
1831                                 my $ref = \$extras{$dep}; # Take reference.
1832                                 if ($$ref !~ m/needed by/) {
1833                                         # First dependency found.
1834                                         if ($$ref =~ m/enabled/) {
1835                                                 $$ref .= " (needed by \e[32;1m$extra\e[0m";
1836                                         } else {
1837                                                 $$ref =~ s/\e\[.*?m//g; # Strip out previous coloring. Will be set in bold+red+blink later.
1838                                                 $$ref .= " (needed by \e[0;32;1;5m$extra\e[0;31;1;5m";
1839                                         }
1840                                 } else {
1841                                         if ($$ref =~ m/enabled/) {
1842                                                 $$ref .= ", \e[32;1m$extra\e[0m";
1843                                         } else {
1844                                                 $$ref .= ", \e[0;32;1;5m$extra\e[0;31;1;5m";
1845                                         }
1846                                 }
1847                         }
1848                 }
1849         }
1850         for my $extra (sort {$a cmp $b} keys(%extras)) {
1851                 my $text = $extras{$extra};
1852                 if ($text =~ m/needed by/ && $text !~ m/enabled/) {
1853                         printf "\e[31;1;5m%-*s = %s%s\e[0m\n", $maxlen, $extra, $text, ($text =~ m/needed by/ ? ")" : "");
1854                 } else {
1855                         printf "%-*s = %s%s\n", $maxlen, $extra, $text, ($text =~ m/needed by/ ? "\e[0m)" : "");
1856                 }
1857         }
1858         return keys(%extras) if wantarray; # Can be used by manage_extras.
1859 }
1860
1861 sub enable_extras (@) {
1862         my (@extras) = @_;
1863         for my $extra (@extras) {
1864                 my $extrapath = "src/modules/extra/$extra";
1865                 if (!-e $extrapath) {
1866                         print STDERR "Cannot enable \e[32;1m$extra\e[0m : No such file or directory in src/modules/extra\n";
1867                         next;
1868                 }
1869                 my $source = "src/modules/$extra";
1870                 if (-e $source) {
1871                         print STDERR "Cannot enable \e[32;1m$extra\e[0m : destination in src/modules exists (might already be enabled?)\n";
1872                         next;
1873                 }
1874                 # Get dependencies, and add them to be processed.
1875                 my @deps = split / +/, getdependencies($extrapath);
1876                 for my $dep (@deps) {
1877                         next if scalar(grep { $_ eq $dep } (@extras)) > 0; # Skip if we're going to be enabling it anyway.
1878                         if (!-e "src/modules/$dep") {
1879                                 if (-e "src/modules/extra/$dep") {
1880                                         print STDERR "Will also enable extra \e[32;1m$dep\e[0m (needed by \e[32;1m$extra\e[0m)\n";
1881                                         push @extras, $dep;
1882                                 } else {
1883                                         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";
1884                                 }
1885                         }
1886                 }
1887                 print "Enabling $extra ... \n";
1888                 symlink "extra/$extra", $source or print STDERR "$source: Cannot link to 'extra/$extra': $!\n";
1889         }
1890 }
1891
1892 sub disable_extras (@)
1893 {
1894         opendir my $dd, "src/modules/extra/";
1895         my @files = readdir($dd);
1896         closedir $dd;
1897         my (@extras) = @_;
1898 EXTRA:  for my $extra (@extras) {
1899                 my $extrapath = "src/modules/extra/$extra";
1900                 my $source = "src/modules/$extra";
1901                 if (!-e $extrapath) {
1902                         print STDERR "Cannot disable \e[32;1m$extra\e[0m : Is not an extra\n";
1903                         next;
1904                 }
1905                 if ((! -l $source) || readlink($source) ne "extra/$extra") {
1906                         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";
1907                         next;
1908                 }
1909                 # Check if anything needs this.
1910                 for my $file (@files) {
1911                         my @deps = split / +/, getdependencies("src/modules/extra/$file");
1912                         # File depends on this extra...
1913                         if (scalar(grep { $_ eq $extra } @deps) > 0) {
1914                                 # And is both enabled and not about to be disabled.
1915                                 if (-e "src/modules/$file" && scalar(grep { $_ eq $file } @extras) < 1) {
1916                                         print STDERR "Cannot disable \e[32;1m$extra\e[0m : is needed by \e[32;1m$file\e[0m\n";
1917                                         next EXTRA;
1918                                 }
1919                         }
1920                 }
1921                 # Now remove.
1922                 print "Disabling $extra ... \n";
1923                 unlink "src/modules/$extra" or print STDERR "Cannot disable \e[32;1m$extra\e[0m : $!\n";
1924         }
1925 }