Mes options de construction préférées pour Go


  • FrançaisFrançais


  • L’une des parties les plus gratifiantes de l’apprentissage d’un nouveau langage de programmation est enfin d’exécuter un exécutable et d’obtenir la sortie souhaitée. Lorsque j’ai découvert le langage de programmation Go, j’ai commencé par lire quelques exemples de programmes pour me familiariser avec la syntaxe, puis j’ai écrit de petits programmes de test. Au fil du temps, cette approche m’a aidé à me familiariser avec la compilation et la construction du programme.

    Les options de construction disponibles pour Go offrent des moyens de mieux contrôler le processus de construction. Ils peuvent également fournir des informations supplémentaires pour aider à diviser le processus en parties plus petites. Dans cet article, je vais démontrer certaines des options que j’ai utilisées. Remarque : j’utilise les termes construire et compiler signifier la même chose.

    Programmation et développement

    Premiers pas avec Go

    J’utilise Go version 1.16.7; cependant, la commande donnée ici devrait également fonctionner sur les versions les plus récentes. Si vous n’avez pas installé Go, vous pouvez le télécharger depuis le Aller sur le site et suivez les instructions d’installation. Vérifiez la version que vous avez installée en ouvrant une commande d’invite et en tapant :

    $ go version

    La réponse devrait ressembler à ceci, selon votre version.

    go version go1.16.7 linux/amd64
    $

    Compilation et exécution de base des programmes Go

    Je vais commencer par un exemple de programme Go qui affiche simplement “Hello World” à l’écran.

    $ cat hello.go
    package main

    import "fmt"

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

    Avant de discuter d’options plus avancées, je vais vous expliquer comment compiler un exemple de programme Go. je me sers de build suivi du nom du fichier source du programme Go, qui dans ce cas est hello.go.

    $ go build hello.go

    Si tout fonctionne correctement, vous devriez voir un exécutable nommé hello créé dans votre répertoire courant. Vous pouvez vérifier qu’il est au format exécutable binaire ELF (sur la plate-forme Linux) en utilisant la commande file. Vous pouvez également l’exécuter et voir qu’il affiche “Hello World”.

    $ ls
    hello  hello.go
    $
    $ file ./hello
    ./hello: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, not stripped
    $
    $ ./hello
    Hello World
    $

    Go fournit un outil pratique run option au cas où vous ne voudriez pas avoir un binaire résultant et que vous vouliez plutôt voir si le programme fonctionne correctement et imprime la sortie souhaitée. Gardez à l’esprit que même si vous ne voyez pas l’exécutable dans votre répertoire actuel, Go compile et produit toujours l’exécutable quelque part, l’exécute, puis le supprime du système. J’expliquerai dans une section ultérieure de cet article.

    $ go run hello.go
    Hello World
    $
    $ ls
    hello.go
    $

    Sous la capuche

    Les commandes ci-dessus ont fonctionné comme un jeu d’enfant pour exécuter mon programme avec un minimum d’effort. Cependant, si vous voulez savoir ce que Go fait sous le capot pour compiler ces programmes, Go fournit un -x option qui imprime tout ce que Go fait pour produire l’exécutable.

    Un coup d’œil rapide vous indique que Go crée un répertoire de travail temporaire dans /tmpproduit l’exécutable, puis le déplace vers le répertoire courant où se trouvait le programme Go source.

    $ go build -x hello.go

    WORK=/tmp/go-build1944767317
    mkdir -p $WORK/b001/

    << snip >>

    mkdir -p $WORK/b001/exe/
    cd .
    /usr/lib/golang/pkg/tool/linux_amd64/link -o $WORK \
    /b001/exe/a.out -importcfg $WORK/b001 \
    /importcfg.link -buildmode=exe -buildid=K26hEYzgDkqJjx2Hf-wz/\
    nDueg0kBjIygx25rYwbK/W-eJaGIOdPEWgwC6o546 \
    /K26hEYzgDkqJjx2Hf-wz -extld=gcc /root/.cache/go-build /cc \
    /cc72cb2f4fbb61229885fc434995964a7a4d6e10692a23cc0ada6707c5d3435b-d
    /usr/lib/golang/pkg/tool/linux_amd64/buildid -w $WORK \
    /b001/exe/a.out # internal
    mv $WORK/b001/exe/a.out hello
    rm -r $WORK/b001/

    Cela aide à résoudre les mystères lorsqu’un programme s’exécute mais qu’aucun exécutable résultant n’est créé dans le répertoire actuel. En utilisant -x montre que le fichier exécutable a bien été créé dans un /tmp répertoire de travail et a été exécuté. Cependant, contrairement au build l’exécutable n’a pas été déplacé vers le répertoire courant, ce qui donne l’impression qu’aucun exécutable n’a été créé.

    $ go run -x hello.go

    mkdir -p $WORK/b001/exe/
    cd .
    /usr/lib/golang/pkg/tool/linux_amd64/link -o $WORK/b001 \
    /exe/hello -importcfg $WORK/b001/importcfg.link -s -w -buildmode=exe -buildid=hK3wnAP20DapUDeuvAAS/E_TzkbzwXz6tM5dEC8Mx \
    /7HYBzuaDGVdaZwSMEWAa/hK3wnAP20DapUDeuvAAS -extld=gcc \
    /root/.cache/go-build/75/ \
    7531fcf5e48444eed677bfc5cda1276a52b73c62ebac3aa99da3c4094fa57dc3-d
    $WORK/b001/exe/hello
    Hello World

    Simuler la compilation sans produire l’exécutable

    Ssupposez que vous ne le faites pas voulez compiler le programme et produire un binaire réel, mais vous voulez voir toutes les étapes du processus. Vous pouvez le faire en utilisant le -n build option, qui imprime les étapes qu’il exécuterait normalement sans créer réellement le binaire.

    $ go build -n hello.go

    Enregistrer les répertoires temporaires

    Beaucoup de travail se fait dans le /tmp répertoire de travail, qui est supprimé une fois l’exécutable créé et exécuté. Mais que se passe-t-il si vous voulez voir quels fichiers ont été créés lors du processus de compilation ? Go fournit un -work option qui peut être utilisée lors de la compilation d’un programme. Le -work L’option imprime le chemin du répertoire de travail en plus d’exécuter le programme, mais elle ne supprime pas le répertoire de travail par la suite, vous pouvez donc vous déplacer vers ce répertoire et examiner tous les fichiers créés pendant le processus de compilation.

    $ go run -work hello.go
    WORK=/tmp/go-build3209320645
    Hello World
    $
    $ find /tmp/go-build3209320645
    /tmp/go-build3209320645
    /tmp/go-build3209320645/b001
    /tmp/go-build3209320645/b001/importcfg.link
    /tmp/go-build3209320645/b001/exe
    /tmp/go-build3209320645/b001/exe/hello
    $
    $ /tmp/go-build3209320645/b001/exe/hello
    Hello World
    $

    Options de compilation alternatives

    Et si, au lieu d’utiliser la magie build/run de Go, vous vouliez compiler le programme à la main et vous retrouver avec un exécutable qui peut être exécuté directement par votre système d’exploitation (dans ce cas, Linux) ? Ce processus peut être divisé en deux parties : compiler et lier. Utilisez le tool option pour voir comment cela fonctionne.

    Tout d’abord, utilisez le tool compile possibilité de produire le résultat ar fichier d’archive, qui contient le .o dossier intermédiaire. Ensuite, utilisez le tool link option sur ce hello.o fichier pour produire l’exécutable final, qui peut ensuite s’exécuter.

    $ go tool compile hello.go
    $
    $ file hello.o
    hello.o: current ar archive
    $
    $ ar t hello.o
    __.PKGDEF
    _go_.o
    $
    $ go tool link -o hello hello.o
    $
    $ file hello
    hello: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, not stripped
    $
    $ ./hello
    Hello World
    $

    Pour jeter un coup d’œil plus loin dans le processus de lien de production de l’exécutable à partir du hello.o fichier, vous pouvez utiliser le -v option, qui recherche le runtime.a fichier inclus dans chaque exécutable Go.

    $ go tool link -v -o hello hello.o
    HEADER = -H5 -T0x401000 -R0x1000
    searching for runtime.a in /usr/lib/golang/pkg/linux_amd64/runtime.a
    82052 symbols, 18774 reachable
            1 package symbols, 1106 hashed symbols, 77185 non-package symbols, 3760 external symbols
    81968 liveness data
    $

    Options de compilation croisée

    Maintenant que j’ai expliqué la compilation d’un programme Go, je vais vous montrer comment Go vous permet de créer un exécutable ciblé sur différentes architectures matérielles et systèmes d’exploitation en fournissant deux variables d’environnement (GOOS et GOARCH) avant le véritable build commande.

    Pourquoi est-ce important ? Vous pouvez voir un exemple lorsqu’un exécutable produit pour l’architecture ARM (aarch64) ne s’exécute pas sur une architecture Intel (x86_64) et produit une erreur de format Exec.

    Ces options rendent triviale la production de binaires multiplateformes.

    $ GOOS=linux GOARCH=arm64 go build hello.go
    $
    $ file ./hello
    ./hello: ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), statically linked, not stripped
    $

    $ ./hello
    bash: ./hello: cannot execute binary file: Exec format error
    $
    $ uname -m
    x86_64
    $

    Vous pouvez lire mon article de blog précédent sur mes expériences de compilation croisée à l’aide de Go pour en savoir plus.

    Afficher les instructions d’assemblage sous-jacentes

    Le code source n’est pas directement converti en un exécutable, bien qu’il génère un format d’assemblage intermédiaire qui est ensuite assemblé en un exécutable. Dans Go, cela est mappé sur un format d’assemblage intermédiaire plutôt que sur les instructions d’assemblage du matériel sous-jacent.

    Pour afficher ce format d’assemblage intermédiaire, utilisez -gcflags suivi par -S donnée à la commande build. Cette commande affiche les instructions d’assemblage.

    $ go build -gcflags="-S" hello.go
    # command-line-arguments
    "".main STEXT size=138 args=0x0 locals=0x58 funcid=0x0
            0x0000 00000 (/test/hello.go:5) TEXT    "".main(SB), ABIInternal, $88-0
            0x0000 00000 (/test/hello.go:5) MOVQ    (TLS), CX
            0x0009 00009 (/test/hello.go:5) CMPQ    SP, 16(CX)
            0x000d 00013 (/test/hello.go:5) PCDATA  $0, $-2
            0x000d 00013 (/test/hello.go:5) JLS     128

    << snip >>
    $

    Vous pouvez également utiliser le objdump -s option, comme indiqué ci-dessous, pour voir les instructions d’assemblage d’un programme exécutable qui a déjà été compilé.

    $ ls
    hello  hello.go
    $
    $
    $ go tool objdump -s main.main hello
    TEXT main.main(SB) /test/hello.go
      hello.go:5            0x4975a0                64488b0c25f8ffffff      MOVQ FS:0xfffffff8, CX                 
      hello.go:5            0x4975a9                483b6110                CMPQ 0x10(CX), SP                      
      hello.go:5            0x4975ad                7671                    JBE 0x497620                           
      hello.go:5            0x4975af                4883ec58                SUBQ $0x58, SP                         
      hello.go:6            0x4975d8                4889442448              MOVQ AX, 0x48(SP)                      

    << snip >>
    $

    Supprimer les fichiers binaires pour réduire leur taille

    Les binaires Go sont généralement volumineux. Par exemple, un simple programme Hello World produit un binaire de taille 1,9 Mo.

    $ go build hello.go
    $
    $ du -sh hello
    1.9M    hello
    $
    $ file hello
    hello: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, not stripped
    $

    Pour réduire la taille du binaire résultant, vous pouvez supprimer les informations inutiles lors de l’exécution. En utilisant -ldflags suivi par -s -w flags rend le binaire résultant légèrement plus léger, à 1,3M.

    $ go build -ldflags="-s -w" hello.go
    $
    $ du -sh hello
    1.3M    hello
    $
    $ file hello
    hello: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, stripped
    $

    Conclusion

    J’espère que cet article vous a présenté quelques options de construction Go pratiques qui peuvent vous aider à mieux comprendre le processus de compilation Go. Pour plus d’informations sur le processus de construction et d’autres options intéressantes disponibles, reportez-vous à la section d’aide :

    $ go help build

    Source

    La Rédaction

    L'équipe rédactionnnelle du site

    Pour contacter personnellement le taulier :

    Laisser un commentaire

    Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

    Copy code