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