Cross compile Auf OSX gehen?

142

Ich versuche, eine Go-App unter OSX zu kompilieren, um Binärdateien für Windows und Linux zu erstellen. Ich habe alles gelesen, was ich im Internet finden konnte. Das nächste Beispiel, das ich gefunden habe, wurde veröffentlicht (abgesehen von vielen unvollendeten Diskussionen auf der Go-Nuts-Mailingliste):

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

Bei meiner Installation funktioniert es jedoch nicht. Ich bin 1.0.2 gegangen. Da 1.0.2 ziemlich neu ist, scheint es mir, dass alle obigen Beispiele nicht für diese Version gelten.

Es wurde versucht, ./make.bash --no-cleanmit ENV-Variablen zu tun, die auf 386 / Windows eingestellt sind, aber es wird für meine Installation erstellt, wobei die darwin/amd64in ENV festgelegten Einstellungen, die davon ausgehen, dass ein anderer Compiler erstellt wird, vollständig ignoriert werden.

Irgendwelche Ratschläge, wie es gemacht werden kann (wenn es überhaupt gemacht werden kann)?

ljgww
quelle
Parallel dazu habe ich die gleiche Frage auf der Golang-Nuts-Mailingliste gestellt und mit der freundlichen Hilfe und Geduld der Leute dort wurde das endgültige Rezept gekocht ... dies ist der Diskussionsthread: groups.google.com/forum/?fromgroups=# ! topic / golang-nut /… es gab mehrere Schritte und Schlussfolgerungen, ich habe mich auf dem Weg geirrt, aber jetzt scheint das Rezept ziemlich einfach zu sein - 3 Schritte und einige Iterationen.
ljgww
Jetzt, wo ich die Zusammenfassung sudodurcharbeite, frage ich mich, warum ENV-Vars keine korrekte Kompilierung ausgelöst haben - vielleicht weil ich es getan habe (wahrscheinlich würde ich beim Sudoing ein anderes Unix-ENV erhalten, sodass GOOS & GOARCH nicht verfügbar wären, wenn sie nicht ausgeführt würden inline)
ljgww
re: jdi - Ich habe nur versucht, meine "mockup" go-App zu kompilieren, um bin / lin-Binärdateien auf dem Mac zu erstellen, aber dazu musste ich go für jede Kombination aus Plattform / Prozessor selbst erstellen. (kann meine eigene Frage noch nicht beantworten - ich habe hier nicht genug Ruf)
ljgww
1
Haben Sie genau das eingegeben, was im Beispiel steht? CGO_ENABLED=0 GOOS=windows GOARCH=amd64 ./make.bash- Wenn Sie versucht haben, es auf mehr als eine Zeile aufzuteilen, wird die Umgebungsvariable nicht exportiert, was den Symptomen entspricht
Nick Craig-Wood
Stellen Sie sicher, dass Sie die Host- und Zielarchitektur nicht verwechseln. Diese Ausgabe sollte angezeigt werden: "# Erstellen von Compilern und Go-Bootstrap-Tool für Host, Darwin / AMD64." "# Erstellen von Paketen und Befehlen für den Host darwin / amd64." "# Erstellen von Paketen und Befehlen für Windows / 386."
Sam

Antworten:

157

Mit Go 1.5 scheinen sie den Cross-Compilation-Prozess verbessert zu haben, was bedeutet, dass er jetzt eingebaut ist. Kein ./make.bash-ing oder brew-ing erforderlich. Der Prozess wird hier beschrieben , aber für die TLDR-Benutzer (wie mich) da draußen: Sie setzen einfach die GOOSund die GOARCHUmgebungsvariablen und führen den go-Build aus.

Machen Sie für die noch fauleren Copy-Paster (wie mich) da draußen so etwas, wenn Sie auf einem * nix-System sind:

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

Sie haben sogar den envTrick gelernt , mit dem Sie Umgebungsvariablen nur für diesen Befehl völlig kostenlos festlegen können.

leondepeon
quelle
4
Der envBefehl führt nur diesen Aufruf in einer benutzerdefinierten Umgebung aus und setzt ihn zurück, nachdem er ausgeführt wurde. Zum Beispiel ausführen export GOOS=windows, dann den Befehl mit oder ohne envund echo $GOOSdanach. Mit dem wurde envdie GOOS nicht verändert.
Leondepeon
3
das gleiche gilt (zumindest in Bash) ohne env. Ich bin export GOOS=windowsdann GOOS=linux bash -c 'echo "GOOS: $GOOS"'dann gelaufen echo "GOOS: $GOOS". Bietet enveine bessere Kompatibilität mit anderen Shell-Dialekten oder mit anderen Plattformen? Wenn nicht, erscheint es hier überflüssig.
Davidchambers
2
@davidchambers In BASH sind sie gleichwertig. Während in einer anderen Shell, z. B. der FISH-Shell, diese nicht unterstützt wird FOO=bar cmd, müssen Sie sie verwenden env FOO=bar cmd. Daher denke ich, dass der größte Vorteil die env FOO=bar cmdKompatibilität ist.
PickBoy
1
Unglaubliche Antwort hier. Sie haben mein Problem gelöst, mir einen neuen Trick beigebracht und mich zum Lachen gebracht.
T Blank
1
Tolle Antwort, danke! Um für Heroku (Intel x86) zu kompilieren, habe ich die Zeile leicht modifiziert env GOOS=linux GOARCH=386 go build -v github.com/path/to/your/appund sie funktioniert wie ein Champion
Ira Herman
136

Dank der freundlichen und geduldigen Hilfe von Golang-Nüssen lautet das Rezept wie folgt:

1) Man muss den Go-Compiler für verschiedene Zielplattformen und -architekturen kompilieren. Dies erfolgt aus dem src-Ordner in der go-Installation. In meinem Fall befindet sich die Go-Installation in. Um /usr/local/goeinen Compiler zu kompilieren, müssen Sie das makeDienstprogramm ausgeben . Bevor Sie dies tun, müssen Sie einige Einschränkungen kennen.

Beim Cross-Compilieren tritt ein Problem mit der CGO-Bibliothek auf, sodass die CGO-Bibliothek deaktiviert werden muss.

Das Kompilieren erfolgt durch Ändern des Speicherorts in das Quellverzeichnis, da das Kompilieren in diesem Ordner erfolgen muss

cd /usr/local/go/src

Kompilieren Sie dann den Go-Compiler:

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

Sie müssen diesen Schritt für jedes Betriebssystem und jede Architektur wiederholen, die Sie kompilieren möchten, indem Sie die Parameter GOOS und GOARCH ändern.

Wenn Sie wie ich im Benutzermodus arbeiten, wird sudo benötigt, da sich der Go-Compiler im Systemverzeichnis befindet. Andernfalls müssen Sie als Superuser angemeldet sein. Auf einem Mac müssen Sie möglicherweise den SU-Zugriff aktivieren / konfigurieren (er ist standardmäßig nicht verfügbar). Wenn Sie jedoch die Installation von Go geschafft haben, haben Sie möglicherweise bereits Root-Zugriff.

2) Sobald Sie alle Cross-Compiler erstellt haben, können Sie Ihre Anwendung problemlos Cross-Compilieren, indem Sie beispielsweise die folgenden Einstellungen verwenden:

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

Ändern Sie die GOOS und GOARCH in Ziele, die Sie erstellen möchten.

Wenn Sie Probleme mit CGO haben, geben Sie CGO_ENABLED = 0 in die Befehlszeile ein. Beachten Sie auch, dass Binärdateien für Linux und Mac keine Erweiterung haben, sodass Sie eine Erweiterung hinzufügen können, um unterschiedliche Dateien zu haben. -o Schalteranweisungen Gehen Sie, um die Ausgabedatei ähnlich wie bei alten Compilern für c / c ++ zu machen. Daher kann der oben verwendete appname.linux eine beliebige andere Erweiterung sein.

ljgww
quelle
Was mich anfangs verwirrt hat, ist, dass im ersten Teil der Kompilierung make sagt: # Building compilers and Go bootstrap tool for host, darwin/amd64aber später endet es tatsächlich als: --- Installed Go for windows/386 in /usr/local/go Installed commands in /usr/local/go/binman soll also eher das Ende als den Beginn des Kompilierens des Compilers beobachten.
ljgww
Alles begann mit dem Versuch zu tun: $ GOARCH=386 GOOS=linux go build app.gound Fehler zu bekommen # runtime /usr/local/go/src/pkg/runtime/extern.go:137: undefined: theGoos /usr/local/go/src/pkg/runtime/extern.go:137: cannot use theGoos as type string in const initializer
ljgww
30
Das Go-Paket in Homebrew enthält die Option "--cross-compile-all", mit der automatisch alle Cross-Compiler erstellt werden.
Nimrodm
8
toller Tipp @nimrodm! Um Ihre Go-Installation neu zu kompilieren, müssen Siebrew reinstall go --cross-compile-all
linqu
1
@ljgww 'sudo' hat ENV nicht konfiguriert. Am Ende benutzte ich chown auf / usr / local / go / pkg / linux_amd64 /
Nuno Silva
63

Wenn Sie Homebrew unter OS X verwenden, haben Sie eine einfachere Lösung:

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

oder..

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

Verwenden reinstallSie diese Option, wenn Sie bereits goinstalliert haben.

docwhat
quelle
3
Die aktualisierten Switches sind: - Cross-Compile-All Erstellen Sie die Cross-Compiler- und Laufzeitunterstützung für alle unterstützten Plattformen. - Cross-Compile-Common Erstellen Sie die Cross-Compiler- und Laufzeitunterstützung für Darwin, Linux und Windows.
Chip Tol
3
--cross-compile-allist jetzt--with-cc-all
Gianebao
@ sheeks06 - behoben. Vielen Dank!
docwhat
1
Diese Flaggen existieren nicht mehr, soweit ich das beurteilen kann. Die einzige relevante Option, die ich sehe, ist --without-cgo :(
rdegges
5
Seit Go 1.5 gibt es keine separaten Cross-Compiler, Sie verwenden nur die Flags jetzt tip.golang.org/doc/go1.5#compiler_and_tools
Chuckus
24

Sie können dies ziemlich einfach mit Docker tun, sodass keine zusätzlichen Bibliotheken erforderlich sind. Führen Sie einfach diesen Befehl aus:

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
'

Weitere Details finden Sie in diesem Beitrag: https://medium.com/iron-io-blog/how-to-cross-compile-go-programs-using-docker-beaa102a316d

Travis Reeder
quelle
1
Warum sollte jemand Docker installieren wollen, um dies zu tun, wenn er nur eine Shell-Schleife durchführen env GOOS=x GOARCH=y go install something/...und die entsprechenden Binärdateien unter erhalten könnte $GOPATH/bin/$GOOS_$GOARCH? Übrigens unterstützt Go mehr als die drei von Ihnen aufgelisteten Betriebssysteme. Warum keine Liebe zu den BSDs?
Dave C
8
Sie würden Docker nicht nur zu diesem Zweck installieren, aber wenn Sie es haben, ist dies einfacher und sauberer als die Alternativen.
Travis Reeder
7

Das Erstellen von ausführbaren Dateien für viele Plattformen kann etwas langwierig sein. Ich empfehle daher, ein Skript zu verwenden:

#!/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

Ich habe dieses Skript nur unter OSX überprüft

Kern - go-executable-build.sh

Dima Kozhevin
quelle
Genau das, wonach ich gesucht habe ... Ich habe es angedockt :) gist.github.com/marcellodesales/…
Marcello de Sales
6

Für Benutzer , die CGO- fähig benötigen und Cross-Compilieren aus OSX-Targeting-Fenstern benötigen

Ich musste CGO beim Kompilieren für Windows von meinem Mac aktivieren, da ich https://github.com/mattn/go-sqlite3 importiert hatte und es brauchte. Das Kompilieren nach anderen Antworten gab mir und Fehler:

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

Wenn du wie ich bist und mit CGO kompilieren musst. Das habe ich getan:

1.Wir werden für Windows mit einer CGO-abhängigen Bibliothek eine Cross-Kompilierung durchführen. Zuerst brauchen wir einen Cross-Compiler wie installiertmingw-w64

brew install mingw-w64

Dies wird es wahrscheinlich hier installieren /usr/local/opt/mingw-w64/bin/.

2. Genau wie bei anderen Antworten müssen wir jetzt zuerst unseren Windows-Bogen zu unserer Go-Compiler-Toolchain hinzufügen. Das Kompilieren eines Compilers benötigt einen Compiler (seltsamer Satz). Das Kompilieren des go-Compilers benötigt einen separaten vorgefertigten Compiler. Wir können eine vorgefertigte Binärdatei herunterladen oder aus dem Quellcode in einem Ordner erstellen, z. B.: ~/Documents/go Jetzt können wir unseren Go-Compiler gemäß der Top-Antwort verbessern, diesmal jedoch mit CGO_ENABLED=1und unserem separaten vorgefertigten Compiler GOROOT_BOOTSTRAP(Pooya ist mein Benutzername):

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. Verwenden Sie jetzt beim Kompilieren unseres Go-Codes mingwdas Kompilieren unserer Go-Datei-Targeting-Fenster mit aktiviertem CGO:

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
Pouya Sanooei
quelle