]> git.netwichtig.de Git - user/henk/code/inspircd.git/blobdiff - make/configure.pm
Update copyright headers.
[user/henk/code/inspircd.git] / make / configure.pm
index 6b4693d453532d216f578a771e6c2fb193a72a19..a49ad13186f864995e2c5c36e649530b929df3cc 100644 (file)
@@ -1,10 +1,10 @@
 #
 # InspIRCd -- Internet Relay Chat Daemon
 #
 #
 # InspIRCd -- Internet Relay Chat Daemon
 #
-#   Copyright (C) 2012-2014 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>
+#   Copyright (C) 2020 Nicole Kleinhoff <ilbelkyr@shalture.org>
+#   Copyright (C) 2013-2021 Sadie Powell <sadie@witchery.services>
+#   Copyright (C) 2012 Robby <robby@chatbelgie.be>
+#   Copyright (C) 2007-2008 Craig Edwards <brain@inspircd.org>
 #   Copyright (C) 2007 Dennis Friis <peavey@inspircd.org>
 #
 # This file is part of InspIRCd.  InspIRCd is free software: you can
 #   Copyright (C) 2007 Dennis Friis <peavey@inspircd.org>
 #
 # This file is part of InspIRCd.  InspIRCd is free software: you can
 #
 
 
 #
 
 
-BEGIN {
-       require 5.10.0;
-}
-
 package make::configure;
 
 package make::configure;
 
-use feature ':5.10';
+use v5.10.0;
 use strict;
 use warnings FATAL => qw(all);
 
 use strict;
 use warnings FATAL => qw(all);
 
-use Cwd                   qw(getcwd);
 use Exporter              qw(import);
 use File::Basename        qw(basename dirname);
 use Exporter              qw(import);
 use File::Basename        qw(basename dirname);
-use File::Spec::Functions qw(catfile);
+use File::Spec::Functions qw(abs2rel catdir catfile);
 
 use make::common;
 use make::console;
 
 
 use make::common;
 use make::console;
 
-use constant CONFIGURE_DIRECTORY     => '.configure';
+use constant CONFIGURE_ROOT          => dirname dirname __FILE__;
+use constant CONFIGURE_DIRECTORY     => catdir(CONFIGURE_ROOT, '.configure');
 use constant CONFIGURE_CACHE_FILE    => catfile(CONFIGURE_DIRECTORY, 'cache.cfg');
 use constant CONFIGURE_CACHE_VERSION => '1';
 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
 
 our @EXPORT = qw(CONFIGURE_CACHE_FILE
                  CONFIGURE_CACHE_VERSION
+                 CONFIGURE_DIRECTORY
                  cmd_clean
                  cmd_help
                  cmd_update
                  run_test
                  test_file
                  test_header
                  cmd_clean
                  cmd_help
                  cmd_update
                  run_test
                  test_file
                  test_header
-                 read_configure_cache
+                 module_expand
+                 module_shrink
                  write_configure_cache
                  get_compiler_info
                  find_compiler
                  write_configure_cache
                  get_compiler_info
                  find_compiler
@@ -59,15 +58,13 @@ our @EXPORT = qw(CONFIGURE_CACHE_FILE
 
 sub __get_socketengines {
        my @socketengines;
 
 sub __get_socketengines {
        my @socketengines;
-       foreach (<src/socketengines/socketengine_*.cpp>) {
+       for (<${\CONFIGURE_ROOT}/src/socketengines/socketengine_*.cpp>) {
                s/src\/socketengines\/socketengine_(\w+)\.cpp/$1/;
                push @socketengines, $1;
        }
        return @socketengines;
 }
 
                s/src\/socketengines\/socketengine_(\w+)\.cpp/$1/;
                push @socketengines, $1;
        }
        return @socketengines;
 }
 
-# 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
 sub __get_template_settings($$$) {
 
        # These are actually hash references
@@ -90,14 +87,13 @@ sub __get_template_settings($$$) {
        $settings{CONFIGURE_DIRECTORY} = CONFIGURE_DIRECTORY;
        $settings{CONFIGURE_CACHE_FILE} = CONFIGURE_CACHE_FILE;
        $settings{SYSTEM_NAME} = lc $^O;
        $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 __test_compiler($) {
        my $compiler = shift;
 
        return %settings;
 }
 
 sub __test_compiler($) {
        my $compiler = shift;
-       return 0 unless run_test("`$compiler`", !system "$compiler -v >/dev/null 2>&1");
+       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;
 }
        return 0 unless run_test("`$compiler`", test_file($compiler, 'compiler.cpp', '-fno-rtti'), 'compatible');
        return 1;
 }
@@ -107,71 +103,85 @@ sub cmd_clean {
 }
 
 sub cmd_help {
 }
 
 sub cmd_help {
-       my $PWD = getcwd();
        my $SELIST = join ', ', __get_socketengines();
        my $SELIST = join ', ', __get_socketengines();
-       print <<EOH;
-Usage: $0 [options]
+       print console_format <<EOH;
+<|GREEN Usage:|> <|BOLD $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.
 
 
 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
+<|GREEN PATH OPTIONS|>
 
 
-  --system                      Automatically set up the installation paths
-                                for system-wide installation.
-  --prefix=[dir]                The root install directory. If this is set then
+  <|BOLD --portable|>                    Automatically set up the installation paths for
+                                portable installation.
+  <|BOLD --system|>                      Automatically set up the installation paths for
+                                system-wide installation.
+  <|BOLD --prefix <DIR>|>                The root install directory. If this is set then
                                 all subdirectories will be adjusted accordingly.
                                 all subdirectories will be adjusted accordingly.
-                                [$PWD/run]
-  --binary-dir=[dir]            The location where the main server binary is
+                                [${\CONFIGURE_ROOT}/run]
+  <|BOLD --binary-dir <DIR>|>            The location where the main server binary is
                                 stored.
                                 stored.
-                                [$PWD/run/bin]
-  --config-dir=[dir]            The location where the configuration files and
+                                [${\CONFIGURE_ROOT}/run/bin]
+  <|BOLD --config-dir <DIR>|>            The location where the configuration files and
                                 SSL certificates are stored.
                                 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
+                                [${\CONFIGURE_ROOT}/run/conf]
+  <|BOLD --data-dir <DIR>|>              The location where the data files, such as the
+                                xline database, are stored.
+                                [${\CONFIGURE_ROOT}/run/data]
+  <|BOLD --example-dir <DIR>|>           The location where the example configuration
+                                files and SQL schemas are stored.
+                                [${\CONFIGURE_ROOT}/run/conf/examples]
+  <|BOLD --log-dir <DIR>|>               The location where the log files are stored.
+                                [${\CONFIGURE_ROOT}/run/logs]
+  <|BOLD --manual-dir <DIR>|>            The location where the manual files are stored.
+                                [${\CONFIGURE_ROOT}/run/manuals]
+  <|BOLD --module-dir <DIR>|>            The location where the loadable modules are
                                 stored.
                                 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
+                                [${\CONFIGURE_ROOT}/run/modules]
+  <|BOLD --runtime-dir <DIR>|>            The location where the runtime files, such as
+                                the pid file, are stored.
+                                [${\CONFIGURE_ROOT}/run/data]
+  <|BOLD --script-dir <DIR>|>            The location where the scripts, such as the
+                                init scripts, are stored.
+                                [${\CONFIGURE_ROOT}/run]
+
+<|GREEN EXTRA MODULE OPTIONS|>
+
+  <|BOLD --enable-extras <MODULE>|>      Enables a comma separated list of extra modules.
+  <|BOLD --disable-extras <MODULE>|>     Disables a comma separated list of extra modules.
+  <|BOLD --list-extras|>                 Shows the availability status of all extra
                                 modules.
 
                                 modules.
 
-MISC OPTIONS
+<|GREEN MISC OPTIONS|>
 
 
-  --clean                       Remove the configuration cache file and start
+  <|BOLD --clean|>                       Remove the configuration cache file and start
                                 the interactive configuration wizard.
                                 the interactive configuration wizard.
-  --disable-interactive         Disables the interactive configuration wizard.
-  --distribution-label=[text]   Sets a distribution specific version label in
+  <|BOLD --disable-auto-extras|>         Disables automatically enabling extra modules
+                                for which the dependencies are available.
+  <|BOLD --disable-interactive|>         Disables the interactive configuration wizard.
+  <|BOLD --distribution-label <TEXT>|>   Sets a distribution specific version label in
                                 the build configuration.
                                 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
+  <|BOLD --gid <ID|NAME>|>               Sets the group to run InspIRCd as.
+  <|BOLD --help|>                        Show this message and exit.
+  <|BOLD --socketengine <NAME>|>         Sets the socket engine to be used. Possible
                                 values are $SELIST.
                                 values are $SELIST.
-  --uid=[id|name]               Sets the user to run InspIRCd as.
-  --update                      Updates the build environment with the settings
+  <|BOLD --uid [ID|NAME]|>               Sets the user to run InspIRCd as.
+  <|BOLD --update|>                      Updates the build environment with the settings
                                 from the cache.
 
                                 from the cache.
 
+<|GREEN FLAGS|>
 
 
-FLAGS
-
-  CXX=[name]                    Sets the C++ compiler to use when building the
+  <|BOLD 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.
                                 server. If not specified then the build system
                                 will search for c++, g++, clang++ or icpc.
+  <|BOLD INSPIRCD_VERBOSE=<0|1>|>        Shows additional information for debugging.
 
 If you have any problems with configuring InspIRCd then visit our IRC channel
 
 If you have any problems with configuring InspIRCd then visit our IRC channel
-at irc.inspircd.org #InspIRCd for support.
+at irc.inspircd.org #InspIRCd or create a support discussion at
+https://github.com/inspircd/inspircd/discussions.
 
 
+Packagers: see https://docs.inspircd.org/packaging/ for packaging advice.
 EOH
        exit 0;
 }
 EOH
        exit 0;
 }
@@ -179,7 +189,9 @@ EOH
 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...';
 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_configure_cache();
+       my %config = read_config_file(CONFIGURE_CACHE_FILE);
+       $config{EXAMPLE_DIR} //= catdir $config{CONFIG_DIR}, 'examples';
+       $config{RUNTIME_DIR} //= $config{DATA_DIR};
        my %compiler = get_compiler_info($config{CXX});
        my %version = get_version $config{DISTRIBUTION};
        parse_templates(\%config, \%compiler, \%version);
        my %compiler = get_compiler_info($config{CXX});
        my %version = get_version $config{DISTRIBUTION};
        parse_templates(\%config, \%compiler, \%version);
@@ -190,8 +202,8 @@ sub cmd_update {
 sub run_test($$;$) {
        my ($what, $result, $adjective) = @_;
        $adjective //= 'available';
 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";
+       print console_format "Checking whether <|GREEN $what|> is $adjective ... ";
+       say console_format($result ? "<|GREEN yes|>" : "<|RED no|>");
        return $result;
 }
 
        return $result;
 }
 
@@ -199,69 +211,61 @@ sub test_file($$;$) {
        my ($compiler, $file, $args) = @_;
        my $status = 0;
        $args //= '';
        my ($compiler, $file, $args) = @_;
        my $status = 0;
        $args //= '';
-       $status ||= system "$compiler -o __test_$file make/test/$file $args >/dev/null 2>&1";
-       $status ||= system "./__test_$file >/dev/null 2>&1";
-       unlink "./__test_$file";
+       $status ||= system "$compiler -o ${\CONFIGURE_ROOT}/__test_$file ${\CONFIGURE_ROOT}/make/test/$file $args ${\CONFIGURE_ERROR_PIPE}";
+       $status ||= system "${\CONFIGURE_ROOT}/__test_$file ${\CONFIGURE_ERROR_PIPE}";
+       unlink "${\CONFIGURE_ROOT}/__test_$file";
        return !$status;
 }
 
 sub test_header($$;$) {
        my ($compiler, $header, $args) = @_;
        $args //= '';
        return !$status;
 }
 
 sub test_header($$;$) {
        my ($compiler, $header, $args) = @_;
        $args //= '';
-       open(COMPILER, "| $compiler -E - $args >/dev/null 2>&1") or return 0;
-       print COMPILER "#include <$header>";
-       close(COMPILER);
+       open(my $fh, "| $compiler -E - $args ${\CONFIGURE_ERROR_PIPE}") or return 0;
+       print $fh "#include <$header>";
+       close $fh;
        return !$?;
 }
 
        return !$?;
 }
 
-sub read_configure_cache {
-       my %config;
-       open(CACHE, CONFIGURE_CACHE_FILE) or return %config;
-       while (my $line = <CACHE>) {
-               next if $line =~ /^\s*($|\#)/;
-               my ($key, $value) = ($line =~ /^(\S+)(?:\s(.*))?$/);
-               $config{$key} = $value;
-       }
-       close(CACHE);
-       return %config;
+sub module_expand($) {
+       my $module = shift;
+       $module = "m_$module" unless $module =~ /^(?:m|core)_/;
+       $module = "$module.cpp" unless $module =~ /\.cpp$/;
+       return $module;
+}
+
+sub module_shrink($) {
+       my $module = basename shift;
+       $module =~ s/(?:^m_|\.cpp$)//g;
+       return $module;
 }
 
 sub write_configure_cache(%) {
        unless (-e CONFIGURE_DIRECTORY) {
 }
 
 sub write_configure_cache(%) {
        unless (-e CONFIGURE_DIRECTORY) {
-               print_format "Creating <|GREEN ${\CONFIGURE_DIRECTORY}|> ...\n";
+               say console_format "Creating <|GREEN ${\abs2rel CONFIGURE_DIRECTORY, CONFIGURE_ROOT}|> ...";
                create_directory CONFIGURE_DIRECTORY, 0750 or print_error "unable to create ${\CONFIGURE_DIRECTORY}: $!";
        }
 
                create_directory CONFIGURE_DIRECTORY, 0750 or print_error "unable to create ${\CONFIGURE_DIRECTORY}: $!";
        }
 
-       print_format "Writing <|GREEN ${\CONFIGURE_CACHE_FILE}|> ...\n";
+       say console_format "Writing <|GREEN ${\abs2rel CONFIGURE_CACHE_FILE, CONFIGURE_ROOT}|> ...";
        my %config = @_;
        my %config = @_;
-       open(CACHE, '>', CONFIGURE_CACHE_FILE) or print_error "unable to write ${\CONFIGURE_CACHE_FILE}: $!";
-       while (my ($key, $value) = each %config) {
-               $value //= '';
-               say CACHE "$key $value";
-       }
-       close(CACHE);
+       write_config_file CONFIGURE_CACHE_FILE, %config;
 }
 
 sub get_compiler_info($) {
        my $binary = shift;
 }
 
 sub get_compiler_info($) {
        my $binary = shift;
-       my $version = `$binary -v 2>&1`;
-       if ($version =~ /Apple\sLLVM\sversion\s(\d+\.\d+)/i) {
-               # Apple version their LLVM releases slightly differently to the mainline LLVM.
-               # See https://trac.macports.org/wiki/XcodeVersionInfo for more information.
-               return (NAME => 'AppleClang', VERSION => $1);
-       } elsif ($version =~ /clang\sversion\s(\d+\.\d+)/i) {
-               return (NAME => 'Clang', VERSION => $1);
-       } elsif ($version =~ /gcc\sversion\s(\d+\.\d+)/i) {
-               return (NAME => 'GCC', VERSION => $1);
-       } elsif ($version =~ /(?:icc|icpc)\sversion\s(\d+\.\d+).\d+\s\(gcc\sversion\s(\d+\.\d+).\d+/i) {
-               return (NAME => 'ICC', VERSION => $1);
+       my %info = (NAME => 'Unknown', VERSION => '0.0');
+       return %info if system "$binary -o __compiler_info ${\CONFIGURE_ROOT}/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(.+)$/;
        }
        }
-       return (NAME => $binary, VERSION => '0.0');
+       close $fh;
+       unlink './__compiler_info';
+       return %info;
 }
 
 sub find_compiler {
        my @compilers = qw(c++ g++ clang++ icpc);
 }
 
 sub find_compiler {
        my @compilers = qw(c++ g++ clang++ icpc);
-       foreach my $compiler (shift // @compilers) {
+       for my $compiler (shift // @compilers) {
                return $compiler if __test_compiler $compiler;
                return "xcrun $compiler" if $^O eq 'darwin' && __test_compiler "xcrun $compiler";
        }
                return $compiler if __test_compiler $compiler;
                return "xcrun $compiler" if $^O eq 'darwin' && __test_compiler "xcrun $compiler";
        }
@@ -276,153 +280,77 @@ sub parse_templates($$$) {
        my %settings = __get_template_settings($config, $compiler, $version);
 
        # Iterate through files in make/template.
        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);
+       for my $template (<${\CONFIGURE_ROOT}/make/template/*>) {
+               say console_format "Parsing <|GREEN ${\abs2rel $template, CONFIGURE_ROOT}|> ...";
+               open(my $fh, $template) or print_error "unable to read $template: $!";
+               my (@lines, $mode, @platforms, @targets);
 
                # First pass: parse template variables and directives.
 
                # First pass: parse template variables and directives.
-               while (my $line = <TEMPLATE>) {
+               while (my $line = <$fh>) {
                        chomp $line;
 
                        # Does this line match a variable?
                        chomp $line;
 
                        # Does this line match a variable?
-                       while ($line =~ /(@(\w+?)@)/) {
-                               my ($variable, $name) = ($1, $2);
+                       while ($line =~ /(@(\w+?)(?:\|(\w*))?@)/) {
+                               my ($variable, $name, $default) = ($1, $2, $3);
                                if (defined $settings{$name}) {
                                        $line =~ s/\Q$variable\E/$settings{$name}/;
                                if (defined $settings{$name}) {
                                        $line =~ s/\Q$variable\E/$settings{$name}/;
+                               } elsif (defined $default) {
+                                       $line =~ s/\Q$variable\E/$default/;
                                } else {
                                } else {
-                                       print_warning "unknown template variable '$name' in $_!";
+                                       print_warning "unknown template variable '$name' in $template!";
                                        last;
                                }
                        }
 
                        # Does this line match a directive?
                                        last;
                                }
                        }
 
                        # 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;
+                       if ($line =~ /^(\s*)%(\w+)\s+(.+)$/) {
+                               if ($2 eq 'define') {
+                                       if ($settings{$3}) {
+                                               push @lines, "#$1define $3";
                                        } else {
                                        } else {
-                                               $targets{DEFAULT} = $2;
+                                               push @lines, "#$1undef $3";
                                        }
                                        }
+                               } elsif ($2 eq 'mode') {
+                                       $mode = oct $3;
+                               } elsif ($2 eq 'platform') {
+                                       push @platforms, $3;
+                               } elsif ($2 eq 'target') {
+                                       push @targets, catfile CONFIGURE_ROOT, $3;
                                } else {
                                } else {
-                                       print_warning "unknown template command '$1' in $_!";
+                                       print_warning "unknown template command '$2' in $template!";
                                        push @lines, $line;
                                }
                                next;
                        }
                        push @lines, $line;
                }
                                        push @lines, $line;
                                }
                                next;
                        }
                        push @lines, $line;
                }
-               close(TEMPLATE);
+               close $fh;
 
                # Only proceed if this file should be templated on this platform.
                if ($#platforms < 0 || grep { $_ eq $^O } @platforms) {
 
                        # Add a default target if the template has not defined one.
 
                # Only proceed if this file should be templated on this platform.
                if ($#platforms < 0 || grep { $_ eq $^O } @platforms) {
 
                        # Add a default target if the template has not defined one.
-                       unless (scalar keys %targets) {
-                               $targets{DEFAULT} = catfile(CONFIGURE_DIRECTORY, basename $_);
+                       unless (@targets) {
+                               push @targets, catfile(CONFIGURE_DIRECTORY, basename $template);
                        }
 
                        }
 
-                       # 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;
-                               }
+                       # Write the templated files to disk.
+                       for my $target (@targets) {
 
                                # Create the directory if it doesn't already exist.
                                my $directory = dirname $target;
                                unless (-e $directory) {
 
                                # Create the directory if it doesn't already exist.
                                my $directory = dirname $target;
                                unless (-e $directory) {
-                                       print_format "Creating <|GREEN $directory|> ...\n";
+                                       say console_format "Creating <|GREEN ${\abs2rel $directory, CONFIGURE_ROOT}|> ...";
                                        create_directory $directory, 0750 or print_error "unable to create $directory: $!";
                                };
 
                                # Write the template file.
                                        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 $_;
+                               say console_format "Writing <|GREEN ${\abs2rel $target, CONFIGURE_ROOT}|> ...";
+                               open(my $fh, '>', $target) or print_error "unable to write $target: $!";
+                               for (@lines) {
+                                       say $fh $_;
                                }
                                }
-                               close(TARGET);
+                               close $fh;
 
                                # Set file permissions.
                                if (defined $mode) {
 
                                # Set file permissions.
                                if (defined $mode) {