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