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