Home | History | Annotate | Line # | Download | only in dist
Configure revision 1.1.1.35
      1 #! /usr/bin/env perl
      2 # -*- mode: perl; -*-
      3 # Copyright 2016-2023 The OpenSSL Project Authors. All Rights Reserved.
      4 #
      5 # Licensed under the Apache License 2.0 (the "License").  You may not use
      6 # this file except in compliance with the License.  You can obtain a copy
      7 # in the file LICENSE in the source distribution or at
      8 # https://www.openssl.org/source/license.html
      9 
     10 ##  Configure -- OpenSSL source tree configuration script
     11 
     12 use 5.10.0;
     13 use strict;
     14 use Config;
     15 use FindBin;
     16 use lib "$FindBin::Bin/util/perl";
     17 use File::Basename;
     18 use File::Spec::Functions qw/:DEFAULT abs2rel rel2abs splitdir/;
     19 use File::Path qw/mkpath/;
     20 use OpenSSL::fallback "$FindBin::Bin/external/perl/MODULES.txt";
     21 use OpenSSL::Glob;
     22 use OpenSSL::Template;
     23 use OpenSSL::config;
     24 
     25 # see INSTALL.md for instructions.
     26 
     27 my $orig_death_handler = $SIG{__DIE__};
     28 $SIG{__DIE__} = \&death_handler;
     29 
     30 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-egd] [sctp] [386] [--prefix=DIR] [--openssldir=OPENSSLDIR] [--with-xxx[=vvv]] [--config=FILE] os/compiler[:flags]\n";
     31 
     32 my $banner = <<"EOF";
     33 
     34 **********************************************************************
     35 ***                                                                ***
     36 ***   OpenSSL has been successfully configured                     ***
     37 ***                                                                ***
     38 ***   If you encounter a problem while building, please open an    ***
     39 ***   issue on GitHub <https://github.com/openssl/openssl/issues>  ***
     40 ***   and include the output from the following command:           ***
     41 ***                                                                ***
     42 ***       perl configdata.pm --dump                                ***
     43 ***                                                                ***
     44 ***   (If you are new to OpenSSL, you might want to consult the    ***
     45 ***   'Troubleshooting' section in the INSTALL.md file first)      ***
     46 ***                                                                ***
     47 **********************************************************************
     48 EOF
     49 
     50 # Options:
     51 #
     52 # --config      add the given configuration file, which will be read after
     53 #               any "Configurations*" files that are found in the same
     54 #               directory as this script.
     55 # --prefix      prefix for the OpenSSL installation, which includes the
     56 #               directories bin, lib, include, share/man, share/doc/openssl
     57 #               This becomes the value of INSTALLTOP in Makefile
     58 #               (Default: /usr/local)
     59 # --openssldir  OpenSSL data area, such as openssl.cnf, certificates and keys.
     60 #               If it's a relative directory, it will be added on the directory
     61 #               given with --prefix.
     62 #               This becomes the value of OPENSSLDIR in Makefile and in C.
     63 #               (Default: PREFIX/ssl)
     64 # --banner=".." Output specified text instead of default completion banner
     65 #
     66 # -w            Don't wait after showing a Configure warning
     67 #
     68 # --cross-compile-prefix Add specified prefix to binutils components.
     69 #
     70 # --api         One of 0.9.8, 1.0.0, 1.0.1, 1.0.2, 1.1.0, 1.1.1, or 3.0
     71 #               Define the public APIs as they were for that version
     72 #               including patch releases.  If 'no-deprecated' is also
     73 #               given, do not compile support for interfaces deprecated
     74 #               up to and including the specified OpenSSL version.
     75 #
     76 # no-hw-xxx     do not compile support for specific crypto hardware.
     77 #               Generic OpenSSL-style methods relating to this support
     78 #               are always compiled but return NULL if the hardware
     79 #               support isn't compiled.
     80 # no-hw         do not compile support for any crypto hardware.
     81 # [no-]threads  [don't] try to create a library that is suitable for
     82 #               multithreaded applications (default is "threads" if we
     83 #               know how to do it)
     84 # [no-]shared   [don't] try to create shared libraries when supported.
     85 # [no-]pic      [don't] try to build position independent code when supported.
     86 #               If disabled, it also disables shared and dynamic-engine.
     87 # no-asm        do not use assembler
     88 # no-egd        do not compile support for the entropy-gathering daemon APIs
     89 # [no-]zlib     [don't] compile support for zlib compression.
     90 # zlib-dynamic  Like "zlib", but the zlib library is expected to be a shared
     91 #               library and will be loaded in run-time by the OpenSSL library.
     92 # sctp          include SCTP support
     93 # no-uplink     Don't build support for UPLINK interface.
     94 # enable-weak-ssl-ciphers
     95 #               Enable weak ciphers that are disabled by default.
     96 # 386           generate 80386 code in assembly modules
     97 # no-sse2       disables IA-32 SSE2 code in assembly modules, the above
     98 #               mentioned '386' option implies this one
     99 # no-<cipher>   build without specified algorithm (dsa, idea, rc5, ...)
    100 # -<xxx> +<xxx> All options which are unknown to the 'Configure' script are
    101 # /<xxx>        passed through to the compiler. Unix-style options beginning
    102 #               with a '-' or '+' are recognized, as well as Windows-style
    103 #               options beginning with a '/'. If the option contains arguments
    104 #               separated by spaces, then the URL-style notation %20 can be
    105 #               used for the space character in order to avoid having to quote
    106 #               the option. For example, -opt%20arg gets expanded to -opt arg.
    107 #               In fact, any ASCII character can be encoded as %xx using its
    108 #               hexadecimal encoding.
    109 # -static       while -static is also a pass-through compiler option (and
    110 #               as such is limited to environments where it's actually
    111 #               meaningful), it triggers a number configuration options,
    112 #               namely no-pic, no-shared and no-threads. It is
    113 #               argued that the only reason to produce statically linked
    114 #               binaries (and in context it means executables linked with
    115 #               -static flag, and not just executables linked with static
    116 #               libcrypto.a) is to eliminate dependency on specific run-time,
    117 #               a.k.a. libc version. The mentioned config options are meant
    118 #               to achieve just that. Unfortunately on Linux it's impossible
    119 #               to eliminate the dependency completely for openssl executable
    120 #               because of getaddrinfo and gethostbyname calls, which can
    121 #               invoke dynamically loadable library facility anyway to meet
    122 #               the lookup requests. For this reason on Linux statically
    123 #               linked openssl executable has rather debugging value than
    124 #               production quality.
    125 #
    126 # BN_LLONG      use the type 'long long' in crypto/bn/bn.h
    127 # RC4_CHAR      use 'char' instead of 'int' for RC4_INT in crypto/rc4/rc4.h
    128 # Following are set automatically by this script
    129 #
    130 # MD5_ASM       use some extra md5 assembler,
    131 # SHA1_ASM      use some extra sha1 assembler, must define L_ENDIAN for x86
    132 # RMD160_ASM    use some extra ripemd160 assembler,
    133 # SHA256_ASM    sha256_block is implemented in assembler
    134 # SHA512_ASM    sha512_block is implemented in assembler
    135 # AES_ASM       AES_[en|de]crypt is implemented in assembler
    136 
    137 # Minimum warning options... any contributions to OpenSSL should at least
    138 # get past these.  Note that we only use these with C compilers, not with
    139 # C++ compilers.
    140 
    141 # -DPEDANTIC complements -pedantic and is meant to mask code that
    142 # is not strictly standard-compliant and/or implementation-specific,
    143 # e.g. inline assembly, disregards to alignment requirements, such
    144 # that -pedantic would complain about. Incidentally -DPEDANTIC has
    145 # to be used even in sanitized builds, because sanitizer too is
    146 # supposed to and does take notice of non-standard behaviour. Then
    147 # -pedantic with pre-C9x compiler would also complain about 'long
    148 # long' not being supported. As 64-bit algorithms are common now,
    149 # it grew impossible to resolve this without sizeable additional
    150 # code, so we just tell compiler to be pedantic about everything
    151 # but 'long long' type.
    152 
    153 my @gcc_devteam_warn = qw(
    154     -DPEDANTIC -pedantic -Wno-long-long -DUNUSEDRESULT_DEBUG
    155     -Wall
    156     -Wmissing-declarations
    157     -Wextra
    158     -Wno-unused-parameter
    159     -Wno-missing-field-initializers
    160     -Wswitch
    161     -Wsign-compare
    162     -Wshadow
    163     -Wformat
    164     -Wtype-limits
    165     -Wundef
    166     -Werror
    167     -Wmissing-prototypes
    168     -Wstrict-prototypes
    169 );
    170 
    171 # These are used in addition to $gcc_devteam_warn when the compiler is clang.
    172 # TODO(openssl-team): fix problems and investigate if (at least) the
    173 # following warnings can also be enabled:
    174 #       -Wcast-align
    175 #       -Wunreachable-code -- no, too ugly/compiler-specific
    176 #       -Wlanguage-extension-token -- no, we use asm()
    177 #       -Wunused-macros -- no, too tricky for BN and _XOPEN_SOURCE etc
    178 #       -Wextended-offsetof -- no, needed in CMS ASN1 code
    179 my @clang_devteam_warn = qw(
    180     -Wno-unknown-warning-option
    181     -Wswitch-default
    182     -Wno-parentheses-equality
    183     -Wno-language-extension-token
    184     -Wno-extended-offsetof
    185     -Wconditional-uninitialized
    186     -Wincompatible-pointer-types-discards-qualifiers
    187     -Wmissing-variable-declarations
    188 );
    189 
    190 my @cl_devteam_warn = qw(
    191     /WX
    192 );
    193 
    194 my $strict_warnings = 0;
    195 
    196 # As for $BSDthreads. Idea is to maintain "collective" set of flags,
    197 # which would cover all BSD flavors. -pthread applies to them all,
    198 # but is treated differently. OpenBSD expands is as -D_POSIX_THREAD
    199 # -lc_r, which is sufficient. FreeBSD 4.x expands it as -lc_r,
    200 # which has to be accompanied by explicit -D_THREAD_SAFE and
    201 # sometimes -D_REENTRANT. FreeBSD 5.x expands it as -lc_r, which
    202 # seems to be sufficient?
    203 our $BSDthreads="-pthread -D_THREAD_SAFE -D_REENTRANT";
    204 
    205 #
    206 # API compatibility name to version number mapping.
    207 #
    208 my $apitable = {
    209     # This table expresses when API additions or changes can occur.
    210     # The numbering used changes from 3.0 and on because we updated
    211     # (solidified) our version numbering scheme at that point.
    212 
    213     # From 3.0 and on, we internalise the given version number in decimal
    214     # as MAJOR * 10000 + MINOR * 100 + 0
    215     "3.0.0" => 30000,
    216     "3.0"   => 30000,
    217 
    218     # Note that before 3.0, we didn't have the same version number scheme.
    219     # Still, the numbering we use here covers what we need.
    220     "1.1.1" => 10101,
    221     "1.1.0" => 10100,
    222     "1.0.2" => 10002,
    223     "1.0.1" => 10001,
    224     "1.0.0" => 10000,
    225     "0.9.8" =>   908,
    226 };
    227 
    228 # For OpenSSL::config::get_platform
    229 my %guess_opts = ();
    230 
    231 my $dryrun = 0;
    232 
    233 our %table = ();
    234 our %config = ();
    235 our %withargs = ();
    236 our $now_printing;      # set to current entry's name in print_table_entry
    237                         # (todo: right thing would be to encapsulate name
    238                         # into %target [class] and make print_table_entry
    239                         # a method)
    240 
    241 # Forward declarations ###############################################
    242 
    243 # read_config(filename)
    244 #
    245 # Reads a configuration file and populates %table with the contents
    246 # (which the configuration file places in %targets).
    247 sub read_config;
    248 
    249 # resolve_config(target)
    250 #
    251 # Resolves all the late evaluations, inheritances and so on for the
    252 # chosen target and any target it inherits from.
    253 sub resolve_config;
    254 
    255 
    256 # Information collection #############################################
    257 
    258 # Unified build supports separate build dir
    259 my $srcdir = catdir(absolutedir(dirname($0))); # catdir ensures local syntax
    260 my $blddir = catdir(absolutedir("."));         # catdir ensures local syntax
    261 
    262 # File::Spec::Unix doesn't detect case insensitivity, so we make sure to
    263 # check if the source and build directory are really the same, and make
    264 # them so.  This avoids all kinds of confusion later on.
    265 # We must check @File::Spec::ISA rather than using File::Spec->isa() to
    266 # know if File::Spec ended up loading File::Spec::Unix.
    267 $srcdir = $blddir
    268     if (grep(/::Unix$/, @File::Spec::ISA)
    269         && samedir($srcdir, $blddir));
    270 
    271 my $dofile = abs2rel(catfile($srcdir, "util/dofile.pl"));
    272 
    273 my $local_config_envname = 'OPENSSL_LOCAL_CONFIG_DIR';
    274 
    275 $config{sourcedir} = abs2rel($srcdir, $blddir);
    276 $config{builddir} = abs2rel($blddir, $blddir);
    277 # echo -n 'holy hand grenade of antioch' | openssl sha256
    278 $config{FIPSKEY} =
    279     'f4556650ac31d35461610bac4ed81b1a181b2d8a43ea2854cbae22ca74560813';
    280 
    281 # Collect reconfiguration information if needed
    282 my @argvcopy=@ARGV;
    283 
    284 if (grep /^reconf(igure)?$/, @argvcopy) {
    285     die "reconfiguring with other arguments present isn't supported"
    286         if scalar @argvcopy > 1;
    287     if (-f "./configdata.pm") {
    288         my $file = "./configdata.pm";
    289         unless (my $return = do $file) {
    290             die "couldn't parse $file: $@" if $@;
    291             die "couldn't do $file: $!"    unless defined $return;
    292             die "couldn't run $file"       unless $return;
    293         }
    294 
    295         @argvcopy = defined($configdata::config{perlargv}) ?
    296             @{$configdata::config{perlargv}} : ();
    297         die "Incorrect data to reconfigure, please do a normal configuration\n"
    298             if (grep(/^reconf/,@argvcopy));
    299         $config{perlenv} = $configdata::config{perlenv} // {};
    300     } else {
    301         die "Insufficient data to reconfigure, please do a normal configuration\n";
    302     }
    303 }
    304 
    305 $config{perlargv} = [ @argvcopy ];
    306 
    307 # Historical: if known directories in crypto/ have been removed, it means
    308 # that those sub-systems are disabled.
    309 # (the other option would be to removed them from the SUBDIRS statement in
    310 # crypto/build.info)
    311 # We reverse the input list for cosmetic purely reasons, to compensate that
    312 # 'unshift' adds at the front of the list (i.e. in reverse input order).
    313 foreach ( reverse sort( 'aes', 'aria', 'bf', 'camellia', 'cast', 'des', 'dh',
    314                         'dsa', 'ec', 'hmac', 'idea', 'md2', 'md5', 'mdc2',
    315                         'rc2', 'rc4', 'rc5', 'ripemd', 'seed', 'sha',
    316                         'sm2', 'sm3', 'sm4') ) {
    317     unshift @argvcopy, "no-$_" if ! -d catdir($srcdir, 'crypto', $_);
    318 }
    319 
    320 # Collect version numbers
    321 my %version = ();
    322 
    323 collect_information(
    324     collect_from_file(catfile($srcdir,'VERSION.dat')),
    325     qr/\s*(\w+)\s*=\s*(.*?)\s*$/ =>
    326         sub {
    327             # Only define it if there is a value at all
    328             if ($2 ne '') {
    329                 my $k = $1;
    330                 my $v = $2;
    331                 # Some values are quoted.  Trim the quotes
    332                 $v = $1 if $v =~ /^"(.*)"$/;
    333                 $version{uc $k} = $v;
    334             }
    335         },
    336     "OTHERWISE" =>
    337         sub { die "Something wrong with this line:\n$_\nin $srcdir/VERSION.dat" },
    338     );
    339 
    340 $config{major} = $version{MAJOR} // 'unknown';
    341 $config{minor} = $version{MINOR} // 'unknown';
    342 $config{patch} = $version{PATCH} // 'unknown';
    343 $config{prerelease} =
    344     defined $version{PRE_RELEASE_TAG} ? "-$version{PRE_RELEASE_TAG}" : '';
    345 $config{build_metadata} =
    346     defined $version{BUILD_METADATA} ? "+$version{BUILD_METADATA}" : '';
    347 $config{shlib_version} = $version{SHLIB_VERSION} // 'unknown';
    348 $config{release_date} = $version{RELEASE_DATE} // 'xx XXX xxxx';
    349 
    350 $config{version} = "$config{major}.$config{minor}.$config{patch}";
    351 $config{full_version} = "$config{version}$config{prerelease}$config{build_metadata}";
    352 
    353 die "erroneous version information in VERSION.dat: ",
    354     "$config{version}, $config{shlib_version}\n"
    355     unless (defined $version{MAJOR}
    356             && defined $version{MINOR}
    357             && defined $version{PATCH}
    358             && defined $version{SHLIB_VERSION});
    359 
    360 # Collect target configurations
    361 
    362 my $pattern = catfile(dirname($0), "Configurations", "*.conf");
    363 foreach (sort glob($pattern)) {
    364     &read_config($_);
    365 }
    366 
    367 if (defined env($local_config_envname)) {
    368     if ($^O eq 'VMS') {
    369         # VMS environment variables are logical names,
    370         # which can be used as is
    371         $pattern = $local_config_envname . ':' . '*.conf';
    372     } else {
    373         $pattern = catfile(env($local_config_envname), '*.conf');
    374     }
    375 
    376     foreach (sort glob($pattern)) {
    377         &read_config($_);
    378     }
    379 }
    380 
    381 # Save away perl command information
    382 $config{perl_cmd} = $^X;
    383 $config{perl_version} = $Config{version};
    384 $config{perl_archname} = $Config{archname};
    385 
    386 $config{prefix}="";
    387 $config{openssldir}="";
    388 $config{processor}="";
    389 $config{libdir}="";
    390 my $auto_threads=1;    # enable threads automatically? true by default
    391 my $default_ranlib;
    392 
    393 # Known TLS and DTLS protocols
    394 my @tls = qw(ssl3 tls1 tls1_1 tls1_2 tls1_3);
    395 my @dtls = qw(dtls1 dtls1_2);
    396 
    397 # Explicitly known options that are possible to disable.  They can
    398 # be regexps, and will be used like this: /^no-${option}$/
    399 # For developers: keep it sorted alphabetically
    400 
    401 my @disablables = (
    402     "acvp-tests",
    403     "afalgeng",
    404     "aria",
    405     "asan",
    406     "asm",
    407     "async",
    408     "autoalginit",
    409     "autoerrinit",
    410     "autoload-config",
    411     "bf",
    412     "blake2",
    413     "buildtest-c++",
    414     "bulk",
    415     "cached-fetch",
    416     "camellia",
    417     "capieng",
    418     "cast",
    419     "chacha",
    420     "cmac",
    421     "cmp",
    422     "cms",
    423     "comp",
    424     "crypto-mdebug",
    425     "ct",
    426     "deprecated",
    427     "des",
    428     "devcryptoeng",
    429     "dgram",
    430     "dh",
    431     "dsa",
    432     "dso",
    433     "dtls",
    434     "dynamic-engine",
    435     "ec",
    436     "ec2m",
    437     "ec_nistp_64_gcc_128",
    438     "ecdh",
    439     "ecdsa",
    440     "egd",
    441     "engine",
    442     "err",
    443     "external-tests",
    444     "filenames",
    445     "fips",
    446     "fips-securitychecks",
    447     "fuzz-afl",
    448     "fuzz-libfuzzer",
    449     "gost",
    450     "idea",
    451     "ktls",
    452     "legacy",
    453     "loadereng",
    454     "makedepend",
    455     "md2",
    456     "md4",
    457     "mdc2",
    458     "module",
    459     "msan",
    460     "multiblock",
    461     "nextprotoneg",
    462     "ocb",
    463     "ocsp",
    464     "padlockeng",
    465     "pic",
    466     "pinshared",
    467     "poly1305",
    468     "posix-io",
    469     "psk",
    470     "rc2",
    471     "rc4",
    472     "rc5",
    473     "rdrand",
    474     "rfc3779",
    475     "rmd160",
    476     "scrypt",
    477     "sctp",
    478     "secure-memory",
    479     "seed",
    480     "shared",
    481     "siphash",
    482     "siv",
    483     "sm2",
    484     "sm3",
    485     "sm4",
    486     "sock",
    487     "srp",
    488     "srtp",
    489     "sse2",
    490     "ssl",
    491     "ssl-trace",
    492     "static-engine",
    493     "stdio",
    494     "tests",
    495     "threads",
    496     "tls",
    497     "trace",
    498     "ts",
    499     "ubsan",
    500     "ui-console",
    501     "unit-test",
    502     "uplink",
    503     "weak-ssl-ciphers",
    504     "whirlpool",
    505     "zlib",
    506     "zlib-dynamic",
    507     );
    508 foreach my $proto ((@tls, @dtls))
    509         {
    510         push(@disablables, $proto);
    511         push(@disablables, "$proto-method") unless $proto eq "tls1_3";
    512         }
    513 
    514 # Internal disablables, for aliasing purposes.  They serve no special
    515 # purpose here, but allow scripts to get to know them through configdata.pm,
    516 # where these are merged with @disablables.
    517 # The actual aliasing mechanism is done via %disable_cascades
    518 my @disablables_int = qw(
    519     crmf
    520     );
    521 
    522 my %deprecated_disablables = (
    523     "ssl2" => undef,
    524     "buf-freelists" => undef,
    525     "crypto-mdebug-backtrace" => undef,
    526     "hw" => "hw",               # causes cascade, but no macro
    527     "hw-padlock" => "padlockeng",
    528     "ripemd" => "rmd160",
    529     "ui" => "ui-console",
    530     "heartbeats" => undef,
    531     );
    532 
    533 # All of the following are disabled by default:
    534 
    535 our %disabled = ( # "what"         => "comment"
    536                   "fips"                => "default",
    537                   "asan"                => "default",
    538                   "buildtest-c++"       => "default",
    539                   "crypto-mdebug"       => "default",
    540                   "crypto-mdebug-backtrace" => "default",
    541                   "devcryptoeng"        => "default",
    542                   "ec_nistp_64_gcc_128" => "default",
    543                   "egd"                 => "default",
    544                   "external-tests"      => "default",
    545                   "fuzz-afl"            => "default",
    546                   "fuzz-libfuzzer"      => "default",
    547                   "ktls"                => "default",
    548                   "md2"                 => "default",
    549                   "msan"                => "default",
    550                   "rc5"                 => "default",
    551                   "sctp"                => "default",
    552                   "ssl3"                => "default",
    553                   "ssl3-method"         => "default",
    554                   "trace"               => "default",
    555                   "ubsan"               => "default",
    556                   "unit-test"           => "default",
    557                   "weak-ssl-ciphers"    => "default",
    558                   "zlib"                => "default",
    559                   "zlib-dynamic"        => "default",
    560                 );
    561 
    562 # Note: => pair form used for aesthetics, not to truly make a hash table
    563 my @disable_cascades = (
    564     # "what"            => [ "cascade", ... ]
    565     "bulk"              => [ "shared", "dso",
    566                              "aria", "async", "autoload-config",
    567                              "blake2", "bf", "camellia", "cast", "chacha",
    568                              "cmac", "cms", "cmp", "comp", "ct",
    569                              "des", "dgram", "dh", "dsa",
    570                              "ec", "engine",
    571                              "filenames",
    572                              "idea", "ktls",
    573                              "md4", "multiblock", "nextprotoneg",
    574                              "ocsp", "ocb", "poly1305", "psk",
    575                              "rc2", "rc4", "rmd160",
    576                              "seed", "siphash", "siv",
    577                              "sm3", "sm4", "srp",
    578                              "srtp", "ssl3-method", "ssl-trace",
    579                              "ts", "ui-console", "whirlpool",
    580                              "fips-securitychecks" ],
    581     sub { $config{processor} eq "386" }
    582                         => [ "sse2" ],
    583     "ssl"               => [ "ssl3" ],
    584     "ssl3-method"       => [ "ssl3" ],
    585     "zlib"              => [ "zlib-dynamic" ],
    586     "des"               => [ "mdc2" ],
    587     "ec"                => [ "ec2m", "ecdsa", "ecdh", "sm2", "gost" ],
    588     "dgram"             => [ "dtls", "sctp" ],
    589     "sock"              => [ "dgram" ],
    590     "dtls"              => [ @dtls ],
    591     sub { 0 == scalar grep { !$disabled{$_} } @dtls }
    592                         => [ "dtls" ],
    593 
    594     "tls"               => [ @tls ],
    595     sub { 0 == scalar grep { !$disabled{$_} } @tls }
    596                         => [ "tls" ],
    597 
    598     "crypto-mdebug"     => [ "crypto-mdebug-backtrace" ],
    599 
    600     "module"            => [ "dynamic-engine", "fips" ],
    601 
    602     # Without shared libraries, dynamic engines aren't possible.
    603     # This is due to them having to link with libcrypto and register features
    604     # using the ENGINE functionality, and since that relies on global tables,
    605     # those *have* to be exacty the same as the ones accessed from the app,
    606     # which cannot be guaranteed if shared libraries aren't present.
    607     # (note that even with shared libraries, both the app and dynamic engines
    608     # must be linked with the same library)
    609     "shared"            => [ "dynamic-engine", "uplink" ],
    610     "dso"               => [ "dynamic-engine", "module" ],
    611     # Other modules don't necessarily have to link with libcrypto, so shared
    612     # libraries do not have to be a condition to produce those.
    613 
    614     # Without position independent code, there can be no shared libraries
    615     # or modules.
    616     "pic"               => [ "shared", "module" ],
    617 
    618     "engine"            => [ "dynamic-engine", grep(/eng$/, @disablables) ],
    619     "dynamic-engine"    => [ "loadereng" ],
    620     "hw"                => [ "padlockeng" ],
    621 
    622     # no-autoalginit is only useful when building non-shared
    623     "autoalginit"       => [ "shared", "apps", "fips" ],
    624 
    625     "stdio"             => [ "apps", "capieng", "egd" ],
    626     "apps"              => [ "tests" ],
    627     "tests"             => [ "external-tests" ],
    628     "comp"              => [ "zlib" ],
    629     "sm3"               => [ "sm2" ],
    630     sub { !$disabled{"unit-test"} } => [ "heartbeats" ],
    631 
    632     sub { !$disabled{"msan"} } => [ "asm" ],
    633 
    634     "cmac"              => [ "siv" ],
    635     "legacy"            => [ "md2" ],
    636 
    637     "cmp"               => [ "crmf" ],
    638 
    639     "fips"              => [ "fips-securitychecks", "acvp-tests" ],
    640 
    641     "deprecated-3.0"    => [ "engine", "srp" ]
    642     );
    643 
    644 # Avoid protocol support holes.  Also disable all versions below N, if version
    645 # N is disabled while N+1 is enabled.
    646 #
    647 my @list = (reverse @tls);
    648 while ((my $first, my $second) = (shift @list, shift @list)) {
    649     last unless @list;
    650     push @disable_cascades, ( sub { !$disabled{$first} && $disabled{$second} }
    651                               => [ @list ] );
    652     unshift @list, $second;
    653 }
    654 my @list = (reverse @dtls);
    655 while ((my $first, my $second) = (shift @list, shift @list)) {
    656     last unless @list;
    657     push @disable_cascades, ( sub { !$disabled{$first} && $disabled{$second} }
    658                               => [ @list ] );
    659     unshift @list, $second;
    660 }
    661 
    662 # Explicit "no-..." options will be collected in %disabled along with the defaults.
    663 # To remove something from %disabled, use "enable-foo".
    664 # For symmetry, "disable-foo" is a synonym for "no-foo".
    665 
    666 # For the "make variables" CPPINCLUDES and CPPDEFINES, we support lists with
    667 # platform specific list separators.  Users from those platforms should
    668 # recognise those separators from how you set up the PATH to find executables.
    669 # The default is the Unix like separator, :, but as an exception, we also
    670 # support the space as separator.
    671 my $list_separator_re =
    672     { VMS           => qr/(?<!\^),/,
    673       MSWin32       => qr/(?<!\\);/ } -> {$^O} // qr/(?<!\\)[:\s]/;
    674 # All the "make variables" we support
    675 # Some get pre-populated for the sake of backward compatibility
    676 # (we supported those before the change to "make variable" support.
    677 my %user = (
    678     AR          => env('AR'),
    679     ARFLAGS     => [],
    680     AS          => undef,
    681     ASFLAGS     => [],
    682     CC          => env('CC'),
    683     CFLAGS      => [ env('CFLAGS') || () ],
    684     CXX         => env('CXX'),
    685     CXXFLAGS    => [ env('CXXFLAGS') || () ],
    686     CPP         => undef,
    687     CPPFLAGS    => [ env('CPPFLAGS') || () ],  # -D, -I, -Wp,
    688     CPPDEFINES  => [],  # Alternative for -D
    689     CPPINCLUDES => [],  # Alternative for -I
    690     CROSS_COMPILE => env('CROSS_COMPILE'),
    691     HASHBANGPERL=> env('HASHBANGPERL') || env('PERL'),
    692     LD          => undef,
    693     LDFLAGS     => [ env('LDFLAGS') || () ],  # -L, -Wl,
    694     LDLIBS      => [ env('LDLIBS') || () ],  # -l
    695     MT          => undef,
    696     MTFLAGS     => [],
    697     PERL        => env('PERL') || ($^O ne "VMS" ? $^X : "perl"),
    698     RANLIB      => env('RANLIB'),
    699     RC          => env('RC') || env('WINDRES'),
    700     RCFLAGS     => [ env('RCFLAGS') || () ],
    701     RM          => undef,
    702    );
    703 # Info about what "make variables" may be prefixed with the cross compiler
    704 # prefix.  This should NEVER mention any such variable with a list for value.
    705 my @user_crossable = qw ( AR AS CC CXX CPP LD MT RANLIB RC );
    706 # The same but for flags given as Configure options.  These are *additional*
    707 # input, as opposed to the VAR=string option that override the corresponding
    708 # config target attributes
    709 my %useradd = (
    710     CPPDEFINES  => [],
    711     CPPINCLUDES => [],
    712     CPPFLAGS    => [],
    713     CFLAGS      => [],
    714     CXXFLAGS    => [],
    715     LDFLAGS     => [],
    716     LDLIBS      => [],
    717     RCFLAGS     => [],
    718    );
    719 
    720 my %user_synonyms = (
    721     HASHBANGPERL=> 'PERL',
    722     RC          => 'WINDRES',
    723    );
    724 
    725 # Some target attributes have been renamed, this is the translation table
    726 my %target_attr_translate =(
    727     ar          => 'AR',
    728     as          => 'AS',
    729     cc          => 'CC',
    730     cxx         => 'CXX',
    731     cpp         => 'CPP',
    732     hashbangperl => 'HASHBANGPERL',
    733     ld          => 'LD',
    734     mt          => 'MT',
    735     ranlib      => 'RANLIB',
    736     rc          => 'RC',
    737     rm          => 'RM',
    738    );
    739 
    740 # Initialisers coming from 'config' scripts
    741 $config{defines} = [ split(/$list_separator_re/, env('__CNF_CPPDEFINES')) ];
    742 $config{includes} = [ split(/$list_separator_re/, env('__CNF_CPPINCLUDES')) ];
    743 $config{cppflags} = [ env('__CNF_CPPFLAGS') || () ];
    744 $config{cflags} = [ env('__CNF_CFLAGS') || () ];
    745 $config{cxxflags} = [ env('__CNF_CXXFLAGS') || () ];
    746 $config{lflags} = [ env('__CNF_LDFLAGS') || () ];
    747 $config{ex_libs} = [ env('__CNF_LDLIBS') || () ];
    748 
    749 $config{openssl_api_defines}=[];
    750 $config{openssl_sys_defines}=[];
    751 $config{openssl_feature_defines}=[];
    752 $config{options}="";
    753 $config{build_type} = "release";
    754 my $target="";
    755 
    756 my %cmdvars = ();               # Stores FOO='blah' type arguments
    757 my %unsupported_options = ();
    758 my %deprecated_options = ();
    759 # If you change this, update apps/version.c
    760 my @known_seed_sources = qw(getrandom devrandom os egd none rdcpu librandom);
    761 my @seed_sources = ();
    762 while (@argvcopy)
    763         {
    764         $_ = shift @argvcopy;
    765 
    766         # Support env variable assignments among the options
    767         if (m|^(\w+)=(.+)?$|)
    768                 {
    769                 $cmdvars{$1} = $2;
    770                 # Every time a variable is given as a configuration argument,
    771                 # it acts as a reset if the variable.
    772                 if (exists $user{$1})
    773                         {
    774                         $user{$1} = ref $user{$1} eq "ARRAY" ? [] : undef;
    775                         }
    776                 #if (exists $useradd{$1})
    777                 #       {
    778                 #       $useradd{$1} = [];
    779                 #       }
    780                 next;
    781                 }
    782 
    783         # VMS is a case insensitive environment, and depending on settings
    784         # out of our control, we may receive options uppercased.  Let's
    785         # downcase at least the part before any equal sign.
    786         if ($^O eq "VMS")
    787                 {
    788                 s/^([^=]*)/lc($1)/e;
    789                 }
    790 
    791         # some people just can't read the instructions, clang people have to...
    792         s/^-no-(?!integrated-as)/no-/;
    793 
    794         # rewrite some options in "enable-..." form
    795         s /^-?-?shared$/enable-shared/;
    796         s /^sctp$/enable-sctp/;
    797         s /^threads$/enable-threads/;
    798         s /^zlib$/enable-zlib/;
    799         s /^zlib-dynamic$/enable-zlib-dynamic/;
    800         s /^fips$/enable-fips/;
    801 
    802         if (/^(no|disable|enable)-(.+)$/)
    803                 {
    804                 my $word = $2;
    805                 if ($word !~ m|hw(?:-.+)| # special treatment for hw regexp opt
    806                         && !exists $deprecated_disablables{$word}
    807                         && !grep { $word eq $_ } @disablables)
    808                         {
    809                         $unsupported_options{$_} = 1;
    810                         next;
    811                         }
    812                 }
    813         if (/^no-(.+)$/ || /^disable-(.+)$/)
    814                 {
    815                 foreach my $proto ((@tls, @dtls))
    816                         {
    817                         if ($1 eq "$proto-method")
    818                                 {
    819                                 $disabled{"$proto"} = "option($proto-method)";
    820                                 last;
    821                                 }
    822                         }
    823                 if ($1 eq "dtls")
    824                         {
    825                         foreach my $proto (@dtls)
    826                                 {
    827                                 $disabled{$proto} = "option(dtls)";
    828                                 }
    829                         $disabled{"dtls"} = "option(dtls)";
    830                         }
    831                 elsif ($1 eq "ssl")
    832                         {
    833                         # Last one of its kind
    834                         $disabled{"ssl3"} = "option(ssl)";
    835                         }
    836                 elsif ($1 eq "tls")
    837                         {
    838                         # XXX: Tests will fail if all SSL/TLS
    839                         # protocols are disabled.
    840                         foreach my $proto (@tls)
    841                                 {
    842                                 $disabled{$proto} = "option(tls)";
    843                                 }
    844                         }
    845                 elsif ($1 eq "static-engine")
    846                         {
    847                         delete $disabled{"dynamic-engine"};
    848                         }
    849                 elsif ($1 eq "dynamic-engine")
    850                         {
    851                         $disabled{"dynamic-engine"} = "option";
    852                         }
    853                 elsif (exists $deprecated_disablables{$1})
    854                         {
    855                         $deprecated_options{$_} = 1;
    856                         if (defined $deprecated_disablables{$1})
    857                                 {
    858                                 $disabled{$deprecated_disablables{$1}} = "option";
    859                                 }
    860                         }
    861                 elsif ($1 =~ m|hw(?:-.+)|) # deprecate hw options in regexp form
    862                         {
    863                         $deprecated_options{$_} = 1;
    864                         }
    865                 else
    866                         {
    867                         $disabled{$1} = "option";
    868                         }
    869                 # No longer an automatic choice
    870                 $auto_threads = 0 if ($1 eq "threads");
    871                 }
    872         elsif (/^enable-(.+)$/)
    873                 {
    874                 if ($1 eq "static-engine")
    875                         {
    876                         $disabled{"dynamic-engine"} = "option";
    877                         }
    878                 elsif ($1 eq "dynamic-engine")
    879                         {
    880                         delete $disabled{"dynamic-engine"};
    881                         }
    882                 elsif ($1 eq "zlib-dynamic")
    883                         {
    884                         delete $disabled{"zlib"};
    885                         }
    886                 my $algo = $1;
    887                 delete $disabled{$algo};
    888 
    889                 # No longer an automatic choice
    890                 $auto_threads = 0 if ($1 eq "threads");
    891                 }
    892         elsif (/^-d$/)          # From older 'config'
    893                 {
    894                 $config{build_type} = "debug";
    895                 }
    896         elsif (/^-v$/)          # From older 'config'
    897                 {
    898                 $guess_opts{verbose} = 1;
    899                 }
    900         elsif (/^-w$/)
    901                 {
    902                 $guess_opts{nowait} = 1;
    903                 }
    904         elsif (/^-t$/)          # From older 'config'
    905                 {
    906                 $dryrun = 1;
    907                 }
    908         elsif (/^--strict-warnings$/)
    909                 {
    910                 # Pretend that our strict flags is a C flag, and replace it
    911                 # with the proper flags later on
    912                 push @{$useradd{CFLAGS}}, '--ossl-strict-warnings';
    913                 $strict_warnings=1;
    914                 }
    915         elsif (/^--debug$/)
    916                 {
    917                 $config{build_type} = "debug";
    918                 }
    919         elsif (/^--release$/)
    920                 {
    921                 $config{build_type} = "release";
    922                 }
    923         elsif (/^386$/)
    924                 { $config{processor}=386; }
    925         elsif (/^rsaref$/)
    926                 {
    927                 # No RSAref support any more since it's not needed.
    928                 # The check for the option is there so scripts aren't
    929                 # broken
    930                 }
    931         elsif (m|^[-+/]|)
    932                 {
    933                 if (/^--prefix=(.*)$/)
    934                         {
    935                         $config{prefix}=$1;
    936                         die "Directory given with --prefix MUST be absolute\n"
    937                                 unless file_name_is_absolute($config{prefix});
    938                         }
    939                 elsif (/^--api=(.*)$/)
    940                         {
    941                         my $api = $1;
    942                         die "Unknown API compatibility level $api"
    943                                 unless defined $apitable->{$api};
    944                         $config{api}=$apitable->{$api};
    945                         }
    946                 elsif (/^--libdir=(.*)$/)
    947                         {
    948                         $config{libdir}=$1;
    949                         }
    950                 elsif (/^--openssldir=(.*)$/)
    951                         {
    952                         $config{openssldir}=$1;
    953                         }
    954                 elsif (/^--with-zlib-lib=(.*)$/)
    955                         {
    956                         $withargs{zlib_lib}=$1;
    957                         }
    958                 elsif (/^--with-zlib-include=(.*)$/)
    959                         {
    960                         $withargs{zlib_include}=$1;
    961                         }
    962                 elsif (/^--with-fuzzer-lib=(.*)$/)
    963                         {
    964                         $withargs{fuzzer_lib}=$1;
    965                         }
    966                 elsif (/^--with-fuzzer-include=(.*)$/)
    967                         {
    968                         $withargs{fuzzer_include}=$1;
    969                         }
    970                 elsif (/^--with-rand-seed=(.*)$/)
    971                         {
    972                         foreach my $x (split(m|,|, $1))
    973                             {
    974                             die "Unknown --with-rand-seed choice $x\n"
    975                                 if ! grep { $x eq $_ } @known_seed_sources;
    976                             push @seed_sources, $x;
    977                             }
    978                         }
    979                 elsif (/^--fips-key=(.*)$/)
    980                         {
    981                         $user{FIPSKEY}=lc($1);
    982                         die "Non-hex character in FIPS key\n"
    983                            if $user{FIPSKEY} =~ /[^a-f0-9]/;
    984                         die "FIPS key must have even number of characters\n"
    985                            if length $1 & 1;
    986                         die "FIPS key too long (64 bytes max)\n"
    987                            if length $1 > 64;
    988                         }
    989                 elsif (/^--banner=(.*)$/)
    990                         {
    991                         $banner = $1 . "\n";
    992                         }
    993                 elsif (/^--cross-compile-prefix=(.*)$/)
    994                         {
    995                         $user{CROSS_COMPILE}=$1;
    996                         }
    997                 elsif (/^--config=(.*)$/)
    998                         {
    999                         read_config $1;
   1000                         }
   1001                 elsif (/^-l(.*)$/)
   1002                         {
   1003                         push @{$useradd{LDLIBS}}, $_;
   1004                         }
   1005                 elsif (/^-framework$/)
   1006                         {
   1007                         push @{$useradd{LDLIBS}}, $_, shift(@argvcopy);
   1008                         }
   1009                 elsif (/^-L(.*)$/ or /^-Wl,/)
   1010                         {
   1011                         push @{$useradd{LDFLAGS}}, $_;
   1012                         }
   1013                 elsif (/^-rpath$/ or /^-R$/)
   1014                         # -rpath is the OSF1 rpath flag
   1015                         # -R is the old Solaris rpath flag
   1016                         {
   1017                         my $rpath = shift(@argvcopy) || "";
   1018                         $rpath .= " " if $rpath ne "";
   1019                         push @{$useradd{LDFLAGS}}, $_, $rpath;
   1020                         }
   1021                 elsif (/^-static$/)
   1022                         {
   1023                         push @{$useradd{LDFLAGS}}, $_;
   1024                         }
   1025                 elsif (m|^[-/]D(.*)$|)
   1026                         {
   1027                         push @{$useradd{CPPDEFINES}}, $1;
   1028                         }
   1029                 elsif (m|^[-/]I(.*)$|)
   1030                         {
   1031                         push @{$useradd{CPPINCLUDES}}, $1;
   1032                         }
   1033                 elsif (/^-Wp,$/)
   1034                         {
   1035                         push @{$useradd{CPPFLAGS}}, $1;
   1036                         }
   1037                 else    # common if (/^[-+]/), just pass down...
   1038                         {
   1039                         # Treat %xx as an ASCII code (e.g. replace %20 by a space character).
   1040                         # This provides a simple way to pass options with arguments separated
   1041                         # by spaces without quoting (e.g. -opt%20arg translates to -opt arg).
   1042                         $_ =~ s/%([0-9a-f]{1,2})/chr(hex($1))/gei;
   1043                         push @{$useradd{CFLAGS}}, $_;
   1044                         push @{$useradd{CXXFLAGS}}, $_;
   1045                         }
   1046                 }
   1047         elsif (m|^/|)
   1048                 {
   1049                 # Treat %xx as an ASCII code (e.g. replace %20 by a space character).
   1050                 # This provides a simple way to pass options with arguments separated
   1051                 # by spaces without quoting (e.g. /opt%20arg translates to /opt arg).
   1052                 $_ =~ s/%([0-9a-f]{1,2})/chr(hex($1))/gei;
   1053                 push @{$useradd{CFLAGS}}, $_;
   1054                 push @{$useradd{CXXFLAGS}}, $_;
   1055                 }
   1056         else
   1057                 {
   1058                 die "target already defined - $target (offending arg: $_)\n" if ($target ne "");
   1059                 $target=$_;
   1060                 }
   1061         unless ($_ eq $target || /^no-/ || /^disable-/)
   1062                 {
   1063                 # "no-..." follows later after implied deactivations
   1064                 # have been derived.  (Don't take this too seriously,
   1065                 # we really only write OPTIONS to the Makefile out of
   1066                 # nostalgia.)
   1067 
   1068                 if ($config{options} eq "")
   1069                         { $config{options} = $_; }
   1070                 else
   1071                         { $config{options} .= " ".$_; }
   1072                 }
   1073         }
   1074 
   1075 if (keys %deprecated_options)
   1076         {
   1077         warn "***** Deprecated options: ",
   1078                 join(", ", keys %deprecated_options), "\n";
   1079         }
   1080 if (keys %unsupported_options)
   1081         {
   1082         die "***** Unsupported options: ",
   1083                 join(", ", keys %unsupported_options), "\n";
   1084         }
   1085 
   1086 # If any %useradd entry has been set, we must check that the "make
   1087 # variables" haven't been set.  We start by checking of any %useradd entry
   1088 # is set.
   1089 if (grep { scalar @$_ > 0 } values %useradd) {
   1090     # Hash of env / make variables names.  The possible values are:
   1091     # 1 - "make vars"
   1092     # 2 - %useradd entry set
   1093     # 3 - both set
   1094     my %detected_vars =
   1095         map { my $v = 0;
   1096               $v += 1 if $cmdvars{$_};
   1097               $v += 2 if @{$useradd{$_}};
   1098               $_ => $v }
   1099         keys %useradd;
   1100 
   1101     # If any of the corresponding "make variables" is set, we error
   1102     if (grep { $_ & 1 } values %detected_vars) {
   1103         my $names = join(', ', grep { $detected_vars{$_} > 0 }
   1104                                sort keys %detected_vars);
   1105         die <<"_____";
   1106 ***** Mixing make variables and additional compiler/linker flags as
   1107 ***** configure command line option is not permitted.
   1108 ***** Affected make variables: $names
   1109 _____
   1110     }
   1111 }
   1112 
   1113 # Check through all supported command line variables to see if any of them
   1114 # were set, and canonicalise the values we got.  If no compiler or linker
   1115 # flag or anything else that affects %useradd was set, we also check the
   1116 # environment for values.
   1117 my $anyuseradd =
   1118     grep { defined $_ && (ref $_ ne 'ARRAY' || @$_) } values %useradd;
   1119 foreach (keys %user) {
   1120     my $value = $cmdvars{$_};
   1121     $value //= env($_) unless $anyuseradd;
   1122     $value //=
   1123         defined $user_synonyms{$_} ? $cmdvars{$user_synonyms{$_}} : undef;
   1124     $value //= defined $user_synonyms{$_} ? env($user_synonyms{$_}) : undef
   1125         unless $anyuseradd;
   1126 
   1127     if (defined $value) {
   1128         if (ref $user{$_} eq 'ARRAY') {
   1129             if ($_ eq 'CPPDEFINES' || $_ eq 'CPPINCLUDES') {
   1130                 $user{$_} = [ split /$list_separator_re/, $value ];
   1131             } else {
   1132                 $user{$_} = [ $value ];
   1133             }
   1134         } elsif (!defined $user{$_}) {
   1135             $user{$_} = $value;
   1136         }
   1137     }
   1138 }
   1139 
   1140 if (grep { /-rpath\b/ } ($user{LDFLAGS} ? @{$user{LDFLAGS}} : ())
   1141     && !$disabled{shared}
   1142     && !($disabled{asan} && $disabled{msan} && $disabled{ubsan})) {
   1143     die "***** Cannot simultaneously use -rpath, shared libraries, and\n",
   1144         "***** any of asan, msan or ubsan\n";
   1145 }
   1146 
   1147 # If no target was given, try guessing.
   1148 unless ($target) {
   1149     my %system_config = OpenSSL::config::get_platform(%guess_opts, %user);
   1150 
   1151     # The $system_config{disable} is used to populate %disabled with
   1152     # entries that aren't already there.
   1153     foreach ( @{$system_config{disable} // []} ) {
   1154         $disabled{$_} = 'system' unless defined $disabled{$_};
   1155     }
   1156     delete $system_config{disable};
   1157 
   1158     # Override config entries with stuff from the guesser.
   1159     # It's assumed that this really is nothing new.
   1160     %config = ( %config, %system_config );
   1161     $target = $system_config{target};
   1162 }
   1163 
   1164 sub disable {
   1165     my $disable_type = shift;
   1166 
   1167     for (@_) {
   1168         $disabled{$_} = $disable_type;
   1169     }
   1170 
   1171     my @tocheckfor = (@_ ? @_ : keys %disabled);
   1172     while (@tocheckfor) {
   1173         my %new_tocheckfor = ();
   1174         my @cascade_copy = (@disable_cascades);
   1175         while (@cascade_copy) {
   1176             my ($test, $descendents) =
   1177                 (shift @cascade_copy, shift @cascade_copy);
   1178             if (ref($test) eq "CODE" ? $test->() : defined($disabled{$test})) {
   1179                 foreach (grep { !defined($disabled{$_}) } @$descendents) {
   1180                     $new_tocheckfor{$_} = 1; $disabled{$_} = "cascade";
   1181                 }
   1182             }
   1183         }
   1184         @tocheckfor = (keys %new_tocheckfor);
   1185     }
   1186 }
   1187 disable();                     # First cascade run
   1188 
   1189 our $die = sub { die @_; };
   1190 if ($target eq "TABLE") {
   1191     local $die = sub { warn @_; };
   1192     foreach (sort keys %table) {
   1193         print_table_entry($_, "TABLE");
   1194     }
   1195     exit 0;
   1196 }
   1197 
   1198 if ($target eq "LIST") {
   1199     foreach (sort keys %table) {
   1200         print $_,"\n" unless $table{$_}->{template};
   1201     }
   1202     exit 0;
   1203 }
   1204 
   1205 if ($target eq "HASH") {
   1206     local $die = sub { warn @_; };
   1207     print "%table = (\n";
   1208     foreach (sort keys %table) {
   1209         print_table_entry($_, "HASH");
   1210     }
   1211     exit 0;
   1212 }
   1213 
   1214 print "Configuring OpenSSL version $config{full_version} ";
   1215 print "for target $target\n";
   1216 
   1217 if (scalar(@seed_sources) == 0) {
   1218     print "Using os-specific seed configuration\n";
   1219     push @seed_sources, 'os';
   1220 }
   1221 if (scalar(grep { $_ eq 'egd' } @seed_sources) > 0) {
   1222     delete $disabled{'egd'};
   1223 }
   1224 if (scalar(grep { $_ eq 'none' } @seed_sources) > 0) {
   1225     die "Cannot seed with none and anything else" if scalar(@seed_sources) > 1;
   1226     warn <<_____ if scalar(@seed_sources) == 1;
   1227 
   1228 ============================== WARNING ===============================
   1229 You have selected the --with-rand-seed=none option, which effectively
   1230 disables automatic reseeding of the OpenSSL random generator.
   1231 All operations depending on the random generator such as creating keys
   1232 will not work unless the random generator is seeded manually by the
   1233 application.
   1234 
   1235 Please read the 'Note on random number generation' section in the
   1236 INSTALL.md instructions and the RAND_DRBG(7) manual page for more
   1237 details.
   1238 ============================== WARNING ===============================
   1239 
   1240 _____
   1241 }
   1242 push @{$config{openssl_feature_defines}},
   1243      map { (my $x = $_) =~ tr|[\-a-z]|[_A-Z]|; "OPENSSL_RAND_SEED_$x" }
   1244         @seed_sources;
   1245 
   1246 # Backward compatibility?
   1247 if ($target =~ m/^CygWin32(-.*)$/) {
   1248     $target = "Cygwin".$1;
   1249 }
   1250 
   1251 # Support for legacy targets having a name starting with 'debug-'
   1252 my ($d, $t) = $target =~ m/^(debug-)?(.*)$/;
   1253 if ($d) {
   1254     $config{build_type} = "debug";
   1255 
   1256     # If we do not find debug-foo in the table, the target is set to foo.
   1257     if (!$table{$target}) {
   1258         $target = $t;
   1259     }
   1260 }
   1261 
   1262 if ($target) {
   1263     # It's possible that we have different config targets for specific
   1264     # toolchains, so we try to detect them, and go for the plain config
   1265     # target if not.
   1266     my $found;
   1267     foreach ( ( "$target-$user{CC}", "$target", undef ) ) {
   1268         $found=$_ if $table{$_} && !$table{$_}->{template};
   1269         last if $found;
   1270     }
   1271     $target = $found;
   1272 } else {
   1273     # If we don't have a config target now, we try the C compiler as we
   1274     # fallback
   1275     my $cc = $user{CC} // 'cc';
   1276     $target = $cc if $table{$cc} && !$table{$cc}->{template};
   1277 }
   1278 
   1279 &usage unless $target;
   1280 
   1281 exit 0 if $dryrun;              # From older 'config'
   1282 
   1283 $config{target} = $target;
   1284 my %target = resolve_config($target);
   1285 
   1286 foreach (keys %target_attr_translate) {
   1287     $target{$target_attr_translate{$_}} = $target{$_}
   1288         if $target{$_};
   1289     delete $target{$_};
   1290 }
   1291 
   1292 %target = ( %{$table{DEFAULTS}}, %target );
   1293 
   1294 my %conf_files = map { $_ => 1 } (@{$target{_conf_fname_int}});
   1295 $config{conf_files} = [ sort keys %conf_files ];
   1296 
   1297 # Using sub disable within these loops may prove fragile, so we run
   1298 # a cascade afterwards
   1299 foreach my $feature (@{$target{disable}}) {
   1300     if (exists $deprecated_disablables{$feature}) {
   1301         warn "***** config $target disables deprecated feature $feature\n";
   1302     } elsif (!grep { $feature eq $_ } @disablables) {
   1303         die "***** config $target disables unknown feature $feature\n";
   1304     }
   1305     $disabled{$feature} = 'config';
   1306 }
   1307 foreach my $feature (@{$target{enable}}) {
   1308     if ("default" eq ($disabled{$feature} // "")) {
   1309         if (exists $deprecated_disablables{$feature}) {
   1310             warn "***** config $target enables deprecated feature $feature\n";
   1311         } elsif (!grep { $feature eq $_ } @disablables) {
   1312             die "***** config $target enables unknown feature $feature\n";
   1313         }
   1314         delete $disabled{$feature};
   1315     }
   1316 }
   1317 
   1318 # If uplink_arch isn't defined, disable uplink
   1319 $disabled{uplink} = 'no uplink_arch' unless (defined $target{uplink_arch});
   1320 # If asm_arch isn't defined, disable asm
   1321 $disabled{asm} = 'no asm_arch' unless (defined $target{asm_arch});
   1322 
   1323 disable();                      # Run a cascade now
   1324 
   1325 $target{CXXFLAGS}//=$target{CFLAGS} if $target{CXX};
   1326 $target{cxxflags}//=$target{cflags} if $target{CXX};
   1327 $target{exe_extension}=".exe" if ($config{target} eq "DJGPP");
   1328 $target{exe_extension}=".pm"  if ($config{target} =~ /vos/);
   1329 
   1330 # Fill %config with values from %user, and in case those are undefined or
   1331 # empty, use values from %target (acting as a default).
   1332 foreach (keys %user) {
   1333     my $ref_type = ref $user{$_};
   1334 
   1335     # Temporary function.  Takes an intended ref type (empty string or "ARRAY")
   1336     # and a value that's to be coerced into that type.
   1337     my $mkvalue = sub {
   1338         my $type = shift;
   1339         my $value = shift;
   1340         my $undef_p = shift;
   1341 
   1342         die "Too many arguments for \$mkvalue" if @_;
   1343 
   1344         while (ref $value eq 'CODE') {
   1345             $value = $value->();
   1346         }
   1347 
   1348         if ($type eq 'ARRAY') {
   1349             return undef unless defined $value;
   1350             return undef if ref $value ne 'ARRAY' && !$value;
   1351             return undef if ref $value eq 'ARRAY' && !@$value;
   1352             return [ $value ] unless ref $value eq 'ARRAY';
   1353         }
   1354         return undef unless $value;
   1355         return $value;
   1356     };
   1357 
   1358     $config{$_} =
   1359         $mkvalue->($ref_type, $user{$_})
   1360         || $mkvalue->($ref_type, $target{$_});
   1361     delete $config{$_} unless defined $config{$_};
   1362 }
   1363 
   1364 # Finish up %config by appending things the user gave us on the command line
   1365 # apart from "make variables"
   1366 foreach (keys %useradd) {
   1367     # The must all be lists, so we assert that here
   1368     die "internal error: \$useradd{$_} isn't an ARRAY\n"
   1369         unless ref $useradd{$_} eq 'ARRAY';
   1370 
   1371     if (defined $config{$_}) {
   1372         push @{$config{$_}}, @{$useradd{$_}};
   1373     } else {
   1374         $config{$_} = [ @{$useradd{$_}} ];
   1375     }
   1376 }
   1377 # At this point, we can forget everything about %user and %useradd,
   1378 # because it's now all been merged into the corresponding $config entry
   1379 
   1380 if (grep { $_ =~ /(?:^|\s)-static(?:\s|$)/ } @{$config{LDFLAGS}}) {
   1381     disable('static', 'pic', 'threads');
   1382 }
   1383 
   1384 # Allow overriding the build file name
   1385 $config{build_file} = env('BUILDFILE') || $target{build_file} || "Makefile";
   1386 
   1387 # Make sure build_scheme is consistent.
   1388 $target{build_scheme} = [ $target{build_scheme} ]
   1389     if ref($target{build_scheme}) ne "ARRAY";
   1390 
   1391 my ($builder, $builder_platform, @builder_opts) =
   1392     @{$target{build_scheme}};
   1393 
   1394 foreach my $checker (($builder_platform."-".$config{build_file}."-checker.pm",
   1395                       $builder_platform."-checker.pm")) {
   1396     my $checker_path = catfile($srcdir, "Configurations", $checker);
   1397     if (-f $checker_path) {
   1398         my $fn = $ENV{CONFIGURE_CHECKER_WARN}
   1399             ? sub { warn $@; } : sub { die $@; };
   1400         if (! do $checker_path) {
   1401             if ($@) {
   1402                 $fn->($@);
   1403             } elsif ($!) {
   1404                 $fn->($!);
   1405             } else {
   1406                 $fn->("The detected tools didn't match the platform\n");
   1407             }
   1408         }
   1409         last;
   1410     }
   1411 }
   1412 
   1413 push @{$config{defines}}, "NDEBUG"    if $config{build_type} eq "release";
   1414 
   1415 if ($target =~ /^mingw/ && `$config{CC} --target-help 2>&1` =~ m/-mno-cygwin/m)
   1416         {
   1417         push @{$config{cflags}}, "-mno-cygwin";
   1418         push @{$config{cxxflags}}, "-mno-cygwin" if $config{CXX};
   1419         push @{$config{shared_ldflag}}, "-mno-cygwin";
   1420         }
   1421 
   1422 if ($target =~ /linux.*-mips/ && !$disabled{asm}
   1423         && !grep { $_ =~ /-m(ips|arch=)/ } (@{$config{CFLAGS}})) {
   1424         # minimally required architecture flags for assembly modules
   1425         my $value;
   1426         $value = '-mips2' if ($target =~ /mips32/);
   1427         $value = '-mips3' if ($target =~ /mips64/);
   1428         unshift @{$config{cflags}}, $value;
   1429         unshift @{$config{cxxflags}}, $value if $config{CXX};
   1430 }
   1431 
   1432 # If threads aren't disabled, check how possible they are
   1433 unless ($disabled{threads}) {
   1434     if ($auto_threads) {
   1435         # Enabled by default, disable it forcibly if unavailable
   1436         if ($target{thread_scheme} eq "(unknown)") {
   1437             disable("unavailable", 'threads');
   1438         }
   1439     } else {
   1440         # The user chose to enable threads explicitly, let's see
   1441         # if there's a chance that's possible
   1442         if ($target{thread_scheme} eq "(unknown)") {
   1443             # If the user asked for "threads" and we don't have internal
   1444             # knowledge how to do it, [s]he is expected to provide any
   1445             # system-dependent compiler options that are necessary.  We
   1446             # can't truly check that the given options are correct, but
   1447             # we expect the user to know what [s]He is doing.
   1448             if (!@{$config{CFLAGS}} && !@{$config{CPPDEFINES}}) {
   1449                 die "You asked for multi-threading support, but didn't\n"
   1450                     ,"provide any system-specific compiler options\n";
   1451             }
   1452         }
   1453     }
   1454 }
   1455 
   1456 # Find out if clang's sanitizers have been enabled with -fsanitize
   1457 # flags and ensure that the corresponding %disabled elements area
   1458 # removed to reflect that the sanitizers are indeed enabled.
   1459 my %detected_sanitizers = ();
   1460 foreach (grep /^-fsanitize=/, @{$config{CFLAGS} || []}) {
   1461     (my $checks = $_) =~ s/^-fsanitize=//;
   1462     foreach (split /,/, $checks) {
   1463         my $d = { address       => 'asan',
   1464                   undefined     => 'ubsan',
   1465                   memory        => 'msan' } -> {$_};
   1466         next unless defined $d;
   1467 
   1468         $detected_sanitizers{$d} = 1;
   1469         if (defined $disabled{$d}) {
   1470             die "***** Conflict between disabling $d and enabling $_ sanitizer"
   1471                 if $disabled{$d} ne "default";
   1472             delete $disabled{$d};
   1473         }
   1474     }
   1475 }
   1476 
   1477 # If threads still aren't disabled, add a C macro to ensure the source
   1478 # code knows about it.  Any other flag is taken care of by the configs.
   1479 unless($disabled{threads}) {
   1480     push @{$config{openssl_feature_defines}}, "OPENSSL_THREADS";
   1481 }
   1482 
   1483 my $no_shared_warn=0;
   1484 if (($target{shared_target} // '') eq "")
   1485         {
   1486         $no_shared_warn = 1
   1487             if (!$disabled{shared} || !$disabled{"dynamic-engine"});
   1488         disable('no-shared-target', 'pic');
   1489         }
   1490 
   1491 if ($disabled{"dynamic-engine"}) {
   1492         $config{dynamic_engines} = 0;
   1493 } else {
   1494         $config{dynamic_engines} = 1;
   1495 }
   1496 
   1497 unless ($disabled{asan} || defined $detected_sanitizers{asan}) {
   1498     push @{$config{cflags}}, "-fsanitize=address";
   1499 }
   1500 
   1501 unless ($disabled{ubsan} || defined $detected_sanitizers{ubsan}) {
   1502     push @{$config{cflags}}, "-fsanitize=undefined", "-fno-sanitize-recover=all", "-DPEDANTIC";
   1503 }
   1504 
   1505 unless ($disabled{msan} || defined $detected_sanitizers{msan}) {
   1506   push @{$config{cflags}}, "-fsanitize=memory";
   1507 }
   1508 
   1509 unless ($disabled{"fuzz-libfuzzer"} && $disabled{"fuzz-afl"}
   1510         && $disabled{asan} && $disabled{ubsan} && $disabled{msan}) {
   1511     push @{$config{cflags}}, "-fno-omit-frame-pointer", "-g";
   1512     push @{$config{cxxflags}}, "-fno-omit-frame-pointer", "-g" if $config{CXX};
   1513 }
   1514 #
   1515 # Platform fix-ups
   1516 #
   1517 
   1518 # This saves the build files from having to check
   1519 if ($disabled{pic})
   1520         {
   1521         foreach (qw(shared_cflag shared_cxxflag shared_cppflag
   1522                     shared_defines shared_includes shared_ldflag
   1523                     module_cflags module_cxxflags module_cppflags
   1524                     module_defines module_includes module_lflags))
   1525                 {
   1526                 delete $config{$_};
   1527                 $target{$_} = "";
   1528                 }
   1529         }
   1530 else
   1531         {
   1532         push @{$config{lib_defines}}, "OPENSSL_PIC";
   1533         }
   1534 
   1535 if ($target{sys_id} ne "")
   1536         {
   1537         push @{$config{openssl_sys_defines}}, "OPENSSL_SYS_$target{sys_id}";
   1538         }
   1539 
   1540 my %predefined_C = compiler_predefined($config{CROSS_COMPILE}.$config{CC});
   1541 my %predefined_CXX = $config{CXX}
   1542     ? compiler_predefined($config{CROSS_COMPILE}.$config{CXX})
   1543     : ();
   1544 
   1545 unless ($disabled{asm}) {
   1546     # big endian systems can use ELFv2 ABI
   1547     if ($target eq "linux-ppc64") {
   1548         $target{perlasm_scheme} = "linux64v2" if ($predefined_C{_CALL_ELF} == 2);
   1549     }
   1550 }
   1551 
   1552 # Check for makedepend capabilities.
   1553 if (!$disabled{makedepend}) {
   1554     # If the attribute makedep_scheme is defined, then we assume that the
   1555     # config target and its associated build file are programmed to deal
   1556     # with it.
   1557     # If makedep_scheme is undefined, we go looking for GCC compatible
   1558     # dependency making, and if that's not available, we try to fall back
   1559     # on 'makedepend'.
   1560     if ($target{makedep_scheme}) {
   1561         $config{makedep_scheme} = $target{makedep_scheme};
   1562         # If the makedepcmd attribute is defined, copy it.  If not, the
   1563         # build files will have to fend for themselves.
   1564         $config{makedepcmd} = $target{makedepcmd} if $target{makedepcmd};
   1565     } elsif (($predefined_C{__GNUC__} // -1) >= 3
   1566              && !($predefined_C{__APPLE_CC__} && !$predefined_C{__clang__})) {
   1567         # We know that GNU C version 3 and up as well as all clang
   1568         # versions support dependency generation, but Xcode did not
   1569         # handle $cc -M before clang support (but claims __GNUC__ = 3)
   1570         $config{makedep_scheme} = 'gcc';
   1571     } else {
   1572         # In all other cases, we look for 'makedepend', and set the
   1573         # makedep_scheme value if we found it.
   1574         $config{makedepcmd} = which('makedepend');
   1575         $config{makedep_scheme} = 'makedepend' if $config{makedepcmd};
   1576     }
   1577 
   1578     # If no depend scheme is set, we disable makedepend
   1579     disable('unavailable', 'makedepend') unless $config{makedep_scheme};
   1580 }
   1581 
   1582 if (!$disabled{asm} && !$predefined_C{__MACH__} && $^O ne 'VMS') {
   1583     # probe for -Wa,--noexecstack option...
   1584     if ($predefined_C{__clang__}) {
   1585         # clang has builtin assembler, which doesn't recognize --help,
   1586         # but it apparently recognizes the option in question on all
   1587         # supported platforms even when it's meaningless. In other words
   1588         # probe would fail, but probed option always accepted...
   1589         push @{$config{cflags}}, "-Wa,--noexecstack", "-Qunused-arguments";
   1590     } else {
   1591         my $cc = $config{CROSS_COMPILE}.$config{CC};
   1592         open(PIPE, "$cc -Wa,--help -c -o null.$$.o -x assembler /dev/null 2>&1 |");
   1593         while(<PIPE>) {
   1594             if (m/--noexecstack/) {
   1595                 push @{$config{cflags}}, "-Wa,--noexecstack";
   1596                 last;
   1597             }
   1598         }
   1599         close(PIPE);
   1600         unlink("null.$$.o");
   1601     }
   1602 }
   1603 
   1604 # Deal with bn_ops ###################################################
   1605 
   1606 $config{bn_ll}                  =0;
   1607 my $def_int="unsigned int";
   1608 $config{rc4_int}                =$def_int;
   1609 ($config{b64l},$config{b64},$config{b32})=(0,0,1);
   1610 
   1611 my $count = 0;
   1612 foreach (sort split(/\s+/,$target{bn_ops})) {
   1613     $count++ if /SIXTY_FOUR_BIT|SIXTY_FOUR_BIT_LONG|THIRTY_TWO_BIT/;
   1614     $config{bn_ll}=1                            if $_ eq 'BN_LLONG';
   1615     $config{rc4_int}="unsigned char"            if $_ eq 'RC4_CHAR';
   1616     ($config{b64l},$config{b64},$config{b32})
   1617         =(0,1,0)                                if $_ eq 'SIXTY_FOUR_BIT';
   1618     ($config{b64l},$config{b64},$config{b32})
   1619         =(1,0,0)                                if $_ eq 'SIXTY_FOUR_BIT_LONG';
   1620     ($config{b64l},$config{b64},$config{b32})
   1621         =(0,0,1)                                if $_ eq 'THIRTY_TWO_BIT';
   1622 }
   1623 die "Exactly one of SIXTY_FOUR_BIT|SIXTY_FOUR_BIT_LONG|THIRTY_TWO_BIT can be set in bn_ops\n"
   1624     if $count > 1;
   1625 
   1626 $config{api} = $config{major} * 10000 + $config{minor} * 100
   1627     unless $config{api};
   1628 foreach (keys %$apitable) {
   1629     $disabled{"deprecated-$_"} = "deprecation"
   1630         if $disabled{deprecated} && $config{api} >= $apitable->{$_};
   1631 }
   1632 
   1633 disable();                      # Run a cascade now
   1634 
   1635 # Hack cflags for better warnings (dev option) #######################
   1636 
   1637 # "Stringify" the C and C++ flags string.  This permits it to be made part of
   1638 # a string and works as well on command lines.
   1639 $config{cflags} = [ map { (my $x = $_) =~ s/([\\\"])/\\$1/g; $x }
   1640                         @{$config{cflags}} ];
   1641 $config{cxxflags} = [ map { (my $x = $_) =~ s/([\\\"])/\\$1/g; $x }
   1642                           @{$config{cxxflags}} ] if $config{CXX};
   1643 
   1644 $config{openssl_api_defines} = [
   1645     "OPENSSL_CONFIGURED_API=".$config{api},
   1646 ];
   1647 
   1648 my @strict_warnings_collection=();
   1649 if ($strict_warnings)
   1650         {
   1651         my $wopt;
   1652         my $gccver = $predefined_C{__GNUC__} // -1;
   1653 
   1654         if ($gccver >= 4)
   1655                 {
   1656                 push @strict_warnings_collection, @gcc_devteam_warn;
   1657                 push @strict_warnings_collection, @clang_devteam_warn
   1658                     if (defined($predefined_C{__clang__}));
   1659                 }
   1660         elsif ($config{target} =~ /^VC-/)
   1661                 {
   1662                 push @strict_warnings_collection, @cl_devteam_warn;
   1663                 }
   1664         else
   1665                 {
   1666                 warn "WARNING --strict-warnings requires gcc[>=4] or gcc-alike, or MSVC"
   1667                 }
   1668         }
   1669 
   1670 $config{CFLAGS} = [ map { $_ eq '--ossl-strict-warnings'
   1671                               ? @strict_warnings_collection
   1672                               : ( $_ ) }
   1673                     @{$config{CFLAGS}} ];
   1674 
   1675 unless ($disabled{afalgeng}) {
   1676     $config{afalgeng}="";
   1677     if (grep { $_ eq 'afalgeng' } @{$target{enable}}) {
   1678         my $minver = 4*10000 + 1*100 + 0;
   1679         if ($config{CROSS_COMPILE} eq "") {
   1680             my $verstr = `uname -r`;
   1681             my ($ma, $mi1, $mi2) = split("\\.", $verstr);
   1682             ($mi2) = $mi2 =~ /(\d+)/;
   1683             my $ver = $ma*10000 + $mi1*100 + $mi2;
   1684             if ($ver < $minver) {
   1685                 disable('too-old-kernel', 'afalgeng');
   1686             } else {
   1687                 push @{$config{engdirs}}, "afalg";
   1688             }
   1689         } else {
   1690             disable('cross-compiling', 'afalgeng');
   1691         }
   1692     } else {
   1693         disable('not-linux', 'afalgeng');
   1694     }
   1695 }
   1696 
   1697 unless ($disabled{devcryptoeng}) {
   1698     if ($target =~ m/^BSD/) {
   1699         my $maxver = 5*100 + 7;
   1700         my $sysstr = `uname -s`;
   1701         my $verstr = `uname -r`;
   1702         $sysstr =~ s|\R$||;
   1703         $verstr =~ s|\R$||;
   1704         my ($ma, $mi, @rest) = split m|\.|, $verstr;
   1705         my $ver = $ma*100 + $mi;
   1706         if ($sysstr eq 'OpenBSD' && $ver >= $maxver) {
   1707             disable('too-new-kernel', 'devcryptoeng');
   1708         }
   1709     }
   1710 }
   1711 
   1712 unless ($disabled{ktls}) {
   1713     $config{ktls}="";
   1714     my $cc = $config{CROSS_COMPILE}.$config{CC};
   1715     if ($target =~ m/^linux/) {
   1716         system("printf '#include <sys/types.h>\n#include <linux/tls.h>' | $cc -E - >/dev/null 2>&1");
   1717         if ($? != 0) {
   1718             disable('too-old-kernel', 'ktls');
   1719         }
   1720     } elsif ($target =~ m/^BSD/) {
   1721         system("printf '#include <sys/types.h>\n#include <sys/ktls.h>' | $cc -E - >/dev/null 2>&1");
   1722         if ($? != 0) {
   1723             disable('too-old-freebsd', 'ktls');
   1724         }
   1725     } else {
   1726         disable('not-linux-or-freebsd', 'ktls');
   1727     }
   1728 }
   1729 
   1730 push @{$config{openssl_other_defines}}, "OPENSSL_NO_KTLS" if ($disabled{ktls});
   1731 
   1732 # Get the extra flags used when building shared libraries and modules.  We
   1733 # do this late because some of them depend on %disabled.
   1734 
   1735 # Make the flags to build DSOs the same as for shared libraries unless they
   1736 # are already defined
   1737 $target{module_cflags} = $target{shared_cflag} unless defined $target{module_cflags};
   1738 $target{module_cxxflags} = $target{shared_cxxflag} unless defined $target{module_cxxflags};
   1739 $target{module_ldflags} = $target{shared_ldflag} unless defined $target{module_ldflags};
   1740 {
   1741     my $shared_info_pl =
   1742         catfile(dirname($0), "Configurations", "shared-info.pl");
   1743     my %shared_info = read_eval_file($shared_info_pl);
   1744     push @{$target{_conf_fname_int}}, $shared_info_pl;
   1745     my $si = $target{shared_target};
   1746     while (ref $si ne "HASH") {
   1747         last if ! defined $si;
   1748         if (ref $si eq "CODE") {
   1749             $si = $si->();
   1750         } else {
   1751             $si = $shared_info{$si};
   1752         }
   1753     }
   1754 
   1755     # Some of the 'shared_target' values don't have any entries in
   1756     # %shared_info.  That's perfectly fine, AS LONG AS the build file
   1757     # template knows how to handle this.  That is currently the case for
   1758     # Windows and VMS.
   1759     if (defined $si) {
   1760         # Just as above, copy certain shared_* attributes to the corresponding
   1761         # module_ attribute unless the latter is already defined
   1762         $si->{module_cflags} = $si->{shared_cflag} unless defined $si->{module_cflags};
   1763         $si->{module_cxxflags} = $si->{shared_cxxflag} unless defined $si->{module_cxxflags};
   1764         $si->{module_ldflags} = $si->{shared_ldflag} unless defined $si->{module_ldflags};
   1765         foreach (sort keys %$si) {
   1766             $target{$_} = defined $target{$_}
   1767                 ? add($si->{$_})->($target{$_})
   1768                 : $si->{$_};
   1769         }
   1770     }
   1771 }
   1772 
   1773 # ALL MODIFICATIONS TO %disabled, %config and %target MUST BE DONE FROM HERE ON
   1774 
   1775 ######################################################################
   1776 # Build up information for skipping certain directories depending on disabled
   1777 # features, as well as setting up macros for disabled features.
   1778 
   1779 # This is a tentative database of directories to skip.  Some entries may not
   1780 # correspond to anything real, but that's ok, they will simply be ignored.
   1781 # The actual processing of these entries is done in the build.info lookup
   1782 # loop further down.
   1783 #
   1784 # The key is a Unix formatted path in the source tree, the value is an index
   1785 # into %disabled_info, so any existing path gets added to a corresponding
   1786 # 'skipped' entry in there with the list of skipped directories.
   1787 my %skipdir = ();
   1788 my %disabled_info = ();         # For configdata.pm
   1789 foreach my $what (sort keys %disabled) {
   1790     # There are deprecated disablables that translate to themselves.
   1791     # They cause disabling cascades, but should otherwise not regiter.
   1792     next if $deprecated_disablables{$what};
   1793     # The generated $disabled{"deprecated-x.y"} entries are special
   1794     # and treated properly elsewhere
   1795     next if $what =~ m|^deprecated-|;
   1796 
   1797     $config{options} .= " no-$what";
   1798 
   1799     if (!grep { $what eq $_ } ( 'buildtest-c++', 'fips', 'threads', 'shared',
   1800                                 'module', 'pic', 'dynamic-engine', 'makedepend',
   1801                                 'zlib-dynamic', 'zlib', 'sse2', 'legacy' )) {
   1802         (my $WHAT = uc $what) =~ s|-|_|g;
   1803         my $skipdir = $what;
   1804 
   1805         # fix-up crypto/directory name(s)
   1806         $skipdir = "ripemd" if $what eq "rmd160";
   1807         $skipdir = "whrlpool" if $what eq "whirlpool";
   1808 
   1809         my $macro = $disabled_info{$what}->{macro} = "OPENSSL_NO_$WHAT";
   1810         push @{$config{openssl_feature_defines}}, $macro;
   1811 
   1812         $skipdir{engines} = $what if $what eq 'engine';
   1813         $skipdir{"crypto/$skipdir"} = $what
   1814             unless $what eq 'async' || $what eq 'err' || $what eq 'dso';
   1815     }
   1816 }
   1817 
   1818 if ($disabled{"dynamic-engine"}) {
   1819     push @{$config{openssl_feature_defines}}, "OPENSSL_NO_DYNAMIC_ENGINE";
   1820 } else {
   1821     push @{$config{openssl_feature_defines}}, "OPENSSL_NO_STATIC_ENGINE";
   1822 }
   1823 
   1824 # If we use the unified build, collect information from build.info files
   1825 my %unified_info = ();
   1826 
   1827 my $buildinfo_debug = defined($ENV{CONFIGURE_DEBUG_BUILDINFO});
   1828 if ($builder eq "unified") {
   1829     use Text::Template 1.46;
   1830 
   1831     sub cleandir {
   1832         my $base = shift;
   1833         my $dir = shift;
   1834         my $relativeto = shift || ".";
   1835 
   1836         $dir = catdir($base,$dir) unless isabsolute($dir);
   1837 
   1838         # Make sure the directories we're building in exists
   1839         mkpath($dir);
   1840 
   1841         my $res = abs2rel(absolutedir($dir), rel2abs($relativeto));
   1842         #print STDERR "DEBUG[cleandir]: $dir , $base => $res\n";
   1843         return $res;
   1844     }
   1845 
   1846     sub cleanfile {
   1847         my $base = shift;
   1848         my $file = shift;
   1849         my $relativeto = shift || ".";
   1850 
   1851         $file = catfile($base,$file) unless isabsolute($file);
   1852 
   1853         my $d = dirname($file);
   1854         my $f = basename($file);
   1855 
   1856         # Make sure the directories we're building in exists
   1857         mkpath($d);
   1858 
   1859         my $res = abs2rel(catfile(absolutedir($d), $f), rel2abs($relativeto));
   1860         #print STDERR "DEBUG[cleanfile]: $d , $f => $res\n";
   1861         return $res;
   1862     }
   1863 
   1864     # Store the name of the template file we will build the build file from
   1865     # in %config.  This may be useful for the build file itself.
   1866     my @build_file_template_names =
   1867         ( $builder_platform."-".$config{build_file}.".tmpl",
   1868           $config{build_file}.".tmpl" );
   1869     my @build_file_templates = ();
   1870 
   1871     # First, look in the user provided directory, if given
   1872     if (defined env($local_config_envname)) {
   1873         @build_file_templates =
   1874             map {
   1875                 if ($^O eq 'VMS') {
   1876                     # VMS environment variables are logical names,
   1877                     # which can be used as is
   1878                     $local_config_envname . ':' . $_;
   1879                 } else {
   1880                     catfile(env($local_config_envname), $_);
   1881                 }
   1882             }
   1883             @build_file_template_names;
   1884     }
   1885     # Then, look in our standard directory
   1886     push @build_file_templates,
   1887         ( map { cleanfile($srcdir, catfile("Configurations", $_), $blddir) }
   1888           @build_file_template_names );
   1889 
   1890     my $build_file_template;
   1891     for $_ (@build_file_templates) {
   1892         $build_file_template = $_;
   1893         last if -f $build_file_template;
   1894 
   1895         $build_file_template = undef;
   1896     }
   1897     if (!defined $build_file_template) {
   1898         die "*** Couldn't find any of:\n", join("\n", @build_file_templates), "\n";
   1899     }
   1900     $config{build_file_templates}
   1901       = [ cleanfile($srcdir, catfile("Configurations", "common0.tmpl"),
   1902                     $blddir),
   1903            $build_file_template ];
   1904 
   1905     my @build_dirs = ( [ ] );   # current directory
   1906 
   1907     $config{build_infos} = [ ];
   1908 
   1909     # We want to detect configdata.pm in the source tree, so we
   1910     # don't use it if the build tree is different.
   1911     my $src_configdata = cleanfile($srcdir, "configdata.pm", $blddir);
   1912 
   1913     # Any source file that we recognise is placed in this hash table, with
   1914     # the list of its intended destinations as value.  When everything has
   1915     # been collected, there's a routine that checks that these source files
   1916     # exist, or if they are generated, that the generator exists.
   1917     my %check_exist = ();
   1918     my %check_generate = ();
   1919 
   1920     my %ordinals = ();
   1921     while (@build_dirs) {
   1922         my @curd = @{shift @build_dirs};
   1923         my $sourced = catdir($srcdir, @curd);
   1924         my $buildd = catdir($blddir, @curd);
   1925 
   1926         my $unixdir = join('/', @curd);
   1927         if (exists $skipdir{$unixdir}) {
   1928             my $what = $skipdir{$unixdir};
   1929             push @{$disabled_info{$what}->{skipped}}, catdir(@curd);
   1930             next;
   1931         }
   1932 
   1933         mkpath($buildd);
   1934 
   1935         my $f = 'build.info';
   1936         # The basic things we're trying to build
   1937         my @programs = ();
   1938         my @libraries = ();
   1939         my @modules = ();
   1940         my @scripts = ();
   1941 
   1942         my %sources = ();
   1943         my %shared_sources = ();
   1944         my %includes = ();
   1945         my %defines = ();
   1946         my %depends = ();
   1947         my %generate = ();
   1948         my %imagedocs = ();
   1949         my %htmldocs = ();
   1950         my %mandocs = ();
   1951 
   1952         # Support for $variablename in build.info files.
   1953         # Embedded perl code is the ultimate master, still.  If its output
   1954         # contains a dollar sign, it had better be escaped, or it will be
   1955         # taken for a variable name prefix.
   1956         my %variables = ();
   1957         # Variable name syntax
   1958         my $variable_name_re = qr/(?P<VARIABLE>[[:alpha:]][[:alnum:]_]*)/;
   1959         # Value modifier syntaxes
   1960         my $variable_subst_re = qr/\/(?P<RE>(?:\\\/|.)*?)\/(?P<SUBST>.*?)/;
   1961         # Variable reference
   1962         my $variable_simple_re = qr/(?<!\\)\$${variable_name_re}/;
   1963         my $variable_w_mod_re =
   1964             qr/(?<!\\)\$\{${variable_name_re}(?P<MOD>(?:\\\/|.)*?)\}/;
   1965         # Tie it all together
   1966         my $variable_re = qr/${variable_simple_re}|${variable_w_mod_re}/;
   1967 
   1968         my $expand_variables = sub {
   1969             my $value = '';
   1970             my $value_rest = shift;
   1971 
   1972             if ($ENV{CONFIGURE_DEBUG_VARIABLE_EXPAND}) {
   1973                 print STDERR
   1974                     "DEBUG[\$expand_variables] Parsed '$value_rest' ...\n"
   1975             }
   1976 
   1977             while ($value_rest =~ /${variable_re}/) {
   1978                 # We must save important regexp values, because the next
   1979                 # regexp clears them
   1980                 my $mod = $+{MOD};
   1981                 my $variable_value = $variables{$+{VARIABLE}};
   1982 
   1983                 $value_rest = $';
   1984                 $value .= $`;
   1985 
   1986                 # Process modifier expressions, if present
   1987                 if (defined $mod) {
   1988                     if ($mod =~ /^${variable_subst_re}$/) {
   1989                         my $re = $+{RE};
   1990                         my $subst = $+{SUBST};
   1991 
   1992                         $variable_value =~ s/\Q$re\E/$subst/g;
   1993 
   1994                         if ($ENV{CONFIGURE_DEBUG_VARIABLE_EXPAND}) {
   1995                             print STDERR
   1996                                 "DEBUG[\$expand_variables] ... and substituted ",
   1997                                 "'$re' with '$subst'\n";
   1998                         }
   1999                     }
   2000                 }
   2001 
   2002                 $value .= $variable_value;
   2003             }
   2004             if ($ENV{CONFIGURE_DEBUG_VARIABLE_EXPAND}) {
   2005                 print STDERR
   2006                     "DEBUG[\$expand_variables] ... into: '$value$value_rest'\n";
   2007             }
   2008             return $value . $value_rest;
   2009         };
   2010 
   2011         # Support for attributes in build.info files
   2012         my %attributes = ();
   2013         my $handle_attributes = sub {
   2014             my $attr_str = shift;
   2015             my $ref = shift;
   2016             my @goals = @_;
   2017 
   2018             return unless defined $attr_str;
   2019 
   2020             my @a = tokenize($attr_str, qr|\s*,\s*|);
   2021             foreach my $a (@a) {
   2022                 my $ac = 1;
   2023                 my $ak = $a;
   2024                 my $av = 1;
   2025                 if ($a =~ m|^(!)?(.*?)\s* = \s*(.*?)$|x) {
   2026                     $ac = ! $1;
   2027                     $ak = $2;
   2028                     $av = $3;
   2029                 }
   2030                 foreach my $g (@goals) {
   2031                     if ($ac) {
   2032                         $$ref->{$g}->{$ak} = $av;
   2033                     } else {
   2034                         delete $$ref->{$g}->{$ak};
   2035                     }
   2036                 }
   2037             }
   2038         };
   2039 
   2040         # Support for pushing values on multiple indexes of a given hash
   2041         # array.
   2042         my $push_to = sub {
   2043             my $valueref = shift;
   2044             my $index_str = shift; # May be undef or empty
   2045             my $attrref = shift;   # May be undef
   2046             my $attr_str = shift;
   2047             my @values = @_;
   2048 
   2049             if (defined $index_str) {
   2050                 my @indexes = ( '' );
   2051                 if ($index_str !~ m|^\s*$|) {
   2052                     @indexes = tokenize($index_str);
   2053                 }
   2054                 foreach (@indexes) {
   2055                     push @{$valueref->{$_}}, @values;
   2056                     if (defined $attrref) {
   2057                         $handle_attributes->($attr_str, \$$attrref->{$_},
   2058                                              @values);
   2059                     }
   2060                 }
   2061             } else {
   2062                 push @$valueref, @values;
   2063                 $handle_attributes->($attr_str, $attrref, @values)
   2064                     if defined $attrref;
   2065             }
   2066         };
   2067 
   2068         if ($buildinfo_debug) {
   2069             print STDERR "DEBUG: Reading ",catfile($sourced, $f),"\n";
   2070         }
   2071         push @{$config{build_infos}}, catfile(abs2rel($sourced, $blddir), $f);
   2072         my $template =
   2073             Text::Template->new(TYPE => 'FILE',
   2074                                 SOURCE => catfile($sourced, $f),
   2075                                 PREPEND => qq{use lib "$FindBin::Bin/util/perl";});
   2076         die "Something went wrong with $sourced/$f: $!\n" unless $template;
   2077         my @text =
   2078             split /^/m,
   2079             $template->fill_in(HASH => { config => \%config,
   2080                                          target => \%target,
   2081                                          disabled => \%disabled,
   2082                                          withargs => \%withargs,
   2083                                          builddir => abs2rel($buildd, $blddir),
   2084                                          sourcedir => abs2rel($sourced, $blddir),
   2085                                          buildtop => abs2rel($blddir, $blddir),
   2086                                          sourcetop => abs2rel($srcdir, $blddir) },
   2087                                DELIMITERS => [ "{-", "-}" ]);
   2088 
   2089         # The top item of this stack has the following values
   2090         # -2 positive already run and we found ELSE (following ELSIF should fail)
   2091         # -1 positive already run (skip until ENDIF)
   2092         # 0 negatives so far (if we're at a condition, check it)
   2093         # 1 last was positive (don't skip lines until next ELSE, ELSIF or ENDIF)
   2094         # 2 positive ELSE (following ELSIF should fail)
   2095         my @skip = ();
   2096 
   2097         # A few useful generic regexps
   2098         my $index_re = qr/\[\s*(?P<INDEX>(?:\\.|.)*?)\s*\]/;
   2099         my $cond_re = qr/\[\s*(?P<COND>(?:\\.|.)*?)\s*\]/;
   2100         my $attribs_re = qr/(?:\{\s*(?P<ATTRIBS>(?:\\.|.)*?)\s*\})?/;
   2101         my $value_re = qr/(?P<VALUE>.*?)/;
   2102         collect_information(
   2103             collect_from_array([ @text ],
   2104                                qr/\\$/ => sub { my $l1 = shift; my $l2 = shift;
   2105                                                 $l1 =~ s/\\$//; $l1.$l2 }),
   2106             # Info we're looking for
   2107             qr/^\s* IF ${cond_re} \s*$/x
   2108             => sub {
   2109                 if (! @skip || $skip[$#skip] > 0) {
   2110                     push @skip, !! $expand_variables->($+{COND});
   2111                 } else {
   2112                     push @skip, -1;
   2113                 }
   2114             },
   2115             qr/^\s* ELSIF ${cond_re} \s*$/x
   2116             => sub { die "ELSIF out of scope" if ! @skip;
   2117                      die "ELSIF following ELSE" if abs($skip[$#skip]) == 2;
   2118                      $skip[$#skip] = -1 if $skip[$#skip] != 0;
   2119                      $skip[$#skip] = !! $expand_variables->($+{COND})
   2120                          if $skip[$#skip] == 0; },
   2121             qr/^\s* ELSE \s*$/x
   2122             => sub { die "ELSE out of scope" if ! @skip;
   2123                      $skip[$#skip] = -2 if $skip[$#skip] != 0;
   2124                      $skip[$#skip] = 2 if $skip[$#skip] == 0; },
   2125             qr/^\s* ENDIF \s*$/x
   2126             => sub { die "ENDIF out of scope" if ! @skip;
   2127                      pop @skip; },
   2128             qr/^\s* ${variable_re} \s* = \s* ${value_re} \s* $/x
   2129             => sub {
   2130                 if (!@skip || $skip[$#skip] > 0) {
   2131                     $variables{$+{VARIABLE}} = $expand_variables->($+{VALUE});
   2132                 }
   2133             },
   2134             qr/^\s* SUBDIRS \s* = \s* ${value_re} \s* $/x
   2135             => sub {
   2136                 if (!@skip || $skip[$#skip] > 0) {
   2137                     foreach (tokenize($expand_variables->($+{VALUE}))) {
   2138                         push @build_dirs, [ @curd, splitdir($_, 1) ];
   2139                     }
   2140                 }
   2141             },
   2142             qr/^\s* PROGRAMS ${attribs_re} \s* =  \s* ${value_re} \s* $/x
   2143             => sub { $push_to->(\@programs, undef,
   2144                                 \$attributes{programs}, $+{ATTRIBS},
   2145                                 tokenize($expand_variables->($+{VALUE})))
   2146                          if !@skip || $skip[$#skip] > 0; },
   2147             qr/^\s* LIBS ${attribs_re} \s* =  \s* ${value_re} \s* $/x
   2148             => sub { $push_to->(\@libraries, undef,
   2149                                 \$attributes{libraries}, $+{ATTRIBS},
   2150                                 tokenize($expand_variables->($+{VALUE})))
   2151                          if !@skip || $skip[$#skip] > 0; },
   2152             qr/^\s* MODULES ${attribs_re} \s* =  \s* ${value_re} \s* $/x
   2153             => sub { $push_to->(\@modules, undef,
   2154                                 \$attributes{modules}, $+{ATTRIBS},
   2155                                 tokenize($expand_variables->($+{VALUE})))
   2156                          if !@skip || $skip[$#skip] > 0; },
   2157             qr/^\s* SCRIPTS ${attribs_re} \s* = \s* ${value_re} \s* $/x
   2158             => sub { $push_to->(\@scripts, undef,
   2159                                 \$attributes{scripts}, $+{ATTRIBS},
   2160                                 tokenize($expand_variables->($+{VALUE})))
   2161                          if !@skip || $skip[$#skip] > 0; },
   2162             qr/^\s* IMAGEDOCS ${index_re} \s* = \s* ${value_re} \s* $/x
   2163             => sub { $push_to->(\%imagedocs, $expand_variables->($+{INDEX}),
   2164                                 undef, undef,
   2165                                 tokenize($expand_variables->($+{VALUE})))
   2166                          if !@skip || $skip[$#skip] > 0; },
   2167             qr/^\s* HTMLDOCS ${index_re} \s* = \s* ${value_re} \s* $/x
   2168             => sub { $push_to->(\%htmldocs, $expand_variables->($+{INDEX}),
   2169                                 undef, undef,
   2170                                 tokenize($expand_variables->($+{VALUE})))
   2171                          if !@skip || $skip[$#skip] > 0; },
   2172             qr/^\s* MANDOCS ${index_re} \s* = \s* ${value_re} \s* $/x
   2173             => sub { $push_to->(\%mandocs, $expand_variables->($+{INDEX}),
   2174                                 undef, undef,
   2175                                 tokenize($expand_variables->($+{VALUE})))
   2176                          if !@skip || $skip[$#skip] > 0; },
   2177             qr/^\s* SOURCE ${index_re} ${attribs_re} \s* = \s* ${value_re} \s* $/x
   2178             => sub { $push_to->(\%sources, $expand_variables->($+{INDEX}),
   2179                                 \$attributes{sources}, $+{ATTRIBS},
   2180                                 tokenize($expand_variables->($+{VALUE})))
   2181                          if !@skip || $skip[$#skip] > 0; },
   2182             qr/^\s* SHARED_SOURCE ${index_re} ${attribs_re} \s* = \s* ${value_re} \s* $/x
   2183             => sub { $push_to->(\%shared_sources, $expand_variables->($+{INDEX}),
   2184                                 \$attributes{sources}, $+{ATTRIBS},
   2185                                 tokenize($expand_variables->($+{VALUE})))
   2186                          if !@skip || $skip[$#skip] > 0; },
   2187             qr/^\s* INCLUDE ${index_re} \s* = \s* ${value_re} \s* $/x
   2188             => sub { $push_to->(\%includes, $expand_variables->($+{INDEX}),
   2189                                 undef, undef,
   2190                                 tokenize($expand_variables->($+{VALUE})))
   2191                          if !@skip || $skip[$#skip] > 0; },
   2192             qr/^\s* DEFINE ${index_re} \s* = \s* ${value_re} \s* $/x
   2193             => sub { $push_to->(\%defines, $expand_variables->($+{INDEX}),
   2194                                 undef, undef,
   2195                                 tokenize($expand_variables->($+{VALUE})))
   2196                          if !@skip || $skip[$#skip] > 0; },
   2197             qr/^\s* DEPEND ${index_re} ${attribs_re} \s* = \s* ${value_re} \s* $/x
   2198             => sub { $push_to->(\%depends, $expand_variables->($+{INDEX}),
   2199                                 \$attributes{depends}, $+{ATTRIBS},
   2200                                 tokenize($expand_variables->($+{VALUE})))
   2201                          if !@skip || $skip[$#skip] > 0; },
   2202             qr/^\s* GENERATE ${index_re} ${attribs_re} \s* = \s* ${value_re} \s* $/x
   2203             => sub { $push_to->(\%generate, $expand_variables->($+{INDEX}),
   2204                                 \$attributes{generate}, $+{ATTRIBS},
   2205                                 $expand_variables->($+{VALUE}))
   2206                          if !@skip || $skip[$#skip] > 0; },
   2207             qr/^\s* (?:\#.*)? $/x => sub { },
   2208             "OTHERWISE" => sub { die "Something wrong with this line:\n$_\nat $sourced/$f" },
   2209             "BEFORE" => sub {
   2210                 if ($buildinfo_debug) {
   2211                     print STDERR "DEBUG: Parsing ",join(" ", @_),"\n";
   2212                     print STDERR "DEBUG: ... before parsing, skip stack is ",join(" ", map { int($_) } @skip),"\n";
   2213                 }
   2214             },
   2215             "AFTER" => sub {
   2216                 if ($buildinfo_debug) {
   2217                     print STDERR "DEBUG: .... after parsing, skip stack is ",join(" ", map { int($_) } @skip),"\n";
   2218                 }
   2219             },
   2220             );
   2221         die "runaway IF?" if (@skip);
   2222 
   2223         if (grep { defined $attributes{modules}->{$_}->{engine} } keys %attributes
   2224                 and !$config{dynamic_engines}) {
   2225             die <<"EOF"
   2226 ENGINES can only be used if configured with 'dynamic-engine'.
   2227 This is usually a fault in a build.info file.
   2228 EOF
   2229         }
   2230 
   2231         {
   2232             my %infos = ( programs  => [ @programs  ],
   2233                           libraries => [ @libraries ],
   2234                           modules   => [ @modules   ],
   2235                           scripts   => [ @scripts   ] );
   2236             foreach my $k (keys %infos) {
   2237                 foreach (@{$infos{$k}}) {
   2238                     my $item = cleanfile($buildd, $_, $blddir);
   2239                     $unified_info{$k}->{$item} = 1;
   2240 
   2241                     # Fix up associated attributes
   2242                     $unified_info{attributes}->{$k}->{$item} =
   2243                         $attributes{$k}->{$_}
   2244                         if defined $attributes{$k}->{$_};
   2245                 }
   2246             }
   2247         }
   2248 
   2249         # Check that we haven't defined any library as both shared and
   2250         # explicitly static.  That is forbidden.
   2251         my @doubles = ();
   2252         foreach (grep /\.a$/, keys %{$unified_info{libraries}}) {
   2253             (my $l = $_) =~ s/\.a$//;
   2254             push @doubles, $l if defined $unified_info{libraries}->{$l};
   2255         }
   2256         die "these libraries are both explicitly static and shared:\n  ",
   2257             join(" ", @doubles), "\n"
   2258             if @doubles;
   2259 
   2260         foreach (keys %sources) {
   2261             my $dest = $_;
   2262             my $ddest = cleanfile($buildd, $_, $blddir);
   2263             foreach (@{$sources{$dest}}) {
   2264                 my $s = cleanfile($sourced, $_, $blddir);
   2265 
   2266                 # If it's generated or we simply don't find it in the source
   2267                 # tree, we assume it's in the build tree.
   2268                 if ($s eq $src_configdata || $generate{$_} || ! -f $s) {
   2269                     $s = cleanfile($buildd, $_, $blddir);
   2270                 }
   2271                 my $o = $_;
   2272                 # We recognise C++, C and asm files
   2273                 if ($s =~ /\.(cc|cpp|c|s|S)$/) {
   2274                     push @{$check_exist{$s}}, $ddest;
   2275                     $o =~ s/\.[csS]$/.o/; # C and assembler
   2276                     $o =~ s/\.(cc|cpp)$/_cc.o/; # C++
   2277                     $o = cleanfile($buildd, $o, $blddir);
   2278                     $unified_info{sources}->{$ddest}->{$o} = -1;
   2279                     $unified_info{sources}->{$o}->{$s} = -1;
   2280                 } elsif ($s =~ /\.rc$/) {
   2281                     # We also recognise resource files
   2282                     push @{$check_exist{$s}}, $ddest;
   2283                     $o =~ s/\.rc$/.res/; # Resource configuration
   2284                     $o = cleanfile($buildd, $o, $blddir);
   2285                     $unified_info{sources}->{$ddest}->{$o} = -1;
   2286                     $unified_info{sources}->{$o}->{$s} = -1;
   2287                 } else {
   2288                     push @{$check_exist{$s}}, $ddest;
   2289                     $unified_info{sources}->{$ddest}->{$s} = 1;
   2290                 }
   2291                 # Fix up associated attributes
   2292                 if ($o ne $_) {
   2293                     $unified_info{attributes}->{sources}->{$ddest}->{$o} =
   2294                         $unified_info{attributes}->{sources}->{$o}->{$s} =
   2295                         $attributes{sources}->{$dest}->{$_}
   2296                         if defined $attributes{sources}->{$dest}->{$_};
   2297                 } else {
   2298                     $unified_info{attributes}->{sources}->{$ddest}->{$s} =
   2299                         $attributes{sources}->{$dest}->{$_}
   2300                         if defined $attributes{sources}->{$dest}->{$_};
   2301                 }
   2302             }
   2303         }
   2304 
   2305         foreach (keys %shared_sources) {
   2306             my $dest = $_;
   2307             my $ddest = cleanfile($buildd, $_, $blddir);
   2308             foreach (@{$shared_sources{$dest}}) {
   2309                 my $s = cleanfile($sourced, $_, $blddir);
   2310 
   2311                 # If it's generated or we simply don't find it in the source
   2312                 # tree, we assume it's in the build tree.
   2313                 if ($s eq $src_configdata || $generate{$_} || ! -f $s) {
   2314                     $s = cleanfile($buildd, $_, $blddir);
   2315                 }
   2316 
   2317                 my $o = $_;
   2318                 if ($s =~ /\.(cc|cpp|c|s|S)$/) {
   2319                     # We recognise C++, C and asm files
   2320                     push @{$check_exist{$s}}, $ddest;
   2321                     $o =~ s/\.[csS]$/.o/; # C and assembler
   2322                     $o =~ s/\.(cc|cpp)$/_cc.o/; # C++
   2323                     $o = cleanfile($buildd, $o, $blddir);
   2324                     $unified_info{shared_sources}->{$ddest}->{$o} = -1;
   2325                     $unified_info{sources}->{$o}->{$s} = -1;
   2326                 } elsif ($s =~ /\.rc$/) {
   2327                     # We also recognise resource files
   2328                     push @{$check_exist{$s}}, $ddest;
   2329                     $o =~ s/\.rc$/.res/; # Resource configuration
   2330                     $o = cleanfile($buildd, $o, $blddir);
   2331                     $unified_info{shared_sources}->{$ddest}->{$o} = -1;
   2332                     $unified_info{sources}->{$o}->{$s} = -1;
   2333                 } elsif ($s =~ /\.ld$/) {
   2334                     # We also recognise linker scripts (or corresponding)
   2335                     # We know they are generated files
   2336                     push @{$check_exist{$s}}, $ddest;
   2337                     $o = cleanfile($buildd, $_, $blddir);
   2338                     $unified_info{shared_sources}->{$ddest}->{$o} = 1;
   2339                 } else {
   2340                     die "unrecognised source file type for shared library: $s\n";
   2341                 }
   2342                 # Fix up associated attributes
   2343                 if ($o ne $_) {
   2344                     $unified_info{attributes}->{shared_sources}->{$ddest}->{$o} =
   2345                         $unified_info{attributes}->{sources}->{$o}->{$s} =
   2346                         $attributes{sources}->{$dest}->{$_}
   2347                         if defined $attributes{sources}->{$dest}->{$_};
   2348                 } else {
   2349                     $unified_info{attributes}->{shared_sources}->{$ddest}->{$o} =
   2350                         $attributes{sources}->{$dest}->{$_}
   2351                         if defined $attributes{sources}->{$dest}->{$_};
   2352                 }
   2353             }
   2354         }
   2355 
   2356         foreach (keys %generate) {
   2357             my $dest = $_;
   2358             my $ddest = cleanfile($buildd, $_, $blddir);
   2359             die "more than one generator for $dest: "
   2360                 ,join(" ", @{$generate{$_}}),"\n"
   2361                 if scalar @{$generate{$_}} > 1;
   2362             my @generator = split /\s+/, $generate{$dest}->[0];
   2363             my $gen = $generator[0];
   2364             $generator[0] = cleanfile($sourced, $gen, $blddir);
   2365 
   2366             # If the generator is itself generated, it's in the build tree
   2367             if ($generate{$gen} || ! -f $generator[0]) {
   2368                 $generator[0] = cleanfile($buildd, $gen, $blddir);
   2369             }
   2370             $check_generate{$ddest}->{$generator[0]}++;
   2371 
   2372             $unified_info{generate}->{$ddest} = [ @generator ];
   2373             # Fix up associated attributes
   2374             $unified_info{attributes}->{generate}->{$ddest} =
   2375                 $attributes{generate}->{$dest}->{$gen}
   2376                 if defined $attributes{generate}->{$dest}->{$gen};
   2377         }
   2378 
   2379         foreach (keys %depends) {
   2380             my $dest = $_;
   2381             my $ddest = $dest;
   2382 
   2383             if ($dest =~ /^\|(.*)\|$/) {
   2384                 # Collect the raw target
   2385                 $unified_info{targets}->{$1} = 1;
   2386                 $ddest = $1;
   2387             } elsif ($dest eq '') {
   2388                 $ddest = '';
   2389             } else {
   2390                 $ddest = cleanfile($sourced, $_, $blddir);
   2391 
   2392                 # If the destination doesn't exist in source, it can only be
   2393                 # a generated file in the build tree.
   2394                 if ($ddest eq $src_configdata || ! -f $ddest) {
   2395                     $ddest = cleanfile($buildd, $_, $blddir);
   2396                 }
   2397             }
   2398             foreach (@{$depends{$dest}}) {
   2399                 my $d = cleanfile($sourced, $_, $blddir);
   2400                 my $d2 = cleanfile($buildd, $_, $blddir);
   2401 
   2402                 # If we know it's generated, or assume it is because we can't
   2403                 # find it in the source tree, we set file we depend on to be
   2404                 # in the build tree rather than the source tree.
   2405                 if ($d eq $src_configdata
   2406                     || (grep { $d2 eq $_ }
   2407                         keys %{$unified_info{generate}})
   2408                     || ! -f $d) {
   2409                     $d = $d2;
   2410                 }
   2411                 $unified_info{depends}->{$ddest}->{$d} = 1;
   2412 
   2413                 # Fix up associated attributes
   2414                 $unified_info{attributes}->{depends}->{$ddest}->{$d} =
   2415                     $attributes{depends}->{$dest}->{$_}
   2416                     if defined $attributes{depends}->{$dest}->{$_};
   2417             }
   2418         }
   2419 
   2420         foreach (keys %includes) {
   2421             my $dest = $_;
   2422             my $ddest = cleanfile($sourced, $_, $blddir);
   2423 
   2424             # If the destination doesn't exist in source, it can only be
   2425             # a generated file in the build tree.
   2426             if ($ddest eq $src_configdata || ! -f $ddest) {
   2427                 $ddest = cleanfile($buildd, $_, $blddir);
   2428             }
   2429             foreach (@{$includes{$dest}}) {
   2430                 my $is = cleandir($sourced, $_, $blddir);
   2431                 my $ib = cleandir($buildd, $_, $blddir);
   2432                 push @{$unified_info{includes}->{$ddest}->{source}}, $is
   2433                     unless grep { $_ eq $is } @{$unified_info{includes}->{$ddest}->{source}};
   2434                 push @{$unified_info{includes}->{$ddest}->{build}}, $ib
   2435                     unless grep { $_ eq $ib } @{$unified_info{includes}->{$ddest}->{build}};
   2436             }
   2437         }
   2438 
   2439         foreach my $dest (keys %defines) {
   2440             my $ddest;
   2441 
   2442             if ($dest ne "") {
   2443                 $ddest = cleanfile($sourced, $dest, $blddir);
   2444 
   2445                 # If the destination doesn't exist in source, it can only
   2446                 # be a generated file in the build tree.
   2447                 if (! -f $ddest) {
   2448                     $ddest = cleanfile($buildd, $dest, $blddir);
   2449                 }
   2450             }
   2451             foreach my $v (@{$defines{$dest}}) {
   2452                 $v =~ m|^([^=]*)(=.*)?$|;
   2453                 die "0 length macro name not permitted\n" if $1 eq "";
   2454                 if ($dest ne "") {
   2455                     die "$1 defined more than once\n"
   2456                         if defined $unified_info{defines}->{$ddest}->{$1};
   2457                     $unified_info{defines}->{$ddest}->{$1} = $2;
   2458                 } else {
   2459                     die "$1 defined more than once\n"
   2460                         if grep { $v eq $_ } @{$config{defines}};
   2461                     push @{$config{defines}}, $v;
   2462                 }
   2463             }
   2464         }
   2465 
   2466         foreach my $section (keys %imagedocs) {
   2467             foreach (@{$imagedocs{$section}}) {
   2468                 my $imagedocs = cleanfile($buildd, $_, $blddir);
   2469                 $unified_info{imagedocs}->{$section}->{$imagedocs} = 1;
   2470             }
   2471         }
   2472 
   2473         foreach my $section (keys %htmldocs) {
   2474             foreach (@{$htmldocs{$section}}) {
   2475                 my $htmldocs = cleanfile($buildd, $_, $blddir);
   2476                 $unified_info{htmldocs}->{$section}->{$htmldocs} = 1;
   2477             }
   2478         }
   2479 
   2480         foreach my $section (keys %mandocs) {
   2481             foreach (@{$mandocs{$section}}) {
   2482                 my $mandocs = cleanfile($buildd, $_, $blddir);
   2483                 $unified_info{mandocs}->{$section}->{$mandocs} = 1;
   2484             }
   2485         }
   2486     }
   2487 
   2488     my $ordinals_text = join(', ', sort keys %ordinals);
   2489     warn <<"EOF" if $ordinals_text;
   2490 
   2491 WARNING: ORDINALS were specified for $ordinals_text
   2492 They are ignored and should be replaced with a combination of GENERATE,
   2493 DEPEND and SHARED_SOURCE.
   2494 EOF
   2495 
   2496     # Check that each generated file is only generated once
   2497     my $ambiguous_generation = 0;
   2498     foreach (sort keys %check_generate) {
   2499         my @generators = sort keys %{$check_generate{$_}};
   2500         my $generators_txt = join(', ', @generators);
   2501         if (scalar @generators > 1) {
   2502             warn "$_ is GENERATEd by more than one generator ($generators_txt)\n";
   2503             $ambiguous_generation++;
   2504         }
   2505         if ($check_generate{$_}->{$generators[0]} > 1) {
   2506             warn "INFO: $_ has more than one GENERATE declaration (same generator)\n"
   2507         }
   2508     }
   2509     die "There are ambiguous source file generations\n"
   2510         if $ambiguous_generation > 0;
   2511 
   2512     # All given source files should exist, or if generated, their
   2513     # generator should exist.  This loop ensures this is true.
   2514     my $missing = 0;
   2515     foreach my $orig (sort keys %check_exist) {
   2516         foreach my $dest (@{$check_exist{$orig}}) {
   2517             if ($orig ne $src_configdata) {
   2518                 if ($orig =~ /\.a$/) {
   2519                     # Static library names may be used as sources, so we
   2520                     # need to detect those and give them special treatment.
   2521                     unless (grep { $_ eq $orig }
   2522                             keys %{$unified_info{libraries}}) {
   2523                         warn "$orig is given as source for $dest, but no such library is built\n";
   2524                         $missing++;
   2525                     }
   2526                 } else {
   2527                     # A source may be generated, and its generator may be
   2528                     # generated as well.  We therefore loop to dig out the
   2529                     # first generator.
   2530                     my $gen = $orig;
   2531 
   2532                     while (my @next = keys %{$check_generate{$gen}}) {
   2533                         $gen = $next[0];
   2534                     }
   2535 
   2536                     if (! -f $gen) {
   2537                         if ($gen ne $orig) {
   2538                             $missing++;
   2539                             warn "$orig is given as source for $dest, but its generator (leading to $gen) is missing\n";
   2540                         } else {
   2541                             $missing++;
   2542                             warn "$orig is given as source for $dest, but is missing\n";
   2543                         }
   2544                     }
   2545                 }
   2546             }
   2547         }
   2548     }
   2549     die "There are files missing\n" if $missing > 0;
   2550 
   2551     # Go through the sources of all libraries and check that the same basename
   2552     # doesn't appear more than once.  Some static library archivers depend on
   2553     # them being unique.
   2554     {
   2555         my $err = 0;
   2556         foreach my $prod (keys %{$unified_info{libraries}}) {
   2557             my @prod_sources =
   2558                 map { keys %{$unified_info{sources}->{$_}} }
   2559                 keys %{$unified_info{sources}->{$prod}};
   2560             my %srccnt = ();
   2561 
   2562             # Count how many times a given each source basename
   2563             # appears for each product.
   2564             foreach my $src (@prod_sources) {
   2565                 $srccnt{basename $src}++;
   2566             }
   2567 
   2568             foreach my $src (keys %srccnt) {
   2569                 if ((my $cnt = $srccnt{$src}) > 1) {
   2570                     print STDERR "$src appears $cnt times for the product $prod\n";
   2571                     $err++
   2572                 }
   2573             }
   2574         }
   2575         die if $err > 0;
   2576     }
   2577 
   2578     # Massage the result
   2579 
   2580     # If we depend on a header file or a perl module, add an inclusion of
   2581     # its directory to allow smoothe inclusion
   2582     foreach my $dest (keys %{$unified_info{depends}}) {
   2583         next if $dest eq "";
   2584         foreach my $d (keys %{$unified_info{depends}->{$dest}}) {
   2585             next unless $d =~ /\.(h|pm)$/;
   2586             my $i = dirname($d);
   2587             my $spot =
   2588                 $d eq "configdata.pm" || defined($unified_info{generate}->{$d})
   2589                 ? 'build' : 'source';
   2590             push @{$unified_info{includes}->{$dest}->{$spot}}, $i
   2591                 unless grep { $_ eq $i } @{$unified_info{includes}->{$dest}->{$spot}};
   2592         }
   2593     }
   2594 
   2595     # Go through all intermediary files and change their names to something that
   2596     # reflects what they will be built for.  Note that for some source files,
   2597     # this leads to duplicate object files because they are used multiple times.
   2598     # the goal is to rename all object files according to this scheme:
   2599     #    {productname}-{midfix}-{origobjname}.[o|res]
   2600     # the {midfix} is a keyword indicating the type of product, which is mostly
   2601     # valuable for libraries since they come in two forms.
   2602     #
   2603     # This also reorganises the {sources} and {shared_sources} so that the
   2604     # former only contains ALL object files that are supposed to end up in
   2605     # static libraries and programs, while the latter contains ALL object files
   2606     # that are supposed to end up in shared libraries and DSOs.
   2607     # The main reason for having two different source structures is to allow
   2608     # the same name to be used for the static and the shared variants of a
   2609     # library.
   2610     {
   2611         # Take copies so we don't get interference from added stuff
   2612         my %unified_copy = ();
   2613         foreach (('sources', 'shared_sources')) {
   2614             $unified_copy{$_} = { %{$unified_info{$_}} }
   2615                 if defined($unified_info{$_});
   2616             delete $unified_info{$_};
   2617         }
   2618         foreach my $prodtype (('programs', 'libraries', 'modules', 'scripts')) {
   2619             # $intent serves multi purposes:
   2620             # - give a prefix for the new object files names
   2621             # - in the case of libraries, rearrange the object files so static
   2622             #   libraries use the 'sources' structure exclusively, while shared
   2623             #   libraries use the 'shared_sources' structure exclusively.
   2624             my $intent = {
   2625                 programs  => { bin    => { src => [ 'sources' ],
   2626                                            dst => 'sources' } },
   2627                 libraries => { lib    => { src => [ 'sources' ],
   2628                                            dst => 'sources' },
   2629                                shlib  => { prodselect =>
   2630                                                sub { grep !/\.a$/, @_ },
   2631                                            src => [ 'sources',
   2632                                                     'shared_sources' ],
   2633                                            dst => 'shared_sources' } },
   2634                 modules   => { dso    => { src => [ 'sources' ],
   2635                                            dst => 'sources' } },
   2636                 scripts   => { script => { src => [ 'sources' ],
   2637                                            dst => 'sources' } }
   2638                } -> {$prodtype};
   2639             foreach my $kind (keys %$intent) {
   2640                 next if ($intent->{$kind}->{dst} eq 'shared_sources'
   2641                              && $disabled{shared});
   2642 
   2643                 my @src = @{$intent->{$kind}->{src}};
   2644                 my $dst = $intent->{$kind}->{dst};
   2645                 my $prodselect = $intent->{$kind}->{prodselect} // sub { @_ };
   2646                 foreach my $prod ($prodselect->(keys %{$unified_info{$prodtype}})) {
   2647                     # %prod_sources has all applicable objects as keys, and
   2648                     # their corresponding sources as values
   2649                     my %prod_sources =
   2650                         map { $_ => [ keys %{$unified_copy{sources}->{$_}} ] }
   2651                         map { keys %{$unified_copy{$_}->{$prod}} }
   2652                         @src;
   2653                     foreach (keys %prod_sources) {
   2654                         # Only affect object files and resource files,
   2655                         # the others simply get a new value
   2656                         # (+1 instead of -1)
   2657                         if ($_ =~ /\.(o|res)$/) {
   2658                             (my $prodname = $prod) =~ s|\.a$||;
   2659                             my $newobj =
   2660                                 catfile(dirname($_),
   2661                                         basename($prodname)
   2662                                             . '-' . $kind
   2663                                             . '-' . basename($_));
   2664                             $unified_info{$dst}->{$prod}->{$newobj} = 1;
   2665                             foreach my $src (@{$prod_sources{$_}}) {
   2666                                 $unified_info{sources}->{$newobj}->{$src} = 1;
   2667                                 # Adjust source attributes
   2668                                 my $attrs = $unified_info{attributes}->{sources};
   2669                                 if (defined $attrs->{$prod}
   2670                                     && defined $attrs->{$prod}->{$_}) {
   2671                                     $attrs->{$prod}->{$newobj} =
   2672                                         $attrs->{$prod}->{$_};
   2673                                     delete $attrs->{$prod}->{$_};
   2674                                 }
   2675                                 foreach my $objsrc (keys %{$attrs->{$_} // {}}) {
   2676                                     $attrs->{$newobj}->{$objsrc} =
   2677                                         $attrs->{$_}->{$objsrc};
   2678                                     delete $attrs->{$_}->{$objsrc};
   2679                                 }
   2680                             }
   2681                             # Adjust dependencies
   2682                             foreach my $deps (keys %{$unified_info{depends}->{$_}}) {
   2683                                 $unified_info{depends}->{$_}->{$deps} = -1;
   2684                                 $unified_info{depends}->{$newobj}->{$deps} = 1;
   2685                             }
   2686                             # Adjust includes
   2687                             foreach my $k (('source', 'build')) {
   2688                                 next unless
   2689                                     defined($unified_info{includes}->{$_}->{$k});
   2690                                 my @incs = @{$unified_info{includes}->{$_}->{$k}};
   2691                                 $unified_info{includes}->{$newobj}->{$k} = [ @incs ];
   2692                             }
   2693                         } else {
   2694                             $unified_info{$dst}->{$prod}->{$_} = 1;
   2695                         }
   2696                     }
   2697                 }
   2698             }
   2699         }
   2700     }
   2701 
   2702     # At this point, we have a number of sources with the value -1.  They
   2703     # aren't part of the local build and are probably meant for a different
   2704     # platform, and can therefore be cleaned away.  That happens when making
   2705     # %unified_info more efficient below.
   2706 
   2707     ### Make unified_info a bit more efficient
   2708     # One level structures
   2709     foreach (("programs", "libraries", "modules", "scripts", "targets")) {
   2710         $unified_info{$_} = [ sort keys %{$unified_info{$_}} ];
   2711     }
   2712     # Two level structures
   2713     foreach my $l1 (("sources", "shared_sources", "ldadd", "depends",
   2714                      "imagedocs", "htmldocs", "mandocs")) {
   2715         foreach my $l2 (sort keys %{$unified_info{$l1}}) {
   2716             my @items =
   2717                 sort
   2718                 grep { $unified_info{$l1}->{$l2}->{$_} > 0 }
   2719                 keys %{$unified_info{$l1}->{$l2}};
   2720             if (@items) {
   2721                 $unified_info{$l1}->{$l2} = [ @items ];
   2722             } else {
   2723                 delete $unified_info{$l1}->{$l2};
   2724             }
   2725         }
   2726     }
   2727     # Defines
   2728     foreach my $dest (sort keys %{$unified_info{defines}}) {
   2729         $unified_info{defines}->{$dest}
   2730             = [ map { $_.$unified_info{defines}->{$dest}->{$_} }
   2731                 sort keys %{$unified_info{defines}->{$dest}} ];
   2732     }
   2733     # Includes
   2734     foreach my $dest (sort keys %{$unified_info{includes}}) {
   2735         if (defined($unified_info{includes}->{$dest}->{build})) {
   2736             my @source_includes = ();
   2737             @source_includes = ( @{$unified_info{includes}->{$dest}->{source}} )
   2738                 if defined($unified_info{includes}->{$dest}->{source});
   2739             $unified_info{includes}->{$dest} =
   2740                 [ @{$unified_info{includes}->{$dest}->{build}} ];
   2741             foreach my $inc (@source_includes) {
   2742                 push @{$unified_info{includes}->{$dest}}, $inc
   2743                     unless grep { $_ eq $inc } @{$unified_info{includes}->{$dest}};
   2744             }
   2745         } elsif (defined($unified_info{includes}->{$dest}->{source})) {
   2746             $unified_info{includes}->{$dest} =
   2747                 [ @{$unified_info{includes}->{$dest}->{source}} ];
   2748         } else {
   2749             delete $unified_info{includes}->{$dest};
   2750         }
   2751     }
   2752 
   2753     # For convenience collect information regarding directories where
   2754     # files are generated, those generated files and the end product
   2755     # they end up in where applicable.  Then, add build rules for those
   2756     # directories
   2757     my %loopinfo = ( "lib" => [ @{$unified_info{libraries}} ],
   2758                      "dso" => [ @{$unified_info{modules}} ],
   2759                      "bin" => [ @{$unified_info{programs}} ],
   2760                      "script" => [ @{$unified_info{scripts}} ],
   2761                      "docs" => [ (map { @{$unified_info{imagedocs}->{$_} // []} }
   2762                                   keys %{$unified_info{imagedocs} // {}}),
   2763                                  (map { @{$unified_info{htmldocs}->{$_} // []} }
   2764                                   keys %{$unified_info{htmldocs} // {}}),
   2765                                  (map { @{$unified_info{mandocs}->{$_} // []} }
   2766                                   keys %{$unified_info{mandocs} // {}}) ] );
   2767     foreach my $type (sort keys %loopinfo) {
   2768         foreach my $product (@{$loopinfo{$type}}) {
   2769             my %dirs = ();
   2770             my $pd = dirname($product);
   2771 
   2772             foreach (@{$unified_info{sources}->{$product} // []},
   2773                      @{$unified_info{shared_sources}->{$product} // []}) {
   2774                 my $d = dirname($_);
   2775 
   2776                 # We don't want to create targets for source directories
   2777                 # when building out of source
   2778                 next if ($config{sourcedir} ne $config{builddir}
   2779                              && $d =~ m|^\Q$config{sourcedir}\E|);
   2780                 # We already have a "test" target, and the current directory
   2781                 # is just silly to make a target for
   2782                 next if $d eq "test" || $d eq ".";
   2783 
   2784                 $dirs{$d} = 1;
   2785                 push @{$unified_info{dirinfo}->{$d}->{deps}}, $_
   2786                     if $d ne $pd;
   2787             }
   2788             foreach (sort keys %dirs) {
   2789                 push @{$unified_info{dirinfo}->{$_}->{products}->{$type}},
   2790                     $product;
   2791             }
   2792         }
   2793     }
   2794 }
   2795 
   2796 # For the schemes that need it, we provide the old *_obj configs
   2797 # from the *_asm_obj ones
   2798 foreach (grep /_(asm|aux)_src$/, keys %target) {
   2799     my $src = $_;
   2800     (my $obj = $_) =~ s/_(asm|aux)_src$/_obj/;
   2801     $target{$obj} = $target{$src};
   2802     $target{$obj} =~ s/\.[csS]\b/.o/g; # C and assembler
   2803     $target{$obj} =~ s/\.(cc|cpp)\b/_cc.o/g; # C++
   2804 }
   2805 
   2806 # Write down our configuration where it fits #########################
   2807 
   2808 my %template_vars = (
   2809     config => \%config,
   2810     target => \%target,
   2811     disablables => \@disablables,
   2812     disablables_int => \@disablables_int,
   2813     disabled => \%disabled,
   2814     withargs => \%withargs,
   2815     unified_info => \%unified_info,
   2816     tls => \@tls,
   2817     dtls => \@dtls,
   2818     makevars => [ sort keys %user ],
   2819     disabled_info => \%disabled_info,
   2820     user_crossable => \@user_crossable,
   2821 );
   2822 my $configdata_outname = 'configdata.pm';
   2823 open CONFIGDATA, ">$configdata_outname.new"
   2824     or die "Trying to create $configdata_outname.new: $!";
   2825 my $configdata_tmplname = cleanfile($srcdir, "configdata.pm.in", $blddir);
   2826 my $configdata_tmpl =
   2827     OpenSSL::Template->new(TYPE => 'FILE', SOURCE => $configdata_tmplname);
   2828 $configdata_tmpl->fill_in(
   2829     FILENAME => $configdata_tmplname,
   2830     OUTPUT => \*CONFIGDATA,
   2831     HASH => { %template_vars,
   2832               autowarntext => [
   2833                   'WARNING: do not edit!',
   2834                   "Generated by Configure from $configdata_tmplname",
   2835               ] }
   2836 ) or die $Text::Template::ERROR;
   2837 close CONFIGDATA;
   2838 
   2839 rename "$configdata_outname.new", $configdata_outname;
   2840 if ($builder_platform eq 'unix') {
   2841     my $mode = (0755 & ~umask);
   2842     chmod $mode, 'configdata.pm'
   2843         or warn sprintf("WARNING: Couldn't change mode for 'configdata.pm' to 0%03o: %s\n",$mode,$!);
   2844 }
   2845 print "Created $configdata_outname\n";
   2846 
   2847 print "Running $configdata_outname\n";
   2848 my $perlcmd = (quotify("maybeshell", $config{PERL}))[0];
   2849 my $cmd = "$perlcmd $configdata_outname";
   2850 #print STDERR "DEBUG[run_dofile]: \$cmd = $cmd\n";
   2851 system($cmd);
   2852 exit 1 if $? != 0;
   2853 
   2854 $SIG{__DIE__} = $orig_death_handler;
   2855 
   2856 print <<"EOF" if ($disabled{threads} eq "unavailable");
   2857 
   2858 The library could not be configured for supporting multi-threaded
   2859 applications as the compiler options required on this system are not known.
   2860 See file INSTALL.md for details if you need multi-threading.
   2861 EOF
   2862 
   2863 print <<"EOF" if ($no_shared_warn);
   2864 
   2865 The options 'shared', 'pic' and 'dynamic-engine' aren't supported on this
   2866 platform, so we will pretend you gave the option 'no-pic', which also disables
   2867 'shared' and 'dynamic-engine'.  If you know how to implement shared libraries
   2868 or position independent code, please let us know (but please first make sure
   2869 you have tried with a current version of OpenSSL).
   2870 EOF
   2871 
   2872 print $banner;
   2873 
   2874 exit(0);
   2875 
   2876 ######################################################################
   2877 #
   2878 # Helpers and utility functions
   2879 #
   2880 
   2881 # Death handler, to print a helpful message in case of failure #######
   2882 #
   2883 sub death_handler {
   2884     die @_ if $^S;              # To prevent the added message in eval blocks
   2885     my $build_file = $config{build_file} // "build file";
   2886     my @message = ( <<"_____", @_ );
   2887 
   2888 Failure!  $build_file wasn't produced.
   2889 Please read INSTALL.md and associated NOTES-* files.  You may also have to
   2890 look over your available compiler tool chain or change your configuration.
   2891 
   2892 _____
   2893 
   2894     # Dying is terminal, so it's ok to reset the signal handler here.
   2895     $SIG{__DIE__} = $orig_death_handler;
   2896     die @message;
   2897 }
   2898 
   2899 # Configuration file reading #########################################
   2900 
   2901 # Note: All of the helper functions are for lazy evaluation.  They all
   2902 # return a CODE ref, which will return the intended value when evaluated.
   2903 # Thus, whenever there's mention of a returned value, it's about that
   2904 # intended value.
   2905 
   2906 # Helper function to implement conditional value variants, with a default
   2907 # plus additional values based on the value of $config{build_type}.
   2908 # Arguments are given in hash table form:
   2909 #
   2910 #       picker(default => "Basic string: ",
   2911 #              debug   => "debug",
   2912 #              release => "release")
   2913 #
   2914 # When configuring with --debug, the resulting string will be
   2915 # "Basic string: debug", and when not, it will be "Basic string: release"
   2916 #
   2917 # This can be used to create variants of sets of flags according to the
   2918 # build type:
   2919 #
   2920 #       cflags => picker(default => "-Wall",
   2921 #                        debug   => "-g -O0",
   2922 #                        release => "-O3")
   2923 #
   2924 sub picker {
   2925     my %opts = @_;
   2926     return sub { add($opts{default} || (),
   2927                      $opts{$config{build_type}} || ())->(); }
   2928 }
   2929 
   2930 # Helper function to combine several values of different types into one.
   2931 # This is useful if you want to combine a string with the result of a
   2932 # lazy function, such as:
   2933 #
   2934 #       cflags => combine("-Wall", sub { $disabled{zlib} ? () : "-DZLIB" })
   2935 #
   2936 sub combine {
   2937     my @stuff = @_;
   2938     return sub { add(@stuff)->(); }
   2939 }
   2940 
   2941 # Helper function to implement conditional values depending on the value
   2942 # of $disabled{threads}.  Can be used as follows:
   2943 #
   2944 #       cflags => combine("-Wall", threads("-pthread"))
   2945 #
   2946 sub threads {
   2947     my @flags = @_;
   2948     return sub { add($disabled{threads} ? () : @flags)->(); }
   2949 }
   2950 
   2951 sub shared {
   2952     my @flags = @_;
   2953     return sub { add($disabled{shared} ? () : @flags)->(); }
   2954 }
   2955 
   2956 our $add_called = 0;
   2957 # Helper function to implement adding values to already existing configuration
   2958 # values.  It handles elements that are ARRAYs, CODEs and scalars
   2959 sub _add {
   2960     my $separator = shift;
   2961 
   2962     # If there's any ARRAY in the collection of values OR the separator
   2963     # is undef, we will return an ARRAY of combined values, otherwise a
   2964     # string of joined values with $separator as the separator.
   2965     my $found_array = !defined($separator);
   2966 
   2967     my @values =
   2968         map {
   2969             my $res = $_;
   2970             while (ref($res) eq "CODE") {
   2971                 $res = $res->();
   2972             }
   2973             if (defined($res)) {
   2974                 if (ref($res) eq "ARRAY") {
   2975                     $found_array = 1;
   2976                     @$res;
   2977                 } else {
   2978                     $res;
   2979                 }
   2980             } else {
   2981                 ();
   2982             }
   2983     } (@_);
   2984 
   2985     $add_called = 1;
   2986 
   2987     if ($found_array) {
   2988         [ @values ];
   2989     } else {
   2990         join($separator, grep { defined($_) && $_ ne "" } @values);
   2991     }
   2992 }
   2993 sub add_before {
   2994     my $separator = " ";
   2995     if (ref($_[$#_]) eq "HASH") {
   2996         my $opts = pop;
   2997         $separator = $opts->{separator};
   2998     }
   2999     my @x = @_;
   3000     sub { _add($separator, @x, @_) };
   3001 }
   3002 sub add {
   3003     my $separator = " ";
   3004     if (ref($_[$#_]) eq "HASH") {
   3005         my $opts = pop;
   3006         $separator = $opts->{separator};
   3007     }
   3008     my @x = @_;
   3009     sub { _add($separator, @_, @x) };
   3010 }
   3011 
   3012 sub read_eval_file {
   3013     my $fname = shift;
   3014     my $content;
   3015     my @result;
   3016 
   3017     open F, "< $fname" or die "Can't open '$fname': $!\n";
   3018     {
   3019         undef local $/;
   3020         $content = <F>;
   3021     }
   3022     close F;
   3023     {
   3024         local $@;
   3025 
   3026         @result = ( eval $content );
   3027         warn $@ if $@;
   3028     }
   3029     return wantarray ? @result : $result[0];
   3030 }
   3031 
   3032 # configuration reader, evaluates the input file as a perl script and expects
   3033 # it to fill %targets with target configurations.  Those are then added to
   3034 # %table.
   3035 sub read_config {
   3036     my $fname = shift;
   3037     my %targets;
   3038 
   3039     {
   3040         # Protect certain tables from tampering
   3041         local %table = ();
   3042 
   3043         %targets = read_eval_file($fname);
   3044     }
   3045     my %preexisting = ();
   3046     foreach (sort keys %targets) {
   3047         $preexisting{$_} = 1 if $table{$_};
   3048     }
   3049     die <<"EOF",
   3050 The following config targets from $fname
   3051 shadow pre-existing config targets with the same name:
   3052 EOF
   3053         map { "  $_\n" } sort keys %preexisting
   3054         if %preexisting;
   3055 
   3056 
   3057     # For each target, check that it's configured with a hash table.
   3058     foreach (keys %targets) {
   3059         if (ref($targets{$_}) ne "HASH") {
   3060             if (ref($targets{$_}) eq "") {
   3061                 warn "Deprecated target configuration for $_, ignoring...\n";
   3062             } else {
   3063                 warn "Misconfigured target configuration for $_ (should be a hash table), ignoring...\n";
   3064             }
   3065             delete $targets{$_};
   3066         } else {
   3067             $targets{$_}->{_conf_fname_int} = add([ $fname ]);
   3068         }
   3069     }
   3070 
   3071     %table = (%table, %targets);
   3072 
   3073 }
   3074 
   3075 # configuration resolver.  Will only resolve all the lazy evaluation
   3076 # codeblocks for the chosen target and all those it inherits from,
   3077 # recursively
   3078 sub resolve_config {
   3079     my $target = shift;
   3080     my @breadcrumbs = @_;
   3081 
   3082 #    my $extra_checks = defined($ENV{CONFIGURE_EXTRA_CHECKS});
   3083 
   3084     if (grep { $_ eq $target } @breadcrumbs) {
   3085         die "inherit_from loop!  target backtrace:\n  "
   3086             ,$target,"\n  ",join("\n  ", @breadcrumbs),"\n";
   3087     }
   3088 
   3089     if (!defined($table{$target})) {
   3090         warn "Warning! target $target doesn't exist!\n";
   3091         return ();
   3092     }
   3093     # Recurse through all inheritances.  They will be resolved on the
   3094     # fly, so when this operation is done, they will all just be a
   3095     # bunch of attributes with string values.
   3096     # What we get here, though, are keys with references to lists of
   3097     # the combined values of them all.  We will deal with lists after
   3098     # this stage is done.
   3099     my %combined_inheritance = ();
   3100     if ($table{$target}->{inherit_from}) {
   3101         my @inherit_from =
   3102             map { ref($_) eq "CODE" ? $_->() : $_ } @{$table{$target}->{inherit_from}};
   3103         foreach (@inherit_from) {
   3104             my %inherited_config = resolve_config($_, $target, @breadcrumbs);
   3105 
   3106             # 'template' is a marker that's considered private to
   3107             # the config that had it.
   3108             delete $inherited_config{template};
   3109 
   3110             foreach (keys %inherited_config) {
   3111                 if (!$combined_inheritance{$_}) {
   3112                     $combined_inheritance{$_} = [];
   3113                 }
   3114                 push @{$combined_inheritance{$_}}, $inherited_config{$_};
   3115             }
   3116         }
   3117     }
   3118 
   3119     # We won't need inherit_from in this target any more, since we've
   3120     # resolved all the inheritances that lead to this
   3121     delete $table{$target}->{inherit_from};
   3122 
   3123     # Now is the time to deal with those lists.  Here's the place to
   3124     # decide what shall be done with those lists, all based on the
   3125     # values of the target we're currently dealing with.
   3126     # - If a value is a coderef, it will be executed with the list of
   3127     #   inherited values as arguments.
   3128     # - If the corresponding key doesn't have a value at all or is the
   3129     #   empty string, the inherited value list will be run through the
   3130     #   default combiner (below), and the result becomes this target's
   3131     #   value.
   3132     # - Otherwise, this target's value is assumed to be a string that
   3133     #   will simply override the inherited list of values.
   3134     my $default_combiner = add();
   3135 
   3136     my %all_keys =
   3137         map { $_ => 1 } (keys %combined_inheritance,
   3138                          keys %{$table{$target}});
   3139 
   3140     sub process_values {
   3141         my $object    = shift;
   3142         my $inherited = shift;  # Always a [ list ]
   3143         my $target    = shift;
   3144         my $entry     = shift;
   3145 
   3146         $add_called = 0;
   3147 
   3148         while(ref($object) eq "CODE") {
   3149             $object = $object->(@$inherited);
   3150         }
   3151         if (!defined($object)) {
   3152             return ();
   3153         }
   3154         elsif (ref($object) eq "ARRAY") {
   3155             local $add_called;  # To make sure recursive calls don't affect it
   3156             return [ map { process_values($_, $inherited, $target, $entry) }
   3157                      @$object ];
   3158         } elsif (ref($object) eq "") {
   3159             return $object;
   3160         } else {
   3161             die "cannot handle reference type ",ref($object)
   3162                 ," found in target ",$target," -> ",$entry,"\n";
   3163         }
   3164     }
   3165 
   3166     foreach my $key (sort keys %all_keys) {
   3167         my $previous = $combined_inheritance{$key};
   3168 
   3169         # Current target doesn't have a value for the current key?
   3170         # Assign it the default combiner, the rest of this loop body
   3171         # will handle it just like any other coderef.
   3172         if (!exists $table{$target}->{$key}) {
   3173             $table{$target}->{$key} = $default_combiner;
   3174         }
   3175 
   3176         $table{$target}->{$key} = process_values($table{$target}->{$key},
   3177                                                $combined_inheritance{$key},
   3178                                                $target, $key);
   3179         unless(defined($table{$target}->{$key})) {
   3180             delete $table{$target}->{$key};
   3181         }
   3182 #        if ($extra_checks &&
   3183 #            $previous && !($add_called ||  $previous ~~ $table{$target}->{$key})) {
   3184 #            warn "$key got replaced in $target\n";
   3185 #        }
   3186     }
   3187 
   3188     # Finally done, return the result.
   3189     return %{$table{$target}};
   3190 }
   3191 
   3192 sub usage
   3193         {
   3194         print STDERR $usage;
   3195         print STDERR "\npick os/compiler from:\n";
   3196         my $j=0;
   3197         my $i;
   3198         my $k=0;
   3199         foreach $i (sort keys %table)
   3200                 {
   3201                 next if $table{$i}->{template};
   3202                 next if $i =~ /^debug/;
   3203                 $k += length($i) + 1;
   3204                 if ($k > 78)
   3205                         {
   3206                         print STDERR "\n";
   3207                         $k=length($i);
   3208                         }
   3209                 print STDERR $i . " ";
   3210                 }
   3211         foreach $i (sort keys %table)
   3212                 {
   3213                 next if $table{$i}->{template};
   3214                 next if $i !~ /^debug/;
   3215                 $k += length($i) + 1;
   3216                 if ($k > 78)
   3217                         {
   3218                         print STDERR "\n";
   3219                         $k=length($i);
   3220                         }
   3221                 print STDERR $i . " ";
   3222                 }
   3223         exit(1);
   3224         }
   3225 
   3226 sub compiler_predefined {
   3227     state %predefined;
   3228     my $cc = shift;
   3229 
   3230     return () if $^O eq 'VMS';
   3231 
   3232     die 'compiler_predefined called without a compiler command'
   3233         unless $cc;
   3234 
   3235     if (! $predefined{$cc}) {
   3236 
   3237         $predefined{$cc} = {};
   3238 
   3239         # collect compiler pre-defines from gcc or gcc-alike...
   3240         open(PIPE, "$cc -dM -E -x c /dev/null 2>&1 |");
   3241         while (my $l = <PIPE>) {
   3242             $l =~ m/^#define\s+(\w+(?:\(\w+\))?)(?:\s+(.+))?/ or last;
   3243             $predefined{$cc}->{$1} = $2 // '';
   3244         }
   3245         close(PIPE);
   3246     }
   3247 
   3248     return %{$predefined{$cc}};
   3249 }
   3250 
   3251 sub which
   3252 {
   3253     my ($name)=@_;
   3254 
   3255     if (eval { require IPC::Cmd; 1; }) {
   3256         IPC::Cmd->import();
   3257         return scalar IPC::Cmd::can_run($name);
   3258     } else {
   3259         # if there is $directories component in splitpath,
   3260         # then it's not something to test with $PATH...
   3261         return $name if (File::Spec->splitpath($name))[1];
   3262 
   3263         foreach (File::Spec->path()) {
   3264             my $fullpath = catfile($_, "$name$target{exe_extension}");
   3265             if (-f $fullpath and -x $fullpath) {
   3266                 return $fullpath;
   3267             }
   3268         }
   3269     }
   3270 }
   3271 
   3272 sub env
   3273 {
   3274     my $name = shift;
   3275     my %opts = @_;
   3276 
   3277     unless ($opts{cacheonly}) {
   3278         # Note that if $ENV{$name} doesn't exist or is undefined,
   3279         # $config{perlenv}->{$name} will be created with the value
   3280         # undef.  This is intentional.
   3281 
   3282         $config{perlenv}->{$name} = $ENV{$name}
   3283             if ! exists $config{perlenv}->{$name};
   3284     }
   3285     return $config{perlenv}->{$name};
   3286 }
   3287 
   3288 # Configuration printer ##############################################
   3289 
   3290 sub print_table_entry
   3291 {
   3292     local $now_printing = shift;
   3293     my %target = resolve_config($now_printing);
   3294     my $type = shift;
   3295 
   3296     # Don't print the templates
   3297     return if $target{template};
   3298 
   3299     my @sequence = (
   3300         "sys_id",
   3301         "cpp",
   3302         "cppflags",
   3303         "defines",
   3304         "includes",
   3305         "cc",
   3306         "cflags",
   3307         "ld",
   3308         "lflags",
   3309         "loutflag",
   3310         "ex_libs",
   3311         "bn_ops",
   3312         "enable",
   3313         "disable",
   3314         "poly1035_asm_src",
   3315         "thread_scheme",
   3316         "perlasm_scheme",
   3317         "dso_scheme",
   3318         "shared_target",
   3319         "shared_cflag",
   3320         "shared_defines",
   3321         "shared_ldflag",
   3322         "shared_rcflag",
   3323         "shared_extension",
   3324         "dso_extension",
   3325         "obj_extension",
   3326         "exe_extension",
   3327         "ranlib",
   3328         "ar",
   3329         "arflags",
   3330         "aroutflag",
   3331         "rc",
   3332         "rcflags",
   3333         "rcoutflag",
   3334         "mt",
   3335         "mtflags",
   3336         "mtinflag",
   3337         "mtoutflag",
   3338         "multilib",
   3339         "build_scheme",
   3340         );
   3341 
   3342     if ($type eq "TABLE") {
   3343         print "\n";
   3344         print "*** $now_printing\n";
   3345         foreach (@sequence) {
   3346             if (ref($target{$_}) eq "ARRAY") {
   3347                 printf "\$%-12s = %s\n", $_, join(" ", @{$target{$_}});
   3348             } else {
   3349                 printf "\$%-12s = %s\n", $_, $target{$_};
   3350             }
   3351         }
   3352     } elsif ($type eq "HASH") {
   3353         my $largest =
   3354             length((sort { length($a) <=> length($b) } @sequence)[-1]);
   3355         print "    '$now_printing' => {\n";
   3356         foreach (@sequence) {
   3357             if ($target{$_}) {
   3358                 if (ref($target{$_}) eq "ARRAY") {
   3359                     print "      '",$_,"'"," " x ($largest - length($_))," => [ ",join(", ", map { "'$_'" } @{$target{$_}})," ],\n";
   3360                 } else {
   3361                     print "      '",$_,"'"," " x ($largest - length($_))," => '",$target{$_},"',\n";
   3362                 }
   3363             }
   3364         }
   3365         print "    },\n";
   3366     }
   3367 }
   3368 
   3369 # Utility routines ###################################################
   3370 
   3371 # On VMS, if the given file is a logical name, File::Spec::Functions
   3372 # will consider it an absolute path.  There are cases when we want a
   3373 # purely syntactic check without checking the environment.
   3374 sub isabsolute {
   3375     my $file = shift;
   3376 
   3377     # On non-platforms, we just use file_name_is_absolute().
   3378     return file_name_is_absolute($file) unless $^O eq "VMS";
   3379 
   3380     # If the file spec includes a device or a directory spec,
   3381     # file_name_is_absolute() is perfectly safe.
   3382     return file_name_is_absolute($file) if $file =~ m|[:\[]|;
   3383 
   3384     # Here, we know the given file spec isn't absolute
   3385     return 0;
   3386 }
   3387 
   3388 # Makes a directory absolute and cleans out /../ in paths like foo/../bar
   3389 # On some platforms, this uses rel2abs(), while on others, realpath() is used.
   3390 # realpath() requires that at least all path components except the last is an
   3391 # existing directory.  On VMS, the last component of the directory spec must
   3392 # exist.
   3393 sub absolutedir {
   3394     my $dir = shift;
   3395 
   3396     # realpath() is quite buggy on VMS.  It uses LIB$FID_TO_NAME, which
   3397     # will return the volume name for the device, no matter what.  Also,
   3398     # it will return an incorrect directory spec if the argument is a
   3399     # directory that doesn't exist.
   3400     if ($^O eq "VMS") {
   3401         return rel2abs($dir);
   3402     }
   3403 
   3404     # We use realpath() on Unix, since no other will properly clean out
   3405     # a directory spec.
   3406     use Cwd qw/realpath/;
   3407 
   3408     return realpath($dir);
   3409 }
   3410 
   3411 # Check if all paths are one and the same, using stat.  They must both exist
   3412 # We need this for the cases when File::Spec doesn't detect case insensitivity
   3413 # (File::Spec::Unix assumes case sensitivity)
   3414 sub samedir {
   3415     die "samedir expects two arguments\n" unless scalar @_ == 2;
   3416 
   3417     my @stat0 = stat($_[0]);    # First argument
   3418     my @stat1 = stat($_[1]);    # Second argument
   3419 
   3420     die "Couldn't stat $_[0]" unless @stat0;
   3421     die "Couldn't stat $_[1]" unless @stat1;
   3422 
   3423     # Compare device number
   3424     return 0 unless ($stat0[0] == $stat1[0]);
   3425     # Compare "inode".  The perl manual recommends comparing as
   3426     # string rather than as number.
   3427     return 0 unless ($stat0[1] eq $stat1[1]);
   3428 
   3429     return 1;                   # All the same
   3430 }
   3431 
   3432 sub quotify {
   3433     my %processors = (
   3434         perl    => sub { my $x = shift;
   3435                          $x =~ s/([\\\$\@"])/\\$1/g;
   3436                          return '"'.$x.'"'; },
   3437         maybeshell => sub { my $x = shift;
   3438                             (my $y = $x) =~ s/([\\\"])/\\$1/g;
   3439                             if ($x ne $y || $x =~ m|\s|) {
   3440                                 return '"'.$y.'"';
   3441                             } else {
   3442                                 return $x;
   3443                             }
   3444                         },
   3445         );
   3446     my $for = shift;
   3447     my $processor =
   3448         defined($processors{$for}) ? $processors{$for} : sub { shift; };
   3449 
   3450     return map { $processor->($_); } @_;
   3451 }
   3452 
   3453 # collect_from_file($filename, $line_concat_cond_re, $line_concat)
   3454 # $filename is a file name to read from
   3455 # $line_concat_cond_re is a regexp detecting a line continuation ending
   3456 # $line_concat is a CODEref that takes care of concatenating two lines
   3457 sub collect_from_file {
   3458     my $filename = shift;
   3459     my $line_concat_cond_re = shift;
   3460     my $line_concat = shift;
   3461 
   3462     open my $fh, $filename || die "unable to read $filename: $!\n";
   3463     return sub {
   3464         my $saved_line = "";
   3465         $_ = "";
   3466         while (<$fh>) {
   3467             s|\R$||;
   3468             if (defined $line_concat) {
   3469                 $_ = $line_concat->($saved_line, $_);
   3470                 $saved_line = "";
   3471             }
   3472             if (defined $line_concat_cond_re && /$line_concat_cond_re/) {
   3473                 $saved_line = $_;
   3474                 next;
   3475             }
   3476             return $_;
   3477         }
   3478         die "$filename ending with continuation line\n" if $_;
   3479         close $fh;
   3480         return undef;
   3481     }
   3482 }
   3483 
   3484 # collect_from_array($array, $line_concat_cond_re, $line_concat)
   3485 # $array is an ARRAYref of lines
   3486 # $line_concat_cond_re is a regexp detecting a line continuation ending
   3487 # $line_concat is a CODEref that takes care of concatenating two lines
   3488 sub collect_from_array {
   3489     my $array = shift;
   3490     my $line_concat_cond_re = shift;
   3491     my $line_concat = shift;
   3492     my @array = (@$array);
   3493 
   3494     return sub {
   3495         my $saved_line = "";
   3496         $_ = "";
   3497         while (defined($_ = shift @array)) {
   3498             s|\R$||;
   3499             if (defined $line_concat) {
   3500                 $_ = $line_concat->($saved_line, $_);
   3501                 $saved_line = "";
   3502             }
   3503             if (defined $line_concat_cond_re && /$line_concat_cond_re/) {
   3504                 $saved_line = $_;
   3505                 next;
   3506             }
   3507             return $_;
   3508         }
   3509         die "input text ending with continuation line\n" if $_;
   3510         return undef;
   3511     }
   3512 }
   3513 
   3514 # collect_information($lineiterator, $line_continue, $regexp => $CODEref, ...)
   3515 # $lineiterator is a CODEref that delivers one line at a time.
   3516 # All following arguments are regex/CODEref pairs, where the regexp detects a
   3517 # line and the CODEref does something with the result of the regexp.
   3518 sub collect_information {
   3519     my $lineiterator = shift;
   3520     my %collectors = @_;
   3521 
   3522     while(defined($_ = $lineiterator->())) {
   3523         s|\R$||;
   3524         my $found = 0;
   3525         if ($collectors{"BEFORE"}) {
   3526             $collectors{"BEFORE"}->($_);
   3527         }
   3528         foreach my $re (keys %collectors) {
   3529             if ($re !~ /^OTHERWISE|BEFORE|AFTER$/ && /$re/) {
   3530                 $collectors{$re}->($lineiterator);
   3531                 $found = 1;
   3532             };
   3533         }
   3534         if ($collectors{"OTHERWISE"}) {
   3535             $collectors{"OTHERWISE"}->($lineiterator, $_)
   3536                 unless $found || !defined $collectors{"OTHERWISE"};
   3537         }
   3538         if ($collectors{"AFTER"}) {
   3539             $collectors{"AFTER"}->($_);
   3540         }
   3541     }
   3542 }
   3543 
   3544 # tokenize($line)
   3545 # tokenize($line,$separator)
   3546 # $line is a line of text to split up into tokens
   3547 # $separator [optional] is a regular expression that separates the tokens,
   3548 # the default being spaces.  Do not use quotes of any kind as separators,
   3549 # that will give undefined results.
   3550 # Returns a list of tokens.
   3551 #
   3552 # Tokens are divided by separator (spaces by default).  If the tokens include
   3553 # the separators, they have to be quoted with single or double quotes.
   3554 # Double quotes inside a double quoted token must be escaped.  Escaping is done
   3555 # with backslash.
   3556 # Basically, the same quoting rules apply for " and ' as in any
   3557 # Unix shell.
   3558 sub tokenize {
   3559     my $line = my $debug_line = shift;
   3560     my $separator = shift // qr|\s+|;
   3561     my @result = ();
   3562 
   3563     if ($ENV{CONFIGURE_DEBUG_TOKENIZE}) {
   3564         print STDERR "DEBUG[tokenize]: \$separator = $separator\n";
   3565     }
   3566 
   3567     while ($line =~ s|^${separator}||, $line ne "") {
   3568         my $token = "";
   3569     again:
   3570         $line =~ m/^(.*?)(${separator}|"|'|$)/;
   3571         $token .= $1;
   3572         $line = $2.$';
   3573 
   3574         if ($line =~ m/^"((?:[^"\\]+|\\.)*)"/) {
   3575             $token .= $1;
   3576             $line = $';
   3577             goto again;
   3578         } elsif ($line =~ m/^'([^']*)'/) {
   3579             $token .= $1;
   3580             $line = $';
   3581             goto again;
   3582         }
   3583         push @result, $token;
   3584     }
   3585 
   3586     if ($ENV{CONFIGURE_DEBUG_TOKENIZE}) {
   3587         print STDERR "DEBUG[tokenize]: Parsed '$debug_line' into:\n";
   3588         print STDERR "DEBUG[tokenize]: ('", join("', '", @result), "')\n";
   3589     }
   3590     return @result;
   3591 }
   3592