TopperDEL
TopperDEL

Reputation: 101

Compile Go for windows/arm and arm64 with buildmode=c-shared

I need to compilet a go library via C to a DLL that can be used through PInvoke on ARM/ARM64 Windows. I find many open issues, topics and discussions about this and it sounds like it might partially work. But if I try it like this:

    export CC="arm-none-eabi-gcc"
    export CXX="arm-none-eabi-g++"
    export GOOS="windows"
    export GOARCH="arm"
    export GOARM=7
    export CGO_ENABLED="1"
    go build -ldflags="-s -w" -o my_library.dll -buildmode c-shared

I get the result buildmode c-shares is not supported on windows/arm. So it seems to still be not supported.

Another problem is that I need to set CGO_ENABLED and route the compiling through a C/C++-Toolchain as I have to add a C-file generated by SWIG. I tried the above on Ubunu 20.04 with the toolchain of the package gcc-arm-none-eabi.

I'm no C/C++/Go-pro - but the same works for nearly all other platforms like Windows, Linux, Android, Mac and iOS. The latter also is based on ARM64, so I do not really understand why this is not possible - though I value the difficulties with all this.

So, if someone with more in-depth-knowledge can help me here that would be great.

Just to clarifiy: I do not want/need to compile Go itself for ARM/ARM64. I need to compile a Go-program for that platform (to use my library from .Net on e.g. the Surface or a Hololens).

Update from 04.08.2021:

Go 1.17rc2 should include windows arm64 now. And I got the hint to use Zig for cross-compiling. So I've changed my build pipeline to something like this (I'm using Azure Devops in a Ubuntu VM):

go get -v golang.org/dl/go1.17rc2
/home/vsts/go/bin/go1.17rc2 download
/home/vsts/go/bin/go1.17rc2 version
sudo snap install zig --classic --beta
zig version
export CC="zig cc -target aarch64-windows-gnu"
export CXX="zig c++ -target aarch64-windows-gnu"
export GOOS="windows"
export GOARCH="arm64"
export GOARM=7
export CGO_ENABLED="1"
/home/vsts/go/bin/go1.17rc2 build -ldflags="-s -w" -o storj_uplink.dll -buildmode c-shared -tags extended

I then get this error:

2021-08-03T19:24:52.0641737Z # runtime/cgo
2021-08-03T19:24:52.0642803Z info: Usage: zig [command] [options]
2021-08-03T19:24:52.0643335Z 
2021-08-03T19:24:52.0643827Z Commands:
2021-08-03T19:24:52.0643940Z 
2021-08-03T19:24:52.0644276Z   build            Build project from build.zig
2021-08-03T19:24:52.0645203Z   init-exe         Initialize a `zig build` application in the cwd
2021-08-03T19:24:52.0645768Z   init-lib         Initialize a `zig build` library in the cwd
2021-08-03T19:24:52.0645950Z 
2021-08-03T19:24:52.0646407Z   ast-check        Look for simple compile errors in any set of files
2021-08-03T19:24:52.0646936Z   build-exe        Create executable from source or object files
2021-08-03T19:24:52.0647468Z   build-lib        Create library from source or object files
2021-08-03T19:24:52.0647994Z   build-obj        Create object from source or object files
2021-08-03T19:24:52.0648390Z   fmt              Reformat Zig source into canonical form
2021-08-03T19:24:52.0648753Z   run              Create executable and run immediately
2021-08-03T19:24:52.0649088Z   test             Create and run a test build
2021-08-03T19:24:52.0649551Z   translate-c      Convert C code to Zig code
2021-08-03T19:24:52.0649707Z 
2021-08-03T19:24:52.0650109Z   ar               Use Zig as a drop-in archiver
2021-08-03T19:24:52.0650576Z   cc               Use Zig as a drop-in C compiler
2021-08-03T19:24:52.0651070Z   c++              Use Zig as a drop-in C++ compiler
2021-08-03T19:24:52.0651549Z   dlltool          Use Zig as a drop-in dlltool.exe
2021-08-03T19:24:52.0652033Z   lib              Use Zig as a drop-in lib.exe
2021-08-03T19:24:52.0652495Z   ranlib           Use Zig as a drop-in ranlib
2021-08-03T19:24:52.0652670Z 
2021-08-03T19:24:52.0652962Z   env              Print lib path, std path, cache directory, and version
2021-08-03T19:24:52.0653531Z   help             Print this help and exit
2021-08-03T19:24:52.0653879Z   libc             Display native libc paths file or validate one
2021-08-03T19:24:52.0654250Z   targets          List available compilation targets
2021-08-03T19:24:52.0654579Z   version          Print version number and exit
2021-08-03T19:24:52.0655062Z   zen              Print Zen of Zig and exit
2021-08-03T19:24:52.0655220Z 
2021-08-03T19:24:52.0655445Z General Options:
2021-08-03T19:24:52.0655565Z 
2021-08-03T19:24:52.0655982Z   -h, --help       Print command-specific usage
2021-08-03T19:24:52.0656154Z 
2021-08-03T19:24:52.0656502Z error: unknown command: -E
2021-08-03T19:25:03.2047129Z # golang.org/x/sys/windows
2021-08-03T19:25:03.2048568Z /home/vsts/go/pkg/mod/golang.org/x/[email protected]/windows/types_windows.go:1620:24: undefined: JOBOBJECT_BASIC_LIMIT_INFORMATION
2021-08-03T19:25:03.2049594Z /home/vsts/go/pkg/mod/golang.org/x/[email protected]/windows/zsyscall_windows.go:3020:38: undefined: WSAData
2021-08-03T19:25:03.2050606Z /home/vsts/go/pkg/mod/golang.org/x/[email protected]/windows/zsyscall_windows.go:3096:51: undefined: Servent
2021-08-03T19:25:03.2051572Z /home/vsts/go/pkg/mod/golang.org/x/[email protected]/windows/zsyscall_windows.go:3110:50: undefined: Servent
2021-08-03T19:25:04.7947309Z ##[error]Bash exited with code '1'.

Basically "unknown command: -E" which is described here. But from my understanding this should work already. And furthermore this blog post does it directly with zig, too.

Second update from 04.08.2021

Go is now calling zig! The workaround using a bash-script is working. Now I get the following error:

2021-08-04T11:54:47.2530981Z # golang.org/x/sys/windows
2021-08-04T11:54:47.2532284Z /home/vsts/go/pkg/mod/golang.org/x/[email protected]/windows/types_windows.go:1620:24: undefined: JOBOBJECT_BASIC_LIMIT_INFORMATION
2021-08-04T11:54:47.2533180Z /home/vsts/go/pkg/mod/golang.org/x/[email protected]/windows/zsyscall_windows.go:3020:38: undefined: WSAData
2021-08-04T11:54:47.2534002Z /home/vsts/go/pkg/mod/golang.org/x/[email protected]/windows/zsyscall_windows.go:3096:51: undefined: Servent
2021-08-04T11:54:47.2534797Z /home/vsts/go/pkg/mod/golang.org/x/[email protected]/windows/zsyscall_windows.go:3110:50: undefined: Servent
2021-08-04T11:54:57.4223210Z # runtime/cgo
2021-08-04T11:54:57.4224911Z /snap/zig/3678/lib/libc/mingw/secapi/vsprintf_s.c:39:10: warning: implicit declaration of function '__ms_vsnprintf' is invalid in C99 [-Wimplicit-function-declaration]
2021-08-04T11:54:57.4225714Z   return __ms_vsnprintf (_DstBuf, _Size, _Format, _ArgList);
2021-08-04T11:54:57.4226223Z          ^
2021-08-04T11:54:57.4226624Z 1 warning generated.
2021-08-04T11:54:57.4227534Z /snap/zig/3678/lib/libc/mingw/math/arm/s_trunc.c/snap/zig/3678/lib/libc/mingw/math/arm/s_truncf.c:24:10: fatal error: '../bsd_private_base.h' file not found
2021-08-04T11:54:57.4228188Z #include "../bsd_private_base.h"
2021-08-04T11:54:57.4228651Z          ^~~~~~~~~~~~~~~~~~~~~~~
2021-08-04T11:54:57.4229332Z :26:10: fatal error: '../bsd_private_base.h' file not found
2021-08-04T11:54:57.4229850Z #include "../bsd_private_base.h"
2021-08-04T11:54:57.4230310Z          ^~~~~~~~~~~~~~~~~~~~~~~
2021-08-04T11:54:57.4230966Z 1 error generated.
2021-08-04T11:54:57.4231397Z 1 error generated.
2021-08-04T11:54:57.4522549Z ##[error]Bash exited with code '1'.

Update from 05.08.2021:

I finally found a toolchain that at least does not throw an error. But now it quits silently without generating a DLL. Not sure what happens now, though. This is my call:

go get -v golang.org/dl/go1.17rc2
/home/vsts/go/bin/go1.17rc2 download
/home/vsts/go/bin/go1.17rc2 version
wget https://developer.arm.com/-/media/Files/downloads/gnu-a/10.3-2021.07/binrel/gcc-arm-10.3-2021.07-x86_64-arm-none-linux-gnueabihf.tar.xz
tar -xf gcc-arm-10.3-2021.07-x86_64-arm-none-linux-gnueabihf.tar.xz
cd gcc-arm-10.3-2021.07-x86_64-arm-none-linux-gnueabihf
cd bin
export PATH=$PATH:$(pwd)
cd ..
cd ..
cd uplink-c

export CC="arm-none-linux-gnueabihf-gcc -v"
export CXX="arm-none-linux-gnueabihf-g++ -v"
export GOOS="windows"
export GOARCH="arm64"
export GOARM=7
export CGO_ENABLED="1"
home/vsts/go/bin/go1.17rc2 build -ldflags="-s -w" -o storj_uplink.dll -buildmode c-shared -tags extended -v

Upvotes: 2

Views: 7284

Answers (1)

VonC
VonC

Reputation: 1323653

I do not want/need to compile Go itself for ARM/ARM64. I need to compile a Go-program for that platform

That should work, using Go 1.17 beta

Its documentation do mention:

Windows

Go 1.17 adds support of 64-bit ARM architecture on Windows (the windows/arm64 port).
This port supports cgo.

The OP topperdel refers in the comments to CL 326310:

cmd/internal/sys: mark windows/arm64 as c-shared-capable

The platform supports c-shared now, so flip this on.
I've given this a small smoke test using WireGuard Tunnel Library, and it was able to pass packets and generally function well.

Since the WireGuard Tunnel Library uses quite a bit of Go functionality under the hood, I think it's a decent test that a lot of things that should be working are working. So this commit enables it.

In order to get all tests passing, we make a few small changes, such as passing -Wno-dll-attribute-on-redeclaration to clang and avoiding loading shared libraries into Powershell on arm.

As illustrated by those issues, this is this is still a work in progress:

  • issue 46502 ("runtime: several tests are failing on windows-arm64-aws builder due to redeclaration warnings (upgraded to errors in testing)"),
  • issue 46701 ("Powershell on arm64/arm cannot load arm64/arm binaries because it is an intel process")

The test part is now (June 13th, 2021) closed with golang/go commit 1ed0d12:

runtime: testprogcgo: don't call exported Go functions directly from Go

Instead route through a C function, to avoid declaration conflicts between the declaration needed in the cgo comment and the declaration generated by cgo in _cgo_export.h.

This is not something user code will ever do, so no need to make it work in cgo.


I mentioned in the comments

From ziglang/zig issue 7342, zig should be supported now.
Example, with Go 1.17 : "Zig Makes Go Cross Compilation Just Work" from Loris Cro (VP of community @ziglang):

CGO_ENABLED=1 GOOS=linux GOARCH=amd64 \
CC="zig cc -target x86_64-linux" \
CXX="zig c++ -target x86_64-linux" \
go build --tags extended

You would need to adapt the arch targets to your need

Note: a bash shell session is needed. So git bash on Windows, for instance.

Upvotes: 1

Related Questions