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