Compilation croisée Allez sur OSX?

142

J'essaie de compiler une application go sur OSX pour créer des binaires pour Windows et Linux. J'ai lu tout ce que j'ai pu trouver sur le net. L'exemple le plus proche que j'ai trouvé a été publié sur (à part de nombreuses discussions inachevées sur la liste de diffusion go-nut):

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

pourtant cela ne fonctionne pas sur mon installation. J'ai aller 1.0.2. Comme la 1.0.2 est assez récente, il me semble que tous les exemples ci-dessus ne s'appliquent pas à cette version.

J'ai essayé de faire ./make.bash --no-cleanavec ENV vars réglé sur 386 / windows, il construit bien, mais il construit pour mon installation qui est darwin/amd64et ignore complètement ce qui est défini dans ENV qui suppose de construire un compilateur différent.

Y a-t-il des conseils sur la façon dont cela peut être fait (si cela peut être fait du tout)?

ljgww
la source
Parallèlement à cela, j'ai posé la même question sur la liste de diffusion de golang-nut, et avec l'aimable aide et la patience des gens, la recette finale a été préparée ... voici le fil de discussion: groups.google.com/forum/?fromgroups=# ! topic / golang-nut /… il y avait plusieurs étapes et conclusions, je me suis trompé en chemin, mais maintenant la recette semble assez simple - 3 étapes et quelques itérations.
ljgww
maintenant que je suis en train de récapituler, je me demande pourquoi les variables ENV n'ont pas déclenché la compilation correcte - peut-être parce que je l'ai fait sudo(j'aurais probablement un autre ENV unix lors du sudo-ing, donc GOOS & GOARCH ne seraient pas disponibles s'ils ne sont pas faits inline)
ljgww
re: jdi - J'essayais juste de compiler mon application go "maquette" pour les binaires win / lin sur mac, mais, pour ce faire, j'ai dû construire go lui-même pour chaque combinaison plate-forme / processeur. (Je ne peux pas encore répondre à ma propre question - n'ayant pas assez de réputation ici)
ljgww
1
Avez-vous tapé exactement ce qu'il a dit dans l'exemple? CGO_ENABLED=0 GOOS=windows GOARCH=amd64 ./make.bash- si vous avez tenté de le diviser sur plus d'une ligne, la variable d'environnement ne sera pas exportée, ce qui correspond aux symptômes
Nick Craig-Wood
Assurez-vous de ne pas confondre architecture hôte et cible. Vous devriez voir cette sortie: "# Construire des compilateurs et un outil de démarrage Go pour l'hôte, darwin / amd64." "# Construction de packages et de commandes pour l'hôte, darwin / amd64." "# Construction de packages et de commandes pour windows / 386."
Sam

Réponses:

157

Avec Go 1.5, ils semblent avoir amélioré le processus de compilation croisée, ce qui signifie qu'il est désormais intégré. Aucun ./make.bash-ing ou brew-ing requis. Le processus est décrit ici mais pour les tldr-ers (comme moi) là - bas: vous définissez simplement les GOOSet les GOARCHvariables d'environnement et éxecuter la construction vont.

Pour les copieurs encore plus paresseux (comme moi), faites quelque chose comme ceci si vous êtes sur un système * nix:

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

Vous avez même appris l' envastuce, qui vous permet de définir des variables d'environnement uniquement pour cette commande, de manière totalement gratuite.

Léondepeon
la source
4
La envcommande exécute uniquement cet appel dans un environnement personnalisé et le «réinitialise» une fois terminé. Par exemple, exécutez export GOOS=windows, puis la commande avec ou sans envet echo $GOOSaprès. Avec le envGOOS n'a pas été changé.
leondepeon
3
la même chose est vraie (au moins dans Bash) sans env. J'ai couru export GOOS=windowsalors GOOS=linux bash -c 'echo "GOOS: $GOOS"'alors echo "GOOS: $GOOS". Fournit-il envune plus grande compatibilité avec d'autres dialectes shell ou avec d'autres plates-formes? Sinon, cela semble superflu ici.
davidchambers
2
@davidchambers En BASH, ils sont équivalents. Alors que dans un autre shell, par exemple le shell FISH, il ne prend pas en charge FOO=bar cmd, vous devez donc utiliser env FOO=bar cmd. Je pense donc que le plus grand avantage à utiliser env FOO=bar cmdest la compatibilité.
PickBoy
1
Réponse incroyable ici. Tu as résolu mon problème, tu m'as appris un nouveau truc et tu m'as fait rire tout seul.
T Blank le
1
Excellente réponse, merci! Afin de compiler pour une utilisation sur heroku (intel x86), j'ai légèrement modifié la ligne env GOOS=linux GOARCH=386 go build -v github.com/path/to/your/appet cela fonctionne comme un champion
Ira Herman
136

Grâce à l'aide aimable et patiente des noix de golang, la recette est la suivante:

1) Il faut compiler le compilateur Go pour différentes plates-formes et architectures cibles. Ceci est fait à partir du dossier src dans l'installation go. Dans mon cas, l'installation de Go se trouve /usr/local/godonc pour compiler un compilateur, vous devez émettre un makeutilitaire. Avant de faire cela, vous devez connaître quelques mises en garde.

Il y a un problème concernant la bibliothèque CGO lors de la compilation croisée, il est donc nécessaire de désactiver la bibliothèque CGO.

La compilation se fait en changeant l'emplacement du répertoire source, car la compilation doit être effectuée dans ce dossier

cd /usr/local/go/src

puis compilez le compilateur Go:

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

Vous devez répéter cette étape pour chaque système d'exploitation et architecture que vous souhaitez effectuer une compilation croisée en modifiant les paramètres GOOS et GOARCH.

Si vous travaillez en mode utilisateur comme je le fais, sudo est nécessaire car le compilateur Go se trouve dans le répertoire système. Sinon, vous devez être connecté en tant que super utilisateur. Sur Mac, vous devrez peut-être activer / configurer l'accès SU (il n'est pas disponible par défaut), mais si vous avez réussi à installer Go, vous avez peut-être déjà un accès root.

2) Une fois que vous avez construit tous les compilateurs croisés, vous pouvez facilement compiler votre application en utilisant les paramètres suivants, par exemple:

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

Changez le GOOS et le GOARCH en cibles que vous souhaitez construire.

Si vous rencontrez des problèmes avec CGO, incluez CGO_ENABLED = 0 dans la ligne de commande. Notez également que les binaires pour linux et mac n'ont pas d'extension, vous pouvez donc ajouter une extension pour avoir des fichiers différents. -o le commutateur demande à Go de créer un fichier de sortie similaire aux anciens compilateurs pour c / c ++ ainsi utilisé ci-dessus appname.linux peut être n'importe quelle autre extension.

ljgww
la source
Ce qui m'a d'abord dérouté, c'est que dans la première partie de la compilation, make dit: # Building compilers and Go bootstrap tool for host, darwin/amd64mais plus tard, cela finit en fait comme: --- Installed Go for windows/386 in /usr/local/go Installed commands in /usr/local/go/bindonc on observera la fin plutôt que le début de la compilation du compilateur.
ljgww
tout a commencé par essayer de faire: $ GOARCH=386 GOOS=linux go build app.goet obtenir une erreur # 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
Le paquet de Go dans Homebrew a une option "--cross-compile-all" qui construira automatiquement tous les compilateurs croisés.
nimrodm
8
bon conseil @nimrodm! pour recompiler votre installation go, vous devez exécuterbrew reinstall go --cross-compile-all
linqu
1
@ljgww 'sudo' n'a pas configuré ENV. J'ai fini par utiliser chown sur / usr / local / go / pkg / linux_amd64 /
Nuno Silva
63

Si vous utilisez Homebrew sur OS X, vous avez une solution plus simple:

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

ou..

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

À utiliser reinstallsi vous avez déjà goinstallé.

doc what
la source
3
Notez que les commutateurs mis à jour sont: --cross-compile-all Construire les compilateurs croisés et le support d'exécution pour toutes les plates-formes prises en charge --cross-compile-common Construire les compilateurs croisés et le support d'exécution pour darwin, linux et windows
Chip Tol
3
--cross-compile-allest maintenant--with-cc-all
gianebao
@ sheeks06 - corrigé. Merci!
docwhat
1
Ces drapeaux n'existent plus d'après ce que je peux dire. La seule option pertinente que je vois est --without-cgo :(
rdegges
5
Depuis Go 1.5, il n'y a pas de compilateurs croisés séparés, vous n'utilisez que les indicateurs maintenant tip.golang.org/doc/go1.5#compiler_and_tools
chuckus
24

Vous pouvez le faire assez facilement en utilisant Docker, donc aucune bibliothèque supplémentaire n'est requise. Exécutez simplement cette commande:

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
'

Vous pouvez trouver plus de détails dans cet article: https://medium.com/iron-io-blog/how-to-cross-compile-go-programs-using-docker-beaa102a316d

Travis Reeder
la source
1
Pourquoi quelqu'un voudrait-il installer Docker pour faire cela alors qu'il pourrait simplement faire une boucle shell env GOOS=x GOARCH=y go install something/...et se retrouver avec les binaires appropriés sous $GOPATH/bin/$GOOS_$GOARCH?? Et BTW, Go prend en charge plus que les trois systèmes d'exploitation que vous répertoriez, pourquoi ne pas aimer les BSD?
Dave C
8
Vous n'installez pas Docker uniquement pour le faire, mais si vous l'avez, c'est plus facile et plus propre que les alternatives.
Travis Reeder
7

Le processus de création d'exécutables pour de nombreuses plates-formes peut être un peu fastidieux, je suggère donc d'utiliser un 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

J'ai vérifié ce script sur OSX uniquement

gist - go-executable-build.sh

Dima Kozhevin
la source
Exactement ce que je cherchais ... Je l'ai dockerisé :) gist.github.com/marcellodesales
Marcello de Sales
6

pour les personnes qui doivent activer CGO et effectuer une compilation croisée à partir de fenêtres de ciblage OSX

J'avais besoin de CGO activé lors de la compilation pour Windows à partir de mon mac car j'avais importé le https://github.com/mattn/go-sqlite3 et il en avait besoin. Compiler selon d'autres réponses m'a donné et erreur:

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

Si vous êtes comme moi et que vous devez compiler avec CGO. C'est ce que j'ai fait:

Nous allons effectuer une compilation croisée pour Windows avec une bibliothèque dépendante de CGO. Nous avons d'abord besoin d'un compilateur croisé installé commemingw-w64

brew install mingw-w64

Cela l'installera probablement ici /usr/local/opt/mingw-w64/bin/ .

Tout comme les autres réponses, nous devons d'abord ajouter notre arcade Windows à notre chaîne d'outils de compilateur go maintenant. La compilation d'un compilateur nécessite un compilateur (phrase étrange). La compilation go compilateur a besoin d'un compilateur pré-construit séparé. Nous pouvons télécharger un binaire prédéfini ou construire à partir des sources dans un dossier, par exemple: ~/Documents/go maintenant nous pouvons améliorer notre compilateur Go, selon la réponse la plus élevée, mais cette fois avec CGO_ENABLED=1et notre compilateur prédéfini séparé GOROOT_BOOTSTRAP(Pooya est mon nom d'utilisateur):

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.Maintenant, lors de la compilation de notre code Go, utilisez mingwpour compiler nos fenêtres de ciblage de fichiers go avec CGO activé:

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
la source