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