util/perl/OpenSSL/config.pm: refactor map_guess()
[openssl.git] / util / perl / OpenSSL / config.pm
1 #! /usr/bin/env perl
2 # Copyright 1998-2020 The OpenSSL Project Authors. All Rights Reserved.
3 #
4 # Licensed under the Apache License 2.0 (the "License").  You may not use
5 # this file except in compliance with the License.  You can obtain a copy
6 # in the file LICENSE in the source distribution or at
7 # https://www.openssl.org/source/license.html
8
9 # Determine the operating system and run ./Configure.  Far descendant from
10 # Apache's minarch and GuessOS.
11
12 package OpenSSL::config;
13
14 use strict;
15 use warnings;
16 use Getopt::Std;
17 use File::Basename;
18 use IPC::Cmd;
19 use POSIX;
20 use Carp;
21
22 # These control our behavior.
23 my $DRYRUN;
24 my $VERBOSE;
25 my $WAIT = 1;
26 my $WHERE = dirname($0);
27
28 # Machine type, etc., used to determine the platform
29 my $MACHINE;
30 my $RELEASE;
31 my $SYSTEM;
32 my $VERSION;
33 my $CCVENDOR;
34 my $CCVER;
35 my $GCC_BITS;
36 my $GCC_ARCH;
37
38 # Some environment variables; they will affect Configure
39 my $CONFIG_OPTIONS = $ENV{CONFIG_OPTIONS} // '';
40 my $CC;
41 my $CROSS_COMPILE;
42
43 # For determine_compiler_settings, the list of known compilers
44 my @c_compilers = qw(clang gcc cc);
45 # Methods to determine compiler version.  The expected output is one of
46 # MAJOR or MAJOR.MINOR or MAJOR.MINOR.PATCH...  or false if the compiler
47 # isn't of the given brand.
48 # This is a list to ensure that gnu comes last, as we've made it a fallback
49 my @cc_version =
50     (
51      clang => sub {
52          my $v = `$CROSS_COMPILE$CC -v 2>&1`;
53          $v =~ m/(?:(?:^clang|LLVM) version|.*based on LLVM)\s+([0-9]+\.[0-9]+)/;
54          return $1;
55      },
56      gnu => sub {
57          my $v = `$CROSS_COMPILE$CC -dumpversion 2>/dev/null`;
58          # Strip off whatever prefix egcs prepends the number with.
59          # Hopefully, this will work for any future prefixes as well.
60          $v =~ s/^[a-zA-Z]*\-//;
61          return $v;
62      },
63     );
64
65 # This is what we will set as the target for calling Configure.
66 my $options = '';
67
68 # Pattern matches against "${SYSTEM}:${RELEASE}:${VERSION}:${MACHINE}"
69 my $simple_guess_patterns = [
70     [ 'A\/UX:',               'm68k-apple-aux3' ],
71     [ 'AIX:[3-9]:4:',         '${MACHINE}-ibm-aix' ],
72     [ 'AIX:.*:[5-9]:',        '${MACHINE}-ibm-aix' ],
73     [ 'AIX:',                 '${MACHINE}-ibm-aix3' ],
74     [ 'HI-UX:',               '${MACHINE}-hi-hiux' ],
75     [ 'IRIX:6.',              'mips3-sgi-irix' ],
76     [ 'IRIX64:',              'mips4-sgi-irix64' ],
77     [ 'Linux:[2-9]',          '${MACHINE}-whatever-linux2' ],
78     [ 'Linux:1',              '${MACHINE}-whatever-linux1' ],
79     [ 'GNU',                  'hurd-x86' ],
80     [ 'LynxOS:',              '${MACHINE}-lynx-lynxos' ],
81     # BSD/OS always says 386
82     [ 'BSD\/OS:4.*',          'i486-whatever-bsdi4' ],
83     [ 'BSD\/386:.*|BSD\/OS:', '${MACHINE}-whatever-bsdi' ],
84     [ 'DragonFly:',           '${MACHINE}-whatever-dragonfly' ],
85     [ 'FreeBSD:',             '${MACHINE}-whatever-freebsd' ],
86     [ 'Haiku:',               '${MACHINE}-whatever-haiku' ],
87     [ 'NetBSD:',              '${MACHINE}-whatever-netbsd' ],
88     [ 'OpenBSD:',             '${MACHINE}-whatever-openbsd' ],
89     [ 'OpenUNIX:',            '${MACHINE}-unknown-OpenUNIX${VERSION}' ],
90     [ 'Paragon.*:',           'i860-intel-osf1' ],
91     [ 'Rhapsody:',            'ppc-apple-rhapsody' ],
92     [ 'SunOS:5.',             '${MACHINE}-whatever-solaris2' ],
93     [ 'SunOS:',               '${MACHINE}-sun-sunos4' ],
94     [ 'UNIX_System_V:4.*:',   '${MACHINE}-whatever-sysv4' ],
95     [ 'VOS:.*:.*:i786',       'i386-stratus-vos' ],
96     [ 'VOS:.*:.*:',           'hppa1.1-stratus-vos' ],
97     [ '.*:4.*:R4.*:m88k',     '${MACHINE}-whatever-sysv4' ],
98     [ 'DYNIX\/ptx:4.*:',      '${MACHINE}-whatever-sysv4' ],
99     [ ':4.0:3.0:3[34]',       'i486-ncr-sysv4' ],
100     [ 'ULTRIX:',              '${MACHINE}-unknown-ultrix' ],
101     [ 'POSIX-BC',             'BS2000-siemens-sysv4' ],
102     [ 'machten:',             '${MACHINE}-tenon-${SYSTEM}' ],
103     [ 'library:',             '${MACHINE}-ncr-sysv4' ],
104     [ 'ConvexOS:.*:11.0:',    '${MACHINE}-v11-${SYSTEM}' ],
105     [ 'MINGW64.*:.*x86_64',   '${MACHINE}-whatever-mingw64' ],
106     [ 'MINGW',                '${MACHINE}-whatever-mingw' ],
107     [ 'CYGWIN',               '${MACHINE}-pc-cygwin' ],
108     [ 'vxworks',              '${MACHINE}-whatever-vxworks' ],
109     [ 'Darwin:.*Power',       'ppc-apple-darwin' ],
110     [ 'Darwin:.*x86_64',      'x86_64-apple-darwin' ],
111     [ 'Darwin:',              'i686-apple-darwin' ],
112
113     # Windows values found by looking at Perl 5's win32/win32.c
114     [ 'Windows NT:.*:amd64',  'VC-WIN64A' ],
115     [ 'Windows NT:.*:ia64',   'VC-WIN64I' ],
116     [ 'Windows NT:.*:x86',    'VC-WIN32' ],
117
118     # VMS values found by observation on existing machinery.  Unfortunately,
119     # the machine part is a bit...  overdone.  It seems, though, that 'Alpha'
120     # exists in that part, making it distinguishable from Itanium.  It will
121     # be interesting to see what we'll get in the upcoming x86_64 port...
122     [ 'OpenVMS:.*:.*:.*:.*Alpha*', 'vms-alpha' ],
123     [ 'OpenVMS:',             'vms-ia64' ],
124
125 ];
126
127 # More complex cases that require run-time code.
128 my $complex_sys_list = [
129     [ 'HP-UX:', sub {
130         my $HPUXVER = $RELEASE;
131         $HPUXVER = s/[^.]*.[0B]*//;
132         # HPUX 10 and 11 targets are unified
133         return "${MACHINE}-hp-hpux1x" if $HPUXVER =~ m@1[0-9]@;
134         return "${MACHINE}-hp-hpux";
135     } ],
136
137     [ 'BSD/386:.*:.*:.*486.*|BSD/OS:.*:.*:.*:.*486', sub {
138         my $BSDVAR = `/sbin/sysctl -n hw.model`;
139         return "i586-whatever-bsdi" if $BSDVAR =~ m@Pentium@;
140         return "i386-whatever-bsdi";
141     } ],
142
143     [ 'FreeBSD:.*:.*:.*386', sub {
144         my $VERS = $RELEASE;
145         $VERS =~ s/[-(].*//;
146         my $MACH = `sysctl -n hw.model`;
147         $MACH = "i386" if $MACH =~ m@386@;
148         $MACH = "i486" if $MACH =~ m@486@;
149         $MACH = "i686" if $MACH =~ m@Pentium II@;
150         $MACH = "i586" if $MACH =~ m@Pentium@;
151         $MACH = "$MACHINE" if $MACH !~ /i.86/;
152         my $ARCH = 'whatever';
153         $ARCH = "pc" if $MACH =~ m@i[0-9]86@;
154         return "${MACH}-${ARCH}-freebsd${VERS}";
155     } ],
156
157     [ 'NetBSD:.*:.*:.*386', sub {
158         my $hw = `/usr/sbin/sysctl -n hw.model || /sbin/sysctl -n hw.model`;
159         $hw =~  s@.*(.)86-class.*@i${1}86@;
160         return "${hw}-whatever-netbsd";
161     } ],
162
163     [ 'OSF1:.*:.*:.*alpha', sub {
164         my $OSFMAJOR = $RELEASE;
165         $OSFMAJOR =~ 's/^V([0-9]*)\..*$/\1/';
166         return "${MACHINE}-dec-tru64" if $OSFMAJOR =~ m@[45]@;
167         return "${MACHINE}-dec-osf";
168     } ],
169 ];
170
171
172 # Run a command, return true if exit zero else false.
173 # Multiple args are glued together into a pipeline.
174 # Name comes from OpenSSL tests, often written as "ok(run(...."
175 sub okrun {
176     my $command = join(' | ', @_);
177     my $status = system($command) >> 8;
178     return $status == 0;
179 }
180
181 # Give user a chance to abort/interrupt if interactive if interactive.
182 sub maybe_abort {
183     if ( $WAIT && -t 1 ) {
184         eval {
185             local $SIG{ALRM} = sub { die "Timeout"; };
186             local $| = 1;
187             alarm(5);
188             print "You have about five seconds to abort: ";
189             my $ignored = <STDIN>;
190             alarm(0);
191         };
192         print "\n" if $@ =~ /Timeout/;
193     }
194 }
195
196 # Expand variable references in a string.
197 sub expand {
198     my $var = shift;
199     $var =~ s/\$\{MACHINE\}/${MACHINE}/;
200     return $var;
201 }
202
203 # Look for ISC/SCO with its unique uname program
204 sub is_sco_uname {
205     open UNAME, "uname -X 2>/dev/null|" or return '';
206     my $line = "";
207     while ( <UNAME> ) {
208         chop;
209         $line = $_ if m@^Release@;
210     }
211     close UNAME;
212     return "" if $line eq '';
213     my @fields = split($line);
214     return $fields[2];
215 }
216
217 sub get_sco_type {
218     my $REL = shift;
219
220     if ( -f "/etc/kconfig" ) {
221         return "${MACHINE}-whatever-isc4" if $REL eq '4.0' || $REL eq '4.1';
222     } else {
223         return "whatever-whatever-sco3" if $REL eq '3.2v4.2';
224         return "whatever-whatever-sco5" if $REL =~ m@3\.2v5\.0.*@;
225         if ( $REL eq "4.2MP" ) {
226             return "whatever-whatever-unixware20" if $VERSION =~ m@2\.0.*@;
227             return "whatever-whatever-unixware21" if $VERSION =~ m@2\.1.*@;
228             return "whatever-whatever-unixware2" if $VERSION =~ m@2.*@;
229         }
230         return "whatever-whatever-unixware1" if $REL eq "4.2";
231         if ( $REL =~ m@5.*@ ) {
232             # We hardcode i586 in place of ${MACHINE} for the following
233             # reason: even though Pentium is minimum requirement for
234             # platforms in question, ${MACHINE} gets always assigned to
235             # i386. This means i386 gets passed to Configure, which will
236             # cause bad assembler code to be generated.
237             return "i586-sco-unixware7" if $VERSION =~ m@[678].*@;
238         }
239     }
240 }
241
242 # Return the cputype-vendor-osversion
243 sub guess_system {
244     ($SYSTEM, undef, $RELEASE, $VERSION, $MACHINE) = POSIX::uname();
245     my $sys = "${SYSTEM}:${RELEASE}:${VERSION}:${MACHINE}";
246
247     # Special-cases for ISC, SCO, Unixware
248     my $REL = is_sco_uname();
249     if ( $REL ne "" ) {
250         my $result = get_sco_type($REL);
251         return expand($result) if $result ne '';
252     }
253
254     # Now pattern-match
255
256     # Simple cases
257     foreach my $tuple ( @$simple_guess_patterns ) {
258         my $pat = @$tuple[0];
259         # Trailing $ omitted on purpose.
260         next if $sys !~ /^$pat/;
261         my $result = @$tuple[1];
262         return expand($result);
263     }
264
265     # Complex cases.
266     foreach my $tuple ( @$complex_sys_list ) {
267         my $pat = @$tuple[0];
268         # Trailing $ omitted on purpose.
269         next if $sys !~ /^$pat/;
270         my $ref = @$tuple[1];
271         my $result = &$ref;
272         return expand($result);
273     }
274
275     # Oh well.
276     return "${MACHINE}-whatever-${SYSTEM}";
277 }
278
279 # We would use List::Util::pair() for this...  unfortunately, that function
280 # only appeared in perl v5.19.3, and we claim to support perl v5.10 and on.
281 # Therefore, we implement a quick cheap variant of our own.
282 sub _pairs (@) {
283     croak "Odd number of arguments" if @_ & 1;
284
285     my @pairlist = ();
286
287     while (@_) {
288         my $x = [ shift, shift ];
289         push @pairlist, $x;
290     }
291     return @pairlist;
292 }
293
294 # Figure out CC, GCCVAR, etc.
295 sub determine_compiler_settings {
296     # Make a copy and don't touch it.  That helps determine if we're
297     # finding the compiler here
298     my $cc = $CC;
299
300     # Set certain default
301     $CCVER = 0;                 # Unknown
302     $CCVENDOR = '';             # Dunno, don't care (unless found later)
303
304     # Find a compiler if we don't already have one
305     if ( ! $cc ) {
306         foreach (@c_compilers) {
307             next unless IPC::Cmd::can_run("$CROSS_COMPILE$_");
308             $CC = $_;
309             last;
310         }
311     }
312
313     # Find the compiler vendor and version number for certain compilers
314     foreach my $pair (_pairs @cc_version) {
315         # Try to get the version number.
316         # Failure gets us undef or an empty string
317         my ( $k, $v ) = @$pair;
318         $v = $v->();
319
320         # If we got a version number, process it
321         if ($v) {
322             $CCVENDOR = $k;
323
324             # The returned version is expected to be one of
325             #
326             # MAJOR
327             # MAJOR.MINOR
328             # MAJOR.MINOR.{whatever}
329             #
330             # We don't care what comes after MAJOR.MINOR.  All we need is to
331             # have them calculated into a single number, using this formula:
332             #
333             # MAJOR * 100 + MINOR
334             # Here are a few examples of what we should get:
335             #
336             # 2.95.1    => 295
337             # 3.1       => 301
338             # 9         => 900
339             my @numbers = split /\./, $v;
340             my @factors = (100, 1);
341             while (@numbers && @factors) {
342                 $CCVER += shift(@numbers) * shift(@factors)
343             }
344             last;
345         }
346     }
347
348     # If no C compiler has been determined at this point, we die.  Hard.
349     die <<_____
350 ERROR!
351 No C compiler found, please specify one with the environment variable CC,
352 or configure with an explicit configuration target.
353 _____
354         unless $CC;
355
356     # Vendor specific overrides, only if we determined the compiler here
357     if ( ! $cc ) {
358         if ( ${SYSTEM} eq 'AIX' ) {
359             # favor vendor cc over gcc
360             if (IPC::Cmd::can_run('cc')) {
361                 $CC = 'cc';
362                 $CCVENDOR = ''; # Determine later
363                 $CCVER = 0;
364             }
365         }
366
367         if ( $SYSTEM eq "SunOS" ) {
368             # check for WorkShop C, expected output is "cc: blah-blah C x.x"
369             my $v = `(cc -V 2>&1) 2>/dev/null | egrep -e '^cc: .* C [0-9]\.[0-9]'`;
370             chomp $v;
371             $v =~ s/.* C \([0-9]\)\.\([0-9]\).*/$1.$2/;
372             my @numbers = split /\./, $v;
373             my @factors = (100, 1);
374             $v = 0;
375             while (@numbers && @factors) {
376                 $v += shift(@numbers) * shift(@factors)
377             }
378
379             if ( $v > 40000 &&  $MACHINE ne 'i86pc' ) {
380                 $CC = 'cc';
381                 $CCVENDOR = ''; # Determine later
382                 $CCVER = $v;
383
384                 if ( $CCVER == 50000 ) {
385                     print <<'EOF';
386 WARNING! Found WorkShop C 5.0.
387          Make sure you have patch #107357-01 or later applied.
388 EOF
389                     maybe_abort();
390                 }
391             }
392         }
393     }
394
395     # On some systems, we assume a cc vendor if it's not already determined
396
397     if ( ! $CCVENDOR ) {
398         $CCVENDOR = 'aix' if $SYSTEM eq 'AIX';
399         $CCVENDOR = 'sun' if $SYSTEM eq 'SunOS';
400     }
401
402     # Some systems need to know extra details
403
404     if ( $SYSTEM eq "HP-UX" && $CCVENDOR eq 'gnu' ) {
405         # By default gcc is a ILP32 compiler (with long long == 64).
406         $GCC_BITS = "32";
407         if ( $CCVER >= 300 ) {
408             # PA64 support only came in with gcc 3.0.x.
409             # We check if the preprocessor symbol __LP64__ is defined.
410             if ( okrun('echo __LP64__',
411                        "$CC -v -E -x c - 2>/dev/null",
412                        'grep "^__LP64__" 2>&1 >/dev/null') ) {
413                 # __LP64__ has slipped through, it therefore is not defined
414             } else {
415                 $GCC_BITS = '64';
416             }
417         }
418     }
419
420     if ( $SYSTEM eq "SunOS" && $CCVENDOR eq 'gnu' ) {
421         if ( $CCVER >= 300 ) {
422             # 64-bit ABI isn't officially supported in gcc 3.0, but seems
423             # to be working; at the very least 'make test' passes.
424             if ( okrun("$CC -v -E -x c /dev/null 2>&1",
425                        'grep __arch64__ >/dev/null') ) {
426                 $GCC_ARCH = "-m64"
427             } else {
428                 $GCC_ARCH = "-m32"
429             }
430         }
431     }
432
433     if ($VERBOSE) {
434         my $vendor = $CCVENDOR ? $CCVENDOR : "(undetermined)";
435         my $version = $CCVER ? $CCVER : "(undetermined)";
436         print "C compiler: $CC\n";
437         print "C compiler vendor: $vendor\n";
438         print "C compiler version: $version\n";
439     }
440 }
441
442 my $map_patterns =
443     [ [ 'uClinux.*64.*',          { target => 'uClinux-dist64' } ],
444       [ 'uClinux.*',              { target => 'uClinux-dist' } ],
445       [ 'mips3-sgi-irix',         { target => 'irix-mips3' } ],
446       [ 'mips4-sgi-irix64',
447         sub {
448             print <<EOF;
449 WARNING! To build 64-bit package, do this:
450          $WHERE/Configure irix64-mips4-$CC
451 EOF
452             maybe_abort();
453             return { target => "irix-mips3" };
454         }
455       ],
456       [ 'ppc-apple-rhapsody',     { target => "rhapsody-ppc" } ],
457       [ 'ppc-apple-darwin.*',
458         sub {
459             my $KERNEL_BITS = $ENV{KERNEL_BITS};
460             my $ISA64 = `sysctl -n hw.optional.64bitops 2>/dev/null`;
461             if ( $ISA64 == 1 && $KERNEL_BITS eq '' ) {
462                 print <<EOF;
463 WARNING! To build 64-bit package, do this:
464          $WHERE/Configure darwin64-ppc-cc
465 EOF
466                 maybe_abort();
467             }
468             return { target => "darwin64-ppc" }
469                 if $ISA64 == 1 && $KERNEL_BITS eq '64';
470             return { target => "darwin-ppc" };
471         }
472       ],
473       [ 'i.86-apple-darwin.*',
474         sub {
475             my $KERNEL_BITS = $ENV{KERNEL_BITS};
476             my $ISA64 = `sysctl -n hw.optional.x86_64 2>/dev/null`;
477             if ( $ISA64 == 1 && $KERNEL_BITS eq '' ) {
478                 print <<EOF;
479 WARNING! To build 64-bit package, do this:
480          KERNEL_BITS=64 $WHERE/Configure \[\[ options \]\]
481 EOF
482                 maybe_abort();
483             }
484             return { target => "darwin64-x86_64" }
485                 if $ISA64 == 1 && $KERNEL_BITS eq '64';
486             return { target => "darwin-i386" };
487         }
488       ],
489       [ 'x86_64-apple-darwin.*',
490         sub {
491             my $KERNEL_BITS = $ENV{KERNEL_BITS};
492             return { target => "darwin-i386" } if $KERNEL_BITS eq '32';
493
494             print <<EOF;
495 WARNING! To build 32-bit package, do this:
496          KERNEL_BITS=32 $WHERE/Configure \[\[ options \]\]
497 EOF
498             maybe_abort();
499             return { target => "darwin64-x86_64" };
500         }
501       ],
502       [ 'armv6\+7-.*-iphoneos',
503         { target => "iphoneos-cross",
504           cflags => [ qw(-arch armv6 -arch armv7) ],
505           cxxflags => [ qw(-arch armv6 -arch armv7) ] }
506       ],
507       [ 'arm64-.*-iphoneos|.*-.*-ios64',
508         { target => "ios64-cross" }
509       ],
510       [ '.*-.*-iphoneos',
511         sub { return { target => "iphoneos-cross",
512                        cflags => [ "-arch ${MACHINE}" ],
513                        cxxflags => [ "-arch ${MACHINE}" ] }; }
514       ],
515       [ 'alpha-.*-linux2.*',
516         sub {
517             my $ISA = `awk '/cpu model/{print \$4;exit(0);}' /proc/cpuinfo`;
518             $ISA //= 'generic';
519             my %config = ();
520             if ( $CCVENDOR eq "gnu" ) {
521                 if ( $ISA =~ 'EV5|EV45' ) {
522                     %config = ( cflags => [ '-mcpu=ev5' ],
523                                 cxxflags =>  [ '-mcpu=ev5' ] );
524                 } elsif ( $ISA =~ 'EV56|PCA56' ) {
525                     %config = ( cflags => [ '-mcpu=ev56' ],
526                                 cxxflags =>  [ '-mcpu=ev56' ] );
527                 } else {
528                     %config = ( cflags => [ '-mcpu=ev6' ],
529                                 cxxflags =>  [ '-mcpu=ev6' ] );
530                 }
531             }
532             return { target => "linux-alpha",
533                      %config };
534         }
535       ],
536       [ 'ppc64-.*-linux2',
537         sub {
538             my $KERNEL_BITS = $ENV{KERNEL_BITS};
539             if ( $KERNEL_BITS eq '' ) {
540                 print <<EOF;
541 WARNING! To build 64-bit package, do this:
542          $WHERE/Configure linux-ppc64
543 EOF
544                 maybe_abort();
545             }
546             return { target => "linux-ppc64" } if $KERNEL_BITS eq '64';
547
548             my %config = ();
549             if (!okrun('echo __LP64__',
550                        'gcc -E -x c - 2>/dev/null',
551                        'grep "^__LP64__" 2>&1 >/dev/null') ) {
552                 %config = ( cflags => [ '-m32' ],
553                             cxxflags =>  [ '-m32' ] );
554             }
555             return { target => "linux-ppc",
556                      %config };
557         }
558       ],
559       [ 'ppc64le-.*-linux2',      { target => "linux-ppc64le" } ],
560       [ 'ppc-.*-linux2',          { target => "linux-ppc" } ],
561       [ 'mips64.*-*-linux2',
562         sub {
563             print <<EOF;
564 WARNING! To build 64-bit package, do this:
565          $WHERE/Configure linux64-mips64
566 EOF
567             maybe_abort();
568             return { target => "linux-mips64" };
569         }
570       ],
571       [ 'mips.*-.*-linux2',       { target => "linux-mips32" } ],
572       [ 'ppc60x-.*-vxworks.*',    { target => "vxworks-ppc60x" } ],
573       [ 'ppcgen-.*-vxworks.*',    { target => "vxworks-ppcgen" } ],
574       [ 'pentium-.*-vxworks.*',   { target => "vxworks-pentium" } ],
575       [ 'simlinux-.*-vxworks.*',  { target => "vxworks-simlinux" } ],
576       [ 'mips-.*-vxworks.*',      { target => "vxworks-mips" } ],
577       [ 'e2k-.*-linux.*',         { target => "linux-generic64",
578                                     defines => [ 'L_ENDIAN' ] } ],
579       [ 'ia64-.*-linux.',         { target => "linux-ia64" } ],
580       [ 'sparc64-.*-linux2',
581         sub {
582             print <<EOF;
583 WARNING! If you *know* that your GNU C supports 64-bit/V9 ABI and you
584          want to build 64-bit library, do this:
585          $WHERE/Configure linux64-sparcv9
586 EOF
587             maybe_abort();
588             return { target => "linux-sparcv9" };
589         }
590       ],
591       [ 'sparc-.*-linux2',
592         sub {
593             my $KARCH = `awk '/^type/{print \$3;exit(0);}' /proc/cpuinfo`;
594             $KARCH //= "sun4";
595             return { target => "linux-sparcv9" } if $KARCH =~ 'sun4u.*';
596             return { target => "linux-sparcv8" } if $KARCH =~ 'sun4[md]';
597             return { target => "linux-generic32",
598                      defines => [ 'L_ENDIAN' ] };
599         }
600       ],
601       [ 'parisc.*-.*-linux2',
602         sub {
603             # 64-bit builds under parisc64 linux are not supported and
604             # compiler is expected to generate 32-bit objects...
605             my $CPUARCH =
606                 `awk '/cpu family/{print substr(\$5,1,3); exit(0);}' /proc/cpuinfo`;
607             my $CPUSCHEDULE =
608                 `awk '/^cpu.[   ]*: PA/{print substr(\$3,3); exit(0);}' /proc/cpuinfo`;
609             # TODO XXX  Model transformations
610             # 0. CPU Architecture for the 1.1 processor has letter suffixes.
611             #    We strip that off assuming no further arch. identification
612             #    will ever be used by GCC.
613             # 1. I'm most concerned about whether is a 7300LC is closer to a
614             #    7100 versus a 7100LC.
615             # 2. The variant 64-bit processors cause concern should GCC support
616             #    explicit schedulers for these chips in the future.
617             #         PA7300LC -> 7100LC (1.1)
618             #         PA8200   -> 8000   (2.0)
619             #         PA8500   -> 8000   (2.0)
620             #         PA8600   -> 8000   (2.0)
621             $CPUSCHEDULE =~ s/7300LC/7100LC/;
622             $CPUSCHEDULE =~ s/8.00/8000/;
623             return
624                 { target => "linux-generic32",
625                   defines => [ 'B_ENDIAN' ],
626                   cflags => [ "-mschedule=$CPUSCHEDULE", "-march=$CPUARCH" ],
627                   cxxflags => [ "-mschedule=$CPUSCHEDULE", "-march=$CPUARCH" ]
628                 };
629         }
630       ],
631       [ 'armv[1-3].*-.*-linux2',  { target => "linux-generic32" } ],
632       [ 'armv[7-9].*-.*-linux2',  { target => "linux-armv4",
633                                     defines => [ 'B_ENDIAN' ],
634                                     cflags => [ '-march=armv7-a' ],
635                                     cxxflags => [ '-march=armv7-a' ] } ],
636       [ 'arm.*-.*-linux2',        { target => "linux-armv4" } ],
637       [ 'aarch64-.*-linux2',      { target => "linux-aarch64" } ],
638       [ 'sh.*b-.*-linux2',        { target => "linux-generic32",
639                                     defines => [ 'B_ENDIAN' ] } ],
640       [ 'sh.*-.*-linux2',         { target => "linux-generic32",
641                                     defines => [ 'L_ENDIAN' ] } ],
642       [ 'm68k.*-.*-linux2',       { target => "linux-generic32",
643                                     defines => [ 'B_ENDIAN' ] } ],
644       [ 's390-.*-linux2',         { target => "linux-generic32",
645                                     defines => [ 'B_ENDIAN' ] } ],
646       [ 's390x-.*-linux2',
647         sub {
648             # Disabled until a glibc bug is fixed; see Configure.
649             if (0
650                 || okrun('egrep -e \'^features.* highgprs\' /proc/cpuinfo >/dev/null') )
651                 {
652                     print <<EOF;
653 WARNING! To build "highgprs" 32-bit package, do this:
654          $WHERE/Configure linux32-s390x
655 EOF
656                     maybe_abort();
657                 }
658             return { target => "linux64-s390x" };
659         }
660       ],
661       [ 'x86_64-.*-linux.',
662         sub {
663             return { target => "linux-x32" }
664                 if okrun("$CC -dM -E -x c /dev/null 2>&1",
665                          'grep -q ILP32 >/dev/null');
666             return { target => "linux-x86_64" };
667         }
668       ],
669       [ '.*86-.*-linux2',
670         sub {
671             # On machines where the compiler understands -m32, prefer a
672             # config target that uses it
673             return { target => "linux-x86" }
674                 if okrun("$CC -m32 -E -x c /dev/null >/dev/null 2>&1");
675             return { target => "linux-elf" };
676         }
677       ],
678       [ '.*86-.*-linux1',         { target => "linux-aout" } ],
679       [ '.*-.*-linux.',           { target => "linux-generic32" } ],
680       [ 'sun4[uv].*-.*-solaris2',
681         sub {
682             my $KERNEL_BITS = $ENV{KERNEL_BITS};
683             my $ISA64 = `isainfo 2>/dev/null | grep sparcv9`;
684             if ( $ISA64 ne "" && $KERNEL_BITS eq '' ) {
685                 if ( $CCVENDOR eq "sun" && $CCVER >= 500 ) {
686                     print <<EOF;
687 WARNING! To build 64-bit package, do this:
688          $WHERE/Configure solaris64-sparcv9-cc
689 EOF
690                     maybe_abort();
691                 } elsif ( $CCVENDOR eq "gnu" && $GCC_ARCH eq "-m64" ) {
692                     # $GCC_ARCH denotes default ABI chosen by compiler driver
693                     # (first one found on the $PATH). I assume that user
694                     # expects certain consistency with the rest of his builds
695                     # and therefore switch over to 64-bit. <appro>
696                     print <<EOF;
697 WARNING! To build 32-bit package, do this:
698          $WHERE/Configure solaris-sparcv9-gcc
699 EOF
700                     maybe_abort();
701                     return { target => "solaris64-sparcv9" };
702                 } elsif ( $GCC_ARCH eq "-m32" ) {
703                     print <<EOF;
704 NOTICE! If you *know* that your GNU C supports 64-bit/V9 ABI and you wish
705         to build 64-bit library, do this:
706         $WHERE/Configure solaris64-sparcv9-gcc
707 EOF
708                     maybe_abort();
709                 }
710             }
711             return { target => "solaris64-sparcv9" }
712                 if $ISA64 ne "" && $KERNEL_BITS eq '64';
713             return { target => "solaris-sparcv9" };
714         }
715       ],
716       [ 'sun4m-.*-solaris2',      { target => "solaris-sparcv8" } ],
717       [ 'sun4d-.*-solaris2',      { target => "solaris-sparcv8" } ],
718       [ 'sun4.*-.*-solaris2',     { target => "solaris-sparcv7" } ],
719       [ '.*86.*-.*-solaris2',
720         sub {
721             my $KERNEL_BITS = $ENV{KERNEL_BITS};
722             my $ISA64 = `isainfo 2>/dev/null | grep amd64`;
723             my $KB = $KERNEL_BITS // '64';
724             return { target => "solaris64-x86_64" }
725                 if $ISA64 ne "" && $KB eq '64';
726             my $REL = uname('-r');
727             $REL =~ s/5\.//;
728             my @tmp_disable = ();
729             push @tmp_disable, 'sse2' if int($REL) < 10;
730             return { target => "solaris-x86",
731                      disable => [ @tmp_disable ] };
732         }
733       ],
734       # We don't have any sunos target in Configurations/*.conf, so why here?
735       [ '.*-.*-sunos4',           { target => "sunos" } ],
736       [ '.*86.*-.*-bsdi4',        { target => "BSD-x86-elf",
737                                     lflags => [ '-ldl' ],
738                                     disable => [ 'sse2' ] } ],
739       [ 'alpha.*-.*-.*bsd.*',     { target => "BSD-generic64",
740                                     defines => [ 'L_ENDIAN' ] } ],
741       [ 'powerpc64-.*-.*bsd.*',   { target => "BSD-generic64",
742                                     defines => [ 'B_ENDIAN' ] } ],
743       [ 'sparc64-.*-.*bsd.*',     { target => "BSD-sparc64" } ],
744       [ 'ia64-.*-.*bsd.*',        { target => "BSD-ia64" } ],
745       [ 'x86_64-.*-dragonfly.*',  { target => "BSD-x86_64" } ],
746       [ 'amd64-.*-.*bsd.*',       { target => "BSD-x86_64" } ],
747       [ '.*86.*-.*-.*bsd.*',
748         sub {
749             # mimic ld behaviour when it's looking for libc...
750             my $libc;
751             if ( -l "/usr/lib/libc.so" ) {
752                 $libc = "/usr/lib/libc.so";
753             } else {
754                 # ld searches for highest libc.so.* and so do we
755                 $libc =
756                     `(ls /usr/lib/libc.so.* /lib/libc.so.* | tail -1) 2>/dev/null`;
757             }
758             my $what = `file -L $libc 2>/dev/null`;
759             return { target => "BSD-x86-elf" } if $what =~ /ELF/;
760             return { target => "BSD-x86",
761                      disable => [ 'sse2' ] };
762         }
763       ],
764       [ '.*-.*-.*bsd.*',          { target => "BSD-generic32" } ],
765       [ 'x86_64-.*-haiku',        { target => "haiku-x86_64" } ],
766       [ '.*-.*-haiku',            { target => "haiku-x86" } ],
767       [ '.*-.*-osf',              { target => "osf1-alpha" } ],
768       [ '.*-.*-tru64',            { target => "tru64-alpha" } ],
769       [ '.*-.*-[Uu]nix[Ww]are7',
770         sub {
771             return { target => "unixware-7",
772                      disable => [ 'sse2' ] } if $CCVENDOR eq "gnu";
773             return { target => "unixware-7",
774                      defines => [ '__i386__' ] };
775         }
776       ],
777       [ '.*-.*-[Uu]nix[Ww]are20.*', { target => "unixware-2.0",
778                                       disable => [ 'sse2', 'sha512' ] } ],
779       [ '.*-.*-[Uu]nix[Ww]are21.*', { target => "unixware-2.1",
780                                       disable => [ 'sse2', 'sha512' ] } ],
781       [ '.*-.*-vos',              { target => "vos",
782                                     disable => [ 'threads', 'shared', 'asm',
783                                                  'dso' ] } ],
784       [ 'BS2000-siemens-sysv4',   { target => "BS2000-OSD" } ],
785       [ 'i[3456]86-.*-cygwin',    { target => "Cygwin-x86" } ],
786       [ '.*-.*-cygwin',
787         sub { return { target => "Cygwin-${MACHINE}" } } ],
788       [ 'x86-.*-android|i.86-.*-android', { target => "android-x86" } ],
789       [ 'armv[7-9].*-.*-android', { target => "android-armeabi",
790                                     cflags => [ '-march=armv7-a' ],
791                                     cxxflags => [ '-march=armv7-a' ] } ],
792       [ 'arm.*-.*-android',       { target => "android-armeabi" } ],
793       [ '.*-hpux1.*',
794         sub {
795             my $KERNEL_BITS = $ENV{KERNEL_BITS};
796             my %common_return = ( defines => [ '_REENTRANT' ] );
797             $KERNEL_BITS ||= `getconf KERNEL_BITS 2>/dev/null` // '32';
798             # See <sys/unistd.h> for further info on CPU_VERSION.
799             my $CPU_VERSION = `getconf CPU_VERSION 2>/dev/null` // 0;
800             if ( $CPU_VERSION >= 768 ) {
801                 # IA-64 CPU
802                 return { target => "hpux64-ia64",
803                          %common_return }
804                     if $KERNEL_BITS eq '64' && ! $CCVENDOR;
805                 return { target => "hpux-ia64",
806                          %common_return };
807             }
808             if ( $CPU_VERSION >= 532 ) {
809                 # PA-RISC 2.x CPU
810                 # PA-RISC 2.0 is no longer supported as separate 32-bit
811                 # target. This is compensated for by run-time detection
812                 # in most critical assembly modules and taking advantage
813                 # of 2.0 architecture in PA-RISC 1.1 build.
814                 my $target = ($CCVENDOR eq "gnu" && $GCC_BITS eq '64')
815                     ? "hpux64-parisc2"
816                     : "hpux-parisc1_1";
817                 if ( $KERNEL_BITS eq '64' && ! $CCVENDOR ) {
818                     print <<EOF;
819 WARNING! To build 64-bit package, do this:
820          $WHERE/Configure hpux64-parisc2-cc
821 EOF
822                     maybe_abort();
823                 }
824                 return { target => $target,
825                          %common_return };
826             }
827             # PA-RISC 1.1+ CPU?
828             return { target => "hpux-parisc1_1",
829                      %common_return } if $CPU_VERSION >= 528;
830             # PA-RISC 1.0 CPU
831             return { target => "hpux-parisc",
832                      %common_return } if $CPU_VERSION >= 523;
833             # Motorola(?) CPU
834             return { target => "hpux",
835                      %common_return };
836         }
837       ],
838       [ '.*-hpux',                { target => "hpux-parisc" } ],
839       [ '.*-aix',
840         sub {
841             my %config = ();
842             my $KERNEL_BITS = $ENV{KERNEL_BITS};
843             $KERNEL_BITS ||= `getconf KERNEL_BITMODE 2>/dev/null`;
844             $KERNEL_BITS ||= '32';
845             my $OBJECT_MODE = $ENV{OBJECT_MODE};
846             $OBJECT_MODE ||= 32;
847             $config{target} = "aix";
848             if ( $OBJECT_MODE == 64 ) {
849                 print 'Your $OBJECT_MODE was found to be set to 64';
850                 $config{target} = "aix64";
851             } else {
852                 if ( $CCVENDOR ne 'gnu' && $KERNEL_BITS eq '64' ) {
853                     print <<EOF;
854 WARNING! To build 64-bit package, do this:
855          $WHERE/Configure aix64-cc
856 EOF
857                     maybe_abort();
858                 }
859             }
860             if ( okrun(
861                        "lsattr -E -O -l `lsdev -c processor|awk '{print \$1;exit}'`",
862                        'grep -i powerpc) >/dev/null 2>&1') ) {
863                 # this applies even to Power3 and later, as they return
864                 # PowerPC_POWER[345]
865             } else {
866                 $config{disable} = [ 'asm' ];
867             }
868             return %config;
869         }
870       ],
871     ];
872
873 # Map GUESSOS into OpenSSL terminology.
874 # Returns a hash table with diverse entries, most importantly 'target',
875 # but also other entries that are fitting for Configure's %config
876 # and MACHINE.
877 # It would be nice to fix this so that this weren't necessary. :( XXX
878 sub map_guess {
879     my $GUESSOS = shift;
880
881     foreach my $tuple ( @$map_patterns ) {
882         my $pat = @$tuple[0];
883         next if $GUESSOS !~ /^${pat}$/;
884         my $result = @$tuple[1];
885         $result = $result->() if ref $result eq 'CODE';
886         return %$result;
887     }
888
889     # Last case, return "z" from x-y-z
890     my @fields = split(/-/, $GUESSOS);
891     return ( target => $fields[2] );
892 }
893
894 # gcc < 2.8 does not support -march=ultrasparc
895 sub check_solaris_sparc8 {
896     my $OUT = shift;
897     if ( $CCVENDOR eq 'gnu' && $CCVER < 208 ) {
898         if ( $OUT eq 'solaris-sparcv9-gcc' ) {
899             print <<EOF;
900 WARNING! Downgrading to solaris-sparcv8-gcc
901          Upgrade to gcc-2.8 or later.
902 EOF
903             maybe_abort();
904             return 'solaris-sparcv8-gcc';
905         }
906         if ( $OUT eq "linux-sparcv9" ) {
907             print <<EOF;
908 WARNING! Downgrading to linux-sparcv8
909          Upgrade to gcc-2.8 or later.
910 EOF
911             maybe_abort();
912             return 'linux-sparcv8';
913         }
914     }
915     return $OUT;
916 }
917
918 ###
919 ###   MAIN PROCESSING
920 ###
921
922 sub get_platform {
923     my %options = @_;
924
925     $VERBOSE = 1 if defined $options{verbose};
926     $WAIT = 0 if defined $options{nowait};
927     $CC = $options{CC};
928     $CROSS_COMPILE = $options{CROSS_COMPILE} // '';
929
930     my $GUESSOS = guess_system();
931     determine_compiler_settings();
932
933     my %ret = map_guess($GUESSOS);
934     $ret{target} = check_solaris_sparc8($ret{target});
935     return %ret;
936 }
937
938 1;