develooper Front page | perl.perl5.porters | Postings from August 2011

is MUTLIARCH pointless?

Thread Next
From:
Nicholas Clark
Date:
August 30, 2011 09:46
Subject:
is MUTLIARCH pointless?
Message ID:
20110830100426.GM37285@plum.flirble.org
tl;dr version - MULTIARCH as implemented can not work, and should go.


multiarch (multiarch.U):
	This variable conditionally defines the MULTIARCH symbol
	which signifies the presence of multiplatform files.
	This is normally set by hints files.

MULTIARCH is referenced in these files:

config_h.SH
NetWare/config_H.wc
plan9/config_h.sample
plan9/config.plan9
Porting/config_H
Porting/config_h.pl
Porting/Glossary
pp_pack.c
uconfig.h
win32/config_H.bc
win32/config_H.ce
win32/config_H.gc
win32/config_H.gc64
win32/config_H.gc64nox
win32/config_H.vc
win32/config_H.vc64

It's all config.h and related, apart from pp_pack.c, which has just this:

/* CROSSCOMPILE and MULTIARCH are going to affect pp_pack() and pp_unpack().
   --jhi Feb 1999 */


The relevant code is this:

/* MEM_ALIGNBYTES:
 *	This symbol contains the number of bytes required to align a
 *	double, or a long double when applicable. Usual values are 2,
 *	4 and 8. The default is eight, for safety.
 */
#if defined(USE_CROSS_COMPILE) || defined(MULTIARCH)
#  define MEM_ALIGNBYTES 8
#else
#define MEM_ALIGNBYTES $alignbytes
#endif

...

/* BYTEORDER:
 *	This symbol holds the hexadecimal constant defined in byteorder,
 *	in a UV, i.e. 0x1234 or 0x4321 or 0x12345678, etc...
 *	If the compiler supports cross-compiling or multiple-architecture
 *	binaries (eg. on NeXT systems), use compiler-defined macros to
 *	determine the byte order.
 *	On NeXT 3.2 (and greater), you can build "Fat" Multiple Architecture
 *	Binaries (MAB) on either big endian or little endian machines.
 *	The endian-ness is available at compile-time.  This only matters
 *	for perl, where the config.h can be generated and installed on
 *	one system, and used by a different architecture to build an
 *	extension.  Older versions of NeXT that might not have
 *	defined either *_ENDIAN__ were all on Motorola 680x0 series,
 *	so the default case (for NeXT) is big endian to catch them.
 *	This might matter for NeXT 3.0.
 */
#if defined(USE_CROSS_COMPILE) || defined(MULTIARCH)
#  ifdef __LITTLE_ENDIAN__
#    if LONGSIZE == 4
#      define BYTEORDER 0x1234
#    else
#      if LONGSIZE == 8
#        define BYTEORDER 0x12345678
#      endif
#    endif
#  else
#    ifdef __BIG_ENDIAN__
#      if LONGSIZE == 4
#        define BYTEORDER 0x4321
#      else
#        if LONGSIZE == 8
#          define BYTEORDER 0x87654321
#        endif
#      endif
#    endif
#  endif
#  if !defined(BYTEORDER) && (defined(NeXT) || defined(__NeXT__))
#    define BYTEORDER 0x4321
#  endif
#else
#define BYTEORDER 0x$byteorder	/* large digits for MSB */
#endif /* NeXT */


Initially, I thought "this logic doesn't really belong in config.h. Really
it should be in perl.h". (Partly because it helps microperl). So I tried
moving it (currently smoke-me/byteorder1 but if you're from the future,
reading this in the archives, it will be gone by then. Even knowing that
it's commit 3ec04ee29e91f808602c5321a273c023912fab82 won't help you).
This will work.

However, I'm thinking that this whole MULTIARCH implementation is flawed.
It only covers different endianness and alignment. It assumes that everything
else is the same.

If one looks at what Apple have to do to get a working multiarch perl on x86
and x86_64, http://www.opensource.apple.com/source/perl/perl-73/5.12/fix/

config.h needs a lot of bogery:

/define[ 	]PRINTF_FORMAT_NULL_OK/c
#ifdef __LP64__
/*#define PRINTF_FORMAT_NULL_OK	/ **/
#else /* !__LP64__ */
#define PRINTF_FORMAT_NULL_OK	/**/
#endif /* __LP64__ */
.
/define[ 	]LONGSIZE/c
#ifdef __LP64__
#define LONGSIZE 8		/**/
#else /* !__LP64__ */
#define LONGSIZE 4		/**/
#endif /* __LP64__ */
.
/define[ 	]CASTI32/c
#ifdef __ppc__
#define CASTI32		/**/
#else /* !__ppc__ */
/*#define CASTI32		/ **/
#endif /* __ppc__ */
.


[etc]

and lib/Config_heavy.pl needs a lot of code injecting, the best example of
which is:

my $_archflags = exists($ENV{ARCHFLAGS}) ? $ENV{ARCHFLAGS} : '@ARCHFLAGS@';
my %_archkeys = (
    archflags => 1,
    ccflags => 1,
    ccflags_nolargefiles => 1,
    lddlflags => 1,
    ldflags => 1,
    ldflags_nolargefiles => 1,
);
my $_64bit = ((~0>>1) > 2147483647);
my $_64bitdefine = ($_64bit ? 'define' : 'undef');
my $_64bitsize = ($_64bit ? '8' : '4');
my $_64bitundef = ($_64bit ? 'undef' : 'define');
my $_i386 = ($Config::byteorder eq '1234');
my $_ppc = ($Config::byteorder eq '4321');

my %_change = (
    byteorder => $Config::byteorder,
    castflags => ($_i386 ? '1' : '0'),
    d_casti32 => ($_ppc ? 'define' : 'undef'),
    d_castneg => ($_i386 ? 'undef' : 'define'),
    d_nv_preserves_uv => $_64bitundef,
    d_printf_format_null => $_64bitundef,
    gidformat => ($_64bit ? '"u"' : '"lu"'),
    i32type => ($_64bit ? 'int' : 'long'),
    i64type => ($_64bit ? 'long' : 'long long'),
    ivsize => $_64bitsize,
    longsize => $_64bitsize,
    need_va_copy => $_64bitdefine,
    nv_preserves_uv_bits => ($_64bit ? '53' : '32'),
    ptrsize => $_64bitsize,
    quadkind => ($_64bit ? '2' : '3'),
    quadtype => ($_64bit ? 'long' : 'long long'),
    sizesize => $_64bitsize,
    u32type => ($_64bit ? 'unsigned int' : 'unsigned long'),
    u64type => ($_64bit ? 'unsigned long' : 'unsigned long long'),
    uidformat => ($_64bit ? '"u"' : '"lu"'),
    uquadtype => ($_64bit ? 'unsigned long' : 'unsigned long long'),
    use64bitall => $_64bitdefine,
    use64bitint => $_64bitdefine,
    uvsize => $_64bitsize,
);
if(exists($ENV{RC_XBS}) && $ENV{RC_XBS} eq 'YES') {
    $_change{installarchlib} = '@ARCHLIB@';
    $_change{installprivlib} = '@PRIVLIB@';
}

sub _fix {
    my $in = shift;
    my($k, $v);
    local $_;
    ($k, $_) = split('=', $in, 2);
    return $in unless defined($k);
    $_archkeys{$k} && do { s/(['"])/$1$_archflags /; return join('=', $k, $_); };
    defined($v = $_change{$k}) && do { s/(['"]).*?\1/$1$v$1/; return join('=', $k, $_); };
    $in;
}



So it's fair to say that MULTIARCH doesn't work. I think it's fair to say
that it's never going to work (in any automated clean fashion), because
the core assumption of Configure is that it can run probes locally which
determine the "shape" of the *architecture* and platform that it's building
for, and record these for future use. A MULTIARCH environment breaks this
assumption - probing for the platform is fine, but the architecture is not
supposed to matter, and the multiarch toolchain is (effectively)
cross-compiling to the other architecture(s) using the configuration of the
current.

The checks for MULTIARCH (and USE_CROSS_COMPILE) was added in this commit,
along with the "fix" for MEM_ALIGNBYTES.

commit 68c15b6fa35fc2fdb7a325ebe019c47b083fda6e
Author: Hans Mulder <hansmu@xs4all.nl>
Date:   Sun Feb 21 23:58:55 1999 +0100

    Not OK: perl 5.00555 on OPENSTEP-Mach-thread 4_2 (UNINSTALLED)
    
    To: perlbug@perl.com
    Reply-To: hansmu@xs4all.nl
    Message-Id: <9902212201.AA13386@icgned.icgroup.nl>
    
    plus other Configure changes: prepare for cross-compilation/
    multiarchitecture builds.
    
    p4raw-id: //depot/cfgperl@3006


The concept of ignoring the probed BYTEORDER started to fix the build on
NeXT in 1996 with

commit 40750cc09a264b13c386a12479d3f3bade1e4c58
Author: Perl 5 Porters <perl5-porters@africa.nicoh.com>
Date:   Wed Jul 10 23:29:53 1996 +0000

    perl 5.003_01: config_h.SH
    
    Insure execution by /bin/sh
    Add BIN_SH macro (defaults to /bin/sh)
    Remove old copy of config.h before creating new one
    Ascertain BYTEORDER at compile time on NeXT, so it's correct for MABs



specifically, this hunk:

@@ -1342,7 +1351,17 @@ sed <<!GROK!THIS! >config.h -e 's!^#undef!/\*#define!' -e 's!^#un-def!#undef!'
  *	This symbol hold the hexadecimal constant defined in byteorder,
  *	i.e. 0x1234 or 0x4321, etc...
  */
+#ifndef NeXT
 #define BYTEORDER 0x$byteorder	/* large digits for MSB */
+#else /* NeXT */
+
+#ifdef __BIG_ENDIAN__
+#define BYTEORDER 0x4321
+#else /* __LITTLE_ENDIAN__ */
+#define BYTEORDER 0x1234
+#endif /* ENDIAN CHECK */
+
+#endif /* !NeXT */
 
 /* CSH:
  *	This symbol, if defined, indicates that the C-shell exists.


It was never in the right place. It should have been in perl.h

However, I think it only happened to work back then because the 2
architectures NeXT ran on were both 32 bit, and differed only in 2 ways.
It can't "scale" up to genuinely different architectures.

As a footnote, I can't see that it's necessary to enable it for
USE_CROSS_COMPILE either. Cross compilation is going to need a target
config.sh that has everything else correct for the target architecture,
so logically that can provide the correct $alignment and $byteorder too.

Either the core can build completely from C compiler headers.
Or it can't, in which case we need probing or canned configs.
But trying a 10% solution for the former just adds cruft.

Nicholas Clark

Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About