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