Below is the file 'configure.pl' from this revision. You can also download the file.

#!/usr/bin/perl -w

require 5.006;

use strict;
use Getopt::Long;
use File::Spec;
use File::Copy;

my $MAJOR_VERSION = 1;
my $MINOR_VERSION = 7;
my $PATCH_VERSION = 3;

my $VERSION_STRING = "$MAJOR_VERSION.$MINOR_VERSION.$PATCH_VERSION";

##################################################
# Data                                           #
##################################################
my (%CPU, %OPERATING_SYSTEM, %COMPILER, %MODULES);

my @DOCS = (
   'api.pdf', 'tutorial.pdf', 'fips140.pdf',
   'api.tex', 'tutorial.tex', 'fips140.tex',
   'credits.txt', 'info.txt', 'license.txt', 'log.txt',
   'thanks.txt', 'todo.txt', 'pgpkeys.asc');

my $TRACING = 0;

##################################################
# Run main() and Quit                            #
##################################################
my $config = {};

main();
exit;

##################################################
# Main Driver                                    #
##################################################
sub main {
    my $base_dir = where_am_i();

    $$config{'base-dir'} = $base_dir;
    $$config{'config-dir'} = File::Spec->catdir($base_dir, 'misc', 'config');
    $$config{'mods-dir'} = File::Spec->catdir($base_dir, 'modules');
    $$config{'src-dir'} = File::Spec->catdir($base_dir, 'src');
    $$config{'include-dir'} = File::Spec->catdir($base_dir, 'include');
    $$config{'checks-dir'} = File::Spec->catdir($base_dir, 'checks');
    $$config{'doc-dir'} = File::Spec->catdir($base_dir, 'doc');

    %CPU = read_info_files($config, 'arch', \&get_arch_info);
    %OPERATING_SYSTEM = read_info_files($config, 'os', \&get_os_info);
    %COMPILER = read_info_files($config, 'cc', \&get_cc_info);
    %MODULES = read_module_files($config);

    add_to($config, {
        'version_major' => $MAJOR_VERSION,
        'version_minor' => $MINOR_VERSION,
        'version_patch' => $PATCH_VERSION,
        'version'       => $VERSION_STRING,
        });

    get_options($config);

    my $default_value_is = sub {
        my ($var, $val) = @_;
        $$config{$var} = $val if not defined($$config{$var});
    };

    &$default_value_is('gcc_bug', 0);
    &$default_value_is('autoconfig', 1);
    &$default_value_is('debug', 0);
    &$default_value_is('shared', 'yes');
    &$default_value_is('local_config', '');

    if(defined($$config{'build-dir'})) {
        $$config{'botan-config'} =
            File::Spec->catfile($$config{'build-dir'}, 'botan-config');
        $$config{'makefile'} =
            File::Spec->catfile($$config{'build-dir'}, 'Makefile');
        $$config{'check_prefix'} = $$config{'build-dir'};
        $$config{'lib_prefix'} = $$config{'build-dir'};
    }
    else { # defaults
        $$config{'build-dir'} = 'build';
        $$config{'botan-config'} = 'botan-config';
        $$config{'makefile'} = 'Makefile';
        $$config{'check_prefix'} = '';
        $$config{'lib_prefix'} = '';
    }

    choose_target($config);

    my $os = $$config{'os'};
    my $cc = $$config{'compiler'};

    &$default_value_is('prefix', os_info_for($os, 'install_root'));
    &$default_value_is('libdir', os_info_for($os, 'lib_dir'));
    &$default_value_is('docdir', os_info_for($os, 'doc_dir'));
    &$default_value_is('make_style', $COMPILER{$cc}{'makefile_style'});

    autoload_modules($config) if($$config{'autoconfig'});

    add_to($config, {
        'includedir'    => os_info_for($os, 'header_dir'),

        'build_lib'     => File::Spec->catdir($$config{'build-dir'}, 'lib'),
        'build_check'   => File::Spec->catdir($$config{'build-dir'}, 'checks'),
        'build_include' =>
            File::Spec->catdir($$config{'build-dir'}, 'include'),
        'build_include_botan' =>
            File::Spec->catdir($$config{'build-dir'}, 'include', 'botan'),

        'mp_bits'       => find_mp_bits(sort keys %{$$config{'modules'}}),
        'mod_libs'      => [ using_libs($os, sort keys %{$$config{'modules'}}) ],

        'sources'       => {
            map_to($$config{'src-dir'}, dir_list($$config{'src-dir'}))
            },

        'includes'      => {
            map_to($$config{'include-dir'}, dir_list($$config{'include-dir'}))
            },

        'check_src'     => {
            map_to($$config{'checks-dir'},
                   grep { $_ ne 'keys' and !m@\.(dat|h)$@ }
                      dir_list($$config{'checks-dir'}))
            }
        });

    load_modules($config);

    my @dirs = mkdirs($$config{'build-dir'},
                      $$config{'build_include'}, $$config{'build_include_botan'},
                      $$config{'build_lib'}, $$config{'build_check'});

    #autoconfig('Created ' . join(' ', @dirs)) if @dirs;

    write_pkg_config($config);

    process_template(File::Spec->catfile($$config{'config-dir'}, 'buildh.in'),
                     File::Spec->catfile($$config{'build-dir'}, 'build.h'),
                     $config);
    $$config{'includes'}{'build.h'} = $$config{'build-dir'};

    copy_include_files($config);

    generate_makefile($config);
}

sub where_am_i {
    my ($volume,$dir,$file) = File::Spec->splitpath($0);
    my $src_dir = File::Spec->catpath($volume, $dir, '');
    return $src_dir if $src_dir;
    return File::Spec->curdir();
}

##################################################
# Diagnostics                                    #
##################################################
sub with_diagnostic {
    my ($type, @args) = @_;

    my $args = join('', @args);
    my $str = "($type): ";
    while(length($str) < 14) { $str = ' ' . $str; }

    $str .= $args . "\n";
    return $str;
}

sub croak {
    die with_diagnostic('error', @_);
}

sub warning {
    warn with_diagnostic('warning', @_);
}

sub autoconfig {
    print with_diagnostic('autoconfig', @_)
        if($$config{'verbose'});
}

sub emit_help {
    print join('', @_);
    exit;
}

sub trace {
    return unless $TRACING;

    my (undef, undef, $line) = caller(0);
    my (undef, undef, undef, $func) = caller(1);

    $func =~ s/main:://;

    warn with_diagnostic('trace', "at $func:$line - ", @_);
}

##################################################
# Display Help and Quit                          #
##################################################
sub display_help {
    sub module_sets {
        my %modsets;
        for my $name (sort keys %MODULES) {
            my %info = %{$MODULES{$name}};
            next unless (defined($info{'modset'}));

            for my $s (split(/,/, $info{'modset'})) {
                $modsets{$s} = undef;
            }
        }

        return sort keys %modsets;
    }

    my $sets = join(' ', module_sets());

    my $listing = sub {
        my (@list) = @_;

        return '' if (@list == 0);

        my ($output, $len) = ('', 0);

        my $append = sub {
            my ($to_append) = @_;
            $output .= $to_append;
            $len += length $to_append;
        };

        foreach my $name (sort @list) {
            next if $name eq 'defaults';
            if($len > 71) {
                $output .= "\n        ";
                $len = 3;
            }
            &$append($name . ' ');
        }
        chop $output;
        return $output;
    };

    my $modules = &$listing(keys %MODULES);
    my $compilers = &$listing(keys %COMPILER);
    my $oses =  &$listing(keys %OPERATING_SYSTEM);
    my $cpus = &$listing(keys %CPU);

    my $helptxt = <<ENDOFHELP;

Usage for $0 (Botan $VERSION_STRING):

  --help               display this help
  --version            display the version of Botan
  --quiet              display only warnings and errors
  --trace              enable tracing

  To change where the library is installed:

  --prefix=PATH:       set the base installation directory
  --libdir=PATH:       install library files in \${prefix}/\${libdir}
  --docdir=PATH:       install documentation in \${prefix}/\${docdir}

  To change build options:

  --build-dir=DIR:     setup the build in DIR
  --local-config=FILE: include the contents of FILE into build.h

  --debug:             set compiler flags for debugging
  --no-shared:         don't build shared libararies
  --make-style=STYLE:  override the guess as to what type of makefile to use

  To change what modules to use:

  --modules=
       [$modules]

  --module-set=[$sets]: Add a prespecified group of modules

  --module-info:       display more information about modules
  --noauto:            don't enable any modules unless specifically named

  Normally $0 will guess the right compiler, OS, and CPU.
  To override it:

  --cc=[$compilers]
  --os=[$oses generic]
  --cpu=[$cpus generic]

  --endian=[little big none]
  --unaligned-mem=[yes no]

  For more information about support CPUs, use --arch-info:

  --arch-info=[$cpus]

See doc/building.pdf for more information about this program.

ENDOFHELP

    emit_help($helptxt);
}

##################################################
# Display Further Information about Modules      #
##################################################
sub module_info {

    my $info = '';
    foreach my $mod (sort keys %MODULES) {
        my $modinfo = $MODULES{$mod};
        my $fullname = $$modinfo{'realname'};

        while(length($mod) < 10) { $mod .= ' '; }
        $info .= "$mod - $fullname\n";
    }

    return $info;
}

##################################################
#
##################################################
sub choose_target {
    my ($config) = @_;

    my $cc = $$config{'compiler'};
    my $os = $$config{'os'};
    my $cpu = $$config{'cpu'};

    $cpu = guess_cpu() if not defined($cpu);
    $cc = guess_compiler() if not defined($cc);
    $os = guess_os() if not defined($os);

    display_help()
        unless(defined($cc) and defined($os) and defined($cpu));

    croak("Compiler $cc isn't known (try --help)")
        unless defined($COMPILER{$cc});

    my %ccinfo = %{$COMPILER{$cc}};

    $os = os_alias($os);
    croak("OS $os isn't known (try --help)") unless
        ($os eq 'generic' or defined($OPERATING_SYSTEM{$os}));

    my ($arch, $submodel) = figure_out_arch($cpu);

    # hacks
    if($cc eq 'gcc') {
        $ccinfo{'binary_name'} = 'c++' if($os eq 'darwin');

        if($$config{'gcc_bug'} != 1) {
            my $binary = $ccinfo{'binary_name'};

            my $gcc_version = `$binary -v 2>&1`;

            $gcc_version = '' if not defined $gcc_version;

            my $has_ll_bug = 0;
            $has_ll_bug = 1 if($gcc_version =~ /4\.[0123]/);
            $has_ll_bug = 1 if($gcc_version =~ /3\.[34]/);
            $has_ll_bug = 1 if($gcc_version =~ /2\.25\.[0-4]/);
            $has_ll_bug = 1 if($gcc_version eq '');

            $has_ll_bug = 0 if($arch eq 'alpha' or $arch =~ /.*64$/);

            if($has_ll_bug)
            {
                warning('Enabling -fpermissive to work around ',
                        'possible GCC bug');

                $$config{'gcc_bug'} = 1;
            }

            warning('GCC 2.95.x issues many spurious warnings')
                if($gcc_version =~ /2\.95\.[0-4]/);
        }
    }

    trace("using $cc $os $arch $submodel");

    add_to($config, {
        'compiler'      => $cc,
        'os'            => $os,
        'arch'          => $arch,
        'submodel'      => $submodel,
    });
}

# Add modules that we think would work (unless autoconfig is off)
# to $$config{'modules'}
sub autoload_modules {
    my ($config) = @_;

    my $cc = $$config{'compiler'};
    my $os = $$config{'os'};
    my $arch = $$config{'arch'};
    my $submodel = $$config{'submodel'};

    my $asm_ok = $$config{'asm_ok'};

    foreach my $mod (sort keys %MODULES) {
        my %modinfo = %{ $MODULES{$mod} };

        if(defined($$config{'modules'}{$mod})) {
            autoconfig("Module $mod - loading by user request");
            next;
        }

        if($modinfo{'load_on'} eq 'request') {
            autoconfig("Module $mod - won't use, loaded by request only");
            next;
        }
        if(!$asm_ok and $modinfo{'load_on'} eq 'asm_ok') {
            autoconfig("Module $mod - won't use; avoiding due to use of --no-asm");
            next;
        }

        my @cc_list = @{ $modinfo{'cc'} };
        if(scalar @cc_list > 0 && !in_array($cc, \@cc_list)) {
            autoconfig("Module $mod - won't use, not compatbile with CC $cc");
            next;
        }

        my @os_list = @{ $modinfo{'os'} };
        if(scalar @os_list > 0 && !in_array($os, \@os_list)) {
            autoconfig("Module $mod - won't use, not compatible with OS $os");
            next;
        }

        my @arch_list = @{ $modinfo{'arch'} };
        if(scalar @arch_list > 0 &&
           !in_array($arch, \@arch_list) &&
           !in_array($submodel, \@arch_list)) {
            autoconfig("Module $mod - won't use, " .
                       "doesn't run on CPU $arch/$submodel");
            next;
        }

        autoconfig("Module $mod - autoloading");
        $$config{'modules'}{$mod} = 1;
    }
}

sub get_options {
    my ($config) = @_;

    my $save_option = sub {
        my ($opt, $val) = @_;
        $opt =~ s/-/_/g;
        $$config{$opt} = $val;
    };

    $$config{'verbose'} = 1;
    $$config{'asm_ok'} = 1;
    $$config{'modules'} = {};

    sub arch_info {
        my $arg = $_[0];

        my $arch = find_arch($arg);

        unless(defined($arch) and defined($CPU{$arch})) {
            warning("Unknown arch name '$arg' passed to --arch-info (try --help)");
            return '';
        }

        my %info = %{ $CPU{$arch} };

        my $out = "Information for $arg ($arch)\n--------\n";

        if(@{$info{'aliases'}}) {
            $out .= 'Aliases: ' . join(' ', @{$info{'aliases'}}) . "\n";
        }

        if(@{$info{'submodels'}}) {
            $out .= 'Submodels: ' . join(' ', @{$info{'submodels'}}) . "\n";
        }

        foreach my $k (keys %{$info{'submodel_aliases'}}) {
            $out .= "Alias '$k' -> '" . $info{'submodel_aliases'}{$k} . "'\n";
        }

        if(defined($info{'endian'})) {
            $out .= 'Default endian: ' . $info{'endian'} . "\n";
        }

        if(defined($info{'unaligned'})) {
            $out .= 'Unaligned memory access: ' . $info{'unaligned'} . "\n";
        }

        return $out;
    }

    sub add_modules {
        my ($config,$mods) = @_;

        foreach my $mod (split(/,/, $mods)) {
            $$config{'modules'}{$mod} = 1;
        }
    }

    sub add_module_sets {
        my ($config,$sets) = @_;

        foreach my $set (split(/,/, $sets)) {
            for my $name (sort keys %MODULES) {
                my %info = %{$MODULES{$name}};

                next unless (defined($info{'modset'}));

                for my $s (split(/,/, $info{'modset'})) {
                    if($s eq $set) {
                        $$config{'modules'}{$name} = 1;
                    }
                }
            }
        }
    }

    exit 1 unless GetOptions(
               'help' => sub { display_help(); },
               'module-info' => sub { emit_help(module_info()); },
               'version' => sub { emit_help("Botan $VERSION_STRING\n") },

               'quiet' => sub { $$config{'verbose'} = 0; },

               'cc=s' => sub { &$save_option('compiler', $_[1]) },
               'os=s' => sub { &$save_option(@_) },
               'cpu=s' => sub { &$save_option(@_) },
               'endian=s' => sub { &$save_option(@_); },
               'unaligned-mem=s' => sub { &$save_option(@_); },

               'arch-info=s' => sub { emit_help(arch_info($_[1])); },

               'prefix=s' => sub { &$save_option(@_); },
               'docdir=s' => sub { &$save_option(@_); },
               'libdir=s' => sub { &$save_option(@_); },
               'build-dir=s' => sub { $$config{'build-dir'} = $_[1]; },
               'local-config=s' =>
                  sub { &$save_option('local_config', slurp_file($_[1])); },

               'make-style=s' => sub { &$save_option(@_); },

               'module=s' => sub { add_modules($config, $_[1]); },
               'modules=s' => sub { add_modules($config, $_[1]); },
               'module-set=s' => sub { add_module_sets($config, $_[1]); },
               'module-sets=s' => sub { add_module_sets($config, $_[1]); },

               'trace' => sub { $TRACING = 1; },
               'debug' => sub { &$save_option($_[0], 1); },
               'no-shared' => sub { $$config{'shared'} = 'no'; },
               'no-asm' => sub { $$config{'asm_ok'} = 0; },

               'noauto' => sub { $$config{'autoconfig'} = 0; },
               'dumb-gcc|gcc295x' => sub { $$config{'gcc_bug'} = 1; }
               );

    # All arguments should now be consumed
    croak("Unknown option $ARGV[0] (try --help)") unless($#ARGV == -1);
}

##################################################
# Functions to search the info tables            #
##################################################
sub find_arch {
    my $name = $_[0];

    foreach my $arch (keys %CPU) {
        my %info = %{$CPU{$arch}};

        return $arch if($name eq $arch);

        foreach my $alias (@{$info{'aliases'}}) {
            return $arch if($name eq $alias);
        }

        foreach my $submodel (@{$info{'submodels'}}) {
            return $arch if($name eq $submodel);
        }

        foreach my $submodel (keys %{$info{'submodel_aliases'}}) {
            return $arch if($name eq $submodel);
        }
    }
    return undef;
};

sub figure_out_arch {
    my ($name) = @_;

    return ('generic', 'generic') if($name eq 'generic');

    my $submodel_alias = sub {
        my ($name,$info) = @_;

        my %info = %{$info};

        foreach my $submodel (@{$info{'submodels'}}) {
            return $submodel if($name eq $submodel);
        }

        return '' unless defined $info{'submodel_aliases'};
        my %sm_aliases = %{$info{'submodel_aliases'}};

        foreach my $alias (keys %sm_aliases) {
            my $official = $sm_aliases{$alias};
            return $official if($alias eq $name);
        }
        return '';
    };

    my $arch = find_arch($name);
    croak("Arch type $name isn't known (try --help)") unless defined $arch;
    trace("mapped name '$name' to arch '$arch'");

    my %archinfo = %{ $CPU{$arch} };

    my $submodel = &$submodel_alias($name, \%archinfo);

    if($submodel eq '') {
        $submodel = $archinfo{'default_submodel'};

        autoconfig("Using $submodel as default type for family ", realname($arch))
           if($submodel ne $arch);
    }

    trace("mapped name '$name' to submodel '$submodel'");

    croak("Couldn't figure out arch type of $name")
        unless defined($arch) and defined($submodel);

    return ($arch,$submodel);
}

sub os_alias {
    my $name = $_[0];

    foreach my $os (keys %OPERATING_SYSTEM) {
        foreach my $alias (@{$OPERATING_SYSTEM{$os}{'aliases'}}) {
            if($alias eq $name) {
                trace("os_alias($name) -> $os");
                return $os;
                }
        }
    }

    return $name;
}

sub os_info_for {
    my ($os,$what) = @_;

    die unless defined($os);

    croak('os_info_for called with an os of defaults (internal problem)')
        if($os eq 'defaults');

    my $result = '';

    if(defined($OPERATING_SYSTEM{$os})) {
        my %osinfo = %{$OPERATING_SYSTEM{$os}};
        $result = $osinfo{$what};
    }

    if(!defined($result) or $result eq '') {
        $result = $OPERATING_SYSTEM{'defaults'}{$what};
    }

    croak("os_info_for: No info for $what on $os") unless defined $result;

    return $result;
}

sub my_compiler {
    my ($config) = @_;
    my $cc = $$config{'compiler'};

    croak('my_compiler called, but no compiler set in config')
        unless defined $cc and $cc ne '';

    croak("unknown compiler $cc") unless defined $COMPILER{$cc};

    return %{$COMPILER{$cc}};
}

sub mach_opt {
    my ($config) = @_;

    my %ccinfo = my_compiler($config);

    # Nothing we can do in that case
    return '' unless $ccinfo{'mach_opt_flags'};

    my $submodel = $$config{'submodel'};
    my $arch = $$config{'arch'};
    if(defined($ccinfo{'mach_opt_flags'}{$submodel}))
    {
        return $ccinfo{'mach_opt_flags'}{$submodel};
    }
    elsif(defined($ccinfo{'mach_opt_flags'}{$arch})) {
        my $mach_opt_flags = $ccinfo{'mach_opt_flags'}{$arch};
        my $processed_modelname = $submodel;

        my $remove = '';
        if(defined($ccinfo{'mach_opt_re'}) and
           defined($ccinfo{'mach_opt_re'}{$arch})) {
            $remove = $ccinfo{'mach_opt_re'}{$arch};
        }

        $processed_modelname =~ s/$remove//;
        $mach_opt_flags =~ s/SUBMODEL/$processed_modelname/g;
        return $mach_opt_flags;
    }
    return '';
}

##################################################
#                                                #
##################################################
sub using_libs {
   my ($os,@using) = @_;
   my %libs;

   foreach my $mod (@using) {
      my %MOD_LIBS = %{ $MODULES{$mod}{'libs'} };
      foreach my $mod_os (keys %MOD_LIBS) {
          next if($mod_os =~ /^all!$os$/);
          next if($mod_os =~ /^all!$os,/);
          next if($mod_os =~ /^all!.*,${os}$/);
          next if($mod_os =~ /^all!.*,$os,.*/);
          next unless($mod_os eq $os or ($mod_os =~ /^all.*/));
          my @liblist = split(/,/, $MOD_LIBS{$mod_os});
          foreach my $lib (@liblist) { $libs{$lib} = 1; }
          }
      }

   return sort keys %libs;
   }

sub libs {
    my ($prefix,$suffix,@libs) = @_;
    my $output = '';
    foreach my $lib (@libs) {
        $output .= ' ' if($output ne '');
        $output .= $prefix . $lib . $suffix;
    }
    return $output;
}

##################################################
# Path and file manipulation utilities           #
##################################################
sub portable_symlink {
   my ($from, $to_dir, $to_fname) = @_;

   my $can_symlink = 0;
   my $can_link = 0;

   unless($^O eq 'MSWin32' or $^O eq 'dos' or $^O eq 'cygwin') {
       $can_symlink = eval { symlink("",""); 1 };
       $can_link = eval { link("",""); 1 };
   }

   chdir $to_dir or croak("Can't chdir to $to_dir ($!)");

   if($can_symlink) {
       symlink $from, $to_fname or
           croak("Can't symlink $from to $to_fname ($!)");
   }
   elsif($can_link) {
       link $from, $to_fname or
           croak("Can't link $from to $to_fname ($!)");
   }
   else {
       copy ($from, $to_fname) or
           croak("Can't copy $from to $to_fname ($!)");
   }

   my $go_up = File::Spec->splitdir($to_dir);
   for(my $j = 0; $j != $go_up; $j++) # return to where we were
   {
       chdir File::Spec->updir();
   }
}

sub copy_include_files {
    my ($config) = @_;

    my $include_dir = $$config{'build_include_botan'};

    trace('Copying to ', $include_dir);

    foreach my $file (dir_list($include_dir)) {
        my $path = File::Spec->catfile($include_dir, $file);
        unlink $path or croak("Could not unlink $path ($!)");
    }

   my $link_up = sub {
       my ($dir, $file) = @_;
       my $updir = File::Spec->updir();
       portable_symlink(File::Spec->catfile($updir, $updir, $updir,
                                            $dir, $file),
                        $include_dir, $file);
   };

    my $files = $$config{'includes'};

    foreach my $file (keys %$files) {
        &$link_up($$files{$file}, $file);
    }
}

sub dir_list {
    my ($dir) = @_;
    opendir(DIR, $dir) or croak("Couldn't read directory '$dir' ($!)");

    my @listing = grep { $_ ne File::Spec->curdir() and
                         $_ ne File::Spec->updir() } readdir DIR;

    closedir DIR;
    return @listing;
}

sub mkdirs {
    my (@dirs) = @_;

    my @created;
    foreach my $dir (@dirs) {
        next if( -e $dir and -d $dir ); # skip it if it's already there
        mkdir($dir, 0777) or
            croak("Could not create directory $dir ($!)");
        push @created, $dir;
    }
    return @created;
}

sub slurp_file {
    my $file = $_[0];

    return '' if(!defined($file) or $file eq '');

    croak("'$file': No such file") unless(-e $file);
    croak("'$file': Not a regular file") unless(-f $file);

    open FILE, "<$file" or croak("Couldn't read $file ($!)");

    my $output = '';
    while(<FILE>) { $output .= $_; }
    close FILE;

    return $output;
}

sub which
{
    my $file = $_[0];
    my @paths = split(/:/, $ENV{PATH});
    foreach my $path (@paths)
    {
        my $file_path = File::Spec->catfile($path, $file);
        return $file_path if(-e $file_path and -r $file_path);
    }
    return '';
}

# Return a hash mapping every var in a list to a constant value
sub map_to {
    my $var = shift;
    return map { $_ => $var } @_;
}

sub in_array {
    my($target, $array) = @_;
    return 0 unless defined($array);
    foreach (@$array) { return 1 if($_ eq $target); }
    return 0;
}

sub add_to {
    my ($to,$from) = @_;

    foreach my $key (keys %$from) {
        $$to{$key} = $$from{$key};
    }
}

##################################################
#                                                #
##################################################
sub find_mp_bits {
    my(@modules_list) = @_;
    my $mp_bits = 32; # default, good for most systems

    my $seen_mp_module = undef;

    foreach my $modname (@modules_list) {
        my %modinfo = %{ $MODULES{$modname} };
        if($modinfo{'mp_bits'}) {
            if(defined($seen_mp_module) and $modinfo{'mp_bits'} != $mp_bits) {
                croak('Inconsistent mp_bits requests from modules ',
                      $seen_mp_module, ' and ', $modname);
            }

            $seen_mp_module = $modname;
            $mp_bits = $modinfo{'mp_bits'};
        }
    }
    return $mp_bits;
}

##################################################
#                                                #
##################################################
sub realname {
    my $arg = $_[0];

    return $COMPILER{$arg}{'realname'}
       if defined $COMPILER{$arg};

    return $OPERATING_SYSTEM{$arg}{'realname'}
       if defined $OPERATING_SYSTEM{$arg};

    return $CPU{$arg}{'realname'}
       if defined $CPU{$arg};

    return $arg;
}

##################################################
#                                                #
##################################################
sub load_modules {
    my ($config) = @_;

    foreach my $mod (sort keys %{$$config{'modules'}}) {
        load_module($config, $mod);
    }

    my $gen_defines = sub {
        my $defines = '';

        my $arch = $$config{'arch'};

        if($arch ne 'generic') {
            my %cpu_info = %{$CPU{$arch}};
            my $endian = $cpu_info{'endian'};

            if(defined($$config{'endian'})) {
                $endian = $$config{'endian'};
                $endian = undef unless($endian eq 'little' || $endian eq 'big');
            }
            elsif(defined($endian)) {
                autoconfig("Since arch is $arch, assuming $endian endian mode");
            }

            $defines .= "#define BOTAN_TARGET_ARCH_IS_" . (uc $arch) . "\n";

            my $submodel = $$config{'submodel'};
            if($arch ne $submodel) {
                $submodel = uc $submodel;
                $submodel =~ s/-/_/g;
                $defines .= "#define BOTAN_TARGET_CPU_IS_$submodel\n";
            }

            my $unaligned_ok = 0;

            if(defined($endian)) {
                $endian = uc $endian;
                $defines .= "#define BOTAN_TARGET_CPU_IS_${endian}_ENDIAN\n";

                if(defined($$config{'unaligned_mem'})) {
                    my $spec = $$config{'unaligned_mem'};

                    if($spec eq 'yes') {
                        $unaligned_ok = 1;
                    }
                    elsif($spec eq 'no') {
                        $unaligned_ok = 0;
                    }
                    else {
                        warning("Unknown arg to --unaligned-mem '$spec', will ignore");
                        $unaligned_ok = 0;
                    }
                }
                elsif(defined($cpu_info{'unaligned'}) and
                      $cpu_info{'unaligned'} eq 'ok')
                {
                    autoconfig("Since arch is $arch, " .
                               "assuming unaligned memory access is OK");
                    $unaligned_ok = 1;
                }
            }

            $defines .=
                "#define BOTAN_TARGET_UNALIGNED_LOADSTOR_OK $unaligned_ok\n