Construire des applications pour différents systèmes d’exploitation et architectures

Dans le développement logiciel, il est important de considérer lesoperating system et le processeur sous-jacentarchitecture pour lesquels vous souhaitez compiler votre binaire. Comme il est souvent lent ou impossible d’exécuter un fichier binaire sur une plate-forme d’OS / architecture différente, il est courant de créer votre fichier binaire final pour de nombreuses plates-formes différentes afin de maximiser l’audience de votre programme. Toutefois, cela peut être difficile lorsque la plate-forme utilisée pour le développement est différente de celle sur laquelle vous souhaitez déployer votre programme. Dans le passé, par exemple, développer un programme sous Windows et le déployer sur une machine Linux ou macOS impliquait la configuration de machines de construction pour chacun des environnements pour lesquels vous vouliez des fichiers binaires. Vous devrez également synchroniser vos outils, en plus d’autres considérations qui augmenteraient les coûts et rendraient plus difficiles les tests et la distribution en collaboration.

Go résout ce problème en intégrant la prise en charge de plusieurs plates-formes directement dans l'outilgo build, ainsi que le reste de la chaîne d'outils Go. En utilisantenvironment variables etbuild tags, vous pouvez contrôler le système d'exploitation et l'architecture pour lesquels votre binaire final est construit, en plus de mettre en place un flux de travail qui peut rapidement basculer l'inclusion de code dépendant de la plate-forme sans changer votre base de code .

Dans ce didacticiel, vous allez rassembler un exemple d'application qui jointstrings dans un chemin de fichier, créer et inclure de manière sélective des extraits de code dépendant de la plate-forme et créer des binaires pour plusieurs systèmes d'exploitation et architectures système sur votre propre système, vous montrant comment pour utiliser cette puissante capacité du langage de programmation Go.

Conditions préalables

Pour suivre l'exemple de cet article, vous aurez besoin de:

Plates-formes possibles pourGOOS etGOARCH

Avant de montrer comment contrôler le processus de construction pour créer des binaires pour différentes plates-formes, examinons d'abord les types de plates-formes pour lesquelles Go est capable de construire et comment Go référence ces plates-formes à l'aide des variables d'environnementGOOS etGOARCH .

L'outil Go propose une commande permettant d'imprimer une liste des plates-formes possibles sur lesquelles Go peut s'appuyer. Cette liste pouvant changer à chaque nouvelle version de Go, les combinaisons présentées ici risquent de ne pas être identiques sur les autres versions de Go. Au moment de la rédaction de ce didacticiel, la version actuelle de Go est1.13.

Pour trouver cette liste de plates-formes possibles, exécutez la commande suivante:

go tool dist list

Vous recevrez une sortie semblable à celle-ci:

Outputaix/ppc64        freebsd/amd64   linux/mipsle   openbsd/386
android/386      freebsd/arm     linux/ppc64    openbsd/amd64
android/amd64    illumos/amd64   linux/ppc64le  openbsd/arm
android/arm      js/wasm         linux/s390x    openbsd/arm64
android/arm64    linux/386       nacl/386       plan9/386
darwin/386       linux/amd64     nacl/amd64p32  plan9/amd64
darwin/amd64     linux/arm       nacl/arm       plan9/arm
darwin/arm       linux/arm64     netbsd/386     solaris/amd64
darwin/arm64     linux/mips      netbsd/amd64   windows/386
dragonfly/amd64  linux/mips64    netbsd/arm     windows/amd64
freebsd/386      linux/mips64le  netbsd/arm64   windows/arm

Cette sortie est un ensemble de paires clé-valeur séparées par un/. La première partie de la combinaison, avant les/, est le système d'exploitation. Dans Go, ces systèmes d'exploitation sont des valeurs possibles pour la variable d'environnementGOOS, prononcée «goose», qui signifieGo Operating System. La deuxième partie, après les/, est l'architecture. Comme précédemment, ce sont toutes les valeurs possibles pour une variable d'environnement:GOARCH. Cela se prononce «gore-ch» et signifieGo Architecture.

Décomposons l'une de ces combinaisons pour comprendre ce qu'elle signifie et comment elle fonctionne, en utilisantlinux/386 comme exemple. La paire clé-valeur commence par lesGOOS, qui dans cet exemple seraientlinux, en référence auxLinux OS. LesGOARCH ici seraient386, ce qui représente lesIntel 80386 microprocessor.

Il existe de nombreuses plates-formes disponibles avec la commandego build, mais la plupart du temps, vous finirez par utiliserlinux,windows oudarwin comme valeur deGOOS. Celles-ci couvrent les trois grandes plates-formes OS:Linux,Windows etmacOS, qui est basée sur lesDarwin operating system et est donc appeléedarwin. Cependant, Go peut également couvrir des plates-formes moins courantes telles quenacl, qui représenteGoogle’s Native Client.

Lorsque vous exécutez une commande telle quego build, Go utilise lesGOOS etGOARCH de la plate-forme actuelle pour déterminer comment construire le binaire. Pour connaître la combinaison de votre plate-forme, vous pouvez utiliser la commandego env et passerGOOS etGOARCH comme arguments:

go env GOOS GOARCH

En testant cet exemple, nous avons exécuté cette commande sur macOS sur une machine avec unAMD64 architecture, nous recevrons donc la sortie suivante:

Outputdarwin
amd64

Ici, la sortie de la commande nous indique que notre système aGOOS=darwin etGOARCH=amd64.

Vous savez maintenant quels sont lesGOOS etGOARCH dans Go, ainsi que leurs valeurs possibles. Ensuite, vous allez créer un programme à utiliser comme exemple d'utilisation de ces variables d'environnement et créer des balises pour créer des fichiers binaires pour d'autres plates-formes.

Ecrire un programme dépendant de la plate-forme avecfilepath.Join()

Avant de commencer à créer des fichiers binaires pour d’autres plates-formes, construisons un exemple de programme. Un bon exemple à cet effet est la fonctionJoin du packagepath/filepath de la bibliothèque standard Go. Cette fonction prend plusieurs chaînes et retourne une chaîne qui est jointe avec le séparateur de chemin de fichier correct.

Il s'agit d'un bon exemple de programme car son fonctionnement dépend du système d'exploitation sur lequel il s'exécute. Sous Windows, le séparateur de chemin est une barre oblique inverse,\, tandis que les systèmes Unix utilisent une barre oblique,/.

Commençons par créer une application qui utilisefilepath.Join(), et plus tard, vous allez écrire votre propre implémentation de la fonctionJoin() qui personnalise le code en fonction des binaires spécifiques à la plate-forme.

Tout d'abord, créez un dossier dans votre répertoiresrc avec le nom de votre application:

mkdir app

Déplacer dans ce répertoire:

cd app

Ensuite, créez un nouveau fichier dans l'éditeur de texte de votre choix nommémain.go. Pour ce tutoriel, nous allons utiliser Nano:

nano main.go

Une fois le fichier ouvert, ajoutez le code suivant:

src/app/main.go

package main

import (
  "fmt"
  "path/filepath"
)

func main() {
  s := filepath.Join("a", "b", "c")
  fmt.Println(s)
}

La fonctionmain() de ce fichier utilisefilepath.Join() pour concaténer troisstrings avec le séparateur de chemin correct dépendant de la plate-forme.

Enregistrez et quittez le fichier, puis exécutez le programme:

go run main.go

Lors de l'exécution de ce programme, vous recevrez une sortie différente en fonction de la plate-forme que vous utilisez. Sous Windows, vous verrez les chaînes séparées par\:

Outputa\b\c

Sur les systèmes Unix tels que macOS et Linux, vous recevrez ce qui suit:

Outputa/b/c

Cela montre qu'en raison des différents protocoles de système de fichiers utilisés sur ces systèmes d'exploitation, le programme devra créer un code différent pour les différentes plates-formes. Mais comme il utilise déjà un séparateur de fichiers différent selon le système d'exploitation, nous savons quefilepath.Join() explique déjà la différence de plate-forme. En effet, la chaîne d’outils Go détecte automatiquement lesGOOS etGOARCH de votre machine et utilise ces informations pour utiliser l’extrait de code avec les bonsbuild tags et le séparateur de fichiers.

Considérons d’où la fonctionfilepath.Join() tire son séparateur. Exécutez la commande suivante pour inspecter l’extrait de code de la bibliothèque standard de Go:

less /usr/local/go/src/os/path_unix.go

Cela affichera le contenu depath_unix.go. Recherchez la partie suivante du fichier:

/usr/local/go/os/path_unix.go

. . .
// +build aix darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris

package os

const (
  PathSeparator     = '/' // OS-specific path separator
  PathListSeparator = ':' // OS-specific path list separator
)
. . .

Cette section définit lesPathSeparator pour toutes les variétés de systèmes de type Unix pris en charge par Go. Notez toutes les balises de construction en haut, qui sont chacune des plates-formes UnixGOOSpossibles associées à Unix. LorsqueGOOS correspond à ces termes, votre programme donnera le séparateur de chemin de fichier de style Unix.

Appuyez surq pour revenir à la ligne de commande.

Ensuite, ouvrez le fichier qui définit le comportement defilepath.Join() lorsqu'il est utilisé sous Windows:

less /usr/local/go/src/os/path_windows.go

Vous verrez ce qui suit:

/usr/local/go/os/path_unix.go

. . .
package os

const (
        PathSeparator     = '\\' // OS-specific path separator
        PathListSeparator = ';'  // OS-specific path list separator
)
. . .

Bien que la valeur dePathSeparator soit ici\, le code restituera la seule barre oblique inverse (\) nécessaire pour les chemins de fichiers Windows, puisque la première barre oblique inverse n'est nécessaire que comme caractère d'échappement.

Notez que, contrairement au fichier Unix, il n’ya pas de balises de construction en haut. En effet,GOOS etGOARCH peuvent également être passés àgo build en ajoutant un trait de soulignement (_) et la valeur de la variable d'environnement comme suffixe au nom de fichier, ce que nous allons aller plus loin dans la sectionUsing GOOS and GOARCH File Name Suffixes. Ici, la partie_windows depath_windows.go fait agir le fichier comme s'il avait la balise de construction// +build windows en haut du fichier. Pour cette raison, lorsque votre programme est exécuté sous Windows, il utilisera les constantes dePathSeparator etPathListSeparator de l'extrait de codepath_windows.go.

Pour revenir à la ligne de commande, quittezless en appuyant surq.

Dans cette étape, vous avez créé un programme qui montre comment Go convertit automatiquement lesGOOS etGOARCH en balises de construction. Dans cet esprit, vous pouvez maintenant mettre à jour votre programme et écrire votre propre implémentation defilepath.Join(), en utilisant des balises de construction pour définir manuellement lesPathSeparator corrects pour les plates-formes Windows et Unix.

Implémentation d'une fonction spécifique à la plate-forme

Maintenant que vous savez comment la bibliothèque standard de Go implémente le code spécifique à la plate-forme, vous pouvez utiliser des balises de construction pour le faire dans votre propre programmeapp. Pour ce faire, vous allez écrire votre propre implémentation defilepath.Join().

Ouvrez votre fichiermain.go:

nano main.go

Remplacez le contenu demain.go par ce qui suit, en utilisant votre propre fonction appeléeJoin():

src/app/main.go

package main

import (
  "fmt"
  "strings"
)

func Join(parts ...string) string {
  return strings.Join(parts, PathSeparator)
}

func main() {
  s := Join("a", "b", "c")
  fmt.Println(s)
}

La fonctionJoin prend un certain nombre departs et les réunit en utilisant la méthodestrings.Join() desstrings package pour concaténer lesparts ensemble en utilisant lePathSeparator.

Vous n’avez pas encore défini lesPathSeparator, alors faites-le maintenant dans un autre fichier. Enregistrez et quittezmain.go, ouvrez votre éditeur préféré et créez un nouveau fichier nommépath.go:

nano path.go

Définissez lePathSeparator et définissez-le égal au séparateur de chemin de fichier Unix,/:

src/app/path.go

package main

const PathSeparator = "/"

Compiler et exécuter l'application:

go build
./app

Vous recevrez le résultat suivant:

Outputa/b/c

Cela fonctionne avec succès pour obtenir un chemin de fichier de type Unix. Mais ce n’est pas encore ce que nous voulons: la sortie est toujoursa/b/c, quelle que soit la plate-forme sur laquelle elle s’exécute. Pour ajouter la fonctionnalité permettant de créer des chemins de fichiers de style Windows, vous devrez ajouter une version Windows desPathSeparator et indiquer à la commandego build la version à utiliser. Dans la section suivante, vous utiliserezbuild tags pour accomplir cela.

Utilisation des balises de constructionGOOS ouGOARCH

Pour tenir compte des plates-formes Windows, vous allez maintenant créer un fichier alternatif àpath.go et utiliser des balises de construction pour vous assurer que les extraits de code ne s'exécutent que lorsqueGOOS etGOARCH sont la plate-forme appropriée.

Mais d'abord, ajoutez une balise de construction àpath.go pour lui dire de construire pour tout sauf pour Windows. Ouvrez le fichier:

nano path.go

Ajoutez la balise de construction en surbrillance suivante au fichier:

src/app/path.go

// +build !windows

package main

const PathSeparator = "/"

Les balises de construction permettent une inversion, ce qui signifie que vous pouvez indiquer à Go de créer ce fichier pour n’importe quelle plate-forme, à l’exception de Windows. Pour inverser une balise de construction, placez un! avant la balise.

Enregistrez et quittez le fichier.

Maintenant, si vous exécutiez ce programme sous Windows, vous obtiendrez le message d'erreur suivant:

Output./main.go:9:29: undefined: PathSeparator

Dans ce cas, Go ne pourrait pas inclurepath.go pour définir la variablePathSeparator.

Maintenant que vous vous êtes assuré quepath.go ne fonctionnera pas lorsqueGOOS est Windows, ajoutez un nouveau fichier,windows.go:

nano windows.go

Danswindows.go, définissez lesPathSeparator Windows, ainsi qu'une balise de construction pour faire savoir à la commandego build qu'il s'agit de l'implémentation Windows:

src/app/windows.go

// +build windows

package main

const PathSeparator = "\\"

Enregistrez le fichier et quittez l'éditeur de texte. L'application peut désormais compiler une manière pour Windows et une autre pour toutes les autres plates-formes.

Bien que les fichiers binaires se construisent désormais correctement pour leurs plates-formes, vous devez apporter d'autres modifications pour pouvoir les compiler pour une plate-forme à laquelle vous n'avez pas accès. Pour ce faire, vous allez modifier vos variables d'environnement localesGOOS etGOARCH à l'étape suivante.

Utilisation de vos variables d'environnement localesGOOS etGOARCH

Auparavant, vous exécutiez la commandego env GOOS GOARCH pour connaître le système d'exploitation et l'architecture sur lesquels vous travailliez. Lorsque vous avez exécuté la commandego env, elle a recherché les deux variables d'environnementGOOS etGOARCH; s'ils sont trouvés, leurs valeurs seraient utilisées, mais si elles ne sont pas trouvées, Go les définirait avec les informations de la plate-forme actuelle. Cela signifie que vous pouvez modifierGOOS ouGOARCH afin qu'ils ne correspondent pas par défaut à votre système d'exploitation et à votre architecture locaux.

La commandego build se comporte de la même manière que la commandego env. Vous pouvez définir les variables d'environnementGOOS ouGOARCH à construire pour une plate-forme différente à l'aide dego build.

Si vous n'utilisez pas de système Windows, créez un binairewindows deapp en définissant la variable d'environnementGOOS surwindows lors de l'exécution de la commandego build:

GOOS=windows go build

Maintenant, listez les fichiers dans votre répertoire actuel:

ls

La sortie de la liste du répertoire montre qu'il y a maintenant un exécutable Windowsapp.exe dans le répertoire du projet:

Outputapp  app.exe  main.go  path.go  windows.go

En utilisant la commandefile, vous pouvez obtenir plus d'informations sur ce fichier, confirmant sa construction:

file app.exe

Vous allez recevoir:

Outputapp.exe: PE32+ executable (console) x86-64 (stripped to external PDB), for MS Windows

Vous pouvez également définir une ou les deux variables d’environnement au moment de la construction. Exécutez ce qui suit:

GOOS=linux GOARCH=ppc64 go build

Votre exécutableapp sera désormais remplacé par un fichier pour une architecture différente. Exécutez la commandefile sur ce binaire:

file app

Vous recevrez une sortie comme celle-ci:

app: ELF 64-bit MSB executable, 64-bit PowerPC or cisco 7500, version 1 (SYSV), statically linked, not stripped

En définissant vos variables d'environnement localesGOOS etGOARCH, vous pouvez désormais créer des binaires pour toutes les plates-formes compatibles de Go sans configuration ni configuration compliquée. Ensuite, vous utiliserez les conventions de nom de fichier pour garder vos fichiers bien organisés et construire pour des plates-formes spécifiques automatiquement sans générer de balises.

Utilisation des suffixes de nom de fichierGOOS etGOARCH

Comme vous l'avez vu précédemment, la bibliothèque standard Go utilise beaucoup de balises de construction pour simplifier le code en séparant les différentes implémentations de plate-forme en différents fichiers. Lorsque vous avez ouvert le fichieros/path_unix.go, il y avait une balise de construction répertoriant toutes les combinaisons possibles considérées comme des plates-formes de type Unix. Cependant, le fichieros/path_windows.go ne contenait aucune balise de construction, car le suffixe du nom de fichier suffisait à indiquer à Go à quelle plate-forme le fichier était destiné.

Regardons la syntaxe de cette fonctionnalité. Lorsque vous nommez un fichier.go, vous pouvez ajouterGOOS etGOARCH comme suffixes au nom du fichier dans cet ordre, en séparant les valeurs par des traits de soulignement (_). Si vous aviez un fichier Go nomméfilename.go, vous pouvez spécifier le système d'exploitation et l'architecture en changeant le nom de fichier enfilename_GOOS_GOARCH.go. Par exemple, si vous souhaitiez le compiler pour Windows avecARM architecture 64 bits, vous créeriez le nom du fichierfilename_windows_arm64.go. Cette convention de dénomination permet de garder le code bien organisé.

Mettez à jour votre programme pour utiliser les suffixes de nom de fichier au lieu des balises de construction. Tout d'abord, renommez le fichierpath.go etwindows.go pour utiliser la convention utilisée dans le packageos:

mv path.go path_unix.go
mv windows.go path_windows.go

Une fois les deux noms de fichiers modifiés, vous pouvez supprimer la balise de construction que vous avez ajoutée àpath_windows.go:

nano path_windows.go

Supprimez// +build windows pour que votre fichier ressemble à ceci:

path_windows.go

package main

const PathSeparator = "\\"

Enregistrez et quittez le fichier.

Commeunix n'est pas unGOOS valide, le suffixe_unix.go n'a aucune signification pour le compilateur Go. Cependant, il indique le but du fichier. Comme le fichieros/path_unix.go, votre fichierpath_unix.go doit toujours utiliser des balises de construction, donc gardez ce fichier inchangé.

En utilisant les conventions de nom de fichier, vous supprimez les balises de construction inutiles de votre code source et rendez le système de fichiers plus propre et plus clair.

Conclusion

La possibilité de générer des fichiers binaires pour plusieurs plates-formes ne nécessitant aucune dépendance est une fonctionnalité puissante de la chaîne d'outils Go. Dans ce didacticiel, vous avez utilisé cette fonctionnalité en ajoutant des balises de construction et des suffixes de nom de fichier pour marquer certains extraits de code à compiler uniquement pour certaines architectures. Vous avez créé votre propre programme dépendant de la plate-forme, puis manipulé les variables d'environnementGOOS etGOARCH pour générer des binaires pour les plates-formes au-delà de votre plate-forme actuelle. Il s'agit d'une compétence précieuse, car il est courant de disposer d'un processus d'intégration continue qui s'exécute automatiquement à travers ces variables d'environnement pour créer des fichiers binaires pour toutes les plateformes.

Pour une étude plus approfondie surgo build, consultez notre tutoriel surCustomizing Go Binaries with Build Tags. Si vous souhaitez en savoir plus sur le langage de programmation Go en général, consultez l'intégralité desHow To Code in Go series.