I've been looking into this, and the weird line I mentioned before in hadrian/src/Rules/Program.hs was to blame.
Make the following change and Hadrian will actually attempt to build a stage 2 aarch64 compiler instead of simply copying the amd64 one from the stage 1 directory (though I haven't tried running that stage 2 compiler yet). diff --git a/hadrian/src/Rules/Program.hs b/hadrian/src/Rules/Program.hs index 2490bffbd2..1ef88b0624 100644 --- a/hadrian/src/Rules/Program.hs +++ b/hadrian/src/Rules/Program.hs @@ -97,13 +97,7 @@ buildProgram bin ctx@(Context{..}) rs = do -- so we use pkgRegisteredLibraryFile instead. registerPackages =<< contextDependencies ctx - cross <- flag CrossCompiling - -- For cross compiler, copy @stage0/bin/<pgm>@ to @stage1/bin/@. - case (cross, stage) of - (True, s) | s > stage0InTree -> do - srcDir <- buildRoot <&> (-/- (stageString stage0InTree -/- "bin")) - copyFile (srcDir -/- takeFileName bin) bin - _ -> buildBinary rs bin ctx + buildBinary rs bin ctx buildBinary :: [(Resource, Int)] -> FilePath -> Context -> Action () buildBinary rs bin context@Context {..} = do Making such a change brings up some errors about --host= not being a valid argument, and I fixed those with the following change, which will make the aforementioned attempt to build a compiler that runs on aarch64 actually succeed: diff --git a/cross-build.ksh b/cross-build.ksh index c7c1234a4f..d95d47d977 100644 --- a/cross-build.ksh +++ b/cross-build.ksh @@ -116,26 +116,22 @@ env \ "stage1.*.cabal.configure.opts += \ --configure-option=CPPFLAGS=--sysroot=$SYSROOT \ --ghc-option=-optc--target=aarch64-unknown-openbsd \ - --ghc-option=-optl--host=aarch64-unknown-openbsd \ --ghc-option=-optl--target=aarch64-unknown-openbsd \ --ghc-option=-opta--target=aarch64-unknown-openbsd" \ "stage1.*.ghc.hs.opts += \ -optc--target=aarch64-unknown-openbsd \ -opta--target=aarch64-unknown-openbsd \ - -optl--host=aarch64-unknown-openbsd \ -optl--target=aarch64-unknown-openbsd \ -optl--sysroot=$SYSROOT" \ "stage1.*.ghc.c.opts += \ -optc--target=aarch64-unknown-openbsd \ -optc-fno-ret-protector \ - -optl--host=aarch64-unknown-openbsd \ -optl--target=aarch64-unknown-openbsd \ -opta--target=aarch64-unknown-openbsd \ -optl--sysroot=$SYSROOT \ -optP--sysroot=$SYSROOT" \ "stage1.*.ghc.link.opts += \ -optc--target=aarch64-unknown-openbsd \ - -optl--host=aarch64-unknown-openbsd \ -optl--target=aarch64-unknown-openbsd \ -opta--target=aarch64-unknown-openbsd \ -optl--sysroot=$SYSROOT" \ So I guess those were part of the unnecessary flags (or no longer necessary, --host definitely fixed some errors at the time for me). And that's it in terms of the stage2:exe:ghc-bin target. The issue comes in when you try to make the binary-dist target; it starts off well, but at some point, it attempts to call the ghc-pkg in the bindist directory before the tarball is actually created, and it fails presumably because the ghc-pkg is an aarch64 binary. A catch-22. That said, the error is a complaint about syntax error and snitches on the ghc-pkg file, but when I open it, it's an aarch64 binary. I suspect it's failing to launch for that reason and reporting that fact to whatever's calling it, and that caller is not expecting that output and complains about a syntax error. I can try to manually copy the bindist directory over to my OpenBSD/arm64 VM and see if it works, but might have to manually run some steps that'd normally be run on the build machine instead of the install machine. I guess the fix here is to move those steps to the $ ./configure --prefix=… && gmake install part of the process. Anyway, if I don't get round to it today, I'll hopefully try that tomorrow and let you know how it goes. It does seem to be a known issue since at least a year ago. See https://gitlab.haskell.org/ghc/ghc/-/issues/23975#note_526549: > The resulting binary under _build/stage2/bin is still a stage1 > cross-compiler, that runs on the x86_64 platform. > Hmm yes, that is not currently tested and I would imagine is broken with > hadrian. By the way, I was able to build the aarch64 hello world and run it without issues without the last commit on your fork which adds $PATH and $LD_LIBRARY_PATH to the cc shim. I wanted to see what errors you were getting without that change as it should be inherited from the cross-build.ksh script, but I got none the whole way through. That could be because I had an existing stage 1 or something, but I'll rerun a fresh build and let you know about that, too. Cheers, Habib