Aller au contenu

Compilation croisée et création de releases

Une autre force de Go c’est la simplicité avec laquelle le compilateur peut produire du code pour différentes architectures. Illustrons avec un simple programme Hello World

La structure des fichiers est la suivante :

.
├── cmd
│   └── hello
│       └── main.go
└── go.mod

Le fichier go.mod contient le code suivant :

go.mod
module demo

go 1.19

et le code Go du programme

cmd/hello/main.go
package main

import (
        "fmt"
)

func main() {
        fmt.Println("Hello World!")
}

On génère un exécutable pour ce programme avec la commande go build :

go build ./cmd/hello

Le nom de l’exécutable correspond au nom du dossier dans lequel se trouve le package main. Dans notre cas, le nom de l’exécutable est hello (sur une machine de type Unix) ou hello.exe (sur une machine Windows). On peut changer le nom de l’exécutable avec l’option -o :

go build -o my-great-program ./cmd/hello

ou

go build -o my-great-program.exe ./cmd/hello

Si nous voulons utiliser notre programme sur un Raspberry Pi, nous pouvons produire un nouveau binaire en modifiant les variables d’environnement GOOS (GO Operating System) et GOARCH (GO ARCHitecture) :

GOOS=linux GOARCH=arm go build -o hello-for-rpi ./cmd/hello

La commande go tool dist list affiche la liste de toutes les combinaisons possibles de GOOS/GOARCH :

go tool dist list

Résultat avec go version go1.23.1 darwin/arm64

aix/ppc64       freebsd/arm     linux/arm64     netbsd/386      plan9/386
android/386     freebsd/arm64   linux/loong64   netbsd/amd64    plan9/amd64
android/amd64   freebsd/riscv64 linux/mips      netbsd/arm      plan9/arm
android/arm     illumos/amd64   linux/mips64    netbsd/arm64    solaris/amd64
android/arm64   ios/amd64       linux/mips64le  openbsd/386     wasip1/wasm
darwin/amd64    ios/arm64       linux/mipsle    openbsd/amd64   windows/386
darwin/arm64    js/wasm         linux/ppc64     openbsd/arm     windows/amd64
dragonfly/amd64 linux/386       linux/ppc64le   openbsd/arm64   windows/arm
freebsd/386     linux/amd64     linux/riscv64   openbsd/ppc64   windows/arm64
freebsd/amd64   linux/arm       linux/s390x     openbsd/riscv64

Utilisation de gox

gox est un outil pour simplifier la génération d’exécutables pour différentes architectures. Installez le gox avec la commande suivante :

go install github.com/mitchellh/gox@latest

Vous pouvez maintenant produire les exécutables avec la commande suivante :

gox ./cmd/hello

Vous pouvez aussi spécifier les architectures pour lesquelles vous voulez produire les exécutables :

gox -arch="amd64 arm64" -os="darwin linux windows" ./cmd/hello

Note

gox n’est plus maintenu et le projet est archivé. Vous pouvez cependant toujours l’utiliser.

Utilisation de GoReleaser

Une autre manière de produire des exécutables est offert par GoReleaser. Pour faire vos premiers pas avec GoReleaser, commencez par installer l’application :

go install github.com/goreleaser/goreleaser@latest

et initialisez le projet :

goreleaser init

vous devriez avoir deux nouveaux fichiers : .gitignore et goreleaser.yaml :

.
├── .gitignore
├── .goreleaser.yaml
├── README.md
├── cmd
│   └── hello
│       └── main.go
└── go.mod

Editez le fichier .goreleaser.yaml pour ajouter les informations sur votre projet :

## .goreleaser.yaml

``` yaml
project_name: hello-world
...
builds:
  - main: ./cmd/hello
    env:
      - CGO_ENABLED=0
...
universal_binaries:
  - replace: true

tapez ensuite la commande suivante pour générer les exécutables :

goreleaser build --snapshot --clean

Dans le dossier dist, vous trouverez les exécutables pour différentes architectures, y-compris un exécutable universel (AMD64/ARM64) pour les Macs (darwin).

• starting build...
• loading              path=.goreleaser.yaml
• skipping validate...
• loading environment variables
• getting and validating git state
  • accepting to run without a git repository because this is a snapshot
  • git state          commit=none branch=none current_tag=v0.0.0
                        previous_tag=<unknown> dirty=false
  • pipe skipped       reason=disabled during snapshot mode
• parsing tag
• setting defaults
• snapshotting
  • building snapshot... version=0.0.0-SNAPSHOT-none
• running before hooks
  • running            hook=go mod tidy
  • running            hook=go generate ./...
• checking distribution directory
  • cleaning dist
• setting up metadata
• storing release metadata
  • writing            file=dist/metadata.json
• loading go mod information
• build prerequisites
• writing effective config file
  • writing            config=dist/config.yaml
• building binaries
  • building           binary=dist/hello-world_windows_386/hello-world.exe
  • building           binary=dist/hello-world_windows_arm64/hello-world.exe
  • building           binary=dist/hello-world_darwin_amd64_v1/hello-world
  • building           binary=dist/hello-world_linux_386/hello-world
  • building           binary=dist/hello-world_windows_amd64_v1/hello-world.exe
  • building           binary=dist/hello-world_darwin_arm64/hello-world
  • building           binary=dist/hello-world_linux_arm64/hello-world
  • building           binary=dist/hello-world_linux_amd64_v1/hello-world
  • took: 3s
• universal binaries
  • creating from 2 binaries id=hello-world 
                         binary=dist/hello-world_darwin_all/hello-world
• storing artifacts metadata
  • writing            file=dist/artifacts.json
• build succeeded after 2s
• thanks for using goreleaser!

En plus de produire des exécutables, GoReleaser peut aussi créer des releases sur GitHub ou sur GitLab. Lisez la documentation pour plus d’informations.