use 5.10.0;
use strict;
use Config;
use FindBin;
use lib "$FindBin::Bin/util/perl";
use File::Basename;
use File::Spec::Functions qw/:DEFAULT abs2rel rel2abs splitdir/;
use File::Path qw/mkpath/;
use OpenSSL::fallback "$FindBin::Bin/external/perl/MODULES.txt";
use OpenSSL::Glob;
use OpenSSL::Template;
use OpenSSL::config;
my $orig_death_handler = $SIG{__DIE__};
$SIG{__DIE__} = \&death_handler;
my $usage="Usage: Configure [no-<feature> ...] [enable-<feature> ...] [-Dxxx] [-lxxx] [-Lxxx] [-fxxx] [-Kxxx] [no-hw-xxx|no-hw] [[no-]threads] [[no-]thread-pool] [[no-]default-thread-pool] [[no-]shared] [[no-]zlib|zlib-dynamic] [no-asm] [no-egd] [sctp] [386] [--prefix=DIR] [--openssldir=OPENSSLDIR] [--with-xxx[=vvv]] [--config=FILE] os/compiler[:flags]\n";
my $banner = <<"EOF";
**********************************************************************
*** ***
*** OpenSSL has been successfully configured ***
*** ***
*** If you encounter a problem while building, please open an ***
*** issue on GitHub <https://github.com/openssl/openssl/issues> ***
*** and include the output from the following command: ***
*** ***
*** perl configdata.pm --dump ***
*** ***
*** (If you are new to OpenSSL, you might want to consult the ***
*** 'Troubleshooting' section in the INSTALL.md file first) ***
*** ***
**********************************************************************
EOF
my @gcc_devteam_warn = qw(
-DPEDANTIC -pedantic -Wno-long-long -DUNUSEDRESULT_DEBUG
-Wall
-Wmissing-declarations
-Wextra
-Wno-unused-parameter
-Wno-missing-field-initializers
-Wno-unterminated-string-initialization
-Wswitch
-Wsign-compare
-Wshadow
-Wformat
-Wno-type-limits
-Wundef
-Werror
-Wmissing-prototypes
-Wstrict-prototypes
);
my @clang_devteam_warn = qw(
-Wno-unknown-warning-option
-Wno-parentheses-equality
-Wno-language-extension-token
-Wno-extended-offsetof
-Wno-missing-braces
-Wno-tautological-constant-out-of-range-compare
-Wconditional-uninitialized
-Wincompatible-pointer-types-discards-qualifiers
-Wmissing-variable-declarations
);
my @cl_devteam_warn = qw(
/WX
);
my $strict_warnings = 0;
our $BSDthreads="-pthread -D_THREAD_SAFE -D_REENTRANT";
my $apitable = {
"3.0.0" => 30000,
"3.0" => 30000,
"1.1.1" => 10101,
"1.1.0" => 10100,
"1.0.2" => 10002,
"1.0.1" => 10001,
"1.0.0" => 10000,
"0.9.8" => 908,
};
my %guess_opts = ();
my $dryrun = 0;
our %table = ();
our %config = ();
our %withargs = ();
our $now_printing;
sub read_config;
sub resolve_config;
my $srcdir = catdir(absolutedir(dirname($0))); my $blddir = catdir(absolutedir("."));
$srcdir = $blddir
if (grep(/::Unix$/, @File::Spec::ISA)
&& samedir($srcdir, $blddir));
my $dofile = abs2rel(catfile($srcdir, "util/dofile.pl"));
my $local_config_envname = 'OPENSSL_LOCAL_CONFIG_DIR';
$config{sourcedir} = abs2rel($srcdir, $blddir);
$config{builddir} = abs2rel($blddir, $blddir);
$config{FIPSKEY} =
'f4556650ac31d35461610bac4ed81b1a181b2d8a43ea2854cbae22ca74560813';
my @argvcopy=@ARGV;
if (grep /^reconf(igure)?$/, @argvcopy) {
die "reconfiguring with other arguments present isn't supported"
if scalar @argvcopy > 1;
if (-f "./configdata.pm") {
my $file = "./configdata.pm";
unless (my $return = do $file) {
die "couldn't parse $file: $@" if $@;
die "couldn't do $file: $!" unless defined $return;
die "couldn't run $file" unless $return;
}
@argvcopy = defined($configdata::config{perlargv}) ?
@{$configdata::config{perlargv}} : ();
die "Incorrect data to reconfigure, please do a normal configuration\n"
if (grep(/^reconf/,@argvcopy));
$config{perlenv} = $configdata::config{perlenv} // {};
} else {
die "Insufficient data to reconfigure, please do a normal configuration\n";
}
}
$config{perlargv} = [ @argvcopy ];
foreach ( reverse sort( 'aes', 'aria', 'bf', 'camellia', 'cast', 'des', 'dh',
'dsa', 'ec', 'hmac', 'idea', 'md2', 'md5', 'mdc2',
'rc2', 'rc4', 'rc5', 'ripemd', 'seed', 'sha',
'sm2', 'sm3', 'sm4') ) {
unshift @argvcopy, "no-$_" if ! -d catdir($srcdir, 'crypto', $_);
}
my %version = ();
collect_information(
collect_from_file(catfile($srcdir,'VERSION.dat')),
qr/\s*(\w+)\s*=\s*(.*?)\s*$/ =>
sub {
if ($2 ne '') {
my $k = $1;
my $v = $2;
$v = $1 if $v =~ /^"(.*)"$/;
$version{uc $k} = $v;
}
},
"OTHERWISE" =>
sub { die "Something wrong with this line:\n$_\nin $srcdir/VERSION.dat" },
);
$config{major} = $version{MAJOR} // 'unknown';
$config{minor} = $version{MINOR} // 'unknown';
$config{patch} = $version{PATCH} // 'unknown';
$config{prerelease} =
defined $version{PRE_RELEASE_TAG} ? "-$version{PRE_RELEASE_TAG}" : '';
$config{build_metadata} =
defined $version{BUILD_METADATA} ? "+$version{BUILD_METADATA}" : '';
$config{shlib_version} = $version{SHLIB_VERSION} // 'unknown';
$config{release_date} = $version{RELEASE_DATE} // 'xx XXX xxxx';
$config{version} = "$config{major}.$config{minor}.$config{patch}";
$config{full_version} = "$config{version}$config{prerelease}$config{build_metadata}";
die "erroneous version information in VERSION.dat: ",
"$config{version}, $config{shlib_version}\n"
unless (defined $version{MAJOR}
&& defined $version{MINOR}
&& defined $version{PATCH}
&& defined $version{SHLIB_VERSION});
my $pattern = catfile(dirname($0), "Configurations", "*.conf");
foreach (sort glob($pattern)) {
&read_config($_);
}
if (defined env($local_config_envname)) {
if ($^O eq 'VMS') {
$pattern = $local_config_envname . ':' . '*.conf';
} else {
$pattern = catfile(env($local_config_envname), '*.conf');
}
foreach (sort glob($pattern)) {
&read_config($_);
}
}
if (!%table) {
print "Failed to find any os/compiler configurations. Please make sure the Configurations directory is included.\n";
&usage;
}
$config{perl_cmd} = $^X;
$config{perl_version} = $Config{version};
$config{perl_archname} = $Config{archname};
$config{prefix}="";
$config{openssldir}="";
$config{processor}="";
$config{libdir}="";
my $auto_threads=1; my $default_ranlib;
my @tls = qw(ssl3 tls1 tls1_1 tls1_2 tls1_3);
my @dtls = qw(dtls1 dtls1_2);
my @disablables = (
"acvp-tests",
"afalgeng",
"apps",
"argon2",
"aria",
"asan",
"asm",
"async",
"atexit",
"autoalginit",
"autoerrinit",
"autoload-config",
"bf",
"blake2",
"brotli",
"brotli-dynamic",
"buildtest-c++",
"bulk",
"cached-fetch",
"camellia",
"capieng",
"winstore",
"cast",
"chacha",
"cmac",
"cmp",
"cms",
"comp",
"crypto-mdebug",
"ct",
"default-thread-pool",
"demos",
"h3demo",
"hqinterop",
"deprecated",
"des",
"devcryptoeng",
"dgram",
"dh",
"docs",
"dsa",
"dso",
"dtls",
"dynamic-engine",
"ec",
"ec2m",
"ec_nistp_64_gcc_128",
"ecdh",
"ecdsa",
"ecx",
"egd",
"engine",
"err",
"external-tests",
"filenames",
"fips",
"fips-securitychecks",
"fips-post",
"fips-jitter",
"fuzz-afl",
"fuzz-libfuzzer",
"gost",
"http",
"idea",
"integrity-only-ciphers",
"jitter",
"ktls",
"legacy",
"loadereng",
"makedepend",
"md2",
"md4",
"mdc2",
"ml-dsa",
"ml-kem",
"module",
"msan",
"multiblock",
"nextprotoneg",
"ocb",
"ocsp",
"padlockeng",
"pic",
"pie",
"pinshared",
"poly1305",
"posix-io",
"psk",
"quic",
"unstable-qlog",
"rc2",
"rc4",
"rc5",
"rdrand",
"rfc3779",
"rmd160",
"scrypt",
"sctp",
"secure-memory",
"seed",
"shared",
"siphash",
"siv",
"slh-dsa",
"sm2",
"sm2-precomp",
"sm3",
"sm4",
"sock",
"srp",
"srtp",
"sse2",
"ssl",
"ssl-trace",
"static-engine",
"stdio",
"sslkeylog",
"tests",
"tfo",
"thread-pool",
"threads",
"tls",
"tls-deprecated-ec",
"trace",
"ts",
"ubsan",
"ui-console",
"unit-test",
"uplink",
"weak-ssl-ciphers",
"whirlpool",
"zlib",
"zlib-dynamic",
"zstd",
"zstd-dynamic",
);
foreach my $proto ((@tls, @dtls))
{
push(@disablables, $proto);
push(@disablables, "$proto-method") unless $proto eq "tls1_3";
}
my @disablables_int = qw(
crmf
);
my %deprecated_disablables = (
"ssl2" => undef,
"buf-freelists" => undef,
"crypto-mdebug-backtrace" => undef,
"hw" => "hw", "hw-padlock" => "padlockeng",
"ripemd" => "rmd160",
"ui" => "ui-console",
"heartbeats" => undef,
);
our %disabled = ( "fips" => "default",
"fips-jitter" => "default",
"asan" => "default",
"brotli" => "default",
"brotli-dynamic" => "default",
"buildtest-c++" => "default",
"crypto-mdebug" => "default",
"crypto-mdebug-backtrace" => "default",
"demos" => "default",
"h3demo" => "default",
"hqinterop" => "default",
"devcryptoeng" => "default",
"ec_nistp_64_gcc_128" => "default",
"egd" => "default",
"external-tests" => "default",
"fuzz-afl" => "default",
"fuzz-libfuzzer" => "default",
"pie" => "default",
"jitter" => "default",
"ktls" => "default",
"md2" => "default",
"msan" => "default",
"rc5" => "default",
"sctp" => "default",
"ssl3" => "default",
"ssl3-method" => "default",
"sslkeylog" => "default",
"tfo" => "default",
"trace" => "default",
"ubsan" => "default",
"unit-test" => "default",
"weak-ssl-ciphers" => "default",
"zlib" => "default",
"zlib-dynamic" => "default",
"zstd" => "default",
"zstd-dynamic" => "default",
);
my @disable_cascades = (
"bulk" => [ "shared", "dso",
"aria", "async", "atexit", "autoload-config",
"blake2", "bf", "camellia", "cast", "chacha",
"cmac", "cms", "cmp", "comp", "ct",
"des", "dgram", "dh", "dsa",
"ec", "engine",
"filenames",
"idea", "ktls",
"md4", "ml-dsa", "ml-kem", "multiblock",
"nextprotoneg", "ocsp", "ocb", "poly1305", "psk",
"rc2", "rc4", "rmd160",
"seed", "siphash", "siv",
"sm3", "sm4", "srp",
"srtp", "ssl3-method", "ssl-trace",
"tfo",
"ts", "ui-console", "whirlpool",
"fips-securitychecks" ],
sub { $config{processor} eq "386" }
=> [ "sse2" ],
"ssl" => [ "ssl3" ],
"ssl3-method" => [ "ssl3" ],
"zlib" => [ "zlib-dynamic" ],
"brotli" => [ "brotli-dynamic" ],
"zstd" => [ "zstd-dynamic" ],
"des" => [ "mdc2" ],
"deprecated" => [ "tls-deprecated-ec" ],
"ec" => [ qw(ec2m ecdsa ecdh sm2 gost ecx tls-deprecated-ec) ],
"dgram" => [ "dtls", "quic", "sctp" ],
"sock" => [ "dgram", "tfo" ],
"dtls" => [ @dtls ],
sub { 0 == scalar grep { !$disabled{$_} } @dtls }
=> [ "dtls" ],
"tls" => [ @tls ],
sub { 0 == scalar grep { !$disabled{$_} } @tls }
=> [ "tls" ],
"tls1_3" => [ "quic" ],
"quic" => [ "unstable-qlog" ],
"crypto-mdebug" => [ "crypto-mdebug-backtrace" ],
"module" => [ "dynamic-engine", "fips" ],
"shared" => [ "dynamic-engine", "uplink" ],
"dso" => [ "dynamic-engine", "module" ],
"pic" => [ "shared", "module" ],
"engine" => [ "dynamic-engine", grep(/eng$/, @disablables) ],
"dynamic-engine" => [ "loadereng" ],
"hw" => [ "padlockeng" ],
"autoalginit" => [ "shared", "apps", "fips" ],
"stdio" => [ "apps", "capieng", "egd" ],
"apps" => [ "tests" ],
"tests" => [ "external-tests" ],
"comp" => [ "zlib", "brotli", "zstd" ],
"sm3" => [ "sm2" ],
sub { !$disabled{"unit-test"} } => [ "heartbeats" ],
sub { !$disabled{"msan"} } => [ "asm" ],
"cmac" => [ "siv" ],
"legacy" => [ "md2" ],
"cmp" => [ "crmf" ],
"fips" => [ "fips-securitychecks", "fips-post", "acvp-tests",
"fips-jitter" ],
"threads" => [ "thread-pool" ],
"thread-pool" => [ "default-thread-pool" ],
"blake2" => [ "argon2" ],
"deprecated-3.0" => [ "engine", "srp" ],
"http" => [ "ocsp" ]
);
my @list = (reverse @tls);
while ((my $first, my $second) = (shift @list, shift @list)) {
last unless @list;
push @disable_cascades, ( sub { !$disabled{$first} && $disabled{$second} }
=> [ @list ] );
unshift @list, $second;
}
my @list = (reverse @dtls);
while ((my $first, my $second) = (shift @list, shift @list)) {
last unless @list;
push @disable_cascades, ( sub { !$disabled{$first} && $disabled{$second} }
=> [ @list ] );
unshift @list, $second;
}
my $list_separator_re =
{ VMS => qr/(?<!\^),/,
MSWin32 => qr/(?<!\\);/ } -> {$^O} // qr/(?<!\\)[:\s]/;
my %user = (
AR => env('AR'),
ARFLAGS => [],
AS => undef,
ASFLAGS => [],
CC => env('CC'),
CFLAGS => [ env('CFLAGS') || () ],
CXX => env('CXX'),
CXXFLAGS => [ env('CXXFLAGS') || () ],
CPP => undef,
CPPFLAGS => [ env('CPPFLAGS') || () ], CPPDEFINES => [], CPPINCLUDES => [], CROSS_COMPILE => env('CROSS_COMPILE'),
HASHBANGPERL=> env('HASHBANGPERL') || env('PERL'),
LD => undef,
LDFLAGS => [ env('LDFLAGS') || () ], LDLIBS => [ env('LDLIBS') || () ], MT => undef,
MTFLAGS => [],
PERL => env('PERL') || ($^O ne "VMS" ? $^X : "perl"),
RANLIB => env('RANLIB'),
RC => env('RC') || env('WINDRES'),
RCFLAGS => [ env('RCFLAGS') || () ],
OBJCOPY => undef,
RM => undef,
);
my @user_crossable = qw ( AR AS CC CXX CPP LD MT RANLIB RC );
my %useradd = (
ASFLAGS => [],
CPPDEFINES => [],
CPPINCLUDES => [],
CPPFLAGS => [],
CFLAGS => [],
CXXFLAGS => [],
LDFLAGS => [],
LDLIBS => [],
RCFLAGS => [],
);
my %user_synonyms = (
HASHBANGPERL=> 'PERL',
RC => 'WINDRES',
);
my %target_attr_translate =(
ar => 'AR',
as => 'AS',
cc => 'CC',
cxx => 'CXX',
cpp => 'CPP',
hashbangperl => 'HASHBANGPERL',
ld => 'LD',
mt => 'MT',
ranlib => 'RANLIB',
rc => 'RC',
rm => 'RM',
);
$config{defines} = [ split(/$list_separator_re/, env('__CNF_CPPDEFINES')) ];
$config{includes} = [ split(/$list_separator_re/, env('__CNF_CPPINCLUDES')) ];
$config{cppflags} = [ env('__CNF_CPPFLAGS') || () ];
$config{cflags} = [ env('__CNF_CFLAGS') || () ];
$config{cxxflags} = [ env('__CNF_CXXFLAGS') || () ];
$config{lflags} = [ env('__CNF_LDFLAGS') || () ];
$config{ex_libs} = [ env('__CNF_LDLIBS') || () ];
$config{openssl_api_defines}=[];
$config{openssl_sys_defines}=[];
$config{openssl_feature_defines}=[];
$config{options}="";
$config{build_type} = "release";
my $target="";
my %cmdvars = (); my %unsupported_options = ();
my %deprecated_options = ();
my @known_seed_sources = qw(getrandom devrandom os egd none rdcpu);
my @seed_sources = ();
while (@argvcopy)
{
$_ = shift @argvcopy;
if (m|^(\w+)=(.+)?$|)
{
$cmdvars{$1} = $2;
if (exists $user{$1})
{
$user{$1} = ref $user{$1} eq "ARRAY" ? [] : undef;
}
next;
}
if ($^O eq "VMS")
{
s/^([^=]*)/lc($1)/e;
}
s/^-no-(?!integrated-as)/no-/;
s /^-?-?shared$/enable-shared/;
s /^sctp$/enable-sctp/;
s /^threads$/enable-threads/;
s /^zlib$/enable-zlib/;
s /^zlib-dynamic$/enable-zlib-dynamic/;
s /^fips$/enable-fips/;
if (/^(no|disable|enable)-(.+)$/)
{
my $word = $2;
if ($word !~ m|hw(?:-.+)| && !exists $deprecated_disablables{$word}
&& !grep { $word eq $_ } @disablables)
{
$unsupported_options{$_} = 1;
next;
}
}
if (/^no-(.+)$/ || /^disable-(.+)$/)
{
foreach my $proto ((@tls, @dtls))
{
if ($1 eq "$proto-method")
{
$disabled{"$proto"} = "option($proto-method)";
last;
}
}
if ($1 eq "dtls")
{
foreach my $proto (@dtls)
{
$disabled{$proto} = "option(dtls)";
}
$disabled{"dtls"} = "option(dtls)";
}
elsif ($1 eq "ssl")
{
$disabled{"ssl3"} = "option(ssl)";
}
elsif ($1 eq "tls")
{
foreach my $proto (@tls)
{
$disabled{$proto} = "option(tls)";
}
}
elsif ($1 eq "static-engine")
{
delete $disabled{"dynamic-engine"};
}
elsif ($1 eq "dynamic-engine")
{
$disabled{"dynamic-engine"} = "option";
}
elsif (exists $deprecated_disablables{$1})
{
$deprecated_options{$_} = 1;
if (defined $deprecated_disablables{$1})
{
$disabled{$deprecated_disablables{$1}} = "option";
}
}
elsif ($1 =~ m|hw(?:-.+)|) {
$deprecated_options{$_} = 1;
}
else
{
$disabled{$1} = "option";
}
$auto_threads = 0 if ($1 eq "threads");
}
elsif (/^enable-(.+)$/)
{
if ($1 eq "static-engine")
{
$disabled{"dynamic-engine"} = "option";
}
elsif ($1 eq "dynamic-engine")
{
delete $disabled{"dynamic-engine"};
}
elsif ($1 eq "zlib-dynamic")
{
delete $disabled{"zlib"};
}
elsif ($1 eq "brotli-dynamic")
{
delete $disabled{"brotli"};
}
elsif ($1 eq "pie")
{
delete $disabled{"pie"};
}
elsif ($1 eq "zstd-dynamic")
{
delete $disabled{"zstd"};
}
elsif ($1 eq "fips-jitter")
{
delete $disabled{"fips"};
delete $disabled{"jitter"};
}
my $algo = $1;
delete $disabled{$algo};
$auto_threads = 0 if ($1 eq "threads");
}
elsif (/^-d$/) {
$config{build_type} = "debug";
}
elsif (/^-v$/) {
$guess_opts{verbose} = 1;
}
elsif (/^-w$/)
{
$guess_opts{nowait} = 1;
}
elsif (/^-t$/) {
$dryrun = 1;
}
elsif (/^--strict-warnings$/)
{
push @{$useradd{CFLAGS}}, '--ossl-strict-warnings';
$strict_warnings=1;
}
elsif (/^--debug$/)
{
$config{build_type} = "debug";
}
elsif (/^--release$/)
{
$config{build_type} = "release";
}
elsif (/^386$/)
{ $config{processor}=386; }
elsif (/^rsaref$/)
{
}
elsif (m|^[-+/]|)
{
if (/^--prefix=(.*)$/)
{
$config{prefix}=$1;
}
elsif (/^--api=(.*)$/)
{
my $api = $1;
die "Unknown API compatibility level $api"
unless defined $apitable->{$api};
$config{api}=$apitable->{$api};
}
elsif (/^--libdir=(.*)$/)
{
$config{libdir}=$1;
}
elsif (/^--openssldir=(.*)$/)
{
$config{openssldir}=$1;
}
elsif (/^--with-jitter-include=(.*)$/)
{
$withargs{jitter_include}=$1;
}
elsif (/^--with-jitter-lib=(.*)$/)
{
$withargs{jitter_lib}=$1;
}
elsif (/^--with-zlib-lib=(.*)$/)
{
$withargs{zlib_lib}=$1;
}
elsif (/^--with-zlib-include=(.*)$/)
{
$withargs{zlib_include}=$1;
}
elsif (/^--with-brotli-lib=(.*)$/)
{
$withargs{brotli_lib}=$1;
}
elsif (/^--with-brotli-include=(.*)$/)
{
$withargs{brotli_include}=$1;
}
elsif (/^--with-zstd-lib=(.*)$/)
{
$withargs{zstd_lib}=$1;
}
elsif (/^--with-zstd-include=(.*)$/)
{
$withargs{zstd_include}=$1;
}
elsif (/^--with-fuzzer-lib=(.*)$/)
{
$withargs{fuzzer_lib}=$1;
}
elsif (/^--with-fuzzer-include=(.*)$/)
{
$withargs{fuzzer_include}=$1;
}
elsif (/^--with-rand-seed=(.*)$/)
{
foreach my $x (split(m|,|, $1))
{
die "Unknown --with-rand-seed choice $x\n"
if ! grep { $x eq $_ } @known_seed_sources;
push @seed_sources, $x;
}
}
elsif (/^--fips-key=(.*)$/)
{
$user{FIPSKEY}=lc($1);
die "Non-hex character in FIPS key\n"
if $user{FIPSKEY} =~ /[^a-f0-9]/;
die "FIPS key must have even number of characters\n"
if length $1 & 1;
die "FIPS key too long (64 bytes max)\n"
if length $1 > 64;
}
elsif (/^--banner=(.*)$/)
{
$banner = $1 . "\n";
}
elsif (/^--cross-compile-prefix=(.*)$/)
{
$user{CROSS_COMPILE}=$1;
}
elsif (/^--config=(.*)$/)
{
read_config $1;
}
elsif (/^-l(.*)$/)
{
push @{$useradd{LDLIBS}}, $_;
}
elsif (/^-framework$/)
{
push @{$useradd{LDLIBS}}, $_, shift(@argvcopy);
}
elsif (/^-L(.*)$/ or /^-Wl,/)
{
push @{$useradd{LDFLAGS}}, $_;
}
elsif (/^-rpath$/ or /^-R$/)
{
my $rpath = shift(@argvcopy) || "";
$rpath .= " " if $rpath ne "";
push @{$useradd{LDFLAGS}}, $_, $rpath;
}
elsif (/^-static$/)
{
push @{$useradd{LDFLAGS}}, $_;
}
elsif (m|^[-/]D(.*)$|)
{
push @{$useradd{CPPDEFINES}}, $1;
}
elsif (m|^[-/]I(.*)$|)
{
push @{$useradd{CPPINCLUDES}}, $1;
}
elsif (/^-Wp,$/)
{
push @{$useradd{CPPFLAGS}}, $1;
}
else {
$_ =~ s/%([0-9a-f]{1,2})/chr(hex($1))/gei;
push @{$useradd{CFLAGS}}, $_;
push @{$useradd{CXXFLAGS}}, $_;
}
}
elsif (m|^/|)
{
$_ =~ s/%([0-9a-f]{1,2})/chr(hex($1))/gei;
push @{$useradd{CFLAGS}}, $_;
push @{$useradd{CXXFLAGS}}, $_;
}
else
{
die "target already defined - $target (offending arg: $_)\n" if ($target ne "");
$target=$_;
}
unless ($_ eq $target || /^no-/ || /^disable-/)
{
if ($config{options} eq "")
{ $config{options} = $_; }
else
{ $config{options} .= " ".$_; }
}
}
if (keys %deprecated_options)
{
warn "***** Deprecated options: ",
join(", ", keys %deprecated_options), "\n";
}
if (keys %unsupported_options)
{
die "***** Unsupported options: ",
join(", ", keys %unsupported_options), "\n";
}
if (grep { scalar @$_ > 0 } values %useradd) {
my %detected_vars =
map { my $v = 0;
$v += 1 if $cmdvars{$_};
$v += 2 if @{$useradd{$_}};
$_ => $v }
keys %useradd;
if (grep { $_ & 1 } values %detected_vars) {
my $names = join(', ', grep { $detected_vars{$_} > 0 }
sort keys %detected_vars);
die <<"_____";
***** Mixing make variables and additional compiler/linker flags as
***** configure command line option is not permitted.
***** Affected make variables: $names
_____
}
}
my $anyuseradd =
grep { defined $_ && (ref $_ ne 'ARRAY' || @$_) } values %useradd;
foreach (keys %user) {
my $value = $cmdvars{$_};
$value //= env($_) unless $anyuseradd;
$value //=
defined $user_synonyms{$_} ? $cmdvars{$user_synonyms{$_}} : undef;
$value //= defined $user_synonyms{$_} ? env($user_synonyms{$_}) : undef
unless $anyuseradd;
if (defined $value) {
if (ref $user{$_} eq 'ARRAY') {
if ($_ eq 'CPPDEFINES' || $_ eq 'CPPINCLUDES') {
$user{$_} = [ split /$list_separator_re/, $value ];
} else {
$user{$_} = [ $value ];
}
} elsif (!defined $user{$_}) {
$user{$_} = $value;
}
}
}
if (grep { /-rpath\b/ } ($user{LDFLAGS} ? @{$user{LDFLAGS}} : ())
&& !$disabled{shared}
&& !($disabled{asan} && $disabled{msan} && $disabled{ubsan})) {
die "***** Cannot simultaneously use -rpath, shared libraries, and\n",
"***** any of asan, msan or ubsan\n";
}
unless ($target) {
my %system_config = OpenSSL::config::get_platform(%guess_opts, %user);
foreach ( @{$system_config{disable} // []} ) {
$disabled{$_} = 'system' unless defined $disabled{$_};
}
delete $system_config{disable};
%config = ( %config, %system_config );
$target = $system_config{target};
}
sub disable {
my $disable_type = shift;
for (@_) {
$disabled{$_} = $disable_type;
}
my @tocheckfor = (@_ ? @_ : keys %disabled);
while (@tocheckfor) {
my %new_tocheckfor = ();
my @cascade_copy = (@disable_cascades);
while (@cascade_copy) {
my ($test, $descendents) =
(shift @cascade_copy, shift @cascade_copy);
if (ref($test) eq "CODE" ? $test->() : defined($disabled{$test})) {
foreach (grep { !defined($disabled{$_}) } @$descendents) {
$new_tocheckfor{$_} = 1; $disabled{$_} = "cascade";
}
}
}
@tocheckfor = (keys %new_tocheckfor);
}
}
disable();
our $die = sub { die @_; };
if ($target eq "TABLE") {
local $die = sub { warn @_; };
foreach (sort keys %table) {
print_table_entry($_, "TABLE");
}
exit 0;
}
if ($target eq "LIST") {
foreach (sort keys %table) {
print $_,"\n" unless $table{$_}->{template};
}
exit 0;
}
if ($target eq "HASH") {
local $die = sub { warn @_; };
print "%table = (\n";
foreach (sort keys %table) {
print_table_entry($_, "HASH");
}
exit 0;
}
print "Configuring OpenSSL version $config{full_version} ";
print "for target $target\n";
if (scalar(@seed_sources) == 0) {
print "Using os-specific seed configuration\n";
push @seed_sources, 'os';
}
if (scalar(grep { $_ eq 'egd' } @seed_sources) > 0) {
delete $disabled{'egd'};
}
if (scalar(grep { $_ eq 'none' } @seed_sources) > 0) {
die "Cannot seed with none and anything else" if scalar(@seed_sources) > 1;
warn <<_____ if scalar(@seed_sources) == 1;
============================== WARNING ===============================
You have selected the --with-rand-seed=none option, which effectively
disables automatic reseeding of the OpenSSL SEED-SRC random generator.
All operations depending on the random generator such as creating keys
will not work unless the random generator is seeded manually by the
application.
Instead of manually seeding, a different random generator can be set
at runtime in openssl.cnf or configured at build time with
-DOPENSSL_DEFAULT_SEED_SRC.
Please read the 'Note on random number generation' section in the
INSTALL.md instructions and the RAND_DRBG(7) manual page for more
details.
============================== WARNING ===============================
_____
}
push @{$config{openssl_feature_defines}},
map { (my $x = $_) =~ tr|[\-a-z]|[_A-Z]|; "OPENSSL_RAND_SEED_$x" }
@seed_sources;
my $provider_string = $disabled{"fips-post"} ? "non-compliant FIPS Provider" : "FIPS Provider";
$config{FIPS_VENDOR} =
(defined $version{FIPS_VENDOR} ? "$version{FIPS_VENDOR} $provider_string for OpenSSL" : "OpenSSL $provider_string");
if ($target =~ m/^CygWin32(-.*)$/) {
$target = "Cygwin".$1;
}
my ($d, $t) = $target =~ m/^(debug-)?(.*)$/;
if ($d) {
$config{build_type} = "debug";
if (!$table{$target}) {
$target = $t;
}
}
if ($target) {
my $found;
foreach ( ( "$target-$user{CC}", "$target", undef ) ) {
$found=$_ if $table{$_} && !$table{$_}->{template};
last if $found;
}
$target = $found;
} else {
my $cc = $user{CC} // 'cc';
$target = $cc if $table{$cc} && !$table{$cc}->{template};
}
&usage unless $target;
exit 0 if $dryrun;
$config{target} = $target;
my %target = resolve_config($target);
foreach (keys %target_attr_translate) {
$target{$target_attr_translate{$_}} = $target{$_}
if $target{$_};
delete $target{$_};
}
%target = ( %{$table{DEFAULTS}}, %target );
my %conf_files = map { $_ => 1 } (@{$target{_conf_fname_int}});
$config{conf_files} = [ sort keys %conf_files ];
foreach my $feature (@{$target{disable}}) {
if (exists $deprecated_disablables{$feature}) {
warn "***** config $target disables deprecated feature $feature\n";
} elsif (!grep { $feature eq $_ } @disablables) {
die "***** config $target disables unknown feature $feature\n";
}
$disabled{$feature} = 'config';
}
foreach my $feature (@{$target{enable}}) {
if ("default" eq ($disabled{$feature} // "")) {
if (exists $deprecated_disablables{$feature}) {
warn "***** config $target enables deprecated feature $feature\n";
} elsif (!grep { $feature eq $_ } @disablables) {
die "***** config $target enables unknown feature $feature\n";
}
delete $disabled{$feature};
}
}
$disabled{uplink} = 'no uplink_arch' unless (defined $target{uplink_arch});
$disabled{asm} = 'no asm_arch' unless (defined $target{asm_arch});
disable();
$target{CXXFLAGS}//=$target{CFLAGS} if $target{CXX};
$target{cxxflags}//=$target{cflags} if $target{CXX};
$target{exe_extension}=".exe" if ($config{target} eq "DJGPP");
$target{exe_extension}=".pm" if ($config{target} =~ /vos/);
foreach (keys %user) {
my $ref_type = ref $user{$_};
my $mkvalue = sub {
my $type = shift;
my $value = shift;
my $undef_p = shift;
die "Too many arguments for \$mkvalue" if @_;
while (ref $value eq 'CODE') {
$value = $value->();
}
if ($type eq 'ARRAY') {
return undef unless defined $value;
return undef if ref $value ne 'ARRAY' && !$value;
return undef if ref $value eq 'ARRAY' && !@$value;
return [ $value ] unless ref $value eq 'ARRAY';
}
return undef unless $value;
return $value;
};
$config{$_} =
$mkvalue->($ref_type, $user{$_})
|| $mkvalue->($ref_type, $target{$_});
delete $config{$_} unless defined $config{$_};
}
foreach (keys %useradd) {
die "internal error: \$useradd{$_} isn't an ARRAY\n"
unless ref $useradd{$_} eq 'ARRAY';
if (defined $config{$_}) {
push @{$config{$_}}, @{$useradd{$_}};
} else {
$config{$_} = [ @{$useradd{$_}} ];
}
}
if ($config{prefix} && !$config{CROSS_COMPILE}) {
die "Directory given with --prefix MUST be absolute\n"
unless file_name_is_absolute($config{prefix});
}
if (grep { $_ =~ /(?:^|\s)-static(?:\s|$)/ } @{$config{LDFLAGS}}) {
disable('static', 'pic', 'threads');
}
$config{build_file} = env('BUILDFILE') || $target{build_file} || "Makefile";
$target{build_scheme} = [ $target{build_scheme} ]
if ref($target{build_scheme}) ne "ARRAY";
my ($builder, $builder_platform, @builder_opts) =
@{$target{build_scheme}};
foreach my $checker (($builder_platform."-".$config{build_file}."-checker.pm",
$builder_platform."-checker.pm")) {
my $checker_path = catfile($srcdir, "Configurations", $checker);
if (-f $checker_path) {
my $fn = $ENV{CONFIGURE_CHECKER_WARN}
? sub { warn $@; } : sub { die $@; };
if (! do $checker_path) {
if ($@) {
$fn->($@);
} elsif ($!) {
$fn->($!);
} else {
$fn->("The detected tools didn't match the platform\n");
}
}
last;
}
}
push @{$config{defines}}, "NDEBUG" if $config{build_type} eq "release";
if ($target =~ /^mingw/ && `$config{CC} --target-help 2>&1` =~ m/-mno-cygwin/m)
{
push @{$config{cflags}}, "-mno-cygwin";
push @{$config{cxxflags}}, "-mno-cygwin" if $config{CXX};
push @{$config{shared_ldflag}}, "-mno-cygwin";
}
if ($target =~ /linux.*-mips/ && !$disabled{asm}
&& !grep { $_ =~ /-m(ips|arch=)/ } (@{$config{CFLAGS}})) {
my $value;
$value = '-mips2' if ($target =~ /mips32/);
$value = '-mips3' if ($target =~ /mips64/);
unshift @{$config{cflags}}, $value;
unshift @{$config{cxxflags}}, $value if $config{CXX};
}
unless ($disabled{threads}) {
if ($auto_threads) {
if ($target{thread_scheme} eq "(unknown)") {
disable("unavailable", 'threads');
}
} else {
if ($target{thread_scheme} eq "(unknown)") {
if (!@{$config{CFLAGS}} && !@{$config{CPPDEFINES}}) {
die "You asked for multi-threading support, but didn't\n"
,"provide any system-specific compiler options\n";
}
}
}
}
my %detected_sanitizers = ();
foreach (grep /^-fsanitize=/, @{$config{CFLAGS} || []}) {
(my $checks = $_) =~ s/^-fsanitize=//;
foreach (split /,/, $checks) {
my $d = { address => 'asan',
undefined => 'ubsan',
memory => 'msan' } -> {$_};
next unless defined $d;
$detected_sanitizers{$d} = 1;
if (defined $disabled{$d}) {
die "***** Conflict between disabling $d and enabling $_ sanitizer"
if $disabled{$d} ne "default";
delete $disabled{$d};
}
}
}
unless($disabled{threads}) {
push @{$config{openssl_feature_defines}}, "OPENSSL_THREADS";
}
if ($disabled{"unstable-qlog"}) {
$disabled{"qlog"} = 1;
}
my $no_shared_warn=0;
if (($target{shared_target} // '') eq "")
{
$no_shared_warn = 1
if (!$disabled{shared} || !$disabled{"dynamic-engine"});
disable('no-shared-target', 'pic');
}
if ($disabled{"dynamic-engine"}) {
$config{dynamic_engines} = 0;
} else {
$config{dynamic_engines} = 1;
}
unless ($disabled{asan} || defined $detected_sanitizers{asan}) {
push @{$config{cflags}}, "-fsanitize=address";
}
unless ($disabled{ubsan} || defined $detected_sanitizers{ubsan}) {
push @{$config{cflags}}, "-fsanitize=undefined", "-fno-sanitize-recover=all", "-DPEDANTIC";
}
unless ($disabled{msan} || defined $detected_sanitizers{msan}) {
push @{$config{cflags}}, "-fsanitize=memory";
}
unless ($disabled{"fuzz-libfuzzer"} && $disabled{"fuzz-afl"}
&& $disabled{asan} && $disabled{ubsan} && $disabled{msan}) {
push @{$config{cflags}}, "-fno-omit-frame-pointer", "-g";
push @{$config{cxxflags}}, "-fno-omit-frame-pointer", "-g" if $config{CXX};
}
if ($disabled{pic})
{
foreach (qw(shared_cflag shared_cxxflag shared_cppflag
shared_defines shared_includes shared_ldflag
module_cflags module_cxxflags module_cppflags
module_defines module_includes module_lflags))
{
delete $config{$_};
$target{$_} = "";
}
}
else
{
push @{$config{lib_defines}}, "OPENSSL_PIC";
}
if ($target{sys_id} ne "")
{
push @{$config{openssl_sys_defines}}, "OPENSSL_SYS_$target{sys_id}";
}
my %predefined_C = compiler_predefined($config{CROSS_COMPILE}.$config{CC});
my %predefined_CXX = $config{CXX}
? compiler_predefined($config{CROSS_COMPILE}.$config{CXX})
: ();
unless ($disabled{asm}) {
if ($target eq "linux-ppc64" || $target eq "BSD-ppc64") {
$target{perlasm_scheme} = "linux64v2" if ($predefined_C{_CALL_ELF} == 2);
}
}
if (!$disabled{makedepend}) {
if ($target{makedep_scheme}) {
$config{makedep_scheme} = $target{makedep_scheme};
$config{makedepcmd} = $target{makedepcmd} if $target{makedepcmd};
} elsif (($predefined_C{__GNUC__} // -1) >= 3
&& !($predefined_C{__APPLE_CC__} && !$predefined_C{__clang__})) {
$config{makedep_scheme} = 'gcc';
} else {
$config{makedepcmd} = which('makedepend');
$config{makedep_scheme} = 'makedepend' if $config{makedepcmd};
}
disable('unavailable', 'makedepend') unless $config{makedep_scheme};
}
if (!$disabled{asm} && !$predefined_C{__MACH__} && $^O ne 'VMS' && !$predefined_C{_AIX}) {
if ($predefined_C{__clang__}) {
push @{$config{cflags}}, "-Wa,--noexecstack", "-Qunused-arguments";
} else {
my $cc = $config{CROSS_COMPILE}.$config{CC};
open(PIPE, "$cc -Wa,--help -c -o null.$$.o -x assembler /dev/null 2>&1 |");
while(<PIPE>) {
if (m/--noexecstack/) {
push @{$config{cflags}}, "-Wa,--noexecstack";
last;
}
}
close(PIPE);
unlink("null.$$.o");
}
}
$config{bn_ll} =0;
my $def_int="unsigned int";
$config{rc4_int} =$def_int;
($config{b64l},$config{b64},$config{b32})=(0,0,1);
my $count = 0;
foreach (sort split(/\s+/,$target{bn_ops})) {
$count++ if /SIXTY_FOUR_BIT|SIXTY_FOUR_BIT_LONG|THIRTY_TWO_BIT/;
$config{bn_ll}=1 if $_ eq 'BN_LLONG';
$config{rc4_int}="unsigned char" if $_ eq 'RC4_CHAR';
($config{b64l},$config{b64},$config{b32})
=(0,1,0) if $_ eq 'SIXTY_FOUR_BIT';
($config{b64l},$config{b64},$config{b32})
=(1,0,0) if $_ eq 'SIXTY_FOUR_BIT_LONG';
($config{b64l},$config{b64},$config{b32})
=(0,0,1) if $_ eq 'THIRTY_TWO_BIT';
}
die "Exactly one of SIXTY_FOUR_BIT|SIXTY_FOUR_BIT_LONG|THIRTY_TWO_BIT can be set in bn_ops\n"
if $count > 1;
$config{api} = $config{major} * 10000 + $config{minor} * 100
unless $config{api};
foreach (keys %$apitable) {
$disabled{"deprecated-$_"} = "deprecation"
if $disabled{deprecated} && $config{api} >= $apitable->{$_};
}
disable();
$config{cflags} = [ map { (my $x = $_) =~ s/([\\\"])/\\$1/g; $x }
@{$config{cflags}} ];
$config{cxxflags} = [ map { (my $x = $_) =~ s/([\\\"])/\\$1/g; $x }
@{$config{cxxflags}} ] if $config{CXX};
$config{openssl_api_defines} = [
"OPENSSL_CONFIGURED_API=".$config{api},
];
my @strict_warnings_collection=();
if ($strict_warnings)
{
my $wopt;
my $gccver = $predefined_C{__GNUC__} // -1;
if ($gccver >= 4)
{
push @strict_warnings_collection, @gcc_devteam_warn;
push @strict_warnings_collection, @clang_devteam_warn
if (defined($predefined_C{__clang__}));
}
elsif ($config{target} =~ /^VC-/)
{
push @strict_warnings_collection, @cl_devteam_warn;
}
else
{
warn "WARNING --strict-warnings requires gcc[>=4] or gcc-alike, or MSVC"
}
}
$config{CFLAGS} = [ map { $_ eq '--ossl-strict-warnings'
? @strict_warnings_collection
: ( $_ ) }
@{$config{CFLAGS}} ];
unless ($disabled{afalgeng}) {
$config{afalgeng}="";
if (grep { $_ eq 'afalgeng' } @{$target{enable}}) {
push @{$config{engdirs}}, "afalg";
} else {
disable('not-linux', 'afalgeng');
}
}
unless ($disabled{devcryptoeng}) {
if ($target =~ m/^BSD/) {
my $maxver = 5*100 + 7;
my $sysstr = `uname -s`;
my $verstr = `uname -r`;
$sysstr =~ s|\R$||;
$verstr =~ s|\R$||;
my ($ma, $mi, @rest) = split m|\.|, $verstr;
my $ver = $ma*100 + $mi;
if ($sysstr eq 'OpenBSD' && $ver >= $maxver) {
disable('too-new-kernel', 'devcryptoeng');
}
}
}
unless ($disabled{ktls}) {
$config{ktls}="";
my $cc = $config{CROSS_COMPILE}.$config{CC};
if ($target =~ m/^linux/) {
system("printf '#include <sys/types.h>\n#include <linux/tls.h>' | $cc -E - >/dev/null 2>&1");
if ($? != 0) {
disable('too-old-kernel', 'ktls');
}
} elsif ($target =~ m/^BSD/) {
system("printf '#include <sys/types.h>\n#include <sys/ktls.h>' | $cc -E - >/dev/null 2>&1");
if ($? != 0) {
disable('too-old-freebsd', 'ktls');
}
} else {
disable('not-linux-or-freebsd', 'ktls');
}
}
unless ($disabled{winstore}) {
unless ($target =~ /^(?:Cygwin|mingw|VC-|BC-)/) {
disable('not-windows', 'winstore');
}
}
push @{$config{openssl_other_defines}}, "OPENSSL_NO_KTLS" if ($disabled{ktls});
$target{module_cflags} = $target{shared_cflag} unless defined $target{module_cflags};
$target{module_cxxflags} = $target{shared_cxxflag} unless defined $target{module_cxxflags};
$target{module_ldflags} = $target{shared_ldflag} unless defined $target{module_ldflags};
{
my $shared_info_pl =
catfile(dirname($0), "Configurations", "shared-info.pl");
my %shared_info = read_eval_file($shared_info_pl);
push @{$target{_conf_fname_int}}, $shared_info_pl;
my $si = $target{shared_target};
while (ref $si ne "HASH") {
last if ! defined $si;
if (ref $si eq "CODE") {
$si = $si->();
} else {
$si = $shared_info{$si};
}
}
if (defined $si) {
$si->{module_cflags} = $si->{shared_cflag} unless defined $si->{module_cflags};
$si->{module_cxxflags} = $si->{shared_cxxflag} unless defined $si->{module_cxxflags};
$si->{module_ldflags} = $si->{shared_ldflag} unless defined $si->{module_ldflags};
foreach (sort keys %$si) {
$target{$_} = defined $target{$_}
? add($si->{$_})->($target{$_})
: $si->{$_};
}
}
}
my %skipdir = ();
my %disabled_info = (); foreach my $what (sort keys %disabled) {
next if $deprecated_disablables{$what};
next if $what =~ m|^deprecated-|;
$config{options} .= " no-$what";
if (!grep { $what eq $_ } ( 'buildtest-c++', 'fips', 'threads', 'shared',
'module', 'pic', 'dynamic-engine', 'makedepend',
'sse2', 'legacy' )) {
(my $WHAT = uc $what) =~ s|-|_|g;
my $skipdir = $what;
$skipdir = "ripemd" if $what eq "rmd160";
$skipdir = "whrlpool" if $what eq "whirlpool";
my $macro = $disabled_info{$what}->{macro} = "OPENSSL_NO_$WHAT";
push @{$config{openssl_feature_defines}}, $macro;
$skipdir{engines} = $what if $what eq 'engine';
$skipdir{"crypto/$skipdir"} = $what
unless $what eq 'async' || $what eq 'err' || $what eq 'dso' || $what eq 'http';
}
}
if ($disabled{"dynamic-engine"}) {
push @{$config{openssl_feature_defines}}, "OPENSSL_NO_DYNAMIC_ENGINE";
} else {
push @{$config{openssl_feature_defines}}, "OPENSSL_NO_STATIC_ENGINE";
}
my %unified_info = ();
my $buildinfo_debug = defined($ENV{CONFIGURE_DEBUG_BUILDINFO});
if ($builder eq "unified") {
use Text::Template 1.46;
sub cleandir {
my $base = shift;
my $dir = shift;
my $relativeto = shift || ".";
my $no_mkpath = shift // 0;
$dir = catdir($base,$dir) unless isabsolute($dir);
mkpath($dir) unless $no_mkpath;
my $res = abs2rel(absolutedir($dir), rel2abs($relativeto));
return $res;
}
sub cleanfile {
my $base = shift;
my $file = shift;
my $relativeto = shift || ".";
my $no_mkpath = shift // 0;
$file = catfile($base,$file) unless isabsolute($file);
my $d = dirname($file);
my $f = basename($file);
mkpath($d) unless $no_mkpath;
my $res = abs2rel(catfile(absolutedir($d), $f), rel2abs($relativeto));
return $res;
}
my @build_file_template_names =
( $builder_platform."-".$config{build_file}.".tmpl",
$config{build_file}.".tmpl" );
my @build_file_templates = ();
if (defined env($local_config_envname)) {
@build_file_templates =
map {
if ($^O eq 'VMS') {
$local_config_envname . ':' . $_;
} else {
catfile(env($local_config_envname), $_);
}
}
@build_file_template_names;
}
push @build_file_templates,
( map { cleanfile($srcdir, catfile("Configurations", $_), $blddir, 1) }
@build_file_template_names );
my $build_file_template;
for $_ (@build_file_templates) {
$build_file_template = $_;
last if -f $build_file_template;
$build_file_template = undef;
}
if (!defined $build_file_template) {
die "*** Couldn't find any of:\n", join("\n", @build_file_templates), "\n";
}
$config{build_file_templates}
= [ cleanfile($srcdir, catfile("Configurations", "common0.tmpl"),
$blddir, 1),
$build_file_template ];
my @build_dirs = ( [ ] );
$config{build_infos} = [ ];
my $src_configdata = cleanfile($srcdir, "configdata.pm", $blddir, 1);
my %check_exist = ();
my %check_generate = ();
my %ordinals = ();
while (@build_dirs) {
my @curd = @{shift @build_dirs};
my $sourced = catdir($srcdir, @curd);
my $buildd = catdir($blddir, @curd);
my $unixdir = join('/', @curd);
if (exists $skipdir{$unixdir}) {
my $what = $skipdir{$unixdir};
push @{$disabled_info{$what}->{skipped}}, catdir(@curd);
next;
}
mkpath($buildd);
my $f = 'build.info';
my @programs = ();
my @libraries = ();
my @modules = ();
my @scripts = ();
my %sources = ();
my %shared_sources = ();
my %includes = ();
my %defines = ();
my %depends = ();
my %generate = ();
my %imagedocs = ();
my %htmldocs = ();
my %mandocs = ();
my %variables = ();
my $variable_name_re = qr/(?P<VARIABLE>[[:alpha:]][[:alnum:]_]*)/;
my $variable_subst_re = qr/\/(?P<RE>(?:\\\/|.)*?)\/(?P<SUBST>.*?)/;
my $variable_simple_re = qr/(?<!\\)\$${variable_name_re}/;
my $variable_w_mod_re =
qr/(?<!\\)\$\{${variable_name_re}(?P<MOD>(?:\\\/|.)*?)\}/;
my $variable_re = qr/${variable_simple_re}|${variable_w_mod_re}/;
my $expand_variables = sub {
my $value = '';
my $value_rest = shift;
if ($ENV{CONFIGURE_DEBUG_VARIABLE_EXPAND}) {
print STDERR
"DEBUG[\$expand_variables] Parsed '$value_rest' ...\n"
}
while ($value_rest =~ /${variable_re}/) {
my $mod = $+{MOD};
my $variable_value = $variables{$+{VARIABLE}};
$value_rest = $';
$value .= $`;
if (defined $mod) {
if ($mod =~ /^${variable_subst_re}$/) {
my $re = $+{RE};
my $subst = $+{SUBST};
$variable_value =~ s/\Q$re\E/$subst/g;
if ($ENV{CONFIGURE_DEBUG_VARIABLE_EXPAND}) {
print STDERR
"DEBUG[\$expand_variables] ... and substituted ",
"'$re' with '$subst'\n";
}
}
}
$value .= $variable_value;
}
if ($ENV{CONFIGURE_DEBUG_VARIABLE_EXPAND}) {
print STDERR
"DEBUG[\$expand_variables] ... into: '$value$value_rest'\n";
}
return $value . $value_rest;
};
my %attributes = ();
my $handle_attributes = sub {
my $attr_str = shift;
my $ref = shift;
my @goals = @_;
return unless defined $attr_str;
my @a = tokenize($attr_str, qr|\s*,\s*|);
foreach my $a (@a) {
my $ac = 1;
my $ak = $a;
my $av = 1;
if ($a =~ m|^(!)?(.*?)\s* = \s*(.*?)$|x) {
$ac = ! $1;
$ak = $2;
$av = $3;
}
foreach my $g (@goals) {
if ($ac) {
$$ref->{$g}->{$ak} = $av;
} else {
delete $$ref->{$g}->{$ak};
}
}
}
};
my $push_to = sub {
my $valueref = shift;
my $index_str = shift; my $attrref = shift; my $attr_str = shift;
my @values = @_;
if (defined $index_str) {
my @indexes = ( '' );
if ($index_str !~ m|^\s*$|) {
@indexes = tokenize($index_str);
}
foreach (@indexes) {
push @{$valueref->{$_}}, @values;
if (defined $attrref) {
$handle_attributes->($attr_str, \$$attrref->{$_},
@values);
}
}
} else {
push @$valueref, @values;
$handle_attributes->($attr_str, $attrref, @values)
if defined $attrref;
}
};
if ($buildinfo_debug) {
print STDERR "DEBUG: Reading ",catfile($sourced, $f),"\n";
}
push @{$config{build_infos}}, catfile(abs2rel($sourced, $blddir), $f);
my $template =
Text::Template->new(TYPE => 'FILE',
SOURCE => catfile($sourced, $f),
PREPEND => qq{use lib "$FindBin::Bin/util/perl";});
die "Something went wrong with $sourced/$f: $!\n" unless $template;
my @text =
split /^/m,
$template->fill_in(HASH => { config => \%config,
target => \%target,
disabled => \%disabled,
withargs => \%withargs,
builddir => abs2rel($buildd, $blddir),
sourcedir => abs2rel($sourced, $blddir),
buildtop => abs2rel($blddir, $blddir),
sourcetop => abs2rel($srcdir, $blddir) },
DELIMITERS => [ "{-", "-}" ]);
my @skip = ();
my $index_re = qr/\[\s*(?P<INDEX>(?:\\.|.)*?)\s*\]/;
my $cond_re = qr/\[\s*(?P<COND>(?:\\.|.)*?)\s*\]/;
my $attribs_re = qr/(?:\{\s*(?P<ATTRIBS>(?:\\.|.)*?)\s*\})?/;
my $value_re = qr/(?P<VALUE>.*?)/;
collect_information(
collect_from_array([ @text ],
qr/\\$/ => sub { my $l1 = shift; my $l2 = shift;
$l1 =~ s/\\$//; $l1.$l2 }),
qr/^\s* IF ${cond_re} \s*$/x
=> sub {
if (! @skip || $skip[$#skip] > 0) {
push @skip, !! $expand_variables->($+{COND});
} else {
push @skip, -1;
}
},
qr/^\s* ELSIF ${cond_re} \s*$/x
=> sub { die "ELSIF out of scope" if ! @skip;
die "ELSIF following ELSE" if abs($skip[$#skip]) == 2;
$skip[$#skip] = -1 if $skip[$#skip] != 0;
$skip[$#skip] = !! $expand_variables->($+{COND})
if $skip[$#skip] == 0; },
qr/^\s* ELSE \s*$/x
=> sub { die "ELSE out of scope" if ! @skip;
$skip[$#skip] = -2 if $skip[$#skip] != 0;
$skip[$#skip] = 2 if $skip[$#skip] == 0; },
qr/^\s* ENDIF \s*$/x
=> sub { die "ENDIF out of scope" if ! @skip;
pop @skip; },
qr/^\s* ${variable_re} \s* = \s* ${value_re} \s* $/x
=> sub {
if (!@skip || $skip[$#skip] > 0) {
$variables{$+{VARIABLE}} = $expand_variables->($+{VALUE});
}
},
qr/^\s* SUBDIRS \s* = \s* ${value_re} \s* $/x
=> sub {
if (!@skip || $skip[$#skip] > 0) {
foreach (tokenize($expand_variables->($+{VALUE}))) {
push @build_dirs, [ @curd, splitdir($_, 1) ];
}
}
},
qr/^\s* PROGRAMS ${attribs_re} \s* = \s* ${value_re} \s* $/x
=> sub { $push_to->(\@programs, undef,
\$attributes{programs}, $+{ATTRIBS},
tokenize($expand_variables->($+{VALUE})))
if !@skip || $skip[$#skip] > 0; },
qr/^\s* LIBS ${attribs_re} \s* = \s* ${value_re} \s* $/x
=> sub { $push_to->(\@libraries, undef,
\$attributes{libraries}, $+{ATTRIBS},
tokenize($expand_variables->($+{VALUE})))
if !@skip || $skip[$#skip] > 0; },
qr/^\s* MODULES ${attribs_re} \s* = \s* ${value_re} \s* $/x
=> sub { $push_to->(\@modules, undef,
\$attributes{modules}, $+{ATTRIBS},
tokenize($expand_variables->($+{VALUE})))
if !@skip || $skip[$#skip] > 0; },
qr/^\s* SCRIPTS ${attribs_re} \s* = \s* ${value_re} \s* $/x
=> sub { $push_to->(\@scripts, undef,
\$attributes{scripts}, $+{ATTRIBS},
tokenize($expand_variables->($+{VALUE})))
if !@skip || $skip[$#skip] > 0; },
qr/^\s* IMAGEDOCS ${index_re} \s* = \s* ${value_re} \s* $/x
=> sub { $push_to->(\%imagedocs, $expand_variables->($+{INDEX}),
undef, undef,
tokenize($expand_variables->($+{VALUE})))
if !@skip || $skip[$#skip] > 0; },
qr/^\s* HTMLDOCS ${index_re} \s* = \s* ${value_re} \s* $/x
=> sub { $push_to->(\%htmldocs, $expand_variables->($+{INDEX}),
undef, undef,
tokenize($expand_variables->($+{VALUE})))
if !@skip || $skip[$#skip] > 0; },
qr/^\s* MANDOCS ${index_re} \s* = \s* ${value_re} \s* $/x
=> sub { $push_to->(\%mandocs, $expand_variables->($+{INDEX}),
undef, undef,
tokenize($expand_variables->($+{VALUE})))
if !@skip || $skip[$#skip] > 0; },
qr/^\s* SOURCE ${index_re} ${attribs_re} \s* = \s* ${value_re} \s* $/x
=> sub { $push_to->(\%sources, $expand_variables->($+{INDEX}),
\$attributes{sources}, $+{ATTRIBS},
tokenize($expand_variables->($+{VALUE})))
if !@skip || $skip[$#skip] > 0; },
qr/^\s* SHARED_SOURCE ${index_re} ${attribs_re} \s* = \s* ${value_re} \s* $/x
=> sub { $push_to->(\%shared_sources, $expand_variables->($+{INDEX}),
\$attributes{sources}, $+{ATTRIBS},
tokenize($expand_variables->($+{VALUE})))
if !@skip || $skip[$#skip] > 0; },
qr/^\s* INCLUDE ${index_re} \s* = \s* ${value_re} \s* $/x
=> sub { $push_to->(\%includes, $expand_variables->($+{INDEX}),
undef, undef,
tokenize($expand_variables->($+{VALUE})))
if !@skip || $skip[$#skip] > 0; },
qr/^\s* DEFINE ${index_re} \s* = \s* ${value_re} \s* $/x
=> sub { $push_to->(\%defines, $expand_variables->($+{INDEX}),
undef, undef,
tokenize($expand_variables->($+{VALUE})))
if !@skip || $skip[$#skip] > 0; },
qr/^\s* DEPEND ${index_re} ${attribs_re} \s* = \s* ${value_re} \s* $/x
=> sub { $push_to->(\%depends, $expand_variables->($+{INDEX}),
\$attributes{depends}, $+{ATTRIBS},
tokenize($expand_variables->($+{VALUE})))
if !@skip || $skip[$#skip] > 0; },
qr/^\s* GENERATE ${index_re} ${attribs_re} \s* = \s* ${value_re} \s* $/x
=> sub { $push_to->(\%generate, $expand_variables->($+{INDEX}),
\$attributes{generate}, $+{ATTRIBS},
$expand_variables->($+{VALUE}))
if !@skip || $skip[$#skip] > 0; },
qr/^\s* (?:\#.*)? $/x => sub { },
"OTHERWISE" => sub { die "Something wrong with this line:\n$_\nat $sourced/$f" },
"BEFORE" => sub {
if ($buildinfo_debug) {
print STDERR "DEBUG: Parsing ",join(" ", @_),"\n";
print STDERR "DEBUG: ... before parsing, skip stack is ",join(" ", map { int($_) } @skip),"\n";
}
},
"AFTER" => sub {
if ($buildinfo_debug) {
print STDERR "DEBUG: .... after parsing, skip stack is ",join(" ", map { int($_) } @skip),"\n";
}
},
);
die "runaway IF?" if (@skip);
if (grep { defined $attributes{modules}->{$_}->{engine} } keys %attributes
and !$config{dynamic_engines}) {
die <<"EOF"
ENGINES can only be used if configured with 'dynamic-engine'.
This is usually a fault in a build.info file.
EOF
}
{
my %infos = ( programs => [ @programs ],
libraries => [ @libraries ],
modules => [ @modules ],
scripts => [ @scripts ] );
foreach my $k (keys %infos) {
foreach (@{$infos{$k}}) {
my $item = cleanfile($buildd, $_, $blddir);
$unified_info{$k}->{$item} = 1;
$unified_info{attributes}->{$k}->{$item} =
$attributes{$k}->{$_}
if defined $attributes{$k}->{$_};
}
}
}
my @doubles = ();
foreach (grep /\.a$/, keys %{$unified_info{libraries}}) {
(my $l = $_) =~ s/\.a$//;
push @doubles, $l if defined $unified_info{libraries}->{$l};
}
die "these libraries are both explicitly static and shared:\n ",
join(" ", @doubles), "\n"
if @doubles;
foreach (keys %sources) {
my $dest = $_;
my $ddest = cleanfile($buildd, $_, $blddir);
foreach (@{$sources{$dest}}) {
my $s = cleanfile($sourced, $_, $blddir, 1);
if ($s eq $src_configdata || $generate{$_} || ! -f $s) {
$s = cleanfile($buildd, $_, $blddir);
}
my $o = $_;
if ($s =~ /\.(cc|cpp|c|s|S)$/) {
push @{$check_exist{$s}}, $ddest;
$o =~ s/\.[csS]$/.o/; $o =~ s/\.(cc|cpp)$/_cc.o/; $o = cleanfile($buildd, $o, $blddir);
$unified_info{sources}->{$ddest}->{$o} = -1;
$unified_info{sources}->{$o}->{$s} = -1;
} elsif ($s =~ /\.rc$/) {
push @{$check_exist{$s}}, $ddest;
$o =~ s/\.rc$/.res/; $o = cleanfile($buildd, $o, $blddir);
$unified_info{sources}->{$ddest}->{$o} = -1;
$unified_info{sources}->{$o}->{$s} = -1;
} else {
push @{$check_exist{$s}}, $ddest;
$unified_info{sources}->{$ddest}->{$s} = 1;
}
if ($o ne $_) {
$unified_info{attributes}->{sources}->{$ddest}->{$o} =
$unified_info{attributes}->{sources}->{$o}->{$s} =
$attributes{sources}->{$dest}->{$_}
if defined $attributes{sources}->{$dest}->{$_};
} else {
$unified_info{attributes}->{sources}->{$ddest}->{$s} =
$attributes{sources}->{$dest}->{$_}
if defined $attributes{sources}->{$dest}->{$_};
}
}
}
foreach (keys %shared_sources) {
my $dest = $_;
my $ddest = cleanfile($buildd, $_, $blddir);
foreach (@{$shared_sources{$dest}}) {
my $s = cleanfile($sourced, $_, $blddir, 1);
if ($s eq $src_configdata || $generate{$_} || ! -f $s) {
$s = cleanfile($buildd, $_, $blddir);
}
my $o = $_;
if ($s =~ /\.(cc|cpp|c|s|S)$/) {
push @{$check_exist{$s}}, $ddest;
$o =~ s/\.[csS]$/.o/; $o =~ s/\.(cc|cpp)$/_cc.o/; $o = cleanfile($buildd, $o, $blddir);
$unified_info{shared_sources}->{$ddest}->{$o} = -1;
$unified_info{sources}->{$o}->{$s} = -1;
} elsif ($s =~ /\.rc$/) {
push @{$check_exist{$s}}, $ddest;
$o =~ s/\.rc$/.res/; $o = cleanfile($buildd, $o, $blddir);
$unified_info{shared_sources}->{$ddest}->{$o} = -1;
$unified_info{sources}->{$o}->{$s} = -1;
} elsif ($s =~ /\.ld$/) {
push @{$check_exist{$s}}, $ddest;
$o = cleanfile($buildd, $_, $blddir);
$unified_info{shared_sources}->{$ddest}->{$o} = 1;
} else {
die "unrecognised source file type for shared library: $s\n";
}
if ($o ne $_) {
$unified_info{attributes}->{shared_sources}->{$ddest}->{$o} =
$unified_info{attributes}->{sources}->{$o}->{$s} =
$attributes{sources}->{$dest}->{$_}
if defined $attributes{sources}->{$dest}->{$_};
} else {
$unified_info{attributes}->{shared_sources}->{$ddest}->{$o} =
$attributes{sources}->{$dest}->{$_}
if defined $attributes{sources}->{$dest}->{$_};
}
}
}
foreach (keys %generate) {
my $dest = $_;
my $ddest = cleanfile($buildd, $_, $blddir);
die "more than one generator for $dest: "
,join(" ", @{$generate{$_}}),"\n"
if scalar @{$generate{$_}} > 1;
my @generator = split /\s+/, $generate{$dest}->[0];
my $gen = $generator[0];
$generator[0] = cleanfile($sourced, $gen, $blddir, 1);
if ($generate{$gen} || ! -f $generator[0]) {
$generator[0] = cleanfile($buildd, $gen, $blddir);
}
$check_generate{$ddest}->{$generator[0]}++;
$unified_info{generate}->{$ddest} = [ @generator ];
$unified_info{attributes}->{generate}->{$ddest} =
$attributes{generate}->{$dest}->{$gen}
if defined $attributes{generate}->{$dest}->{$gen};
}
foreach (keys %depends) {
my $dest = $_;
my $ddest = $dest;
if ($dest =~ /^\|(.*)\|$/) {
$unified_info{targets}->{$1} = 1;
$ddest = $1;
} elsif ($dest eq '') {
$ddest = '';
} else {
$ddest = cleanfile($sourced, $dest, $blddir, 1);
if ($ddest eq $src_configdata || ! -f $ddest) {
$ddest = cleanfile($buildd, $dest, $blddir);
}
}
foreach my $f (@{$depends{$dest}}) {
my $i; my $i2; my $m; my $d; my $d2;
if ($unified_info{generate}->{$ddest}
&& $f =~ m/^(.*?)\|(.*)$/) {
$i = $1;
$m = $2;
$d = cleanfile($sourced, "$i/$m", $blddir, 1);
$d2 = cleanfile($buildd, "$i/$m", $blddir);
$i2 = cleandir($buildd, $i, $blddir);
$i = cleandir($sourced, $i, $blddir, 1);
} else {
$d = cleanfile($sourced, $f, $blddir, 1);
$d2 = cleanfile($buildd, $f, $blddir);
}
if ($d eq $src_configdata
|| (grep { $d2 eq $_ }
keys %{$unified_info{generate}})
|| ! -f $d) {
$d = $d2;
$i = $i2;
}
if ($i) {
$d = "$i|$m";
}
$unified_info{depends}->{$ddest}->{$d} = 1;
$unified_info{attributes}->{depends}->{$ddest}->{$d} =
$attributes{depends}->{$dest}->{$f}
if defined $attributes{depends}->{$dest}->{$f};
}
}
foreach (keys %includes) {
my $dest = $_;
my $ddest = cleanfile($sourced, $_, $blddir, 1);
if ($ddest eq $src_configdata || ! -f $ddest) {
$ddest = cleanfile($buildd, $_, $blddir);
}
foreach (@{$includes{$dest}}) {
my $is = cleandir($sourced, $_, $blddir, 1);
my $ib = cleandir($buildd, $_, $blddir);
push @{$unified_info{includes}->{$ddest}->{source}}, $is
unless grep { $_ eq $is } @{$unified_info{includes}->{$ddest}->{source}};
push @{$unified_info{includes}->{$ddest}->{build}}, $ib
unless grep { $_ eq $ib } @{$unified_info{includes}->{$ddest}->{build}};
}
}
foreach my $dest (keys %defines) {
my $ddest;
if ($dest ne "") {
$ddest = cleanfile($sourced, $dest, $blddir, 1);
if (! -f $ddest) {
$ddest = cleanfile($buildd, $dest, $blddir);
}
}
foreach my $v (@{$defines{$dest}}) {
$v =~ m|^([^=]*)(=.*)?$|;
die "0 length macro name not permitted\n" if $1 eq "";
if ($dest ne "") {
die "$1 defined more than once\n"
if defined $unified_info{defines}->{$ddest}->{$1};
$unified_info{defines}->{$ddest}->{$1} = $2;
} else {
die "$1 defined more than once\n"
if grep { $v eq $_ } @{$config{defines}};
push @{$config{defines}}, $v;
}
}
}
foreach my $section (keys %imagedocs) {
foreach (@{$imagedocs{$section}}) {
my $imagedocs = cleanfile($buildd, $_, $blddir);
$unified_info{imagedocs}->{$section}->{$imagedocs} = 1;
}
}
foreach my $section (keys %htmldocs) {
foreach (@{$htmldocs{$section}}) {
my $htmldocs = cleanfile($buildd, $_, $blddir);
$unified_info{htmldocs}->{$section}->{$htmldocs} = 1;
}
}
foreach my $section (keys %mandocs) {
foreach (@{$mandocs{$section}}) {
my $mandocs = cleanfile($buildd, $_, $blddir);
$unified_info{mandocs}->{$section}->{$mandocs} = 1;
}
}
}
my $ordinals_text = join(', ', sort keys %ordinals);
warn <<"EOF" if $ordinals_text;
WARNING: ORDINALS were specified for $ordinals_text
They are ignored and should be replaced with a combination of GENERATE,
DEPEND and SHARED_SOURCE.
EOF
my $ambiguous_generation = 0;
foreach (sort keys %check_generate) {
my @generators = sort keys %{$check_generate{$_}};
my $generators_txt = join(', ', @generators);
if (scalar @generators > 1) {
warn "$_ is GENERATEd by more than one generator ($generators_txt)\n";
$ambiguous_generation++;
}
if ($check_generate{$_}->{$generators[0]} > 1) {
warn "INFO: $_ has more than one GENERATE declaration (same generator)\n"
}
}
die "There are ambiguous source file generations\n"
if $ambiguous_generation > 0;
my $missing = 0;
foreach my $orig (sort keys %check_exist) {
foreach my $dest (@{$check_exist{$orig}}) {
if ($orig ne $src_configdata) {
if ($orig =~ /\.a$/) {
unless (grep { $_ eq $orig }
keys %{$unified_info{libraries}}) {
warn "$orig is given as source for $dest, but no such library is built\n";
$missing++;
}
} else {
my $gen = $orig;
while (my @next = keys %{$check_generate{$gen}}) {
$gen = $next[0];
}
if (! -f $gen) {
if ($gen ne $orig) {
$missing++;
warn "$orig is given as source for $dest, but its generator (leading to $gen) is missing\n";
} else {
$missing++;
warn "$orig is given as source for $dest, but is missing\n";
}
}
}
}
}
}
die "There are files missing\n" if $missing > 0;
{
my $err = 0;
foreach my $prod (keys %{$unified_info{libraries}}) {
my @prod_sources =
map { keys %{$unified_info{sources}->{$_}} }
keys %{$unified_info{sources}->{$prod}};
my %srccnt = ();
foreach my $src (@prod_sources) {
$srccnt{basename $src}++;
}
foreach my $src (keys %srccnt) {
if ((my $cnt = $srccnt{$src}) > 1) {
print STDERR "$src appears $cnt times for the product $prod\n";
$err++
}
}
}
die if $err > 0;
}
foreach my $dest (keys %{$unified_info{depends}}) {
next if $dest eq "";
foreach my $d (keys %{$unified_info{depends}->{$dest}}) {
next unless $d =~ /\.(h|pm)$/;
my $i = $d =~ m/\|/ ? $` : dirname($d);
my $spot =
$d eq "configdata.pm" || defined($unified_info{generate}->{$d})
? 'build' : 'source';
push @{$unified_info{includes}->{$dest}->{$spot}}, $i
unless grep { $_ eq $i } @{$unified_info{includes}->{$dest}->{$spot}};
}
}
{
my %unified_copy = ();
foreach (('sources', 'shared_sources')) {
$unified_copy{$_} = { %{$unified_info{$_}} }
if defined($unified_info{$_});
delete $unified_info{$_};
}
foreach my $prodtype (('programs', 'libraries', 'modules', 'scripts')) {
my $intent = {
programs => { bin => { src => [ 'sources' ],
dst => 'sources' } },
libraries => { lib => { src => [ 'sources' ],
dst => 'sources' },
shlib => { prodselect =>
sub { grep !/\.a$/, @_ },
src => [ 'sources',
'shared_sources' ],
dst => 'shared_sources' } },
modules => { dso => { src => [ 'sources' ],
dst => 'sources' } },
scripts => { script => { src => [ 'sources' ],
dst => 'sources' } }
} -> {$prodtype};
foreach my $kind (keys %$intent) {
next if ($intent->{$kind}->{dst} eq 'shared_sources'
&& $disabled{shared});
my @src = @{$intent->{$kind}->{src}};
my $dst = $intent->{$kind}->{dst};
my $prodselect = $intent->{$kind}->{prodselect} // sub { @_ };
foreach my $prod ($prodselect->(keys %{$unified_info{$prodtype}})) {
my %prod_sources =
map { $_ => [ keys %{$unified_copy{sources}->{$_}} ] }
map { keys %{$unified_copy{$_}->{$prod}} }
@src;
foreach (keys %prod_sources) {
if ($_ =~ /\.(o|res)$/) {
(my $prodname = $prod) =~ s|\.a$||;
my $newobj =
catfile(dirname($_),
basename($prodname)
. '-' . $kind
. '-' . basename($_));
$unified_info{$dst}->{$prod}->{$newobj} = 1;
foreach my $src (@{$prod_sources{$_}}) {
$unified_info{sources}->{$newobj}->{$src} = 1;
my $attrs = $unified_info{attributes}->{sources};
if (defined $attrs->{$prod}
&& defined $attrs->{$prod}->{$_}) {
$attrs->{$prod}->{$newobj} =
$attrs->{$prod}->{$_};
delete $attrs->{$prod}->{$_};
}
foreach my $objsrc (keys %{$attrs->{$_} // {}}) {
$attrs->{$newobj}->{$objsrc} =
$attrs->{$_}->{$objsrc};
delete $attrs->{$_}->{$objsrc};
}
}
foreach my $deps (keys %{$unified_info{depends}->{$_}}) {
$unified_info{depends}->{$_}->{$deps} = -1;
$unified_info{depends}->{$newobj}->{$deps} = 1;
}
foreach my $k (('source', 'build')) {
next unless
defined($unified_info{includes}->{$_}->{$k});
my @incs = @{$unified_info{includes}->{$_}->{$k}};
$unified_info{includes}->{$newobj}->{$k} = [ @incs ];
}
} else {
$unified_info{$dst}->{$prod}->{$_} = 1;
}
}
}
}
}
}
foreach (("programs", "libraries", "modules", "scripts", "targets")) {
$unified_info{$_} = [ sort keys %{$unified_info{$_}} ];
}
foreach my $l1 (("sources", "shared_sources", "ldadd", "depends",
"imagedocs", "htmldocs", "mandocs")) {
foreach my $l2 (sort keys %{$unified_info{$l1}}) {
my @items =
sort
grep { $unified_info{$l1}->{$l2}->{$_} > 0 }
keys %{$unified_info{$l1}->{$l2}};
if (@items) {
$unified_info{$l1}->{$l2} = [ @items ];
} else {
delete $unified_info{$l1}->{$l2};
}
}
}
foreach my $dest (sort keys %{$unified_info{defines}}) {
$unified_info{defines}->{$dest}
= [ map { $_.$unified_info{defines}->{$dest}->{$_} }
sort keys %{$unified_info{defines}->{$dest}} ];
}
foreach my $dest (sort keys %{$unified_info{includes}}) {
if (defined($unified_info{includes}->{$dest}->{build})) {
my @source_includes = ();
@source_includes = ( @{$unified_info{includes}->{$dest}->{source}} )
if defined($unified_info{includes}->{$dest}->{source});
$unified_info{includes}->{$dest} =
[ @{$unified_info{includes}->{$dest}->{build}} ];
foreach my $inc (@source_includes) {
push @{$unified_info{includes}->{$dest}}, $inc
unless grep { $_ eq $inc } @{$unified_info{includes}->{$dest}};
}
} elsif (defined($unified_info{includes}->{$dest}->{source})) {
$unified_info{includes}->{$dest} =
[ @{$unified_info{includes}->{$dest}->{source}} ];
} else {
delete $unified_info{includes}->{$dest};
}
}
my %loopinfo = ( "lib" => [ @{$unified_info{libraries}} ],
"dso" => [ @{$unified_info{modules}} ],
"bin" => [ @{$unified_info{programs}} ],
"script" => [ @{$unified_info{scripts}} ],
"docs" => [ (map { @{$unified_info{imagedocs}->{$_} // []} }
keys %{$unified_info{imagedocs} // {}}),
(map { @{$unified_info{htmldocs}->{$_} // []} }
keys %{$unified_info{htmldocs} // {}}),
(map { @{$unified_info{mandocs}->{$_} // []} }
keys %{$unified_info{mandocs} // {}}) ] );
foreach my $type (sort keys %loopinfo) {
foreach my $product (@{$loopinfo{$type}}) {
my %dirs = ();
my $pd = dirname($product);
foreach (@{$unified_info{sources}->{$product} // []},
@{$unified_info{shared_sources}->{$product} // []}) {
my $d = dirname($_);
next if ($config{sourcedir} ne $config{builddir}
&& $d =~ m|^\Q$config{sourcedir}\E|);
next if $d eq "test" || $d eq ".";
$dirs{$d} = 1;
push @{$unified_info{dirinfo}->{$d}->{deps}}, $_
if $d ne $pd;
}
foreach (sort keys %dirs) {
push @{$unified_info{dirinfo}->{$_}->{products}->{$type}},
$product;
}
}
}
}
foreach (grep /_(asm|aux)_src$/, keys %target) {
my $src = $_;
(my $obj = $_) =~ s/_(asm|aux)_src$/_obj/;
$target{$obj} = $target{$src};
$target{$obj} =~ s/\.[csS]\b/.o/g; $target{$obj} =~ s/\.(cc|cpp)\b/_cc.o/g; }
my %template_vars = (
config => \%config,
target => \%target,
disablables => \@disablables,
disablables_int => \@disablables_int,
disabled => \%disabled,
withargs => \%withargs,
unified_info => \%unified_info,
tls => \@tls,
dtls => \@dtls,
makevars => [ sort keys %user ],
disabled_info => \%disabled_info,
user_crossable => \@user_crossable,
);
my $configdata_outname = 'configdata.pm';
open CONFIGDATA, ">$configdata_outname.new"
or die "Trying to create $configdata_outname.new: $!";
my $configdata_tmplname = cleanfile($srcdir, "configdata.pm.in", $blddir, 1);
my $configdata_tmpl =
OpenSSL::Template->new(TYPE => 'FILE', SOURCE => $configdata_tmplname);
$configdata_tmpl->fill_in(
FILENAME => $configdata_tmplname,
OUTPUT => \*CONFIGDATA,
HASH => { %template_vars,
autowarntext => [
'WARNING: do not edit!',
"Generated by Configure from $configdata_tmplname",
] }
) or die $Text::Template::ERROR;
close CONFIGDATA;
rename "$configdata_outname.new", $configdata_outname;
if ($builder_platform eq 'unix') {
my $mode = (0755 & ~umask);
chmod $mode, 'configdata.pm'
or warn sprintf("WARNING: Couldn't change mode for 'configdata.pm' to 0%03o: %s\n",$mode,$!);
}
print "Created $configdata_outname\n";
print "Running $configdata_outname\n";
my $perlcmd = (quotify("maybeshell", $config{PERL}))[0];
my $cmd = "$perlcmd $configdata_outname";
system($cmd);
exit 1 if $? != 0;
$SIG{__DIE__} = $orig_death_handler;
print <<"EOF" if ($disabled{threads} eq "unavailable");
The library could not be configured for supporting multi-threaded
applications as the compiler options required on this system are not known.
See file INSTALL.md for details if you need multi-threading.
EOF
print <<"EOF" if ($no_shared_warn);
The options 'shared', 'pic' and 'dynamic-engine' aren't supported on this
platform, so we will pretend you gave the option 'no-pic', which also disables
'shared' and 'dynamic-engine'. If you know how to implement shared libraries
or position independent code, please let us know (but please first make sure
you have tried with a current version of OpenSSL).
EOF
print $banner;
exit(0);
sub death_handler {
die @_ if $^S; my $build_file = $config{build_file} // "build file";
my @message = ( <<"_____", @_ );
Failure! $build_file wasn't produced.
Please read INSTALL.md and associated NOTES-* files. You may also have to
look over your available compiler tool chain or change your configuration.
_____
$SIG{__DIE__} = $orig_death_handler;
die @message;
}
sub picker {
my %opts = @_;
return sub { add($opts{default} || (),
$opts{$config{build_type}} || ())->(); }
}
sub combine {
my @stuff = @_;
return sub { add(@stuff)->(); }
}
sub threads {
my @flags = @_;
return sub { add($disabled{threads} ? () : @flags)->(); }
}
sub shared {
my @flags = @_;
return sub { add($disabled{shared} ? () : @flags)->(); }
}
our $add_called = 0;
sub _add {
my $separator = shift;
my $found_array = !defined($separator);
my @values =
map {
my $res = $_;
while (ref($res) eq "CODE") {
$res = $res->();
}
if (defined($res)) {
if (ref($res) eq "ARRAY") {
$found_array = 1;
@$res;
} else {
$res;
}
} else {
();
}
} (@_);
$add_called = 1;
if ($found_array) {
[ @values ];
} else {
join($separator, grep { defined($_) && $_ ne "" } @values);
}
}
sub add_before {
my $separator = " ";
if (ref($_[$#_]) eq "HASH") {
my $opts = pop;
$separator = $opts->{separator};
}
my @x = @_;
sub { _add($separator, @x, @_) };
}
sub add {
my $separator = " ";
if (ref($_[$#_]) eq "HASH") {
my $opts = pop;
$separator = $opts->{separator};
}
my @x = @_;
sub { _add($separator, @_, @x) };
}
sub read_eval_file {
my $fname = shift;
my $content;
my @result;
open F, "< $fname" or die "Can't open '$fname': $!\n";
{
undef local $/;
$content = <F>;
}
close F;
{
local $@;
@result = ( eval $content );
warn $@ if $@;
}
return wantarray ? @result : $result[0];
}
sub read_config {
my $fname = shift;
my %targets;
{
local %table = ();
%targets = read_eval_file($fname);
}
my %preexisting = ();
foreach (sort keys %targets) {
$preexisting{$_} = 1 if $table{$_};
}
die <<"EOF",
The following config targets from $fname
shadow pre-existing config targets with the same name:
EOF
map { " $_\n" } sort keys %preexisting
if %preexisting;
foreach (keys %targets) {
if (ref($targets{$_}) ne "HASH") {
if (ref($targets{$_}) eq "") {
warn "Deprecated target configuration for $_, ignoring...\n";
} else {
warn "Misconfigured target configuration for $_ (should be a hash table), ignoring...\n";
}
delete $targets{$_};
} else {
$targets{$_}->{_conf_fname_int} = add([ $fname ]);
}
}
%table = (%table, %targets);
}
sub resolve_config {
my $target = shift;
my @breadcrumbs = @_;
if (grep { $_ eq $target } @breadcrumbs) {
die "inherit_from loop! target backtrace:\n "
,$target,"\n ",join("\n ", @breadcrumbs),"\n";
}
if (!defined($table{$target})) {
warn "Warning! target $target doesn't exist!\n";
return ();
}
my %combined_inheritance = ();
if ($table{$target}->{inherit_from}) {
my @inherit_from =
map { ref($_) eq "CODE" ? $_->() : $_ } @{$table{$target}->{inherit_from}};
foreach (@inherit_from) {
my %inherited_config = resolve_config($_, $target, @breadcrumbs);
delete $inherited_config{template};
foreach (keys %inherited_config) {
if (!$combined_inheritance{$_}) {
$combined_inheritance{$_} = [];
}
push @{$combined_inheritance{$_}}, $inherited_config{$_};
}
}
}
delete $table{$target}->{inherit_from};
my $default_combiner = add();
my %all_keys =
map { $_ => 1 } (keys %combined_inheritance,
keys %{$table{$target}});
sub process_values {
my $object = shift;
my $inherited = shift; my $target = shift;
my $entry = shift;
$add_called = 0;
while(ref($object) eq "CODE") {
$object = $object->(@$inherited);
}
if (!defined($object)) {
return ();
}
elsif (ref($object) eq "ARRAY") {
local $add_called; return [ map { process_values($_, $inherited, $target, $entry) }
@$object ];
} elsif (ref($object) eq "") {
return $object;
} else {
die "cannot handle reference type ",ref($object)
," found in target ",$target," -> ",$entry,"\n";
}
}
foreach my $key (sort keys %all_keys) {
my $previous = $combined_inheritance{$key};
if (!exists $table{$target}->{$key}) {
$table{$target}->{$key} = $default_combiner;
}
$table{$target}->{$key} = process_values($table{$target}->{$key},
$combined_inheritance{$key},
$target, $key);
unless(defined($table{$target}->{$key})) {
delete $table{$target}->{$key};
}
}
return %{$table{$target}};
}
sub usage
{
print STDERR $usage;
print STDERR "\npick os/compiler from:\n";
my $j=0;
my $i;
my $k=0;
foreach $i (sort keys %table)
{
next if $table{$i}->{template};
next if $i =~ /^debug/;
$k += length($i) + 1;
if ($k > 78)
{
print STDERR "\n";
$k=length($i);
}
print STDERR $i . " ";
}
foreach $i (sort keys %table)
{
next if $table{$i}->{template};
next if $i !~ /^debug/;
$k += length($i) + 1;
if ($k > 78)
{
print STDERR "\n";
$k=length($i);
}
print STDERR $i . " ";
}
exit(1);
}
sub compiler_predefined {
state %predefined;
my $cc = shift;
return () if $^O eq 'VMS';
die 'compiler_predefined called without a compiler command'
unless $cc;
if (! $predefined{$cc}) {
$predefined{$cc} = {};
open(PIPE, "$cc -dM -E -x c /dev/null 2>&1 |");
while (my $l = <PIPE>) {
$l =~ m/^#define\s+(\w+(?:\(\w+\))?)(?:\s+(.+))?/ or last;
$predefined{$cc}->{$1} = $2 // '';
}
close(PIPE);
}
return %{$predefined{$cc}};
}
sub which
{
my ($name)=@_;
if (eval { require IPC::Cmd; 1; }) {
IPC::Cmd->import();
return scalar IPC::Cmd::can_run($name);
} else {
return $name if (File::Spec->splitpath($name))[1];
foreach (File::Spec->path()) {
my $fullpath = catfile($_, "$name$target{exe_extension}");
if (-f $fullpath and -x $fullpath) {
return $fullpath;
}
}
}
}
sub env
{
my $name = shift;
my %opts = @_;
unless ($opts{cacheonly}) {
$config{perlenv}->{$name} = $ENV{$name}
if ! exists $config{perlenv}->{$name};
}
return $config{perlenv}->{$name};
}
sub print_table_entry
{
local $now_printing = shift;
my %target = resolve_config($now_printing);
my $type = shift;
return if $target{template};
my @sequence = (
"sys_id",
"cpp",
"cppflags",
"defines",
"includes",
"cc",
"cflags",
"ld",
"lflags",
"loutflag",
"ex_libs",
"bn_ops",
"enable",
"disable",
"poly1035_asm_src",
"thread_scheme",
"perlasm_scheme",
"dso_scheme",
"shared_target",
"shared_cflag",
"shared_defines",
"shared_ldflag",
"shared_rcflag",
"shared_extension",
"dso_extension",
"obj_extension",
"exe_extension",
"ranlib",
"ar",
"arflags",
"aroutflag",
"rc",
"rcflags",
"rcoutflag",
"mt",
"mtflags",
"mtinflag",
"mtoutflag",
"multilib",
"build_scheme",
);
if ($type eq "TABLE") {
print "\n";
print "*** $now_printing\n";
foreach (@sequence) {
if (ref($target{$_}) eq "ARRAY") {
printf "\$%-12s = %s\n", $_, join(" ", @{$target{$_}});
} else {
printf "\$%-12s = %s\n", $_, $target{$_};
}
}
} elsif ($type eq "HASH") {
my $largest =
length((sort { length($a) <=> length($b) } @sequence)[-1]);
print " '$now_printing' => {\n";
foreach (@sequence) {
if ($target{$_}) {
if (ref($target{$_}) eq "ARRAY") {
print " '",$_,"'"," " x ($largest - length($_))," => [ ",join(", ", map { "'$_'" } @{$target{$_}})," ],\n";
} else {
print " '",$_,"'"," " x ($largest - length($_))," => '",$target{$_},"',\n";
}
}
}
print " },\n";
}
}
sub isabsolute {
my $file = shift;
return file_name_is_absolute($file) unless $^O eq "VMS";
return file_name_is_absolute($file) if $file =~ m|[:\[]|;
return 0;
}
sub absolutedir {
my $dir = shift;
if ($^O eq "VMS") {
return rel2abs($dir);
}
if ($^O eq "MSWin32") {
return rel2abs($dir);
}
use Cwd qw/realpath/;
return realpath($dir);
}
sub samedir {
die "samedir expects two arguments\n" unless scalar @_ == 2;
my @stat0 = stat($_[0]); my @stat1 = stat($_[1]);
die "Couldn't stat $_[0]" unless @stat0;
die "Couldn't stat $_[1]" unless @stat1;
return 0 unless ($stat0[0] == $stat1[0]);
return 0 unless ($stat0[1] eq $stat1[1]);
return 1; }
sub quotify {
my %processors = (
perl => sub { my $x = shift;
$x =~ s/([\\\$\@"])/\\$1/g;
return '"'.$x.'"'; },
maybeshell => sub { my $x = shift;
(my $y = $x) =~ s/([\\\"])/\\$1/g;
if ($x ne $y || $x =~ m|\s|) {
return '"'.$y.'"';
} else {
return $x;
}
},
);
my $for = shift;
my $processor =
defined($processors{$for}) ? $processors{$for} : sub { shift; };
return map { $processor->($_); } @_;
}
sub collect_from_file {
my $filename = shift;
my $line_concat_cond_re = shift;
my $line_concat = shift;
open my $fh, $filename || die "unable to read $filename: $!\n";
return sub {
my $saved_line = "";
$_ = "";
while (<$fh>) {
s|\R$||;
if (defined $line_concat) {
$_ = $line_concat->($saved_line, $_);
$saved_line = "";
}
if (defined $line_concat_cond_re && /$line_concat_cond_re/) {
$saved_line = $_;
next;
}
return $_;
}
die "$filename ending with continuation line\n" if $_;
close $fh;
return undef;
}
}
sub collect_from_array {
my $array = shift;
my $line_concat_cond_re = shift;
my $line_concat = shift;
my @array = (@$array);
return sub {
my $saved_line = "";
$_ = "";
while (defined($_ = shift @array)) {
s|\R$||;
if (defined $line_concat) {
$_ = $line_concat->($saved_line, $_);
$saved_line = "";
}
if (defined $line_concat_cond_re && /$line_concat_cond_re/) {
$saved_line = $_;
next;
}
return $_;
}
die "input text ending with continuation line\n" if $_;
return undef;
}
}
sub collect_information {
my $lineiterator = shift;
my %collectors = @_;
while(defined($_ = $lineiterator->())) {
s|\R$||;
my $found = 0;
if ($collectors{"BEFORE"}) {
$collectors{"BEFORE"}->($_);
}
foreach my $re (keys %collectors) {
if ($re !~ /^OTHERWISE|BEFORE|AFTER$/ && /$re/) {
$collectors{$re}->($lineiterator);
$found = 1;
};
}
if ($collectors{"OTHERWISE"}) {
$collectors{"OTHERWISE"}->($lineiterator, $_)
unless $found || !defined $collectors{"OTHERWISE"};
}
if ($collectors{"AFTER"}) {
$collectors{"AFTER"}->($_);
}
}
}
sub tokenize {
my $line = my $debug_line = shift;
my $separator = shift // qr|\s+|;
my @result = ();
if ($ENV{CONFIGURE_DEBUG_TOKENIZE}) {
print STDERR "DEBUG[tokenize]: \$separator = $separator\n";
}
while ($line =~ s|^${separator}||, $line ne "") {
my $token = "";
again:
$line =~ m/^(.*?)(${separator}|"|'|$)/;
$token .= $1;
$line = $2.$';
if ($line =~ m/^"((?:[^"\\]+|\\.)*)"/) {
$token .= $1;
$line = $';
goto again;
} elsif ($line =~ m/^'([^']*)'/) {
$token .= $1;
$line = $';
goto again;
}
push @result, $token;
}
if ($ENV{CONFIGURE_DEBUG_TOKENIZE}) {
print STDERR "DEBUG[tokenize]: Parsed '$debug_line' into:\n";
print STDERR "DEBUG[tokenize]: ('", join("', '", @result), "')\n";
}
return @result;
}