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