xref: /freebsd/crypto/openssl/Configure (revision e8d8bef961a50d4dc22501cde4fb9fb0be1b2532)
1#! /usr/bin/env perl
2# -*- mode: perl; -*-
3# Copyright 2016-2021 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
1206if (grep { $_ eq '-static' } @{$config{LDFLAGS}}) {
1207    disable('static', 'pic', 'threads');
1208}
1209
1210# Allow overriding the build file name
1211$config{build_file} = env('BUILDFILE') || $target{build_file} || "Makefile";
1212
1213# Make sure build_scheme is consistent.
1214$target{build_scheme} = [ $target{build_scheme} ]
1215    if ref($target{build_scheme}) ne "ARRAY";
1216
1217my ($builder, $builder_platform, @builder_opts) =
1218    @{$target{build_scheme}};
1219
1220foreach my $checker (($builder_platform."-".$target{build_file}."-checker.pm",
1221                      $builder_platform."-checker.pm")) {
1222    my $checker_path = catfile($srcdir, "Configurations", $checker);
1223    if (-f $checker_path) {
1224        my $fn = $ENV{CONFIGURE_CHECKER_WARN}
1225            ? sub { warn $@; } : sub { die $@; };
1226        if (! do $checker_path) {
1227            if ($@) {
1228                $fn->($@);
1229            } elsif ($!) {
1230                $fn->($!);
1231            } else {
1232                $fn->("The detected tools didn't match the platform\n");
1233            }
1234        }
1235        last;
1236    }
1237}
1238
1239push @{$config{defines}}, "NDEBUG"    if $config{build_type} eq "release";
1240
1241if ($target =~ /^mingw/ && `$config{CC} --target-help 2>&1` =~ m/-mno-cygwin/m)
1242        {
1243        push @{$config{cflags}}, "-mno-cygwin";
1244        push @{$config{cxxflags}}, "-mno-cygwin" if $config{CXX};
1245        push @{$config{shared_ldflag}}, "-mno-cygwin";
1246        }
1247
1248if ($target =~ /linux.*-mips/ && !$disabled{asm}
1249        && !grep { $_ !~ /-m(ips|arch=)/ } (@{$config{CFLAGS}})) {
1250        # minimally required architecture flags for assembly modules
1251        my $value;
1252        $value = '-mips2' if ($target =~ /mips32/);
1253        $value = '-mips3' if ($target =~ /mips64/);
1254        unshift @{$config{cflags}}, $value;
1255        unshift @{$config{cxxflags}}, $value if $config{CXX};
1256}
1257
1258# If threads aren't disabled, check how possible they are
1259unless ($disabled{threads}) {
1260    if ($auto_threads) {
1261        # Enabled by default, disable it forcibly if unavailable
1262        if ($target{thread_scheme} eq "(unknown)") {
1263            disable("unavailable", 'threads');
1264        }
1265    } else {
1266        # The user chose to enable threads explicitly, let's see
1267        # if there's a chance that's possible
1268        if ($target{thread_scheme} eq "(unknown)") {
1269            # If the user asked for "threads" and we don't have internal
1270            # knowledge how to do it, [s]he is expected to provide any
1271            # system-dependent compiler options that are necessary.  We
1272            # can't truly check that the given options are correct, but
1273            # we expect the user to know what [s]He is doing.
1274            if (!@{$config{CFLAGS}} && !@{$config{CPPDEFINES}}) {
1275                die "You asked for multi-threading support, but didn't\n"
1276                    ,"provide any system-specific compiler options\n";
1277            }
1278        }
1279    }
1280}
1281
1282# If threads still aren't disabled, add a C macro to ensure the source
1283# code knows about it.  Any other flag is taken care of by the configs.
1284unless($disabled{threads}) {
1285    push @{$config{openssl_thread_defines}}, "OPENSSL_THREADS";
1286}
1287
1288# With "deprecated" disable all deprecated features.
1289if (defined($disabled{"deprecated"})) {
1290        $config{api} = $maxapi;
1291}
1292
1293my $no_shared_warn=0;
1294if ($target{shared_target} eq "")
1295        {
1296        $no_shared_warn = 1
1297            if (!$disabled{shared} || !$disabled{"dynamic-engine"});
1298        disable('no-shared-target', 'pic');
1299        }
1300
1301if ($disabled{"dynamic-engine"}) {
1302        $config{dynamic_engines} = 0;
1303} else {
1304        $config{dynamic_engines} = 1;
1305}
1306
1307unless ($disabled{asan}) {
1308    push @{$config{cflags}}, "-fsanitize=address";
1309}
1310
1311unless ($disabled{ubsan}) {
1312    # -DPEDANTIC or -fnosanitize=alignment may also be required on some
1313    # platforms.
1314    push @{$config{cflags}}, "-fsanitize=undefined", "-fno-sanitize-recover=all";
1315}
1316
1317unless ($disabled{msan}) {
1318  push @{$config{cflags}}, "-fsanitize=memory";
1319}
1320
1321unless ($disabled{"fuzz-libfuzzer"} && $disabled{"fuzz-afl"}
1322        && $disabled{asan} && $disabled{ubsan} && $disabled{msan}) {
1323    push @{$config{cflags}}, "-fno-omit-frame-pointer", "-g";
1324    push @{$config{cxxflags}}, "-fno-omit-frame-pointer", "-g" if $config{CXX};
1325}
1326#
1327# Platform fix-ups
1328#
1329
1330# This saves the build files from having to check
1331if ($disabled{pic})
1332        {
1333        foreach (qw(shared_cflag shared_cxxflag shared_cppflag
1334                    shared_defines shared_includes shared_ldflag
1335                    module_cflags module_cxxflags module_cppflags
1336                    module_defines module_includes module_lflags))
1337                {
1338                delete $config{$_};
1339                $target{$_} = "";
1340                }
1341        }
1342else
1343        {
1344        push @{$config{lib_defines}}, "OPENSSL_PIC";
1345        }
1346
1347if ($target{sys_id} ne "")
1348        {
1349        push @{$config{openssl_sys_defines}}, "OPENSSL_SYS_$target{sys_id}";
1350        }
1351
1352unless ($disabled{asm}) {
1353    $target{cpuid_asm_src}=$table{DEFAULTS}->{cpuid_asm_src} if ($config{processor} eq "386");
1354    push @{$config{lib_defines}}, "OPENSSL_CPUID_OBJ" if ($target{cpuid_asm_src} ne "mem_clr.c");
1355
1356    $target{bn_asm_src} =~ s/\w+-gf2m.c// if (defined($disabled{ec2m}));
1357
1358    # bn-586 is the only one implementing bn_*_part_words
1359    push @{$config{lib_defines}}, "OPENSSL_BN_ASM_PART_WORDS" if ($target{bn_asm_src} =~ /bn-586/);
1360    push @{$config{lib_defines}}, "OPENSSL_IA32_SSE2" if (!$disabled{sse2} && $target{bn_asm_src} =~ /86/);
1361
1362    push @{$config{lib_defines}}, "OPENSSL_BN_ASM_MONT" if ($target{bn_asm_src} =~ /-mont/);
1363    push @{$config{lib_defines}}, "OPENSSL_BN_ASM_MONT5" if ($target{bn_asm_src} =~ /-mont5/);
1364    push @{$config{lib_defines}}, "OPENSSL_BN_ASM_GF2m" if ($target{bn_asm_src} =~ /-gf2m/);
1365    push @{$config{lib_defines}}, "BN_DIV3W" if ($target{bn_asm_src} =~ /-div3w/);
1366
1367    if ($target{sha1_asm_src}) {
1368        push @{$config{lib_defines}}, "SHA1_ASM"   if ($target{sha1_asm_src} =~ /sx86/ || $target{sha1_asm_src} =~ /sha1/);
1369        push @{$config{lib_defines}}, "SHA256_ASM" if ($target{sha1_asm_src} =~ /sha256/);
1370        push @{$config{lib_defines}}, "SHA512_ASM" if ($target{sha1_asm_src} =~ /sha512/);
1371    }
1372    if ($target{keccak1600_asm_src} ne $table{DEFAULTS}->{keccak1600_asm_src}) {
1373        push @{$config{lib_defines}}, "KECCAK1600_ASM";
1374    }
1375    if ($target{rc4_asm_src} ne $table{DEFAULTS}->{rc4_asm_src}) {
1376        push @{$config{lib_defines}}, "RC4_ASM";
1377    }
1378    if ($target{md5_asm_src}) {
1379        push @{$config{lib_defines}}, "MD5_ASM";
1380    }
1381    $target{cast_asm_src}=$table{DEFAULTS}->{cast_asm_src} unless $disabled{pic}; # CAST assembler is not PIC
1382    if ($target{rmd160_asm_src}) {
1383        push @{$config{lib_defines}}, "RMD160_ASM";
1384    }
1385    if ($target{aes_asm_src}) {
1386        push @{$config{lib_defines}}, "AES_ASM" if ($target{aes_asm_src} =~ m/\baes-/);;
1387        push @{$config{lib_defines}}, "AESNI_ASM" if ($target{aes_asm_src} =~ m/\baesni-/);;
1388        # aes-ctr.fake is not a real file, only indication that assembler
1389        # module implements AES_ctr32_encrypt...
1390        push @{$config{lib_defines}}, "AES_CTR_ASM" if ($target{aes_asm_src} =~ s/\s*aes-ctr\.fake//);
1391        # aes-xts.fake indicates presence of AES_xts_[en|de]crypt...
1392        push @{$config{lib_defines}}, "AES_XTS_ASM" if ($target{aes_asm_src} =~ s/\s*aes-xts\.fake//);
1393        $target{aes_asm_src} =~ s/\s*(vpaes|aesni)-x86\.s//g if ($disabled{sse2});
1394        push @{$config{lib_defines}}, "VPAES_ASM" if ($target{aes_asm_src} =~ m/vpaes/);
1395        push @{$config{lib_defines}}, "BSAES_ASM" if ($target{aes_asm_src} =~ m/bsaes/);
1396    }
1397    if ($target{wp_asm_src} =~ /mmx/) {
1398        if ($config{processor} eq "386") {
1399            $target{wp_asm_src}=$table{DEFAULTS}->{wp_asm_src};
1400        } elsif (!$disabled{"whirlpool"}) {
1401            push @{$config{lib_defines}}, "WHIRLPOOL_ASM";
1402        }
1403    }
1404    if ($target{modes_asm_src} =~ /ghash-/) {
1405        push @{$config{lib_defines}}, "GHASH_ASM";
1406    }
1407    if ($target{ec_asm_src} =~ /ecp_nistz256/) {
1408        push @{$config{lib_defines}}, "ECP_NISTZ256_ASM";
1409    }
1410    if ($target{ec_asm_src} =~ /x25519/) {
1411        push @{$config{lib_defines}}, "X25519_ASM";
1412    }
1413    if ($target{padlock_asm_src} ne $table{DEFAULTS}->{padlock_asm_src}) {
1414        push @{$config{dso_defines}}, "PADLOCK_ASM";
1415    }
1416    if ($target{poly1305_asm_src} ne "") {
1417        push @{$config{lib_defines}}, "POLY1305_ASM";
1418    }
1419}
1420
1421my %predefined_C = compiler_predefined($config{CROSS_COMPILE}.$config{CC});
1422my %predefined_CXX = $config{CXX}
1423    ? compiler_predefined($config{CROSS_COMPILE}.$config{CXX})
1424    : ();
1425
1426# Check for makedepend capabilities.
1427if (!$disabled{makedepend}) {
1428    if ($config{target} =~ /^(VC|vms)-/) {
1429        # For VC- and vms- targets, there's nothing more to do here.  The
1430        # functionality is hard coded in the corresponding build files for
1431        # cl (Windows) and CC/DECC (VMS).
1432    } elsif (($predefined_C{__GNUC__} // -1) >= 3
1433             && !($predefined_C{__APPLE_CC__} && !$predefined_C{__clang__})) {
1434        # We know that GNU C version 3 and up as well as all clang
1435        # versions support dependency generation, but Xcode did not
1436        # handle $cc -M before clang support (but claims __GNUC__ = 3)
1437        $config{makedepprog} = "\$(CROSS_COMPILE)$config{CC}";
1438    } else {
1439        # In all other cases, we look for 'makedepend', and disable the
1440        # capability if not found.
1441        $config{makedepprog} = which('makedepend');
1442        disable('unavailable', 'makedepend') unless $config{makedepprog};
1443    }
1444}
1445
1446if (!$disabled{asm} && !$predefined_C{__MACH__} && $^O ne 'VMS') {
1447    # probe for -Wa,--noexecstack option...
1448    if ($predefined_C{__clang__}) {
1449        # clang has builtin assembler, which doesn't recognize --help,
1450        # but it apparently recognizes the option in question on all
1451        # supported platforms even when it's meaningless. In other words
1452        # probe would fail, but probed option always accepted...
1453        push @{$config{cflags}}, "-Wa,--noexecstack", "-Qunused-arguments";
1454    } else {
1455        my $cc = $config{CROSS_COMPILE}.$config{CC};
1456        open(PIPE, "$cc -Wa,--help -c -o null.$$.o -x assembler /dev/null 2>&1 |");
1457        while(<PIPE>) {
1458            if (m/--noexecstack/) {
1459                push @{$config{cflags}}, "-Wa,--noexecstack";
1460                last;
1461            }
1462        }
1463        close(PIPE);
1464        unlink("null.$$.o");
1465    }
1466}
1467
1468# Deal with bn_ops ###################################################
1469
1470$config{bn_ll}                  =0;
1471$config{export_var_as_fn}       =0;
1472my $def_int="unsigned int";
1473$config{rc4_int}                =$def_int;
1474($config{b64l},$config{b64},$config{b32})=(0,0,1);
1475
1476my $count = 0;
1477foreach (sort split(/\s+/,$target{bn_ops})) {
1478    $count++ if /SIXTY_FOUR_BIT|SIXTY_FOUR_BIT_LONG|THIRTY_TWO_BIT/;
1479    $config{export_var_as_fn}=1                 if $_ eq 'EXPORT_VAR_AS_FN';
1480    $config{bn_ll}=1                            if $_ eq 'BN_LLONG';
1481    $config{rc4_int}="unsigned char"            if $_ eq 'RC4_CHAR';
1482    ($config{b64l},$config{b64},$config{b32})
1483        =(0,1,0)                                if $_ eq 'SIXTY_FOUR_BIT';
1484    ($config{b64l},$config{b64},$config{b32})
1485        =(1,0,0)                                if $_ eq 'SIXTY_FOUR_BIT_LONG';
1486    ($config{b64l},$config{b64},$config{b32})
1487        =(0,0,1)                                if $_ eq 'THIRTY_TWO_BIT';
1488}
1489die "Exactly one of SIXTY_FOUR_BIT|SIXTY_FOUR_BIT_LONG|THIRTY_TWO_BIT can be set in bn_ops\n"
1490    if $count > 1;
1491
1492
1493# Hack cflags for better warnings (dev option) #######################
1494
1495# "Stringify" the C and C++ flags string.  This permits it to be made part of
1496# a string and works as well on command lines.
1497$config{cflags} = [ map { (my $x = $_) =~ s/([\\\"])/\\$1/g; $x }
1498                        @{$config{cflags}} ];
1499$config{cxxflags} = [ map { (my $x = $_) =~ s/([\\\"])/\\$1/g; $x }
1500                          @{$config{cxxflags}} ] if $config{CXX};
1501
1502if (defined($config{api})) {
1503    $config{openssl_api_defines} = [ "OPENSSL_MIN_API=".$apitable->{$config{api}} ];
1504    my $apiflag = sprintf("OPENSSL_API_COMPAT=%s", $apitable->{$config{api}});
1505    push @{$config{defines}}, $apiflag;
1506}
1507
1508my @strict_warnings_collection=();
1509if ($strict_warnings)
1510        {
1511        my $wopt;
1512        my $gccver = $predefined_C{__GNUC__} // -1;
1513
1514        if ($gccver >= 4)
1515                {
1516                push @strict_warnings_collection, @gcc_devteam_warn;
1517                push @strict_warnings_collection, @clang_devteam_warn
1518                    if (defined($predefined_C{__clang__}));
1519                }
1520        elsif ($config{target} =~ /^VC-/)
1521                {
1522                push @strict_warnings_collection, @cl_devteam_warn;
1523                }
1524        else
1525                {
1526                warn "WARNING --strict-warnings requires gcc[>=4] or gcc-alike, or MSVC"
1527                }
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"
2644                unless grep { $_ =~ /^${what}$/ } keys %disabled;
2645        }
2646        print "\nDisabled features:\n\n";
2647        foreach my $what (@disablables) {
2648            my @what2 = grep { $_ =~ /^${what}$/ } keys %disabled;
2649            my $what3 = $what2[0];
2650            if ($what3) {
2651                print "    $what3", ' ' x ($longest - length($what3) + 1),
2652                    "[$disabled{$what3}]", ' ' x ($longest2 - length($disabled{$what3}) + 1);
2653                print $disabled_info{$what3}->{macro}
2654                    if $disabled_info{$what3}->{macro};
2655                print ' (skip ',
2656                    join(', ', @{$disabled_info{$what3}->{skipped}}),
2657                    ')'
2658                    if $disabled_info{$what3}->{skipped};
2659                print "\n";
2660            }
2661        }
2662    }
2663    if ($dump || $target) {
2664        print "\nConfig target attributes:\n\n";
2665        foreach (sort keys %target) {
2666            next if $_ =~ m|^_| || $_ eq 'template';
2667            my $quotify = sub {
2668                map { (my $x = $_) =~ s|([\\\$\@"])|\\$1|g; "\"$x\""} @_;
2669            };
2670            print '    ', $_, ' => ';
2671            if (ref($target{$_}) eq "ARRAY") {
2672                print '[ ', join(', ', $quotify->(@{$target{$_}})), " ],\n";
2673            } else {
2674                print $quotify->($target{$_}), ",\n"
2675            }
2676        }
2677    }
2678    if ($dump || $envvars) {
2679        print "\nRecorded environment:\n\n";
2680        foreach (sort keys %{$config{perlenv}}) {
2681            print '    ',$_,' = ',($config{perlenv}->{$_} || ''),"\n";
2682        }
2683    }
2684    if ($dump || $makevars) {
2685        print "\nMakevars:\n\n";
2686        foreach my $var (@makevars) {
2687            my $prefix = '';
2688            $prefix = $config{CROSS_COMPILE}
2689                if grep { $var eq $_ } @user_crossable;
2690            $prefix //= '';
2691            print '    ',$var,' ' x (16 - length $var),'= ',
2692                (ref $config{$var} eq 'ARRAY'
2693                 ? join(' ', @{$config{$var}})
2694                 : $prefix.$config{$var}),
2695                "\n"
2696                if defined $config{$var};
2697        }
2698
2699        my @buildfile = ($config{builddir}, $config{build_file});
2700        unshift @buildfile, $here
2701            unless file_name_is_absolute($config{builddir});
2702        my $buildfile = canonpath(catdir(@buildfile));
2703        print <<"_____";
2704
2705NOTE: These variables only represent the configuration view.  The build file
2706template may have processed these variables further, please have a look at the
2707build file for more exact data:
2708    $buildfile
2709_____
2710    }
2711    if ($dump || $buildparams) {
2712        my @buildfile = ($config{builddir}, $config{build_file});
2713        unshift @buildfile, $here
2714            unless file_name_is_absolute($config{builddir});
2715        print "\nbuild file:\n\n";
2716        print "    ", canonpath(catfile(@buildfile)),"\n";
2717
2718        print "\nbuild file templates:\n\n";
2719        foreach (@{$config{build_file_templates}}) {
2720            my @tmpl = ($_);
2721            unshift @tmpl, $here
2722                unless file_name_is_absolute($config{sourcedir});
2723            print '    ',canonpath(catfile(@tmpl)),"\n";
2724        }
2725    }
2726    if ($reconf) {
2727        if ($verbose) {
2728            print 'Reconfiguring with: ', join(' ',@{$config{perlargv}}), "\n";
2729            foreach (sort keys %{$config{perlenv}}) {
2730                print '    ',$_,' = ',($config{perlenv}->{$_} || ""),"\n";
2731            }
2732        }
2733
2734        chdir $here;
2735        exec $^X,catfile($config{sourcedir}, 'Configure'),'reconf';
2736    }
2737}
2738
27391;
2740
2741__END__
2742
2743=head1 NAME
2744
2745configdata.pm - configuration data for OpenSSL builds
2746
2747=head1 SYNOPSIS
2748
2749Interactive:
2750
2751  perl configdata.pm [options]
2752
2753As data bank module:
2754
2755  use configdata;
2756
2757=head1 DESCRIPTION
2758
2759This module can be used in two modes, interactively and as a module containing
2760all the data recorded by OpenSSL's Configure script.
2761
2762When used interactively, simply run it as any perl script, with at least one
2763option, and you will get the information you ask for.  See L</OPTIONS> below.
2764
2765When loaded as a module, you get a few databanks with useful information to
2766perform build related tasks.  The databanks are:
2767
2768    %config             Configured things.
2769    %target             The OpenSSL config target with all inheritances
2770                        resolved.
2771    %disabled           The features that are disabled.
2772    @disablables        The list of features that can be disabled.
2773    %withargs           All data given through --with-THING options.
2774    %unified_info       All information that was computed from the build.info
2775                        files.
2776
2777=head1 OPTIONS
2778
2779=over 4
2780
2781=item B<--help>
2782
2783Print a brief help message and exit.
2784
2785=item B<--man>
2786
2787Print the manual page and exit.
2788
2789=item B<--dump> | B<-d>
2790
2791Print all relevant configuration data.  This is equivalent to B<--command-line>
2792B<--options> B<--target> B<--environment> B<--make-variables>
2793B<--build-parameters>.
2794
2795=item B<--command-line> | B<-c>
2796
2797Print the current configuration command line.
2798
2799=item B<--options> | B<-o>
2800
2801Print the features, both enabled and disabled, and display defined macro and
2802skipped directories where applicable.
2803
2804=item B<--target> | B<-t>
2805
2806Print the config attributes for this config target.
2807
2808=item B<--environment> | B<-e>
2809
2810Print the environment variables and their values at the time of configuration.
2811
2812=item B<--make-variables> | B<-m>
2813
2814Print the main make variables generated in the current configuration
2815
2816=item B<--build-parameters> | B<-b>
2817
2818Print the build parameters, i.e. build file and build file templates.
2819
2820=item B<--reconfigure> | B<--reconf> | B<-r>
2821
2822Redo the configuration.
2823
2824=item B<--verbose> | B<-v>
2825
2826Verbose output.
2827
2828=back
2829
2830=cut
2831
2832EOF
2833close(OUT);
2834if ($builder_platform eq 'unix') {
2835    my $mode = (0755 & ~umask);
2836    chmod $mode, 'configdata.pm'
2837        or warn sprintf("WARNING: Couldn't change mode for 'configdata.pm' to 0%03o: %s\n",$mode,$!);
2838}
2839
2840my %builders = (
2841    unified => sub {
2842        print 'Creating ',$target{build_file},"\n";
2843        run_dofile(catfile($blddir, $target{build_file}),
2844                   @{$config{build_file_templates}});
2845    },
2846    );
2847
2848$builders{$builder}->($builder_platform, @builder_opts);
2849
2850$SIG{__DIE__} = $orig_death_handler;
2851
2852print <<"EOF" if ($disabled{threads} eq "unavailable");
2853
2854The library could not be configured for supporting multi-threaded
2855applications as the compiler options required on this system are not known.
2856See file INSTALL for details if you need multi-threading.
2857EOF
2858
2859print <<"EOF" if ($no_shared_warn);
2860
2861The options 'shared', 'pic' and 'dynamic-engine' aren't supported on this
2862platform, so we will pretend you gave the option 'no-pic', which also disables
2863'shared' and 'dynamic-engine'.  If you know how to implement shared libraries
2864or position independent code, please let us know (but please first make sure
2865you have tried with a current version of OpenSSL).
2866EOF
2867
2868print <<"EOF";
2869
2870**********************************************************************
2871***                                                                ***
2872***   OpenSSL has been successfully configured                     ***
2873***                                                                ***
2874***   If you encounter a problem while building, please open an    ***
2875***   issue on GitHub <https://github.com/openssl/openssl/issues>  ***
2876***   and include the output from the following command:           ***
2877***                                                                ***
2878***       perl configdata.pm --dump                                ***
2879***                                                                ***
2880***   (If you are new to OpenSSL, you might want to consult the    ***
2881***   'Troubleshooting' section in the INSTALL file first)         ***
2882***                                                                ***
2883**********************************************************************
2884EOF
2885
2886exit(0);
2887
2888######################################################################
2889#
2890# Helpers and utility functions
2891#
2892
2893# Death handler, to print a helpful message in case of failure #######
2894#
2895sub death_handler {
2896    die @_ if $^S;              # To prevent the added message in eval blocks
2897    my $build_file = $target{build_file} // "build file";
2898    my @message = ( <<"_____", @_ );
2899
2900Failure!  $build_file wasn't produced.
2901Please read INSTALL and associated NOTES files.  You may also have to look over
2902your available compiler tool chain or change your configuration.
2903
2904_____
2905
2906    # Dying is terminal, so it's ok to reset the signal handler here.
2907    $SIG{__DIE__} = $orig_death_handler;
2908    die @message;
2909}
2910
2911# Configuration file reading #########################################
2912
2913# Note: All of the helper functions are for lazy evaluation.  They all
2914# return a CODE ref, which will return the intended value when evaluated.
2915# Thus, whenever there's mention of a returned value, it's about that
2916# intended value.
2917
2918# Helper function to implement conditional inheritance depending on the
2919# value of $disabled{asm}.  Used in inherit_from values as follows:
2920#
2921#      inherit_from => [ "template", asm("asm_tmpl") ]
2922#
2923sub asm {
2924    my @x = @_;
2925    sub {
2926        $disabled{asm} ? () : @x;
2927    }
2928}
2929
2930# Helper function to implement conditional value variants, with a default
2931# plus additional values based on the value of $config{build_type}.
2932# Arguments are given in hash table form:
2933#
2934#       picker(default => "Basic string: ",
2935#              debug   => "debug",
2936#              release => "release")
2937#
2938# When configuring with --debug, the resulting string will be
2939# "Basic string: debug", and when not, it will be "Basic string: release"
2940#
2941# This can be used to create variants of sets of flags according to the
2942# build type:
2943#
2944#       cflags => picker(default => "-Wall",
2945#                        debug   => "-g -O0",
2946#                        release => "-O3")
2947#
2948sub picker {
2949    my %opts = @_;
2950    return sub { add($opts{default} || (),
2951                     $opts{$config{build_type}} || ())->(); }
2952}
2953
2954# Helper function to combine several values of different types into one.
2955# This is useful if you want to combine a string with the result of a
2956# lazy function, such as:
2957#
2958#       cflags => combine("-Wall", sub { $disabled{zlib} ? () : "-DZLIB" })
2959#
2960sub combine {
2961    my @stuff = @_;
2962    return sub { add(@stuff)->(); }
2963}
2964
2965# Helper function to implement conditional values depending on the value
2966# of $disabled{threads}.  Can be used as follows:
2967#
2968#       cflags => combine("-Wall", threads("-pthread"))
2969#
2970sub threads {
2971    my @flags = @_;
2972    return sub { add($disabled{threads} ? () : @flags)->(); }
2973}
2974
2975sub shared {
2976    my @flags = @_;
2977    return sub { add($disabled{shared} ? () : @flags)->(); }
2978}
2979
2980our $add_called = 0;
2981# Helper function to implement adding values to already existing configuration
2982# values.  It handles elements that are ARRAYs, CODEs and scalars
2983sub _add {
2984    my $separator = shift;
2985
2986    # If there's any ARRAY in the collection of values OR the separator
2987    # is undef, we will return an ARRAY of combined values, otherwise a
2988    # string of joined values with $separator as the separator.
2989    my $found_array = !defined($separator);
2990
2991    my @values =
2992        map {
2993            my $res = $_;
2994            while (ref($res) eq "CODE") {
2995                $res = $res->();
2996            }
2997            if (defined($res)) {
2998                if (ref($res) eq "ARRAY") {
2999                    $found_array = 1;
3000                    @$res;
3001                } else {
3002                    $res;
3003                }
3004            } else {
3005                ();
3006            }
3007    } (@_);
3008
3009    $add_called = 1;
3010
3011    if ($found_array) {
3012        [ @values ];
3013    } else {
3014        join($separator, grep { defined($_) && $_ ne "" } @values);
3015    }
3016}
3017sub add_before {
3018    my $separator = " ";
3019    if (ref($_[$#_]) eq "HASH") {
3020        my $opts = pop;
3021        $separator = $opts->{separator};
3022    }
3023    my @x = @_;
3024    sub { _add($separator, @x, @_) };
3025}
3026sub add {
3027    my $separator = " ";
3028    if (ref($_[$#_]) eq "HASH") {
3029        my $opts = pop;
3030        $separator = $opts->{separator};
3031    }
3032    my @x = @_;
3033    sub { _add($separator, @_, @x) };
3034}
3035
3036sub read_eval_file {
3037    my $fname = shift;
3038    my $content;
3039    my @result;
3040
3041    open F, "< $fname" or die "Can't open '$fname': $!\n";
3042    {
3043        undef local $/;
3044        $content = <F>;
3045    }
3046    close F;
3047    {
3048        local $@;
3049
3050        @result = ( eval $content );
3051        warn $@ if $@;
3052    }
3053    return wantarray ? @result : $result[0];
3054}
3055
3056# configuration reader, evaluates the input file as a perl script and expects
3057# it to fill %targets with target configurations.  Those are then added to
3058# %table.
3059sub read_config {
3060    my $fname = shift;
3061    my %targets;
3062
3063    {
3064        # Protect certain tables from tampering
3065        local %table = ();
3066
3067        %targets = read_eval_file($fname);
3068    }
3069    my %preexisting = ();
3070    foreach (sort keys %targets) {
3071        $preexisting{$_} = 1 if $table{$_};
3072    }
3073    die <<"EOF",
3074The following config targets from $fname
3075shadow pre-existing config targets with the same name:
3076EOF
3077        map { "  $_\n" } sort keys %preexisting
3078        if %preexisting;
3079
3080
3081    # For each target, check that it's configured with a hash table.
3082    foreach (keys %targets) {
3083        if (ref($targets{$_}) ne "HASH") {
3084            if (ref($targets{$_}) eq "") {
3085                warn "Deprecated target configuration for $_, ignoring...\n";
3086            } else {
3087                warn "Misconfigured target configuration for $_ (should be a hash table), ignoring...\n";
3088            }
3089            delete $targets{$_};
3090        } else {
3091            $targets{$_}->{_conf_fname_int} = add([ $fname ]);
3092        }
3093    }
3094
3095    %table = (%table, %targets);
3096
3097}
3098
3099# configuration resolver.  Will only resolve all the lazy evaluation
3100# codeblocks for the chosen target and all those it inherits from,
3101# recursively
3102sub resolve_config {
3103    my $target = shift;
3104    my @breadcrumbs = @_;
3105
3106#    my $extra_checks = defined($ENV{CONFIGURE_EXTRA_CHECKS});
3107
3108    if (grep { $_ eq $target } @breadcrumbs) {
3109        die "inherit_from loop!  target backtrace:\n  "
3110            ,$target,"\n  ",join("\n  ", @breadcrumbs),"\n";
3111    }
3112
3113    if (!defined($table{$target})) {
3114        warn "Warning! target $target doesn't exist!\n";
3115        return ();
3116    }
3117    # Recurse through all inheritances.  They will be resolved on the
3118    # fly, so when this operation is done, they will all just be a
3119    # bunch of attributes with string values.
3120    # What we get here, though, are keys with references to lists of
3121    # the combined values of them all.  We will deal with lists after
3122    # this stage is done.
3123    my %combined_inheritance = ();
3124    if ($table{$target}->{inherit_from}) {
3125        my @inherit_from =
3126            map { ref($_) eq "CODE" ? $_->() : $_ } @{$table{$target}->{inherit_from}};
3127        foreach (@inherit_from) {
3128            my %inherited_config = resolve_config($_, $target, @breadcrumbs);
3129
3130            # 'template' is a marker that's considered private to
3131            # the config that had it.
3132            delete $inherited_config{template};
3133
3134            foreach (keys %inherited_config) {
3135                if (!$combined_inheritance{$_}) {
3136                    $combined_inheritance{$_} = [];
3137                }
3138                push @{$combined_inheritance{$_}}, $inherited_config{$_};
3139            }
3140        }
3141    }
3142
3143    # We won't need inherit_from in this target any more, since we've
3144    # resolved all the inheritances that lead to this
3145    delete $table{$target}->{inherit_from};
3146
3147    # Now is the time to deal with those lists.  Here's the place to
3148    # decide what shall be done with those lists, all based on the
3149    # values of the target we're currently dealing with.
3150    # - If a value is a coderef, it will be executed with the list of
3151    #   inherited values as arguments.
3152    # - If the corresponding key doesn't have a value at all or is the
3153    #   empty string, the inherited value list will be run through the
3154    #   default combiner (below), and the result becomes this target's
3155    #   value.
3156    # - Otherwise, this target's value is assumed to be a string that
3157    #   will simply override the inherited list of values.
3158    my $default_combiner = add();
3159
3160    my %all_keys =
3161        map { $_ => 1 } (keys %combined_inheritance,
3162                         keys %{$table{$target}});
3163
3164    sub process_values {
3165        my $object    = shift;
3166        my $inherited = shift;  # Always a [ list ]
3167        my $target    = shift;
3168        my $entry     = shift;
3169
3170        $add_called = 0;
3171
3172        while(ref($object) eq "CODE") {
3173            $object = $object->(@$inherited);
3174        }
3175        if (!defined($object)) {
3176            return ();
3177        }
3178        elsif (ref($object) eq "ARRAY") {
3179            local $add_called;  # To make sure recursive calls don't affect it
3180            return [ map { process_values($_, $inherited, $target, $entry) }
3181                     @$object ];
3182        } elsif (ref($object) eq "") {
3183            return $object;
3184        } else {
3185            die "cannot handle reference type ",ref($object)
3186                ," found in target ",$target," -> ",$entry,"\n";
3187        }
3188    }
3189
3190    foreach (sort keys %all_keys) {
3191        my $previous = $combined_inheritance{$_};
3192
3193        # Current target doesn't have a value for the current key?
3194        # Assign it the default combiner, the rest of this loop body
3195        # will handle it just like any other coderef.
3196        if (!exists $table{$target}->{$_}) {
3197            $table{$target}->{$_} = $default_combiner;
3198        }
3199
3200        $table{$target}->{$_} = process_values($table{$target}->{$_},
3201                                               $combined_inheritance{$_},
3202                                               $target, $_);
3203        unless(defined($table{$target}->{$_})) {
3204            delete $table{$target}->{$_};
3205        }
3206#        if ($extra_checks &&
3207#            $previous && !($add_called ||  $previous ~~ $table{$target}->{$_})) {
3208#            warn "$_ got replaced in $target\n";
3209#        }
3210    }
3211
3212    # Finally done, return the result.
3213    return %{$table{$target}};
3214}
3215
3216sub usage
3217        {
3218        print STDERR $usage;
3219        print STDERR "\npick os/compiler from:\n";
3220        my $j=0;
3221        my $i;
3222        my $k=0;
3223        foreach $i (sort keys %table)
3224                {
3225                next if $table{$i}->{template};
3226                next if $i =~ /^debug/;
3227                $k += length($i) + 1;
3228                if ($k > 78)
3229                        {
3230                        print STDERR "\n";
3231                        $k=length($i);
3232                        }
3233                print STDERR $i . " ";
3234                }
3235        foreach $i (sort keys %table)
3236                {
3237                next if $table{$i}->{template};
3238                next if $i !~ /^debug/;
3239                $k += length($i) + 1;
3240                if ($k > 78)
3241                        {
3242                        print STDERR "\n";
3243                        $k=length($i);
3244                        }
3245                print STDERR $i . " ";
3246                }
3247        print STDERR "\n\nNOTE: If in doubt, on Unix-ish systems use './config'.\n";
3248        exit(1);
3249        }
3250
3251sub run_dofile
3252{
3253    my $out = shift;
3254    my @templates = @_;
3255
3256    unlink $out || warn "Can't remove $out, $!"
3257        if -f $out;
3258    foreach (@templates) {
3259        die "Can't open $_, $!" unless -f $_;
3260    }
3261    my $perlcmd = (quotify("maybeshell", $config{PERL}))[0];
3262    my $cmd = "$perlcmd \"-I.\" \"-Mconfigdata\" \"$dofile\" -o\"Configure\" \"".join("\" \"",@templates)."\" > \"$out.new\"";
3263    #print STDERR "DEBUG[run_dofile]: \$cmd = $cmd\n";
3264    system($cmd);
3265    exit 1 if $? != 0;
3266    rename("$out.new", $out) || die "Can't rename $out.new, $!";
3267}
3268
3269sub compiler_predefined {
3270    state %predefined;
3271    my $cc = shift;
3272
3273    return () if $^O eq 'VMS';
3274
3275    die 'compiler_predefined called without a compiler command'
3276        unless $cc;
3277
3278    if (! $predefined{$cc}) {
3279
3280        $predefined{$cc} = {};
3281
3282        # collect compiler pre-defines from gcc or gcc-alike...
3283        open(PIPE, "$cc -dM -E -x c /dev/null 2>&1 |");
3284        while (my $l = <PIPE>) {
3285            $l =~ m/^#define\s+(\w+(?:\(\w+\))?)(?:\s+(.+))?/ or last;
3286            $predefined{$cc}->{$1} = $2 // '';
3287        }
3288        close(PIPE);
3289    }
3290
3291    return %{$predefined{$cc}};
3292}
3293
3294sub which
3295{
3296    my ($name)=@_;
3297
3298    if (eval { require IPC::Cmd; 1; }) {
3299        IPC::Cmd->import();
3300        return scalar IPC::Cmd::can_run($name);
3301    } else {
3302        # if there is $directories component in splitpath,
3303        # then it's not something to test with $PATH...
3304        return $name if (File::Spec->splitpath($name))[1];
3305
3306        foreach (File::Spec->path()) {
3307            my $fullpath = catfile($_, "$name$target{exe_extension}");
3308            if (-f $fullpath and -x $fullpath) {
3309                return $fullpath;
3310            }
3311        }
3312    }
3313}
3314
3315sub env
3316{
3317    my $name = shift;
3318    my %opts = @_;
3319
3320    unless ($opts{cacheonly}) {
3321        # Note that if $ENV{$name} doesn't exist or is undefined,
3322        # $config{perlenv}->{$name} will be created with the value
3323        # undef.  This is intentional.
3324
3325        $config{perlenv}->{$name} = $ENV{$name}
3326            if ! exists $config{perlenv}->{$name};
3327    }
3328    return $config{perlenv}->{$name};
3329}
3330
3331# Configuration printer ##############################################
3332
3333sub print_table_entry
3334{
3335    local $now_printing = shift;
3336    my %target = resolve_config($now_printing);
3337    my $type = shift;
3338
3339    # Don't print the templates
3340    return if $target{template};
3341
3342    my @sequence = (
3343        "sys_id",
3344        "cpp",
3345        "cppflags",
3346        "defines",
3347        "includes",
3348        "cc",
3349        "cflags",
3350        "unistd",
3351        "ld",
3352        "lflags",
3353        "loutflag",
3354        "ex_libs",
3355        "bn_ops",
3356        "apps_aux_src",
3357        "cpuid_asm_src",
3358        "uplink_aux_src",
3359        "bn_asm_src",
3360        "ec_asm_src",
3361        "des_asm_src",
3362        "aes_asm_src",
3363        "bf_asm_src",
3364        "md5_asm_src",
3365        "cast_asm_src",
3366        "sha1_asm_src",
3367        "rc4_asm_src",
3368        "rmd160_asm_src",
3369        "rc5_asm_src",
3370        "wp_asm_src",
3371        "cmll_asm_src",
3372        "modes_asm_src",
3373        "padlock_asm_src",
3374        "chacha_asm_src",
3375        "poly1035_asm_src",
3376        "thread_scheme",
3377        "perlasm_scheme",
3378        "dso_scheme",
3379        "shared_target",
3380        "shared_cflag",
3381        "shared_defines",
3382        "shared_ldflag",
3383        "shared_rcflag",
3384        "shared_extension",
3385        "dso_extension",
3386        "obj_extension",
3387        "exe_extension",
3388        "ranlib",
3389        "ar",
3390        "arflags",
3391        "aroutflag",
3392        "rc",
3393        "rcflags",
3394        "rcoutflag",
3395        "mt",
3396        "mtflags",
3397        "mtinflag",
3398        "mtoutflag",
3399        "multilib",
3400        "build_scheme",
3401        );
3402
3403    if ($type eq "TABLE") {
3404        print "\n";
3405        print "*** $now_printing\n";
3406        foreach (@sequence) {
3407            if (ref($target{$_}) eq "ARRAY") {
3408                printf "\$%-12s = %s\n", $_, join(" ", @{$target{$_}});
3409            } else {
3410                printf "\$%-12s = %s\n", $_, $target{$_};
3411            }
3412        }
3413    } elsif ($type eq "HASH") {
3414        my $largest =
3415            length((sort { length($a) <=> length($b) } @sequence)[-1]);
3416        print "    '$now_printing' => {\n";
3417        foreach (@sequence) {
3418            if ($target{$_}) {
3419                if (ref($target{$_}) eq "ARRAY") {
3420                    print "      '",$_,"'"," " x ($largest - length($_))," => [ ",join(", ", map { "'$_'" } @{$target{$_}})," ],\n";
3421                } else {
3422                    print "      '",$_,"'"," " x ($largest - length($_))," => '",$target{$_},"',\n";
3423                }
3424            }
3425        }
3426        print "    },\n";
3427    }
3428}
3429
3430# Utility routines ###################################################
3431
3432# On VMS, if the given file is a logical name, File::Spec::Functions
3433# will consider it an absolute path.  There are cases when we want a
3434# purely syntactic check without checking the environment.
3435sub isabsolute {
3436    my $file = shift;
3437
3438    # On non-platforms, we just use file_name_is_absolute().
3439    return file_name_is_absolute($file) unless $^O eq "VMS";
3440
3441    # If the file spec includes a device or a directory spec,
3442    # file_name_is_absolute() is perfectly safe.
3443    return file_name_is_absolute($file) if $file =~ m|[:\[]|;
3444
3445    # Here, we know the given file spec isn't absolute
3446    return 0;
3447}
3448
3449# Makes a directory absolute and cleans out /../ in paths like foo/../bar
3450# On some platforms, this uses rel2abs(), while on others, realpath() is used.
3451# realpath() requires that at least all path components except the last is an
3452# existing directory.  On VMS, the last component of the directory spec must
3453# exist.
3454sub absolutedir {
3455    my $dir = shift;
3456
3457    # realpath() is quite buggy on VMS.  It uses LIB$FID_TO_NAME, which
3458    # will return the volume name for the device, no matter what.  Also,
3459    # it will return an incorrect directory spec if the argument is a
3460    # directory that doesn't exist.
3461    if ($^O eq "VMS") {
3462        return rel2abs($dir);
3463    }
3464
3465    # We use realpath() on Unix, since no other will properly clean out
3466    # a directory spec.
3467    use Cwd qw/realpath/;
3468
3469    return realpath($dir);
3470}
3471
3472# Check if all paths are one and the same, using stat.  They must both exist
3473# We need this for the cases when File::Spec doesn't detect case insensitivity
3474# (File::Spec::Unix assumes case sensitivity)
3475sub samedir {
3476    die "samedir expects two arguments\n" unless scalar @_ == 2;
3477
3478    my @stat0 = stat($_[0]);    # First argument
3479    my @stat1 = stat($_[1]);    # Second argument
3480
3481    die "Couldn't stat $_[0]" unless @stat0;
3482    die "Couldn't stat $_[1]" unless @stat1;
3483
3484    # Compare device number
3485    return 0 unless ($stat0[0] == $stat1[0]);
3486    # Compare "inode".  The perl manual recommends comparing as
3487    # string rather than as number.
3488    return 0 unless ($stat0[1] eq $stat1[1]);
3489
3490    return 1;                   # All the same
3491}
3492
3493sub quotify {
3494    my %processors = (
3495        perl    => sub { my $x = shift;
3496                         $x =~ s/([\\\$\@"])/\\$1/g;
3497                         return '"'.$x.'"'; },
3498        maybeshell => sub { my $x = shift;
3499                            (my $y = $x) =~ s/([\\\"])/\\$1/g;
3500                            if ($x ne $y || $x =~ m|\s|) {
3501                                return '"'.$y.'"';
3502                            } else {
3503                                return $x;
3504                            }
3505                        },
3506        );
3507    my $for = shift;
3508    my $processor =
3509        defined($processors{$for}) ? $processors{$for} : sub { shift; };
3510
3511    return map { $processor->($_); } @_;
3512}
3513
3514# collect_from_file($filename, $line_concat_cond_re, $line_concat)
3515# $filename is a file name to read from
3516# $line_concat_cond_re is a regexp detecting a line continuation ending
3517# $line_concat is a CODEref that takes care of concatenating two lines
3518sub collect_from_file {
3519    my $filename = shift;
3520    my $line_concat_cond_re = shift;
3521    my $line_concat = shift;
3522
3523    open my $fh, $filename || die "unable to read $filename: $!\n";
3524    return sub {
3525        my $saved_line = "";
3526        $_ = "";
3527        while (<$fh>) {
3528            s|\R$||;
3529            if (defined $line_concat) {
3530                $_ = $line_concat->($saved_line, $_);
3531                $saved_line = "";
3532            }
3533            if (defined $line_concat_cond_re && /$line_concat_cond_re/) {
3534                $saved_line = $_;
3535                next;
3536            }
3537            return $_;
3538        }
3539        die "$filename ending with continuation line\n" if $_;
3540        close $fh;
3541        return undef;
3542    }
3543}
3544
3545# collect_from_array($array, $line_concat_cond_re, $line_concat)
3546# $array is an ARRAYref of lines
3547# $line_concat_cond_re is a regexp detecting a line continuation ending
3548# $line_concat is a CODEref that takes care of concatenating two lines
3549sub collect_from_array {
3550    my $array = shift;
3551    my $line_concat_cond_re = shift;
3552    my $line_concat = shift;
3553    my @array = (@$array);
3554
3555    return sub {
3556        my $saved_line = "";
3557        $_ = "";
3558        while (defined($_ = shift @array)) {
3559            s|\R$||;
3560            if (defined $line_concat) {
3561                $_ = $line_concat->($saved_line, $_);
3562                $saved_line = "";
3563            }
3564            if (defined $line_concat_cond_re && /$line_concat_cond_re/) {
3565                $saved_line = $_;
3566                next;
3567            }
3568            return $_;
3569        }
3570        die "input text ending with continuation line\n" if $_;
3571        return undef;
3572    }
3573}
3574
3575# collect_information($lineiterator, $line_continue, $regexp => $CODEref, ...)
3576# $lineiterator is a CODEref that delivers one line at a time.
3577# All following arguments are regex/CODEref pairs, where the regexp detects a
3578# line and the CODEref does something with the result of the regexp.
3579sub collect_information {
3580    my $lineiterator = shift;
3581    my %collectors = @_;
3582
3583    while(defined($_ = $lineiterator->())) {
3584        s|\R$||;
3585        my $found = 0;
3586        if ($collectors{"BEFORE"}) {
3587            $collectors{"BEFORE"}->($_);
3588        }
3589        foreach my $re (keys %collectors) {
3590            if ($re !~ /^OTHERWISE|BEFORE|AFTER$/ && /$re/) {
3591                $collectors{$re}->($lineiterator);
3592                $found = 1;
3593            };
3594        }
3595        if ($collectors{"OTHERWISE"}) {
3596            $collectors{"OTHERWISE"}->($lineiterator, $_)
3597                unless $found || !defined $collectors{"OTHERWISE"};
3598        }
3599        if ($collectors{"AFTER"}) {
3600            $collectors{"AFTER"}->($_);
3601        }
3602    }
3603}
3604
3605# tokenize($line)
3606# $line is a line of text to split up into tokens
3607# returns a list of tokens
3608#
3609# Tokens are divided by spaces.  If the tokens include spaces, they
3610# have to be quoted with single or double quotes.  Double quotes
3611# inside a double quoted token must be escaped.  Escaping is done
3612# with backslash.
3613# Basically, the same quoting rules apply for " and ' as in any
3614# Unix shell.
3615sub tokenize {
3616    my $line = my $debug_line = shift;
3617    my @result = ();
3618
3619    while ($line =~ s|^\s+||, $line ne "") {
3620        my $token = "";
3621        while ($line ne "" && $line !~ m|^\s|) {
3622            if ($line =~ m/^"((?:[^"\\]+|\\.)*)"/) {
3623                $token .= $1;
3624                $line = $';
3625            } elsif ($line =~ m/^'([^']*)'/) {
3626                $token .= $1;
3627                $line = $';
3628            } elsif ($line =~ m/^(\S+)/) {
3629                $token .= $1;
3630                $line = $';
3631            }
3632        }
3633        push @result, $token;
3634    }
3635
3636    if ($ENV{CONFIGURE_DEBUG_TOKENIZE}) {
3637        print STDERR "DEBUG[tokenize]: Parsed '$debug_line' into:\n";
3638        print STDERR "DEBUG[tokenize]: ('", join("', '", @result), "')\n";
3639    }
3640    return @result;
3641}
3642