Processing GNU-style "make variables" - implementation
authorRichard Levitte <levitte@openssl.org>
Fri, 26 Jan 2018 18:56:44 +0000 (19:56 +0100)
committerRichard Levitte <levitte@openssl.org>
Sun, 28 Jan 2018 06:26:11 +0000 (07:26 +0100)
Support the following "make variables":

AR              (GNU compatible)
ARFLAGS         (GNU Compatible)
AS              (GNU Compatible)
ASFLAGS         (GNU Compatible)
CC              (GNU Compatible)
CFLAGS          (GNU Compatible)
CXX             (GNU Compatible)
CXXFLAGS        (GNU Compatible)
CPP             (GNU Compatible)
CPPFLAGS        (GNU Compatible)
CPPDEFINES      List of CPP macro definitions.  Alternative for -D
CPPINCLUDES     List of CPP inclusion directories.  Alternative for -I
HASHBANGPERL    Perl invocation to be inserted after '#!' in public
                perl scripts.
LDFLAGS         (GNU Compatible)
LDLIBS          (GNU Compatible)
RANLIB          Program to generate library archive index
RC              Program to manipulate Windows resources
RCFLAGS         Flags for $(RC)
RM              (GNU Compatible)

Setting one of these overrides the corresponding data from our config
targets.  However, flags given directly on the configuration command
line are additional, and are therefore added to the flags coming from
one of the variables above or the config target.

Fixes #2420

Reviewed-by: Tim Hudson <tjh@openssl.org>
Reviewed-by: Rich Salz <rsalz@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/5177)

Configurations/10-main.conf
Configurations/descrip.mms.tmpl
Configurations/shared-info.pl
Configurations/unix-Makefile.tmpl
Configurations/windows-makefile.tmpl
Configure
INSTALL

index 9a27dc9065bd86310afc851a5154a7a741eb820e..e773563dabee870a35c391e75f3e7fbb966e89b2 100644 (file)
@@ -1408,7 +1408,7 @@ my %targets = (
             # WIN32 UNICODE build gets linked with unicows.lib for
             # backward compatibility with Win9x.
             push @ex_libs, 'unicows.lib'
-                if (grep { $_ eq "UNICODE" } @user_defines);
+                if (grep { $_ eq "UNICODE" } @{$user{CPPDEFINES}});
             return join(" ", @ex_libs, @_);
         }),
         sys_id           => "WIN32",
index 9995b43b9f6c0343447b2a87f3cf9c3a88b20b0e..87c6834a14dcd97689c21df65516e48ac8ebf013 100644 (file)
@@ -171,16 +171,16 @@ OPENSSLDIR_C={- $osslprefix -}DATAROOT:[000000]
 # Where installed engines reside, for C
 ENGINESDIR_C={- $osslprefix -}ENGINES{- $sover_dirname.$target{pointer_size} -}:
 
-CC= {- $target{cc} -}
+CC= {- $config{cc} -}
 DEFINES={- our $defines = join(",",
                                '__dummy', # To make comma processing easier
-                               @{$target{defines}}, @{$config{defines}}) -}
-CPPFLAGS={- our $cppflags = join('', $target{cppflags}, $config{cppflags}) -}
+                               @{$config{defines}}) -}
+CPPFLAGS={- our $cppflags = join('', @{$config{cppflags}}) -}
 CPPFLAGS_Q={- $cppflags =~ s|"|""|g; $defines =~ s|"|""|g;
               $cppflags."/DEFINE($defines)" -}
-CFLAGS={- $target{cflags} -} {- $config{cflags} -}
-LDFLAGS= {- $target{lflags} -}
-EX_LIBS= {- $target{ex_libs} ? ",".$target{ex_libs} : "" -}{- $config{ex_libs} ? ",".$config{ex_libs} : "" -}
+CFLAGS={- join('', @{$config{cflags}}) -}
+LDFLAGS= {- join('', @{$config{lflags}}) -}
+EX_LIBS= {- join('', map { ','.$_ } @{$config{ex_libs}}) -}
 LIB_DEFINES={- join("",
                     (map { ",$_" }
                      @{$target{shared_defines}},
@@ -200,8 +200,8 @@ PERL={- $config{perl} -}
 # dependent assembler flags. E.g. if you throw -mcpu=ultrasparc at SPARC
 # gcc, then the driver will automatically translate it to -xarch=v8plus
 # and pass it down to assembler.
-AS={- $target{as} -}
-ASFLAG={- $target{asflags} -}
+AS={- $config{as} -}
+ASFLAGS={- join('', @{$config{asflags}}) -}
 
 # .FIRST and .LAST are special targets with MMS and MMK.
 # The defines in there are for C.  includes that look like
index c5ebfc6e378fa64d033d4881f2b1a27858a1e969..d3e6941eb6213aad2c48a8cb7963a8ca66ce3a83 100644 (file)
 
 sub detect_gnu_ld {
     my @lines =
-        `$config{cross_compile_prefix}$target{cc} -Wl,-V /dev/null 2>&1`;
+        `$config{cross_compile_prefix}$config{cc} -Wl,-V /dev/null 2>&1`;
     return grep /^GNU ld/, @lines;
 }
 sub detect_gnu_cc {
     my @lines =
-        `$config{cross_compile_prefix}$target{cc} -v 2>&1`;
+        `$config{cross_compile_prefix}$config{cc} -v 2>&1`;
     return grep /gcc/, @lines;
 }
 
index 4c4506bfb4e0a3a1f1e49209114fdf5582772d6d..1eb5818ddc73134a833814e0f61bae5d47e52b14 100644 (file)
@@ -185,24 +185,22 @@ ECHO = echo
 
 CROSS_COMPILE= {- $config{cross_compile_prefix} -}
 CPPFLAGS={- our $cppflags = join(" ",
-                                 (map { "-D".$_}
-                                  @{$target{defines}}, @{$config{defines}}),
-                                 (map { "-I".$_}
-                                  @{$target{includes}}, @{$config{includes}}),
-                                 $target{cppflags}, $config{cppflags}) -}
+                                 (map { "-D".$_} @{$config{defines}}),
+                                 (map { "-I".$_} @{$config{includes}}),
+                                 @{$config{cppflags}}) -}
 CPPFLAGS_Q={- $cppflags =~ s|([\\"])|\\$1|g; $cppflags -}
-CC= $(CROSS_COMPILE){- $target{cc} -}
-CFLAGS={- $target{cflags} -} {- $config{cflags} -}
-CXX= $(CROSS_COMPILE){- $target{cxx} -}
-CXXFLAGS={- $target{cxxflags} -} {- $config{cxxflags} -} -std=c++11
-LDFLAGS= {- $config{lflags} -} {- $target{lflags} -}
-PLIB_LDFLAGS= {- $target{plib_lflags} -}
-EX_LIBS= {- $target{ex_libs} -} {- $config{ex_libs} -}
-LIB_CPPFLAGS={- join(" ",
-                     (map { "-D".$_}
-                      'OPENSSLDIR="\"$(OPENSSLDIR)\""',
-                      'ENGINESDIR="\"$(ENGINESDIR)\""'),
-                     $target{shared_cppflag} || "") -}
+CC= $(CROSS_COMPILE){- $config{cc} -}
+CFLAGS={- join(' ', @{$config{cflags}}) -}
+CXX= $(CROSS_COMPILE){- $config{cxx} -}
+CXXFLAGS={- join(' ', @{$config{cxxflags}}) -} -std=c++11
+LDFLAGS= {- join(' ', @{$config{lflags}}) -}
+PLIB_LDFLAGS= {- join(' ', @{$config{plib_lflags}}) -}
+EX_LIBS= {- join(' ', @{$config{ex_libs}}) -}
+LIB_CPPFLAGS={- join(' ',
+                     (map { '-D'.$_ }
+                          ('OPENSSLDIR="\"$(OPENSSLDIR)\""',
+                           'ENGINESDIR="\"$(ENGINESDIR)\""')),
+                     $target{shared_cppflag}) || "" -}
 LIB_CFLAGS={- $target{shared_cflag} || "" -}
 LIB_CXXFLAGS={- $target{shared_cxxflag} || "" -}
 LIB_LDFLAGS={- $target{shared_ldflag}." ".$config{shared_ldflag} -}
@@ -217,12 +215,11 @@ BIN_LDFLAGS={- $target{bin_lflags} || "" -}
 
 PERL={- $config{perl} -}
 
-ARFLAGS= {- $target{arflags} -}
-AR=$(CROSS_COMPILE){- $target{ar} || "ar" -} $(ARFLAGS) r
-RANLIB= {- $target{ranlib} -}
-NM= $(CROSS_COMPILE){- $target{nm} || "nm" -}
-RCFLAGS={- $target{shared_rcflag} -}
+AR=$(CROSS_COMPILE){- $config{ar} -}
+ARFLAGS= {- join(' ', @{$config{arflags}}) -}
+RANLIB= {- $config{ranlib} -}
 RC= $(CROSS_COMPILE){- $target{rc} || "windres" -}
+RCFLAGS={- join(' ', @{$config{rcflags}}) -} {- $target{shared_rcflag} -}
 RM= rm -f
 RMDIR= rmdir
 TAR= {- $target{tar} || "tar" -}
@@ -238,8 +235,8 @@ TARFILE=        ../$(NAME).tar
 # dependent assembler flags. E.g. if you throw -mcpu=ultrasparc at SPARC
 # gcc, then the driver will automatically translate it to -xarch=v8plus
 # and pass it down to assembler.
-AS=$(CC) -c
-ASFLAG=$(CFLAGS)
+AS={- $config{as} || '$(CC) -c' -}
+ASFLAGS={- join(' ', @{$config{asflags}}) || '$(CFLAGS)' -}
 PERLASM_SCHEME= {- $target{perlasm_scheme} -}
 
 # For x86 assembler: Set PROCESSOR to 386 if you want to support
@@ -1057,7 +1054,7 @@ EOF
       my $objs = join(" ", @objs);
       return <<"EOF";
 $lib$libext: $objs
-       \$(AR) \$\@ \$\?
+       \$(AR) \$(ARFLAGS) \$\@ \$\?
        \$(RANLIB) \$\@ || echo Never mind.
 EOF
   }
index 95d7334dc61d77413066935a0de59decaff44094..082ce0798daf44c02c40232c608365daaa14780b 100644 (file)
@@ -159,29 +159,27 @@ OPENSSLDIR=$(OPENSSLDIR_dev)$(OPENSSLDIR_dir)
 ENGINESDIR=$(ENGINESDIR_dev)$(ENGINESDIR_dir)
 !ENDIF
 
-CC={- $target{cc} -}
+CC={- $config{cc} -}
 CPPFLAGS={- our $cppflags = join(" ",
-                                 (map { "-D".$_}
-                                  @{$target{defines}}, @{$config{defines}}),
-                                 (map { " /I ".$_}
-                                  @{$target{includes}}, @{$config{includes}}),
-                                 $target{cppflags}, $config{cppflags}) -}
+                                 (map { "-D".$_} @{$config{defines}}),
+                                 (map { " /I ".$_} @{$config{includes}}),
+                                 @{$config{cppflags}}) -}
 CPPFLAGS_Q={- $cppflags =~ s|([\\"])|\\$1|g; $cppflags -}
-CFLAGS={- $target{cflags} -} {- $config{cflags} -}
+CFLAGS={- join(' ', @{$config{cflags}}) -}
 COUTFLAG={- $target{coutflag} || "/Fo" -}$(OSSL_EMPTY)
-RC={- $target{rc} || "rc" -}
+RC={- $config{rc} -}
 RCOUTFLAG={- $target{rcoutflag} || "/fo" -}$(OSSL_EMPTY)
-LD={- $target{ld} || "link" -}
-LDFLAGS={- $target{lflags} -}
+LD={- $config{ld} -}
+LDFLAGS={- join(' ', @{$config{lflags}}) -}
 LDOUTFLAG={- $target{loutflag} || "/out:" -}$(OSSL_EMPTY)
-EX_LIBS={- $target{ex_libs} -}
+EX_LIBS={- join(' ', @{$config{ex_libs}}) -}
 LIB_CPPFLAGS={- join(" ",
                      $target{shared_cppflag} || "",
                      (map { quotiry_l("-D".$_) }
                       'OPENSSLDIR="$(OPENSSLDIR)"',
                       'ENGINESDIR="$(ENGINESDIR)"')) -}
-LIB_CFLAGS={- join(" ", $target{lib_cflags}, $target{shared_cflag}) || "" -}
-LIB_LDFLAGS={- $target{shared_ldflag} || "" -}
+LIB_CFLAGS={- join(" ", $target{lib_cflags}, $target{shared_cflag}) -}
+LIB_LDFLAGS={- join(' ', $target{shared_ldflag}, $config{shared_ldflag}) -}
 DSO_CPPFLAGS={- $target{dso_cppflags} || "" -}
 DSO_CFLAGS={- $target{dso_cflags} || "" -}
 DSO_LDFLAGS={- $target{dso_ldflag} || "" -}
@@ -191,17 +189,17 @@ BIN_LDFLAGS={- $target{bin_lflags} -}
 
 PERL={- $config{perl} -}
 
-AR={- $target{ar} -}
-ARFLAGS= {- $target{arflags} -}
+AR={- $config{ar} -}
+ARFLAGS= {- join(' ', @{$config{arflags}}) -}
 AROUTFLAG={- $target{aroutflag} || "/out:" -}$(OSSL_EMPTY)
 
-MT={- $target{mt} -}
-MTFLAGS= {- $target{mtflags} -}
+MT={- $config{mt} -}
+MTFLAGS= {- join(' ', @{$config{mtflags}}) -}
 MTINFLAG={- $target{mtinflag} || "-manifest " -}$(OSSL_EMPTY)
 MTOUTFLAG={- $target{mtoutflag} || "-outputresource:" -}$(OSSL_EMPTY)
 
-AS={- $target{as} -}
-ASFLAGS={- $target{asflags} -}
+AS={- $config{as} -}
+ASFLAGS={- join(' ', @{$config{asflags}}) -}
 ASOUTFLAG={- $target{asoutflag} -}$(OSSL_EMPTY)
 PERLASM_SCHEME= {- $target{perlasm_scheme} -}
 
@@ -316,10 +314,10 @@ install_dev:
        @if "$(INSTALLTOP)"=="" ( echo INSTALLTOP should not be empty & exit 1 )
        @echo *** Installing development files
        @"$(PERL)" "$(SRCDIR)\util\mkdir-p.pl" "$(INSTALLTOP)\include\openssl"
-       @rem {- output_off() unless grep { $_ eq "OPENSSL_USE_APPLINK" } @{$target{defines}}; "" -}
+       @rem {- output_off() unless grep { $_ eq "OPENSSL_USE_APPLINK" } @{$config{defines}}; "" -}
        @"$(PERL)" "$(SRCDIR)\util\copy.pl" "$(SRCDIR)\ms\applink.c" \
                                       "$(INSTALLTOP)\include\openssl"
-       @rem {- output_on() unless grep { $_ eq "OPENSSL_USE_APPLINK" } @{$target{defines}}; "" -}
+       @rem {- output_on() unless grep { $_ eq "OPENSSL_USE_APPLINK" } @{$config{defines}}; "" -}
        @"$(PERL)" "$(SRCDIR)\util\copy.pl" "$(SRCDIR)\include\openssl\*.h" \
                                       "$(INSTALLTOP)\include\openssl"
        @"$(PERL)" "$(SRCDIR)\util\copy.pl" $(BLDDIR)\include\openssl\*.h \
index 97696d75d2c5169a108f36b726eec833d3927ec1..c79276b10e20304290c41e03f1e1a793ae0983a5 100755 (executable)
--- a/Configure
+++ b/Configure
@@ -519,20 +519,82 @@ my $no_sse2=0;
 
 &usage if ($#ARGV < 0);
 
-my $user_cflags="";
-my $user_cppflags=();
-my @user_defines=();
-my @user_includes=();
+# For the "make variables" CINCLUDES and CDEFINES, we support lists with
+# platform specific list separators.  Users from those platforms should
+# recognise those separators from how you set up the PATH to find executables.
+# The default is the Unix like separator, :, but as an exception, we also
+# support the space as separator.
+my $list_separator_re =
+    { VMS           => qr/(?<!\^),/,
+      MSWin32       => qr/(?<!\\);/ } -> {$^O} // qr/(?<!\\)[:\s]/;
+# All the "make variables" we support
+my %user = (
+    AR          => undef,
+    ARFLAGS     => [],
+    AS          => undef,
+    ASFLAGS     => [],
+    CC          => undef,
+    CFLAGS      => [],
+    CXX         => undef,
+    CXXFLAGS    => [],
+    CPP         => undef,
+    CPPFLAGS    => [],  # -D, -I, -Wp,
+    CPPDEFINES  => [],  # Alternative for -D
+    CPPINCLUDES => [],  # Alternative for -I
+    HASHBANGPERL=> undef,
+    LD          => undef,
+    LDFLAGS     => [],  # -L, -Wl,
+    LDLIBS      => [],  # -l
+    MT          => undef,
+    MTFLAGS     => [],
+    RANLIB      => undef,
+    RC          => undef,
+    RCFLAGS     => [],
+    RM          => undef,
+   );
+# The same but for flags given as Configure options.  These are *additional*
+# input, as opposed to the VAR=string option that override the corresponding
+# config target attributes
+my %useradd = (
+    CPPDEFINES  => [],
+    CPPINCLUDES => [],
+    CPPFLAGS    => [],
+    CFLAGS      => [],
+    CXXFLAGS    => [],
+    LDFLAGS     => [],
+    LDLIBS      => [],
+   );
+
+my %user_synonyms = (
+    HASHBANGPERL=> 'PERL',
+    RC          => 'WINDRES',
+   );
+my %user_to_target = (
+    # If not given here, the value is the lc of the key
+    CPPDEFINES  => 'defines',
+    CPPINCLUDES => 'includes',
+    LDFLAGS     => 'lflags',
+    LDLIBS      => 'ex_libs',
+   );
+my %user_defaults = (
+    AR          => 'ar',
+    ARFLAGS     => [ 'r' ],
+    CC          => 'cc',
+    CXX         => 'c++',
+    HASHBANGPERL=> '/usr/bin/env perl', # Only Unix actually cares
+    RANLIB      => sub { which("$config{cross_compile_prefix}ranlib") ?
+                             "\$(CROSS_COMPILE)ranlib" : "true"; },
+    RC          => 'windres',
+   );
+
 $config{openssl_api_defines}=[];
 $config{openssl_algorithm_defines}=[];
 $config{openssl_thread_defines}=[];
 $config{openssl_sys_defines}=[];
 $config{openssl_other_defines}=[];
-my $ldflags="";
-my $libs="";
-my $target="";
 $config{options}="";
 $config{build_type} = "release";
+my $target="";
 
 my %unsupported_options = ();
 my %deprecated_options = ();
@@ -547,6 +609,16 @@ while (@argvcopy)
        if (m|^(\w+)=(.+)?$|)
                {
                $config{perlenv}->{$1} = $2;
+               # Every time a variable is given as a configuration argument,
+               # it acts as a reset if the variable.
+               if (exists $user{$1})
+                       {
+                       $user{$1} = ref $user{$1} eq "ARRAY" ? [] : undef;
+                       }
+               if (exists $useradd{$1})
+                       {
+                       $useradd{$1} = [];
+                       }
                next;
                }
 
@@ -734,15 +806,15 @@ while (@argvcopy)
                        }
                elsif (/^-L(.*)$/)
                        {
-                       $ldflags.=$_." ";
+                       push @{$useradd{LDFLAGS}}, $_;
                        }
                elsif (/^-l(.*)$/ or /^-Wl,/)
                        {
-                       $libs.=$_." ";
+                       push @{$useradd{LDLIBS}}, $_;
                        }
                elsif (/^-framework$/)
                        {
-                       $libs.=$_." ".shift(@argvcopy)." ";
+                       push @{$useradd{LDLIBS}}, $_, shift(@argvcopy);
                        }
                elsif (/^-rpath$/ or /^-R$/)
                        # -rpath is the OSF1 rpath flag
@@ -750,11 +822,11 @@ while (@argvcopy)
                        {
                        my $rpath = shift(@argvcopy) || "";
                        $rpath .= " " if $rpath ne "";
-                       $libs.=$_." ".$rpath;
+                       push @{$useradd{LDFLAGS}}, $_, $rpath;
                        }
                elsif (/^-static$/)
                        {
-                       $libs.=$_." ";
+                       push @{$useradd{LDFLAGS}}, $_;
                        $disabled{"dso"} = "forced";
                        $disabled{"pic"} = "forced";
                        $disabled{"shared"} = "forced";
@@ -762,20 +834,21 @@ while (@argvcopy)
                        }
                elsif (/^-D(.*)$/)
                        {
-                       push @user_defines, $1;
+                       push @{$useradd{CPPDEFINES}}, $1;
                        }
                elsif (/^-I(.*)$/)
                        {
-                       push @user_includes, $1;
+                       push @{$useradd{CPPINCLUDES}}, $1;
                        }
                elsif (/^-Wp,$/)
                        {
-                       $user_cppflags.=" ".$_;
+                       push @{$useradd{CPPFLAGS}}, $1;
                        }
                else    # common if (/^[-+]/), just pass down...
                        {
                        $_ =~ s/%([0-9a-f]{1,2})/chr(hex($1))/gei;
-                       $user_cflags.=" ".$_;
+                       push @{$useradd{CFLAGS}}, $_;
+                       push @{$useradd{CXXFLAGS}}, $_;
                        }
                }
        else
@@ -812,7 +885,20 @@ while (@argvcopy)
                }
        }
 
-if ($libs =~ /(^|\s)-Wl,-rpath,/
+foreach (keys %user) {
+    my $value = env($_);
+    $value //= defined $user_synonyms{$_} ? env($user_synonyms{$_}) : undef;
+
+    if (defined $value) {
+        if (ref $user{$_} eq 'ARRAY') {
+            $user{$_} = [ split /$list_separator_re/, $value ];
+        } elsif (!defined $user{$_}) {
+            $user{$_} = $value;
+        }
+    }
+}
+
+if (grep { $_ =~ /(^|\s)-Wl,-rpath,/ } ($user{LDLIBS} ? @{$user{LDLIBS}} : ())
     && !$disabled{shared}
     && !($disabled{asan} && $disabled{msan} && $disabled{ubsan})) {
     die "***** Cannot simultaneously use -rpath, shared libraries, and\n",
@@ -1012,7 +1098,10 @@ foreach (sort (keys %disabled))
                        push @{$config{openssl_other_defines}}, "OPENSSL_NO_$WHAT";
                        print " OPENSSL_NO_$WHAT";
 
-                       if (/^err$/)    { push @user_defines, "OPENSSL_NO_ERR"; }
+                       if (/^err$/)
+                               {
+                               push @{$useradd{CPPDEFINES}}, "OPENSSL_NO_ERR";
+                               }
                        }
                }
 
@@ -1039,37 +1128,51 @@ $config{cross_compile_prefix} = env('CROSS_COMPILE')
 # Note: only Unix cares about HASHBANGPERL...  that explains
 # the default string.
 $config{perl} =    ($^O ne "VMS" ? $^X : "perl");
-$config{hashbangperl} =
-    env('HASHBANGPERL')           || env('PERL')      || "/usr/bin/env perl";
-$target{cc} =      env('CC')      || $target{cc}      || "cc";
-$target{cxx} =     env('CXX')     || $target{cxx}     || "c++";
-$target{ranlib} =  env('RANLIB')  || $target{ranlib}  ||
-                   (which("$config{cross_compile_prefix}ranlib") ?
-                          "\$(CROSS_COMPILE)ranlib" : "true");
-$target{ar} =      env('AR')      || $target{ar}      || "ar";
-$target{nm} =      env('NM')      || $target{nm}      || "nm";
-$target{rc} =
-    env('RC')  || env('WINDRES')  || $target{rc}      || "windres";
+foreach (keys %user) {
+    my $target_key = $user_to_target{$_} // lc $_;
+    my $ref_type = ref $user{$_};
+
+    # Temporary function.  Takes an intended ref type (empty string or "ARRAY")
+    # and a value that's to be coerced into that type.
+    my $mkvalue = sub {
+        my $type = shift;
+        my $value = shift;
+        my $undef_p = shift;
+
+        die "Too many arguments for \$mkvalue" if @_;
+
+        while (ref $value eq 'CODE') {
+            $value = $value->();
+        }
+
+        if ($type eq 'ARRAY') {
+            return undef unless defined $value;
+            return undef if ref $value ne 'ARRAY' && !$value;
+            return undef if ref $value eq 'ARRAY' && !@$value;
+            return [ $value ] unless ref $value eq 'ARRAY';
+        }
+        return undef unless $value;
+        return $value;
+    };
+
+    $config{$target_key} =
+        $mkvalue->($ref_type, $user{$_})
+        || $mkvalue->($ref_type, $target{$target_key});
+    $config{$target_key} ||=$mkvalue->($ref_type, $user_defaults{$_})
+        if exists $user_defaults{$_};
+    if (defined $useradd{$_} && @{$useradd{$_}}) {
+        if (defined $config{$target_key}) {
+            push @{$config{$target_key}}, @{$useradd{$_}};
+        } else {
+            $config{$target_key} = [ @{$useradd{$_}} ];
+        }
+    }
+    delete $config{$target_key} unless defined $config{$target_key};
+}
+$config{plib_lflags} = [ $target{plib_lflags} ];
 
 # Allow overriding the build file name
-$target{build_file} = env('BUILDFILE') || $target{build_file} || "Makefile";
-
-# Cache information necessary for reconfiguration
-$config{cc} = $target{cc};
-$config{cxx} = $target{cxx};
-$config{build_file} = $target{build_file};
-
-# For cflags, lflags, plib_lflags, ex_libs and defines, add the debug_
-# or release_ attributes.
-# Do it in such a way that no spurious space is appended (hence the grep).
-$config{defines} = [];
-$config{includes} = [];
-$config{cppflags} = "";
-$config{cflags} = "";
-$config{cxxflags} = "";
-$config{lflags} = "";
-$config{ex_libs} = "";
-$config{shared_ldflag} = "";
+$config{build_file} = env('BUILDFILE') || $target{build_file} || "Makefile";
 
 # Make sure build_scheme is consistent.
 $target{build_scheme} = [ $target{build_scheme} ]
@@ -1099,16 +1202,17 @@ foreach my $checker (($builder_platform."-".$target{build_file}."-checker.pm",
 
 push @{$config{defines}}, "NDEBUG"    if $config{build_type} eq "release";
 
-if ($target =~ /^mingw/ && `$target{cc} --target-help 2>&1` =~ m/-mno-cygwin/m)
+if ($target =~ /^mingw/ && `$config{cc} --target-help 2>&1` =~ m/-mno-cygwin/m)
        {
-       $config{cflags} .= " -mno-cygwin";
-       $config{shared_ldflag} .= " -mno-cygwin";
+       push @{$config{cflags}}, "-mno-cygwin";
+       push @{$config{shared_ldflag}}, "-mno-cygwin";
        }
 
-if ($target =~ /linux.*-mips/ && !$disabled{asm} && $user_cflags !~ /-m(ips|arch=)/) {
+if ($target =~ /linux.*-mips/ && !$disabled{asm}
+        && !grep { $_ !~ /-m(ips|arch=)/ } @{$user{CFLAGS}}) {
        # minimally required architecture flags for assembly modules
-       $config{cflags}="-mips2 $config{cflags}" if ($target =~ /mips32/);
-       $config{cflags}="-mips3 $config{cflags}" if ($target =~ /mips64/);
+       unshift @{$config{cflags}}, '-mips2' if ($target =~ /mips32/);
+       unshift @{$config{cflags}}, '-mips3' if ($target =~ /mips64/);
 }
 
 # The DSO code currently always implements all functions so that no
@@ -1134,9 +1238,6 @@ if (!$disabled{dso} && $target{dso_scheme} ne "")
                }
        }
 
-$config{ex_libs}="$libs$config{ex_libs}" if ($libs ne "");
-$config{lflags}="$config{lflags}$ldflags" if ($ldflags ne "");
-
 # If threads aren't disabled, check how possible they are
 unless ($disabled{threads}) {
     if ($auto_threads) {
@@ -1153,7 +1254,7 @@ unless ($disabled{threads}) {
             # system-dependent compiler options that are necessary.  We
             # can't truly check that the given options are correct, but
             # we expect the user to know what [s]He is doing.
-            if (!$user_cflags && !@user_defines) {
+            if (!@{$user{CFLAGS}} && !@{$user{CPPDEFINES}}) {
                 die "You asked for multi-threading support, but didn't\n"
                     ,"provide any system-specific compiler options\n";
             }
@@ -1164,9 +1265,7 @@ unless ($disabled{threads}) {
 # If threads still aren't disabled, add a C macro to ensure the source
 # code knows about it.  Any other flag is taken care of by the configs.
 unless($disabled{threads}) {
-    foreach (("defines", "openssl_thread_defines")) {
-        push @{$config{$_}}, "OPENSSL_THREADS";
-    }
+    push @{$config{openssl_thread_defines}}, "OPENSSL_THREADS";
 }
 
 # With "deprecated" disable all deprecated features.
@@ -1193,22 +1292,22 @@ if ($disabled{"dynamic-engine"}) {
 }
 
 unless ($disabled{asan}) {
-    $config{cflags} .= "-fsanitize=address ";
+    push @{$config{cflags}}, "-fsanitize=address";
 }
 
 unless ($disabled{ubsan}) {
     # -DPEDANTIC or -fnosanitize=alignment may also be required on some
     # platforms.
-    $config{cflags} .= "-fsanitize=undefined -fno-sanitize-recover=all ";
+    push @{$config{cflags}}, "-fsanitize=undefined", "-fno-sanitize-recover=all";
 }
 
 unless ($disabled{msan}) {
-  $config{cflags} .= "-fsanitize=memory ";
+  push @{$config{cflags}}, "-fsanitize=memory";
 }
 
 unless ($disabled{"fuzz-libfuzzer"} && $disabled{"fuzz-afl"}
         && $disabled{asan} && $disabled{ubsan} && $disabled{msan}) {
-    $config{cflags} .= "-fno-omit-frame-pointer -g ";
+    push @{$config{cflags}}, "-fno-omit-frame-pointer", "-g";
 }
 #
 # Platform fix-ups
@@ -1222,6 +1321,7 @@ if ($disabled{pic})
                    dso_cflags dso_cxxflags dso_cppflags
                     dso_defines dso_includes dso_lflags))
                {
+               delete $config{$_};
                $target{$_} = "";
                }
        }
@@ -1294,7 +1394,7 @@ unless ($disabled{asm}) {
     }
 }
 
-my %predefined = compiler_predefined($target{cc});
+my %predefined = compiler_predefined($config{cc});
 
 # Check for makedepend capabilities.
 if (!$disabled{makedepend}) {
@@ -1305,7 +1405,7 @@ if (!$disabled{makedepend}) {
     } elsif ($predefined{__GNUC__} >= 3) {
         # We know that GNU C version 3 and up as well as all clang
         # versions support dependency generation
-        $config{makedepprog} = "\$(CROSS_COMPILE)$target{cc}";
+        $config{makedepprog} = "\$(CROSS_COMPILE)$config{cc}";
     } else {
         # In all other cases, we look for 'makedepend', and disable the
         # capability if not found.
@@ -1344,7 +1444,8 @@ die "Exactly one of SIXTY_FOUR_BIT|SIXTY_FOUR_BIT_LONG|THIRTY_TWO_BIT can be set
 
 # "Stringify" the C flags string.  This permits it to be made part of a string
 # and works as well on command lines.
-$config{cflags} =~ s/([\\\"])/\\$1/g;
+$config{cflags} = [ map { (my $x = $_) =~ s/([\\\"])/\\$1/g; $x }
+                        @{$config{cflags}} ];
 
 if (defined($config{api})) {
     $config{openssl_api_defines} = [ "OPENSSL_MIN_API=".$apitable->{$config{api}} ];
@@ -1353,7 +1454,7 @@ if (defined($config{api})) {
 }
 
 if (defined($predefined{__clang__}) && !$disabled{asm}) {
-    $config{cflags} .= " -Qunused-arguments";
+    push @{$config{cflags}}, "-Qunused-arguments";
 }
 
 if ($strict_warnings)
@@ -1366,13 +1467,15 @@ if ($strict_warnings)
        $gcc_devteam_warn .= " -Wmisleading-indentation" if $gccver >= 6;
        foreach $wopt (split /\s+/, $gcc_devteam_warn)
                {
-               $config{cflags} .= " $wopt" unless ($config{cflags} =~ /(?:^|\s)$wopt(?:\s|$)/)
+               push @{$config{cflags}}, $wopt
+                       unless grep { $_ eq $wopt } @{$config{cflags}};
                }
        if (defined($predefined{__clang__}))
                {
                foreach $wopt (split /\s+/, $clang_devteam_warn)
                        {
-                       $config{cflags} .= " $wopt" unless ($config{cflags} =~ /(?:^|\s)$wopt(?:\s|$)/)
+                       push @{$config{cflags}}, $wopt
+                               unless grep { $_ eq $wopt } @{$config{cflags}};
                        }
                }
        }
@@ -1381,22 +1484,15 @@ unless ($disabled{"crypto-mdebug-backtrace"})
        {
        foreach my $wopt (split /\s+/, $memleak_devteam_backtrace)
                {
-               $config{cflags} .= " $wopt" unless ($config{cflags} =~ /(?:^|\s)$wopt(?:\s|$)/)
+               push @{$config{cflags}}, $wopt
+                       unless grep { $_ eq $wopt } @{$config{cflags}};
                }
        if ($target =~ /^BSD-/)
                {
-               $config{ex_libs} .= " -lexecinfo";
+               push @{$config{ex_libs}}, "-lexecinfo";
                }
        }
 
-$config{cppflags}.=$user_cppflags;
-push @{$config{defines}}, @user_defines;
-push @{$config{includes}}, @user_includes;
-$config{cflags}.=$user_cflags;
-$config{cxxflags}.=$user_cflags;
-
-# ALL MODIFICATIONS TO %config and %target MUST BE DONE FROM HERE ON
-
 unless ($disabled{afalgeng}) {
     $config{afalgeng}="";
     if ($target =~ m/^linux/) {
@@ -1421,6 +1517,8 @@ unless ($disabled{afalgeng}) {
 
 push @{$config{openssl_other_defines}}, "OPENSSL_NO_AFALGENG" if ($disabled{afalgeng});
 
+# ALL MODIFICATIONS TO %config and %target MUST BE DONE FROM HERE ON
+
 # If we use the unified build, collect information from build.info files
 my %unified_info = ();
 
@@ -2220,18 +2318,25 @@ print "PROCESSOR     =$config{processor}\n" if $config{processor};
 print "PERL          =$config{perl}\n";
 print "PERLVERSION   =$Config{version} for $Config{archname}\n";
 print "HASHBANGPERL  =$config{hashbangperl}\n";
-print "CC            =$config{cross_compile_prefix}$target{cc}\n";
-print "CFLAG         =$target{cflags} $config{cflags}\n";
-print "CXX           =$config{cross_compile_prefix}$target{cxx}\n"
-    if defined $target{cxx};
-print "CXXFLAG       =$target{cxxflags} $config{cxxflags}\n"
-    if defined $target{cxx};
-print "DEFINES       =",join(" ", @{$target{defines}}, @{$config{defines}}),"\n";
-#print "RANLIB        =", $target{ranlib} eq '$(CROSS_COMPILE)ranlib' ?
-#                             "$config{cross_compile_prefix}ranlib" :
-#                             "$target{ranlib}", "\n";
-print "LDFLAGS       =$config{lflags} $target{lflags}\n";
-print "EX_LIBS       =$target{ex_libs} $config{ex_libs}\n";
+print "DEFINES       =",join(" ", @{$config{defines}}),"\n"
+    if defined $config{defines};
+print "INCLUDES      =",join(" ", @{$config{includes}}),"\n"
+    if defined $config{includes};
+print "CPPFLAGS      =",join(" ", @{$config{cppflags}}),"\n"
+    if defined $config{cppflags};
+print "CC            =$config{cross_compile_prefix}$config{cc}\n";
+print "CFLAGS        =",join(" ", @{$config{cflags}}),"\n"
+    if defined $config{cflags};
+print "CXX           =$config{cross_compile_prefix}$config{cxx}\n"
+    if defined $config{cxx};
+print "CXXFLAGS      =",join(" ", @{$config{cxxflags}}),"\n"
+    if defined $config{cxxflags};
+print "LD            =$config{cross_compile_prefix}$config{ld}\n"
+    if defined $config{ld};
+print "LDFLAGS       =",join(" ", @{$config{lflags}}),"\n"
+    if defined $config{lflags};
+print "EX_LIBS       =",join(" ", @{$config{ex_libs}}),"\n"
+    if defined $config{ex_libs};
 
 my %builders = (
     unified => sub {
diff --git a/INSTALL b/INSTALL
index 558381770b2281e20a112b5bb8e4d230ae987350..3130fbed478370c041eab2fea051a051dedfb219 100644 (file)
--- a/INSTALL
+++ b/INSTALL
                    whirlpool.  The "ripemd" algorithm is deprecated and if used
                    is synonymous with rmd160.
 
-  -Dxxx, lxxx, -Lxxx, -Wl, -rpath, -R, -framework, -static
+  -Dxxx, -Ixxx, -Wp, -lxxx, -Lxxx, -Wl, -rpath, -R, -framework, -static
                    These system specific options will be recognised and
                    passed through to the compiler to allow you to define
                    preprocessor symbols, specify additional libraries, library
                    unsuitable for execution on other, typically older,
                    processor. Consult your compiler documentation.
 
+                   Take note of the VAR=value documentation below and how
+                   these flags interact with those variables.
+
   -xxx, +xxx
                    Additional options that are not otherwise recognised are
                    passed through as they are to the compiler as well.  Again,
                    consult your compiler documentation.
 
+                   Take note of the VAR=value documentation below and how
+                   these flags interact with those variables.
+
   VAR=value
                    Assignment if environment variable for Configure.  These
                    work just like normal environment variable assignments,
                    the corresponding value in the inherited environment, if
                    there is one.
 
+                   The following variables are used as "make variables" and
+                   can be used as an alternative to giving preprocessor,
+                   compiler and linker options directly as configuration.
+                   The following variables are supported:
+
+                   AR              The static library archiver.
+                   ARFLAGS         Flags for the static library archiver.
+                   AS              The assembler compiler.
+                   ASFLAGS         Flags for the assembler compiler.
+                   CC              The C compiler.
+                   CFLAGS          Flags for the C compiler.
+                   CXX             The C++ compiler.
+                   CXXFLAGS        Flags for the C++ compiler.
+                   CPP             The C/C++ preprocessor.
+                   CPPFLAGS        Flags for the C/C++ preprocessor.
+                   CPPDEFINES      List of CPP macro definitions, separated
+                                   by a platform specific character (':' or
+                                   space for Unix, ';' for Windows, ',' for
+                                   VMS).  This can be used in place of -D.
+                   CPPINCLUDES     List of CPP inclusion directories, separated
+                                   the same way as for CPPDEFINES.  This can
+                                   be used in place of -I.
+                   HASHBANGPERL    Perl invocation to be inserted after '#!'
+                                   in public perl scripts.
+                   LD              The program linker (not used on Unix, $(CC)
+                                   is used there).
+                   LDFLAGS         Flags for the shared library, DSO and
+                                   program linker.
+                   LDLIBS          Extra libraries to use when linking.
+                                   Takes the form of a space separated list
+                                   of library specifications on Unix and
+                                   Windows, and as a comma separated list of
+                                   libraries on VMS.
+                   RANLIB          The library archive indexer.
+                   RC              The Windows resources manipulator.
+                   RCFLAGS         Flags for the Windows reources manipulator.
+                   RM              The command to remove files and directories.
+
+                   These can be mixed with flags given on the command line.
+                   Any variable assignment resets any corresponding flags
+                   given before it, so for example:
+
+                       ./config -DFOO CPPFLAGS=-DBAR -DCOOKIE
+
+                   Will end up having 'CPPFLAGS=-DBAR -DCOOKIE'.
+
+                   Here is how the flags documented above are collected as
+                   augmentation of these variables:
+
+                   -Dxxx           xxx is collected in CPPDEFINES
+                   -Ixxx           xxx is collected in CPPINCLUDES
+                   -Wp,xxx         collected in CPPFLAGS
+                   -Lxxx           collected in LDFLAGS
+                   -lxxx           collected in LDLIBS
+                   -Wp,xxx         collected in LDLIBS
+                   -rpath xxx      collected in LDLIBS
+                   -R xxx          collected in LDLIBS
+                   -framework xxx  collected in LDLIBS
+                   -static         collected in LDLIBS
+                   -xxx            collected in CFLAGS
+                   +xxx            collected in CFLAGS
+
   reconf
   reconfigure
                    Reconfigure from earlier data.  This fetches the previous