Cross compiling from Windows to other OSs - go

I read this and this about this activity, and the action mentioned as:
% env GOOS=darwin GOARCH=386 go build hello.go
// or
% env GOOS=linux GOARCH=arm GOARM=7 go build hello.go
// and so on
But in Windows there is no command named env, I got the below:
'env' is not recognized as an internal or external command,
operable program or batch file.

On windows powershell you should be able to do:
$env:GOOS = "linux"
$env:GOARCH = "arm"
$env:GOARM = "7"
go build hello.go

To check supported compilation tools: go tool dist list
Cross compiling not working with cgo, i.e. not working with any file has import "C"
At Powershell
# For ARM
$env:GOOS = "linux"
$env:GOARCH = "arm"
$env:GOARM = "7"
go build -o main main.go
# For darwin
$env:GOOS = "darwin"
$env:GOARCH = "amd64"
go build -o main.dmg main.go
# same for others
$env:GOOS = "windows"
$env:GOARCH = "amd64"
go build -o main.exe main.go
At CMD Command Prompt:
set GOOS=darwin
set GOARCH=amd64
go build -o main.dmg main.go
To do it in Linux or Mac and compiling to Win
GOOS=windows GOARCH=amd64 go build -o main.exe main.go
Cross compiling will silently rebuild most of standard library, and for this reason will be quite slow. To speed-up the process, you can install all the standard packages required for cross compiling on your system, for example to install at Linux/Mac the cross compiling requirements for windows-amd64 use:
GOOS=windows GOARCH=amd64 go install
Similar for any other OS you need to cross compile for it at Windows

Related

Cross-compiling for linux arm/7: clang error: argument unused during compilation '-marm'

What is the reason and how to solve it? Please..
cmd : CGO_ENABLED=1 GOOS=linux GOARCH=arm GOARM=7 go build
output:
# runtime/cgo
clang: error: argument unused during compilation: '-marm' [-Werror,-Wunused-command-line-argument]
OS: macOS Big Sur
Golang verson: go1.17 darwin/amd64
Read the fine manual:
When cross-compiling, you must specify a C cross-compiler for cgo to use. You can do this by setting the generic CC_FOR_TARGET or the more specific CC_FOR_${GOOS}_${GOARCH} (for example, CC_FOR_linux_arm) environment variable when building the toolchain using make.bash, or you can set the CC environment variable any time you run the go tool.
So you need to specify the cross-compiler for CGo, e.g. like so:
 CC=arm-linux-gnueabihf-gcc CGO_ENABLED=1 GOOS=linux GOARCH=arm GOARM=7 go build
For C++ code also add CXX=arm-linux-gnueabihf-g++.
You'll need to have gcc-arm-linux-gnueabihf and libc6-dev-armhf-cross packages installed for the above to work (on Linux, don't know about Mac).

Golang c-archive with libc instead of glibc

Is it possible?
I have the following Go function I'd like to call from a C program:
// package name: test
package main
import "C"
//export Start
func Start() {
println("Hello world")
}
func main() {
}
I'm using the following command to build the archive
go build -buildmode=c-archive -o test.a main.go
Using gcc I can get this C program working:
#include <stdio.h>
#include "test.h"
int main() {
Start();
return 0;
}
I'm using the following command to build the executable:
gcc main.c sdlgotest.a -o main -lpthread
This all works fine for amd64, but I'd like to use this archive in a aarch64 targed development environment (using libtransistor)
libtransistor build system uses LLVM but it has it's own set of standard includes (libc, etc.) and it doesn't use glibc.
So when I'm trying to get libtransistor to link my archive I get the following errors:
/usr/lib/llvm-5.0/bin/ld.lld: error: undefined symbol: stderr
>>> referenced by gcc_libinit.c:29
>>> 000006.o:(x_cgo_sys_thread_create) in archive ./sdlgotest.a
/usr/lib/llvm-5.0/bin/ld.lld: error: undefined symbol: stderr
>>> referenced by gcc_libinit.c:29
>>> 000006.o:(x_cgo_sys_thread_create) in archive ./sdlgotest.a
libtransistor by the way is compiling the code with flags like this:
-nostdlib -nostdlibinc -isystem /opt/libtransistor/include/
So I guess the problem is that the linker can't resolve those glibc symbols.
Is there a way to compile the Go runtime without those glibc symbols so I can use the archive like I intend to? (without relying on GCC toolchain or glibc)
From the docs:
The default C and C++ compilers may be changed by the CC and CXX environment variables, respectively; those environment variables may include command line options.
So I'd try something like
$ CC=clang go build -buildmode=c-archive -o test.a main.go
and see what happens.
Run go env and see the list of env parameters set to go. You can change certain parameters based on what you need.
Following are some of the samples that I have used to build a shared dll from go program.
GOARCH=386 GOOS=windows CGO_ENABLED=1 GOPATH=`pwd` CC=i686-w64-mingw32-gcc go build -o go-shared-lib.dll -buildmode=c-shared go-shared-libs
GOARCH=amd64 GOOS=windows CGO_ENABLED=1 GOPATH=`pwd` CC=x86_64-w64-mingw32-gcc go build -o go-shared-lib.dll -buildmode=c-shared go-shared-libs

Go - Windows to Linux [duplicate]

I've installed Go 1.2 on a Windows machine, wrote up a dummy program and set the environment variables GOARCH and GOOS to "AMD64" and "linux" respectively.
When i issue the "go build" command, i receive an error:
go build runtime: linux/amd64 must be bootstrapped using make.bat
What does this mean?
It tells you it needs all tools built before you can use them.
If your windows GOARCH is amd64, then you could "build" all required tools by running this small batch programs:
set GOARCH=amd64
set GOOS=linux
go tool dist install -v pkg/runtime
go install -v -a std
If that succeeds then you should be able to do what you've described (just use amd64, not AMD64 - it is case sensitive).
If your windows GOARCH is 386, then you would need to build your 386 tools first. You would need to download mingw gcc for that. Do what user2714852 said.
Here https://golang.org/wiki/WindowsCrossCompiling are similar instructions for linux, perhaps you find them helpful.
Alex
I was having some major problems with building for linux from windows, At the end of the day, it was fairly simple. I would comment on Alex's post, but I can not as I am a stackoverflow newb.
As alex said, set the environment variables. This must be done as administrator (eg right click the "command prompt" or "Powershell" shortcut and click "Run as Administrator")
set GOARCH=amd64
set GOOS=linux
If you use Powershell, use
$Env:GOOS = "linux"; $Env:GOARCH = "amd64"
If you dont do it as administrator, the variables wont take effect and you will just be building it for the OS & Architecture you are on at the moment.
I found its always good to check your go environment vars by running go env, which gives you the list of current go environment variables
go env
set GOARCH=amd64
set GOBIN=
set GOEXE=
set GOHOSTARCH=amd64
set GOHOSTOS=windows
set GOOS=linux
set GOPATH=T:\Projects\gopath
set GORACE=
set GOROOT=C:\Go
set GOTOOLDIR=C:\Go\pkg\tool\windows_amd64
set GCCGO=gccgo
set CC=gcc
set GOGCCFLAGS=-fPIC -m64 -fmessage-length=0
set CXX=g++
set CGO_ENABLED=0
set PKG_CONFIG=pkg-config
set CGO_CFLAGS=-g -O2
set CGO_CPPFLAGS=
set CGO_CXXFLAGS=-g -O2
set CGO_FFLAGS=-g -O2
set CGO_LDFLAGS=-g -O2
Make sure the GOOS & GOARCH are set to the values you specified earlier.
If thats all good, you should be able to navigate to the directory containing your go code, and from the command line run:
go build
Which will build the package for the system and the architecure that are set in the environment variables.
I encountered some other issues once I finally figured this out, but that is another matter not related to this issue.
To set the PowerShell environment variables use (no admin mode required):
$env:GOOS = "linux"
Than build your programm go build
The changed environment variable is only pesent in the current PowerShell window. Everything will be resetted when you reopen the window.
To cross-compile Go, fist you need to be able to build Go from the source code. To do that, it looks like you need to install MinGW to get gcc and other tools. Help on that is at https://code.google.com/p/go-wiki/wiki/WindowsBuild.
From there, here's how it goes if it's like Linux cross-compiling:
First cd to your your go\src directory. If you're not sure where that is, type go env and you'll see a line like GOROOT="\some\dir\" in the output; just do cd \some\dir\src\
Then, with GOOS=linux and GOARCH=amd64 set, type .\make.bat, which will build a version of the Go compiler, etc. targeting Linux. Then you shouldn't get this error anymore.
If you using docker, you can build a docker image for linux builts. For example:
First of all, you can prepare a DockerFile as follows:
FROM golang:1.15-alpine3.12 as builder
RUN mkdir /go/src/hello
WORKDIR /go/src/hello
#install nano, zip and git
RUN apk add nano zip git
COPY ./ ./
#build main
RUN GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o main
#zip main
RUN zip main.zip main
Than you can build an image with docker build -t yourname/hello . After that have to export your zip file from this image:
First, use the image as a container with the command docker run -it yourname / hello.
Second, open a new terminal and run the docker ps to view the Container IDs.
And finally, run the command docker cp YOUR_WORKING_CONTAINER_ID:/go/src/hello/main.zip . to export the zip file.
This can be a long way, but it will allow you to build using docker without being dependent on the platform. Below is an example developed by me for using a docker image for updating golang lambda function (via aws-cli).
To build a program that is written by you, you can build it in a single command.
env GOOS=`target-OS` GOARCH=`target-architecture` go build .
PS: Don't miss out the . (You have to be in the program directory)
Replace target-OS and target-architecture from the list below
GOOS - Target Operating System
GOARCH - Target Architecture
android
arm
darwin
386
darwin
amd64
darwin
arm
darwin
arm64
dragonfly
amd64
freebsd
386
freebsd
amd64
freebsd
arm
linux
386
linux
amd64
linux
arm
linux
arm64
linux
ppc64
linux
ppc64le
linux
mips
linux
mipsle
linux
mips64
linux
mips64le
netbsd
386
netbsd
amd64
netbsd
arm
openbsd
386
openbsd
amd64
openbsd
arm
plan9
386
plan9
amd64
solaris
amd64
windows
386
windows
amd64
Example: For a windows system with amd64 architecture we would use
env GOOS=windows GOARCH=amd64 go build .
Build from other source code

How to cross compile from Windows to Linux?

I've installed Go 1.2 on a Windows machine, wrote up a dummy program and set the environment variables GOARCH and GOOS to "AMD64" and "linux" respectively.
When i issue the "go build" command, i receive an error:
go build runtime: linux/amd64 must be bootstrapped using make.bat
What does this mean?
It tells you it needs all tools built before you can use them.
If your windows GOARCH is amd64, then you could "build" all required tools by running this small batch programs:
set GOARCH=amd64
set GOOS=linux
go tool dist install -v pkg/runtime
go install -v -a std
If that succeeds then you should be able to do what you've described (just use amd64, not AMD64 - it is case sensitive).
If your windows GOARCH is 386, then you would need to build your 386 tools first. You would need to download mingw gcc for that. Do what user2714852 said.
Here https://golang.org/wiki/WindowsCrossCompiling are similar instructions for linux, perhaps you find them helpful.
Alex
I was having some major problems with building for linux from windows, At the end of the day, it was fairly simple. I would comment on Alex's post, but I can not as I am a stackoverflow newb.
As alex said, set the environment variables. This must be done as administrator (eg right click the "command prompt" or "Powershell" shortcut and click "Run as Administrator")
set GOARCH=amd64
set GOOS=linux
If you use Powershell, use
$Env:GOOS = "linux"; $Env:GOARCH = "amd64"
If you dont do it as administrator, the variables wont take effect and you will just be building it for the OS & Architecture you are on at the moment.
I found its always good to check your go environment vars by running go env, which gives you the list of current go environment variables
go env
set GOARCH=amd64
set GOBIN=
set GOEXE=
set GOHOSTARCH=amd64
set GOHOSTOS=windows
set GOOS=linux
set GOPATH=T:\Projects\gopath
set GORACE=
set GOROOT=C:\Go
set GOTOOLDIR=C:\Go\pkg\tool\windows_amd64
set GCCGO=gccgo
set CC=gcc
set GOGCCFLAGS=-fPIC -m64 -fmessage-length=0
set CXX=g++
set CGO_ENABLED=0
set PKG_CONFIG=pkg-config
set CGO_CFLAGS=-g -O2
set CGO_CPPFLAGS=
set CGO_CXXFLAGS=-g -O2
set CGO_FFLAGS=-g -O2
set CGO_LDFLAGS=-g -O2
Make sure the GOOS & GOARCH are set to the values you specified earlier.
If thats all good, you should be able to navigate to the directory containing your go code, and from the command line run:
go build
Which will build the package for the system and the architecure that are set in the environment variables.
I encountered some other issues once I finally figured this out, but that is another matter not related to this issue.
To set the PowerShell environment variables use (no admin mode required):
$env:GOOS = "linux"
Than build your programm go build
The changed environment variable is only pesent in the current PowerShell window. Everything will be resetted when you reopen the window.
To cross-compile Go, fist you need to be able to build Go from the source code. To do that, it looks like you need to install MinGW to get gcc and other tools. Help on that is at https://code.google.com/p/go-wiki/wiki/WindowsBuild.
From there, here's how it goes if it's like Linux cross-compiling:
First cd to your your go\src directory. If you're not sure where that is, type go env and you'll see a line like GOROOT="\some\dir\" in the output; just do cd \some\dir\src\
Then, with GOOS=linux and GOARCH=amd64 set, type .\make.bat, which will build a version of the Go compiler, etc. targeting Linux. Then you shouldn't get this error anymore.
If you using docker, you can build a docker image for linux builts. For example:
First of all, you can prepare a DockerFile as follows:
FROM golang:1.15-alpine3.12 as builder
RUN mkdir /go/src/hello
WORKDIR /go/src/hello
#install nano, zip and git
RUN apk add nano zip git
COPY ./ ./
#build main
RUN GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o main
#zip main
RUN zip main.zip main
Than you can build an image with docker build -t yourname/hello . After that have to export your zip file from this image:
First, use the image as a container with the command docker run -it yourname / hello.
Second, open a new terminal and run the docker ps to view the Container IDs.
And finally, run the command docker cp YOUR_WORKING_CONTAINER_ID:/go/src/hello/main.zip . to export the zip file.
This can be a long way, but it will allow you to build using docker without being dependent on the platform. Below is an example developed by me for using a docker image for updating golang lambda function (via aws-cli).
To build a program that is written by you, you can build it in a single command.
env GOOS=`target-OS` GOARCH=`target-architecture` go build .
PS: Don't miss out the . (You have to be in the program directory)
Replace target-OS and target-architecture from the list below
GOOS - Target Operating System
GOARCH - Target Architecture
android
arm
darwin
386
darwin
amd64
darwin
arm
darwin
arm64
dragonfly
amd64
freebsd
386
freebsd
amd64
freebsd
arm
linux
386
linux
amd64
linux
arm
linux
arm64
linux
ppc64
linux
ppc64le
linux
mips
linux
mipsle
linux
mips64
linux
mips64le
netbsd
386
netbsd
amd64
netbsd
arm
openbsd
386
openbsd
amd64
openbsd
arm
plan9
386
plan9
amd64
solaris
amd64
windows
386
windows
amd64
Example: For a windows system with amd64 architecture we would use
env GOOS=windows GOARCH=amd64 go build .
Build from other source code

Cross compile Go on OSX?

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)?
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.
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.
2) 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.
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.
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
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
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
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
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"

Resources