Configure: allow building without things deprecated up to and including v3.0
[openssl.git] / Configure
index 9a600913c76269f9a7903c4dedd87acb22fc0de8..b762cf80d4b9af43584d1f3fe00a99fd36f4a7fc 100755 (executable)
--- a/Configure
+++ b/Configure
@@ -15,12 +15,15 @@ use Config;
 use FindBin;
 use lib "$FindBin::Bin/util/perl";
 use File::Basename;
-use File::Spec::Functions qw/:DEFAULT abs2rel rel2abs/;
+use File::Spec::Functions qw/:DEFAULT abs2rel rel2abs splitdir/;
 use File::Path qw/mkpath/;
 use OpenSSL::Glob;
 
 # see INSTALL for instructions.
 
+my $orig_death_handler = $SIG{__DIE__};
+$SIG{__DIE__} = \&death_handler;
+
 my $usage="Usage: Configure [no-<cipher> ...] [enable-<cipher> ...] [-Dxxx] [-lxxx] [-Lxxx] [-fxxx] [-Kxxx] [no-hw-xxx|no-hw] [[no-]threads] [[no-]shared] [[no-]zlib|zlib-dynamic] [no-asm] [no-dso] [no-egd] [sctp] [386] [--prefix=DIR] [--openssldir=OPENSSLDIR] [--with-xxx[=vvv]] [--config=FILE] os/compiler[:flags]\n";
 
 # Options:
@@ -40,8 +43,9 @@ my $usage="Usage: Configure [no-<cipher> ...] [enable-<cipher> ...] [-Dxxx] [-lx
 #
 # --cross-compile-prefix Add specified prefix to binutils components.
 #
-# --api         One of 0.9.8, 1.0.0 or 1.1.0.  Do not compile support for
-#               interfaces deprecated as of the specified OpenSSL version.
+# --api         One of 0.9.8, 1.0.0, 1.1.0 or 3.0.0 (or 3).  Do not compile
+#               support for interfaces deprecated as of the specified OpenSSL
+#               version.
 #
 # no-hw-xxx     do not compile support for specific crypto hardware.
 #               Generic OpenSSL-style methods relating to this support
@@ -170,8 +174,9 @@ our $BSDthreads="-pthread -D_THREAD_SAFE -D_REENTRANT";
 #
 # API compatibility name to version number mapping.
 #
-my $maxapi = "1.1.0";           # API for "no-deprecated" builds
+my $maxapi = "3.0.0";           # API for "no-deprecated" builds
 my $apitable = {
+    "3.0.0" => "0x30000000L",
     "1.1.0" => "0x10100000L",
     "1.0.0" => "0x10000000L",
     "0.9.8" => "0x00908000L",
@@ -239,28 +244,34 @@ if (grep /^reconf(igure)?$/, @argvcopy) {
 $config{perlargv} = [ @argvcopy ];
 
 # Collect version numbers
-$config{version} = "unknown";
-$config{version_num} = "unknown";
-$config{shlib_version_number} = "unknown";
-$config{shlib_version_history} = "unknown";
+$config{major} = "unknown";
+$config{minor} = "unknown";
+$config{patch} = "unknown";
+$config{prerelease} = "";
+$config{build_metadata} = "";
+$config{shlib_version} = "unknown";
 
 collect_information(
     collect_from_file(catfile($srcdir,'include/openssl/opensslv.h')),
-    qr/OPENSSL.VERSION.TEXT.*OpenSSL (\S+) / => sub { $config{version} = $1; },
-    qr/OPENSSL.VERSION.NUMBER.*(0x\S+)/             => sub { $config{version_num}=$1 },
-    qr/SHLIB_VERSION_NUMBER *"([^"]+)"/             => sub { $config{shlib_version_number}=$1 },
-    qr/SHLIB_VERSION_HISTORY *"([^"]*)"/     => sub { $config{shlib_version_history}=$1 }
+    qr/#\s+define\s+OPENSSL_VERSION_MAJOR\s+(\d+)/ =>
+        sub { $config{major} = $1; },
+    qr/#\s+define\s+OPENSSL_VERSION_MINOR\s+(\d+)/ =>
+        sub { $config{minor} = $1; },
+    qr/#\s+define\s+OPENSSL_VERSION_PATCH\s+(\d+)/ =>
+        sub { $config{patch} = $1; },
+    qr/#\s+define\s+OPENSSL_VERSION_PRE_RELEASE\s+"((?:\\.|[^"])*)"/ =>
+        sub { $config{prerelease} = $1; },
+    qr/#\s+define\s+OPENSSL_VERSION_BUILD_METADATA\s+"((?:\\.|[^"])*)"/ =>
+        sub { $config{build_metadata} = $1; },
+    qr/#\s+define\s+OPENSSL_SHLIB_VERSION\s+([\d\.]+)/ =>
+        sub { $config{shlib_version} = $1; },
     );
-if ($config{shlib_version_history} ne "") { $config{shlib_version_history} .= ":"; }
-
-($config{major}, $config{minor})
-    = ($config{version} =~ /^([0-9]+)\.([0-9\.]+)/);
-($config{shlib_major}, $config{shlib_minor})
-    = ($config{shlib_version_number} =~ /^([0-9]+)\.([0-9\.]+)/);
 die "erroneous version information in opensslv.h: ",
-    "$config{major}, $config{minor}, $config{shlib_major}, $config{shlib_minor}\n"
-    if ($config{major} eq "" || $config{minor} eq ""
-       || $config{shlib_major} eq "" ||  $config{shlib_minor} eq "");
+    "$config{major}.$config{minor}.$config{patch}, $config{shlib_version}\n"
+    if ($config{major} eq "unknown"
+            || $config{minor} eq "unknown"
+            || $config{patch} eq "unknown"
+            || $config{shlib_version} eq "unknown");
 
 # Collect target configurations
 
@@ -295,21 +306,6 @@ $config{libdir}="";
 my $auto_threads=1;    # enable threads automatically? true by default
 my $default_ranlib;
 
-# Top level directories to build
-$config{dirs} = [ "crypto", "ssl", "engines", "apps", "test", "util", "tools", "fuzz" ];
-# crypto/ subdirectories to build
-$config{sdirs} = [
-    "objects",
-    "md2", "md4", "md5", "sha", "mdc2", "hmac", "ripemd", "whrlpool", "poly1305", "blake2", "siphash", "sm3",
-    "des", "aes", "rc2", "rc4", "rc5", "idea", "aria", "bf", "cast", "camellia", "seed", "sm4", "chacha", "modes",
-    "bn", "ec", "rsa", "dsa", "dh", "sm2", "dso", "engine",
-    "buffer", "bio", "stack", "lhash", "rand", "err",
-    "evp", "asn1", "pem", "x509", "x509v3", "conf", "txt_db", "pkcs7", "pkcs12", "comp", "ocsp", "ui",
-    "cms", "ts", "srp", "cmac", "ct", "async", "kdf", "store"
-    ];
-# test/ subdirectories to build
-$config{tdirs} = [ "ossl_shim" ];
-
 # Known TLS and DTLS protocols
 my @tls = qw(ssl3 tls1 tls1_1 tls1_2 tls1_3);
 my @dtls = qw(dtls1 dtls1_2);
@@ -402,7 +398,6 @@ my @disablables = (
     "tests",
     "threads",
     "tls",
-    "tls13downgrade",
     "ts",
     "ubsan",
     "ui-console",
@@ -446,7 +441,6 @@ our %disabled = ( # "what"         => "comment"
                  "ssl3"                => "default",
                  "ssl3-method"         => "default",
                   "ubsan"              => "default",
-                 "tls13downgrade"      => "default",
                  "unit-test"           => "default",
                  "weak-ssl-ciphers"    => "default",
                  "zlib"                => "default",
@@ -553,6 +547,7 @@ my %user = (
     LDLIBS      => [],  # -l
     MT          => undef,
     MTFLAGS     => [],
+    PERL        => env('PERL') || ($^O ne "VMS" ? $^X : "perl"),
     RANLIB      => env('RANLIB'),
     RC          => env('RC') || env('WINDRES'),
     RCFLAGS     => [],
@@ -604,10 +599,8 @@ $config{lflags} = [ env('__CNF_LDFLAGS') || () ];
 $config{ex_libs} = [ env('__CNF_LDLIBS') || () ];
 
 $config{openssl_api_defines}=[];
-$config{openssl_algorithm_defines}=[];
-$config{openssl_thread_defines}=[];
 $config{openssl_sys_defines}=[];
-$config{openssl_other_defines}=[];
+$config{openssl_feature_defines}=[];
 $config{options}="";
 $config{build_type} = "release";
 my $target="";
@@ -823,11 +816,7 @@ while (@argvcopy)
                        {
                        read_config $1;
                        }
-               elsif (/^-L(.*)$/)
-                       {
-                       push @{$useradd{LDFLAGS}}, $_;
-                       }
-               elsif (/^-l(.*)$/ or /^-Wl,/)
+               elsif (/^-l(.*)$/)
                        {
                        push @{$useradd{LDLIBS}}, $_;
                        }
@@ -835,6 +824,10 @@ while (@argvcopy)
                        {
                        push @{$useradd{LDLIBS}}, $_, shift(@argvcopy);
                        }
+               elsif (/^-L(.*)$/ or /^-Wl,/)
+                       {
+                       push @{$useradd{LDFLAGS}}, $_;
+                       }
                elsif (/^-rpath$/ or /^-R$/)
                        # -rpath is the OSF1 rpath flag
                        # -R is the old Solaris rpath flag
@@ -887,21 +880,21 @@ while (@argvcopy)
                else
                        { $config{options} .= " ".$_; }
                }
+       }
 
-        if (defined($config{api}) && !exists $apitable->{$config{api}}) {
-               die "***** Unsupported api compatibility level: $config{api}\n",
-        }
+if (defined($config{api}) && !exists $apitable->{$config{api}}) {
+       die "***** Unsupported api compatibility level: $config{api}\n",
+}
 
-       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 (keys %deprecated_options)
+       {
+       warn "***** Deprecated options: ",
+               join(", ", keys %deprecated_options), "\n";
+       }
+if (keys %unsupported_options)
+       {
+       die "***** Unsupported options: ",
+               join(", ", keys %unsupported_options), "\n";
        }
 
 # If any %useradd entry has been set, we must check that the "make
@@ -954,7 +947,7 @@ foreach (keys %user) {
     }
 }
 
-if (grep { $_ =~ /(^|\s)-Wl,-rpath,/ } ($user{LDLIBS} ? @{$user{LDLIBS}} : ())
+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",
@@ -1008,10 +1001,24 @@ if (scalar(@seed_sources) == 0) {
     print "Using os-specific seed configuration\n";
     push @seed_sources, 'os';
 }
-die "Cannot seed with none and anything else"
-    if scalar(grep { $_ eq 'none' } @seed_sources) > 0
-        && scalar(@seed_sources) > 1;
-push @{$config{openssl_other_defines}},
+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 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.
+
+Please read the 'Note on random number generation' section in the
+INSTALL 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;
 
@@ -1030,11 +1037,12 @@ if ($d) {
        $target = $t;
     }
 }
+
+&usage if !$table{$target} || $table{$target}->{template};
+
 $config{target} = $target;
 my %target = resolve_config($target);
 
-&usage if (!%target || $target{template});
-
 foreach (keys %target_attr_translate) {
     $target{$target_attr_translate{$_}} = $target{$_}
         if $target{$_};
@@ -1109,17 +1117,18 @@ $target{exe_extension}="";
 $target{exe_extension}=".exe" if ($config{target} eq "DJGPP"
                                   || $config{target} =~ /^(?:Cygwin|mingw)/);
 $target{exe_extension}=".pm"  if ($config{target} =~ /vos/);
-
+$target{def_extension}=".ld";
+$target{def_extension}=".def" if $config{target} =~ /^mingw|VC-/;
+$target{def_extension}=".opt" if $config{target} =~ /^vms/;
 ($target{shared_extension_simple}=$target{shared_extension})
-    =~ s|\.\$\(SHLIB_VERSION_NUMBER\)||;
-$target{dso_extension}=$target{shared_extension_simple};
+    =~ s|\.\$\(SHLIB_VERSION_NUMBER\)||
+    unless defined($target{shared_extension_simple});
+$target{dso_extension}//=$target{shared_extension_simple};
 ($target{shared_import_extension}=$target{shared_extension_simple}.".a")
     if ($config{target} =~ /^(?:Cygwin|mingw)/);
 
-# Allow overriding the names of some tools.  USE WITH CARE
-# Note: only Unix cares about HASHBANGPERL...  that explains
-# the default string.
-$config{perl} =    ($^O ne "VMS" ? $^X : "perl");
+# Fill %config with values from %user, and in case those are undefined or
+# empty, use values from %target (acting as a default).
 foreach (keys %user) {
     my $ref_type = ref $user{$_};
 
@@ -1155,6 +1164,19 @@ foreach (keys %user) {
 # Allow overriding the build file name
 $config{build_file} = env('BUILDFILE') || $target{build_file} || "Makefile";
 
+######################################################################
+# Build up information for skipping certain directories depending on disabled
+# features, as well as setting up macros for disabled features.
+
+# This is a tentative database of directories to skip.  Some entries may not
+# correspond to anything real, but that's ok, they will simply be ignored.
+# The actual processing of these entries is done in the build.info lookup
+# loop further down.
+#
+# The key is a Unix formated path in the source tree, the value is an index
+# into %disabled_info, so any existing path gets added to a corresponding
+# 'skipped' entry in there with the list of skipped directories.
+my %skipdir = ();
 my %disabled_info = ();         # For configdata.pm
 foreach my $what (sort keys %disabled) {
     $config{options} .= " no-$what";
@@ -1163,32 +1185,18 @@ foreach my $what (sort keys %disabled) {
                                 'dynamic-engine', 'makedepend',
                                 'zlib-dynamic', 'zlib', 'sse2' )) {
         (my $WHAT = uc $what) =~ s|-|_|g;
-
-        # Fix up C macro end names
-        $WHAT = "RMD160" if $what eq "ripemd";
+        my $skipdir = $what;
 
         # fix-up crypto/directory name(s)
-        $what = "ripemd" if $what eq "rmd160";
-        $what = "whrlpool" if $what eq "whirlpool";
+        $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;
 
-        if ((grep { $what eq $_ } @{$config{sdirs}})
-                && $what ne 'async' && $what ne 'err') {
-            @{$config{sdirs}} = grep { $what ne $_} @{$config{sdirs}};
-            $disabled_info{$what}->{skipped} = [ catdir('crypto', $what) ];
-
-            if ($what ne 'engine') {
-                push @{$config{openssl_algorithm_defines}}, $macro;
-            } else {
-                @{$config{dirs}} = grep !/^engines$/, @{$config{dirs}};
-                push @{$disabled_info{engine}->{skipped}}, catdir('engines');
-                push @{$config{openssl_other_defines}}, $macro;
-            }
-        } else {
-            push @{$config{openssl_other_defines}}, $macro;
-        }
-
+        $skipdir{engines} = $what if $what eq 'engine';
+        $skipdir{"crypto/$skipdir"} = $what
+            unless $what eq 'async' || $what eq 'err';
     }
 }
 
@@ -1266,7 +1274,7 @@ unless ($disabled{threads}) {
 # If threads still aren't disabled, add a C macro to ensure the source
 # code knows about it.  Any other flag is taken care of by the configs.
 unless($disabled{threads}) {
-    push @{$config{openssl_thread_defines}}, "OPENSSL_THREADS";
+    push @{$config{openssl_feature_defines}}, "OPENSSL_THREADS";
 }
 
 # With "deprecated" disable all deprecated features.
@@ -1285,10 +1293,10 @@ if ($target{shared_target} eq "")
        }
 
 if ($disabled{"dynamic-engine"}) {
-        push @{$config{openssl_other_defines}}, "OPENSSL_NO_DYNAMIC_ENGINE";
+        push @{$config{openssl_feature_defines}}, "OPENSSL_NO_DYNAMIC_ENGINE";
         $config{dynamic_engines} = 0;
 } else {
-        push @{$config{openssl_other_defines}}, "OPENSSL_NO_STATIC_ENGINE";
+        push @{$config{openssl_feature_defines}}, "OPENSSL_NO_STATIC_ENGINE";
         $config{dynamic_engines} = 1;
 }
 
@@ -1354,6 +1362,7 @@ unless ($disabled{asm}) {
     push @{$config{lib_defines}}, "OPENSSL_BN_ASM_MONT" if ($target{bn_asm_src} =~ /-mont/);
     push @{$config{lib_defines}}, "OPENSSL_BN_ASM_MONT5" if ($target{bn_asm_src} =~ /-mont5/);
     push @{$config{lib_defines}}, "OPENSSL_BN_ASM_GF2m" if ($target{bn_asm_src} =~ /-gf2m/);
+    push @{$config{lib_defines}}, "BN_DIV3W" if ($target{bn_asm_src} =~ /-div3w/);
 
     if ($target{sha1_asm_src}) {
        push @{$config{lib_defines}}, "SHA1_ASM"   if ($target{sha1_asm_src} =~ /sx86/ || $target{sha1_asm_src} =~ /sha1/);
@@ -1430,7 +1439,7 @@ if (!$disabled{makedepend}) {
     }
 }
 
-if (!$disabled{asm}) {
+if (!$disabled{asm} && !$predefined{__MACH__} && $^O ne 'VMS') {
     # probe for -Wa,--noexecstack option...
     if ($predefined{__clang__}) {
         # clang has builtin assembler, which doesn't recognize --help,
@@ -1438,7 +1447,7 @@ if (!$disabled{asm}) {
         # supported platforms even when it's meaningless. In other words
         # probe would fail, but probed option always accepted...
         push @{$config{cflags}}, "-Wa,--noexecstack", "-Qunused-arguments";
-    } elsif ($^O ne 'VMS') {
+    } 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>) {
@@ -1558,7 +1567,7 @@ unless ($disabled{afalgeng}) {
     }
 }
 
-push @{$config{openssl_other_defines}}, "OPENSSL_NO_AFALGENG" if ($disabled{afalgeng});
+push @{$config{openssl_feature_defines}}, "OPENSSL_NO_AFALGENG" if ($disabled{afalgeng});
 
 # Finish up %config by appending things the user gave us on the command line
 # apart from "make variables"
@@ -1659,34 +1668,26 @@ if ($builder eq "unified") {
           cleanfile($srcdir, catfile("Configurations", "common.tmpl"),
                     $blddir) ];
 
-    my @build_infos = ( [ ".", "build.info" ] );
-    foreach (@{$config{dirs}}) {
-        push @build_infos, [ $_, "build.info" ]
-            if (-f catfile($srcdir, $_, "build.info"));
-    }
-    foreach (@{$config{sdirs}}) {
-        push @build_infos, [ catdir("crypto", $_), "build.info" ]
-            if (-f catfile($srcdir, "crypto", $_, "build.info"));
-    }
-    foreach (@{$config{engdirs}}) {
-        push @build_infos, [ catdir("engines", $_), "build.info" ]
-            if (-f catfile($srcdir, "engines", $_, "build.info"));
-    }
-    foreach (@{$config{tdirs}}) {
-        push @build_infos, [ catdir("test", $_), "build.info" ]
-            if (-f catfile($srcdir, "test", $_, "build.info"));
-    }
+    my @build_dirs = ( [ ] );   # current directory
 
     $config{build_infos} = [ ];
 
     my %ordinals = ();
-    foreach (@build_infos) {
-        my $sourced = catdir($srcdir, $_->[0]);
-        my $buildd = catdir($blddir, $_->[0]);
+    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 = $_->[1];
+        my $f = 'build.info';
         # The basic things we're trying to build
         my @programs = ();
         my @programs_install = ();
@@ -1704,6 +1705,7 @@ if ($builder eq "unified") {
         my %sources = ();
         my %shared_sources = ();
         my %includes = ();
+        my %defines = ();
         my %depends = ();
         my %renames = ();
         my %sharednames = ();
@@ -1764,6 +1766,14 @@ if ($builder eq "unified") {
             qr/^\s*ENDIF\s*$/
             => sub { die "ENDIF out of scope" if ! @skip;
                      pop @skip; },
+            qr/^\s*SUBDIRS\s*=\s*(.*)\s*$/
+            => sub {
+                if (!@skip || $skip[$#skip] > 0) {
+                    foreach (tokenize($1)) {
+                        push @build_dirs, [ @curd, splitdir($_, 1) ];
+                    }
+                }
+            },
             qr/^\s*PROGRAMS(_NO_INST)?\s*=\s*(.*)\s*$/
             => sub {
                 if (!@skip || $skip[$#skip] > 0) {
@@ -1819,6 +1829,9 @@ if ($builder eq "unified") {
             qr/^\s*INCLUDE\[((?:\\.|[^\\\]])+)\]\s*=\s*(.*)\s*$/
             => sub { push @{$includes{$1}}, tokenize($2)
                          if !@skip || $skip[$#skip] > 0 },
+            qr/^\s*DEFINE\[((?:\\.|[^\\\]])+)\]\s*=\s*(.*)\s*$/
+            => sub { push @{$defines{$1}}, tokenize($2)
+                         if !@skip || $skip[$#skip] > 0 },
             qr/^\s*DEPEND\[((?:\\.|[^\\\]])*)\]\s*=\s*(.*)\s*$/
             => sub { push @{$depends{$1}}, tokenize($2)
                          if !@skip || $skip[$#skip] > 0 },
@@ -2018,15 +2031,15 @@ EOF
                     $o =~ s/\.[csS]$/.o/; # C and assembler
                     $o =~ s/\.(cc|cpp)$/_cc.o/; # C++
                     $o = cleanfile($buildd, $o, $blddir);
-                    $unified_info{sources}->{$ddest}->{$o} = 1;
-                    $unified_info{sources}->{$o}->{$s} = 1;
+                    $unified_info{sources}->{$ddest}->{$o} = -1;
+                    $unified_info{sources}->{$o}->{$s} = -1;
                 } elsif ($s =~ /\.rc$/) {
                     # We also recognise resource files
                     my $o = $_;
                     $o =~ s/\.rc$/.res/; # Resource configuration
                     my $o = cleanfile($buildd, $o, $blddir);
-                    $unified_info{sources}->{$ddest}->{$o} = 1;
-                    $unified_info{sources}->{$o}->{$s} = 1;
+                    $unified_info{sources}->{$ddest}->{$o} = -1;
+                    $unified_info{sources}->{$o}->{$s} = -1;
                 } else {
                     $unified_info{sources}->{$ddest}->{$s} = 1;
                 }
@@ -2054,20 +2067,20 @@ EOF
                     $o =~ s/\.[csS]$/.o/; # C and assembler
                     $o =~ s/\.(cc|cpp)$/_cc.o/; # C++
                     $o = cleanfile($buildd, $o, $blddir);
-                    $unified_info{shared_sources}->{$ddest}->{$o} = 1;
-                    $unified_info{sources}->{$o}->{$s} = 1;
+                    $unified_info{shared_sources}->{$ddest}->{$o} = -1;
+                    $unified_info{sources}->{$o}->{$s} = -1;
                 } elsif ($s =~ /\.rc$/) {
                     # We also recognise resource files
                     my $o = $_;
                     $o =~ s/\.rc$/.res/; # Resource configuration
                     my $o = cleanfile($buildd, $o, $blddir);
-                    $unified_info{shared_sources}->{$ddest}->{$o} = 1;
-                    $unified_info{sources}->{$o}->{$s} = 1;
-                } elsif ($s =~ /\.(def|map|opt)$/) {
-                    # We also recognise .def / .map / .opt files
+                    $unified_info{shared_sources}->{$ddest}->{$o} = -1;
+                    $unified_info{sources}->{$o}->{$s} = -1;
+                } elsif ($s =~ /\.ld$/) {
+                    # We also recognise linker scripts (or corresponding)
                     # We know they are generated files
-                    my $def = cleanfile($buildd, $s, $blddir);
-                    $unified_info{shared_sources}->{$ddest}->{$def} = 1;
+                    my $ld = cleanfile($buildd, $_, $blddir);
+                    $unified_info{shared_sources}->{$ddest}->{$ld} = 1;
                 } else {
                     die "unrecognised source file type for shared library: $s\n";
                 }
@@ -2151,6 +2164,27 @@ EOF
                     unless grep { $_ eq $ib } @{$unified_info{includes}->{$ddest}->{build}};
             }
         }
+
+        foreach (keys %defines) {
+            my $dest = $_;
+            my $ddest = cleanfile($sourced, $_, $blddir);
+
+            # If the destination doesn't exist in source, it can only be
+            # a generated file in the build tree.
+            if (! -f $ddest) {
+                $ddest = cleanfile($buildd, $_, $blddir);
+                if ($unified_info{rename}->{$ddest}) {
+                    $ddest = $unified_info{rename}->{$ddest};
+                }
+            }
+            foreach (@{$defines{$dest}}) {
+                m|^([^=]*)(=.*)?$|;
+                die "0 length macro name not permitted\n" if $1 eq "";
+                die "$1 defined more than once\n"
+                    if defined $unified_info{defines}->{$ddest}->{$1};
+                $unified_info{defines}->{$ddest}->{$1} = $2;
+            }
+        }
     }
 
     my $ordinals_text = join(', ', sort keys %ordinals);
@@ -2178,25 +2212,104 @@ EOF
         }
     }
 
-    # Trickle down includes placed on libraries, engines and programs to
-    # their sources (i.e. object files)
-    foreach my $dest (keys %{$unified_info{engines}},
-                      keys %{$unified_info{libraries}},
-                      keys %{$unified_info{programs}}) {
-        foreach my $k (("source", "build")) {
-            next unless defined($unified_info{includes}->{$dest}->{$k});
-            my @incs = reverse @{$unified_info{includes}->{$dest}->{$k}};
-            foreach my $obj (grep /\.o$/,
-                             (keys %{$unified_info{sources}->{$dest}},
-                              keys %{$unified_info{shared_sources}->{$dest}})) {
-                foreach my $inc (@incs) {
-                    unshift @{$unified_info{includes}->{$obj}->{$k}}, $inc
-                        unless grep { $_ eq $inc } @{$unified_info{includes}->{$obj}->{$k}};
+    # Go through all intermediary files and change their names to something that
+    # reflects what they will be built for.  Note that for some source files,
+    # this leads to duplicate object files because they are used multiple times.
+    # the goal is to rename all object files according to this scheme:
+    #    {productname}-{midfix}-{origobjname}.[o|res]
+    # the {midfix} is a keyword indicating the type of product, which is mostly
+    # valuable for libraries since they come in two forms.
+    #
+    # This also reorganises the {sources} and {shared_sources} so that the
+    # former only contains ALL object files that are supposed to end up in
+    # static libraries and programs, while the latter contains ALL object files
+    # that are supposed to end up in shared libraries and DSOs.
+    # The main reason for having two different source structures is to allow
+    # the same name to be used for the static and the shared variants of a
+    # library.
+    {
+        # Take copies so we don't get interference from added stuff
+        my %unified_copy = ();
+        foreach (('sources', 'shared_sources')) {
+            $unified_copy{$_} = { %{$unified_info{$_}} }
+                if defined($unified_info{$_});
+            delete $unified_info{$_};
+        }
+        foreach my $prodtype (('programs', 'libraries', 'engines', 'scripts')) {
+            # $intent serves multi purposes:
+            # - give a prefix for the new object files names
+            # - in the case of libraries, rearrange the object files so static
+            #   libraries use the 'sources' structure exclusively, while shared
+            #   libraries use the 'shared_sources' structure exclusively.
+            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' } },
+                engines   => { dso    => { src => [ 'sources',
+                                                    'shared_sources' ],
+                                           dst => 'shared_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}})) {
+                    # %prod_sources has all applicable objects as keys, and
+                    # their corresponding sources as values
+                    my %prod_sources =
+                        map { $_ => [ keys %{$unified_copy{sources}->{$_}} ] }
+                        map { keys %{$unified_copy{$_}->{$prod}} }
+                        @src;
+                    foreach (keys %prod_sources) {
+                        # Only affect object files and resource files,
+                        # the others simply get a new value
+                        # (+1 instead of -1)
+                        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;
+                            }
+                            # Adjust dependencies
+                            foreach my $deps (keys %{$unified_info{depends}->{$_}}) {
+                                $unified_info{depends}->{$_}->{$deps} = -1;
+                                $unified_info{depends}->{$newobj}->{$deps} = 1;
+                            }
+                            # Adjust includes
+                            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;
+                        }
+                    }
                 }
             }
         }
-        delete $unified_info{includes}->{$dest};
     }
+    # At this point, we have a number of sources with the value -1.  They
+    # aren't part of the local build and are probably meant for a different
+    # platform, and can therefore be cleaned away.  That happens when making
+    # %unified_info more efficient below.
 
     ### Make unified_info a bit more efficient
     # One level structures
@@ -2206,10 +2319,23 @@ EOF
     # Two level structures
     foreach my $l1 (("install", "sources", "shared_sources", "ldadd", "depends")) {
         foreach my $l2 (sort keys %{$unified_info{$l1}}) {
-            $unified_info{$l1}->{$l2} =
-                [ sort keys %{$unified_info{$l1}->{$l2}} ];
+            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};
+            }
         }
     }
+    # Defines
+    foreach my $dest (sort keys %{$unified_info{defines}}) {
+        $unified_info{defines}->{$dest}
+            = [ map { $_.$unified_info{defines}->{$dest}->{$_} }
+                sort keys %{$unified_info{defines}->{$dest}} ];
+    }
     # Includes
     foreach my $dest (sort keys %{$unified_info{includes}}) {
         if (defined($unified_info{includes}->{$dest}->{build})) {
@@ -2222,9 +2348,47 @@ EOF
                 push @{$unified_info{includes}->{$dest}}, $inc
                     unless grep { $_ eq $inc } @{$unified_info{includes}->{$dest}};
             }
-        } else {
+        } elsif (defined($unified_info{includes}->{$dest}->{source})) {
             $unified_info{includes}->{$dest} =
                 [ @{$unified_info{includes}->{$dest}->{source}} ];
+        } else {
+            delete $unified_info{includes}->{$dest};
+        }
+    }
+
+    # For convenience collect information regarding directories where
+    # files are generated, those generated files and the end product
+    # they end up in where applicable.  Then, add build rules for those
+    # directories
+    my %loopinfo = ( "lib" => [ @{$unified_info{libraries}} ],
+                     "dso" => [ @{$unified_info{engines}} ],
+                     "bin" => [ @{$unified_info{programs}} ],
+                     "script" => [ @{$unified_info{scripts}} ] );
+    foreach my $type (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($_);
+
+                # We don't want to create targets for source directories
+                # when building out of source
+                next if ($config{sourcedir} ne $config{builddir}
+                             && $d =~ m|^\Q$config{sourcedir}\E|);
+                # We already have a "test" target, and the current directory
+                # is just silly to make a target for
+                next if $d eq "test" || $d eq ".";
+
+                $dirs{$d} = 1;
+                push @{$unified_info{dirinfo}->{$d}->{deps}}, $_
+                    if $d ne $pd;
+            }
+            foreach (keys %dirs) {
+                push @{$unified_info{dirinfo}->{$_}->{products}->{$type}},
+                    $product;
+            }
         }
     }
 }
@@ -2458,7 +2622,7 @@ _____
     if ($dump || $cmdline) {
         print "\nCommand line (with current working directory = $here):\n\n";
         print '    ',join(' ',
-                          $config{perl},
+                          $config{PERL},
                           catfile($config{sourcedir}, 'Configure'),
                           @{$config{perlargv}}), "\n";
         print "\nPerl information:\n\n";
@@ -2679,6 +2843,8 @@ my %builders = (
 
 $builders{$builder}->($builder_platform, @builder_opts);
 
+$SIG{__DIE__} = $orig_death_handler;
+
 print <<"EOF" if ($disabled{threads} eq "unavailable");
 
 The library could not be configured for supporting multi-threaded
@@ -2699,10 +2865,16 @@ print <<"EOF";
 
 **********************************************************************
 ***                                                                ***
-***   If you want to report a building issue, please include the   ***
-***   output from this command:                                    ***
+***   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                                ***
 ***                                                                ***
-***     perl configdata.pm --dump                                  ***
+***   (If you are new to OpenSSL, you might want to consult the    ***
+***   'Troubleshooting' section in the INSTALL file first)         ***
 ***                                                                ***
 **********************************************************************
 EOF
@@ -2714,6 +2886,24 @@ exit(0);
 # Helpers and utility functions
 #
 
+# Death handler, to print a helpful message in case of failure #######
+#
+sub death_handler {
+    die @_ if $^S;              # To prevent the added message in eval blocks
+    my $build_file = $target{build_file} // "build file";
+    my @message = ( <<"_____", @_ );
+
+Failure!  $build_file wasn't produced.
+Please read INSTALL and associated NOTES files.  You may also have to look over
+your available compiler tool chain or change your configuration.
+
+_____
+
+    # Dying is terminal, so it's ok to reset the signal handler here.
+    $SIG{__DIE__} = $orig_death_handler;
+    die @message;
+}
+
 # Configuration file reading #########################################
 
 # Note: All of the helper functions are for lazy evaluation.  They all
@@ -3064,7 +3254,7 @@ sub run_dofile
     foreach (@templates) {
         die "Can't open $_, $!" unless -f $_;
     }
-    my $perlcmd = (quotify("maybeshell", $config{perl}))[0];
+    my $perlcmd = (quotify("maybeshell", $config{PERL}))[0];
     my $cmd = "$perlcmd \"-I.\" \"-Mconfigdata\" \"$dofile\" -o\"Configure\" \"".join("\" \"",@templates)."\" > \"$out.new\"";
     #print STDERR "DEBUG[run_dofile]: \$cmd = $cmd\n";
     system($cmd);