Skip to content

Instantly share code, notes, and snippets.

@steeve
Last active July 9, 2024 04:49
Show Gist options
  • Save steeve/6905542 to your computer and use it in GitHub Desktop.
Save steeve/6905542 to your computer and use it in GitHub Desktop.
How to cross compile Go with CGO programs for a different OS/Arch

How to cross compile Go with CGO programs for a different OS/Arch

It is possible to compile Go programs for a different OS, even though go build says otherwise.

You'll need:

First of all, clone the Go repo and switch to tip:

$ hg clone -u release https://code.google.com/p/go
$ cd go
go$ hg update default

Apply the patch:

go$ curl https://gist.github.com/steeve/6905542/raw/cross_compile_goos.patch | patch -p1
patching file src/cmd/go/build.go

Build Go:

go$ cd src
go/src$ bash all.bash

Now use golang-crosscompiler to build all the toolchains

go$ git clone https://github.com/davecheney/golang-crosscompile.git
go$ source golang-crosscompile/crosscompile.bash
go$ go-crosscompile-build-all
go-crosscompile-build darwin/386
# Building C bootstrap tool.
....
---
Installed Go for windows/amd64 in /usr/local/go
Installed commands in /usr/local/go/bin

Almost there, now a little cmd-fu and you're done. Just set the CC env var to your toolchain's gcc, set the proper GOOS, GOARCH, GOARM (if needed) and finally the proper -extld ldflag.

Cross compiling from darwin/amd64 to windows/386:

$ CC=i586-mingw32-gcc GOOS=windows GOARCH=386 CGO_ENABLED=1 go build -v -o myprogram.exe -ldflags="-extld=$CC"

Cross compiling from darwin/amd64 to linux/amd64:

$ CC=x86_64-pc-linux-gcc GOOS=linux GOARCH=amd64 CGO_ENABLED=1 go build -v -o myprogram -ldflags="-extld=$CC"

Cross compiling from linux/amd64 to linux/arm (in that case a Raspberry Pi):

$ CC=arm-linux-gnueabihf-gcc GOOS=linux GOARCH=arm GOARM=6 CGO_ENABLED=1 go build -v -o myprogram -ldflags="-extld=$CC"
diff --git a/src/cmd/go/build.go b/src/cmd/go/build.go.patched
index 2ce968a..a90044f 100644
--- a/src/cmd/go/build.go
+++ b/src/cmd/go/build.go.patched
@@ -1921,9 +1921,9 @@ var (
)
func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles []string, gxxfiles []string) (outGo, outObj []string, err error) {
- if goos != toolGOOS {
- return nil, nil, errors.New("cannot use cgo when compiling for a different operating system")
- }
+ // if goos != toolGOOS {
+ // return nil, nil, errors.New("cannot use cgo when compiling for a different operating system")
+ // }
cgoCPPFLAGS := stringList(envList("CGO_CPPFLAGS"), p.CgoCPPFLAGS)
cgoCFLAGS := stringList(envList("CGO_CFLAGS"), p.CgoCFLAGS)
@c4milo
Copy link

c4milo commented Jun 13, 2014

Any hints about how to install the toolchains in OSX?

@c4milo
Copy link

c4milo commented Jun 13, 2014

nvm, I'm going to use qemu

@drewwells
Copy link

Is this still relevant with Go 1.3.3?

@prateekbaheti
Copy link

any pointers on cross compiling from darwin/amd64 to windows/amd64 ?

@elimisteve
Copy link

elimisteve commented Feb 4, 2017

Dear citizens of the past and future,

Since ~2015, basic cross-compiling has gotten very easy:

For Linux desktop:

$ GOOS=linux GOARCH=amd64 go build

For iOS:

$ GOOS=darwin GOARCH=arm64 go build

For old Windows desktop:

$ GOOS=windows GOARCH=386 go build

To get the complete list of GOOS/GOARCH combinations, run

$ go tool dist list

@davmaz
Copy link

davmaz commented Feb 10, 2017

Thanks for this link. I thought, however, that cross-compiling AND using CGO was explicitly NOT supported. In other words, I have a cross-compiled library (like OpenBLAS which is built with gfortran and gcc for the ARM target), but I can't link to that library from go code. Am I missing something? I should mention that I'm doing all of this on an X86 machine.

@thapakazi
Copy link

does this still works ? @steeve

@slaveofcode
Copy link

Dear citizens of the past and future,

Since ~2015, basic cross-compiling has gotten very easy:

For Linux desktop:

$ GOOS=linux GOARCH=amd64 go build

For iOS:

$ GOOS=darwin GOARCH=arm64 go build

For old Windows desktop:

$ GOOS=windows GOARCH=386 go build

To get the complete list of GOOS/GOARCH combinations, run

$ go tool dist list

Your statement is true for building without CGO_ENABLED flag

@johnelliott
Copy link

Has anyone found guidance for doing CC with cgo and statically linking for a single sharable binary that contains the C dependencies?

I would guess this is a consideration of the cross compiler invocation, so if anyone has a tip there that's just as good :)

@RichardLindhout
Copy link

docker run -it --rm \
  -v $GOPATH/src/github.com/MYPROJECT/app/backend:/go/src/github.com/MYPROJECT/app/backend \
  -w /go/src/github.com/MYPROJECT/app/backend \
  -e CGO_ENABLED=1 \
  docker.elastic.co/beats-dev/golang-crossbuild:1.14.4-main-debian8 \
  --build-cmd "go build" \
  -p "linux/amd64"

@rahamotaqy
Copy link

Dear citizens of the past and future,
Since ~2015, basic cross-compiling has gotten very easy:
For Linux desktop:

$ GOOS=linux GOARCH=amd64 go build

For iOS:

$ GOOS=darwin GOARCH=arm64 go build

For old Windows desktop:

$ GOOS=windows GOARCH=386 go build

To get the complete list of GOOS/GOARCH combinations, run

$ go tool dist list

Your statement is true for building without CGO_ENABLED flag

have anybody found a solution?

@elimisteve
Copy link

@codertjay
Copy link

codertjay commented Feb 13, 2024

For the CGO_Enabled issues i as able to fix mine this way
Install MinGW-w64: If you haven't already, install the MinGW-w64 toolchain. On Ubuntu, you can do this with the following command:

sudo apt-get install mingw-w64

Set the CC Environment Variable: Before running the go build command, set the CC environment variable to point to the MinGW-w64 C compiler. For example:

export CC=/usr/bin/x86_64-w64-mingw32-gcc

Build Your Application: Now try building your Go application again with the same GOOS, GOARCH, and CGO_ENABLED environment variables:
GOOS=windows GOARCH=amd64 CGO_ENABLED=1 go build -o BPSMailer.exe
If you continue to experience issues, it may be helpful to check the documentation for the MinGW-w64 toolchain or seek assistance from the Go community, as they may have encountered similar issues when cross-compiling Go applications for Windows.

![image](Screenshot from 2024-02-13 12-57-58)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment