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