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