bytestring
bytestring copied to clipboard
storableToF should use target instead of host arch?
Currently we have:
{-# INLINE CONLIKE storableToF #-}
storableToF :: forall a. Storable a => FixedPrim a
-- Not all architectures are forgiving of unaligned accesses; whitelist ones
-- which are known not to trap (either to the kernel for emulation, or crash).
#if defined(i386_HOST_ARCH) || defined(x86_64_HOST_ARCH) \
|| ((defined(arm_HOST_ARCH) || defined(aarch64_HOST_ARCH)) \
&& defined(__ARM_FEATURE_UNALIGNED)) \
|| defined(powerpc_HOST_ARCH) || defined(powerpc64_HOST_ARCH) \
|| defined(powerpc64le_HOST_ARCH)
storableToF = FP (sizeOf (undefined :: a)) (\x op -> poke (castPtr op) x)
#else
storableToF = FP (sizeOf (undefined :: a)) $ \x op ->
if ptrToWordPtr op `mod` fromIntegral (alignment (undefined :: a)) == 0 then poke (castPtr op) x
else with x $ \tp -> copyBytes op (castPtr tp) (sizeOf (undefined :: a))
#endif
Isn't this broken during cross compilation? E.g. if I compile on powerpc_HOST_ARCH targeting a platform that doesn't support unaligned access wouldn't this fall over?
I'm not an expert on cross compilation but seemed wrong to me.
You're probably correct, @AndreasPK. Do you have a suggestion how to fix this? Are there corresponding x_TARGET_ARCH
pragmas that we could make use of?
I think x_HOST_ARCH
is the correct thing to check. The host arch for a given build is the machine the compiled code will be run on. If I understand correctly, the idea of a target arch doesn't even make sense in the context of bytestring as it's not a compiler.
But this is definitely a confusing topic. Ideally these functions should be tested in a cross-compiled build.
I think x_HOST_ARCH is the correct thing to check. The host arch for a given build is the machine the compiled code will be run on. If I understand correctly, the idea of a target arch doesn't even make sense in the context of bytestring as it's not a compiler.
If you are reasonably sure of this feel free to close this ticket. It seemed wrong to me but it might be fine for all I know. I really don't know enough about cross compilation to say for sure.
I think
x_HOST_ARCH
is the correct thing to check. The host arch for a given build is the machine the compiled code will be run on. If I understand correctly, the idea of a target arch doesn't even make sense in the context of bytestring as it's not a compiler.But this is definitely a confusing topic. Ideally these functions should be tested in a cross-compiled build.
I'm afraid we can't just outright discount bytestring as not being a compiler. It is certainly part of GHC, and as such part of any cross compiling ghc.
Now, which one is active? Let's take an aarch64 cross compiler, and compile the following Main.hs
{-# language CPP #-}
main = do
#if defined(aarch64_HOST_ARCH)
putStrLn "aarch64_HOST_ARCH"
#endif
#if defined(aarch64_TARGET_ARCH)
putStrLn "aarch64_TARGET_ARCH)
#endif
return ()
$ aarch64-unknown-linux-gnu-ghc Main.hs
$ qemu-aarch64 Main
aarch64_HOST_ARCH
As such we can see that _HOST_ARCH
is active, as that's where the final library/executable will be hosted. However, we should be aware that there are cases, where libraries are part of cross compilers and _TARGET_ARCH
might also be defined.
--
If you wonder how to get such a cross compiler for experimental purposes:
- clone https://github.com/angerman/ghc-repro-21767
- run
nix develop .#packages.x86_64-linux."aarch64-linux:exe:repro@8107"
you sould have theaarch64-unknown-linux-gnu-ghc
in path,qemu
won't be in path but at/nix/store/salf5mh7mr22p5s7vxl62kzbw8b9dpiy-qemu-6.2.0/bin/qemu-aarch64
; due to being a dependency of the iserv cross compilation setup. To get most of this from caches, you want
substituters = https://cache.zw3rk.com/
trusted-public-keys = loony-tools:pr9m4BkM/5/eSTZlkQyRt57Jz7OMBxNSUiMC4FkcNfk=
I'm afraid we can't just outright discount bytestring as not being a compiler. It is certainly part of GHC, and as such part of any cross compiling ghc.
GHC depends on bytestring, so that any ghc is linked with some build of bytestring, with bytestring_HOST = ghc_HOST
. But each GHC build corresponds to at least two different bytestring builds, so there isn't a one-to-one correspondence to be found here. In particular, the GHC build process also builds a variant of bytestring with bytestring_HOST = ghc_BUILD
for linking with the stage1-ghc that produces the final compiler, and in the cross-compilation case I wouldn't be surprised if there is a third bytestring variant with bytestring_HOST = ghc_TARGET
for linking with the executables produced by that cross-compiling ghc.
So, are all three of these bytestring variants "certainly part of" GHC? And for which of them is the notion of "target arch" applicable and relevant? I think the best answer to both questions is "none of them."