]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - configure
Rewrite the build system directive parser.
[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.10.0;
31 }
32
33 use feature ':5.10';
34 use strict;
35 use warnings FATAL => qw(all);
36
37 use File::Basename        qw(basename);
38 use File::Copy            ();
39 use File::Spec::Functions qw(rel2abs);
40 use Getopt::Long          qw(GetOptions);
41 use POSIX                 qw(getgid getuid);
42
43 use make::common;
44 use make::configure;
45 use make::console;
46 use make::directive;
47
48 my ($opt_binary_dir,
49     $opt_config_dir,
50     $opt_data_dir,
51     $opt_development,
52     $opt_disable_interactive,
53     $opt_distribution_label,
54     $opt_gid,
55     $opt_log_dir,
56     $opt_manual_dir,
57     $opt_module_dir,
58     $opt_prefix,
59     $opt_socketengine,
60     $opt_system,
61     $opt_uid);
62
63 sub list_extras ();
64
65 sub enable_extras (@);
66
67 sub disable_extras (@);
68
69 my @opt_enableextras;
70 my @opt_disableextras;
71
72 GetOptions(
73         'clean'  => \&cmd_clean,
74         'help'   => \&cmd_help,
75         'update' => \&cmd_update,
76
77         'development'          => \$opt_development,
78         'disable-interactive'  => \$opt_disable_interactive,
79         'distribution-label=s' => \$opt_distribution_label,
80         'binary-dir=s'         => \$opt_binary_dir,
81         'config-dir=s'         => \$opt_config_dir,
82         'data-dir=s'           => \$opt_data_dir,
83         'gid=s'                => \$opt_gid,
84         'log-dir=s'            => \$opt_log_dir,
85         'manual-dir=s'         => \$opt_manual_dir,
86         'module-dir=s'         => \$opt_module_dir,
87         'prefix=s'             => \$opt_prefix,
88         'socketengine=s'       => \$opt_socketengine,
89         'system'               => \$opt_system,
90         'uid=s'                => \$opt_uid,
91
92         # TODO: when the modulemanager rewrite is done these should be removed.
93         'disable-extras=s@' => \@opt_disableextras,
94         'enable-extras=s@'  => \@opt_enableextras,
95         'list-extras'       => sub { list_extras; exit 0; },
96 );
97
98 if (scalar(@opt_enableextras) + scalar(@opt_disableextras) > 0) {
99         @opt_enableextras = split /,/, join(',', @opt_enableextras);
100         @opt_disableextras = split /,/, join(',', @opt_disableextras);
101         enable_extras(@opt_enableextras);
102         disable_extras(@opt_disableextras);
103         list_extras;
104         print "Remember: YOU are responsible for making sure any libraries needed have been installed!\n";
105         exit 0;
106 }
107
108 our $interactive = !(
109         !-t STDIN ||
110         !-t STDOUT ||
111         defined $opt_binary_dir ||
112         defined $opt_config_dir ||
113         defined $opt_data_dir ||
114         defined $opt_development ||
115         defined $opt_disable_interactive ||
116         defined $opt_distribution_label ||
117         defined $opt_gid ||
118         defined $opt_log_dir ||
119         defined $opt_manual_dir ||
120         defined $opt_module_dir ||
121         defined $opt_prefix ||
122         defined $opt_socketengine ||
123         defined $opt_system ||
124         defined $opt_uid
125 );
126
127 my %version = get_version();
128 print_format "<|BOLD Configuring InspIRCd $version{FULL} on $^O.|>\n";
129
130 our %config;
131 if ($interactive) {
132         %config = read_configure_cache();
133         run_test CONFIGURE_CACHE_FILE, %config;
134         if (!defined $config{VERSION}) {
135                 $config{VERSION} = CONFIGURE_CACHE_VERSION;
136         } elsif ($config{VERSION} != CONFIGURE_CACHE_VERSION) {
137                 print_warning "ignoring contents of ${\CONFIGURE_CACHE_FILE} as it was generated by an incompatible version of $0!";
138                 %config = ('VERSION', CONFIGURE_CACHE_VERSION);
139         }
140 }
141
142 $config{CXX} = find_compiler($config{CXX} // $ENV{CXX});
143 unless ($config{CXX}) {
144         print "A suitable C++ compiler could not be detected on your system!\n";
145         print "Set the CXX environment variable to the compiler binary path if this is incorrect.\n";
146         exit 1; 
147 }
148 my %compiler = get_compiler_info($config{CXX});
149
150 $config{HAS_CLOCK_GETTIME} = run_test 'clock_gettime()', test_file($config{CXX}, 'clock_gettime.cpp', '-lrt');
151 $config{HAS_EVENTFD} = run_test 'eventfd()', test_file($config{CXX}, 'eventfd.cpp');
152
153 if ($config{HAS_EPOLL} = run_test 'epoll', test_header($config{CXX}, 'sys/epoll.h')) {
154         $config{SOCKETENGINE} //= 'epoll';
155 }
156
157 if ($config{HAS_KQUEUE} = run_test 'kqueue', test_file($config{CXX}, 'kqueue.cpp')) {
158         $config{SOCKETENGINE} //= 'kqueue';
159 }
160
161 if ($config{HAS_PORTS} = run_test 'Solaris IOCP', test_header($config{CXX}, 'port.h')) {
162         $config{SOCKETENGINE} //= 'ports';
163 }
164
165 if ($config{HAS_POLL} = run_test 'poll', test_header($config{CXX}, 'poll.h')) {
166         $config{SOCKETENGINE} //= 'poll';
167 }
168
169 # Select is available on all platforms
170 $config{HAS_SELECT} = 1;
171 $config{SOCKETENGINE} //= 'select';
172
173 if (defined $opt_socketengine) {
174         my $cfgkey = 'HAS_' . uc $opt_socketengine;
175         if ($config{$cfgkey} && -f "src/socketengines/socketengine_$opt_socketengine.cpp") {
176                 $config{SOCKETENGINE} = $opt_socketengine;
177         } else {
178                 print "Unable to use a socket engine which is not supported on this platform ($opt_socketengine)!\n";
179                 print "Available socket engines are:";
180                 foreach (<src/socketengines/socketengine_*.cpp>) {
181                         s/src\/socketengines\/socketengine_(\w+)\.cpp/$1/;
182                         print " $1" if $config{'HAS_' . uc $1};
183                 }
184                 print "\n";     
185                 exit 1;
186         }
187 }
188
189 # If the user has specified a distribution label then we use it in
190 # place of the label from src/version.sh or Git.
191 if (defined $opt_distribution_label) {
192         $version{LABEL} = $opt_distribution_label;
193 }
194
195 if (defined $opt_system) {
196         $config{BASE_DIR}   = $opt_prefix     // '/var/lib/inspircd';
197         $config{BINARY_DIR} = $opt_binary_dir // '/usr/sbin';
198         $config{CONFIG_DIR} = $opt_config_dir // '/etc/inspircd';
199         $config{DATA_DIR}   = $opt_data_dir   // '/var/inspircd';
200         $config{LOG_DIR}    = $opt_module_dir // '/var/log/inspircd';
201         $config{MANUAL_DIR} = $opt_manual_dir // '/usr/share/man/man1';
202         $config{MODULE_DIR} = $opt_module_dir // '/usr/lib/inspircd';
203 } else {
204         $config{BASE_DIR}   = $opt_prefix     // $config{BASE_DIR}   // rel2abs 'run';
205         $config{BINARY_DIR} = $opt_binary_dir // $config{BINARY_DIR} // rel2abs $config{BASE_DIR} . '/bin';
206         $config{CONFIG_DIR} = $opt_config_dir // $config{CONFIG_DIR} // rel2abs $config{BASE_DIR} . '/conf';
207         $config{DATA_DIR}   = $opt_data_dir   // $config{DATA_DIR}   // rel2abs $config{BASE_DIR} . '/data';
208         $config{LOG_DIR}    = $opt_log_dir    // $config{LOG_DIR}    // rel2abs $config{BASE_DIR} . '/logs';
209         $config{MANUAL_DIR} = $opt_manual_dir // $config{MANUAL_DIR} // rel2abs $config{BASE_DIR} . '/manuals';
210         $config{MODULE_DIR} = $opt_module_dir // $config{MODULE_DIR} // rel2abs $config{BASE_DIR} . '/modules';
211 }
212
213 # Parse --gid=123 or --gid=foo and extract the group id.
214 my @group;
215 if (defined $opt_gid) {
216         @group = $opt_gid =~ /^\d+$/ ? getgrgid($opt_gid) : getgrnam($opt_gid);
217         print_error "there is no '$opt_gid' group on this system!" unless @group;
218 } else {
219         @group = $opt_system ? getgrnam('irc') : getgrgid($config{GID} // getgid());
220         print_error "you need to specify a group to run as using '--gid [id|name]'!" unless @group;
221 }
222 $config{GROUP} = $group[0];
223 $config{GID}   = $group[2];
224
225 # Parse --uid=123 or --uid=foo and extract the user id.
226 my @user;
227 if (defined $opt_uid) {
228         @user = $opt_uid =~ /^\d+$/ ? getpwuid($opt_uid) : getpwnam($opt_uid);
229         print_error "there is no '$opt_uid' user on this system!" unless @user;
230 } else {
231         @user = $opt_system ? getpwnam('irc') : getpwuid($config{UID} // getuid());
232         print_error "you need to specify a user to run as using '--uid [id|name]'!" unless @user;
233 }
234 $config{USER} = $user[0];
235 $config{UID}  = $user[2];
236
237 # Clear the screen.
238 system 'tput', 'clear' if $interactive;
239
240 # Check that the user actually wants this version.
241 if ($version{LABEL} ne 'release') {
242         print_warning <<'EOW';
243 You are building a development version. This contains code which has
244 not been tested as heavily and may contain various faults which could seriously
245 affect the running of your server. It is recommended that you use a stable
246 version instead.
247
248 You can obtain the latest stable version from http://www.inspircd.org/ or by
249 running `git checkout insp20` if you are installing from Git.
250 EOW
251         if (!prompt_bool $interactive, 'I understand this warning and want to continue anyway.', $opt_development // 0) {
252                 say STDERR 'If you understand this warning and still want to continue pass the --development flag.' unless $interactive;
253                 exit 1;
254         }
255 }
256
257 # Configure directory settings.
258 my $question = <<"EOQ";
259 Currently, InspIRCd is configured with the following paths:
260
261 <|BOLD Base:|>   $config{BASE_DIR}
262 <|BOLD Binary:|> $config{BINARY_DIR}
263 <|BOLD Config:|> $config{CONFIG_DIR}
264 <|BOLD Data:|>   $config{DATA_DIR}
265 <|BOLD Log:|>    $config{LOG_DIR}
266 <|BOLD Manual:|> $config{MANUAL_DIR}
267 <|BOLD Module:|> $config{MODULE_DIR}
268
269 Do you want to change these settings?
270 EOQ
271 if (prompt_bool $interactive, $question, 0) {
272         my $original_base_dir = $config{BASE_DIR};
273         $config{BASE_DIR} = prompt_dir $interactive, 'In what directory do you wish to install the InspIRCd base?', $config{BASE_DIR};
274         foreach my $key (qw(BINARY_DIR CONFIG_DIR DATA_DIR LOG_DIR MANUAL_DIR MODULE_DIR)) {
275                 $config{$key} =~ s/^\Q$original_base_dir\E/$config{BASE_DIR}/;
276         }
277         $config{BINARY_DIR} = prompt_dir $interactive, 'In what directory should the InspIRCd binary be placed?', $config{BINARY_DIR};
278         $config{CONFIG_DIR} = prompt_dir $interactive, 'In what directory are configuration files to be stored?', $config{CONFIG_DIR};
279         $config{DATA_DIR}   = prompt_dir $interactive, 'In what directory are variable data files to be stored?', $config{DATA_DIR};
280         $config{LOG_DIR}    = prompt_dir $interactive, 'In what directory are log files to be stored?',           $config{LOG_DIR};
281         $config{MANUAL_DIR} = prompt_dir $interactive, 'In what directory are manual pages to be placed?',        $config{MANUAL_DIR};
282         $config{MODULE_DIR} = prompt_dir $interactive, 'In what directory are modules to be placed?',             $config{MODULE_DIR};
283 }
284
285 # Configure module settings.
286 $question = <<'EOQ';
287 Currently, InspIRCd is configured to automatically enable all available extra modules.
288
289 Would you like to enable extra modules manually?
290 EOQ
291 if (prompt_bool $interactive, $question, 0) {
292         foreach my $extra (<src/modules/extra/m_*.cpp>) {
293                 my $module_name = basename $extra, '.cpp';
294                 if (prompt_bool $interactive, "Would you like to enable $module_name?", 0) {
295                         enable_extras "$module_name.cpp";
296                 }
297         }
298 } else {
299         # TODO: finish modulemanager rewrite and replace this code with:
300         # system './modulemanager', 'enable', '--auto';
301         enable_extras 'm_ssl_gnutls.cpp' unless system 'pkg-config --exists gnutls >/dev/null 2>&1';
302         enable_extras 'm_ssl_mbedtls.cpp' if -e '/usr/include/mbedtls/ssl.h';
303         enable_extras 'm_ssl_openssl.cpp' unless system 'pkg-config --exists openssl >/dev/null 2>&1';
304 }
305
306 # Generate SSL certificates.
307 if (<src/modules/m_ssl_*.cpp> && prompt_bool $interactive, 'Would you like to generate SSL certificates now?', $interactive) {
308         system './tools/genssl', 'auto';
309 }
310
311 write_configure_cache %config;
312 parse_templates \%config, \%compiler, \%version;
313
314 print_format <<"EOM";
315
316 Configuration is complete! You have chosen to build with the following settings:
317
318 <|GREEN Compiler:|>
319   <|GREEN Binary:|>  $config{CXX}
320   <|GREEN Name:|>    $compiler{NAME}
321   <|GREEN Version:|> $compiler{VERSION}
322
323 <|GREEN Extra Modules:|>
324 EOM
325
326 for my $file (<src/modules/m_*>) {
327         my $module = basename $file, '.cpp';
328         say "  * $module" if -l $file;
329 }
330
331 print_format <<"EOM";
332
333 <|GREEN Paths:|>
334   <|GREEN Base:|>   $config{BASE_DIR}
335   <|GREEN Binary:|> $config{BINARY_DIR}
336   <|GREEN Config:|> $config{CONFIG_DIR}
337   <|GREEN Data:|>   $config{DATA_DIR}
338   <|GREEN Log:|>    $config{LOG_DIR}
339   <|GREEN Manual:|> $config{MANUAL_DIR}
340   <|GREEN Module:|> $config{MODULE_DIR}
341
342 <|GREEN Execution Group:|> $config{GROUP} ($config{GID})
343 <|GREEN Execution User:|>  $config{USER} ($config{UID})
344 <|GREEN Socket Engine:|>   $config{SOCKETENGINE}
345
346 To build with these settings run '<|GREEN make -j${\get_cpu_count}|>' now.
347
348 EOM
349
350 # Routine to list out the extra/ modules that have been enabled.
351 # Note: when getting any filenames out and comparing, it's important to lc it if the
352 # file system is not case-sensitive (== Epoc, MacOS, OS/2 (incl DOS/DJGPP), VMS, Win32
353 # (incl NetWare, Symbian)). Cygwin may or may not be case-sensitive, depending on
354 # configuration, however, File::Spec does not currently tell us (it assumes Unix behavior).
355 sub list_extras () {
356         use File::Spec;
357         # @_ not used
358         my $srcdir = File::Spec->catdir("src", "modules");
359         my $abs_srcdir = File::Spec->rel2abs($srcdir);
360         local $_;
361         my $dd;
362         opendir $dd, File::Spec->catdir($abs_srcdir, "extra") or die (File::Spec->catdir($abs_srcdir, "extra") . ": $!\n");
363         my @extras = map { File::Spec->case_tolerant() ? lc($_) : $_ } (readdir($dd));
364         closedir $dd;
365         undef $dd;
366         opendir $dd, $abs_srcdir or die "$abs_srcdir: $!\n";
367         my @sources = map { File::Spec->case_tolerant() ? lc($_) : $_ } (readdir($dd));
368         closedir $dd;
369         undef $dd;
370         my $maxlen = (sort { $b <=> $a } (map {length($_)} (@extras)))[0];
371         my %extras = ();
372 EXTRA:  for my $extra (@extras) {
373                 next if (File::Spec->curdir() eq $extra || File::Spec->updir() eq $extra);
374                 my $abs_extra = File::Spec->catfile($abs_srcdir, "extra", $extra);
375                 my $abs_source = File::Spec->catfile($abs_srcdir, $extra);
376                 next unless ($extra =~ m/\.(cpp|h)$/ || (-d $abs_extra)); # C++ Source/Header, or directory
377                 if (-l $abs_source) {
378                         # Symlink, is it in the right place?
379                         my $targ = readlink($abs_source);
380                         my $abs_targ = File::Spec->rel2abs($targ, $abs_srcdir);
381                         if ($abs_targ eq $abs_extra) {
382                                 $extras{$extra} = "\e[32;1menabled\e[0m";
383                         } else {
384                                 $extras{$extra} = sprintf("\e[31;1mwrong symlink target (%s)\e[0m", $abs_targ);
385                         }
386                 } elsif (-e $abs_source) {
387                         my ($devext, $inoext) = stat($abs_extra);
388                         my ($devsrc, $inosrc, undef, $lnksrc) = stat($abs_source);
389                         if ($lnksrc > 1) {
390                                 if ($devsrc == $devext && $inosrc == $inoext) {
391                                         $extras{$extra} = "\e[32;1menabled\e[0m";
392                                 } else {
393                                         $extras{$extra} = sprintf("\e[31;1mwrong hardlink target (%d:%d)\e[0m", $devsrc, $inosrc);
394                                 }
395                         } else {
396                                 open my $extfd, "<", $abs_extra;
397                                 open my $srcfd, "<", $abs_source;
398                                 local $/ = undef;
399                                 if (scalar(<$extfd>) eq scalar(<$srcfd>)) {
400                                         $extras{$extra} = "\e[32;1menabled\e[0m";
401                                 } else {
402                                         $extras{$extra} = sprintf("\e[31;1mout of synch (re-copy)\e[0m");
403                                 }
404                         }
405                 } else {
406                         $extras{$extra} = "\e[33;1mdisabled\e[0m";
407                 }
408         }
409         # Now let's add dependency info
410         for my $extra (keys(%extras)) {
411                 next unless $extras{$extra} =~ m/enabled/; # only process enabled extras.
412                 my $abs_extra = File::Spec->catfile($abs_srcdir, "extra", $extra);
413                 my @deps = split /\s+/, get_directive($abs_extra, 'ModDep', '');
414                 for my $dep (@deps) {
415                         if (exists($extras{$dep})) {
416                                 my $ref = \$extras{$dep}; # Take reference.
417                                 if ($$ref !~ m/needed by/) {
418                                         # First dependency found.
419                                         if ($$ref =~ m/enabled/) {
420                                                 $$ref .= " (needed by \e[32;1m$extra\e[0m";
421                                         } else {
422                                                 $$ref =~ s/\e\[.*?m//g; # Strip out previous coloring. Will be set in bold+red+blink later.
423                                                 $$ref .= " (needed by \e[0;32;1;5m$extra\e[0;31;1;5m";
424                                         }
425                                 } else {
426                                         if ($$ref =~ m/enabled/) {
427                                                 $$ref .= ", \e[32;1m$extra\e[0m";
428                                         } else {
429                                                 $$ref .= ", \e[0;32;1;5m$extra\e[0;31;1;5m";
430                                         }
431                                 }
432                         }
433                 }
434         }
435         for my $extra (sort {$a cmp $b} keys(%extras)) {
436                 my $text = $extras{$extra};
437                 if ($text =~ m/needed by/ && $text !~ m/enabled/) {
438                         printf "\e[31;1;5m%-*s = %s%s\e[0m\n", $maxlen, $extra, $text, ($text =~ m/needed by/ ? ")" : "");
439                 } else {
440                         printf "%-*s = %s%s\n", $maxlen, $extra, $text, ($text =~ m/needed by/ ? "\e[0m)" : "");
441                 }
442         }
443         return keys(%extras) if wantarray; # Can be used by manage_extras.
444 }
445
446 sub enable_extras (@) {
447         my (@extras) = @_;
448         for my $extra (@extras) {
449                 my $extrapath = "src/modules/extra/$extra";
450                 if (!-e $extrapath) {
451                         print STDERR "Cannot enable \e[32;1m$extra\e[0m : No such file or directory in src/modules/extra\n";
452                         next;
453                 }
454                 my $source = "src/modules/$extra";
455                 if (-e $source) {
456                         print STDERR "Cannot enable \e[32;1m$extra\e[0m : destination in src/modules exists (might already be enabled?)\n";
457                         next;
458                 }
459                 # Get dependencies, and add them to be processed.
460                 my @deps = split /\s+/, get_directive($extrapath, 'ModDep', '');
461                 for my $dep (@deps) {
462                         next if scalar(grep { $_ eq $dep } (@extras)) > 0; # Skip if we're going to be enabling it anyway.
463                         if (!-e "src/modules/$dep" && !-e "include/$dep") {
464                                 if (-e "src/modules/extra/$dep") {
465                                         print STDERR "Will also enable extra \e[32;1m$dep\e[0m (needed by \e[32;1m$extra\e[0m)\n";
466                                         push @extras, $dep;
467                                 } else {
468                                         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";
469                                 }
470                         }
471                 }
472                 print "Enabling $extra ... \n";
473                 symlink "extra/$extra", $source or print STDERR "$source: Cannot link to 'extra/$extra': $!\n";
474         }
475 }
476
477 sub disable_extras (@)
478 {
479         opendir my $dd, "src/modules/extra/";
480         my @files = readdir($dd);
481         closedir $dd;
482         my (@extras) = @_;
483 EXTRA:  for my $extra (@extras) {
484                 my $extrapath = "src/modules/extra/$extra";
485                 my $source = "src/modules/$extra";
486                 if (!-e $extrapath) {
487                         print STDERR "Cannot disable \e[32;1m$extra\e[0m : Is not an extra\n";
488                         next;
489                 }
490                 if ((! -l $source) || readlink($source) ne "extra/$extra") {
491                         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";
492                         next;
493                 }
494                 # Check if anything needs this.
495                 for my $file (@files) {
496                         my @deps = split /\s+/, get_directive("src/modules/extra/$file", 'ModDep', '');
497                         # File depends on this extra...
498                         if (scalar(grep { $_ eq $extra } @deps) > 0) {
499                                 # And is both enabled and not about to be disabled.
500                                 if (-e "src/modules/$file" && scalar(grep { $_ eq $file } @extras) < 1) {
501                                         print STDERR "Cannot disable \e[32;1m$extra\e[0m : is needed by \e[32;1m$file\e[0m\n";
502                                         next EXTRA;
503                                 }
504                         }
505                 }
506                 # Now remove.
507                 print "Disabling $extra ... \n";
508                 unlink "src/modules/$extra" or print STDERR "Cannot disable \e[32;1m$extra\e[0m : $!\n";
509         }
510 }