From 8f8a595abcede0e3a30cc8219510c87b773de470 Mon Sep 17 00:00:00 2001 From: lloyd Date: Mon, 31 Aug 2009 18:40:38 +0000 Subject: Move configure.pl to doc/scripts --- configure.pl | 2337 ---------------------------------------------- doc/scripts/configure.pl | 2337 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 2337 insertions(+), 2337 deletions(-) delete mode 100755 configure.pl create mode 100755 doc/scripts/configure.pl diff --git a/configure.pl b/configure.pl deleted file mode 100755 index 4859ede74..000000000 --- a/configure.pl +++ /dev/null @@ -1,2337 +0,0 @@ -#!/usr/bin/perl -w - -require 5.006; - -use strict; - -use Config; -use Getopt::Long; -use File::Spec; -use File::Copy; -use File::Find; -use Sys::Hostname; - -my $MAJOR_VERSION = 1; -my $MINOR_VERSION = 9; -my $PATCH_VERSION = 0; - -my $VERSION_SUFFIX = '-pre'; - -my $SO_PATCH_VERSION = 0; - -my $VERSION_STRING = "$MAJOR_VERSION.$MINOR_VERSION.$PATCH_VERSION$VERSION_SUFFIX"; -my $SO_VERSION_STRING = "$MAJOR_VERSION.$MINOR_VERSION.$SO_PATCH_VERSION$VERSION_SUFFIX"; - -################################################## -# Data # -################################################## -my (%CPU, %OPERATING_SYSTEM, %COMPILER, %MODULES); - -my @DOCS = ( - 'api.pdf', 'tutorial.pdf', 'fips140.pdf', - 'api.tex', 'tutorial.tex', 'fips140.tex', - 'credits.txt', 'license.txt', 'log.txt', - 'thanks.txt', 'todo.txt', 'pgpkeys.asc'); - -my $TRACING = 0; - -################################################## -# Run main() and Quit # -################################################## -my $config = {}; - -main(); -exit; - -sub exec_uname { - # Only exec it if we think it might actually work - if(-f '/bin/uname' || -f '/usr/bin/uname' || -f '/bin/sh') { - my $uname = `uname -a`; - if($uname) { - chomp $uname; - return $uname; - } - } - - return ''; -} - -sub deprecation_warning { - warning("$0 is deprecated; migration to ./configure.py strongly recommended"); -} - -################################################## -# Main Driver # -################################################## -sub main { - my $base_dir = where_am_i(); - - deprecation_warning(); - - $$config{'uname'} = exec_uname(); - - $$config{'base-dir'} = $base_dir; - $$config{'src-dir'} = File::Spec->catdir($base_dir, 'src'); - $$config{'checks-dir'} = File::Spec->catdir($base_dir, 'checks'); - $$config{'doc_src_dir'} = File::Spec->catdir($base_dir, 'doc'); - - $$config{'config-dir'} = - File::Spec->catdir($$config{'src-dir'}, 'build-data'); - - $$config{'command_line'} = $0 . ' ' . join(' ', @ARGV); - $$config{'timestamp'} = gmtime; - $$config{'user'} = getlogin || getpwuid($<) || ''; - $$config{'hostname'} = hostname; - - %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, - 'so_version' => $SO_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', ''); - - # Goes into build-specific dirs (maybe) - - $$config{'build_dir'} = 'build'; - $$config{'botan_config'} = File::Spec->catfile( - $$config{'build_dir'}, 'botan-config'); - - $$config{'botan_pkgconfig'} = File::Spec->catfile( - $$config{'build_dir'}, - 'botan-' . $MAJOR_VERSION . '.' . $MINOR_VERSION . '.pc'); - - $$config{'makefile'} = 'Makefile'; - $$config{'check_prefix'} = ''; - $$config{'lib_prefix'} = ''; - - if(defined($$config{'with_build_dir'})) { - for my $var ('build_dir', - 'botan_config', - 'botan_pkgconfig', - 'makefile', - 'check_prefix', - 'lib_prefix') - { - $$config{$var} = File::Spec->catfile($$config{'with_build_dir'}, - $$config{$var}); - } - } - else { - } - - 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'}); - - scan_modules($config); - - print_enabled_modules($config); - - 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($config), - 'mod_libs' => [ using_libs($config) ], - - 'sources' => { }, - 'includes' => { }, - - '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); - - determine_config($config); - - process_template(File::Spec->catfile($$config{'config-dir'}, 'buildh.in'), - File::Spec->catfile($$config{'build_dir'}, 'build.h'), - $config); - - process_template(File::Spec->catfile( - $$config{'config-dir'}, 'botan.doxy.in'), - File::Spec->catfile($$config{'doc_src_dir'}, 'botan.doxy'), - $config); - - $$config{'includes'}{'build.h'} = $$config{'build_dir'}; - - generate_makefile($config); - - copy_include_files($config); - - deprecation_warning(); -} - -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', @_); -} - -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:://; - - print 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 > 58) { - $output .= "\n "; - $len = 8; - } - &$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 = <&1`; - - $gcc_version = '' if not defined $gcc_version; - - my $has_ll_bug = 0; - $has_ll_bug = 1 if($gcc_version =~ /4\.[01234]/); - $has_ll_bug = 1 if($gcc_version =~ /3\.[34]/); - $has_ll_bug = 1 if($gcc_version =~ /2\.95\.[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, - }); -} - -sub module_runs_on { - my ($config, $modinfo, $mod, $noisy) = @_; - - my $cc = $$config{'compiler'}; - my $os = $$config{'os'}; - my $submodel = $$config{'submodel'}; - my $arch = $$config{'arch'}; - - my %modinfo = %{$modinfo}; - - my $realname = $modinfo{'realname'}; - - my @arch_list = @{ $modinfo{'arch'} }; - if(scalar @arch_list > 0 && !in_array($arch, \@arch_list) && - !in_array($submodel, \@arch_list)) - { - autoconfig("$mod ($realname): skipping, " . - "not compatible with " . realname($arch) . - "/" . $submodel) if $noisy; - return 0; - } - - my @os_list = @{ $modinfo{'os'} }; - if(scalar @os_list > 0 && !in_array($os, \@os_list)) - { - autoconfig("$mod ($realname): " . - "skipping, not compatible with " . realname($os)) if $noisy; - return 0; - } - - my @cc_list = @{ $modinfo{'cc'} }; - if(scalar @cc_list > 0 && !in_array($cc, \@cc_list)) { - autoconfig("$mod ($realname): " . - "skipping, not compatible with " . realname($cc)) if $noisy; - return 0; - } - - - if($modinfo{'uses_tr1'} eq 'yes') { - return 0 unless defined($$config{'tr1'}); - - my $tr1 = $$config{'tr1'}; - return 0 unless($tr1 eq 'system' or $tr1 eq 'boost'); - } - - return 1; -} - -sub scan_modules { - my ($config) = @_; - - foreach my $mod (sort keys %MODULES) { - my %modinfo = %{ $MODULES{$mod} }; - - next if(defined($$config{'modules'}{$mod}) && $$config{'modules'}{$mod} < 0); - - next unless(module_runs_on($config, \%modinfo, $mod, 0)); - - if($modinfo{'load_on'} eq 'auto' or - ($modinfo{'load_on'} eq 'asm_ok' and $$config{'asm_ok'})) { - - my %maybe_load = (); - my $all_deps_found = 1; - - LINE: foreach (@{$modinfo{'requires'}}) { - for my $req_mod (split(/\|/, $_)) { - next unless defined $MODULES{$req_mod}; - - next if(defined($$config{'modules'}{$req_mod}) && $$config{'modules'}{$req_mod} < 0); - next unless(module_runs_on($config, $MODULES{$req_mod}, $req_mod, 0)); - - $maybe_load{$req_mod} = 1; - next LINE; - } - $all_deps_found = 0; - } - - if($all_deps_found) { - foreach my $depmod (keys %maybe_load) - { $$config{'modules'}{$depmod} = 1; } - $$config{'modules'}{$mod} = 1; - } - } - } -} - -sub print_enabled_modules { - my ($config) = @_; - - return unless($$config{'verbose'}); - - my %by_type; - - foreach my $mod (sort keys %MODULES) { - my $type = $MODULES{$mod}{'type'}; - - my $n = 0; - $n = 1 if($$config{'modules'}{$mod} && $$config{'modules'}{$mod} > 0); - - $by_type{$type}{$mod} = $n; - } - - for my $type (sort keys %by_type) { - my %mods = %{$by_type{$type}}; - - my @load_lines; - - if(keys %mods == 1) { - my $on = $mods{$type}; - - if($on > 0) { - print with_diagnostic('loading', $type); - } - else { - print with_diagnostic('loading', '[', $type , ']'); - } - } - else { - my $s = $type . ': '; - - for my $mod (sort keys %mods) { - my $on = $mods{$mod}; - - if($s eq '') { - $s = ' ' x (length($type) + 16); - } - - if($on > 0) { - $s .= $mod . ' '; - } - else { - $s .= '[' . $mod . '] '; - } - - if(length($s) > 60) { - push @load_lines, $s; - $s = ''; - } - } - - #print "Last1 '$s'\n"; - - $s =~ s/\s*$//m; # strip trailing whitespace - - push @load_lines, $s if($s ne ''); - - - print with_diagnostic('loading', join("\n", @load_lines)); - } - } -} - -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{'tr1'} = undef; # not enabled by default - $$config{'modules'} = {}; - - sub arch_info { - my $arg = $_[0]; - - my $arch = find_arch($arg); - - unless(defined($arch) and defined($CPU{$arch})) { - warning("Unknown arch '$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)) { - # -1 means disabled by user, do not load - $$config{'modules'}{$mod} = 1 unless( - defined($$config{'modules'}{$mod}) && - $$config{'modules'}{$mod} == -1); - } - } - - sub disable_modules { - my ($config,$mods) = @_; - - foreach my $mod (split(/,/, $mods)) { - # -1 means disabled by user, do not load - $$config{'modules'}{$mod} = -1; - } - } - - sub add_module_sets { - my ($config,$sets) = @_; - - foreach my $set (split(/,/, $sets)) { - for my $mod (sort keys %MODULES) { - my %info = %{$MODULES{$mod}}; - - next unless (defined($info{'modset'})); - - for my $s (split(/,/, $info{'modset'})) { - if($s eq $set) { - $$config{'modules'}{$mod} = 1 - unless($$config{'modules'}{$mod} == -1); - } - } - } - } - } - - exit 1 unless GetOptions( - 'prefix=s' => sub { &$save_option(@_); }, - 'exec-prefix=s' => sub { &$save_option(@_); }, - - 'bindir=s' => sub { &$save_option(@_); }, - 'datadir' => sub { &$save_option(@_); }, - 'datarootdir' => sub { &$save_option(@_); }, - 'docdir=s' => sub { &$save_option(@_); }, - 'dvidir' => sub { &$save_option(@_); }, - 'htmldir' => sub { &$save_option(@_); }, - 'includedir' => sub { &$save_option(@_); }, - 'infodir' => sub { &$save_option(@_); }, - 'libdir=s' => sub { &$save_option(@_); }, - 'libexecdir' => sub { &$save_option(@_); }, - 'localedir' => sub { &$save_option(@_); }, - 'localstatedir' => sub { &$save_option(@_); }, - 'mandir' => sub { &$save_option(@_); }, - 'oldincludedir' => sub { &$save_option(@_); }, - 'pdfdir' => sub { &$save_option(@_); }, - 'psdir' => sub { &$save_option(@_); }, - 'sbindir=s' => sub { &$save_option(@_); }, - 'sharedstatedir' => sub { &$save_option(@_); }, - 'sysconfdir' => sub { &$save_option(@_); }, - - 'cc=s' => sub { &$save_option('compiler', $_[1]) }, - 'os=s' => sub { &$save_option(@_) }, - 'cpu=s' => sub { &$save_option(@_) }, - - 'help' => sub { display_help(); }, - 'module-info' => sub { emit_help(module_info()); }, - 'version' => sub { emit_help("$VERSION_STRING\n") }, - 'so-version' => sub { emit_help("$SO_VERSION_STRING\n") }, - - 'with-tr1-implementation=s' => sub { $$config{'tr1'} = $_[1]; }, - - 'quiet' => sub { $$config{'verbose'} = 0; }, - 'trace' => sub { $TRACING = 1; }, - - 'enable-asm' => sub { $$config{'asm_ok'} = 1; }, - 'disable-asm' => sub { $$config{'asm_ok'} = 0; }, - - 'enable-autoconfig' => sub { $$config{'autoconfig'} = 1; }, - 'disable-autoconfig' => sub { $$config{'autoconfig'} = 0; }, - - 'enable-shared' => sub { $$config{'shared'} = 'yes'; }, - 'disable-shared' => sub { $$config{'shared'} = 'no'; }, - - 'enable-debug' => sub { &$save_option('debug', 1); }, - 'disable-debug' => sub { &$save_option('debug', 0); }, - - 'enable-modules:s' => sub { add_modules($config, $_[1]); }, - 'disable-modules:s' => sub { disable_modules($config, $_[1]); }, - - 'with-openssl' => sub { add_modules($config, 'openssl'); }, - 'without-openssl' => sub { disable_modules($config, 'openssl'); }, - 'with-gnump' => sub { add_modules($config, 'gnump'); }, - 'without-gnump' => sub { disable_modules($config, 'gnump'); }, - 'with-bzip2' => sub { add_modules($config, 'bzip2'); }, - 'without-bzip2' => sub { disable_modules($config, 'bzip2'); }, - 'with-zlib' => sub { add_modules($config, 'zlib'); }, - 'without-zlib' => sub { disable_modules($config, 'zlib'); }, - - 'use-module-set=s' => sub { add_module_sets($config, $_[1]); }, - - 'with-build-dir=s' => sub { &$save_option(@_); }, - 'with-endian=s' => sub { &$save_option(@_); }, - 'with-unaligned-mem=s' => sub { &$save_option(@_); }, - 'with-local-config=s' => - sub { &$save_option('local_config', slurp_file($_[1])); }, - - 'modules=s' => sub { add_modules($config, $_[1]); }, - 'show-arch-info=s' => sub { emit_help(arch_info($_[1])); }, - 'make-style=s' => sub { &$save_option(@_); }, - '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 ($config) = @_; - - my $os = $$config{'os'}; - my %libs; - - foreach my $mod (sort keys %{$$config{'modules'}}) { - next if ${$$config{'modules'}}{$mod} < 0; - - 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) = @_; - - #trace("portable_symlink($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 { !/#/ and -f File::Spec->catfile($dir, $_) and - $_ 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() { $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 (sort keys %{$$config{'modules'}}) { - croak("Unknown module $modname") unless defined $MODULES{$modname}; - - next if $$config{'modules'}{$modname} < 0; - - 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_module { - my ($config, $modname) = @_; - - #trace("load_module($modname)"); - - croak("Unknown module $modname") unless defined($MODULES{$modname}); - - my %module = %{$MODULES{$modname}}; - - my $works_on = sub { - my ($what, $lst_ref) = @_; - my @lst = @{$lst_ref}; - return 1 if not @lst; # empty list -> no restrictions - return 1 if $what eq 'generic'; # trust the user - return in_array($what, \@lst); - }; - - # Check to see if everything is OK WRT system requirements - my $os = $$config{'os'}; - - croak("Module '$modname' does not run on $os") - unless(&$works_on($os, $module{'os'})); - - my $arch = $$config{'arch'}; - my $sub = $$config{'submodel'}; - - croak("Module '$modname' does not run on $arch/$sub") - unless(&$works_on($arch, $module{'arch'}) or - &$works_on($sub, $module{'arch'})); - - my $cc = $$config{'compiler'}; - - croak("Module '$modname' does not work with $cc") - unless(&$works_on($cc, $module{'cc'})); - - my $handle_files = sub { - my($lst, $func) = @_; - return unless defined($lst); - - foreach (sort @$lst) { - &$func($module{'moddirs'}, $config, $_); - } - }; - - &$handle_files($module{'ignore'}, \&ignore_file); - &$handle_files($module{'add'}, \&add_file); - &$handle_files($module{'replace'}, - sub { ignore_file(@_); add_file(@_); }); - - warning($modname, ': ', $module{'note'}) - if(defined($module{'note'})); -} - -sub load_modules { - my ($config) = @_; - - my @mod_names; - - foreach my $mod (sort keys %{$$config{'modules'}}) { - next unless($$config{'modules'}{$mod} > 0); - - load_module($config, $mod); - - push @mod_names, $mod; - } - - $$config{'mod_list'} = join("\n", @mod_names); - - my $unaligned_ok = 0; - - my $target_os_defines = sub { - my @macro_list; - - my $os = $$config{'os'}; - if($os ne 'generic') { - push @macro_list, '#define BOTAN_TARGET_OS_IS_' . uc $os; - - my @features = @{$OPERATING_SYSTEM{$os}{'target_features'}}; - - for my $feature (@features) { - push @macro_list, '#define BOTAN_TARGET_OS_HAS_' . uc $feature; - } - - } - return join("\n", @macro_list); - }; - - $$config{'target_os_defines'} = &$target_os_defines(); - - my $target_cpu_defines = sub { - my @macro_list; - - my $arch = $$config{'arch'}; - if($arch ne 'generic') { - my %cpu_info = %{$CPU{$arch}}; - my $endian = $cpu_info{'endian'}; - - if(defined($$config{'with_endian'})) { - $endian = $$config{'with_endian'}; - $endian = undef unless($endian eq 'little' || - $endian eq 'big'); - } - elsif(defined($endian)) { - autoconfig("Since arch is $arch, assuming $endian endian mode"); - } - - push @macro_list, "#define BOTAN_TARGET_ARCH_IS_" . (uc $arch); - - my $submodel = $$config{'submodel'}; - if($arch ne $submodel) { - $submodel = uc $submodel; - $submodel =~ tr/-/_/; - $submodel =~ tr/.//; - - push @macro_list, "#define BOTAN_TARGET_CPU_IS_$submodel"; - } - - if(defined($endian)) { - $endian = uc $endian; - push @macro_list, - "#define BOTAN_TARGET_CPU_IS_${endian}_ENDIAN"; - - # See if the user set --with-unaligned-mem - if(defined($$config{'with_unaligned_mem'})) { - my $spec = $$config{'with_unaligned_mem'}; - - if($spec eq 'yes') { - $unaligned_ok = 1; - } - elsif($spec eq 'no') { - $unaligned_ok = 0; - } - else { - warning('Unknown arg to --with-unaligned-mem (' . - $spec . ') will ignore'); - $unaligned_ok = 0; - } - } - # Otherwise, see if the CPU has a default setting - 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; - } - } - } - - # variable is always set (one or zero) - push @macro_list, - "#define BOTAN_TARGET_UNALIGNED_LOADSTOR_OK $unaligned_ok"; - return join("\n", @macro_list); - }; - - $$config{'target_cpu_defines'} = &$target_cpu_defines(); - - my $target_compiler_defines = sub { - my @macro_list; - - if(defined($$config{'tr1'})) { - my $tr1 = $$config{'tr1'}; - - if($tr1 eq 'system') { - push @macro_list, '#define BOTAN_USE_STD_TR1'; - } - elsif($tr1 eq 'boost') { - push @macro_list, '#define BOTAN_USE_BOOST_TR1'; - } - elsif($tr1 ne 'none') { - croak("Unknown --with-tr1= option value '$tr1' (try --help)"); - } - } - - return join("\n", @macro_list); - }; - - $$config{'target_compiler_defines'} = &$target_compiler_defines(); - - my $gen_defines = sub { - my @macro_list; - - my %defines; - - foreach my $mod (sort keys %{$$config{'modules'}}) { - next unless $$config{'modules'}{$mod} > 0; - - my $defs = $MODULES{$mod}{'define'}; - next unless $defs; - - push @{$defines{$MODULES{$mod}{'type'}}}, split(/,/, $defs); - } - - foreach my $type (sort keys %defines) { - push @macro_list, "\n/* $type */"; - - for my $macro (@{$defines{$type}}) { - die unless(defined $macro and $macro ne ''); - push @macro_list, "#define BOTAN_HAS_$macro"; - } - } - - return join("\n", @macro_list); - }; - - $$config{'module_defines'} = &$gen_defines(); -} - -################################################## -# # -################################################## -sub file_type { - my ($file) = @_; - - return 'sources' - if($file =~ /\.cpp$/ or $file =~ /\.c$/ or $file =~ /\.S$/); - return 'includes' if($file =~ /\.h$/); - - croak('file_type() - don\'t know what sort of file ', $file, ' is'); -} - -sub add_file { - my ($mod_dir, $config, $file) = @_; - - check_for_file($config, $file, $mod_dir, $mod_dir); - - my $do_add_file = sub { - my ($type) = @_; - - croak("File $file already added from ", $$config{$type}{$file}) - if(defined($$config{$type}{$file})); - - if($file =~ /(.*):(.*)/) { - my @dirs = File::Spec->splitdir($mod_dir); - - $dirs[$#dirs-1] = $1; - - $$config{$type}{$2} = File::Spec->catdir(@dirs); - } - else { - $$config{$type}{$file} = $mod_dir; - } - }; - - &$do_add_file(file_type($file)); -} - -sub ignore_file { - my ($mod_dir, $config, $file) = @_; - check_for_file($config, $file, undef, $mod_dir); - - my $do_ignore_file = sub { - my ($type, $ok_if_from) = @_; - - if(defined ($$config{$type}{$file})) { - - croak("$mod_dir - File $file modified from ", - $$config{$type}{$file}) - if($$config{$type}{$file} ne $ok_if_from); - - delete $$config{$type}{$file}; - } - }; - - &$do_ignore_file(file_type($file)); -} - -sub check_for_file { - my ($config, $file, $added_from, $mod_dir) = @_; - - #trace("check_for_file($file, $added_from, $mod_dir)"); - - my $full_path = sub { - my ($file,$mod_dir) = @_; - - if($file =~ /(.*):(.*)/) { - return File::Spec->catfile($mod_dir, '..', $1, $2); - } else { - return File::Spec->catfile($mod_dir, $file) if(defined($mod_dir)); - - my @typeinfo = file_type($config, $file); - return File::Spec->catfile($typeinfo[1], $file); - } - }; - - $file = &$full_path($file, $added_from); - - croak("Module $mod_dir requires that file $file exist. This error\n ", - 'should never occur; please contact the maintainers with details.') - unless(-e $file); -} - -################################################## -# # -################################################## -sub process_template { - my ($in, $out, $config) = @_; - - trace("process_template: $in -> $out"); - - my $contents = slurp_file($in); - - foreach my $name (keys %$config) { - my $val = $$config{$name}; - - unless(defined $val) { - trace("Undefined variable $name in $in"); - next; - } - - $contents =~ s/\%\{$name\}/$val/g; - } - - if($contents =~ /\%\{([a-z_]*)\}/) { - - sub summarize { - my ($n, $s) = @_; - - $s =~ s/\n/\\n/; # escape newlines - - return $s if(length($s) <= $n); - - return substr($s, 0, 57) . '...'; - } - - foreach my $key (sort keys %$config) { - print with_diagnostic("debug", - "In %config:", $key, " -> ", - summarize(60, $$config{$key})); - } - - croak("Unbound variable '$1' in $in"); - } - - open OUT, ">$out" or croak("Couldn't write $out ($!)"); - print OUT $contents; - close OUT; -} - -################################################## -# # -################################################## -sub read_list { - my ($line, $reader, $marker, $func) = @_; - - if($line =~ m@^<$marker>$@) { - while(1) { - $line = &$reader(); - - die "EOF while searching for $marker" unless $line; - last if($line =~ m@^$@); - &$func($line); - } - } -} - -sub list_push { - my ($listref) = @_; - return sub { push @$listref, $_[0]; } -} - -sub match_any_of { - my ($line, $hash, $quoted, @any_of) = @_; - - $quoted = ($quoted eq 'quoted') ? 1 : 0; - - foreach my $what (@any_of) { - $$hash{$what} = $1 if(not $quoted and $line =~ /^$what (.*)/); - $$hash{$what} = $1 if($quoted and $line =~ /^$what \"(.*)\"/); - } -} - -################################################## -# # -################################################## -sub make_reader { - my $filename = $_[0]; - - croak("make_reader(): Arg was undef") if not defined $filename; - - open FILE, "<$filename" or - croak("Couldn't read $filename ($!)"); - - return sub { - my $line = ''; - while(1) { - my $line = ; - last unless defined($line); - - chomp($line); - $line =~ s/#.*//; - $line =~ s/^\s*//; - $line =~ s/\s*$//; - $line =~ s/\s\s*/ /; - $line =~ s/\t/ /; - return $line if $line ne ''; - } - close FILE; - return undef; - } -} - -################################################## -# # -################################################## -sub read_info_files { - my ($config, $dir, $func) = @_; - - $dir = File::Spec->catdir($$config{'config-dir'}, $dir); - - my %allinfo; - foreach my $file (dir_list($dir)) { - my $fullpath = File::Spec->catfile($dir, $file); - - trace("reading $fullpath"); - %{$allinfo{$file}} = &$func($file, $fullpath); - } - - return %allinfo; -} - -sub read_module_files { - my ($config) = @_; - - my %allinfo; - - my @modinfos; - - File::Find::find( - { wanted => sub - { if(-f $_ && /^info\.txt\z/s) { - my $name = $File::Find::name; - push @modinfos, $name; - } - } - }, - $$config{'src-dir'}); - - foreach my $modfile (@modinfos) { - trace("reading $modfile"); - - my ($volume,$dirs,$file) = File::Spec->splitpath($modfile); - - my @dirs = File::Spec->splitdir($dirs); - my $moddir = $dirs[$#dirs-1]; - - trace("module $moddir in $dirs $modfile"); - - %{$allinfo{$moddir}} = get_module_info($dirs, $moddir, $modfile); - } - - return %allinfo; -} - -################################################## -# # -################################################## - -sub get_module_info { - my ($dirs, $name, $modfile) = @_; - my $reader = make_reader($modfile); - - my %info; - - $info{'name'} = $name; - $info{'modinfo'} = $modfile; - $info{'moddirs'} = $dirs; - - # Default module settings - $info{'load_on'} = 'request'; # default unless specified - $info{'uses_tr1'} = 'no'; - $info{'libs'} = {}; - $info{'use'} = 'no'; - - my @dir_arr = File::Spec->splitdir($dirs); - $info{'type'} = $dir_arr[$#dir_arr-2]; # cipher, hash, ... - if($info{'type'} eq 'src') { $info{'type'} = $dir_arr[$#dir_arr-1]; } - - while($_ = &$reader()) { - match_any_of($_, \%info, 'quoted', 'realname', 'note', 'type'); - match_any_of($_, \%info, 'unquoted', 'define', 'mp_bits', - 'modset', 'load_on', 'uses_tr1'); - - read_list($_, $reader, 'arch', list_push(\@{$info{'arch'}})); - read_list($_, $reader, 'cc', list_push(\@{$info{'cc'}})); - read_list($_, $reader, 'os', list_push(\@{$info{'os'}})); - read_list($_, $reader, 'add', list_push(\@{$info{'add'}})); - read_list($_, $reader, 'replace', list_push(\@{$info{'replace'}})); - read_list($_, $reader, 'ignore', list_push(\@{$info{'ignore'}})); - read_list($_, $reader, 'requires', list_push(\@{$info{'requires'}})); - - read_list($_, $reader, 'libs', - sub { - my $line = $_[0]; - $line =~ m/^([\w!,]*) -> ([\w.,-]*)$/; - $info{'libs'}{$1} = $2; - }); - - if(/^require_version /) { - if(/^require_version (\d+)\.(\d+)\.(\d+)$/) { - my $version = "$1.$2.$3"; - my $needed_version = 100*$1 + 10*$2 + $3; - - my $have_version = - 100*$MAJOR_VERSION + 10*$MINOR_VERSION + $PATCH_VERSION; - - if($needed_version > $have_version) { - warning("Module $name needs v$version; disabling"); - return (); - } - } - else { - croak("In module $name, bad version requirement '$_'"); - } - } - } - - return %info; -} - -################################################## -# # -################################################## -sub get_arch_info { - my ($name,$file) = @_; - my $reader = make_reader($file); - - my %info; - $info{'name'} = $name; - - while($_ = &$reader()) { - match_any_of($_, \%info, 'quoted', 'realname'); - match_any_of($_, \%info, 'unquoted', - 'default_submodel', 'endian', 'unaligned'); - - read_list($_, $reader, 'aliases', list_push(\@{$info{'aliases'}})); - read_list($_, $reader, 'submodels', list_push(\@{$info{'submodels'}})); - - read_list($_, $reader, 'submodel_aliases', - sub { - my $line = $_[0]; - $line =~ m/^(\S*) -> (\S*)$/; - $info{'submodel_aliases'}{$1} = $2; - }); - } - return %info; -} - -################################################## -# # -################################################## -sub get_os_info { - my ($name,$file) = @_; - my $reader = make_reader($file); - - my %info; - $info{'name'} = $name; - - while($_ = &$reader()) { - match_any_of($_, \%info, - 'quoted', 'realname', 'ar_command', - 'install_cmd_data', 'install_cmd_exec'); - - match_any_of($_, \%info, 'unquoted', - 'os_type', - 'obj_suffix', - 'so_suffix', - 'static_suffix', - 'install_root', - 'header_dir', - 'lib_dir', 'doc_dir', - 'ar_needs_ranlib'); - - read_list($_, $reader, 'aliases', list_push(\@{$info{'aliases'}})); - - read_list($_, $reader, 'target_features', - list_push(\@{$info{'target_features'}})); - - read_list($_, $reader, 'supports_shared', - list_push(\@{$info{'supports_shared'}})); - } - return %info; -} - -################################################## -# Read a file from misc/config/cc and set the values from -# there into a hash for later reference -################################################## -sub get_cc_info { - my ($name,$file) = @_; - my $reader = make_reader($file); - - my %info; - $info{'name'} = $name; - - while($_ = &$reader()) { - match_any_of($_, \%info, 'quoted', - 'realname', - 'binary_name', - 'compile_option', - 'output_to_option', - 'add_include_dir_option', - 'add_lib_dir_option', - 'add_lib_option', - 'lib_opt_flags', - 'check_opt_flags', - 'dll_import_flags', - 'dll_export_flags', - 'lang_flags', - 'warning_flags', - 'shared_flags', - 'ar_command', - 'debug_flags', - 'no_debug_flags'); - - match_any_of($_, \%info, 'unquoted', - 'makefile_style', - 'compiler_has_tr1'); - - sub quoted_mapping { - my $hashref = $_[0]; - return sub { - my $line = $_[0]; - $line =~ m/^(\S*) -> \"(.*)\"$/; - $$hashref{$1} = $2; - } - } - - read_list($_, $reader, 'mach_abi_linking', - quoted_mapping(\%{$info{'mach_abi_linking'}})); - read_list($_, $reader, 'so_link_flags', - quoted_mapping(\%{$info{'so_link_flags'}})); - - read_list($_, $reader, 'mach_opt', - sub { - my $line = $_[0]; - $line =~ m/^(\S*) -> \"(.*)\" ?(.*)?$/; - $info{'mach_opt_flags'}{$1} = $2; - $info{'mach_opt_re'}{$1} = $3; - }); - - } - return %info; -} - -################################################## -# # -################################################## -sub write_pkg_config { - my ($config) = @_; - - return if($$config{'os'} eq 'generic' or - $$config{'os'} eq 'windows'); - - $$config{'link_to'} = libs('-l', '', 'm', @{$$config{'mod_libs'}}); - - my $botan_config = $$config{'botan_config'}; - - process_template( - File::Spec->catfile($$config{'config-dir'}, 'botan-config.in'), - $botan_config, $config); - chmod 0755, $botan_config; - - process_template( - File::Spec->catfile($$config{'config-dir'}, 'botan.pc.in'), - $$config{'botan_pkgconfig'}, $config); - - delete $$config{'link_to'}; -} - -################################################## -# # -################################################## -sub file_list { - my ($put_in, $from, $to, %files) = @_; - - my $list = ''; - - my $spaces = 16; - - foreach (sort keys %files) { - my $file = $_; - - $file =~ s/$from/$to/ if(defined($from) and defined($to)); - - my $dir = $files{$_}; - $dir = $put_in if defined $put_in; - - if(defined($dir)) { - $list .= File::Spec->catfile ($dir, $file); - } - else { - $list .= $file; - } - - $list .= " \\\n "; - } - - $list =~ s/\\\n +$//; # remove trailing escape - - return $list; -} - -sub build_cmds { - my ($config, $dir, $flags, $files) = @_; - - my $obj_suffix = $$config{'obj_suffix'}; - - my %ccinfo = my_compiler($config); - - my $inc = $ccinfo{'add_include_dir_option'}; - my $from = $ccinfo{'compile_option'}; - my $to = $ccinfo{'output_to_option'}; - - my $inc_dir = $$config{'build_include'}; - - # Probably replace by defaults to -I -c -o - croak('undef value found in build_cmds') - unless defined($inc) and defined($from) and defined($to); - - my $bld_line = "\t\$(CXX) $inc$inc_dir $flags $from\$? $to\$@"; - - my @output_lines; - - foreach (sort keys %$files) { - my $src_file = File::Spec->catfile($$files{$_}, $_); - my $obj_file = File::Spec->catfile($dir, $_); - - $obj_file =~ s/\.cpp$/.$obj_suffix/; - $obj_file =~ s/\.c$/.$obj_suffix/; - $obj_file =~ s/\.S$/.$obj_suffix/; - - push @output_lines, "$obj_file: $src_file\n$bld_line"; - } - - return join("\n\n", @output_lines); -} - -sub determine_config { - my ($config) = @_; - - sub os_ar_command { - return os_info_for(shift, 'ar_command'); - } - - sub append_if { - my($var,$addme,$cond) = @_; - - croak('append_if: reference was undef') unless defined $var; - - if($cond and $addme ne '') { - $$var .= ' ' unless($$var eq '' or $$var =~ / $/); - $$var .= $addme; - } - } - - sub append_ifdef { - my($var,$addme) = @_; - append_if($var, $addme, defined($addme)); - } - - my $empty_if_nil = sub { - my $val = $_[0]; - return $val if defined($val); - return ''; - }; - - my %ccinfo = my_compiler($config); - - my $lang_flags = ''; - append_ifdef(\$lang_flags, $ccinfo{'lang_flags'}); - append_if(\$lang_flags, "-fpermissive", $$config{'gcc_bug'}); - - my $debug = $$config{'debug'}; - - my $lib_opt_flags = ''; - append_ifdef(\$lib_opt_flags, $ccinfo{'lib_opt_flags'}); - append_ifdef(\$lib_opt_flags, $ccinfo{'debug_flags'}) if($debug); - append_ifdef(\$lib_opt_flags, $ccinfo{'no_debug_flags'}) if(!$debug); - - # This is a default that works on most Unix and Unix-like systems - my $ar_command = 'ar crs'; - my $ranlib_command = 'true'; # almost no systems need it anymore - - # See if there are any over-riding methods. We presume if CC is creating - # the static libs, it knows how to create the index itself. - - my $os = $$config{'os'}; - - if($ccinfo{'ar_command'}) { - $ar_command = $ccinfo{'ar_command'}; - } - elsif(os_ar_command($os)) - { - $ar_command = os_ar_command($os); - $ranlib_command = 'ranlib' - if(os_info_for($os, 'ar_needs_ranlib') eq 'yes'); - } - - my $arch = $$config{'arch'}; - - my $abi_opts = ''; - append_ifdef(\$abi_opts, $ccinfo{'mach_abi_linking'}{$arch}); - append_ifdef(\$abi_opts, $ccinfo{'mach_abi_linking'}{$os}); - append_ifdef(\$abi_opts, $ccinfo{'mach_abi_linking'}{'all'}); - $abi_opts = ' ' . $abi_opts if($abi_opts ne ''); - - if($$config{'shared'} eq 'yes' and - (in_array('all', $OPERATING_SYSTEM{$os}{'supports_shared'}) or - in_array($$config{'compiler'}, - $OPERATING_SYSTEM{$os}{'supports_shared'}))) { - - $$config{'shared_flags'} = &$empty_if_nil($ccinfo{'shared_flags'}); - $$config{'so_link'} = &$empty_if_nil($ccinfo{'so_link_flags'}{$os}); - - if($$config{'so_link'} eq '') { - $$config{'so_link'} = - &$empty_if_nil($ccinfo{'so_link_flags'}{'default'}) - } - - if($$config{'shared_flags'} eq '' and $$config{'so_link'} eq '') { - $$config{'shared'} = 'no'; - - warning($$config{'compiler'}, ' has no shared object flags set ', - "for $os; disabling shared"); - } - } - else { - autoconfig("No shared library generated with " . - $$config{'compiler'} . " on " . $$config{'os'}); - - $$config{'shared'} = 'no'; - $$config{'shared_flags'} = ''; - $$config{'so_link'} = ''; - } - - add_to($config, { - 'cc' => $ccinfo{'binary_name'} . $abi_opts, - 'lib_opt' => $lib_opt_flags, - 'check_opt' => &$empty_if_nil($ccinfo{'check_opt_flags'}), - 'mach_opt' => mach_opt($config), - 'lang_flags' => $lang_flags, - 'warn_flags' => &$empty_if_nil($ccinfo{'warning_flags'}), - - 'ar_command' => $ar_command, - 'ranlib_command' => $ranlib_command, - 'static_suffix' => os_info_for($os, 'static_suffix'), - 'so_suffix' => os_info_for($os, 'so_suffix'), - 'obj_suffix' => os_info_for($os, 'obj_suffix'), - - 'dll_export_flags' => $ccinfo{'dll_export_flags'}, - 'dll_import_flags' => $ccinfo{'dll_import_flags'}, - - 'install_cmd_exec' => os_info_for($os, 'install_cmd_exec'), - 'install_cmd_data' => os_info_for($os, 'install_cmd_data'), - }); -} - -sub generate_makefile { - my ($config) = @_; - - my $is_in_doc_dir = - sub { -e File::Spec->catfile($$config{'doc_src_dir'}, $_[0]) }; - - my $docs = file_list(undef, undef, undef, - map_to($$config{'doc_src_dir'}, - grep { &$is_in_doc_dir($_); } @DOCS)); - - $docs .= File::Spec->catfile($$config{'base-dir'}, 'readme.txt'); - - my $includes = file_list(undef, undef, undef, - map_to($$config{'build_include_botan'}, - keys %{$$config{'includes'}})); - - my $lib_objs = file_list($$config{'build_lib'}, '(\.cpp$|\.c$|\.S$)', - '.' . $$config{'obj_suffix'}, - %{$$config{'sources'}}); - - my $check_objs = file_list($$config{'build_check'}, '.cpp', - '.' . $$config{'obj_suffix'}, - %{$$config{'check_src'}}), - - my $lib_build_cmds = build_cmds($config, $$config{'build_lib'}, - '$(LIB_FLAGS)', $$config{'sources'}); - - my $check_build_cmds = build_cmds($config, $$config{'build_check'}, - '$(CHECK_FLAGS)', $$config{'check_src'}); - - add_to($config, { - 'lib_objs' => $lib_objs, - 'check_objs' => $check_objs, - 'lib_build_cmds' => $lib_build_cmds, - 'check_build_cmds' => $check_build_cmds, - - 'doc_files' => $docs, - 'include_files' => $includes - }); - - my $template_dir = File::Spec->catdir($$config{'config-dir'}, 'makefile'); - my $template = undef; - - my $make_style = $$config{'make_style'}; - - if($make_style eq 'unix') { - $template = File::Spec->catfile($template_dir, 'unix.in'); - - $template = File::Spec->catfile($template_dir, 'unix_shr.in') - if($$config{'shared'} eq 'yes'); - - add_to($config, { - 'link_to' => libs('-l', '', 'm', @{$$config{'mod_libs'}}), - }); - } - elsif($make_style eq 'nmake') { - $template = File::Spec->catfile($template_dir, 'nmake.in'); - - add_to($config, { - 'shared' => 'no', - 'link_to' => libs('', '', '', @{$$config{'mod_libs'}}), - }); - } - - croak("Don't know about makefile format '$make_style'") - unless defined $template; - - trace("'$make_style' -> '$template'"); - - process_template($template, $$config{'makefile'}, $config); - - autoconfig("Wrote ${make_style}-style makefile in $$config{'makefile'}"); -} - -################################################## -# Configuration Guessing # -################################################## -sub guess_cpu_from_this -{ - my $cpuinfo = lc $_[0]; - - $cpuinfo =~ s/\(r\)//g; - $cpuinfo =~ s/\(tm\)//g; - $cpuinfo =~ s/ //g; - - trace("guess_cpu_from_this($cpuinfo)"); - - # The 32-bit SPARC stuff is impossible to match to arch type easily, and - # anyway the uname stuff will pick up that it's a SPARC so it doesn't - # matter. If it's an Ultra, assume a 32-bit userspace, no 64-bit code - # possible; that's the most common setup right now anyway - return 'sparc32-v9' if($cpuinfo =~ /ultrasparc/); - - # Should probably do this once and cache it - my @names; - my %all_alias; - - foreach my $arch (keys %CPU) { - my %info = %{$CPU{$arch}}; - - foreach my $submodel (@{$info{'submodels'}}) { - push @names, $submodel; - } - - if(defined($info{'submodel_aliases'})) { - my %submodel_aliases = %{$info{'submodel_aliases'}}; - foreach my $sm_alias (keys %submodel_aliases) { - push @names, $sm_alias; - $all_alias{$sm_alias} = $submodel_aliases{$sm_alias}; - } - } - } - - @names = sort { length($b) <=> length($a) } @names; - - foreach my $name (@names) { - if($cpuinfo =~ $name) { - trace("Matched '$cpuinfo' against '$name'"); - - return $all_alias{$name} if defined($all_alias{$name}); - - return $name; - } - } - - trace("Couldn't match $cpuinfo against any submodels"); - - # No match? Try arch names. Reset @names - @names = (); - - foreach my $arch (keys %CPU) { - my %info = %{$CPU{$arch}}; - - push @names, $info{'name'}; - - foreach my $alias (@{$info{'aliases'}}) { - push @names, $alias; - } - } - - @names = sort { length($b) <=> length($a) } @names; - - foreach my $name (@names) { - if($cpuinfo =~ $name) { - trace("Matched '$cpuinfo' against '$name'"); - return $name; - } - } - - return ''; -} - -# Do some WAGing and see if we can figure out what system we are. Think about -# this as a really moronic config.guess -sub guess_compiler -{ - my @CCS = ('gcc', 'msvc', 'icc', 'compaq', 'kai'); - - # First try the CC enviornmental variable, if it's set - if(defined($ENV{CC})) - { - my @new_CCS = ($ENV{CC}); - foreach my $cc (@CCS) { push @new_CCS, $cc; } - @CCS = @new_CCS; - } - - foreach (@CCS) - { - my $bin_name = $COMPILER{$_}{'binary_name'}; - if(which($bin_name) ne '') { - autoconfig("Guessing to use $_ as the compiler " . - "(use --cc to set)"); - return $_; - } - } - - croak( - "Can't find a usable C++ compiler, is PATH right?\n" . - "You might need to run with the --cc option (try $0 --help)\n"); -} - -sub guess_os -{ - sub recognize_os - { - my $os = os_alias($_[0]); - if(defined($OPERATING_SYSTEM{$os})) { - autoconfig("Guessing operating system is $os (use --os to set)"); - return $os; - } - return undef; - } - - my $guess = recognize_os($^O); - return $guess if $guess; - - trace("Can't guess os from $^O"); - - my $uname = $$config{'uname'}; - - if($uname ne '') { - $guess = recognize_os($uname); - return $guess if $guess; - trace("Can't guess os from $uname"); - } - - warning("Unknown OS ('$^O', '$uname'), falling back to generic code"); - return 'generic'; -} - -sub guess_cpu -{ - # If we have /proc/cpuinfo, try to get nice specific information about - # what kind of CPU we're running on. - my $cpuinfo = '/proc/cpuinfo'; - - if(defined($ENV{'CPUINFO'})) { - my $cpuinfo_env = $ENV{'CPUINFO'}; - - if(-e $cpuinfo_env and -r $cpuinfo_env) { - autoconfig("Will use $cpuinfo_env as /proc/cpuinfo"); - $cpuinfo = $cpuinfo_env; - } else { - warn("Could not read from ENV /proc/cpuinfo ($cpuinfo_env)"); - } - } - - if(-e $cpuinfo and -r $cpuinfo) - { - open CPUINFO, $cpuinfo or die "Could not read $cpuinfo\n"; - - while() { - - chomp; - $_ =~ s/\t/ /g; - $_ =~ s/ +/ /g; - - if($_ =~ /^cpu +: (.*)/ or - $_ =~ /^model name +: (.*)/) - { - my $cpu = guess_cpu_from_this($1); - if($cpu ne '') { - autoconfig("Guessing CPU using $cpuinfo line '$_'"); - autoconfig("Guessing CPU is a $cpu (use --cpu to set)"); - return $cpu; - } - } - } - - autoconfig("*** Could not figure out CPU based on $cpuinfo"); - autoconfig("*** Please mail contents to lloyd\@randombit.net"); - } - - sub known_arch { - my ($name) = @_; - - foreach my $arch (keys %CPU) { - my %info = %{$CPU{$arch}}; - - return 1 if $name eq $info{'name'}; - foreach my $submodel (@{$info{'submodels'}}) { - return 1 if $name eq $submodel; - } - - foreach my $alias (@{$info{'aliases'}}) { - return 1 if $name eq $alias; - } - - if(defined($info{'submodel_aliases'})) { - my %submodel_aliases = %{$info{'submodel_aliases'}}; - foreach my $sm_alias (keys %submodel_aliases) { - return 1 if $name eq $sm_alias; - } - } - } - - my $guess = guess_cpu_from_this($name); - - return 0 if($guess eq $name or $guess eq ''); - - return known_arch($guess); - } - - my $uname = $$config{'uname'}; - if($uname ne '') { - my $cpu = guess_cpu_from_this($uname); - - if($cpu ne '') - { - autoconfig("Guessing CPU using uname output '$uname'"); - autoconfig("Guessing CPU is a $cpu (use --cpu to set)"); - - return $cpu if known_arch($cpu); - } - } - - my $config_archname = $Config{'archname'}; - my $cpu = guess_cpu_from_this($config_archname); - - if($cpu ne '') - { - autoconfig("Guessing CPU using Config{archname} '$config_archname'"); - autoconfig("Guessing CPU is a $cpu (use --cpu to set)"); - - return $cpu if known_arch($cpu); - } - - warning("Could not determine CPU type (try --cpu option)"); - return 'generic'; -} diff --git a/doc/scripts/configure.pl b/doc/scripts/configure.pl new file mode 100755 index 000000000..4859ede74 --- /dev/null +++ b/doc/scripts/configure.pl @@ -0,0 +1,2337 @@ +#!/usr/bin/perl -w + +require 5.006; + +use strict; + +use Config; +use Getopt::Long; +use File::Spec; +use File::Copy; +use File::Find; +use Sys::Hostname; + +my $MAJOR_VERSION = 1; +my $MINOR_VERSION = 9; +my $PATCH_VERSION = 0; + +my $VERSION_SUFFIX = '-pre'; + +my $SO_PATCH_VERSION = 0; + +my $VERSION_STRING = "$MAJOR_VERSION.$MINOR_VERSION.$PATCH_VERSION$VERSION_SUFFIX"; +my $SO_VERSION_STRING = "$MAJOR_VERSION.$MINOR_VERSION.$SO_PATCH_VERSION$VERSION_SUFFIX"; + +################################################## +# Data # +################################################## +my (%CPU, %OPERATING_SYSTEM, %COMPILER, %MODULES); + +my @DOCS = ( + 'api.pdf', 'tutorial.pdf', 'fips140.pdf', + 'api.tex', 'tutorial.tex', 'fips140.tex', + 'credits.txt', 'license.txt', 'log.txt', + 'thanks.txt', 'todo.txt', 'pgpkeys.asc'); + +my $TRACING = 0; + +################################################## +# Run main() and Quit # +################################################## +my $config = {}; + +main(); +exit; + +sub exec_uname { + # Only exec it if we think it might actually work + if(-f '/bin/uname' || -f '/usr/bin/uname' || -f '/bin/sh') { + my $uname = `uname -a`; + if($uname) { + chomp $uname; + return $uname; + } + } + + return ''; +} + +sub deprecation_warning { + warning("$0 is deprecated; migration to ./configure.py strongly recommended"); +} + +################################################## +# Main Driver # +################################################## +sub main { + my $base_dir = where_am_i(); + + deprecation_warning(); + + $$config{'uname'} = exec_uname(); + + $$config{'base-dir'} = $base_dir; + $$config{'src-dir'} = File::Spec->catdir($base_dir, 'src'); + $$config{'checks-dir'} = File::Spec->catdir($base_dir, 'checks'); + $$config{'doc_src_dir'} = File::Spec->catdir($base_dir, 'doc'); + + $$config{'config-dir'} = + File::Spec->catdir($$config{'src-dir'}, 'build-data'); + + $$config{'command_line'} = $0 . ' ' . join(' ', @ARGV); + $$config{'timestamp'} = gmtime; + $$config{'user'} = getlogin || getpwuid($<) || ''; + $$config{'hostname'} = hostname; + + %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, + 'so_version' => $SO_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', ''); + + # Goes into build-specific dirs (maybe) + + $$config{'build_dir'} = 'build'; + $$config{'botan_config'} = File::Spec->catfile( + $$config{'build_dir'}, 'botan-config'); + + $$config{'botan_pkgconfig'} = File::Spec->catfile( + $$config{'build_dir'}, + 'botan-' . $MAJOR_VERSION . '.' . $MINOR_VERSION . '.pc'); + + $$config{'makefile'} = 'Makefile'; + $$config{'check_prefix'} = ''; + $$config{'lib_prefix'} = ''; + + if(defined($$config{'with_build_dir'})) { + for my $var ('build_dir', + 'botan_config', + 'botan_pkgconfig', + 'makefile', + 'check_prefix', + 'lib_prefix') + { + $$config{$var} = File::Spec->catfile($$config{'with_build_dir'}, + $$config{$var}); + } + } + else { + } + + 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'}); + + scan_modules($config); + + print_enabled_modules($config); + + 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($config), + 'mod_libs' => [ using_libs($config) ], + + 'sources' => { }, + 'includes' => { }, + + '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); + + determine_config($config); + + process_template(File::Spec->catfile($$config{'config-dir'}, 'buildh.in'), + File::Spec->catfile($$config{'build_dir'}, 'build.h'), + $config); + + process_template(File::Spec->catfile( + $$config{'config-dir'}, 'botan.doxy.in'), + File::Spec->catfile($$config{'doc_src_dir'}, 'botan.doxy'), + $config); + + $$config{'includes'}{'build.h'} = $$config{'build_dir'}; + + generate_makefile($config); + + copy_include_files($config); + + deprecation_warning(); +} + +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', @_); +} + +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:://; + + print 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 > 58) { + $output .= "\n "; + $len = 8; + } + &$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 = <&1`; + + $gcc_version = '' if not defined $gcc_version; + + my $has_ll_bug = 0; + $has_ll_bug = 1 if($gcc_version =~ /4\.[01234]/); + $has_ll_bug = 1 if($gcc_version =~ /3\.[34]/); + $has_ll_bug = 1 if($gcc_version =~ /2\.95\.[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, + }); +} + +sub module_runs_on { + my ($config, $modinfo, $mod, $noisy) = @_; + + my $cc = $$config{'compiler'}; + my $os = $$config{'os'}; + my $submodel = $$config{'submodel'}; + my $arch = $$config{'arch'}; + + my %modinfo = %{$modinfo}; + + my $realname = $modinfo{'realname'}; + + my @arch_list = @{ $modinfo{'arch'} }; + if(scalar @arch_list > 0 && !in_array($arch, \@arch_list) && + !in_array($submodel, \@arch_list)) + { + autoconfig("$mod ($realname): skipping, " . + "not compatible with " . realname($arch) . + "/" . $submodel) if $noisy; + return 0; + } + + my @os_list = @{ $modinfo{'os'} }; + if(scalar @os_list > 0 && !in_array($os, \@os_list)) + { + autoconfig("$mod ($realname): " . + "skipping, not compatible with " . realname($os)) if $noisy; + return 0; + } + + my @cc_list = @{ $modinfo{'cc'} }; + if(scalar @cc_list > 0 && !in_array($cc, \@cc_list)) { + autoconfig("$mod ($realname): " . + "skipping, not compatible with " . realname($cc)) if $noisy; + return 0; + } + + + if($modinfo{'uses_tr1'} eq 'yes') { + return 0 unless defined($$config{'tr1'}); + + my $tr1 = $$config{'tr1'}; + return 0 unless($tr1 eq 'system' or $tr1 eq 'boost'); + } + + return 1; +} + +sub scan_modules { + my ($config) = @_; + + foreach my $mod (sort keys %MODULES) { + my %modinfo = %{ $MODULES{$mod} }; + + next if(defined($$config{'modules'}{$mod}) && $$config{'modules'}{$mod} < 0); + + next unless(module_runs_on($config, \%modinfo, $mod, 0)); + + if($modinfo{'load_on'} eq 'auto' or + ($modinfo{'load_on'} eq 'asm_ok' and $$config{'asm_ok'})) { + + my %maybe_load = (); + my $all_deps_found = 1; + + LINE: foreach (@{$modinfo{'requires'}}) { + for my $req_mod (split(/\|/, $_)) { + next unless defined $MODULES{$req_mod}; + + next if(defined($$config{'modules'}{$req_mod}) && $$config{'modules'}{$req_mod} < 0); + next unless(module_runs_on($config, $MODULES{$req_mod}, $req_mod, 0)); + + $maybe_load{$req_mod} = 1; + next LINE; + } + $all_deps_found = 0; + } + + if($all_deps_found) { + foreach my $depmod (keys %maybe_load) + { $$config{'modules'}{$depmod} = 1; } + $$config{'modules'}{$mod} = 1; + } + } + } +} + +sub print_enabled_modules { + my ($config) = @_; + + return unless($$config{'verbose'}); + + my %by_type; + + foreach my $mod (sort keys %MODULES) { + my $type = $MODULES{$mod}{'type'}; + + my $n = 0; + $n = 1 if($$config{'modules'}{$mod} && $$config{'modules'}{$mod} > 0); + + $by_type{$type}{$mod} = $n; + } + + for my $type (sort keys %by_type) { + my %mods = %{$by_type{$type}}; + + my @load_lines; + + if(keys %mods == 1) { + my $on = $mods{$type}; + + if($on > 0) { + print with_diagnostic('loading', $type); + } + else { + print with_diagnostic('loading', '[', $type , ']'); + } + } + else { + my $s = $type . ': '; + + for my $mod (sort keys %mods) { + my $on = $mods{$mod}; + + if($s eq '') { + $s = ' ' x (length($type) + 16); + } + + if($on > 0) { + $s .= $mod . ' '; + } + else { + $s .= '[' . $mod . '] '; + } + + if(length($s) > 60) { + push @load_lines, $s; + $s = ''; + } + } + + #print "Last1 '$s'\n"; + + $s =~ s/\s*$//m; # strip trailing whitespace + + push @load_lines, $s if($s ne ''); + + + print with_diagnostic('loading', join("\n", @load_lines)); + } + } +} + +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{'tr1'} = undef; # not enabled by default + $$config{'modules'} = {}; + + sub arch_info { + my $arg = $_[0]; + + my $arch = find_arch($arg); + + unless(defined($arch) and defined($CPU{$arch})) { + warning("Unknown arch '$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)) { + # -1 means disabled by user, do not load + $$config{'modules'}{$mod} = 1 unless( + defined($$config{'modules'}{$mod}) && + $$config{'modules'}{$mod} == -1); + } + } + + sub disable_modules { + my ($config,$mods) = @_; + + foreach my $mod (split(/,/, $mods)) { + # -1 means disabled by user, do not load + $$config{'modules'}{$mod} = -1; + } + } + + sub add_module_sets { + my ($config,$sets) = @_; + + foreach my $set (split(/,/, $sets)) { + for my $mod (sort keys %MODULES) { + my %info = %{$MODULES{$mod}}; + + next unless (defined($info{'modset'})); + + for my $s (split(/,/, $info{'modset'})) { + if($s eq $set) { + $$config{'modules'}{$mod} = 1 + unless($$config{'modules'}{$mod} == -1); + } + } + } + } + } + + exit 1 unless GetOptions( + 'prefix=s' => sub { &$save_option(@_); }, + 'exec-prefix=s' => sub { &$save_option(@_); }, + + 'bindir=s' => sub { &$save_option(@_); }, + 'datadir' => sub { &$save_option(@_); }, + 'datarootdir' => sub { &$save_option(@_); }, + 'docdir=s' => sub { &$save_option(@_); }, + 'dvidir' => sub { &$save_option(@_); }, + 'htmldir' => sub { &$save_option(@_); }, + 'includedir' => sub { &$save_option(@_); }, + 'infodir' => sub { &$save_option(@_); }, + 'libdir=s' => sub { &$save_option(@_); }, + 'libexecdir' => sub { &$save_option(@_); }, + 'localedir' => sub { &$save_option(@_); }, + 'localstatedir' => sub { &$save_option(@_); }, + 'mandir' => sub { &$save_option(@_); }, + 'oldincludedir' => sub { &$save_option(@_); }, + 'pdfdir' => sub { &$save_option(@_); }, + 'psdir' => sub { &$save_option(@_); }, + 'sbindir=s' => sub { &$save_option(@_); }, + 'sharedstatedir' => sub { &$save_option(@_); }, + 'sysconfdir' => sub { &$save_option(@_); }, + + 'cc=s' => sub { &$save_option('compiler', $_[1]) }, + 'os=s' => sub { &$save_option(@_) }, + 'cpu=s' => sub { &$save_option(@_) }, + + 'help' => sub { display_help(); }, + 'module-info' => sub { emit_help(module_info()); }, + 'version' => sub { emit_help("$VERSION_STRING\n") }, + 'so-version' => sub { emit_help("$SO_VERSION_STRING\n") }, + + 'with-tr1-implementation=s' => sub { $$config{'tr1'} = $_[1]; }, + + 'quiet' => sub { $$config{'verbose'} = 0; }, + 'trace' => sub { $TRACING = 1; }, + + 'enable-asm' => sub { $$config{'asm_ok'} = 1; }, + 'disable-asm' => sub { $$config{'asm_ok'} = 0; }, + + 'enable-autoconfig' => sub { $$config{'autoconfig'} = 1; }, + 'disable-autoconfig' => sub { $$config{'autoconfig'} = 0; }, + + 'enable-shared' => sub { $$config{'shared'} = 'yes'; }, + 'disable-shared' => sub { $$config{'shared'} = 'no'; }, + + 'enable-debug' => sub { &$save_option('debug', 1); }, + 'disable-debug' => sub { &$save_option('debug', 0); }, + + 'enable-modules:s' => sub { add_modules($config, $_[1]); }, + 'disable-modules:s' => sub { disable_modules($config, $_[1]); }, + + 'with-openssl' => sub { add_modules($config, 'openssl'); }, + 'without-openssl' => sub { disable_modules($config, 'openssl'); }, + 'with-gnump' => sub { add_modules($config, 'gnump'); }, + 'without-gnump' => sub { disable_modules($config, 'gnump'); }, + 'with-bzip2' => sub { add_modules($config, 'bzip2'); }, + 'without-bzip2' => sub { disable_modules($config, 'bzip2'); }, + 'with-zlib' => sub { add_modules($config, 'zlib'); }, + 'without-zlib' => sub { disable_modules($config, 'zlib'); }, + + 'use-module-set=s' => sub { add_module_sets($config, $_[1]); }, + + 'with-build-dir=s' => sub { &$save_option(@_); }, + 'with-endian=s' => sub { &$save_option(@_); }, + 'with-unaligned-mem=s' => sub { &$save_option(@_); }, + 'with-local-config=s' => + sub { &$save_option('local_config', slurp_file($_[1])); }, + + 'modules=s' => sub { add_modules($config, $_[1]); }, + 'show-arch-info=s' => sub { emit_help(arch_info($_[1])); }, + 'make-style=s' => sub { &$save_option(@_); }, + '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 ($config) = @_; + + my $os = $$config{'os'}; + my %libs; + + foreach my $mod (sort keys %{$$config{'modules'}}) { + next if ${$$config{'modules'}}{$mod} < 0; + + 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) = @_; + + #trace("portable_symlink($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 { !/#/ and -f File::Spec->catfile($dir, $_) and + $_ 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() { $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 (sort keys %{$$config{'modules'}}) { + croak("Unknown module $modname") unless defined $MODULES{$modname}; + + next if $$config{'modules'}{$modname} < 0; + + 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_module { + my ($config, $modname) = @_; + + #trace("load_module($modname)"); + + croak("Unknown module $modname") unless defined($MODULES{$modname}); + + my %module = %{$MODULES{$modname}}; + + my $works_on = sub { + my ($what, $lst_ref) = @_; + my @lst = @{$lst_ref}; + return 1 if not @lst; # empty list -> no restrictions + return 1 if $what eq 'generic'; # trust the user + return in_array($what, \@lst); + }; + + # Check to see if everything is OK WRT system requirements + my $os = $$config{'os'}; + + croak("Module '$modname' does not run on $os") + unless(&$works_on($os, $module{'os'})); + + my $arch = $$config{'arch'}; + my $sub = $$config{'submodel'}; + + croak("Module '$modname' does not run on $arch/$sub") + unless(&$works_on($arch, $module{'arch'}) or + &$works_on($sub, $module{'arch'})); + + my $cc = $$config{'compiler'}; + + croak("Module '$modname' does not work with $cc") + unless(&$works_on($cc, $module{'cc'})); + + my $handle_files = sub { + my($lst, $func) = @_; + return unless defined($lst); + + foreach (sort @$lst) { + &$func($module{'moddirs'}, $config, $_); + } + }; + + &$handle_files($module{'ignore'}, \&ignore_file); + &$handle_files($module{'add'}, \&add_file); + &$handle_files($module{'replace'}, + sub { ignore_file(@_); add_file(@_); }); + + warning($modname, ': ', $module{'note'}) + if(defined($module{'note'})); +} + +sub load_modules { + my ($config) = @_; + + my @mod_names; + + foreach my $mod (sort keys %{$$config{'modules'}}) { + next unless($$config{'modules'}{$mod} > 0); + + load_module($config, $mod); + + push @mod_names, $mod; + } + + $$config{'mod_list'} = join("\n", @mod_names); + + my $unaligned_ok = 0; + + my $target_os_defines = sub { + my @macro_list; + + my $os = $$config{'os'}; + if($os ne 'generic') { + push @macro_list, '#define BOTAN_TARGET_OS_IS_' . uc $os; + + my @features = @{$OPERATING_SYSTEM{$os}{'target_features'}}; + + for my $feature (@features) { + push @macro_list, '#define BOTAN_TARGET_OS_HAS_' . uc $feature; + } + + } + return join("\n", @macro_list); + }; + + $$config{'target_os_defines'} = &$target_os_defines(); + + my $target_cpu_defines = sub { + my @macro_list; + + my $arch = $$config{'arch'}; + if($arch ne 'generic') { + my %cpu_info = %{$CPU{$arch}}; + my $endian = $cpu_info{'endian'}; + + if(defined($$config{'with_endian'})) { + $endian = $$config{'with_endian'}; + $endian = undef unless($endian eq 'little' || + $endian eq 'big'); + } + elsif(defined($endian)) { + autoconfig("Since arch is $arch, assuming $endian endian mode"); + } + + push @macro_list, "#define BOTAN_TARGET_ARCH_IS_" . (uc $arch); + + my $submodel = $$config{'submodel'}; + if($arch ne $submodel) { + $submodel = uc $submodel; + $submodel =~ tr/-/_/; + $submodel =~ tr/.//; + + push @macro_list, "#define BOTAN_TARGET_CPU_IS_$submodel"; + } + + if(defined($endian)) { + $endian = uc $endian; + push @macro_list, + "#define BOTAN_TARGET_CPU_IS_${endian}_ENDIAN"; + + # See if the user set --with-unaligned-mem + if(defined($$config{'with_unaligned_mem'})) { + my $spec = $$config{'with_unaligned_mem'}; + + if($spec eq 'yes') { + $unaligned_ok = 1; + } + elsif($spec eq 'no') { + $unaligned_ok = 0; + } + else { + warning('Unknown arg to --with-unaligned-mem (' . + $spec . ') will ignore'); + $unaligned_ok = 0; + } + } + # Otherwise, see if the CPU has a default setting + 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; + } + } + } + + # variable is always set (one or zero) + push @macro_list, + "#define BOTAN_TARGET_UNALIGNED_LOADSTOR_OK $unaligned_ok"; + return join("\n", @macro_list); + }; + + $$config{'target_cpu_defines'} = &$target_cpu_defines(); + + my $target_compiler_defines = sub { + my @macro_list; + + if(defined($$config{'tr1'})) { + my $tr1 = $$config{'tr1'}; + + if($tr1 eq 'system') { + push @macro_list, '#define BOTAN_USE_STD_TR1'; + } + elsif($tr1 eq 'boost') { + push @macro_list, '#define BOTAN_USE_BOOST_TR1'; + } + elsif($tr1 ne 'none') { + croak("Unknown --with-tr1= option value '$tr1' (try --help)"); + } + } + + return join("\n", @macro_list); + }; + + $$config{'target_compiler_defines'} = &$target_compiler_defines(); + + my $gen_defines = sub { + my @macro_list; + + my %defines; + + foreach my $mod (sort keys %{$$config{'modules'}}) { + next unless $$config{'modules'}{$mod} > 0; + + my $defs = $MODULES{$mod}{'define'}; + next unless $defs; + + push @{$defines{$MODULES{$mod}{'type'}}}, split(/,/, $defs); + } + + foreach my $type (sort keys %defines) { + push @macro_list, "\n/* $type */"; + + for my $macro (@{$defines{$type}}) { + die unless(defined $macro and $macro ne ''); + push @macro_list, "#define BOTAN_HAS_$macro"; + } + } + + return join("\n", @macro_list); + }; + + $$config{'module_defines'} = &$gen_defines(); +} + +################################################## +# # +################################################## +sub file_type { + my ($file) = @_; + + return 'sources' + if($file =~ /\.cpp$/ or $file =~ /\.c$/ or $file =~ /\.S$/); + return 'includes' if($file =~ /\.h$/); + + croak('file_type() - don\'t know what sort of file ', $file, ' is'); +} + +sub add_file { + my ($mod_dir, $config, $file) = @_; + + check_for_file($config, $file, $mod_dir, $mod_dir); + + my $do_add_file = sub { + my ($type) = @_; + + croak("File $file already added from ", $$config{$type}{$file}) + if(defined($$config{$type}{$file})); + + if($file =~ /(.*):(.*)/) { + my @dirs = File::Spec->splitdir($mod_dir); + + $dirs[$#dirs-1] = $1; + + $$config{$type}{$2} = File::Spec->catdir(@dirs); + } + else { + $$config{$type}{$file} = $mod_dir; + } + }; + + &$do_add_file(file_type($file)); +} + +sub ignore_file { + my ($mod_dir, $config, $file) = @_; + check_for_file($config, $file, undef, $mod_dir); + + my $do_ignore_file = sub { + my ($type, $ok_if_from) = @_; + + if(defined ($$config{$type}{$file})) { + + croak("$mod_dir - File $file modified from ", + $$config{$type}{$file}) + if($$config{$type}{$file} ne $ok_if_from); + + delete $$config{$type}{$file}; + } + }; + + &$do_ignore_file(file_type($file)); +} + +sub check_for_file { + my ($config, $file, $added_from, $mod_dir) = @_; + + #trace("check_for_file($file, $added_from, $mod_dir)"); + + my $full_path = sub { + my ($file,$mod_dir) = @_; + + if($file =~ /(.*):(.*)/) { + return File::Spec->catfile($mod_dir, '..', $1, $2); + } else { + return File::Spec->catfile($mod_dir, $file) if(defined($mod_dir)); + + my @typeinfo = file_type($config, $file); + return File::Spec->catfile($typeinfo[1], $file); + } + }; + + $file = &$full_path($file, $added_from); + + croak("Module $mod_dir requires that file $file exist. This error\n ", + 'should never occur; please contact the maintainers with details.') + unless(-e $file); +} + +################################################## +# # +################################################## +sub process_template { + my ($in, $out, $config) = @_; + + trace("process_template: $in -> $out"); + + my $contents = slurp_file($in); + + foreach my $name (keys %$config) { + my $val = $$config{$name}; + + unless(defined $val) { + trace("Undefined variable $name in $in"); + next; + } + + $contents =~ s/\%\{$name\}/$val/g; + } + + if($contents =~ /\%\{([a-z_]*)\}/) { + + sub summarize { + my ($n, $s) = @_; + + $s =~ s/\n/\\n/; # escape newlines + + return $s if(length($s) <= $n); + + return substr($s, 0, 57) . '...'; + } + + foreach my $key (sort keys %$config) { + print with_diagnostic("debug", + "In %config:", $key, " -> ", + summarize(60, $$config{$key})); + } + + croak("Unbound variable '$1' in $in"); + } + + open OUT, ">$out" or croak("Couldn't write $out ($!)"); + print OUT $contents; + close OUT; +} + +################################################## +# # +################################################## +sub read_list { + my ($line, $reader, $marker, $func) = @_; + + if($line =~ m@^<$marker>$@) { + while(1) { + $line = &$reader(); + + die "EOF while searching for $marker" unless $line; + last if($line =~ m@^$@); + &$func($line); + } + } +} + +sub list_push { + my ($listref) = @_; + return sub { push @$listref, $_[0]; } +} + +sub match_any_of { + my ($line, $hash, $quoted, @any_of) = @_; + + $quoted = ($quoted eq 'quoted') ? 1 : 0; + + foreach my $what (@any_of) { + $$hash{$what} = $1 if(not $quoted and $line =~ /^$what (.*)/); + $$hash{$what} = $1 if($quoted and $line =~ /^$what \"(.*)\"/); + } +} + +################################################## +# # +################################################## +sub make_reader { + my $filename = $_[0]; + + croak("make_reader(): Arg was undef") if not defined $filename; + + open FILE, "<$filename" or + croak("Couldn't read $filename ($!)"); + + return sub { + my $line = ''; + while(1) { + my $line = ; + last unless defined($line); + + chomp($line); + $line =~ s/#.*//; + $line =~ s/^\s*//; + $line =~ s/\s*$//; + $line =~ s/\s\s*/ /; + $line =~ s/\t/ /; + return $line if $line ne ''; + } + close FILE; + return undef; + } +} + +################################################## +# # +################################################## +sub read_info_files { + my ($config, $dir, $func) = @_; + + $dir = File::Spec->catdir($$config{'config-dir'}, $dir); + + my %allinfo; + foreach my $file (dir_list($dir)) { + my $fullpath = File::Spec->catfile($dir, $file); + + trace("reading $fullpath"); + %{$allinfo{$file}} = &$func($file, $fullpath); + } + + return %allinfo; +} + +sub read_module_files { + my ($config) = @_; + + my %allinfo; + + my @modinfos; + + File::Find::find( + { wanted => sub + { if(-f $_ && /^info\.txt\z/s) { + my $name = $File::Find::name; + push @modinfos, $name; + } + } + }, + $$config{'src-dir'}); + + foreach my $modfile (@modinfos) { + trace("reading $modfile"); + + my ($volume,$dirs,$file) = File::Spec->splitpath($modfile); + + my @dirs = File::Spec->splitdir($dirs); + my $moddir = $dirs[$#dirs-1]; + + trace("module $moddir in $dirs $modfile"); + + %{$allinfo{$moddir}} = get_module_info($dirs, $moddir, $modfile); + } + + return %allinfo; +} + +################################################## +# # +################################################## + +sub get_module_info { + my ($dirs, $name, $modfile) = @_; + my $reader = make_reader($modfile); + + my %info; + + $info{'name'} = $name; + $info{'modinfo'} = $modfile; + $info{'moddirs'} = $dirs; + + # Default module settings + $info{'load_on'} = 'request'; # default unless specified + $info{'uses_tr1'} = 'no'; + $info{'libs'} = {}; + $info{'use'} = 'no'; + + my @dir_arr = File::Spec->splitdir($dirs); + $info{'type'} = $dir_arr[$#dir_arr-2]; # cipher, hash, ... + if($info{'type'} eq 'src') { $info{'type'} = $dir_arr[$#dir_arr-1]; } + + while($_ = &$reader()) { + match_any_of($_, \%info, 'quoted', 'realname', 'note', 'type'); + match_any_of($_, \%info, 'unquoted', 'define', 'mp_bits', + 'modset', 'load_on', 'uses_tr1'); + + read_list($_, $reader, 'arch', list_push(\@{$info{'arch'}})); + read_list($_, $reader, 'cc', list_push(\@{$info{'cc'}})); + read_list($_, $reader, 'os', list_push(\@{$info{'os'}})); + read_list($_, $reader, 'add', list_push(\@{$info{'add'}})); + read_list($_, $reader, 'replace', list_push(\@{$info{'replace'}})); + read_list($_, $reader, 'ignore', list_push(\@{$info{'ignore'}})); + read_list($_, $reader, 'requires', list_push(\@{$info{'requires'}})); + + read_list($_, $reader, 'libs', + sub { + my $line = $_[0]; + $line =~ m/^([\w!,]*) -> ([\w.,-]*)$/; + $info{'libs'}{$1} = $2; + }); + + if(/^require_version /) { + if(/^require_version (\d+)\.(\d+)\.(\d+)$/) { + my $version = "$1.$2.$3"; + my $needed_version = 100*$1 + 10*$2 + $3; + + my $have_version = + 100*$MAJOR_VERSION + 10*$MINOR_VERSION + $PATCH_VERSION; + + if($needed_version > $have_version) { + warning("Module $name needs v$version; disabling"); + return (); + } + } + else { + croak("In module $name, bad version requirement '$_'"); + } + } + } + + return %info; +} + +################################################## +# # +################################################## +sub get_arch_info { + my ($name,$file) = @_; + my $reader = make_reader($file); + + my %info; + $info{'name'} = $name; + + while($_ = &$reader()) { + match_any_of($_, \%info, 'quoted', 'realname'); + match_any_of($_, \%info, 'unquoted', + 'default_submodel', 'endian', 'unaligned'); + + read_list($_, $reader, 'aliases', list_push(\@{$info{'aliases'}})); + read_list($_, $reader, 'submodels', list_push(\@{$info{'submodels'}})); + + read_list($_, $reader, 'submodel_aliases', + sub { + my $line = $_[0]; + $line =~ m/^(\S*) -> (\S*)$/; + $info{'submodel_aliases'}{$1} = $2; + }); + } + return %info; +} + +################################################## +# # +################################################## +sub get_os_info { + my ($name,$file) = @_; + my $reader = make_reader($file); + + my %info; + $info{'name'} = $name; + + while($_ = &$reader()) { + match_any_of($_, \%info, + 'quoted', 'realname', 'ar_command', + 'install_cmd_data', 'install_cmd_exec'); + + match_any_of($_, \%info, 'unquoted', + 'os_type', + 'obj_suffix', + 'so_suffix', + 'static_suffix', + 'install_root', + 'header_dir', + 'lib_dir', 'doc_dir', + 'ar_needs_ranlib'); + + read_list($_, $reader, 'aliases', list_push(\@{$info{'aliases'}})); + + read_list($_, $reader, 'target_features', + list_push(\@{$info{'target_features'}})); + + read_list($_, $reader, 'supports_shared', + list_push(\@{$info{'supports_shared'}})); + } + return %info; +} + +################################################## +# Read a file from misc/config/cc and set the values from +# there into a hash for later reference +################################################## +sub get_cc_info { + my ($name,$file) = @_; + my $reader = make_reader($file); + + my %info; + $info{'name'} = $name; + + while($_ = &$reader()) { + match_any_of($_, \%info, 'quoted', + 'realname', + 'binary_name', + 'compile_option', + 'output_to_option', + 'add_include_dir_option', + 'add_lib_dir_option', + 'add_lib_option', + 'lib_opt_flags', + 'check_opt_flags', + 'dll_import_flags', + 'dll_export_flags', + 'lang_flags', + 'warning_flags', + 'shared_flags', + 'ar_command', + 'debug_flags', + 'no_debug_flags'); + + match_any_of($_, \%info, 'unquoted', + 'makefile_style', + 'compiler_has_tr1'); + + sub quoted_mapping { + my $hashref = $_[0]; + return sub { + my $line = $_[0]; + $line =~ m/^(\S*) -> \"(.*)\"$/; + $$hashref{$1} = $2; + } + } + + read_list($_, $reader, 'mach_abi_linking', + quoted_mapping(\%{$info{'mach_abi_linking'}})); + read_list($_, $reader, 'so_link_flags', + quoted_mapping(\%{$info{'so_link_flags'}})); + + read_list($_, $reader, 'mach_opt', + sub { + my $line = $_[0]; + $line =~ m/^(\S*) -> \"(.*)\" ?(.*)?$/; + $info{'mach_opt_flags'}{$1} = $2; + $info{'mach_opt_re'}{$1} = $3; + }); + + } + return %info; +} + +################################################## +# # +################################################## +sub write_pkg_config { + my ($config) = @_; + + return if($$config{'os'} eq 'generic' or + $$config{'os'} eq 'windows'); + + $$config{'link_to'} = libs('-l', '', 'm', @{$$config{'mod_libs'}}); + + my $botan_config = $$config{'botan_config'}; + + process_template( + File::Spec->catfile($$config{'config-dir'}, 'botan-config.in'), + $botan_config, $config); + chmod 0755, $botan_config; + + process_template( + File::Spec->catfile($$config{'config-dir'}, 'botan.pc.in'), + $$config{'botan_pkgconfig'}, $config); + + delete $$config{'link_to'}; +} + +################################################## +# # +################################################## +sub file_list { + my ($put_in, $from, $to, %files) = @_; + + my $list = ''; + + my $spaces = 16; + + foreach (sort keys %files) { + my $file = $_; + + $file =~ s/$from/$to/ if(defined($from) and defined($to)); + + my $dir = $files{$_}; + $dir = $put_in if defined $put_in; + + if(defined($dir)) { + $list .= File::Spec->catfile ($dir, $file); + } + else { + $list .= $file; + } + + $list .= " \\\n "; + } + + $list =~ s/\\\n +$//; # remove trailing escape + + return $list; +} + +sub build_cmds { + my ($config, $dir, $flags, $files) = @_; + + my $obj_suffix = $$config{'obj_suffix'}; + + my %ccinfo = my_compiler($config); + + my $inc = $ccinfo{'add_include_dir_option'}; + my $from = $ccinfo{'compile_option'}; + my $to = $ccinfo{'output_to_option'}; + + my $inc_dir = $$config{'build_include'}; + + # Probably replace by defaults to -I -c -o + croak('undef value found in build_cmds') + unless defined($inc) and defined($from) and defined($to); + + my $bld_line = "\t\$(CXX) $inc$inc_dir $flags $from\$? $to\$@"; + + my @output_lines; + + foreach (sort keys %$files) { + my $src_file = File::Spec->catfile($$files{$_}, $_); + my $obj_file = File::Spec->catfile($dir, $_); + + $obj_file =~ s/\.cpp$/.$obj_suffix/; + $obj_file =~ s/\.c$/.$obj_suffix/; + $obj_file =~ s/\.S$/.$obj_suffix/; + + push @output_lines, "$obj_file: $src_file\n$bld_line"; + } + + return join("\n\n", @output_lines); +} + +sub determine_config { + my ($config) = @_; + + sub os_ar_command { + return os_info_for(shift, 'ar_command'); + } + + sub append_if { + my($var,$addme,$cond) = @_; + + croak('append_if: reference was undef') unless defined $var; + + if($cond and $addme ne '') { + $$var .= ' ' unless($$var eq '' or $$var =~ / $/); + $$var .= $addme; + } + } + + sub append_ifdef { + my($var,$addme) = @_; + append_if($var, $addme, defined($addme)); + } + + my $empty_if_nil = sub { + my $val = $_[0]; + return $val if defined($val); + return ''; + }; + + my %ccinfo = my_compiler($config); + + my $lang_flags = ''; + append_ifdef(\$lang_flags, $ccinfo{'lang_flags'}); + append_if(\$lang_flags, "-fpermissive", $$config{'gcc_bug'}); + + my $debug = $$config{'debug'}; + + my $lib_opt_flags = ''; + append_ifdef(\$lib_opt_flags, $ccinfo{'lib_opt_flags'}); + append_ifdef(\$lib_opt_flags, $ccinfo{'debug_flags'}) if($debug); + append_ifdef(\$lib_opt_flags, $ccinfo{'no_debug_flags'}) if(!$debug); + + # This is a default that works on most Unix and Unix-like systems + my $ar_command = 'ar crs'; + my $ranlib_command = 'true'; # almost no systems need it anymore + + # See if there are any over-riding methods. We presume if CC is creating + # the static libs, it knows how to create the index itself. + + my $os = $$config{'os'}; + + if($ccinfo{'ar_command'}) { + $ar_command = $ccinfo{'ar_command'}; + } + elsif(os_ar_command($os)) + { + $ar_command = os_ar_command($os); + $ranlib_command = 'ranlib' + if(os_info_for($os, 'ar_needs_ranlib') eq 'yes'); + } + + my $arch = $$config{'arch'}; + + my $abi_opts = ''; + append_ifdef(\$abi_opts, $ccinfo{'mach_abi_linking'}{$arch}); + append_ifdef(\$abi_opts, $ccinfo{'mach_abi_linking'}{$os}); + append_ifdef(\$abi_opts, $ccinfo{'mach_abi_linking'}{'all'}); + $abi_opts = ' ' . $abi_opts if($abi_opts ne ''); + + if($$config{'shared'} eq 'yes' and + (in_array('all', $OPERATING_SYSTEM{$os}{'supports_shared'}) or + in_array($$config{'compiler'}, + $OPERATING_SYSTEM{$os}{'supports_shared'}))) { + + $$config{'shared_flags'} = &$empty_if_nil($ccinfo{'shared_flags'}); + $$config{'so_link'} = &$empty_if_nil($ccinfo{'so_link_flags'}{$os}); + + if($$config{'so_link'} eq '') { + $$config{'so_link'} = + &$empty_if_nil($ccinfo{'so_link_flags'}{'default'}) + } + + if($$config{'shared_flags'} eq '' and $$config{'so_link'} eq '') { + $$config{'shared'} = 'no'; + + warning($$config{'compiler'}, ' has no shared object flags set ', + "for $os; disabling shared"); + } + } + else { + autoconfig("No shared library generated with " . + $$config{'compiler'} . " on " . $$config{'os'}); + + $$config{'shared'} = 'no'; + $$config{'shared_flags'} = ''; + $$config{'so_link'} = ''; + } + + add_to($config, { + 'cc' => $ccinfo{'binary_name'} . $abi_opts, + 'lib_opt' => $lib_opt_flags, + 'check_opt' => &$empty_if_nil($ccinfo{'check_opt_flags'}), + 'mach_opt' => mach_opt($config), + 'lang_flags' => $lang_flags, + 'warn_flags' => &$empty_if_nil($ccinfo{'warning_flags'}), + + 'ar_command' => $ar_command, + 'ranlib_command' => $ranlib_command, + 'static_suffix' => os_info_for($os, 'static_suffix'), + 'so_suffix' => os_info_for($os, 'so_suffix'), + 'obj_suffix' => os_info_for($os, 'obj_suffix'), + + 'dll_export_flags' => $ccinfo{'dll_export_flags'}, + 'dll_import_flags' => $ccinfo{'dll_import_flags'}, + + 'install_cmd_exec' => os_info_for($os, 'install_cmd_exec'), + 'install_cmd_data' => os_info_for($os, 'install_cmd_data'), + }); +} + +sub generate_makefile { + my ($config) = @_; + + my $is_in_doc_dir = + sub { -e File::Spec->catfile($$config{'doc_src_dir'}, $_[0]) }; + + my $docs = file_list(undef, undef, undef, + map_to($$config{'doc_src_dir'}, + grep { &$is_in_doc_dir($_); } @DOCS)); + + $docs .= File::Spec->catfile($$config{'base-dir'}, 'readme.txt'); + + my $includes = file_list(undef, undef, undef, + map_to($$config{'build_include_botan'}, + keys %{$$config{'includes'}})); + + my $lib_objs = file_list($$config{'build_lib'}, '(\.cpp$|\.c$|\.S$)', + '.' . $$config{'obj_suffix'}, + %{$$config{'sources'}}); + + my $check_objs = file_list($$config{'build_check'}, '.cpp', + '.' . $$config{'obj_suffix'}, + %{$$config{'check_src'}}), + + my $lib_build_cmds = build_cmds($config, $$config{'build_lib'}, + '$(LIB_FLAGS)', $$config{'sources'}); + + my $check_build_cmds = build_cmds($config, $$config{'build_check'}, + '$(CHECK_FLAGS)', $$config{'check_src'}); + + add_to($config, { + 'lib_objs' => $lib_objs, + 'check_objs' => $check_objs, + 'lib_build_cmds' => $lib_build_cmds, + 'check_build_cmds' => $check_build_cmds, + + 'doc_files' => $docs, + 'include_files' => $includes + }); + + my $template_dir = File::Spec->catdir($$config{'config-dir'}, 'makefile'); + my $template = undef; + + my $make_style = $$config{'make_style'}; + + if($make_style eq 'unix') { + $template = File::Spec->catfile($template_dir, 'unix.in'); + + $template = File::Spec->catfile($template_dir, 'unix_shr.in') + if($$config{'shared'} eq 'yes'); + + add_to($config, { + 'link_to' => libs('-l', '', 'm', @{$$config{'mod_libs'}}), + }); + } + elsif($make_style eq 'nmake') { + $template = File::Spec->catfile($template_dir, 'nmake.in'); + + add_to($config, { + 'shared' => 'no', + 'link_to' => libs('', '', '', @{$$config{'mod_libs'}}), + }); + } + + croak("Don't know about makefile format '$make_style'") + unless defined $template; + + trace("'$make_style' -> '$template'"); + + process_template($template, $$config{'makefile'}, $config); + + autoconfig("Wrote ${make_style}-style makefile in $$config{'makefile'}"); +} + +################################################## +# Configuration Guessing # +################################################## +sub guess_cpu_from_this +{ + my $cpuinfo = lc $_[0]; + + $cpuinfo =~ s/\(r\)//g; + $cpuinfo =~ s/\(tm\)//g; + $cpuinfo =~ s/ //g; + + trace("guess_cpu_from_this($cpuinfo)"); + + # The 32-bit SPARC stuff is impossible to match to arch type easily, and + # anyway the uname stuff will pick up that it's a SPARC so it doesn't + # matter. If it's an Ultra, assume a 32-bit userspace, no 64-bit code + # possible; that's the most common setup right now anyway + return 'sparc32-v9' if($cpuinfo =~ /ultrasparc/); + + # Should probably do this once and cache it + my @names; + my %all_alias; + + foreach my $arch (keys %CPU) { + my %info = %{$CPU{$arch}}; + + foreach my $submodel (@{$info{'submodels'}}) { + push @names, $submodel; + } + + if(defined($info{'submodel_aliases'})) { + my %submodel_aliases = %{$info{'submodel_aliases'}}; + foreach my $sm_alias (keys %submodel_aliases) { + push @names, $sm_alias; + $all_alias{$sm_alias} = $submodel_aliases{$sm_alias}; + } + } + } + + @names = sort { length($b) <=> length($a) } @names; + + foreach my $name (@names) { + if($cpuinfo =~ $name) { + trace("Matched '$cpuinfo' against '$name'"); + + return $all_alias{$name} if defined($all_alias{$name}); + + return $name; + } + } + + trace("Couldn't match $cpuinfo against any submodels"); + + # No match? Try arch names. Reset @names + @names = (); + + foreach my $arch (keys %CPU) { + my %info = %{$CPU{$arch}}; + + push @names, $info{'name'}; + + foreach my $alias (@{$info{'aliases'}}) { + push @names, $alias; + } + } + + @names = sort { length($b) <=> length($a) } @names; + + foreach my $name (@names) { + if($cpuinfo =~ $name) { + trace("Matched '$cpuinfo' against '$name'"); + return $name; + } + } + + return ''; +} + +# Do some WAGing and see if we can figure out what system we are. Think about +# this as a really moronic config.guess +sub guess_compiler +{ + my @CCS = ('gcc', 'msvc', 'icc', 'compaq', 'kai'); + + # First try the CC enviornmental variable, if it's set + if(defined($ENV{CC})) + { + my @new_CCS = ($ENV{CC}); + foreach my $cc (@CCS) { push @new_CCS, $cc; } + @CCS = @new_CCS; + } + + foreach (@CCS) + { + my $bin_name = $COMPILER{$_}{'binary_name'}; + if(which($bin_name) ne '') { + autoconfig("Guessing to use $_ as the compiler " . + "(use --cc to set)"); + return $_; + } + } + + croak( + "Can't find a usable C++ compiler, is PATH right?\n" . + "You might need to run with the --cc option (try $0 --help)\n"); +} + +sub guess_os +{ + sub recognize_os + { + my $os = os_alias($_[0]); + if(defined($OPERATING_SYSTEM{$os})) { + autoconfig("Guessing operating system is $os (use --os to set)"); + return $os; + } + return undef; + } + + my $guess = recognize_os($^O); + return $guess if $guess; + + trace("Can't guess os from $^O"); + + my $uname = $$config{'uname'}; + + if($uname ne '') { + $guess = recognize_os($uname); + return $guess if $guess; + trace("Can't guess os from $uname"); + } + + warning("Unknown OS ('$^O', '$uname'), falling back to generic code"); + return 'generic'; +} + +sub guess_cpu +{ + # If we have /proc/cpuinfo, try to get nice specific information about + # what kind of CPU we're running on. + my $cpuinfo = '/proc/cpuinfo'; + + if(defined($ENV{'CPUINFO'})) { + my $cpuinfo_env = $ENV{'CPUINFO'}; + + if(-e $cpuinfo_env and -r $cpuinfo_env) { + autoconfig("Will use $cpuinfo_env as /proc/cpuinfo"); + $cpuinfo = $cpuinfo_env; + } else { + warn("Could not read from ENV /proc/cpuinfo ($cpuinfo_env)"); + } + } + + if(-e $cpuinfo and -r $cpuinfo) + { + open CPUINFO, $cpuinfo or die "Could not read $cpuinfo\n"; + + while() { + + chomp; + $_ =~ s/\t/ /g; + $_ =~ s/ +/ /g; + + if($_ =~ /^cpu +: (.*)/ or + $_ =~ /^model name +: (.*)/) + { + my $cpu = guess_cpu_from_this($1); + if($cpu ne '') { + autoconfig("Guessing CPU using $cpuinfo line '$_'"); + autoconfig("Guessing CPU is a $cpu (use --cpu to set)"); + return $cpu; + } + } + } + + autoconfig("*** Could not figure out CPU based on $cpuinfo"); + autoconfig("*** Please mail contents to lloyd\@randombit.net"); + } + + sub known_arch { + my ($name) = @_; + + foreach my $arch (keys %CPU) { + my %info = %{$CPU{$arch}}; + + return 1 if $name eq $info{'name'}; + foreach my $submodel (@{$info{'submodels'}}) { + return 1 if $name eq $submodel; + } + + foreach my $alias (@{$info{'aliases'}}) { + return 1 if $name eq $alias; + } + + if(defined($info{'submodel_aliases'})) { + my %submodel_aliases = %{$info{'submodel_aliases'}}; + foreach my $sm_alias (keys %submodel_aliases) { + return 1 if $name eq $sm_alias; + } + } + } + + my $guess = guess_cpu_from_this($name); + + return 0 if($guess eq $name or $guess eq ''); + + return known_arch($guess); + } + + my $uname = $$config{'uname'}; + if($uname ne '') { + my $cpu = guess_cpu_from_this($uname); + + if($cpu ne '') + { + autoconfig("Guessing CPU using uname output '$uname'"); + autoconfig("Guessing CPU is a $cpu (use --cpu to set)"); + + return $cpu if known_arch($cpu); + } + } + + my $config_archname = $Config{'archname'}; + my $cpu = guess_cpu_from_this($config_archname); + + if($cpu ne '') + { + autoconfig("Guessing CPU using Config{archname} '$config_archname'"); + autoconfig("Guessing CPU is a $cpu (use --cpu to set)"); + + return $cpu if known_arch($cpu); + } + + warning("Could not determine CPU type (try --cpu option)"); + return 'generic'; +} -- cgit v1.2.3