diff options
Diffstat (limited to 'make')
-rwxr-xr-x | make/calcdep.pl | 127 | ||||
-rw-r--r-- | make/common.pm | 131 | ||||
-rw-r--r-- | make/configure.pm | 600 | ||||
-rw-r--r-- | make/console.pm | 159 | ||||
-rw-r--r-- | make/directive.pm | 271 | ||||
-rw-r--r-- | make/gnutlscert.pm | 150 | ||||
-rw-r--r-- | make/opensslcert.pm | 66 | ||||
-rwxr-xr-x | make/run-cc.pl | 237 | ||||
-rw-r--r-- | make/template/config.h (renamed from make/check_strlcpy.cpp) | 24 | ||||
-rw-r--r-- | make/template/gdbargs | 4 | ||||
-rw-r--r-- | make/template/inspircd | 66 | ||||
-rw-r--r-- | make/template/inspircd-genssl.1 | 46 | ||||
-rw-r--r-- | make/template/inspircd.1 | 104 | ||||
-rw-r--r-- | make/template/inspircd.service | 35 | ||||
-rw-r--r-- | make/template/main.mk | 179 | ||||
-rw-r--r-- | make/template/org.inspircd.plist | 5 | ||||
-rw-r--r-- | make/test/clock_gettime.cpp (renamed from make/check_epoll.cpp) | 9 | ||||
-rw-r--r-- | make/test/compiler.cpp (renamed from make/check_stdint.cpp) | 22 | ||||
-rw-r--r-- | make/test/compiler_info.cpp | 41 | ||||
-rw-r--r-- | make/test/eventfd.cpp (renamed from make/check_eventfd.cpp) | 0 | ||||
-rw-r--r-- | make/test/kqueue.cpp (renamed from make/check_kqueue.cpp) | 2 | ||||
-rwxr-xr-x | make/unit-cc.pl | 86 | ||||
-rw-r--r-- | make/utilities.pm | 471 |
23 files changed, 1429 insertions, 1406 deletions
diff --git a/make/calcdep.pl b/make/calcdep.pl index 49506dd3b..99355efa4 100755 --- a/make/calcdep.pl +++ b/make/calcdep.pl @@ -19,15 +19,27 @@ # +BEGIN { + require 5.10.0; + unless (-f 'configure') { + print "Error: $0 must be run from the main source directory!\n"; + exit 1; + } +} + use strict; -use warnings; -use POSIX qw(getcwd); +use warnings FATAL => qw(all); + +use constant { + BUILDPATH => $ENV{BUILDPATH}, + SOURCEPATH => $ENV{SOURCEPATH} +}; sub find_output; sub gendep($); sub dep_cpp($$$); sub dep_so($); -sub dep_dir($); +sub dep_dir($$); sub run(); my %f2dep; @@ -36,21 +48,16 @@ run; exit 0; sub run() { - my $build = $ENV{BUILDPATH}; - mkdir $build; - chdir $build or die "Could not open build directory: $!"; + mkdir BUILDPATH; + chdir BUILDPATH or die "Could not open build directory: $!"; unlink 'include'; - symlink "$ENV{SOURCEPATH}/include", 'include'; + symlink "${\SOURCEPATH}/include", 'include'; mkdir $_ for qw/bin modules obj/; -# BSD make has a horribly annoying bug resulting in an extra chdir of the make process -# Create symlinks to work around it - symlink "../$_", "obj/$_" for qw/bin modules obj/; - $build = getcwd(); open MAKE, '>real.mk' or die "Could not write real.mk: $!"; - chdir "$ENV{SOURCEPATH}/src"; + chdir "${\SOURCEPATH}/src"; - if ($ENV{PURE_STATIC}) { + if ($ENV{INSPIRCD_STATIC}) { run_static(); } else { run_dynamic(); @@ -59,7 +66,6 @@ sub run() { } sub run_dynamic() { - my $build = $ENV{BUILDPATH}; print MAKE <<END; # DO NOT EDIT THIS FILE # It is autogenerated by make/calcdep.pl, and will be overwritten @@ -71,56 +77,56 @@ bad-target: \@echo "in order to set the correct environment variables" \@exit 1 -all: inspircd commands modules +all: inspircd modules END - my(@core_deps, @cmdlist, @modlist); + my(@core_deps, @modlist); for my $file (<*.cpp>, <modes/*.cpp>, <socketengines/*.cpp>, "threadengines/threadengine_pthread.cpp") { my $out = find_output $file; dep_cpp $file, $out, 'gen-o'; - next if $file =~ m#^socketengines/# && $file ne "socketengines/$ENV{SOCKETENGINE}.cpp"; + next if $file =~ m#^socketengines/# && $file ne "socketengines/socketengine_$ENV{SOCKETENGINE}.cpp"; + # Having a module in the src directory is a bad idea because it will be linked to the core binary + if ($file =~ /^(m|core)_.*\.cpp/) { + my $correctsubdir = ($file =~ /^m_/ ? "modules" : "coremods"); + print "Error: module $file is in the src directory, put it in src/$correctsubdir instead!\n"; + exit 1; + } push @core_deps, $out; } - for my $file (<commands/*.cpp>) { - my $out = dep_so $file; - push @cmdlist, $out; - } - - opendir my $moddir, 'modules'; - for my $file (sort readdir $moddir) { - next if $file =~ /^\./; - if (-e "modules/extra/$file" && !-l "modules/$file") { - # Incorrect symlink? - print "Replacing symlink for $file found in modules/extra\n"; - rename "modules/$file", "modules/$file~"; - symlink "extra/$file", "modules/$file"; - } - if ($file =~ /^m_/ && -d "modules/$file" && dep_dir "modules/$file") { - mkdir "$build/obj/$file"; - push @modlist, "modules/$file.so"; - } - if ($file =~ /^m_.*\.cpp$/) { - my $out = dep_so "modules/$file"; - push @modlist, $out; + foreach my $directory (qw(coremods modules)) { + opendir(my $moddir, $directory); + for my $file (sort readdir $moddir) { + next if $file =~ /^\./; + if ($directory eq 'modules' && -e "modules/extra/$file" && !-l "modules/$file") { + # Incorrect symlink? + print "Replacing symlink for $file found in modules/extra\n"; + rename "modules/$file", "modules/$file~"; + symlink "extra/$file", "modules/$file"; + } + if ($file =~ /^(?:core|m)_/ && -d "$directory/$file" && dep_dir "$directory/$file", "modules/$file") { + mkdir "${\BUILDPATH}/obj/$file"; + push @modlist, "modules/$file.so"; + } + if ($file =~ /^.*\.cpp$/) { + my $out = dep_so "$directory/$file"; + push @modlist, $out; + } } } my $core_mk = join ' ', @core_deps; - my $cmds = join ' ', @cmdlist; my $mods = join ' ', @modlist; print MAKE <<END; bin/inspircd: $core_mk - @\$(SOURCEPATH)/make/unit-cc.pl core-ld\$(VERBOSE) \$\@ \$^ \$> + @\$(SOURCEPATH)/make/unit-cc.pl core-ld \$\@ \$^ \$> inspircd: bin/inspircd -commands: $cmds - modules: $mods -.PHONY: all bad-target inspircd commands modules +.PHONY: all bad-target inspircd modules END } @@ -141,14 +147,14 @@ all: inspircd END my(@deps, @srcs); - for my $file (<*.cpp>, <modes/*.cpp>, <socketengines/*.cpp>, <commands/*.cpp>, + for my $file (<*.cpp>, <modes/*.cpp>, <socketengines/*.cpp>, <coremods/*.cpp>, <coremods/core_*/*.cpp>, <modules/*.cpp>, <modules/m_*/*.cpp>, "threadengines/threadengine_pthread.cpp") { my $out = find_output $file, 1; if ($out =~ m#obj/([^/]+)/[^/]+.o$#) { - mkdir "$ENV{BUILDPATH}/obj/$1"; + mkdir "${\BUILDPATH}/obj/$1"; } dep_cpp $file, $out, 'gen-o'; - next if $file =~ m#^socketengines/# && $file ne "socketengines/$ENV{SOCKETENGINE}.cpp"; + next if $file =~ m#^socketengines/# && $file ne "socketengines/socketengine_$ENV{SOCKETENGINE}.cpp"; push @deps, $out; push @srcs, $file; } @@ -158,10 +164,10 @@ END print MAKE <<END; obj/ld-extra.cmd: $core_src - \@\$(SOURCEPATH)/make/unit-cc.pl gen-ld\$(VERBOSE) \$\@ \$^ \$> + \@\$(SOURCEPATH)/make/unit-cc.pl gen-ld \$\@ \$^ \$> bin/inspircd: $core_mk obj/ld-extra.cmd - \@\$(SOURCEPATH)/make/unit-cc.pl static-ld\$(VERBOSE) \$\@ \$^ \$> + \@\$(SOURCEPATH)/make/unit-cc.pl static-ld \$\@ \$^ \$> inspircd: bin/inspircd @@ -173,11 +179,11 @@ END sub find_output { my($file, $static) = @_; my($path,$base) = $file =~ m#^((?:.*/)?)([^/]+)\.cpp# or die "Bad file $file"; - if ($path eq 'modules/' || $path eq 'commands/') { + if ($path eq 'modules/' || $path eq 'coremods/') { return $static ? "obj/$base.o" : "modules/$base.so"; } elsif ($path eq '' || $path eq 'modes/' || $path =~ /^[a-z]+engines\/$/) { return "obj/$base.o"; - } elsif ($path =~ m#modules/(m_.*)/#) { + } elsif ($path =~ m#modules/(m_.*)/# || $path =~ m#coremods/(core_.*)/#) { return "obj/$1/$base.o"; } else { die "Can't determine output for $file"; @@ -199,7 +205,7 @@ sub gendep($) { while (<$in>) { if (/^\s*#\s*include\s*"([^"]+)"/) { my $inc = $1; - next if $inc eq 'inspircd_version.h' && $f eq '../include/inspircd.h'; + next if $inc eq 'config.h' && $f eq '../include/inspircd.h'; my $found = 0; for my $loc ("$basedir/$inc", "../include/$inc") { next unless -e $loc; @@ -225,26 +231,19 @@ sub dep_cpp($$$) { gendep $file; print MAKE "$out: $file $f2dep{$file}\n"; - print MAKE "\t@\$(SOURCEPATH)/make/unit-cc.pl $type\$(VERBOSE) \$\@ \$(SOURCEPATH)/src/$file \$>\n"; + print MAKE "\t@\$(SOURCEPATH)/make/unit-cc.pl $type \$\@ \$(SOURCEPATH)/src/$file \$>\n"; } sub dep_so($) { my($file) = @_; my $out = find_output $file; - my $split = find_output $file, 1; - if ($ENV{SPLIT_CC}) { - dep_cpp $file, $split, 'gen-o'; - print MAKE "$out: $split\n"; - print MAKE "\t@\$(SOURCEPATH)/make/unit-cc.pl link-so\$(VERBOSE) \$\@ \$(SOURCEPATH)/src/$file \$>\n"; - } else { - dep_cpp $file, $out, 'gen-so'; - } + dep_cpp $file, $out, 'gen-so'; return $out; } -sub dep_dir($) { - my($dir) = @_; +sub dep_dir($$) { + my($dir, $outdir) = @_; my @ofiles; opendir DIR, $dir; for my $file (sort readdir DIR) { @@ -256,8 +255,8 @@ sub dep_dir($) { closedir DIR; if (@ofiles) { my $ofiles = join ' ', @ofiles; - print MAKE "$dir.so: $ofiles\n"; - print MAKE "\t@\$(SOURCEPATH)/make/unit-cc.pl link-dir\$(VERBOSE) \$\@ \$^ \$>\n"; + print MAKE "$outdir.so: $ofiles\n"; + print MAKE "\t@\$(SOURCEPATH)/make/unit-cc.pl link-dir \$\@ ${\SOURCEPATH}/src/$dir \$^ \$>\n"; return 1; } else { return 0; diff --git a/make/common.pm b/make/common.pm new file mode 100644 index 000000000..6ca280bec --- /dev/null +++ b/make/common.pm @@ -0,0 +1,131 @@ +# +# InspIRCd -- Internet Relay Chat Daemon +# +# Copyright (C) 2013-2017 Peter Powell <petpow@saberuk.com> +# +# This file is part of InspIRCd. InspIRCd is free software: you can +# redistribute it and/or modify it under the terms of the GNU General Public +# License as published by the Free Software Foundation, version 2. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +# details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + + +BEGIN { + require 5.10.0; +} + +package make::common; + +use feature ':5.10'; +use strict; +use warnings FATAL => qw(all); + +use Exporter qw(import); +use File::Path qw(mkpath); +use File::Spec::Functions qw(rel2abs); + +use make::console; + +our @EXPORT = qw(create_directory + get_cpu_count + get_version + read_config_file + write_config_file); + +sub create_directory($$) { + my ($location, $permissions) = @_; + return eval { + mkpath($location, 0, $permissions); + return 1; + } // 0; +} + +sub get_version { + state %version; + return %version if %version; + + # Attempt to retrieve version information from src/version.sh + chomp(my $vf = `sh src/version.sh 2>/dev/null`); + if ($vf =~ /^InspIRCd-([0-9]+)\.([0-9]+)\.([0-9]+)(?:-(\w+))?$/) { + %version = ( MAJOR => $1, MINOR => $2, PATCH => $3, LABEL => $4 ); + } + + # Attempt to retrieve missing version information from Git + chomp(my $gr = `git describe --tags 2>/dev/null`); + if ($gr =~ /^v([0-9]+)\.([0-9]+)\.([0-9]+)(?:-\d+-g(\w+))?$/) { + $version{MAJOR} //= $1; + $version{MINOR} //= $2; + $version{PATCH} //= $3; + $version{LABEL} = $4 if defined $4; + } + + # If the user has specified a distribution label then we use it in + # place of the label from src/version.sh or Git. + $version{LABEL} = shift // $version{LABEL}; + + # If any of these fields are missing then the user has deleted the + # version file and is not running from Git. Fill in the fields with + # dummy data so we don't get into trouble with undef values later. + $version{MAJOR} //= '0'; + $version{MINOR} //= '0'; + $version{PATCH} //= '0'; + + # If there is no label then the user is using a stable release which + # does not have a label attached. + if (defined $version{LABEL}) { + $version{FULL} = "$version{MAJOR}.$version{MINOR}.$version{PATCH}-$version{LABEL}" + } else { + $version{LABEL} = 'release'; + $version{FULL} = "$version{MAJOR}.$version{MINOR}.$version{PATCH}" + } + + return %version; +} + +sub get_cpu_count { + my $count = 1; + if ($^O =~ /bsd/) { + $count = `sysctl -n hw.ncpu 2>/dev/null` || 1; + } elsif ($^O eq 'darwin') { + $count = `sysctl -n hw.activecpu 2>/dev/null` || 1; + } elsif ($^O eq 'linux') { + $count = `getconf _NPROCESSORS_ONLN 2>/dev/null` || 1; + } elsif ($^O eq 'solaris') { + $count = `psrinfo -p 2>/dev/null` || 1; + } + chomp($count); + return $count; +} + +sub read_config_file($) { + my $path = shift; + my %config; + open(my $fh, $path) or return %config; + while (my $line = <$fh>) { + next if $line =~ /^\s*($|\#)/; + my ($key, $value) = ($line =~ /^(\S+)(?:\s(.*))?$/); + $config{$key} = $value; + } + close $fh; + return %config; +} + +sub write_config_file($%) { + my $path = shift; + my %config = @_; + open(my $fh, '>', $path) or print_error "unable to write to $path: $!"; + while (my ($key, $value) = each %config) { + $value //= ''; + say $fh "$key $value"; + } + close $fh; +} + +1; diff --git a/make/configure.pm b/make/configure.pm index 9b8e2d0e4..48bd8db38 100644 --- a/make/configure.pm +++ b/make/configure.pm @@ -1,7 +1,7 @@ # # InspIRCd -- Internet Relay Chat Daemon # -# Copyright (C) 2012 Peter Powell <petpow@saberuk.com> +# Copyright (C) 2012-2017 Peter Powell <petpow@saberuk.com> # Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net> # Copyright (C) 2007-2008 Craig Edwards <craigedwards@brainbox.cc> # Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org> @@ -21,289 +21,395 @@ # -package make::configure; +BEGIN { + require 5.10.0; +} -require 5.8.0; +package make::configure; +use feature ':5.10'; use strict; use warnings FATAL => qw(all); -use Exporter 'import'; -use POSIX; -use make::utilities; -our @EXPORT = qw(promptnumeric dumphash is_dir getmodules getrevision getcompilerflags getlinkerflags getdependencies nopedantic resolve_directory yesno showhelp promptstring_s module_installed); - -my $no_git = 0; - -sub yesno { - my ($flag,$prompt) = @_; - print "$prompt [\e[1;32m$main::config{$flag}\e[0m] -> "; - chomp(my $tmp = <STDIN>); - if ($tmp eq "") { $tmp = $main::config{$flag} } - if (($tmp eq "") || ($tmp =~ /^y/i)) - { - $main::config{$flag} = "y"; +use Cwd qw(getcwd); +use Exporter qw(import); +use File::Basename qw(basename dirname); +use File::Spec::Functions qw(catfile); + +use make::common; +use make::console; + +use constant CONFIGURE_DIRECTORY => '.configure'; +use constant CONFIGURE_CACHE_FILE => catfile(CONFIGURE_DIRECTORY, 'cache.cfg'); +use constant CONFIGURE_CACHE_VERSION => '1'; +use constant CONFIGURE_ERROR_PIPE => $ENV{INSPIRCD_VERBOSE} ? '' : '1>/dev/null 2>/dev/null'; + +our @EXPORT = qw(CONFIGURE_CACHE_FILE + CONFIGURE_CACHE_VERSION + cmd_clean + cmd_help + cmd_update + run_test + test_file + test_header + write_configure_cache + get_compiler_info + find_compiler + parse_templates); + +sub __get_socketengines { + my @socketengines; + foreach (<src/socketengines/socketengine_*.cpp>) { + s/src\/socketengines\/socketengine_(\w+)\.cpp/$1/; + push @socketengines, $1; } - else - { - $main::config{$flag} = "n"; - } - return; + return @socketengines; } -sub resolve_directory -{ - my $ret = $_[0]; - eval - { - use File::Spec; - $ret = File::Spec->rel2abs($_[0]); - }; - return $ret; -} +# TODO: when buildtool is done this can be mostly removed with +# the remainder being merged into parse_templates. +sub __get_template_settings($$$) { + + # These are actually hash references + my ($config, $compiler, $version) = @_; -sub getrevision { - if ($no_git) - { - return "0"; + # Start off by populating with the config + my %settings = %$config; + + # Compiler information + while (my ($key, $value) = each %{$compiler}) { + $settings{'COMPILER_' . $key} = $value; } - my $data = `git describe --tags 2>/dev/null`; - if ($data eq "") - { - $no_git = 1; - return '0'; + + # Version information + while (my ($key, $value) = each %{$version}) { + $settings{'VERSION_' . $key} = $value; } - chomp $data; # remove \n - return $data; + + # Miscellaneous information + $settings{CONFIGURE_DIRECTORY} = CONFIGURE_DIRECTORY; + $settings{CONFIGURE_CACHE_FILE} = CONFIGURE_CACHE_FILE; + $settings{SYSTEM_NAME} = lc $^O; + chomp($settings{SYSTEM_NAME_VERSION} = `uname -sr 2>/dev/null`); + + return %settings; } -sub getcompilerflags { - my ($file) = @_; - open(FLAGS, $file) or return ""; - while (<FLAGS>) { - if ($_ =~ /^\/\* \$CompileFlags: (.+) \*\/\r?$/) { - my $x = translate_functions($1, $file); - next if ($x eq ""); - close(FLAGS); - return $x; - } - } - close(FLAGS); - return ""; +sub __test_compiler($) { + my $compiler = shift; + return 0 unless run_test("`$compiler`", !system "$compiler -v ${\CONFIGURE_ERROR_PIPE}"); + return 0 unless run_test("`$compiler`", test_file($compiler, 'compiler.cpp', '-fno-rtti'), 'compatible'); + return 1; } -sub getlinkerflags { - my ($file) = @_; - open(FLAGS, $file) or return ""; - while (<FLAGS>) { - if ($_ =~ /^\/\* \$LinkerFlags: (.+) \*\/\r?$/) { - my $x = translate_functions($1, $file); - next if ($x eq ""); - close(FLAGS); - return $x; - } - } - close(FLAGS); - return ""; +sub cmd_clean { + unlink CONFIGURE_CACHE_FILE; } -sub getdependencies { - my ($file) = @_; - open(FLAGS, $file) or return ""; - while (<FLAGS>) { - if ($_ =~ /^\/\* \$ModDep: (.+) \*\/\r?$/) { - my $x = translate_functions($1, $file); - next if ($x eq ""); - close(FLAGS); - return $x; - } - } - close(FLAGS); - return ""; +sub cmd_help { + my $PWD = getcwd(); + my $SELIST = join ', ', __get_socketengines(); + print <<EOH; +Usage: $0 [options] + +When no options are specified, configure runs in interactive mode and you must +specify any required values manually. If one or more options are specified, +non-interactive configuration is started and any omitted values are defaulted. + +PATH OPTIONS + + --system Automatically set up the installation paths + for system-wide installation. + --prefix=[dir] The root install directory. If this is set then + all subdirectories will be adjusted accordingly. + [$PWD/run] + --binary-dir=[dir] The location where the main server binary is + stored. + [$PWD/run/bin] + --config-dir=[dir] The location where the configuration files and + SSL certificates are stored. + [$PWD/run/conf] + --data-dir=[dir] The location where the data files, such as the + pid file, are stored. + [$PWD/run/data] + --log-dir=[dir] The location where the log files are stored. + [$PWD/run/logs] + --manual-dir=[dir] The location where the manual files are stored. + [$PWD/run/manuals] + --module-dir=[dir] The location where the loadable modules are + stored. + [$PWD/run/modules] + +EXTRA MODULE OPTIONS + + --enable-extras=[extras] Enables a comma separated list of extra modules. + --disable-extras=[extras] Disables a comma separated list of extra modules. + --list-extras Shows the availability status of all extra + modules. + +MISC OPTIONS + + --clean Remove the configuration cache file and start + the interactive configuration wizard. + --disable-interactive Disables the interactive configuration wizard. + --distribution-label=[text] Sets a distribution specific version label in + the build configuration. + --gid=[id|name] Sets the group to run InspIRCd as. + --help Show this message and exit. + --socketengine=[name] Sets the socket engine to be used. Possible + values are $SELIST. + --uid=[id|name] Sets the user to run InspIRCd as. + --update Updates the build environment with the settings + from the cache. + + +FLAGS + + CXX=[name] Sets the C++ compiler to use when building the + server. If not specified then the build system + will search for c++, g++, clang++ or icpc. + +If you have any problems with configuring InspIRCd then visit our IRC channel +at irc.inspircd.org #InspIRCd for support. + +EOH + exit 0; } -sub nopedantic { - my ($file) = @_; - open(FLAGS, $file) or return ""; - while (<FLAGS>) { - if ($_ =~ /^\/\* \$NoPedantic \*\/\r?$/) { - my $x = translate_functions($_, $file); - next if ($x eq ""); - close(FLAGS); - return 1; - } - } - close(FLAGS); - return 0; +sub cmd_update { + print_error "You have not run $0 before. Please do this before trying to update the generated files." unless -f CONFIGURE_CACHE_FILE; + say 'Updating...'; + my %config = read_config_file(CONFIGURE_CACHE_FILE); + my %compiler = get_compiler_info($config{CXX}); + my %version = get_version $config{DISTRIBUTION}; + parse_templates(\%config, \%compiler, \%version); + say 'Update complete!'; + exit 0; } -sub getmodules -{ - my ($silent) = @_; +sub run_test($$;$) { + my ($what, $result, $adjective) = @_; + $adjective //= 'available'; + print_format "Checking whether <|GREEN $what|> is $adjective ... "; + print_format $result ? "<|GREEN yes|>\n" : "<|RED no|>\n"; + return $result; +} - my $i = 0; +sub test_file($$;$) { + my ($compiler, $file, $args) = @_; + my $status = 0; + $args //= ''; + $status ||= system "$compiler -o __test_$file make/test/$file $args ${\CONFIGURE_ERROR_PIPE}"; + $status ||= system "./__test_$file ${\CONFIGURE_ERROR_PIPE}"; + unlink "./__test_$file"; + return !$status; +} - if (!$silent) - { - print "Detecting modules "; - } +sub test_header($$;$) { + my ($compiler, $header, $args) = @_; + $args //= ''; + open(COMPILER, "| $compiler -E - $args ${\CONFIGURE_ERROR_PIPE}") or return 0; + print COMPILER "#include <$header>"; + close(COMPILER); + return !$?; +} - opendir(DIRHANDLE, "src/modules") or die("WTF, missing src/modules!"); - foreach my $name (sort readdir(DIRHANDLE)) - { - if ($name =~ /^m_(.+)\.cpp$/) - { - my $mod = $1; - $main::modlist[$i++] = $mod; - if (!$silent) - { - print "."; - } - } +sub write_configure_cache(%) { + unless (-e CONFIGURE_DIRECTORY) { + print_format "Creating <|GREEN ${\CONFIGURE_DIRECTORY}|> ...\n"; + create_directory CONFIGURE_DIRECTORY, 0750 or print_error "unable to create ${\CONFIGURE_DIRECTORY}: $!"; } - closedir(DIRHANDLE); - if (!$silent) - { - print "\nOk, $i modules.\n"; - } + print_format "Writing <|GREEN ${\CONFIGURE_CACHE_FILE}|> ...\n"; + my %config = @_; + write_config_file CONFIGURE_CACHE_FILE, %config; } -sub promptnumeric($$) -{ - my $continue = 0; - my ($prompt, $configitem) = @_; - while (!$continue) - { - print "Please enter the maximum $prompt?\n"; - print "[\e[1;32m$main::config{$configitem}\e[0m] -> "; - chomp(my $var = <STDIN>); - if ($var eq "") - { - $var = $main::config{$configitem}; - } - if ($var =~ /^\d+$/) { - # We don't care what the number is, set it and be on our way. - $main::config{$configitem} = $var; - $continue = 1; - print "\n"; - } else { - print "You must enter a number in this field. Please try again.\n\n"; - } +sub get_compiler_info($) { + my $binary = shift; + my %info = (NAME => 'Unknown', VERSION => '0.0'); + return %info if system "$binary -o __compiler_info make/test/compiler_info.cpp ${\CONFIGURE_ERROR_PIPE}"; + open(my $fh, '-|', './__compiler_info 2>/dev/null'); + while (my $line = <$fh>) { + $info{$1} = $2 if $line =~ /^([A-Z]+)\s(.+)$/; } + close $fh; + unlink './__compiler_info'; + return %info; } -sub module_installed($) -{ - my $module = shift; - eval("use $module;"); - return !$@; +sub find_compiler { + my @compilers = qw(c++ g++ clang++ icpc); + foreach my $compiler (shift // @compilers) { + return $compiler if __test_compiler $compiler; + return "xcrun $compiler" if $^O eq 'darwin' && __test_compiler "xcrun $compiler"; + } } -sub promptstring_s($$) -{ - my ($prompt,$default) = @_; - my $var; - print "$prompt\n"; - print "[\e[1;32m$default\e[0m] -> "; - chomp($var = <STDIN>); - $var = $default if $var eq ""; - print "\n"; - return $var; -} +sub parse_templates($$$) { + + # These are actually hash references + my ($config, $compiler, $version) = @_; + + # Collect settings to be used when generating files + my %settings = __get_template_settings($config, $compiler, $version); + + # Iterate through files in make/template. + foreach (<make/template/*>) { + print_format "Parsing <|GREEN $_|> ...\n"; + open(TEMPLATE, $_) or print_error "unable to read $_: $!"; + my (@lines, $mode, @platforms, %targets); + + # First pass: parse template variables and directives. + while (my $line = <TEMPLATE>) { + chomp $line; + + # Does this line match a variable? + while ($line =~ /(@(\w+?)@)/) { + my ($variable, $name) = ($1, $2); + if (defined $settings{$name}) { + $line =~ s/\Q$variable\E/$settings{$name}/; + } else { + print_warning "unknown template variable '$name' in $_!"; + last; + } + } -sub dumphash() -{ - print "\n\e[1;32mPre-build configuration is complete!\e[0m\n\n"; - print "\e[0mBase install path:\e[1;32m\t\t$main::config{BASE_DIR}\e[0m\n"; - print "\e[0mConfig path:\e[1;32m\t\t\t$main::config{CONFIG_DIR}\e[0m\n"; - print "\e[0mModule path:\e[1;32m\t\t\t$main::config{MODULE_DIR}\e[0m\n"; - print "\e[0mGCC Version Found:\e[1;32m\t\t$main::config{GCCVER}.$main::config{GCCMINOR}\e[0m\n"; - print "\e[0mCompiler program:\e[1;32m\t\t$main::config{CC}\e[0m\n"; - print "\e[0mGnuTLS Support:\e[1;32m\t\t\t$main::config{USE_GNUTLS}\e[0m\n"; - print "\e[0mOpenSSL Support:\e[1;32m\t\t$main::config{USE_OPENSSL}\e[0m\n\n"; - print "\e[1;32mImportant note: The maximum length values are now configured in the\e[0m\n"; - print "\e[1;32m configuration file, not in ./configure! See the <limits>\e[0m\n"; - print "\e[1;32m tag in the configuration file for more information.\e[0m\n\n"; -} + # Does this line match a directive? + if ($line =~ /^\s*%(\w+)\s+(.+)$/) { + if ($1 eq 'define') { + if ($settings{$2}) { + push @lines, "#define $2"; + } else { + push @lines, "#undef $2"; + } + } elsif ($1 eq 'mode') { + $mode = oct $2; + } elsif ($1 eq 'platform') { + push @platforms, $2; + } elsif ($1 eq 'target') { + if ($2 =~ /(\w+)\s(.+)/) { + $targets{$1} = $2; + } else { + $targets{DEFAULT} = $2; + } + } else { + print_warning "unknown template command '$1' in $_!"; + push @lines, $line; + } + next; + } + push @lines, $line; + } + close(TEMPLATE); -sub is_dir -{ - my ($path) = @_; - if (chdir($path)) - { - chdir($main::this); - return 1; - } - else - { - # Just in case.. - chdir($main::this); - return 0; - } -} + # Only proceed if this file should be templated on this platform. + if ($#platforms < 0 || grep { $_ eq $^O } @platforms) { -sub showhelp -{ - chomp(my $PWD = `pwd`); - print <<EOH; -Usage: configure [options] - -*** NOTE: NON-INTERACTIVE CONFIGURE IS *NOT* SUPPORTED BY THE *** -*** INSPIRCD DEVELOPMENT TEAM. DO NOT ASK FOR HELP REGARDING *** -*** NON-INTERACTIVE CONFIGURE ON THE FORUMS OR ON IRC! *** - -Options: [defaults in brackets after descriptions] - -When no options are specified, interactive -configuration is started and you must specify -any required values manually. If one or more -options are specified, non-interactive configuration -is started, and any omitted values are defaulted. - -Arguments with a single \"-\" symbol, as in -InspIRCd 1.0.x, are also allowed. - - --disable-interactive Sets no options itself, but - will disable any interactive prompting. - --update Update makefiles and dependencies - --clean Remove .config.cache file and go interactive - --enable-gnutls Enable GnuTLS module [no] - --enable-openssl Enable OpenSSL module [no] - --enable-epoll Enable epoll() where supported [set] - --enable-kqueue Enable kqueue() where supported [set] - --disable-epoll Do not enable epoll(), fall back - to select() [not set] - --disable-kqueue Do not enable kqueue(), fall back - to select() [not set] - --with-cc=[filename] Use an alternative compiler to - build InspIRCd [g++] - --with-maxbuf=[n] Change the per message buffer size [512] - DO NOT ALTER THIS OPTION WITHOUT GOOD REASON - AS IT *WILL* BREAK CLIENTS!!! - --prefix=[directory] Base directory to install into (if defined, - can automatically define config, module, bin - and library dirs as subdirectories of prefix) - [$PWD] - --config-dir=[directory] Config file directory for config and SSL certs - [$PWD/run/conf] - --log-dir=[directory] Log file directory for logs - [$PWD/run/logs] - --data-dir=[directory] Data directory for variable data, such as the - permchannel configuration and the XLine database - [$PWD/run/data] - --module-dir=[directory] Modules directory for loadable modules - [$PWD/run/modules] - --binary-dir=[directory] Binaries directory for core binary - [$PWD/run/bin] - --list-extras Show current status of extra modules - --enable-extras=[extras] Enable the specified list of extras - --disable-extras=[extras] Disable the specified list of extras - --help Show this help text and exit + # Add a default target if the template has not defined one. + unless (scalar keys %targets) { + $targets{DEFAULT} = catfile(CONFIGURE_DIRECTORY, basename $_); + } -EOH - exit(0); + # Second pass: parse makefile junk and write files. + while (my ($name, $target) = each %targets) { + + # TODO: when buildtool is done this mess can be removed completely. + my @final_lines; + foreach my $line (@lines) { + + # Are we parsing a makefile and does this line match a statement? + if ($name =~ /(?:BSD|GNU)_MAKE/ && $line =~ /^\s*\@(\w+)(?:\s+(.+))?$/) { + my @tokens = split /\s/, $2 if defined $2; + if ($1 eq 'DO_EXPORT' && defined $2) { + if ($name eq 'BSD_MAKE') { + foreach my $variable (@tokens) { + push @final_lines, "MAKEENV += $variable='\${$variable}'"; + } + } elsif ($name eq 'GNU_MAKE') { + push @final_lines, "export $2"; + } + } elsif ($1 eq 'ELSE') { + if ($name eq 'BSD_MAKE') { + push @final_lines, ".else"; + } elsif ($name eq 'GNU_MAKE') { + push @final_lines, "else"; + } + } elsif ($1 eq 'ENDIF') { + if ($name eq 'BSD_MAKE') { + push @final_lines, ".endif"; + } elsif ($name eq 'GNU_MAKE') { + push @final_lines, "endif"; + } + } elsif ($1 eq 'ELSIFEQ' && defined $2) { + if ($name eq 'BSD_MAKE') { + push @final_lines, ".elif $tokens[0] == $tokens[1]"; + } elsif ($name eq 'GNU_MAKE') { + push @final_lines, "else ifeq ($tokens[0], $tokens[1])"; + } + } elsif ($1 eq 'IFDEF' && defined $2) { + if ($name eq 'BSD_MAKE') { + push @final_lines, ".if defined($2)"; + } elsif ($name eq 'GNU_MAKE') { + push @final_lines, "ifdef $2"; + } + } elsif ($1 eq 'IFEQ' && defined $2) { + if ($name eq 'BSD_MAKE') { + push @final_lines, ".if $tokens[0] == $tokens[1]"; + } elsif ($name eq 'GNU_MAKE') { + push @final_lines, "ifeq ($tokens[0],$tokens[1])"; + } + } elsif ($1 eq 'IFNEQ' && defined $2) { + if ($name eq 'BSD_MAKE') { + push @final_lines, ".if $tokens[0] != $tokens[1]"; + } elsif ($name eq 'GNU_MAKE') { + push @final_lines, "ifneq ($tokens[0],$tokens[1])"; + } + } elsif ($1 eq 'IFNDEF' && defined $2) { + if ($name eq 'BSD_MAKE') { + push @final_lines, ".if !defined($2)"; + } elsif ($name eq 'GNU_MAKE') { + push @final_lines, "ifndef $2"; + } + } elsif ($1 eq 'TARGET' && defined $2) { + if ($tokens[0] eq $name) { + push @final_lines, substr($2, length($tokens[0]) + 1); + } + } elsif ($1 !~ /[A-Z]/) { + # HACK: silently ignore if lower case as these are probably make commands. + push @final_lines, $line; + } else { + print_warning "unknown template command '$1' in $_!"; + push @final_lines, $line; + } + next; + } + + push @final_lines, $line; + } + + # Create the directory if it doesn't already exist. + my $directory = dirname $target; + unless (-e $directory) { + print_format "Creating <|GREEN $directory|> ...\n"; + create_directory $directory, 0750 or print_error "unable to create $directory: $!"; + }; + + # Write the template file. + print_format "Writing <|GREEN $target|> ...\n"; + open(TARGET, '>', $target) or print_error "unable to write $target: $!"; + foreach (@final_lines) { + say TARGET $_; + } + close(TARGET); + + # Set file permissions. + if (defined $mode) { + chmod $mode, $target; + } + } + } + } } 1; - diff --git a/make/console.pm b/make/console.pm new file mode 100644 index 000000000..0d3c1b38d --- /dev/null +++ b/make/console.pm @@ -0,0 +1,159 @@ +# +# InspIRCd -- Internet Relay Chat Daemon +# +# Copyright (C) 2014-2017 Peter Powell <petpow@saberuk.com> +# +# This file is part of InspIRCd. InspIRCd is free software: you can +# redistribute it and/or modify it under the terms of the GNU General Public +# License as published by the Free Software Foundation, version 2. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +# details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + + +package make::console; + +BEGIN { + require 5.10.0; +} + +use feature ':5.10'; +use strict; +use warnings FATAL => qw(all); + +use Class::Struct qw(struct); +use Exporter qw(import); +use File::Path qw(mkpath); +use File::Spec::Functions qw(rel2abs); + +our @EXPORT = qw(command + execute_command + print_format + print_error + print_warning + prompt_bool + prompt_dir + prompt_string); + +my %FORMAT_CODES = ( + DEFAULT => "\e[0m", + BOLD => "\e[1m", + UNDERLINE => "\e[4m", + + RED => "\e[1;31m", + GREEN => "\e[1;32m", + YELLOW => "\e[1;33m", + BLUE => "\e[1;34m" +); + +my %commands; + +struct 'command' => { + 'callback' => '$', + 'description' => '$', +}; + +sub __console_format($$) { + my ($name, $data) = @_; + return $data unless -t STDOUT; + return $FORMAT_CODES{uc $name} . $data . $FORMAT_CODES{DEFAULT}; +} + +sub print_format($;$) { + my $message = shift; + my $stream = shift // *STDOUT; + while ($message =~ /(<\|(\S+)\s(.*?)\|>)/) { + my $formatted = __console_format $2, $3; + $message =~ s/\Q$1\E/$formatted/; + } + print { $stream } $message; +} + +sub print_error { + print_format "<|RED Error:|> ", *STDERR; + for my $line (@_) { + print_format "$line\n", *STDERR; + } + exit 1; +} + +sub print_warning { + print_format "<|YELLOW Warning:|> ", *STDERR; + for my $line (@_) { + print_format "$line\n", *STDERR; + } +} + +sub prompt_bool($$$) { + my ($interactive, $question, $default) = @_; + my $answer = prompt_string($interactive, $question, $default ? 'y' : 'n'); + return $answer =~ /y/i; +} + +sub prompt_dir($$$;$) { + my ($interactive, $question, $default, $create_now) = @_; + my ($answer, $create); + do { + $answer = rel2abs(prompt_string($interactive, $question, $default)); + $create = prompt_bool($interactive && !-d $answer, "$answer does not exist. Create it?", 'y'); + if ($create && $create_now) { + unless (create_directory $answer, 0750) { + print_warning "unable to create $answer: $!\n"; + $create = 0; + } + } + } while (!$create); + return $answer; +} + +sub prompt_string($$$) { + my ($interactive, $question, $default) = @_; + return $default unless $interactive; + print_format "$question\n"; + print_format "[<|GREEN $default|>] => "; + chomp(my $answer = <STDIN>); + say ''; + return $answer ? $answer : $default; +} + +sub command($$$) { + my ($name, $description, $callback) = @_; + $commands{$name} = command->new; + $commands{$name}->callback($callback); + $commands{$name}->description($description); +} + +sub command_alias($$) { + my ($source, $target) = @_; + command $source, undef, sub(@) { + execute_command $target, @_; + }; +} + +sub execute_command(@) { + my $command = defined $_[0] ? lc shift : 'help'; + if ($command eq 'help') { + print_format "<|GREEN Usage:|> $0 <<|UNDERLINE COMMAND|>> [<|UNDERLINE OPTIONS...|>]\n\n"; + print_format "<|GREEN Commands:|>\n"; + for my $key (sort keys %commands) { + next unless defined $commands{$key}->description; + my $name = sprintf "%-15s", $key; + my $description = $commands{$key}->description; + print_format " <|BOLD $name|> # $description\n"; + } + exit 0; + } elsif (!$commands{$command}) { + print_error "no command called <|BOLD $command|> exists!", + "See <|BOLD $0 help|> for a list of commands."; + } else { + return $commands{$command}->callback->(@_); + } +} + +1; diff --git a/make/directive.pm b/make/directive.pm new file mode 100644 index 000000000..4501fc5ec --- /dev/null +++ b/make/directive.pm @@ -0,0 +1,271 @@ +# +# InspIRCd -- Internet Relay Chat Daemon +# +# Copyright (C) 2016 Peter Powell <petpow@saberuk.com> +# +# This file is part of InspIRCd. InspIRCd is free software: you can +# redistribute it and/or modify it under the terms of the GNU General Public +# License as published by the Free Software Foundation, version 2. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +# details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + + +package make::directive; + +BEGIN { + require 5.10.0; +} + +use feature ':5.10'; +use strict; +use warnings FATAL => qw(all); + +use File::Basename qw(basename); +use Exporter qw(import); + +use make::configure; +use make::console; + +use constant DIRECTIVE_ERROR_PIPE => $ENV{INSPIRCD_VERBOSE} ? '' : '2>/dev/null'; + +our @EXPORT = qw(get_directive + execute_functions); + +sub get_directive($$;$) +{ + my ($file, $property, $default) = @_; + open(MODULE, $file) or return $default; + + my $value = ''; + while (<MODULE>) { + if ($_ =~ /^\/\* \$(\S+): (.+) \*\/$/ || $_ =~ /^\/\/\/ \$(\S+): (.+)/) { + next unless $1 eq $property; + $value .= ' ' . execute_functions($file, $1, $2); + } + } + close(MODULE); + + # Strip all extraneous whitespace. + $value =~ s/^\s+|\s+$//g; + return $value || $default; +} + +sub execute_functions($$$) { + my ($file, $name, $line) = @_; + + # NOTE: we have to use 'our' instead of 'my' here because of a Perl bug. + for (our @parameters = (); $line =~ /([a-z_]+)\((?:\s*"([^"]*)(?{push @parameters, $2})"\s*)*\)/; undef @parameters) { + my $sub = make::directive->can("__function_$1"); + print_error "unknown $name directive '$1' in $file!" unless $sub; + + # Call the subroutine and replace the function. + my $result = $sub->($file, @parameters); + if (defined $result) { + $line = $` . $result . $'; + next; + } + + # If the subroutine returns undef then it is a sign that we should + # disregard the rest of the line and stop processing it. + $line = $`; + } + + return $line; +} + +sub __environment { + my ($prefix, $suffix) = @_; + $suffix =~ s/[-.]/_/g; + $suffix =~ s/[^A-Za-z0-9_]//g; + return $prefix . uc $suffix; +} + +sub __error { + my ($file, @message) = @_; + push @message, ''; + + # If we have package details then suggest to the user that they check + # that they have the packages installed.= + my $dependencies = get_directive($file, 'PackageInfo'); + if (defined $dependencies) { + my @packages = sort grep { /^\S+$/ } split /\s/, $dependencies; + push @message, 'You should make sure you have the following packages installed:'; + for (@packages) { + push @message, " * $_"; + } + } else { + push @message, 'You should make sure that you have all of the required dependencies'; + push @message, 'for this module installed.'; + } + push @message, ''; + + # If we have author information then tell the user to report the bug + # to them. Otherwise, assume it is a bundled module and tell the user + # to report it to the InspIRCd issue tracker. + my $author = get_directive($file, 'ModAuthor'); + if (defined $author) { + push @message, 'If you believe this error to be a bug then you can try to contact the'; + push @message, 'author of this module:'; + my $author_mail = get_directive($file, 'ModAuthorMail'); + if (defined $author_mail) { + push @message, " * $author <$author_mail>"; + } else { + push @message, " * $author"; + } + } else { + push @message, 'If you believe this error to be a bug then you can file a bug report'; + push @message, 'at https://github.com/inspircd/inspircd/issues'; + } + push @message, ''; + + push @message, 'If you would like help with fixing this problem then visit our IRC'; + push @message, 'channel at irc.inspircd.org #InspIRCd for support.'; + push @message, ''; + + print_error @message; +} + +sub __function_error { + my ($file, @messages) = @_; + __error $file, @messages; +} + +sub __function_execute { + my ($file, $command, $environment, $defaults) = @_; + + # Try to execute the command... + chomp(my $result = `$command ${\DIRECTIVE_ERROR_PIPE}`); + unless ($?) { + print_format "Execution of `<|GREEN $command|>` succeeded: <|BOLD $result|>\n"; + return $result; + } + + # If looking up with pkg-config fails then check the environment... + if (defined $environment && $environment ne '') { + $environment = __environment 'INSPIRCD_', $environment; + if (defined $ENV{$environment}) { + print_format "Execution of `<|GREEN $command|>` failed; using the environment: <|BOLD $ENV{$environment}|>\n"; + return $ENV{$environment}; + } + } + + # If all else fails then look for the defaults.. + if (defined $defaults) { + print_format "Execution of `<|GREEN $command|>` failed; using the defaults: <|BOLD $defaults|>\n"; + return $defaults; + } + + # Executing the command failed and we don't have any defaults so give up. + __error $file, "`<|GREEN $command|>` exited with a non-zero exit code!"; +} + +sub __function_find_compiler_flags { + my ($file, $name, $defaults) = @_; + + # Try to look up the compiler flags with pkg-config... + chomp(my $flags = `pkg-config --cflags $name ${\DIRECTIVE_ERROR_PIPE}`); + unless ($?) { + print_format "Found the compiler flags for <|GREEN ${\basename $file, '.cpp'}|> using pkg-config: <|BOLD $flags|>\n"; + return $flags; + } + + # If looking up with pkg-config fails then check the environment... + my $key = __environment 'INSPIRCD_CXXFLAGS_', $name; + if (defined $ENV{$key}) { + print_format "Found the compiler flags for <|GREEN ${\basename $file, '.cpp'}|> using the environment: <|BOLD $ENV{$key}|>\n"; + return $ENV{$key}; + } + + # If all else fails then look for the defaults.. + if (defined $defaults) { + print_format "Found the compiler flags for <|GREEN ${\basename $file, '.cpp'}|> using the defaults: <|BOLD $defaults|>\n"; + return $defaults; + } + + # We can't find it via pkg-config, via the environment, or via the defaults so give up. + __error $file, "unable to find the compiler flags for <|GREEN ${\basename $file, '.cpp'}|>!"; +} + +sub __function_find_linker_flags { + my ($file, $name, $defaults) = @_; + + # Try to look up the linker flags with pkg-config... + chomp(my $flags = `pkg-config --libs $name ${\DIRECTIVE_ERROR_PIPE}`); + unless ($?) { + print_format "Found the linker flags for <|GREEN ${\basename $file, '.cpp'}|> using pkg-config: <|BOLD $flags|>\n"; + return $flags; + } + + # If looking up with pkg-config fails then check the environment... + my $key = __environment 'INSPIRCD_CXXFLAGS_', $name; + if (defined $ENV{$key}) { + print_format "Found the linker flags for <|GREEN ${\basename $file, '.cpp'}|> using the environment: <|BOLD $ENV{$key}|>\n"; + return $ENV{$key}; + } + + # If all else fails then look for the defaults.. + if (defined $defaults) { + print_format "Found the linker flags for <|GREEN ${\basename $file, '.cpp'}|> using the defaults: <|BOLD $defaults|>\n"; + return $defaults; + } + + # We can't find it via pkg-config, via the environment, or via the defaults so give up. + __error $file, "unable to find the linker flags for <|GREEN ${\basename $file, '.cpp'}|>!"; +} + +sub __function_require_system { + my ($file, $name, $minimum, $maximum) = @_; + my ($system, $version); + + # Linux is special and can be compared by distribution names. + if ($^O eq 'linux' && $name ne 'linux') { + chomp($system = lc `lsb_release --id --short 2>/dev/null`); + chomp($version = lc `lsb_release --release --short 2>/dev/null`); + } + + # Gather information on the system if we don't have it already. + chomp($system ||= lc `uname -s 2>/dev/null`); + chomp($version ||= lc `uname -r 2>/dev/null`); + + # We only care about the important bit of the version number so trim the rest. + $version =~ s/^(\d+\.\d+).+/$1/; + + # Check whether the current system is suitable. + return undef if $name ne $system; + return undef if defined $minimum && $version < $minimum; + return undef if defined $maximum && $version > $maximum; + + # Requirement directives don't change anything directly. + return ""; +} + +sub __function_require_version { + my ($file, $name, $minimum, $maximum) = @_; + + # If pkg-config isn't installed then we can't do anything here. + if (system "pkg-config --exists $name ${\DIRECTIVE_ERROR_PIPE}") { + print_warning "unable to look up the version of $name using pkg-config!"; + return undef; + } + + # Check with pkg-config whether we have the required version. + return undef if defined $minimum && system "pkg-config --atleast-version $minimum $name"; + return undef if defined $maximum && system "pkg-config --max-version $maximum $name"; + + # Requirement directives don't change anything directly. + return ""; +} + +sub __function_warning { + my ($file, @messages) = @_; + print_warning @messages; +} + +1; diff --git a/make/gnutlscert.pm b/make/gnutlscert.pm deleted file mode 100644 index 2c46e0e63..000000000 --- a/make/gnutlscert.pm +++ /dev/null @@ -1,150 +0,0 @@ -# -# InspIRCd -- Internet Relay Chat Daemon -# -# Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> -# Copyright (C) 2007 Craig Edwards <craigedwards@brainbox.cc> -# -# This file is part of InspIRCd. InspIRCd is free software: you can -# redistribute it and/or modify it under the terms of the GNU General Public -# License as published by the Free Software Foundation, version 2. -# -# This program is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more -# details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. -# - - -package make::gnutlscert; - -require 5.8.0; - -use strict; -use warnings FATAL => qw(all); - -use Exporter 'import'; -use make::configure; -our @EXPORT = qw(make_gnutls_cert); - -# On OS X the GnuTLS certtool is prefixed to avoid collision with the system certtool. -my $certtool = $^O eq 'darwin' ? 'gnutls-certtool' : 'certtool'; - -sub make_gnutls_cert() -{ - if (system "$certtool --version >/dev/null 2>&1") - { - print "\e[1;31mError:\e[0m unable to find '$certtool' in the PATH!\n"; - return 1; - } - open (FH, ">certtool.template"); - my $timestr = time(); - my $commonname = promptstring_s('What is the hostname of your server?', 'irc.example.com'); - my $email = promptstring_s('What email address can you be contacted at?', 'example@example.com'); - my $unit = promptstring_s('What is the name of your unit?', 'Server Admins'); - my $org = promptstring_s('What is the name of your organization?', 'Example IRC Network'); - my $city = promptstring_s('What city are you located in?', 'Example City'); - my $state = promptstring_s('What state are you located in?', 'Example State'); - my $country = promptstring_s('What is the ISO 3166-1 code for the country you are located in?', 'XZ'); - my $days = promptstring_s('How many days do you want your certificate to be valid for?', '365'); - print FH <<__END__; -# X.509 Certificate options -# -# DN options - -# The organization of the subject. -organization = "$org" - -# The organizational unit of the subject. -unit = "$unit" - -# The locality of the subject. -locality = "$city" - -# The state of the certificate owner. -state = "$state" - -# The country of the subject. Two letter code. -country = "$country" - -# The common name of the certificate owner. -cn = "$commonname" - -# A user id of the certificate owner. -#uid = "clauper" - -# If the supported DN OIDs are not adequate you can set -# any OID here. -# For example set the X.520 Title and the X.520 Pseudonym -# by using OID and string pairs. -#dn_oid = "2.5.4.12" "Dr." "2.5.4.65" "jackal" - -# This is deprecated and should not be used in new -# certificates. -# pkcs9_email = "none\@none.org" - -# The serial number of the certificate -serial = $timestr - -# In how many days, counting from today, this certificate will expire. -expiration_days = $days - -# X.509 v3 extensions - -# A dnsname in case of a WWW server. -#dns_name = "www.none.org" - -# An IP address in case of a server. -#ip_address = "192.168.1.1" - -# An email in case of a person -email = "$email" - -# An URL that has CRLs (certificate revocation lists) -# available. Needed in CA certificates. -#crl_dist_points = "http://www.getcrl.crl/getcrl/" - -# Whether this is a CA certificate or not -#ca - -# Whether this certificate will be used for a TLS client -tls_www_client - -# Whether this certificate will be used for a TLS server -tls_www_server - -# Whether this certificate will be used to sign data (needed -# in TLS DHE ciphersuites). -signing_key - -# Whether this certificate will be used to encrypt data (needed -# in TLS RSA ciphersuites). Note that it is prefered to use different -# keys for encryption and signing. -encryption_key - -# Whether this key will be used to sign other certificates. -cert_signing_key - -# Whether this key will be used to sign CRLs. -crl_signing_key - -# Whether this key will be used to sign code. -code_signing_key - -# Whether this key will be used to sign OCSP data. -ocsp_signing_key - -# Whether this key will be used for time stamping. -time_stamping_key -__END__ -close(FH); -if ( (my $status = system("$certtool --generate-privkey --outfile key.pem")) ne 0) { return 1; } -if ( (my $status = system("$certtool --generate-self-signed --load-privkey key.pem --outfile cert.pem --template certtool.template")) ne 0) { return 1; } -unlink("certtool.template"); -return 0; -} - -1; - diff --git a/make/opensslcert.pm b/make/opensslcert.pm deleted file mode 100644 index 20da704f7..000000000 --- a/make/opensslcert.pm +++ /dev/null @@ -1,66 +0,0 @@ -# -# InspIRCd -- Internet Relay Chat Daemon -# -# Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> -# Copyright (C) 2007 Craig Edwards <craigedwards@brainbox.cc> -# -# This file is part of InspIRCd. InspIRCd is free software: you can -# redistribute it and/or modify it under the terms of the GNU General Public -# License as published by the Free Software Foundation, version 2. -# -# This program is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more -# details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. -# - - -package make::opensslcert; - -require 5.8.0; - -use strict; -use warnings FATAL => qw(all); - -use Exporter 'import'; -use make::configure; -our @EXPORT = qw(make_openssl_cert); - - -sub make_openssl_cert() -{ - if (system 'openssl version >/dev/null 2>&1') - { - print "\e[1;31mCertificate generation failed:\e[0m unable to find 'openssl' in the PATH!\n"; - return; - } - open (FH, ">openssl.template"); - my $commonname = promptstring_s('What is the hostname of your server?', 'irc.example.com'); - my $email = promptstring_s('What email address can you be contacted at?', 'example@example.com'); - my $unit = promptstring_s('What is the name of your unit?', 'Server Admins'); - my $org = promptstring_s('What is the name of your organization?', 'Example IRC Network'); - my $city = promptstring_s('What city are you located in?', 'Example City'); - my $state = promptstring_s('What state are you located in?', 'Example State'); - my $country = promptstring_s('What is the ISO 3166-1 code for the country you are located in?', 'XZ'); - my $time = promptstring_s('How many days do you want your certificate to be valid for?', '365'); - my $use_1024 = promptstring_s('Do you want to generate less secure dhparams which are compatible with old versions of Java?', 'n'); - print FH <<__END__; -$country -$state -$city -$org -$unit -$commonname -$email -__END__ -close(FH); -my $dhbits = $use_1024 =~ /^(1|on|true|yes|y)$/ ? 1024 : 2048; -system("cat openssl.template | openssl req -x509 -nodes -newkey rsa:2048 -keyout key.pem -out cert.pem -days $time 2>/dev/null"); -system("openssl dhparam -out dhparams.pem $dhbits"); -unlink("openssl.template"); -} - -1; diff --git a/make/run-cc.pl b/make/run-cc.pl deleted file mode 100755 index 58b5850ca..000000000 --- a/make/run-cc.pl +++ /dev/null @@ -1,237 +0,0 @@ -#!/usr/bin/env perl - -# -# InspIRCd -- Internet Relay Chat Daemon -# -# Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org> -# Copyright (C) 2008 Craig Edwards <craigedwards@brainbox.cc> -# -# This file is part of InspIRCd. InspIRCd is free software: you can -# redistribute it and/or modify it under the terms of the GNU General Public -# License as published by the Free Software Foundation, version 2. -# -# This program is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more -# details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. -# - - -### THIS IS DESIGNED TO BE RUN BY MAKE! DO NOT RUN FROM THE SHELL (because it MIGHT sigterm the shell)! ### - -use strict; -use warnings FATAL => qw(all); - -use POSIX (); - -# Runs the compiler, passing it the given arguments. -# Filters select output from the compiler's standard error channel and -# can take different actions as a result. - -# NOTE: this is *NOT* a hash (sadly: a hash would stringize all the regexes and thus render them useless, plus you can't index a hash based on regexes anyway) -# even though we use the => in it. - -# The subs are passed the message, and anything the regex captured. - -my $cc = shift(@ARGV); - -my $showncmdline = 0; - -# GCC's "location of error stuff", which accumulates the "In file included from" include stack -my $location = ""; - -my @msgfilters = ( - [ qr/^(.*) warning: cannot pass objects of non-POD type `(.*)' through `\.\.\.'; call will abort at runtime/ => sub { - my ($msg, $where, $type) = @_; - my $errstr = $location . "$where error: cannot pass objects of non-POD type `$type' through `...'\n"; - $location = ""; - if ($type =~ m/::(basic_)?string/) { - $errstr .= "$where (Did you forget to call c_str()?)\n"; - } - die $errstr; - } ], - - # Start of an include stack. - [ qr/^In file included from .*[,:]$/ => sub { - my ($msg) = @_; - $location = "$msg\n"; - return undef; - } ], - - # Continuation of an include stack. - [ qr/^ from .*[,:]$/ => sub { - my ($msg) = @_; - $location .= "$msg\n"; - return undef; - } ], - - # A function, method, constructor, or destructor is the site of a problem - [ qr/In ((con|de)structor|(member )?function)/ => sub { - my ($msg) = @_; - # If a complete location string is waiting then probably we dropped an error, so drop the location for a new one. - if ($location =~ m/In ((con|de)structor|(member )?function)/) { - $location = "$msg\n"; - } else { - $location .= "$msg\n"; - } - return undef; - } ], - - [ qr/^.* warning: / => sub { - my ($msg) = @_; - my $str = $location . "\e[33;1m$msg\e[0m\n"; - $showncmdline = 1; - $location = ""; - return $str; - } ], - - [ qr/^.* error: / => sub { - my ($msg) = @_; - my $str = ""; - $str = "An error occured when executing:\e[37;1m $cc " . join(' ', @ARGV) . "\n" unless $showncmdline; - $showncmdline = 1; - $str .= $location . "\e[31;1m$msg\e[0m\n"; - $location = ""; - return $str; - } ], - - [ qr/./ => sub { - my ($msg) = @_; - $msg = $location . $msg; - $location = ""; - $msg =~ s/std::basic_string\<char\, std\:\:char_traits\<char\>, std::allocator\<char\> \>(\s+|)/std::string/g; - $msg =~ s/std::basic_string\<char\, .*?irc_char_traits\<char\>, std::allocator\<char\> \>(\s+|)/irc::string/g; - for my $stl (qw(deque vector list)) { - $msg =~ s/std::$stl\<(\S+), std::allocator\<\1\> \>/std::$stl\<$1\>/g; - $msg =~ s/std::$stl\<(std::pair\<\S+, \S+\>), std::allocator\<\1 \> \>/std::$stl<$1 >/g; - } - $msg =~ s/std::map\<(\S+), (\S+), std::less\<\1\>, std::allocator\<std::pair\<const \1, \2\> \> \>/std::map<$1, $2>/g; - # Warning: These filters are GNU C++ specific! - $msg =~ s/__gnu_cxx::__normal_iterator\<(\S+)\*, std::vector\<\1\> \>/std::vector<$1>::iterator/g; - $msg =~ s/__gnu_cxx::__normal_iterator\<(std::pair\<\S+, \S+\>)\*, std::vector\<\1 \> \>/std::vector<$1 >::iterator/g; - $msg =~ s/__gnu_cxx::__normal_iterator\<char\*, std::string\>/std::string::iterator/g; - $msg =~ s/__gnu_cxx::__normal_iterator\<char\*, irc::string\>/irc::string::iterator/g; - return $msg; - } ], -); - -my $pid; - -my ($r_stderr, $w_stderr); - -my $name = ""; -my $action = ""; - -if ($cc eq "ar") { - $name = $ARGV[1]; - $action = "ARCHIVE"; -} else { - foreach my $n (@ARGV) - { - if ($n =~ /\.cpp$/) - { - my $f = $n; - if (defined $ENV{SOURCEPATH}) { - $f =~ s#^$ENV{SOURCEPATH}/src/##; - } - if ($action eq "BUILD") - { - $name .= " " . $f; - } - else - { - $action = "BUILD"; - $name = $f; - } - } - elsif ($action eq "BUILD") # .cpp has priority. - { - next; - } - elsif ($n eq "-o") - { - $action = $name = $n; - } - elsif ($name eq "-o") - { - $action = "LINK"; - $name = $n; - } - } -} - -if (!defined($cc) || $cc eq "") { - die "Compiler not specified!\n"; -} - -pipe($r_stderr, $w_stderr) or die "pipe stderr: $!\n"; - -$pid = fork; - -die "Cannot fork to start $cc! $!\n" unless defined($pid); - -if ($pid) { - - printf "\t\e[1;32m%-20s\e[0m%s\n", $action . ":", $name unless $name eq ""; - - my $fail = 0; - # Parent - Close child-side pipes. - close $w_stderr; - # Close STDIN to ensure no conflicts with child. - close STDIN; - # Now read each line of stderr -LINE: while (defined(my $line = <$r_stderr>)) { - chomp $line; - - for my $filter (@msgfilters) { - my @caps; - if (@caps = ($line =~ $filter->[0])) { - $@ = ""; - $line = eval { - $filter->[1]->($line, @caps); - }; - if ($@) { - # Note that $line is undef now. - $fail = 1; - print STDERR $@; - } - next LINE unless defined($line); - } - } - # Chomp off newlines again, in case the filters put some back in. - chomp $line; - print STDERR "$line\n"; - } - waitpid $pid, 0; - close $r_stderr; - my $exit = $?; - # Simulate the same exit, so make gets the right termination info. - if (POSIX::WIFSIGNALED($exit)) { - # Make won't get the right termination info (it gets ours, not the compiler's), so we must tell the user what really happened ourselves! - print STDERR "$cc killed by signal " . POSIX::WTERMSIGN($exit) . "\n"; - kill "TERM", getppid(); # Needed for bsd make. - kill "TERM", $$; - } - else { - if (POSIX::WEXITSTATUS($exit) == 0) { - if ($fail) { - kill "TERM", getppid(); # Needed for bsd make. - kill "TERM", $$; - } - exit 0; - } else { - exit POSIX::WEXITSTATUS($exit); - } - } -} else { - # Child - Close parent-side pipes. - close $r_stderr; - # Divert stderr - open STDERR, ">&", $w_stderr or die "Cannot divert STDERR: $!\n"; - # Run the compiler! - exec { $cc } $cc, @ARGV; - die "exec $cc: $!\n"; -} diff --git a/make/check_strlcpy.cpp b/make/template/config.h index e51d18d40..660678b38 100644 --- a/make/check_strlcpy.cpp +++ b/make/template/config.h @@ -1,7 +1,7 @@ /* * InspIRCd -- Internet Relay Chat Daemon * - * Copyright (C) 2015 Peter Powell <petpow@saberuk.com> + * Copyright (C) 2014 Peter Powell <petpow@saberuk.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public @@ -17,9 +17,21 @@ */ -#include <string.h> +#pragma once -int main() { - char test[5]; - strlcpy(test, "test", sizeof(test)); -} +#define INSPIRCD_BRANCH "InspIRCd-@VERSION_MAJOR@.@VERSION_MINOR@" +#define INSPIRCD_VERSION "InspIRCd-@VERSION_FULL@" +#define INSPIRCD_SYSTEM "@SYSTEM_NAME_VERSION@" + +#define INSPIRCD_CONFIG_PATH "@CONFIG_DIR@" +#define INSPIRCD_DATA_PATH "@DATA_DIR@" +#define INSPIRCD_LOG_PATH "@LOG_DIR@" +#define INSPIRCD_MODULE_PATH "@MODULE_DIR@" + +#define INSPIRCD_SOCKETENGINE_NAME "@SOCKETENGINE@" + +#ifndef _WIN32 + %target include/config.h + %define HAS_CLOCK_GETTIME + %define HAS_EVENTFD +#endif diff --git a/make/template/gdbargs b/make/template/gdbargs new file mode 100644 index 000000000..de76c7270 --- /dev/null +++ b/make/template/gdbargs @@ -0,0 +1,4 @@ +%target .gdbargs +handle SIGPIPE pass nostop noprint +handle SIGHUP pass nostop noprint +run diff --git a/make/template/inspircd b/make/template/inspircd index b43ad60c9..949f85cee 100644 --- a/make/template/inspircd +++ b/make/template/inspircd @@ -1,3 +1,4 @@ +%mode 0750 #!/usr/bin/env perl # @@ -29,17 +30,35 @@ use strict; use POSIX; use Fcntl; +# From http://refspecs.linuxbase.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/iniscrptact.html +use constant { + STATUS_EXIT_SUCCESS => 0, + STATUS_EXIT_DEAD_WITH_PIDFILE => 1, + STATUS_EXIT_DEAD_WITH_LOCKFILE => 2, + STATUS_EXIT_NOT_RUNNING => 3, + STATUS_EXIT_UNKNOWN => 4, + + GENERIC_EXIT_SUCCESS => 0, + GENERIC_EXIT_UNSPECIFIED => 1, + GENERIC_EXIT_INVALID_ARGUMENTS => 2, + GENERIC_EXIT_UNIMPLEMENTED => 3, + GENERIC_EXIT_INSUFFICIENT_PRIVILEGE => 4, + GENERIC_EXIT_NOT_INSTALLED => 5, + GENERIC_EXIT_NOT_CONFIGURED => 6, + GENERIC_EXIT_NOT_RUNNING => 7 +}; + my $basepath = "@BASE_DIR@"; my $confpath = "@CONFIG_DIR@/"; my $binpath = "@BINARY_DIR@"; my $runpath = "@BASE_DIR@"; my $datadir = "@DATA_DIR@"; my $valgrindlogpath = "$basepath/valgrindlogs"; -my $executable = "@EXECUTABLE@"; -my $version = "@VERSION@"; +my $executable = "inspircd"; +my $version = "@VERSION_FULL@"; my $uid = "@UID@"; -if ($< == 0 || $> == 0) { +if (!("--runasroot" ~~ @ARGV) && ($< == 0 || $> == 0)) { if ($uid !~ /^\d+$/) { # Named UID, look it up $uid = getpwnam $uid; @@ -87,12 +106,11 @@ if (!defined($sub)) { print STDERR "Invalid command or none given.\n"; cmd_help(); - exit 1; + exit GENERIC_EXIT_UNIMPLEMENTED; } else { - $sub->(@ARGV); - exit 0; + exit $sub->(@ARGV); # Error code passed through return value } sub cmd_help() @@ -105,7 +123,7 @@ sub cmd_help() $_ =~ s/_/-/g foreach (@cmds, @devs); print STDERR "Usage: ./inspircd (" . join("|", @cmds) . ")\n"; print STDERR "Developer arguments: (" . join("|", @devs) . ")\n"; - exit 0; + exit GENERIC_EXIT_SUCCESS; } sub cmd_status() @@ -113,10 +131,10 @@ sub cmd_status() if (getstatus() == 1) { my $pid = getprocessid(); print "InspIRCd is running (PID: $pid)\n"; - exit(); + exit STATUS_EXIT_SUCCESS; } else { print "InspIRCd is not running. (Or PID File not found)\n"; - exit(); + exit STATUS_EXIT_NOT_RUNNING; } } @@ -126,23 +144,23 @@ sub cmd_rehash() my $pid = getprocessid(); system("kill -HUP $pid >/dev/null 2>&1"); print "InspIRCd rehashed (pid: $pid).\n"; - exit(); + exit GENERIC_EXIT_SUCCESS; } else { print "InspIRCd is not running. (Or PID File not found)\n"; - exit(); + exit GENERIC_EXIT_NOT_RUNNING; } } sub cmd_cron() { if (getstatus() == 0) { goto &cmd_start(@_); } - exit(); + exit GENERIC_EXIT_UNSPECIFIED; } sub cmd_version() { print "InspIRCd version: $version\n"; - exit(); + exit GENERIC_EXIT_SUCCESS; } sub cmd_restart(@) @@ -156,13 +174,13 @@ sub hid_cheese_sandwich() { print "Creating Cheese Sandwich..\n"; print "Done.\n"; - exit(); + exit GENERIC_EXIT_SUCCESS; } sub cmd_start(@) { # Check to see its not 'running' already. - if (getstatus() == 1) { print "InspIRCd is already running.\n"; return 0; } + if (getstatus() == 1) { print "InspIRCd is already running.\n"; exit GENERIC_EXIT_SUCCESS; } # If we are still alive here.. Try starting the IRCd.. chdir $runpath; print "$binpath/$executable doesn't exist\n" and return 0 unless(-e "$binpath/$executable"); @@ -224,7 +242,7 @@ sub dev_valdebug(@) # If we are still alive here.. Try starting the IRCd.. # May want to do something with these args at some point: --suppressions=.inspircd.sup --gen-suppressions=yes # Could be useful when we want to stop it complaining about things we're sure aren't issues. - exec qw(valgrind -v --tool=memcheck --leak-check=yes --db-attach=yes --num-callers=10), "$binpath/$executable", qw(--nofork --debug --nolog), @_; + exec qw(valgrind -v --tool=memcheck --leak-check=yes --db-attach=yes --num-callers=30), "$binpath/$executable", qw(--nofork --debug --nolog), @_; die "Failed to start valgrind: $!\n"; } @@ -258,7 +276,7 @@ sub dev_valdebug_unattended(@) sysopen STDERR, "$valgrindlogpath/valdebug.$suffix", O_WRONLY | O_CREAT | O_NOCTTY | O_APPEND, 0666 or die "Can't open $valgrindlogpath/valdebug.$suffix: $!\n"; # May want to do something with these args at some point: --suppressions=.inspircd.sup --gen-suppressions=yes # Could be useful when we want to stop it complaining about things we're sure aren't issues. - exec qw(valgrind -v --tool=memcheck --leak-check=full --show-reachable=yes --num-callers=15 --track-fds=yes), + exec qw(valgrind -v --tool=memcheck --leak-check=full --show-reachable=yes --num-callers=30 --track-fds=yes), "--suppressions=$binpath/valgrind.sup", qw(--gen-suppressions=all), qw(--leak-resolution=med --time-stamp=yes --log-fd=2 --), "$binpath/$executable", qw(--nofork --debug --nolog), @_; @@ -283,13 +301,13 @@ sub dev_screenvaldebug(@) # If we are still alive here.. Try starting the IRCd.. print "Starting InspIRCd in `screen`, type `screen -r` when the ircd crashes to view the valgrind and gdb output and get a backtrace.\n"; print "Once you're inside the screen session press ^C + d to re-detach from the session\n"; - exec qw(screen -m -d valgrind -v --tool=memcheck --leak-check=yes --db-attach=yes --num-callers=10), "$binpath/$executable", qw(--nofork --debug --nolog), @_; + exec qw(screen -m -d valgrind -v --tool=memcheck --leak-check=yes --db-attach=yes --num-callers=30), "$binpath/$executable", qw(--nofork --debug --nolog), @_; die "Failed to start screen: $!\n"; } sub cmd_stop() { - if (getstatus() == 0) { print "InspIRCd is not running. (Or PID File not found)\n"; return 0; } + if (getstatus() == 0) { print "InspIRCd is not running. (Or PID File not found)\n"; return GENERIC_EXIT_SUCCESS; } # Get to here, we have something to kill. my $pid = getprocessid(); print "Stopping InspIRCd (pid: $pid)...\n"; @@ -299,12 +317,12 @@ sub cmd_stop() sleep 1; if (getstatus() == 0) { print "InspIRCd Stopped.\n"; - return; + return GENERIC_EXIT_SUCCESS; } } print "InspIRCd not dying quietly -- forcing kill\n"; kill KILL => $pid; - return 0; + return GENERIC_EXIT_SUCCESS; } ### @@ -415,7 +433,7 @@ sub checkvalgrind unless(`valgrind --version`) { print "Couldn't start valgrind: $!\n"; - exit; + exit GENERIC_EXIT_UNSPECIFIED; } } @@ -424,7 +442,7 @@ sub checkgdb unless(`gdb --version`) { print "Couldn't start gdb: $!\n"; - exit; + exit GENERIC_EXIT_UNSPECIFIED; } } @@ -433,6 +451,6 @@ sub checkscreen unless(`screen --version`) { print "Couldn't start screen: $!\n"; - exit; + exit GENERIC_EXIT_UNSPECIFIED; } } diff --git a/make/template/inspircd-genssl.1 b/make/template/inspircd-genssl.1 new file mode 100644 index 000000000..d43a3b4e8 --- /dev/null +++ b/make/template/inspircd-genssl.1 @@ -0,0 +1,46 @@ +.\" +.\" InspIRCd -- Internet Relay Chat Daemon +.\" +.\" Copyright (C) 2014 Peter Powell <petpow@saberuk.com> +.\" +.\" This file is part of InspIRCd. InspIRCd is free software: you can +.\" redistribute it and/or modify it under the terms of the GNU General Public +.\" License as published by the Free Software Foundation, version 2. +.\" +.\" This program is distributed in the hope that it will be useful, but WITHOUT +.\" ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +.\" FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +.\" details. +.\" +.\" You should have received a copy of the GNU General Public License +.\" along with this program. If not, see <http://www.gnu.org/licenses/>. +.\" + + +.TH "InspIRCd" "1" "June 2014" "InspIRCd @VERSION_FULL@" "InspIRCd Manual" + +.SH "NAME" +\t\fBInspIRCd\fR - \fIthe\fR stable, high-performance and modular Internet Relay Chat Daemon +.BR + +.SH "SYNOPSIS" +\t\fBinspircd-genssl\fR [ auto | gnutls | openssl ] + +.SH "OPTIONS" +.TP +.B "auto" +.br +Looks for both GnuTLS and OpenSSL and uses the first one which is available for certificate generation. +.TP +.B "gnutls" +.br +Generates certificates using GnuTLS. +.TP +.br +.B "openssl" +Generates certificates using OpenSSL. + +.SH "SUPPORT" +IRC support for InspIRCd can be found at irc://irc.inspircd.org/inspircd. + +Bug reports and feature requests can be filed at https://github.com/inspircd/inspircd/issues. diff --git a/make/template/inspircd.1 b/make/template/inspircd.1 new file mode 100644 index 000000000..eb1453d2f --- /dev/null +++ b/make/template/inspircd.1 @@ -0,0 +1,104 @@ +.\" +.\" InspIRCd -- Internet Relay Chat Daemon +.\" +.\" Copyright (C) 2014 Peter Powell <petpow@saberuk.com> +.\" +.\" This file is part of InspIRCd. InspIRCd is free software: you can +.\" redistribute it and/or modify it under the terms of the GNU General Public +.\" License as published by the Free Software Foundation, version 2. +.\" +.\" This program is distributed in the hope that it will be useful, but WITHOUT +.\" ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +.\" FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +.\" details. +.\" +.\" You should have received a copy of the GNU General Public License +.\" along with this program. If not, see <http://www.gnu.org/licenses/>. +.\" + + +.TH "InspIRCd" "1" "June 2014" "InspIRCd @VERSION_FULL@" "InspIRCd Manual" + +.SH "NAME" +\t\fBInspIRCd\fR - \fIthe\fR stable, high-performance and modular Internet Relay Chat Daemon +.BR + +.SH "SYNOPSIS" +\t\fBinspircd\fR [--config <file>] [--debug] [--nofork] [--nolog] [--runasroot] [--version] + +.SH "OPTIONS" +.TP +.B "--config <file>" +.br +Sets the path to the main configuration file. Defaults to \fI@CONFIG_DIR@/inspircd.conf\fR. +.TP +.B "--debug" +.br +Log verbosely to the standard output stream. +.TP +.B "--nofork" +.br +Don't fork into the background after starting up. +.TP +.B "--nolog" +.br +Don't write to log files. +.TP +.B "--runasroot" +.br +Allow the server to start as root (not recommended). +.TP +.B "--version" +.br +Displays the InspIRCd version and exits. + +.SH "EXIT STATUS" +.TP +.B "0 (EXIT_STATUS_NOERROR)" +.br +The server exited cleanly. +.TP +.B "1 (EXIT_STATUS_DIE)" +.br +The server exited because the DIE command was executed. +.TP +.B "2 (EXIT_STATUS_CONFIG)" +.br +The server exited because of a configuration file error. +.TP +.B "3 (EXIT_STATUS_LOG)" +.br +The server exited because of a log file error. +.TP +.B "4 (EXIT_STATUS_FORK)" +.br +The server exited because it was unable to fork into the background. +.TP +.B "5 (EXIT_STATUS_ARGV)" +.br +The server exited because an invalid argument was passed to it on the command line. +.TP +.B "6 (EXIT_STATUS_PID)" +.br +The server exited because it was unable to write to the PID file. +.TP +.B "7 (EXIT_STATUS_SOCKETENGINE)" +.br +The server exited because it was unable to initialize the @SOCKETENGINE@ socket engine. +.TP +.B "8 (EXIT_STATUS_ROOT)" +.br +The server exited because the user tried to start as root without \fI--runasroot\fR. +.TP +.B "9 (EXIT_STATUS_MODULE)" +.br +The server exited because it was unable to load a module on first run. +.TP +.B "10 (EXIT_STATUS_SIGTERM)" +.br +The server exited because it received SIGTERM. + +.SH "SUPPORT" +IRC support for InspIRCd can be found at irc://irc.inspircd.org/inspircd. + +Bug reports and feature requests can be filed at https://github.com/inspircd/inspircd/issues. diff --git a/make/template/inspircd.service b/make/template/inspircd.service new file mode 100644 index 000000000..e5f28a674 --- /dev/null +++ b/make/template/inspircd.service @@ -0,0 +1,35 @@ +%platform linux +# +# InspIRCd -- Internet Relay Chat Daemon +# +# Copyright (C) 2014 Peter Powell <petpow@saberuk.com> +# +# This file is part of InspIRCd. InspIRCd is free software: you can +# redistribute it and/or modify it under the terms of the GNU General Public +# License as published by the Free Software Foundation, version 2. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +# details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + + +[Unit] +After=network.target +Description=InspIRCd - Internet Relay Chat Daemon +Requires=network.target + +[Service] +ExecReload=@BASE_DIR@/inspircd rehash +ExecStart=@BASE_DIR@/inspircd start +ExecStop=@BASE_DIR@/inspircd stop +PIDFile=@DATA_DIR@/inspircd.pid +Restart=on-failure +Type=forking + +[Install] +WantedBy=multi-user.target diff --git a/make/template/main.mk b/make/template/main.mk index 23daa7efc..50feb8f8d 100644 --- a/make/template/main.mk +++ b/make/template/main.mk @@ -1,3 +1,5 @@ +%target BSD_MAKE BSDmakefile +%target GNU_MAKE GNUmakefile # # InspIRCd -- Internet Relay Chat Daemon # @@ -30,33 +32,38 @@ # -CC = @CC@ -SYSTEM = @SYSTEM@ -BUILDPATH = @BUILD_DIR@ +CXX = @CXX@ +COMPILER = @COMPILER_NAME@ +SYSTEM = @SYSTEM_NAME@ +BUILDPATH ?= $(PWD)/build SOCKETENGINE = @SOCKETENGINE@ -CXXFLAGS = -pipe -fPIC -DPIC -LDLIBS = -pthread -lstdc++ -LDFLAGS = +CORECXXFLAGS = -fPIC -fvisibility=hidden -fvisibility-inlines-hidden -pipe -Iinclude -Wall -Wextra -Wfatal-errors -Wno-unused-parameter -Wshadow +LDLIBS = -lstdc++ CORELDFLAGS = -rdynamic -L. $(LDFLAGS) PICLDFLAGS = -fPIC -shared -rdynamic $(LDFLAGS) BASE = "$(DESTDIR)@BASE_DIR@" CONPATH = "$(DESTDIR)@CONFIG_DIR@" +MANPATH = "$(DESTDIR)@MANUAL_DIR@" MODPATH = "$(DESTDIR)@MODULE_DIR@" LOGPATH = "$(DESTDIR)@LOG_DIR@" DATPATH = "$(DESTDIR)@DATA_DIR@" BINPATH = "$(DESTDIR)@BINARY_DIR@" INSTALL = install INSTUID = @UID@ -INSTMODE_DIR = 0755 -INSTMODE_BIN = 0755 -INSTMODE_LIB = 0644 - -@IFEQ $(CC) icpc - CXXFLAGS += -Wshadow -@ELSE - CXXFLAGS += -pedantic -Woverloaded-virtual -Wshadow -Wformat=2 -Wmissing-format-attribute -Wall +INSTMODE_DIR = 0750 +INSTMODE_BIN = 0750 +INSTMODE_LIB = 0640 + +@IFNEQ $(COMPILER) ICC + CORECXXFLAGS += -Woverloaded-virtual -Wshadow +@IFNEQ $(SYSTEM) openbsd + CORECXXFLAGS += -pedantic -Wformat=2 -Wmissing-format-attribute +@ENDIF @ENDIF +@IFNEQ $(SYSTEM) darwin + LDLIBS += -pthread +@ENDIF @IFEQ $(SYSTEM) linux LDLIBS += -ldl -lrt @@ -71,90 +78,72 @@ INSTMODE_LIB = 0644 LDLIBS += -lsocket -lnsl -lrt -lresolv INSTALL = ginstall @ENDIF -@IFEQ $(SYSTEM) sunos - LDLIBS += -lsocket -lnsl -lrt -lresolv - INSTALL = ginstall -@ENDIF @IFEQ $(SYSTEM) darwin - CXXFLAGS += -DDARWIN -frtti LDLIBS += -ldl CORELDFLAGS = -dynamic -bind_at_load -L. $(LDFLAGS) PICLDFLAGS = -fPIC -shared -twolevel_namespace -undefined dynamic_lookup $(LDFLAGS) @ENDIF -@IFEQ $(SYSTEM) interix - CXXFLAGS += -D_ALL_SOURCE -I/usr/local/include -@ENDIF - -@IFNDEF D - D=0 -@ENDIF -GCC6=@GCC6@ -@IFEQ $(GCC6) true - CXXFLAGS += -fno-delete-null-pointer-checks +@IFNDEF INSPIRCD_DEBUG + INSPIRCD_DEBUG=0 @ENDIF DBGOK=0 -@IFEQ $(D) 0 - CXXFLAGS += -O2 -@IFEQ $(CC) g++ - CXXFLAGS += -g1 +@IFEQ $(INSPIRCD_DEBUG) 0 + CORECXXFLAGS += -fno-rtti -O2 +@IFEQ $(COMPILER) GCC + CORECXXFLAGS += -g1 @ENDIF HEADER = std-header DBGOK=1 @ENDIF -@IFEQ $(D) 1 - CXXFLAGS += -O0 -g3 -Werror +@IFEQ $(INSPIRCD_DEBUG) 1 + CORECXXFLAGS += -O0 -g3 -Werror -DINSPIRCD_ENABLE_RTTI HEADER = debug-header DBGOK=1 @ENDIF -@IFEQ $(D) 2 - CXXFLAGS += -O2 -g3 +@IFEQ $(INSPIRCD_DEBUG) 2 + CORECXXFLAGS += -fno-rtti -O2 -g3 HEADER = debug-header DBGOK=1 @ENDIF FOOTER = finishmessage -CXXFLAGS += -Iinclude +@TARGET GNU_MAKE MAKEFLAGS += --no-print-directory -@GNU_ONLY MAKEFLAGS += --no-print-directory +@TARGET GNU_MAKE SOURCEPATH = $(shell /bin/pwd) +@TARGET BSD_MAKE SOURCEPATH != /bin/pwd -@GNU_ONLY SOURCEPATH = $(shell /bin/pwd) -@BSD_ONLY SOURCEPATH != /bin/pwd - -@IFDEF V - RUNCC = $(CC) - RUNLD = $(CC) - VERBOSE = -v -@ELSE - @GNU_ONLY MAKEFLAGS += --silent - @BSD_ONLY MAKE += -s - RUNCC = perl "$(SOURCEPATH)/make/run-cc.pl" $(CC) - RUNLD = perl "$(SOURCEPATH)/make/run-cc.pl" $(CC) - VERBOSE = +@IFNDEF INSPIRCD_VERBOSE + @TARGET GNU_MAKE MAKEFLAGS += --silent + @TARGET BSD_MAKE MAKE += -s @ENDIF -@IFDEF PURE_STATIC - CXXFLAGS += -DPURE_STATIC +@IFDEF INSPIRCD_STATIC + CORECXXFLAGS += -DINSPIRCD_STATIC @ENDIF -@DO_EXPORT RUNCC RUNLD CXXFLAGS LDLIBS PICLDFLAGS VERBOSE SOCKETENGINE CORELDFLAGS -@DO_EXPORT SOURCEPATH BUILDPATH PURE_STATIC SPLIT_CC +# Add the users CPPFLAGS/CXXFLAGS to the base ones to allow them to +# override things like -Wfatal-errors if they wish to. +CORECXXFLAGS += $(CPPFLAGS) $(CXXFLAGS) + +@DO_EXPORT CXX CORECXXFLAGS LDLIBS PICLDFLAGS INSPIRCD_VERBOSE SOCKETENGINE CORELDFLAGS +@DO_EXPORT SOURCEPATH BUILDPATH INSPIRCD_STATIC # Default target TARGET = all -@IFDEF M +@IFDEF INSPIRCD_MODULE HEADER = mod-header FOOTER = mod-footer - @BSD_ONLY TARGET = modules/${M:S/.so$//}.so - @GNU_ONLY TARGET = modules/$(M:.so=).so + @TARGET BSD_MAKE TARGET = modules/${INSPIRCD_MODULE:S/.so$//}.so + @TARGET GNU_MAKE TARGET = modules/$(INSPIRCD_MODULE:.so=).so @ENDIF -@IFDEF T +@IFDEF INSPIRCD_TARGET HEADER = FOOTER = target - TARGET = $(T) + TARGET = $(INSPIRCD_TARGET) @ENDIF @IFEQ $(DBGOK) 0 @@ -168,7 +157,7 @@ target: $(HEADER) cd "$(BUILDPATH)"; $(MAKEENV) $(MAKE) -f real.mk $(TARGET) debug: - @${MAKE} D=1 all + @${MAKE} INSPIRCD_DEBUG=1 all debug-header: @echo "*************************************" @@ -185,7 +174,7 @@ debug-header: @echo "*************************************" mod-header: -@IFDEF PURE_STATIC +@IFDEF INSPIRCD_STATIC @echo 'Cannot build single modules in pure-static build' @exit 1 @ENDIF @@ -229,18 +218,29 @@ install: target @-$(INSTALL) -d -o $(INSTUID) -m $(INSTMODE_DIR) $(DATPATH) @-$(INSTALL) -d -o $(INSTUID) -m $(INSTMODE_DIR) $(LOGPATH) @-$(INSTALL) -d -m $(INSTMODE_DIR) $(BINPATH) - @-$(INSTALL) -d -m $(INSTMODE_DIR) $(CONPATH)/examples/aliases @-$(INSTALL) -d -m $(INSTMODE_DIR) $(CONPATH)/examples/modules + @-$(INSTALL) -d -m $(INSTMODE_DIR) $(CONPATH)/examples/services + @-$(INSTALL) -d -m $(INSTMODE_DIR) $(MANPATH) @-$(INSTALL) -d -m $(INSTMODE_DIR) $(MODPATH) [ "$(BUILDPATH)/bin/" -ef $(BINPATH) ] || $(INSTALL) -m $(INSTMODE_BIN) "$(BUILDPATH)/bin/inspircd" $(BINPATH) -@IFNDEF PURE_STATIC +@IFNDEF INSPIRCD_STATIC [ "$(BUILDPATH)/modules/" -ef $(MODPATH) ] || $(INSTALL) -m $(INSTMODE_LIB) "$(BUILDPATH)/modules/"*.so $(MODPATH) @ENDIF - -$(INSTALL) -m $(INSTMODE_BIN) @STARTSCRIPT@ $(BASE) 2>/dev/null - -$(INSTALL) -m $(INSTMODE_LIB) tools/gdbargs $(BASE)/.gdbargs 2>/dev/null + -$(INSTALL) -m $(INSTMODE_BIN) @CONFIGURE_DIRECTORY@/inspircd $(BASE) 2>/dev/null + -$(INSTALL) -m $(INSTMODE_LIB) .gdbargs $(BASE)/.gdbargs 2>/dev/null +@IFEQ $(SYSTEM) darwin + -$(INSTALL) -m $(INSTMODE_BIN) @CONFIGURE_DIRECTORY@/org.inspircd.plist $(BASE) 2>/dev/null +@ENDIF +@IFEQ $(SYSTEM) linux + -$(INSTALL) -m $(INSTMODE_LIB) @CONFIGURE_DIRECTORY@/inspircd.service $(BASE) 2>/dev/null +@ENDIF + -$(INSTALL) -m $(INSTMODE_LIB) @CONFIGURE_DIRECTORY@/inspircd.1 $(MANPATH) 2>/dev/null + -$(INSTALL) -m $(INSTMODE_LIB) @CONFIGURE_DIRECTORY@/inspircd-genssl.1 $(MANPATH) 2>/dev/null + -$(INSTALL) -m $(INSTMODE_BIN) tools/genssl $(BINPATH)/inspircd-genssl 2>/dev/null -$(INSTALL) -m $(INSTMODE_LIB) docs/conf/*.example $(CONPATH)/examples - -$(INSTALL) -m $(INSTMODE_LIB) docs/conf/aliases/*.example $(CONPATH)/examples/aliases -$(INSTALL) -m $(INSTMODE_LIB) docs/conf/modules/*.example $(CONPATH)/examples/modules + -$(INSTALL) -m $(INSTMODE_LIB) docs/conf/services/*.example $(CONPATH)/examples/services + -$(INSTALL) -m $(INSTMODE_LIB) *.pem $(CONPATH) 2>/dev/null @echo "" @echo "*************************************" @echo "* INSTALL COMPLETE! *" @@ -255,11 +255,9 @@ install: target @echo 'Remember to create your config file:' $(CONPATH)/inspircd.conf @echo 'Examples are available at:' $(CONPATH)/examples/ -@GNU_ONLY RCS_FILES = $(wildcard .git/index src/version.sh) -@BSD_ONLY RCS_FILES = src/version.sh -GNUmakefile BSDmakefile: make/template/main.mk configure $(RCS_FILES) - ./configure -update -@BSD_ONLY .MAKEFILEDEPS: BSDmakefile +GNUmakefile BSDmakefile: make/template/main.mk src/version.sh configure @CONFIGURE_CACHE_FILE@ + ./configure --update +@TARGET BSD_MAKE .MAKEFILEDEPS: BSDmakefile clean: @echo Cleaning... @@ -272,21 +270,20 @@ clean: deinstall: -rm -f $(BINPATH)/inspircd -rm -rf $(CONPATH)/examples - -rm -f $(MODPATH)/cmd_*.so + -rm -f $(MANPATH)/inspircd.1 + -rm -f $(MANPATH)/inspircd-genssl.1 -rm -f $(MODPATH)/m_*.so + -rm -f $(MODPATH)/core_*.so -rm -f $(BASE)/.gdbargs + -rm -f $(BASE)/inspircd.service -rm -f $(BASE)/org.inspircd.plist -squeakyclean: distclean - configureclean: - rm -f .config.cache + rm -f .gdbargs rm -f BSDmakefile rm -f GNUmakefile - rm -f include/inspircd_config.h - rm -f include/inspircd_version.h - rm -f inspircd - -rm -f org.inspircd.plist + rm -f include/config.h + rm -rf @CONFIGURE_DIRECTORY@ distclean: clean configureclean -rm -rf "$(SOURCEPATH)/run" @@ -298,11 +295,11 @@ help: @echo 'Use: ${MAKE} [flags] [targets]' @echo '' @echo 'Flags:' - @echo ' V=1 Show the full command being executed instead of "BUILD: dns.cpp"' - @echo ' D=1 Enable debug build, for module development or crash tracing' - @echo ' D=2 Enable debug build with optimizations, for detailed backtraces' - @echo ' DESTDIR= Specify a destination root directory (for tarball creation)' - @echo ' -j <N> Run a parallel build using N jobs' + @echo ' INSPIRCD_VERBOSE=1 Show the full command being executed instead of "BUILD: dns.cpp"' + @echo ' INSPIRCD_DEBUG=1 Enable debug build, for module development or crash tracing' + @echo ' INSPIRCD_DEBUG=2 Enable debug build with optimizations, for detailed backtraces' + @echo ' DESTDIR= Specify a destination root directory (for tarball creation)' + @echo ' -j <N> Run a parallel build using N jobs' @echo '' @echo 'Targets:' @echo ' all Complete build of InspIRCd, without installing (default)' @@ -310,10 +307,10 @@ help: @echo ' Currently installs to ${BASE}' @echo ' debug Compile a debug build. Equivalent to "make D=1 all"' @echo '' - @echo ' M=m_foo Builds a single module (cmd_foo also works here)' - @echo ' T=target Builds a user-specified target, such as "inspircd" or "modules"' - @echo ' Other targets are specified by their path in the build directory' - @echo ' Multiple targets may be separated by a space' + @echo ' INSPIRCD_MODULE=m_foo Builds a single module (core_foo also works here)' + @echo ' INSPIRCD_TARGET=target Builds a user-specified target, such as "inspircd" or "modules"' + @echo ' Other targets are specified by their path in the build directory' + @echo ' Multiple targets may be separated by a space' @echo '' @echo ' clean Cleans object files produced by the compile' @echo ' distclean Cleans all generated files (build, configure, run, etc)' @@ -322,4 +319,4 @@ help: .NOTPARALLEL: -.PHONY: all target debug debug-header mod-header mod-footer std-header finishmessage install clean deinstall squeakyclean configureclean help +.PHONY: all target debug debug-header mod-header mod-footer std-header finishmessage install clean deinstall configureclean help diff --git a/make/template/org.inspircd.plist b/make/template/org.inspircd.plist index 4dac209f6..ae4e90916 100644 --- a/make/template/org.inspircd.plist +++ b/make/template/org.inspircd.plist @@ -1,3 +1,4 @@ +%platform darwin <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> @@ -26,6 +27,8 @@ <key>StandardErrorPath</key> <string>@LOG_DIR@/launchd-stderr.log</string> <key>UserName</key> - <string>ircdaemon</string> + <string>@USER@</string> + <key>GroupName</key> + <string>@GROUP@</string> </dict> </plist> diff --git a/make/check_epoll.cpp b/make/test/clock_gettime.cpp index a5ed1c10b..d111d591f 100644 --- a/make/check_epoll.cpp +++ b/make/test/clock_gettime.cpp @@ -1,7 +1,7 @@ /* * InspIRCd -- Internet Relay Chat Daemon * - * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> + * Copyright (C) 2013 Peter Powell <petpow@saberuk.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public @@ -17,9 +17,10 @@ */ -#include <sys/epoll.h> +#include <time.h> int main() { - int fd = epoll_create(1); - return (fd < 0); + timespec time_spec; + clock_gettime(CLOCK_REALTIME, &time_spec); + return 0; } diff --git a/make/check_stdint.cpp b/make/test/compiler.cpp index fbd01b80d..f01423325 100644 --- a/make/check_stdint.cpp +++ b/make/test/compiler.cpp @@ -1,7 +1,8 @@ /* * InspIRCd -- Internet Relay Chat Daemon * - * Copyright (C) 2015 Peter Powell <petpow@saberuk.com> + * Copyright (C) 2016 Attila Molnar <attilamolnar@hush.com> + * Copyright (C) 2014-2015 Peter Powell <petpow@saberuk.com> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public @@ -17,9 +18,22 @@ */ -#include <stdint.h> +#include <iostream> +#if defined _LIBCPP_VERSION +# include <array> +# include <type_traits> +# include <unordered_map> +#else +# include <tr1/array> +# include <tr1/type_traits> +# include <tr1/unordered_map> +#endif + +#if defined __llvm__ && !defined __clang__ && __GNUC__ == 4 && __GNUC_MINOR__ == 2 && __GNUC_PATCHLEVEL__ == 1 +# error "LLVM-GCC 4.2.1 has broken visibility support." +#endif int main() { - uint32_t ret = 0; - return ret; + std::cout << "Hello, World!" << std::endl; + return 0; } diff --git a/make/test/compiler_info.cpp b/make/test/compiler_info.cpp new file mode 100644 index 000000000..10b156fc8 --- /dev/null +++ b/make/test/compiler_info.cpp @@ -0,0 +1,41 @@ +/* + * InspIRCd -- Internet Relay Chat Daemon + * + * Copyright (C) 2017 Peter Powell <petpow@saberuk.com> + * + * This file is part of InspIRCd. InspIRCd is free software: you can + * redistribute it and/or modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include <iostream> + +#if defined __INTEL_COMPILER // Also defines __clang__ and __GNUC__ +# define INSPIRCD_COMPILER_NAME "Intel" +# define INSPIRCD_COMPILER_VERSION (__INTEL_COMPILER / 100) << '.' << (__INTEL_COMPILER % 100) +#elif defined __clang__ // Also defines __GNUC__ +# if defined __apple_build_version__ +# define INSPIRCD_COMPILER_NAME "AppleClang" +# else +# define INSPIRCD_COMPILER_NAME "Clang" +# endif +# define INSPIRCD_COMPILER_VERSION __clang_major__ << '.' << __clang_minor__ +#elif defined __GNUC__ +# define INSPIRCD_COMPILER_NAME "GCC" +# define INSPIRCD_COMPILER_VERSION __GNUC__ << '.' << __GNUC_MINOR__ +#endif + +int main() { + std::cout << "NAME " << INSPIRCD_COMPILER_NAME << std::endl + << "VERSION " << INSPIRCD_COMPILER_VERSION << std::endl; + return 0; +} diff --git a/make/check_eventfd.cpp b/make/test/eventfd.cpp index 9b38b793b..9b38b793b 100644 --- a/make/check_eventfd.cpp +++ b/make/test/eventfd.cpp diff --git a/make/check_kqueue.cpp b/make/test/kqueue.cpp index 6034253df..708677adf 100644 --- a/make/check_kqueue.cpp +++ b/make/test/kqueue.cpp @@ -1,7 +1,7 @@ /* * InspIRCd -- Internet Relay Chat Daemon * - * Copyright (C) 2015 Peter Powell <petpow@saberuk.com> + * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public diff --git a/make/unit-cc.pl b/make/unit-cc.pl index a494fb74b..1cf6cf866 100755 --- a/make/unit-cc.pl +++ b/make/unit-cc.pl @@ -19,32 +19,23 @@ # +BEGIN { + push @INC, $ENV{SOURCEPATH}; + require 5.10.0; +} + use strict; -use warnings; -BEGIN { push @INC, $ENV{SOURCEPATH}; } -use make::configure; +use warnings FATAL => qw(all); + +use File::Spec::Functions qw(abs2rel); + +use make::console; +use make::directive; chdir $ENV{BUILDPATH}; my $type = shift; my $out = shift; -my $verbose = ($type =~ s/-v$//); - -## BEGIN HACK: REMOVE IN 2.2! -sub read_config_cache { - my %cfg = (); - open(CACHE, '../.config.cache') or return %cfg; - while (my $line = <CACHE>) { - next if $line =~ /^\s*($|\#)/; - my ($key, $value) = ($line =~ /^(\S+)="(.*)"$/); - $cfg{$key} = $value; - } - close(CACHE); - return %cfg; -} - -our %config = read_config_cache(); -## END HACK if ($type eq 'gen-ld') { do_static_find(@ARGV); @@ -65,10 +56,25 @@ if ($type eq 'gen-ld') { } exit 1; +sub message($$$) { + my ($type, $file, $command) = @_; + if ($ENV{INSPIRCD_VERBOSE}) { + print "$command\n"; + } else { + print_format "\t<|GREEN $type:|>\t\t$file\n"; + } +} + +sub rpath($) { + my $message = shift; + $message =~ s/-L(\S+)/-Wl,-rpath,$1 -L$1/g unless defined $ENV{INSPIRCD_DISABLE_RPATH}; + return $message; +} + sub do_static_find { my @flags; for my $file (@ARGV) { - push @flags, getlinkerflags($file); + push @flags, rpath(get_directive($file, 'LinkerFlags', '')); } open F, '>', $out; print F join ' ', @flags; @@ -77,32 +83,37 @@ sub do_static_find { } sub do_static_link { - my $execstr = "$ENV{RUNLD} -o $out $ENV{CORELDFLAGS}"; + my $execstr = "$ENV{CXX} -o $out $ENV{CORELDFLAGS}"; + my $link_flags = ''; for (@ARGV) { if (/\.cmd$/) { open F, '<', $_; my $libs = <F>; chomp $libs; - $execstr .= ' '.$libs; + $link_flags .= ' '.$libs; close F; } else { $execstr .= ' '.$_; } } - $execstr .= ' '.$ENV{LDLIBS}; - print "$execstr\n" if $verbose; + $execstr .= ' '.$ENV{LDLIBS}.' '.$link_flags; + message 'LINK', $out, $execstr; exec $execstr; } sub do_core_link { - my $execstr = "$ENV{RUNLD} -o $out $ENV{CORELDFLAGS} @_ $ENV{LDLIBS}"; - print "$execstr\n" if $verbose; + my $execstr = "$ENV{CXX} -o $out $ENV{CORELDFLAGS} @_ $ENV{LDLIBS}"; + message 'LINK', $out, $execstr; exec $execstr; } sub do_link_dir { - my $execstr = "$ENV{RUNLD} -o $out $ENV{PICLDFLAGS} @_"; - print "$execstr\n" if $verbose; + my ($dir, $link_flags) = (shift, ''); + for my $file (<$dir/*.cpp>) { + $link_flags .= rpath(get_directive($file, 'LinkerFlags', '')) . ' '; + } + my $execstr = "$ENV{CXX} -o $out $ENV{PICLDFLAGS} $link_flags @_"; + message 'LINK', $out, $execstr; exec $execstr; } @@ -111,27 +122,22 @@ sub do_compile { my $flags = ''; my $libs = ''; - my $binary = $ENV{RUNCC}; if ($do_compile) { - $flags = $ENV{CXXFLAGS}; - $flags =~ s/ -pedantic// if nopedantic($file); - $flags .= ' ' . getcompilerflags($file); + $flags = $ENV{CORECXXFLAGS} . ' ' . get_directive($file, 'CompilerFlags', ''); - if ($file =~ m#(?:^|/)((?:m|cmd)_[^/. ]+)(?:\.cpp|/.*\.cpp)$#) { - $flags .= ' -DMODNAME='.$1.'.so'; + if ($file =~ m#(?:^|/)((?:m|core)_[^/. ]+)(?:\.cpp|/.*\.cpp)$#) { + $flags .= ' -DMODNAME=\\"'.$1.'\\"'; } - } else { - $binary = $ENV{RUNLD}; } if ($do_link) { $flags = join ' ', $flags, $ENV{PICLDFLAGS}; - $libs = join ' ', getlinkerflags($file); + $libs = rpath(get_directive($file, 'LinkerFlags', '')); } else { $flags .= ' -c'; } - my $execstr = "$binary -o $out $flags $file $libs"; - print "$execstr\n" if $verbose; + my $execstr = "$ENV{CXX} -o $out $flags $file $libs"; + message 'BUILD', abs2rel($file, "$ENV{SOURCEPATH}/src"), $execstr; exec $execstr; } diff --git a/make/utilities.pm b/make/utilities.pm deleted file mode 100644 index baba584ad..000000000 --- a/make/utilities.pm +++ /dev/null @@ -1,471 +0,0 @@ -# -# InspIRCd -- Internet Relay Chat Daemon -# -# Copyright (C) 2010 Daniel De Graaf <danieldg@inspircd.org> -# Copyright (C) 2007-2008 Craig Edwards <craigedwards@brainbox.cc> -# Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org> -# Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> -# -# This file is part of InspIRCd. InspIRCd is free software: you can -# redistribute it and/or modify it under the terms of the GNU General Public -# License as published by the Free Software Foundation, version 2. -# -# This program is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more -# details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. -# - - -package make::utilities; - -require 5.8.0; - -use strict; -use warnings FATAL => qw(all); - -use Exporter 'import'; -use POSIX; -use File::Temp; -use Getopt::Long; -use Fcntl; -our @EXPORT = qw(make_rpath pkgconfig_get_include_dirs pkgconfig_get_lib_dirs pkgconfig_check_version translate_functions promptstring); - -# Parse the output of a *_config program, -# such as pcre_config, take out the -L -# directive and return an rpath for it. - -# \e[1;32msrc/Makefile\e[0m - -my %already_added = (); -my $if_skip_lines = 0; - -sub promptstring($$$$$) -{ - my ($prompt, $configitem, $default, $package, $commandlineswitch) = @_; - my $var; - if (!$main::interactive) - { - my $opt_commandlineswitch; - GetOptions ("$commandlineswitch=s" => \$opt_commandlineswitch); - if (defined $opt_commandlineswitch) - { - print "\e[1;32m$opt_commandlineswitch\e[0m\n"; - $var = $opt_commandlineswitch; - } - else - { - die "Could not detect $package! Please specify the $prompt via the command line option \e[1;32m--$commandlineswitch=\"/path/to/file\"\e[0m"; - } - } - else - { - print "\nPlease enter the $prompt?\n"; - print "[\e[1;32m$default\e[0m] -> "; - chomp($var = <STDIN>); - } - if ($var eq "") - { - $var = $default; - } - $main::config{$configitem} = $var; -} - -sub make_rpath($;$) -{ - my ($executable, $module) = @_; - return "" if defined $ENV{DISABLE_RPATH}; - chomp(my $data = `$executable`); - my $output = ""; - while ($data =~ /-L(\S+)/) - { - my $libpath = $1; - if (!exists $already_added{$libpath}) - { - print "Adding runtime library path to \e[1;32m$module\e[0m ... \e[1;32m$libpath\e[0m\n"; - $already_added{$libpath} = 1; - } - $output .= "-Wl,-rpath -Wl,$libpath -L$libpath "; - $data =~ s/-L(\S+)//; - } - return $output; -} - -sub extend_pkg_path() -{ - return if defined $ENV{DISABLE_EXTEND_PKG_PATH}; - if (!exists $ENV{PKG_CONFIG_PATH}) - { - $ENV{PKG_CONFIG_PATH} = "/usr/lib/pkgconfig:/usr/local/lib/pkgconfig:/usr/local/libdata/pkgconfig:/usr/X11R6/libdata/pkgconfig"; - } - else - { - $ENV{PKG_CONFIG_PATH} .= ":/usr/local/lib/pkgconfig:/usr/local/libdata/pkgconfig:/usr/X11R6/libdata/pkgconfig"; - } -} - -sub pkgconfig_get_include_dirs($$$;$) -{ - my ($packagename, $headername, $defaults, $module) = @_; - - my $key = "default_includedir_$packagename"; - if (exists $main::config{$key}) - { - print "Locating include directory for package \e[1;32m$packagename\e[0m for module \e[1;32m$module\e[0m... "; - my $ret = $main::config{$key}; - print "\e[1;32m$ret\e[0m (cached)\n"; - return $ret; - } - - extend_pkg_path(); - - print "Locating include directory for package \e[1;32m$packagename\e[0m for module \e[1;32m$module\e[0m... "; - - my $v = `pkg-config --modversion $packagename 2>/dev/null`; - my $ret = `pkg-config --cflags $packagename 2>/dev/null`; - my $foo = ""; - if ((!defined $v) || ($v eq "")) - { - print "\e[31mCould not find $packagename via pkg-config\e[m (\e[1;32mplease install pkg-config\e[m)\n"; - my $locbin = $^O eq 'solaris' ? 'slocate' : 'locate'; - $foo = `$locbin "$headername" 2>/dev/null | head -n 1`; - my $find = $foo =~ /(.+)\Q$headername\E/ ? $1 : ''; - chomp($find); - if ((defined $find) && ($find ne "") && ($find ne $packagename)) - { - print "(\e[1;32mFound via search\e[0m) "; - $foo = "-I$1"; - } - else - { - $foo = " "; - undef $v; - } - $ret = "$foo"; - } - if (($defaults ne "") && (($ret eq "") || (!defined $ret))) - { - $ret = "$foo " . $defaults; - } - chomp($ret); - if ((($ret eq " ") || (!defined $ret)) && ((!defined $v) || ($v eq ""))) - { - my $key = "default_includedir_$packagename"; - if (exists $main::config{$key}) - { - $ret = $main::config{$key}; - } - else - { - $headername =~ s/^\///; - promptstring("path to the directory containing $headername", $key, "/usr/include",$packagename,"$packagename-includes"); - $packagename =~ tr/a-z/A-Z/; - if (defined $v) - { - $main::config{$key} = "-I$main::config{$key}" . " $defaults -DVERSION_$packagename=\"$v\""; - } - else - { - $main::config{$key} = "-I$main::config{$key}" . " $defaults -DVERSION_$packagename=\"0.0\""; - } - $main::config{$key} =~ s/^\s+//g; - $ret = $main::config{$key}; - return $ret; - } - } - else - { - chomp($v); - my $key = "default_includedir_$packagename"; - $packagename =~ tr/a-z/A-Z/; - $main::config{$key} = "$ret -DVERSION_$packagename=\"$v\""; - $main::config{$key} =~ s/^\s+//g; - $ret = $main::config{$key}; - print "\e[1;32m$ret\e[0m (version $v)\n"; - } - $ret =~ s/^\s+//g; - return $ret; -} - -sub pkgconfig_check_version($$;$) -{ - my ($packagename, $version, $module) = @_; - - extend_pkg_path(); - - print "Checking version of package \e[1;32m$packagename\e[0m is >= \e[1;32m$version\e[0m... "; - - my $v = `pkg-config --modversion $packagename 2>/dev/null`; - if (defined $v) - { - chomp($v); - } - if ((defined $v) && ($v ne "")) - { - if (!system "pkg-config --atleast-version $version $packagename") - { - print "\e[1;32mYes (version $v)\e[0m\n"; - return 1; - } - else - { - print "\e[1;32mNo (version $v)\e[0m\n"; - return 0; - } - } - # If we didnt find it, we cant definitively say its too old. - # Return ok, and let pkgconflibs() or pkgconfincludes() pick up - # the missing library later on. - print "\e[1;32mNo (not found)\e[0m\n"; - return 1; -} - -sub pkgconfig_get_lib_dirs($$$;$) -{ - my ($packagename, $libname, $defaults, $module) = @_; - - my $key = "default_libdir_$packagename"; - if (exists $main::config{$key}) - { - print "Locating library directory for package \e[1;32m$packagename\e[0m for module \e[1;32m$module\e[0m... "; - my $ret = $main::config{$key}; - print "\e[1;32m$ret\e[0m (cached)\n"; - return $ret; - } - - extend_pkg_path(); - - print "Locating library directory for package \e[1;32m$packagename\e[0m for module \e[1;32m$module\e[0m... "; - - my $v = `pkg-config --modversion $packagename 2>/dev/null`; - my $ret = `pkg-config --libs $packagename 2>/dev/null`; - - my $foo = ""; - if ((!defined $v) || ($v eq "")) - { - my $locbin = $^O eq 'solaris' ? 'slocate' : 'locate'; - $foo = `$locbin "$libname" | head -n 1`; - $foo =~ /(.+)\Q$libname\E/; - my $find = $1; - chomp($find); - if ((defined $find) && ($find ne "") && ($find ne $packagename)) - { - print "(\e[1;32mFound via search\e[0m) "; - $foo = "-L$1"; - } - else - { - $foo = " "; - undef $v; - } - $ret = "$foo"; - } - - if (($defaults ne "") && (($ret eq "") || (!defined $ret))) - { - $ret = "$foo " . $defaults; - } - chomp($ret); - if ((($ret eq " ") || (!defined $ret)) && ((!defined $v) || ($v eq ""))) - { - my $key = "default_libdir_$packagename"; - if (exists $main::config{$key}) - { - $ret = $main::config{$key}; - } - else - { - $libname =~ s/^\///; - promptstring("path to the directory containing $libname", $key, "/usr/lib",$packagename,"$packagename-libs"); - $main::config{$key} = "-L$main::config{$key}" . " $defaults"; - $main::config{$key} =~ s/^\s+//g; - $ret = $main::config{$key}; - return $ret; - } - } - else - { - chomp($v); - print "\e[1;32m$ret\e[0m (version $v)\n"; - my $key = "default_libdir_$packagename"; - $main::config{$key} = $ret; - $main::config{$key} =~ s/^\s+//g; - $ret =~ s/^\s+//g; - } - $ret =~ s/^\s+//g; - return $ret; -} - -# Translate a $CompileFlags etc line and parse out function calls -# to functions within these modules at configure time. -sub translate_functions($$) -{ - my ($line,$module) = @_; - - eval - { - $module =~ /modules*\/(.+?)$/; - $module = $1; - - # This is only a cursory check, just designed to catch casual accidental use of backticks. - # There are pleanty of ways around it, but its not supposed to be for security, just checking - # that people are using the new configuration api as theyre supposed to and not just using - # backticks instead of eval(), being as eval has accountability. People wanting to get around - # the accountability will do so anyway. - if (($line =~ /`/) && ($line !~ /eval\(.+?`.+?\)/)) - { - die "Developers should no longer use backticks in configuration macros. Please use exec() and eval() macros instead. Offending line: $line (In module: $module)"; - } - - if ($line =~ /if(gt|lt)\("(.+?)","(.+?)"\)/) { - chomp(my $result = `$2 2>/dev/null`); - if (($1 eq 'gt' && $result le $3) || ($1 eq 'lt' && $result ge $3)) { - $line = substr $line, 0, $-[0]; - } else { - $line =~ s/if$1\("$2","$3"\)//; - } - } - - if ($line =~ /ifuname\(\!"(\w+)"\)/) - { - my $uname = $1; - if ($uname eq $^O) - { - $line = ""; - return ""; - } - - $line =~ s/ifuname\(\!"(.+?)"\)//; - } - - if ($line =~ /ifuname\("(\w+)"\)/) - { - my $uname = $1; - if ($uname ne $^O) - { - $line = ""; - return ""; - } - - $line =~ s/ifuname\("(.+?)"\)//; - } - - if ($line =~ /if\("(\w+)"\)/) - { - if (defined $main::config{$1}) - { - if (($main::config{$1} !~ /y/i) and ($main::config{$1} ne "1")) - { - $line = ""; - return ""; - } - } - - $line =~ s/if\("(.+?)"\)//; - } - if ($line =~ /if\(\!"(\w+)"\)/) - { - if (!exists $main::config{$1}) - { - $line = ""; - return ""; - } - else - { - if (defined $1) - { - if (exists ($main::config{$1}) and (($main::config{$1} =~ /y/i) or ($main::config{$1} eq "1"))) - { - $line = ""; - return ""; - } - } - } - - $line =~ s/if\(\!"(.+?)"\)//; - } - while ($line =~ /exec\("(.+?)"\)/) - { - print "Executing program for module \e[1;32m$module\e[0m ... \e[1;32m$1\e[0m\n"; - my $replace = `$1`; - die $replace if ($replace =~ /Configuration failed/); - chomp($replace); - $line =~ s/exec\("(.+?)"\)/$replace/; - } - while ($line =~ /execruntime\("(.+?)"\)/) - { - $line =~ s/execruntime\("(.+?)"\)/`$1`/; - } - while ($line =~ /eval\("(.+?)"\)/) - { - print "Evaluating perl code for module \e[1;32m$module\e[0m ... "; - my $tmpfile; - do - { - $tmpfile = File::Temp::tmpnam(); - } until sysopen(TF, $tmpfile, O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW, 0700); - print "(Created and executed \e[1;32m$tmpfile\e[0m)\n"; - print TF $1; - close TF; - my $replace = `perl $tmpfile`; - chomp($replace); - unlink($tmpfile); - $line =~ s/eval\("(.+?)"\)/$replace/; - } - while ($line =~ /pkgconflibs\("(.+?)","(.+?)","(.+?)"\)/) - { - my $replace = pkgconfig_get_lib_dirs($1, $2, $3, $module); - $line =~ s/pkgconflibs\("(.+?)","(.+?)","(.+?)"\)/$replace/; - } - while ($line =~ /pkgconfversion\("(.+?)","(.+?)"\)/) - { - if (pkgconfig_check_version($1, $2, $module) != 1) - { - die "Version of package $1 is too old. Please upgrade it to version \e[1;32m$2\e[0m or greater and try again."; - } - # This doesnt actually get replaced with anything - $line =~ s/pkgconfversion\("(.+?)","(.+?)"\)//; - } - while ($line =~ /pkgconflibs\("(.+?)","(.+?)",""\)/) - { - my $replace = pkgconfig_get_lib_dirs($1, $2, "", $module); - $line =~ s/pkgconflibs\("(.+?)","(.+?)",""\)/$replace/; - } - while ($line =~ /pkgconfincludes\("(.+?)","(.+?)",""\)/) - { - my $replace = pkgconfig_get_include_dirs($1, $2, "", $module); - $line =~ s/pkgconfincludes\("(.+?)","(.+?)",""\)/$replace/; - } - while ($line =~ /pkgconfincludes\("(.+?)","(.+?)","(.+?)"\)/) - { - my $replace = pkgconfig_get_include_dirs($1, $2, $3, $module); - $line =~ s/pkgconfincludes\("(.+?)","(.+?)","(.+?)"\)/$replace/; - } - while ($line =~ /rpath\("(.+?)"\)/) - { - my $replace = make_rpath($1,$module); - $line =~ s/rpath\("(.+?)"\)/$replace/; - } - }; - if ($@) - { - my $err = $@; - #$err =~ s/at .+? line \d+.*//g; - print "\n\nConfiguration failed. The following error occured:\n\n$err\n"; - print "\nMake sure you have pkg-config installed\n"; - print "\nIn the case of gnutls configuration errors on debian,\n"; - print "Ubuntu, etc, you should ensure that you have installed\n"; - print "gnutls-bin as well as libgnutls-dev and libgnutls.\n"; - exit; - } - else - { - return $line; - } -} - -1; - |