]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - configure
Remove various broken/useless features from the build system.
[user/henk/code/inspircd.git] / configure
1 #!/usr/bin/env perl
2
3 #
4 # InspIRCd -- Internet Relay Chat Daemon
5 #
6 #   Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org>
7 #   Copyright (C) 2007, 2009 Dennis Friis <peavey@inspircd.org>
8 #   Copyright (C) 2003, 2006-2008 Craig Edwards <craigedwards@brainbox.cc>
9 #   Copyright (C) 2006-2008 Robin Burchell <robin+git@viroteck.net>
10 #   Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org>
11 #   Copyright (C) 2007 John Brooks <john.brooks@dereferenced.net>
12 #   Copyright (C) 2006 Oliver Lupton <oliverlupton@gmail.com>
13 #   Copyright (C) 2003-2006 Craig McLure <craig@chatspike.net>
14 #
15 # This file is part of InspIRCd.  InspIRCd is free software: you can
16 # redistribute it and/or modify it under the terms of the GNU General Public
17 # License as published by the Free Software Foundation, version 2.
18 #
19 # This program is distributed in the hope that it will be useful, but WITHOUT
20 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
21 # FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
22 # details.
23 #
24 # You should have received a copy of the GNU General Public License
25 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
26 #
27
28
29 BEGIN {
30         require 5.8.0;
31 }
32
33 use strict;
34 use warnings FATAL => qw(all);
35
36 use File::Copy ();
37 use File::Spec::Functions qw(rel2abs);
38 use Cwd;
39 use Getopt::Long;
40
41 use make::configure;
42 use make::utilities;
43
44 our ($opt_use_gnutls, $opt_use_openssl, $opt_nointeractive, $opt_socketengine,
45      $opt_system, $opt_uid, $opt_base_dir, $opt_config_dir, $opt_module_dir, $opt_binary_dir,
46      $opt_data_dir, $opt_log_dir);
47
48 sub list_extras ();
49
50 sub enable_extras (@);
51
52 sub disable_extras (@);
53
54 my @opt_enableextras;
55 my @opt_disableextras;
56
57 GetOptions (
58         'enable-gnutls' => \$opt_use_gnutls,
59         'system' => \$opt_system,
60         'uid=s' => \$opt_uid,
61         'enable-openssl' => \$opt_use_openssl,
62         'disable-interactive' => \$opt_nointeractive,
63         'socketengine=s' => \$opt_socketengine,
64         'prefix=s' => \$opt_base_dir,
65         'config-dir=s' => \$opt_config_dir,
66         'module-dir=s' => \$opt_module_dir,
67         'binary-dir=s' => \$opt_binary_dir,
68         'data-dir=s' => \$opt_data_dir,
69         'log-dir=s' => \$opt_log_dir,
70         'help'  => \&cmd_help,
71         'update' => \&cmd_update,
72         'clean' => \&cmd_clean,
73         'list-extras' => sub { list_extras; exit 0; }, # This, --enable-extras, and --disable-extras are for non-interactive managing.
74         'enable-extras=s@' => \@opt_enableextras, # ^
75         'disable-extras=s@' => \@opt_disableextras, # ^
76 );
77
78 if (scalar(@opt_enableextras) + scalar(@opt_disableextras) > 0) {
79         @opt_enableextras = split /,/, join(',', @opt_enableextras);
80         @opt_disableextras = split /,/, join(',', @opt_disableextras);
81         enable_extras(@opt_enableextras);
82         disable_extras(@opt_disableextras);
83         list_extras;
84         print "Remember: YOU are responsible for making sure any libraries needed have been installed!\n";
85         exit 0;
86 }
87
88 our $interactive = !(
89         (defined $opt_base_dir) ||
90         (defined $opt_config_dir) ||
91         (defined $opt_module_dir) ||
92         (defined $opt_base_dir) ||
93         (defined $opt_binary_dir) ||
94         (defined $opt_data_dir) ||
95         (defined $opt_log_dir) ||
96         (defined $opt_nointeractive) ||
97         (defined $opt_socketengine) ||
98         (defined $opt_use_openssl) ||
99         (defined $opt_system) ||
100         (defined $opt_uid) ||
101         (defined $opt_use_gnutls)
102 );
103
104 our %config = read_configure_cache();
105
106 print "Checking for cache from previous configure... ";
107 print %config ? "found\n" : "not found\n";
108
109 $config{BASE_DIR} = getcwd()."/run";
110
111 if (defined $opt_base_dir) {
112         $config{BASE_DIR} = $opt_base_dir;
113 } elsif (defined $opt_system) {
114         $config{BASE_DIR} = '/var/lib/inspircd';
115 }
116
117 if (defined $opt_system) {
118         $config{UID} = defined $opt_uid ? $opt_uid : 'ircd';
119         $config{CONFIG_DIR} = '/etc/inspircd';
120         $config{MODULE_DIR} = '/usr/lib/inspircd';
121         $config{BINARY_DIR} = '/usr/sbin/';
122         $config{DATA_DIR} = '/var/inspircd';
123         $config{LOG_DIR} = '/var/log/inspircd';
124 } else {
125         $config{UID} = defined $opt_uid ? $opt_uid : $<;
126         $config{CONFIG_DIR} = rel2abs($config{BASE_DIR}."/conf");
127         $config{MODULE_DIR} = rel2abs($config{BASE_DIR}."/modules");
128         $config{BINARY_DIR} = rel2abs($config{BASE_DIR}."/bin");
129         $config{DATA_DIR} = rel2abs($config{BASE_DIR}."/data");
130         $config{LOG_DIR} = rel2abs($config{BASE_DIR}."/logs");
131 }
132
133 if (defined $opt_config_dir) {
134         $config{CONFIG_DIR} = $opt_config_dir;
135 }
136 if (defined $opt_module_dir) {
137         $config{MODULE_DIR} = $opt_module_dir;
138 }
139 if (defined $opt_binary_dir) {
140         $config{BINARY_DIR} = $opt_binary_dir;
141 }
142 if (defined $opt_data_dir) {
143         $config{DATA_DIR} = $opt_data_dir;
144 }
145 if (defined $opt_log_dir) {
146         $config{LOG_DIR} = $opt_log_dir;
147 }
148 chomp($config{HAS_GNUTLS}   = `pkg-config --modversion gnutls 2>/dev/null`);
149 chomp($config{HAS_OPENSSL}  = `pkg-config --modversion openssl 2>/dev/null`);
150
151 chomp(our $gnutls_ver = $config{HAS_GNUTLS});
152 chomp(our $openssl_ver = $config{HAS_OPENSSL});
153 $config{USE_GNUTLS}         = 0;
154 if (defined $opt_use_gnutls)
155 {
156         $config{USE_GNUTLS} = "y";                                      # Use gnutls.
157 }
158 $config{USE_OPENSSL}    = 0;                                            # Use openssl.
159 if (defined $opt_use_openssl)
160 {
161         $config{USE_OPENSSL} = "y";
162 }
163
164 $config{CXX} = defined $ENV{CXX} && !system("$ENV{CXX} -v > /dev/null 2>&1") ? $ENV{CXX} : find_compiler();
165 if ($config{CXX} eq "") {
166         print "A C++ compiler could not be detected on your system!\n";
167         print "Set the CXX environment variable to the full path if this is incorrect.\n";
168         exit 1; 
169 }
170
171 our %cxx = get_compiler_info($config{CXX});
172 if ($cxx{UNSUPPORTED}) {
173         print "Your C++ compiler is too old to build InspIRCd!\n";
174         print "Reason: $cxx{REASON}\n";
175         exit 1;
176 }
177
178 if ($config{HAS_OPENSSL} =~ /^([-[:digit:].]+)(?:[a-z])?(?:\-[a-z][0-9])?/) {
179         $config{HAS_OPENSSL} = $1;
180 } else {
181         $config{HAS_OPENSSL} = "";
182 }
183
184 $config{HAS_CLOCK_GETTIME} = run_test 'clock_gettime()', test_file($config{CXX}, 'clock_gettime.cpp', '-lrt');
185 $config{HAS_EVENTFD} = run_test 'eventfd()', test_file($config{CXX}, 'eventfd.cpp');
186
187 if ($config{HAS_EPOLL} = run_test 'epoll', test_header($config{CXX}, 'sys/epoll.h')) {
188         $config{SOCKETENGINE} ||= 'epoll';
189 }
190
191 if ($config{HAS_KQUEUE} = run_test 'kqueue', test_file($config{CXX}, 'kqueue.cpp')) {
192         $config{SOCKETENGINE} ||= 'kqueue';
193 }
194
195 if ($config{HAS_PORTS} = run_test 'Solaris IOCP', test_header($config{CXX}, 'port.h')) {
196         $config{SOCKETENGINE} ||= 'ports';
197 }
198
199 if ($config{HAS_POLL} = run_test 'poll', test_header($config{CXX}, 'poll.h')) {
200         $config{SOCKETENGINE} ||= 'poll';
201 }
202
203 # Select is available on all platforms
204 $config{HAS_SELECT} = 1;
205 $config{SOCKETENGINE} ||= "select";
206
207 if (defined $opt_socketengine) {
208         my $cfgkey = "HAS_" . uc $opt_socketengine;
209         if ($config{$cfgkey} && -f "src/socketengines/socketengine_$opt_socketengine.cpp") {
210                 $config{SOCKETENGINE} = $opt_socketengine;
211         } else {
212                 print "Unable to use a socket engine which is not supported on this platform ($opt_socketengine)!\n";
213                 print "Available socket engines are:";
214                 foreach (<src/socketengines/socketengine_*.cpp>) {
215                         s/src\/socketengines\/socketengine_(\w+)\.cpp/$1/;
216                         print " $1" if $config{"HAS_" . uc $1};
217                 }
218                 print "\n";     
219                 exit 1;
220         }
221 }
222
223 print "Checking for libgnutls... ";
224 if (defined($config{HAS_GNUTLS}) && (($config{HAS_GNUTLS}) || ($config{HAS_GNUTLS} eq "y"))) {
225         if (defined($gnutls_ver) && ($gnutls_ver ne "")) {
226                 print "yes\n";
227                 $config{HAS_GNUTLS} = "y";
228         } else {
229                 print "no\n";
230                 $config{HAS_GNUTLS} = "n";
231         }
232 } else {
233         print "no\n";
234         $config{HAS_GNUTLS} = "n";
235 }
236
237 print "Checking for openssl... ";
238 if (defined($config{HAS_OPENSSL}) && (($config{HAS_OPENSSL}) || ($config{HAS_OPENSSL} eq "y"))) {
239         if (defined($openssl_ver) && ($openssl_ver ne "")) {
240                 print "yes\n";
241                 $config{HAS_OPENSSL} = "y";
242         } else {
243                 print "no\n";
244                 $config{HAS_OPENSSL} = "n";
245         }
246 } else {
247         print "no\n";
248         $config{HAS_OPENSSL} = "n";
249 }
250
251 if ($interactive)
252 {
253         # Clear the screen.
254         system 'tput', 'clear';
255
256         my $revision = get_revision();
257         chomp(my $version = `sh src/version.sh`);
258
259         # Display Introduction Message..
260         print <<"STOP" ;
261 Welcome to the \e[1mInspIRCd\e[0m configuration program! (\e[1minteractive mode\e[0m)
262 \e[1mPackage maintainers: Type ./configure --help for non-interactive help\e[0m
263
264 *** If you are unsure of any of these values, leave it blank for    ***
265 *** standard settings that will work, and your server will run      ***
266 *** using them. Please consult your IRC network admin if in doubt.  ***
267
268 Press \e[1m<RETURN>\e[0m to accept the default for any option, or enter
269 a new value. Please note: You will \e[1mHAVE\e[0m to read the docs
270 dir, otherwise you won't have a config file!
271
272 Your operating system is: \e[1;32m$^O\e[0m 
273 STOP
274         print "Your InspIRCd version is: \e[1;32m";
275         print $revision eq 'release' ? substr($version, 9) : substr($revision, 1);
276         print "\e[0m\n\n";
277         print "The following compiler has been detected: \e[1;32m$cxx{NAME} $cxx{VERSION}\e[0m ($config{CXX})\n\n";
278
279         # Check that the user actually wants this version.
280         if (index($version, '+') != -1) {
281                 print <<"EOW" ;
282 \e[1;31mWARNING!\e[0m You are building a development version. This contains code which has
283 not been tested as heavily and may contain various faults which could seriously
284 affect the running of your server. It is recommended that you use a stable
285 version instead.
286
287 You can obtain the latest stable version from https://github.com/inspircd/inspircd/releases
288 or by running `git checkout insp20` if you are installing from Git.
289
290 EOW
291         exit 1 unless prompt_bool(1, 'I understand this warning and want to continue anyway.', 0);
292         }
293
294         # Directory Settings..
295         my $tmpbase = $config{BASE_DIR};
296         $config{BASE_DIR} = prompt_dir(1, 'What directory do you wish to install the InspIRCd base?', $config{BASE_DIR});
297         if ($tmpbase ne $config{BASE_DIR}) {
298                 $config{CONFIG_DIR} = rel2abs($config{BASE_DIR}."/conf");
299                 $config{MODULE_DIR} = rel2abs($config{BASE_DIR}."/modules");
300                 $config{DATA_DIR} = rel2abs($config{BASE_DIR}."/data");
301                 $config{LOG_DIR} = rel2abs($config{BASE_DIR}."/logs");
302                 $config{BINARY_DIR} = rel2abs($config{BASE_DIR}."/bin");
303         }
304
305         $config{BINARY_DIR} = prompt_dir(1, 'In what directory should the InspIRCd binary be placed?', $config{BINARY_DIR});
306         $config{CONFIG_DIR} = prompt_dir(1, 'In what directory are the configuration files to be stored?', $config{CONFIG_DIR});
307         $config{DATA_DIR} = prompt_dir(1, 'In what directory are variable data files to be stored?', $config{DATA_DIR});
308         $config{LOG_DIR} = prompt_dir(1, 'In what directory are log files to be stored?', $config{LOG_DIR});
309         $config{MODULE_DIR} = prompt_dir(1, 'In what directory are the modules to be placed?', $config{MODULE_DIR});
310
311         my $chose_hiperf = 0;
312         if ($config{HAS_KQUEUE}) {
313                 $config{USE_KQUEUE} = prompt_bool(1, 'Your operating system has support for the high performance kqueue socket engine. Would you like to enable it?', 1);
314                 if ($config{USE_KQUEUE}) {
315                         $config{SOCKETENGINE} = "kqueue";
316                         $chose_hiperf = 1;
317                 }
318         }
319         if ($config{HAS_EPOLL}) {
320                 $config{USE_EPOLL} = prompt_bool(1, 'Your operating system has support for the high performance epoll socket engine. Would you like to enable it?', 1);
321                 if ($config{USE_EPOLL}) {
322                         $config{SOCKETENGINE} = "epoll";
323                         $chose_hiperf = 1;
324                 }
325         }
326         if ($config{HAS_PORTS}) {
327                 $config{USE_PORTS} = prompt_bool(1, 'Your operating system has support for the high performance IOCP socket engine. Would you like to enable it?', 1);
328                 if ($config{USE_PORTS}) {
329                         $config{SOCKETENGINE} = "ports";
330                         $chose_hiperf = 1;
331                 }
332         }
333
334         if (!$chose_hiperf && $config{HAS_POLL}) {
335                 $config{USE_POLL} = prompt_bool(1, 'Your operating system has support for the mid performance poll socket engine. Would you like to enable it?', 1);
336                 if ($config{USE_POLL}) {
337                         $config{SOCKETENGINE} = "poll";
338                 }
339         }
340         unless ($chose_hiperf || $config{USE_POLL})
341         {
342                 print "No high-performance socket engines are available, or you chose not to enable one. Defaulting to select() engine.\n\n";
343                 $config{SOCKETENGINE} = "select";
344         }
345
346         if ($config{HAS_GNUTLS} eq "y" || $config{HAS_OPENSSL} eq "y")
347         {
348                 print "Detected GnuTLS version: \e[1;32m" . $gnutls_ver . "\e[0m\n";
349                 print "Detected OpenSSL version: \e[1;32m" . $openssl_ver . "\e[0m\n\n";
350
351                 $config{USE_SSL} = prompt_bool(1, 'One or more SSL libraries detected. Would you like to enable SSL support?', 1);
352                 if ($config{USE_SSL})
353                 {
354                         if ($config{HAS_GNUTLS} eq "y")
355                         {
356                                 $config{USE_GNUTLS} = prompt_bool(1, 'Would you like to enable SSL with m_ssl_gnutls (recommended)?', 1);
357                                 if ($config{USE_GNUTLS})
358                                 {
359                                         print "Using GnuTLS SSL module.\n\n";
360                                         unlink 'src/modules/m_ssl_gnutls.cpp' if -f 'src/modules/m_ssl_gnutls.cpp';
361                                         symlink "extra/m_ssl_gnutls.cpp", "src/modules/m_ssl_gnutls.cpp" or print STDERR "Symlink failed: $!\n";
362                                 }
363                         }
364
365                         if ($config{HAS_OPENSSL} eq "y")
366                         {
367                                 $config{USE_OPENSSL} = prompt_bool(1, 'Would you like to enable SSL with m_ssl_openssl (recommended)?', 1);
368                                 if ($config{USE_OPENSSL})
369                                 {
370                                         print "Using OpenSSL SSL module.\n\n";
371                                         unlink 'src/modules/m_ssl_openssl.cpp' if -f 'src/modules/m_ssl_openssl.cpp';
372                                         symlink "extra/m_ssl_openssl.cpp", "src/modules/m_ssl_openssl.cpp" or print STDERR "Symlink failed: $!\n";
373                                 }
374                         }
375                 }
376         }
377         else
378         {
379                 print "\nCould not detect OpenSSL or GnuTLS. Make sure pkg-config is installed and\n";
380                 print "is in your path.\n\n";
381         }
382 }
383
384 # We are on a POSIX system, we can enable POSIX extras without asking
385 symlink "extra/m_regex_posix.cpp", "src/modules/m_regex_posix.cpp";
386
387 if (($config{USE_GNUTLS}) && ($config{HAS_GNUTLS} ne "y"))
388 {
389         print "Sorry, but I couldn't detect GnuTLS. Make sure pkg-config is in your path.\n";
390         exit 1;
391 }
392 if (($config{USE_OPENSSL}) && ($config{HAS_OPENSSL} ne "y"))
393 {
394         print "Sorry, but I couldn't detect OpenSSL. Make sure pkg-config is in your path.\n";
395         exit 1;
396 }
397
398 if ($config{USE_GNUTLS} || $config{USE_OPENSSL}) {
399         if (my $val = prompt_bool($interactive, 'Would you like to generate SSL certificates now?', $interactive)) {
400                 unless (-r "$config{CONFIG_DIR}/key.pem" && -r "$config{CONFIG_DIR}/cert.pem" && -r "$config{CONFIG_DIR}/dhparams.pem") {
401                         unless (system './tools/genssl auto') {
402                                 print "\nCertificate generation complete, copying to config directory... ";
403                                 File::Copy::move("key.pem", "$config{CONFIG_DIR}/key.pem") or print STDERR "Could not copy key.pem!\n";
404                                 File::Copy::move("cert.pem", "$config{CONFIG_DIR}/cert.pem") or print STDERR "Could not copy cert.pem!\n";
405                                 File::Copy::move("dhparams.pem", "$config{CONFIG_DIR}/dhparams.pem") or print STDERR "Could not copy dhparams.pem!\n";
406                                 print "Done.\n\n";
407                         }
408                 } else {
409                         print "SSL certificates found, skipping.\n\n"
410                 }
411         } else {
412                 print "Skipping SSL certificate generation in non-interactive mode.\n\n";
413         }
414 } else {
415         print "Skipping SSL Certificate generation, SSL support is not available.\n\n";
416 }
417
418 print "Writing \e[1;32m.config.cache\e[0m ...\n";
419 write_configure_cache(%config);
420 writefiles();
421 dump_hash();
422
423 print "\n";
424 print "To build your server with these settings, please run '\e[1;32mmake\e[0m' now.\n";
425 if ($config{USE_GNUTLS} || $config{USE_OPENSSL}) {
426         print "Please note: for \e[1;32mSSL support\e[0m you will need to load required\n";
427         print "modules in your config. This configure script has added those modules to the\n";
428         print "build process. For more info, please refer to:\n";
429         print "\e[1;32mhttp://wiki.inspircd.org/Installation_From_Tarball\e[0m\n";
430 }
431 print "*** \e[1;32mRemember to edit your configuration files!!!\e[0m ***\n\n";
432
433 sub writefiles {
434         chomp(my $incos = `uname -n -s -r`);
435         chomp(my $version = `sh src/version.sh`);
436         my $revision = get_revision();
437         my $branch = "InspIRCd-0.0";
438         if ($version =~ /^(InspIRCd-[0-9]+\.[0-9]+)\.[0-9]+/)
439         {
440                 $branch = $1;
441         }
442         print "Writing \e[1;32mconfig.h\e[0m\n";
443         open(FILEHANDLE, ">include/config.h.tmp");
444         print FILEHANDLE <<EOF;
445 /* Auto generated by configure, do not modify! */
446 #pragma once
447
448 #define BRANCH "$branch"
449 #define VERSION "$version"
450 #define REVISION "$revision"
451 #define SYSTEM "$incos"
452 #define INSPIRCD_SOCKETENGINE_NAME "$config{SOCKETENGINE}"
453
454 #define CONFIG_PATH "$config{CONFIG_DIR}"
455 #define DATA_PATH "$config{DATA_DIR}"
456 #define LOG_PATH "$config{LOG_DIR}"
457 #define MOD_PATH "$config{MODULE_DIR}"
458
459 EOF
460
461         if ($config{HAS_EVENTFD}) {
462                 print FILEHANDLE "#define HAS_EVENTFD\n";
463         }
464         if ($config{HAS_CLOCK_GETTIME}) {
465                 print FILEHANDLE "#define HAS_CLOCK_GETTIME\n";
466         }
467
468         print FILEHANDLE "\n#include \"threadengines/threadengine_pthread.h\"\n";
469         close(FILEHANDLE);
470
471         unlink 'include/config.h';
472         rename 'include/config.h.tmp', 'include/config.h';
473
474         # Do this once here, and cache it in the .*.inc files,
475         # rather than attempting to read src/version.sh from
476         # compiled code -- we might not have the source to hand.
477
478         my @dotfiles = qw(main.mk inspircd);
479         push @dotfiles, 'org.inspircd.plist' if $^O eq 'darwin';
480
481         foreach my $file (@dotfiles) {
482                 open(FILEHANDLE, "make/template/$file") or die "Can't open make/template/$file: $!";
483                 $_ = join '', <FILEHANDLE>;
484                 close(FILEHANDLE);
485
486                 $config{COMPILER} = lc $cxx{NAME};
487                 $config{SYSTEM} = lc $^O;
488
489                 for my $var (qw(
490                         CXX COMPILER SYSTEM BASE_DIR CONFIG_DIR MODULE_DIR BINARY_DIR DATA_DIR UID SOCKETENGINE
491                 )) {
492                         s/\@$var\@/$config{$var}/g;
493                 }
494
495                 s/\@VERSION\@/$version/ if defined $version;
496
497                 if ($file eq 'main.mk') {
498                         print "Writing \e[1;32mGNUmakefile\e[0m ...\n";
499
500                         my $mk_tmp = $_;
501                         s/\@IFDEF (\S+)/ifdef $1/g;
502                         s/\@IFNDEF (\S+)/ifndef $1/g;
503                         s/\@IFEQ (\S+) (\S+)/ifeq ($1,$2)/g;
504                         s/\@IFNEQ (\S+) (\S+)/ifneq ($1,$2)/g;
505                         s/\@ELSIFEQ (\S+) (\S+)/else ifeq ($1,$2)/g;
506                         s/\@ELSE/else/g;
507                         s/\@ENDIF/endif/g;
508                         s/ *\@BSD_ONLY .*\n//g;
509                         s/\@GNU_ONLY //g;
510                         s/\@DO_EXPORT (.*)/export $1/g;
511                         open MKF, '>GNUmakefile' or die "Can't write to GNUmakefile: $!";
512                         print MKF $_;
513                         close MKF;
514
515                         print "Writing \e[1;32mBSDmakefile\e[0m ...\n";
516                         $_ = $mk_tmp;
517                         s/\@IFDEF (\S+)/.if defined($1)/g;
518                         s/\@IFNDEF (\S+)/.if !defined($1)/g;
519                         s/\@IFEQ (\S+) (\S+)/.if $1 == $2/g;
520                         s/\@IFNEQ (\S+) (\S+)/.if $1 != $2/g;
521                         s/\@ELSIFEQ (\S+) (\S+)/.elif $1 == $2/g;
522                         s/\@ELSE/.else/g;
523                         s/\@ENDIF/.endif/g;
524                         s/\@BSD_ONLY //g;
525                         s/ *\@GNU_ONLY .*\n//g;
526                         $mk_tmp = $_;
527                         $mk_tmp =~ s#\@DO_EXPORT (.*)#"MAKEENV += ".join ' ', map "$_='\${$_}'", split /\s/, $1#eg;
528                         open MKF, '>BSDmakefile' or die "Can't write to BSDmakefile: $!";
529                         print MKF $mk_tmp;
530                         close MKF;
531                 } else {
532                         print "Writing \e[1;32m$file\e[0m ...\n";
533                         open(FILEHANDLE, ">$file") or die("Can't write to $file: $!\n");
534                         print FILEHANDLE $_;
535                         close(FILEHANDLE);
536                 }
537         }
538
539         chmod 0750, 'inspircd';
540 }
541
542 # Routine to list out the extra/ modules that have been enabled.
543 # Note: when getting any filenames out and comparing, it's important to lc it if the
544 # file system is not case-sensitive (== Epoc, MacOS, OS/2 (incl DOS/DJGPP), VMS, Win32
545 # (incl NetWare, Symbian)). Cygwin may or may not be case-sensitive, depending on
546 # configuration, however, File::Spec does not currently tell us (it assumes Unix behavior).
547 sub list_extras () {
548         use File::Spec;
549         # @_ not used
550         my $srcdir = File::Spec->catdir("src", "modules");
551         my $abs_srcdir = File::Spec->rel2abs($srcdir);
552         local $_;
553         my $dd;
554         opendir $dd, File::Spec->catdir($abs_srcdir, "extra") or die (File::Spec->catdir($abs_srcdir, "extra") . ": $!\n");
555         my @extras = map { File::Spec->case_tolerant() ? lc($_) : $_ } (readdir($dd));
556         closedir $dd;
557         undef $dd;
558         opendir $dd, $abs_srcdir or die "$abs_srcdir: $!\n";
559         my @sources = map { File::Spec->case_tolerant() ? lc($_) : $_ } (readdir($dd));
560         closedir $dd;
561         undef $dd;
562         my $maxlen = (sort { $b <=> $a } (map {length($_)} (@extras)))[0];
563         my %extras = ();
564 EXTRA:  for my $extra (@extras) {
565                 next if (File::Spec->curdir() eq $extra || File::Spec->updir() eq $extra);
566                 my $abs_extra = File::Spec->catfile($abs_srcdir, "extra", $extra);
567                 my $abs_source = File::Spec->catfile($abs_srcdir, $extra);
568                 next unless ($extra =~ m/\.(cpp|h)$/ || (-d $abs_extra)); # C++ Source/Header, or directory
569                 if (-l $abs_source) {
570                         # Symlink, is it in the right place?
571                         my $targ = readlink($abs_source);
572                         my $abs_targ = File::Spec->rel2abs($targ, $abs_srcdir);
573                         if ($abs_targ eq $abs_extra) {
574                                 $extras{$extra} = "\e[32;1menabled\e[0m";
575                         } else {
576                                 $extras{$extra} = sprintf("\e[31;1mwrong symlink target (%s)\e[0m", $abs_targ);
577                         }
578                 } elsif (-e $abs_source) {
579                         my ($devext, $inoext) = stat($abs_extra);
580                         my ($devsrc, $inosrc, undef, $lnksrc) = stat($abs_source);
581                         if ($lnksrc > 1) {
582                                 if ($devsrc == $devext && $inosrc == $inoext) {
583                                         $extras{$extra} = "\e[32;1menabled\e[0m";
584                                 } else {
585                                         $extras{$extra} = sprintf("\e[31;1mwrong hardlink target (%d:%d)\e[0m", $devsrc, $inosrc);
586                                 }
587                         } else {
588                                 open my $extfd, "<", $abs_extra;
589                                 open my $srcfd, "<", $abs_source;
590                                 local $/ = undef;
591                                 if (scalar(<$extfd>) eq scalar(<$srcfd>)) {
592                                         $extras{$extra} = "\e[32;1menabled\e[0m";
593                                 } else {
594                                         $extras{$extra} = sprintf("\e[31;1mout of synch (re-copy)\e[0m");
595                                 }
596                         }
597                 } else {
598                         $extras{$extra} = "\e[33;1mdisabled\e[0m";
599                 }
600         }
601         # Now let's add dependency info
602         for my $extra (keys(%extras)) {
603                 next unless $extras{$extra} =~ m/enabled/; # only process enabled extras.
604                 my $abs_extra = File::Spec->catfile($abs_srcdir, "extra", $extra);
605                 my @deps = split /\s+/, get_property($abs_extra, 'ModDep');
606                 for my $dep (@deps) {
607                         if (exists($extras{$dep})) {
608                                 my $ref = \$extras{$dep}; # Take reference.
609                                 if ($$ref !~ m/needed by/) {
610                                         # First dependency found.
611                                         if ($$ref =~ m/enabled/) {
612                                                 $$ref .= " (needed by \e[32;1m$extra\e[0m";
613                                         } else {
614                                                 $$ref =~ s/\e\[.*?m//g; # Strip out previous coloring. Will be set in bold+red+blink later.
615                                                 $$ref .= " (needed by \e[0;32;1;5m$extra\e[0;31;1;5m";
616                                         }
617                                 } else {
618                                         if ($$ref =~ m/enabled/) {
619                                                 $$ref .= ", \e[32;1m$extra\e[0m";
620                                         } else {
621                                                 $$ref .= ", \e[0;32;1;5m$extra\e[0;31;1;5m";
622                                         }
623                                 }
624                         }
625                 }
626         }
627         for my $extra (sort {$a cmp $b} keys(%extras)) {
628                 my $text = $extras{$extra};
629                 if ($text =~ m/needed by/ && $text !~ m/enabled/) {
630                         printf "\e[31;1;5m%-*s = %s%s\e[0m\n", $maxlen, $extra, $text, ($text =~ m/needed by/ ? ")" : "");
631                 } else {
632                         printf "%-*s = %s%s\n", $maxlen, $extra, $text, ($text =~ m/needed by/ ? "\e[0m)" : "");
633                 }
634         }
635         return keys(%extras) if wantarray; # Can be used by manage_extras.
636 }
637
638 sub enable_extras (@) {
639         my (@extras) = @_;
640         for my $extra (@extras) {
641                 my $extrapath = "src/modules/extra/$extra";
642                 if (!-e $extrapath) {
643                         print STDERR "Cannot enable \e[32;1m$extra\e[0m : No such file or directory in src/modules/extra\n";
644                         next;
645                 }
646                 my $source = "src/modules/$extra";
647                 if (-e $source) {
648                         print STDERR "Cannot enable \e[32;1m$extra\e[0m : destination in src/modules exists (might already be enabled?)\n";
649                         next;
650                 }
651                 # Get dependencies, and add them to be processed.
652                 my @deps = split /\s+/, get_property($extrapath, 'ModDep');
653                 for my $dep (@deps) {
654                         next if scalar(grep { $_ eq $dep } (@extras)) > 0; # Skip if we're going to be enabling it anyway.
655                         if (!-e "src/modules/$dep" && !-e "include/$dep") {
656                                 if (-e "src/modules/extra/$dep") {
657                                         print STDERR "Will also enable extra \e[32;1m$dep\e[0m (needed by \e[32;1m$extra\e[0m)\n";
658                                         push @extras, $dep;
659                                 } else {
660                                         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";
661                                 }
662                         }
663                 }
664                 print "Enabling $extra ... \n";
665                 symlink "extra/$extra", $source or print STDERR "$source: Cannot link to 'extra/$extra': $!\n";
666         }
667 }
668
669 sub disable_extras (@)
670 {
671         opendir my $dd, "src/modules/extra/";
672         my @files = readdir($dd);
673         closedir $dd;
674         my (@extras) = @_;
675 EXTRA:  for my $extra (@extras) {
676                 my $extrapath = "src/modules/extra/$extra";
677                 my $source = "src/modules/$extra";
678                 if (!-e $extrapath) {
679                         print STDERR "Cannot disable \e[32;1m$extra\e[0m : Is not an extra\n";
680                         next;
681                 }
682                 if ((! -l $source) || readlink($source) ne "extra/$extra") {
683                         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";
684                         next;
685                 }
686                 # Check if anything needs this.
687                 for my $file (@files) {
688                         my @deps = split /\s+/, get_property("src/modules/extra/$file", 'ModDep');
689                         # File depends on this extra...
690                         if (scalar(grep { $_ eq $extra } @deps) > 0) {
691                                 # And is both enabled and not about to be disabled.
692                                 if (-e "src/modules/$file" && scalar(grep { $_ eq $file } @extras) < 1) {
693                                         print STDERR "Cannot disable \e[32;1m$extra\e[0m : is needed by \e[32;1m$file\e[0m\n";
694                                         next EXTRA;
695                                 }
696                         }
697                 }
698                 # Now remove.
699                 print "Disabling $extra ... \n";
700                 unlink "src/modules/$extra" or print STDERR "Cannot disable \e[32;1m$extra\e[0m : $!\n";
701         }
702 }