xref: /freebsd/crypto/openssl/Configure (revision e7be843b4a162e68651d3911f0357ed464915629)
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
12use 5.10.0;
13use strict;
14use Config;
15use FindBin;
16use lib "$FindBin::Bin/util/perl";
17use File::Basename;
18use File::Spec::Functions qw/:DEFAULT abs2rel rel2abs splitdir/;
19use File::Path qw/mkpath/;
20use OpenSSL::fallback "$FindBin::Bin/external/perl/MODULES.txt";
21use OpenSSL::Glob;
22use OpenSSL::Template;
23use OpenSSL::config;
24
25# see INSTALL.md for instructions.
26
27my $orig_death_handler = $SIG{__DIE__};
28$SIG{__DIE__} = \&death_handler;
29
30my $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
32my $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**********************************************************************
48EOF
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
167my @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
194my @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
206my @cl_devteam_warn = qw(
207    /WX
208);
209
210my $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?
219our $BSDthreads="-pthread -D_THREAD_SAFE -D_REENTRANT";
220
221#
222# API compatibility name to version number mapping.
223#
224my $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
245my %guess_opts = ();
246
247my $dryrun = 0;
248
249our %table = ();
250our %config = ();
251our %withargs = ();
252our $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).
263sub 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.
269sub resolve_config;
270
271
272# Information collection #############################################
273
274# Unified build supports separate build dir
275my $srcdir = catdir(absolutedir(dirname($0))); # catdir ensures local syntax
276my $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
287my $dofile = abs2rel(catfile($srcdir, "util/dofile.pl"));
288
289my $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
298my @argvcopy=@ARGV;
299
300if (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).
329foreach ( 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
337my %version = ();
338
339collect_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
369die "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
378my $pattern = catfile(dirname($0), "Configurations", "*.conf");
379foreach (sort glob($pattern)) {
380    &read_config($_);
381}
382
383if (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
398if (!%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}="";
412my $auto_threads=1;    # enable threads automatically? true by default
413my $default_ranlib;
414
415# Known TLS and DTLS protocols
416my @tls = qw(ssl3 tls1 tls1_1 tls1_2 tls1_3);
417my @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
423my @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    );
560foreach 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
570my @disablables_int = qw(
571    crmf
572    );
573
574my %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
587our %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
627my @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#
725my @list = (reverse @tls);
726while ((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}
732my @list = (reverse @dtls);
733while ((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.
749my $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.
755my %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.
784my @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
788my %useradd = (
789    ASFLAGS     => [],
790    CPPDEFINES  => [],
791    CPPINCLUDES => [],
792    CPPFLAGS    => [],
793    CFLAGS      => [],
794    CXXFLAGS    => [],
795    LDFLAGS     => [],
796    LDLIBS      => [],
797    RCFLAGS     => [],
798   );
799
800my %user_synonyms = (
801    HASHBANGPERL=> 'PERL',
802    RC          => 'WINDRES',
803   );
804
805# Some target attributes have been renamed, this is the translation table
806my %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";
834my $target="";
835
836my %cmdvars = ();               # Stores FOO='blah' type arguments
837my %unsupported_options = ();
838my %deprecated_options = ();
839# If you change this, update apps/version.c
840my @known_seed_sources = qw(getrandom devrandom os egd none rdcpu);
841my @seed_sources = ();
842while (@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
1194if (keys %deprecated_options)
1195        {
1196        warn "***** Deprecated options: ",
1197                join(", ", keys %deprecated_options), "\n";
1198        }
1199if (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.
1208if (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.
1236my $anyuseradd =
1237    grep { defined $_ && (ref $_ ne 'ARRAY' || @$_) } values %useradd;
1238foreach (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
1259if (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.
1267unless ($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
1283sub 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}
1306disable();                     # First cascade run
1307
1308our $die = sub { die @_; };
1309if ($target eq "TABLE") {
1310    local $die = sub { warn @_; };
1311    foreach (sort keys %table) {
1312        print_table_entry($_, "TABLE");
1313    }
1314    exit 0;
1315}
1316
1317if ($target eq "LIST") {
1318    foreach (sort keys %table) {
1319        print $_,"\n" unless $table{$_}->{template};
1320    }
1321    exit 0;
1322}
1323
1324if ($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
1333print "Configuring OpenSSL version $config{full_version} ";
1334print "for target $target\n";
1335
1336if (scalar(@seed_sources) == 0) {
1337    print "Using os-specific seed configuration\n";
1338    push @seed_sources, 'os';
1339}
1340if (scalar(grep { $_ eq 'egd' } @seed_sources) > 0) {
1341    delete $disabled{'egd'};
1342}
1343if (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 ===============================
1348You have selected the --with-rand-seed=none option, which effectively
1349disables automatic reseeding of the OpenSSL SEED-SRC random generator.
1350All operations depending on the random generator such as creating keys
1351will not work unless the random generator is seeded manually by the
1352application.
1353
1354Instead of manually seeding, a different random generator can be set
1355at runtime in openssl.cnf or configured at build time with
1356-DOPENSSL_DEFAULT_SEED_SRC.
1357
1358Please read the 'Note on random number generation' section in the
1359INSTALL.md instructions and the RAND_DRBG(7) manual page for more
1360details.
1361============================== WARNING ===============================
1362
1363_____
1364}
1365push @{$config{openssl_feature_defines}},
1366     map { (my $x = $_) =~ tr|[\-a-z]|[_A-Z]|; "OPENSSL_RAND_SEED_$x" }
1367        @seed_sources;
1368
1369my $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?
1375if ($target =~ m/^CygWin32(-.*)$/) {
1376    $target = "Cygwin".$1;
1377}
1378
1379# Support for legacy targets having a name starting with 'debug-'
1380my ($d, $t) = $target =~ m/^(debug-)?(.*)$/;
1381if ($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
1390if ($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
1409exit 0 if $dryrun;              # From older 'config'
1410
1411$config{target} = $target;
1412my %target = resolve_config($target);
1413
1414foreach (keys %target_attr_translate) {
1415    $target{$target_attr_translate{$_}} = $target{$_}
1416        if $target{$_};
1417    delete $target{$_};
1418}
1419
1420%target = ( %{$table{DEFAULTS}}, %target );
1421
1422my %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
1427foreach 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}
1435foreach 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
1451disable();                      # 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).
1460foreach (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"
1494foreach (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
1508if ($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
1513if (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
1524my ($builder, $builder_platform, @builder_opts) =
1525    @{$target{build_scheme}};
1526
1527foreach 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
1546push @{$config{defines}}, "NDEBUG"    if $config{build_type} eq "release";
1547
1548if ($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
1555if ($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
1566unless ($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.
1592my %detected_sanitizers = ();
1593foreach (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.
1612unless($disabled{threads}) {
1613    push @{$config{openssl_feature_defines}}, "OPENSSL_THREADS";
1614}
1615
1616if ($disabled{"unstable-qlog"}) {
1617    $disabled{"qlog"} = 1;
1618}
1619
1620my $no_shared_warn=0;
1621if (($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
1628if ($disabled{"dynamic-engine"}) {
1629        $config{dynamic_engines} = 0;
1630} else {
1631        $config{dynamic_engines} = 1;
1632}
1633
1634unless ($disabled{asan} || defined $detected_sanitizers{asan}) {
1635    push @{$config{cflags}}, "-fsanitize=address";
1636}
1637
1638unless ($disabled{ubsan} || defined $detected_sanitizers{ubsan}) {
1639    push @{$config{cflags}}, "-fsanitize=undefined", "-fno-sanitize-recover=all", "-DPEDANTIC";
1640}
1641
1642unless ($disabled{msan} || defined $detected_sanitizers{msan}) {
1643  push @{$config{cflags}}, "-fsanitize=memory";
1644}
1645
1646unless ($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
1656if ($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        }
1667else
1668        {
1669        push @{$config{lib_defines}}, "OPENSSL_PIC";
1670        }
1671
1672if ($target{sys_id} ne "")
1673        {
1674        push @{$config{openssl_sys_defines}}, "OPENSSL_SYS_$target{sys_id}";
1675        }
1676
1677my %predefined_C = compiler_predefined($config{CROSS_COMPILE}.$config{CC});
1678my %predefined_CXX = $config{CXX}
1679    ? compiler_predefined($config{CROSS_COMPILE}.$config{CXX})
1680    : ();
1681
1682unless ($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.
1690if (!$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
1719if (!$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;
1744my $def_int="unsigned int";
1745$config{rc4_int}                =$def_int;
1746($config{b64l},$config{b64},$config{b32})=(0,0,1);
1747
1748my $count = 0;
1749foreach (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}
1760die "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};
1765foreach (keys %$apitable) {
1766    $disabled{"deprecated-$_"} = "deprecation"
1767        if $disabled{deprecated} && $config{api} >= $apitable->{$_};
1768}
1769
1770disable();                      # 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
1785my @strict_warnings_collection=();
1786if ($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
1812unless ($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
1821unless ($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
1836unless ($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
1854unless ($disabled{winstore}) {
1855    unless ($target =~ /^(?:Cygwin|mingw|VC-|BC-)/) {
1856        disable('not-windows', 'winstore');
1857    }
1858}
1859
1860push @{$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.
1917my %skipdir = ();
1918my %disabled_info = ();         # For configdata.pm
1919foreach 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
1948if ($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
1955my %unified_info = ();
1956
1957my $buildinfo_debug = defined($ENV{CONFIGURE_DEBUG_BUILDINFO});
1958if ($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"
2358ENGINES can only be used if configured with 'dynamic-engine'.
2359This is usually a fault in a build.info file.
2360EOF
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
2653WARNING: ORDINALS were specified for $ordinals_text
2654They are ignored and should be replaced with a combination of GENERATE,
2655DEPEND and SHARED_SOURCE.
2656EOF
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
2962foreach (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
2972my %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);
2986my $configdata_outname = 'configdata.pm';
2987open CONFIGDATA, ">$configdata_outname.new"
2988    or die "Trying to create $configdata_outname.new: $!";
2989my $configdata_tmplname = cleanfile($srcdir, "configdata.pm.in", $blddir, 1);
2990my $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;
3001close CONFIGDATA;
3002
3003rename "$configdata_outname.new", $configdata_outname;
3004if ($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}
3009print "Created $configdata_outname\n";
3010
3011print "Running $configdata_outname\n";
3012my $perlcmd = (quotify("maybeshell", $config{PERL}))[0];
3013my $cmd = "$perlcmd $configdata_outname";
3014#print STDERR "DEBUG[run_dofile]: \$cmd = $cmd\n";
3015system($cmd);
3016exit 1 if $? != 0;
3017
3018$SIG{__DIE__} = $orig_death_handler;
3019
3020print <<"EOF" if ($disabled{threads} eq "unavailable");
3021
3022The library could not be configured for supporting multi-threaded
3023applications as the compiler options required on this system are not known.
3024See file INSTALL.md for details if you need multi-threading.
3025EOF
3026
3027print <<"EOF" if ($no_shared_warn);
3028
3029The options 'shared', 'pic' and 'dynamic-engine' aren't supported on this
3030platform, 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
3032or position independent code, please let us know (but please first make sure
3033you have tried with a current version of OpenSSL).
3034EOF
3035
3036print $banner;
3037
3038exit(0);
3039
3040######################################################################
3041#
3042# Helpers and utility functions
3043#
3044
3045# Death handler, to print a helpful message in case of failure #######
3046#
3047sub 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
3052Failure!  $build_file wasn't produced.
3053Please read INSTALL.md and associated NOTES-* files.  You may also have to
3054look 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#
3088sub 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#
3100sub 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#
3110sub threads {
3111    my @flags = @_;
3112    return sub { add($disabled{threads} ? () : @flags)->(); }
3113}
3114
3115sub shared {
3116    my @flags = @_;
3117    return sub { add($disabled{shared} ? () : @flags)->(); }
3118}
3119
3120our $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
3123sub _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}
3157sub 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}
3166sub 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
3176sub 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.
3199sub 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",
3214The following config targets from $fname
3215shadow pre-existing config targets with the same name:
3216EOF
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
3242sub 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
3356sub 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
3390sub 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
3415sub 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
3436sub 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
3454sub 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.
3538sub 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.
3557sub 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)
3585sub 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
3603sub 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
3628sub 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
3659sub 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.
3689sub 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.
3729sub 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