Cross compile Go on OSX?

GoCompilationCross Compiling

Go Problem Overview


I am trying to cross-compile a go app on OSX to build binaries for windows and linux. I have read everything what I could find on the net. Closest example that I have found has been published on (apart from many unfinished discussions on go-nuts mailing list):

http://solovyov.net/en/2012/03/09/cross-compiling-go/

yet it does not work on my installation. I have go 1.0.2. As 1.0.2 is quite recent it looks to me that all above examples do not apply to this version.

Tried to do ./make.bash --no-clean with ENV vars set to 386/windows, it does build go, however it builds go for my installation which is darwin/amd64 and completely ignores what is set in ENV that suppose to build different compiler.

Any advises how it can be done (if it can be done at all)?

Go Solutions


Solution 1 - Go

With Go 1.5 they seem to have improved the cross compilation process, meaning it is built in now. No ./make.bash-ing or brew-ing required. The process is described here but for the TLDR-ers (like me) out there: you just set the GOOS and the GOARCH environment variables and run the go build.

For the even lazier copy-pasters (like me) out there, do something like this if you're on a *nix system:

env GOOS=linux GOARCH=arm go build -v github.com/path/to/your/app

You even learned the env trick, which let you set environment variables for that command only, completely free of charge.

Solution 2 - Go

Thanks to kind and patient help from golang-nuts, recipe is the following:

  1. One needs to compile Go compiler for different target platforms and architectures. This is done from src folder in go installation. In my case Go installation is located in /usr/local/go thus to compile a compiler you need to issue make utility. Before doing this you need to know some caveats.

There is an issue about CGO library when cross compiling so it is needed to disable CGO library.

Compiling is done by changing location to source dir, since compiling has to be done in that folder

cd /usr/local/go/src

then compile the Go compiler:

sudo GOOS=windows GOARCH=386 CGO_ENABLED=0 ./make.bash --no-clean

You need to repeat this step for each OS and Architecture you wish to cross compile by changing the GOOS and GOARCH parameters.

If you are working in user mode as I do, sudo is needed because Go compiler is in the system dir. Otherwise you need to be logged in as super user. On Mac you may need to enable/configure SU access (it is not available by default), but if you have managed to install Go you possibly already have root access.

  1. Once you have all cross compilers built, you can happily cross compile your application by using the following settings for example:

    GOOS=windows GOARCH=386 go build -o appname.exe appname.go

    GOOS=linux GOARCH=386 CGO_ENABLED=0 go build -o appname.linux appname.go

Change the GOOS and GOARCH to targets you wish to build.

If you encounter problems with CGO include CGO_ENABLED=0 in the command line. Also note that binaries for linux and mac have no extension so you may add extension for the sake of having different files. -o switch instructs Go to make output file similar to old compilers for c/c++ thus above used appname.linux can be any other extension.

Solution 3 - Go

If you use Homebrew on OS X, then you have a simpler solution:

$ brew install go --with-cc-common # Linux, Darwin, and Windows

or..

$ brew install go --with-cc-all # All the cross-compilers

Use reinstall if you already have go installed.

Solution 4 - Go

You can do this pretty easily using Docker, so no extra libs required. Just run this command:

docker run --rm -it -v "$GOPATH":/go -w /go/src/github.com/iron-io/ironcli golang:1.4.2-cross sh -c '
for GOOS in darwin linux windows; do
  for GOARCH in 386 amd64; do
    echo "Building $GOOS-$GOARCH"
    export GOOS=$GOOS
    export GOARCH=$GOARCH
    go build -o bin/ironcli-$GOOS-$GOARCH
  done
done
'

You can find more details in this post: https://medium.com/iron-io-blog/how-to-cross-compile-go-programs-using-docker-beaa102a316d

Solution 5 - Go

The process of creating executables for many platforms can be a little tedious, so I suggest to use a script:

#!/usr/bin/env bash

package=$1
if [[ -z "$package" ]]; then
  echo "usage: $0 <package-name>"
  exit 1
fi
package_name=$package

#the full list of the platforms: https://golang.org/doc/install/source#environment
platforms=(
"darwin/386"
"dragonfly/amd64"
"freebsd/386"
"freebsd/amd64"
"freebsd/arm"
"linux/386"
"linux/amd64"
"linux/arm"
"linux/arm64"
"netbsd/386"
"netbsd/amd64"
"netbsd/arm"
"openbsd/386"
"openbsd/amd64"
"openbsd/arm"
"plan9/386"
"plan9/amd64"
"solaris/amd64"
"windows/amd64"
"windows/386" )

for platform in "${platforms[@]}"
do
    platform_split=(${platform//\// })
    GOOS=${platform_split[0]}
    GOARCH=${platform_split[1]}
    output_name=$package_name'-'$GOOS'-'$GOARCH
    if [ $GOOS = "windows" ]; then
        output_name+='.exe'
    fi

    env GOOS=$GOOS GOARCH=$GOARCH go build -o $output_name $package
    if [ $? -ne 0 ]; then
        echo 'An error has occurred! Aborting the script execution...'
        exit 1
    fi
done

I checked this script on OSX only

gist - go-executable-build.sh

Solution 6 - Go

> for people who need CGO enabled and cross compile from OSX targeting > windows

I needed CGO enabled while compiling for windows from my mac since I had imported the https://github.com/mattn/go-sqlite3 and it needed it. Compiling according to other answers gave me and error:

/usr/local/go/src/runtime/cgo/gcc_windows_amd64.c:8:10: fatal error: 'windows.h' file not found

If you're like me and you have to compile with CGO. This is what I did:

1.We're going to cross compile for windows with a CGO dependent library. First we need a cross compiler installed like mingw-w64

brew install mingw-w64

This will probably install it here /usr/local/opt/mingw-w64/bin/.

2.Just like other answers we first need to add our windows arch to our go compiler toolchain now. Compiling a compiler needs a compiler (weird sentence) compiling go compiler needs a separate pre-built compiler. We can download a prebuilt binary or build from source in a folder eg: ~/Documents/go now we can improve our Go compiler, according to top answer but this time with CGO_ENABLED=1 and our separate prebuilt compiler GOROOT_BOOTSTRAP(Pooya is my username):

cd /usr/local/go/src
sudo GOOS=windows GOARCH=amd64 CGO_ENABLED=1 GOROOT_BOOTSTRAP=/Users/Pooya/Documents/go ./make.bash --no-clean
sudo GOOS=windows GOARCH=386 CGO_ENABLED=1 GOROOT_BOOTSTRAP=/Users/Pooya/Documents/go ./make.bash --no-clean

3.Now while compiling our Go code use mingw to compile our go file targeting windows with CGO enabled:

GOOS="windows" GOARCH="386" CGO_ENABLED="1" CC="/usr/local/opt/mingw-w64/bin/i686-w64-mingw32-gcc" go build hello.go
GOOS="windows" GOARCH="amd64" CGO_ENABLED="1" CC="/usr/local/opt/mingw-w64/bin/x86_64-w64-mingw32-gcc" go build hello.go

Solution 7 - Go

Since go 1.17.1 you must explicitly set go env variables.

I've done it in a shell script

#!/bin/bash

GOOS=linux 
GOARCH=amd64
go.exe get -d -v ./...
go.exe env -w GOOS=$GOOS
go.exe env -w GOARCH=$GOARCH
go.exe build -v ./cmd/tecnoalarm/main.go

Solution 8 - Go

> for people who need CGO enabled and cross-compile from another system

There is one docker solution golang-crossbuild

Here is one example to build linux/armv7 on Windows/MacOS

docker run -it --rm \
  -v $GOPATH/src/github.com/user/go-project:/go/src/github.com/user/go-project \
  -w /go/src/github.com/user/go-project \
  -e CGO_ENABLED=1 \
  docker.elastic.co/beats-dev/golang-crossbuild:1.16.4-armhf \
  --build-cmd "make build" \
  -p "linux/armv7"

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionljgwwView Question on Stackoverflow
Solution 1 - GoSnacOverflowView Answer on Stackoverflow
Solution 2 - GoljgwwView Answer on Stackoverflow
Solution 3 - GodocwhatView Answer on Stackoverflow
Solution 4 - GoTravis ReederView Answer on Stackoverflow
Solution 5 - GoDima KozhevinView Answer on Stackoverflow
Solution 6 - GoPouya SanooeiView Answer on Stackoverflow
Solution 7 - GoLuca GiulianiniView Answer on Stackoverflow
Solution 8 - GozangwView Answer on Stackoverflow