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