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.
Время на прочтение
9 мин
Количество просмотров 99K
Несмотря на то, что кроссплатформенность стала фактически стандартным атрибутом практически всех современных языков и библиотек, создавать по-настоящему кроссплатформенный продукт, всё равно было непросто. Компилируемые языки и сопутствующие библиотеки требовали сложной установки и настройки среды сборки и библиотек, а интерпретируемые — обязывали иметь или деплоить в составе необходимую версию интерпретатора. Есть немало проектов, пытающихся сделать этот процесс чуть более простым, но зачастую единственным решением оставалось устанавливать отдельный сервер и компилировать нативно.
В Go кросс-платформенность вышла на тот уровень, когда впервые можно смело отказаться от compile farms, специально настроенных dev-сред, виртуальных машин для сборки или chroot/docker-dev решений. И это ещё один серьезный game-changer, подробнее о котором я и хочу рассказать и показать на примерах
Поехали.
Как известно, в Go сознательно отказались от динамической линковки — по ряду причин, основная из которых очень схожа с обычным объяснением дизайна почти любого аспекта Go — «преимущества [динамической линковки] намного меньше её недостатков и сложности, которая она привносит в архитектуру». Что ж, главной причиной появления dynamic linking было желание экономить ресурсы — прежде всего диcковое пространство и память — которые сейчас достаточно дешевы, не только на серверах, но и в embedded-устройствах (коптеры, к примеру, несут на борту уже по 1-2 Гб RAM!). Вобщем, перечислять плюсы и минусы отдельного способа линковки — это потянет на отдельный пост, так что пока просто принимаем, как есть — в Go на выходе всегда имеем статический бинарник.
На данный момент для актуальной версии Go 1.4.1 реализована поддержка следующих платформ:
- Linux 2.61 и выше — amd64, 386, arm
- MacOS X 10.6 и выше — amd64, 386
- Windows XP и выше — amd64, 386
- FreeBSD 8 и выше — amd64, 386, arm
- NetBSD — amd64, 386, arm
- OpenBSD — amd64, 386
- DragonFly BSD — amd64, 386
- Plan 9 — amd64, 386
- Google Native Client — amd64p32, 386
- Android — arm
1 — официально поддерживаются ядра 2.6.23 и выше, но в реальности всё работает и на более ранних ядрах ветки 2.6 — к примеру немало людей используют Go на RHEL5/CentOS5 с 2.6.18.
В Go 1.5 ожидается поддержка iOS.
Еще примечательно, что изначально поддержки Windows в Go не было — команда маленькая, и
пачкать руки
заниматься имплементацией кода для Windows было некому, но благодаря тому, что проект открыли для open-source разработки — порт для Windows был очень быстро написан сторонними людьми и интегрирован в официальную кодовую базу.
Хотя описанные далее процессы будут абсолютно одинаковы для всех платформ (за исключеним, разве что, Android и Native Client (NaCl), для которых нужны лишние телодвижения), далее в статье будет по-умолчанию считаться, что вы используете одну из трех самых популярных десктопных платформ — Linux, MacOS X или Windows. Кроме того, для большей простоты я буду подразумевать, что мы пишем и используем исключительно Go-код, без необходимости линковаться с С-библиотеками (и, тем самым, без необходимости использовать cgo/gcc). Есть еще отдельный кейс — когда нужно использовать ряд функций из стандартной библиотеки, завязанных на cgo, но об этом я напишу отдельной главой в конце.
Подготовка toolchain
Первый шаг, который необходимо выполнить — это собрать toolchain для нужной платформы.
Переходим в директорию с исходным кодом Go (она же $GOROOT/src, она же всегда есть у вас на машине) и пересобираем под нужную платформу, скажем Windows/amd64:
cd $(go env GOROOT)/src
sudo GOOS=windows GOARCH=amd64 CGO_ENABLED=0 ./make.bash --no-clean
Процесс занимает на Macbook Air 2012 около 26 секунд. Скрипт make.bash — это стандартный скрипт сборки Go, которым бы вы инсталлировали Go, если бы ставили из исходников. Он собирает, собственно, Go, и всю стандартную библиотеку, только в этот раз — для платформы windows/amd64.
Также, по упомянутой выше причине, мы отключили поддержку CGO.
Значения GOOS и GOARCH
Таблица значений GOOS (если кто знает, как на Хабре сделать таблица в 50% ширины — подскажите):
OS | $GOOS |
---|---|
Linux | linux |
MacOS X | darwin |
Windows | windows |
FreeBSD | freebsd |
NetBSD | netbsd |
OpenBSD | openbsd |
DragonFly BSD | dragonfly |
Plan 9 | plan9 |
Native Client | nacl |
Android | android |
И GOARCH:
Architecture | $GOARCH |
---|---|
x386 | 386 |
AMD64 | amd64 |
AMD64 с 32-указателями | amd64p32 |
ARM | arm |
Пример 1. Веб-сервер, написанный и собранный в Linux для Windows
Напишем простенький веб-сервер, который в Go писать проще, чем в некоторых языках/библиотеках парсить командную строку.
package main
import (
"log"
"net/http"
)
func Handler(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello, world\n"))
}
func main() {
http.HandleFunc("/", Handler)
log.Println("Starting HTTP server on :1234")
log.Fatal(http.ListenAndServe(":1234", nil))
}
И соберем его для Windows 32- и 64-bit:
GOOS=windows GOARCH=386 go build -o http_example.exe
GOOS=windows GOARCH=amd64 go build -o http_example64.exe
Проверяем:
$ file http_example*.exe
http_example.exe: PE32 executable for MS Windows (console) Intel 80386 32-bit
http_example64.exe: PE32+ executable for MS Windows (console) Mono/.Net assembly
Думаю, не нужно говорить, что оба бинарника готовы к копированию на целевую Windows-систему и будут работать.
Пример 2. Кросс-компиляция под ARM для телефона Nokia N9
Сразу скажу, что сейчас я с embedded-девайсами плотно не работаю, поэтому могу какие-то детали не знать — так что постараюсь не углубляться в эту тему, но в целом за ситуацией с Go на embedded слежу. Вообще говоря, Go не позиционировался как язык для embedded-платформ, что, впрочем, не помешало народу активно начать его использовать в этой области. Возможно, причина в том, что embedded-индустрия сделала скачок вперед, и теперь «встраиваемое» устройство уже не означает критически малое количество ресурсов, а возможно компромиссы не в пользу экономии памяти в Go оказались гораздо менее ощутимыми на практике, но факт есть факт — для Go уже создано масса проектов вроде Gobot (robotics-фреймворк для целой кучи платформ — от Arduino, Raspberry PI и Beaglebone Back до LeapMotion, Pebble и ArDrone) или EMBD (фреймворк для работы с hobby-бордами), а PayPal уже пару лет использует Go в своем beacon-девайсе для беспроводных чекинов и платежей.
Для примера возьмем Nokia N9 (или N950, кому повезло) — и соберем вышеприведенный пример для него:
GOOS=linux GOARCH=arm go build -o http_example_arm
scp http_example_arm developer@192.168.2.16:/home/user/
Вот так просто, да.
Для ARM-платформ, на самом деле, может понадобиться еще указывать флаг GOARM, но тут, если версия по-умолчанию не подходит, бинарник на целевой платформе выдаст понятное сообщение, вроде такого:
runtime: this CPU has no floating point hardware, so it cannot
run this GOARM=7 binary. Recompile using GOARM=5.
Автоматизируем процесс
Казалось бы, что может быть проще указания одной переменной перед go build. Но есть ситуации, когда код нужно собирать и деплоить на разные платформы по 100 раз в день. Для таких задач есть несколько проектов, для автоматизации процессов подготовки toolchain-ов и, непосредственно, сборки кода под нужную платформу.
Gox
Ссылка: github.com/mitchellh/gox
Инсталляция и подготовка сразу всех возможных toolchain-ов:
go get github.com/mitchellh/gox
gox -build-toolchain
...
Теперь, вместо «go build», пишем «gox»:
$ gox
Number of parallel builds: 4
--> darwin/386: github.com/mitchellh/gox
--> darwin/amd64: github.com/mitchellh/gox
--> linux/386: github.com/mitchellh/gox
--> linux/amd64: github.com/mitchellh/gox
--> linux/arm: github.com/mitchellh/gox
--> freebsd/386: github.com/mitchellh/gox
--> freebsd/amd64: github.com/mitchellh/gox
--> openbsd/386: github.com/mitchellh/gox
--> openbsd/amd64: github.com/mitchellh/gox
--> windows/386: github.com/mitchellh/gox
--> windows/amd64: github.com/mitchellh/gox
--> freebsd/arm: github.com/mitchellh/gox
--> netbsd/386: github.com/mitchellh/gox
--> netbsd/amd64: github.com/mitchellh/gox
--> netbsd/arm: github.com/mitchellh/gox
--> plan9/386: github.com/mitchellh/gox
Можно указывать конкретный пакет или конкретную платформу:
gox -os="linux"
gox -osarch="linux/amd64"
gox github.com/divan/gorilla-xmlrpc/xml
Остальные аргументы командной строки идентичны go build. Достаточно интуитивно.
GoCX
GoCX — это один из самых известных врапперов вокруг фич кросс-компиляции, но с упором на пакаджинг (умеет делать .deb даже) и различные плюшки для автоматизированных сборок. Сам не пользовал, поэтому, кому интересно, смотрите сайт и документацию.
github.com/laher/goxc
Разбираемся с CGO
Если кто-то смотрел видео с конференции GopherCon 2014, которая проходила прошлой весной в Денвере, то, возможно, помнит выступление Alan Shreve «Build Your Developer Tools in Go» — и одну из вещей, которую он говорит достаточно категорично: «не используйте кросс-компиляцию, компилируйте нативно». Дальше идет объяснение — причина в Cgo. Если вам не нужно использовать cgo — все окей. И на самом деле, очень малая часть очень специфичного кода в Go нуждается в сторонних С-библиотеках. В чем же проблема?
Проблема в том, что некоторые функции стандартной библиотеки зависят от cgo. Тоесть, если мы собираем Go с CGO_ENABLED=0, они просто не будут доступны и на этапе компиляции мы получим ошибку. Несмотря на то, что тут есть очень удобный и красивый workaround, давайте разберемся, что же именно в стандартной библиотеке зависит от cgo.
К счастью, сделать это просто:
# cd $(go env GOROOT)/src/
# grep -re "^// +build.*[^\!]cgo" *
crypto/x509/root_cgo_darwin.go:// +build cgo
net/cgo_android.go:// +build cgo,!netgo
net/cgo_linux.go:// +build !android,cgo,!netgo
net/cgo_netbsd.go:// +build cgo,!netgo
net/cgo_openbsd.go:// +build cgo,!netgo
net/cgo_unix_test.go:// +build cgo,!netgo
os/user/lookup_unix.go:// +build cgo
runtime/crash_cgo_test.go:// +build cgo
Вкратце пройдемся по этим файлам:
- crypto/x509/root_cgo_darwin.go — имплементирует одну функцию для получения корневых X.509 сертификатов в MacOS X. Если вы не используете явно эту фичу — ничего страшного, без cgo у вас все будет работать.
- net/cgo_android/linux/netbsd/openbsd/cgo_unix_test.go — код необходимый для использования нативного DNS-резолвера в разных unix-ах. Чуть ниже подробности.
- os/user/lookup_unix.go — функции из пакета os/user — для получения информации о текущем юзере (uid, gid, username). Используется getpwuid_r() для чтения passwd-записей
- runtime/crash_cgo_test.go — файл с тестами для хендлинга крешей, ничего релевантного
Теперь подробнее про DNS-resolver.
Каждый файл из того списка (который скомпилируется только для своей платформы благодаря тегам // +build) содержит имплементацию единственной функции cgoAddrInfoFlags(), которая, в свою очередь, используется в cgoLookupIP(), которая, используется в dnsclient_unix.go, в котором мы находим функцию goLookupIP(), которая служит fallback-вариантом при отсутствии cgo-enabled кода, и тут же находим объяснение:
// goLookupIP is the native Go implementation of LookupIP.
// Used only if cgoLookupIP refuses to handle the request
// (that is, only if cgoLookupIP is the stub in cgo_stub.go).
// Normally we let cgo use the C library resolver instead of
// depending on our lookup code, so that Go and C get the same
// answers.
goLookupIP фактически резолвит только по Hosts-файлу и по DNS-протоколу, что для большинства систем — ок. Но могут быть проблемы, если в системе будут использоваться нестандартные методы резолвинга имён. Полагаю, что в 99% случаев, hosts и dns будут более, чем достаточно.
В сухом остатке имеем — если ваш код не использует С/С++-библиотеки через Cgo, и не использует следующие две вещи:
- проверку x.509 сертификатов, которая должна работать на MacOS X
- гарантированно получать системную информацию о текущем юзере
то на все заморочки с Cgo можно забить.
Первая часть (с X.509) на самом деле не такая уж редкая. Если я правильно понимаю — этот код нужен, если ваша программа использует стандартный net/http.StartAndListenTLS() — и вы используете реальные сертификаты, которые реально нужно проверять.
Поэтому вкратце о простом workaround вокруг этой темы — называется он gonative, и делает одну простую вещь — скачивает с официального сайта бинарные версии golang нужной версии для нужной платформы, в которой уже есть скомпилированные бинарники всех стандартных пакетов и, фактически, завершает процесс «собрать toolchain с cgo-кодом».
Всё что нужно сделать, это установить её (go get github.com/inconshreveable/gonative) и выполнить одну простую команду:
gonative
И дальше использовать стандартные процедуры кросскомпиляции, как и раньше, ручками или через gox/gocx.
Подробнее о gonative тут: inconshreveable.com/04-30-2014/cross-compiling-golang-programs-with-native-libraries
Практическое применение
Теперь о главном — применении на практике. Я использовал в продакшене пока только три схемы — «сборка на darwin/amd64 -> деплой на linux/386», «linux/amd64 -> linux/386» и «linux/amd64 -> windows/amd64». Это продукты, которые уже больше года полноценно работают. Третий случай (деплой на windows) тогда меня вообще застал врасплох — был сервер, успешно бегущий на Linux, и тут вдруг резко понадобилось его запускать на Windows. Причем «вот срочно надо». Вспоминая бессонные ночи опыта с кросс- — да что там кросс, просто с компиляцией Qt для деплоя на Windows — 60-секундный процесс «гуглим как это делается → сборка toolchain → перекомпиляция проекта → деплой на windows» — стал просто шоком, я тогда даже не поверил глазам.
Но тут возникает следующий момент — раз кросс-компиляция и деплой становятся такими простыми и быстрыми, появляется стимул все зависимости от файлов — будь-то конфиги, сертификаты или что угодно еще — встраивать в бинарник тоже. Впрочем, это достаточно простая задача, даже для сторонних библиотек, благодаря эффективному использованию io.Reader интерфейса и пакету go-bindata, но это уже тема для отдельной статьи.
Надеюсь, ничего из главного не упустил.
Но в целом это на самом деле очень существенная разница со всем предыдущим опытом кросс-сборки. Если честно, я до сих пор не привык к этой перемене. Больше не нужны виртуалки с настроенной dev-средой, не нужны докер-имиджи для сборки — да вообще dev-environment отпадает как таковой. Это слишком резкий game changer, чтобы так быстро привыкнуть.
Ссылки
dave.cheney.net/2012/09/08/an-introduction-to-cross-compilation-with-go
blog.hashbangbash.com/2014/04/linking-golang-statically
www.limitlessfx.com/cross-compile-golang-app-for-windows-from-linux.html
How do you build Go binaries that target operating systems and architectures other than your own? This is called cross-compiling, and it’s easy to do with Go.
Programs written in Go can easily be compiled for a wide variety of target operating systems such as Windows, macOS, and Linux by using the GOARCH
and GOOS
environmental variables. These represent the compilation architecture and the name of the target operating system respectively, and are set to your host compilation architecture (GOHOSTARCH
) and operating system (GOHOSTOS
) by default.
You can use the go env
command to view the values of these variables on your machine:
$ go env
...
GOARCH="amd64"
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
...
Compile for Windows
Here’s the command you need to run to compile your Go project for a 64-bit Windows machine:
$ GOOS=windows GOARCH=amd64 go build -o bin/app-amd64.exe app.go
In this scenario, GOOS
is windows, and GOARCH
is amd64
indicating a 64-bit architecture. If you need to support a 32-bit architecture, all you need to do is change GOARCH
to 386
.
$ GOOS=windows GOARCH=386 go build -o bin/app-386.exe app.go
Compile for macOS
The GOARCH
values for Windows are also valid for macOS, but in this case the required GOOS
value is darwin
:
# 64-bit
$ GOOS=darwin GOARCH=amd64 go build -o bin/app-amd64-darwin app.go
# 32-bit
$ GOOS=darwin GOARCH=386 go build -o bin/app-386-darwin app.go
Compile for Linux
To build your Go program for Linux, use linux
as the value of GOOS
and the appropriate GOARCH
value for your target CPU architecture:
# 64-bit
$ GOOS=linux GOARCH=amd64 go build -o bin/app-amd64-linux app.go
# 32-bit
$ GOOS=linux GOARCH=386 go build -o bin/app-386-linux app.go
Other operating systems and CPU architectures
Go supports a lot more OS and CPU architecture combinations than what I’ve described above, but these are the most used ones. If you need to compile for ARM, Android, Web Assembly, or other targets, please refer to the Go docs to see the combinations of GOOS
and GOARCH
that are available to you.
Thanks for reading, and happy coding!
- #golang
When go build
is issued on a Windows host a .exe binary is created. How to ensure that a Linux binary is created on a Windows host?
The following was tried, but did not solve the issue:
GOOS=linux;go build hello-world.go
asked Aug 6, 2017 at 19:07
1
You can easily set the target operating system and processor architecture using the environment variables GOOS and GOARCH respectively. So, as you want to build it for linux operating system, following command with above environment variables will do,
$ GOOS=linux GOARCH=amd64 go build -o hello main.go
Here is the list of all the supported operating system with which you can easily do cross compilation using Go lang.
answered Aug 13, 2017 at 20:18
mohan08pmohan08p
3602 silver badges7 bronze badges
It seems that docker build
opens a new shell and export
is needed. The following command created a Linux binary:
export GOOS=linux; go build hello-world.go
answered Aug 6, 2017 at 20:05
030030
13.1k15 gold badges68 silver badges170 bronze badges
Windows also has a one-liner solution, just a bit uglier than the linux version. Any of the below lines will do the job:
cmd /C "SET GOOS=linux&& SET GOARCH=amd64&& go build main.go"
cmd /C "SET "GOOS=linux" && SET "GOARCH=amd64" && go build main.go"
Be careful, if you just write ...SET GOOS=linux && SET ...
then you will get an error message
cmd/go: unsupported GOOS/GOARCH pair linux /amd64
because there will be an extra space after the value linux
. In order to avoid this, use either the condensed form linux&&
or the other version with quotation marks.
answered Feb 21, 2020 at 13:58
Этой заметкой открываю новую рублику по программированию на Go Lang. Один из первых вопросов, которые пришлось решить — как пользователю Windows 10 скомпилировать исполняемый файл для Linux сервера? Процесс сборки бинарного файла на системе одного типа для системы другого типа называется кросскомпиляцией. Ответ достаточно прост, сначала нужно задать константы:
set GOARCH=amd64
set GOOS=linux
Теперь можно компилировать:
go build turboapp.go
Через несколько секунд получаем файл turboapp и закидываем его на сервер, и устанавливаем права доступа:
chmod +x turboapp
Всё, теперь можно запускать!
Данное решение работает для такой конфигурации сервера:
Linux server.developer 2.6.32-696.16.1.el6.x86_64 #1 SMP Wed Nov 15 16:51:15 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
На windows системе установлен:
go version go1.10 windows/amd64
Для компиляции под другие операционные системы и архитектуры используйте эти таблицы:
OS | $GOOS |
---|---|
Linux | linux |
MacOS X | darwin |
Windows | windows |
FreeBSD | freebsd |
NetBSD | netbsd |
OpenBSD | openbsd |
DragonFly BSD | dragonfly |
Plan 9 | plan9 |
Native Client | nacl |
Android | android |
Architecture | $GOARCH |
---|---|
x386 | 386 |
AMD64 | amd64 |
AMD64 с 32-указателями | amd64p32 |
ARM | arm |
Post Views:
2 906