Cómo crear ejecutables Go para múltiples plataformas en Ubuntu 20.04

Introducción
El lenguaje de programación Go viene con una rica cadena de herramientas que hace que obtener paquetes y crear ejecutables sea increíblemente fácil. Una de las características más poderosas de Go es la capacidad de crear ejecutables para cualquier plataforma externa compatible con Go. Esto hace que las pruebas y la distribución de paquetes sean mucho más fáciles, porque no es necesario tener acceso a una plataforma específica para distribuir el paquete en ella.
En este tutorial, utilizará las herramientas de Go para obtener un paquete del control de versiones e instalar automáticamente su ejecutable. Luego, compilará e instalará manualmente el ejecutable para familiarizarse con el proceso. Luego, compilará un ejecutable para una arquitectura diferente y automatizará el proceso de compilación para crear ejecutables para múltiples plataformas. Cuando termine, sabrá cómo compilar ejecutables para Windows y macOS, así como para otras plataformas que desee admitir.
Prerrequisitos
Para seguir este tutorial, necesitarás:
- Un servidor Ubuntu 20.04 configurado siguiendo la guía de configuración inicial del servidor Ubuntu 20.04 , incluido un usuario sudo no root y un firewall.
- Go instalado, como se describe en Cómo instalar Go en Ubuntu 20.04 .
Paso 1: Creación de un programa Go sencillo
Ahora que Go está instalado, puedes intentar crear tu propio Hello, World!.
Primero, crea un nuevo directorio para tu espacio de trabajo de Go, que es donde Go creará sus archivos:
- mkdir hello
A continuación, muévete al directorio que acabas de crear:
- cd hello
Al importar paquetes, hay que gestionar las dependencias a través del propio módulo del código. Esto se puede hacer creando un go.modarchivo con el go mod initcomando:
- go mod init hello
A continuación, crea un Hello, World!archivo Go en tu editor de texto preferido:
- nano hello.go
Añade el siguiente texto a tu hello.goarchivo:
Hola.Ve
package mainimport "fmt"func main() { fmt.Println("Hello, World!")}
Luego, guarde y cierre el archivo presionando CTRL+X, luego Y, y luego ENTER.
Pruebe su código para verificar que imprime el Hello, World!saludo:
- go run .
OutputHello, World!
El go runcomando compila y ejecuta el paquete Go a partir de una lista de .goarchivos fuente del nuevo hellodirectorio que creaste y la ruta que importaste. Pero también puedes usarlo go buildpara crear un archivo ejecutable que te permita ahorrar algo de tiempo.
Paso 2: creación de un ejecutable
El go runcomando ejecutó el código de su programa “¡Hola mundo!”, pero es posible que desee compilar su programa en un binario para ejecutarlo en cualquier parte de su sistema, no solo desde el código fuente. El go buildcomando compila ejecutables.
- go build hello
Como antes, si no hay salida, esto indica que la operación se ha realizado correctamente. El ejecutable se generará en el directorio actual, con el mismo nombre que el directorio que contiene el paquete. En este caso, el ejecutable se llamará hello.
Si se encuentra en el directorio del paquete, puede omitir la ruta al paquete y simplemente ejecutar go build.
Para especificar un nombre o una ubicación diferentes para el ejecutable, utilice el -oindicador. Construyamos un ejecutable llamado helloy colóquelo en un builddirectorio dentro del directorio de trabajo actual:
- go build -o build/hello hello
Este comando crea el ejecutable y también crea el ./builddirectorio si no existe.
Ahora veamos cómo instalar ejecutables.
Paso 3: Instalación de un ejecutable
La creación de un ejecutable crea el archivo ejecutable en el directorio actual o en el directorio que elija. La instalación de un ejecutable es el proceso de crear un ejecutable y almacenarlo en $GOPATH/bin. El go installcomando funciona igual que go build, pero go installse encarga de colocar el archivo de salida en el lugar correcto para usted.
Para instalar un ejecutable, utilice go install, seguido de la ruta de importación del paquete. Una vez más, utilice su programa “Hello, World!” para probar esto:
- go install hello
Al igual que con go build, no verá ningún resultado si el comando se ejecutó correctamente. Y como antes, el ejecutable se crea con el mismo nombre que el directorio que contiene el paquete. Pero esta vez, el ejecutable se almacena en $GOPATH/bin. Si $GOPATH/bines parte de su $PATHvariable de entorno, el ejecutable estará disponible desde cualquier lugar de su sistema operativo. Puede verificar su ubicación mediante whichel comando:
- which hello
Verás el siguiente resultado:
Output of which/home/sammy/go/bin/hello
Ahora que comprende cómo go getfuncionan , go buildy go install, y cómo se relacionan, exploremos una de las características más populares de Go: crear ejecutables para otras plataformas de destino.
Paso 4: creación de ejecutables para diferentes arquitecturas
El go buildcomando le permite crear un archivo ejecutable para cualquier plataforma de destino compatible con Go, en su plataforma . Esto significa que puede probar, publicar y distribuir su aplicación sin crear esos archivos ejecutables en las plataformas de destino que desea utilizar.
La compilación cruzada funciona estableciendo las variables de entorno necesarias que especifican el sistema operativo y la arquitectura de destino. Usamos la variable GOOSpara el sistema operativo y GOARCHla arquitectura de destino. Para crear un ejecutable, el comando adoptaría esta forma:
- GOOS=target-OS GOARCH=target-architecture go build package-import-path
El sistema operativo y la arquitectura se configuran antes de ejecutar el go buildcomando. Esto le permite usar variables de entorno solo para la ejecución del comando actual. Las variables se anulan o se restablecen después de ejecutar el comando.
Para saber qué sistemas operativos y plataformas están disponibles para crear ejecutables, puede utilizar la distherramienta:
- go tool dist list
Esto le proporcionará una lista de sistemas operativos y arquitecturas separados por /caracteres:
Outputaix/ppc64android/386android/amd64android/armandroid/arm64darwin/amd64darwin/arm64dragonfly/amd64freebsd/386freebsd/amd64freebsd/armfreebsd/arm64illumos/amd64ios/amd64ios/arm64js/wasmlinux/386linux/amd64linux/armlinux/arm64linux/mipslinux/mips64linux/mips64lelinux/mipslelinux/ppc64linux/ppc64lelinux/riscv64linux/s390xnetbsd/386netbsd/amd64netbsd/armnetbsd/arm64openbsd/386openbsd/amd64openbsd/armopenbsd/arm64openbsd/mips64plan9/386plan9/amd64plan9/armsolaris/amd64windows/386windows/amd64windows/arm
Advertencia: la compilación cruzada de ejecutables para Android requiere el NDK de Android y alguna configuración adicional que está más allá del alcance de este tutorial.
Usando los valores de la lista, podemos crear un saludo para Windows de 64 bits de la siguiente manera:
- GOOS=windows GOARCH=amd64 go build hello
Una vez más, no hay salida que indique que la operación se ha realizado correctamente. El ejecutable se creará en el directorio actual, utilizando el nombre del paquete como nombre. Sin embargo, dado que creamos este ejecutable para Windows, el nombre termina con el sufijo .exe.
Deberías tener un hello.exearchivo en tu directorio actual, que puedes verificar con el lscomando.
- ls hello.exe
Verás el hello.exearchivo listado en la salida:
Outputhello.exe
Nota : Puede utilizar la -obandera para cambiar el nombre del ejecutable o colocarlo en una ubicación diferente. Sin embargo, al crear un ejecutable para Windows y proporcionar un nombre diferente, asegúrese de especificar explícitamente el .exesufijo al configurar el nombre del ejecutable.
Veamos cómo programar este proceso para facilitar el lanzamiento de software para múltiples entornos de destino.
Paso 5: Creación de un script para automatizar la compilación cruzada
El proceso de creación de ejecutables para muchas plataformas puede ser un poco tedioso, pero podemos crear un script para facilitar las cosas.
El script tomará la ruta de importación del paquete como argumento, iterará a través de una lista predefinida de pares de sistemas operativos y plataformas, y generará un ejecutable para cada par, colocando la salida en el directorio actual. Cada ejecutable se nombrará con el nombre del paquete, seguido de la plataforma y la arquitectura de destino, en el formato package-OS-architecture. Este será un script universal que puede usar en cualquier proyecto.
Dentro del directorio de tu proyecto, crea un nuevo archivo llamado go-executable-build.bashen tu editor de texto:
- nano go-executable-build.bash
Comenzaremos nuestro script con una línea shebang . Esta línea define qué intérprete analizará este script cuando se ejecute como ejecutable. Agregue la siguiente línea para especificar quién bashdebe ejecutar este script:
go-ejecutable-build.bash
#!/usr/bin/env bash
Queremos tomar la ruta de importación del paquete como argumento de la línea de comandos. Para ello, utilizaremos la variable, donde es un número no negativo. La variable contiene el nombre del script que ejecutaste, mientras que y mayor contendrán argumentos proporcionados por el usuario. Agrega esta línea al script, que tomará el primer argumento de la línea de comandos y lo almacenará en una variable llamada :$nn$0$1package
go-ejecutable-build.bash
...package=$1
A continuación, asegúrese de que el usuario haya proporcionado este valor. Si no se proporciona el valor, salga del script con un mensaje que explica cómo utilizar el script:
go-ejecutable-build.bash
...if [[ -z "$package" ]]; then echo "usage: $0 package-name" exit 1fi
Esta ifdeclaración verifica el valor de la $packagevariable. Si no está configurada, usamos echopara imprimir el uso correcto y luego terminamos el script usando exit. exittoma un valor de retorno como argumento, que debe ser 0para ejecuciones exitosas y cualquier valor distinto de cero para ejecuciones fallidas. Usamos 1aquí ya que el script no tuvo éxito.
Nota : Si desea que este script funcione con un paquete predefinido, cambie la packagevariable para que apunte a esa ruta de importación:
go-ejecutable-build.bash
...package="github.com/user/hello"
A continuación, queremos extraer el nombre del paquete de la ruta. La ruta de importación del paquete está delimitada por /caracteres, y el nombre del paquete se encuentra al final de la ruta. Primero, dividiremos la ruta de importación del paquete en una matriz, utilizando el /como delimitador:
go-ejecutable-build.bash
package_split=(${package//// })
El nombre del paquete debe ser el último elemento de esta nueva $package_splitmatriz. En Bash, puedes usar un índice de matriz negativo para acceder a una matriz desde el final en lugar de desde el principio. Agrega esta línea para obtener el nombre del paquete de la matriz y almacenarlo en una variable llamada package_name:
go-ejecutable-build.bash
...package_name=${package_split[-1]}
Ahora, deberá decidir para qué plataformas y arquitecturas desea crear archivos ejecutables. En este tutorial, crearemos archivos ejecutables para Windows de 64 bits, Windows de 32 bits y macOS de 64 bits. Pondremos estos destinos en una matriz con el formato , de modo que podamos dividir cada par en variables y utilizando el mismo método que utilizamos para extraer el nombre del paquete de la ruta. Agregue las plataformas al script:OS/PlatformGOOSGOARCH
go-ejecutable-build.bash
...platforms=("windows/amd64" "windows/386" "darwin/amd64")
A continuación, iteraremos a través de la matriz de plataformas, dividiremos cada entrada de plataforma en valores para las variables de entorno GOOSy GOARCHy los usaremos para crear el ejecutable. Podemos hacerlo con el siguiente forbucle:
go-ejecutable-build.bash
...for platform in "${platforms[@]}"do ...done
La platformvariable contendrá una entrada de la platformsmatriz en cada iteración. Necesitamos dividirla platformen dos variables: GOOSy GOARCH. Agregue las siguientes líneas al forbucle:
go-ejecutable-build.bash
for platform in "${platforms[@]}"do platform_split=(${platform//// }) GOOS=${platform_split[0]} GOARCH=${platform_split[1]} done
A continuación, generaremos el nombre del ejecutable combinando el nombre del paquete con el sistema operativo y la arquitectura. Cuando estamos compilando para Windows, también necesitamos agregar el .exesufijo al nombre del archivo. Agregue este código al forbucle:
go-ejecutable-build.bash
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' fidone
Con las variables configuradas, las usamos go buildpara crear el ejecutable. Agregamos esta línea al cuerpo del forbucle, justo encima de la donepalabra clave:
go-ejecutable-build.bash
... if [ $GOOS = "windows" ]; then output_name+='.exe' fi env GOOS=$GOOS GOARCH=$GOARCH go build -o $output_name $packagedone
Por último, debemos comprobar si se han producido errores al crear el ejecutable. Por ejemplo, podríamos encontrarnos con un error si intentamos crear un paquete para el que no tenemos las fuentes. Podemos comprobar si el go buildcódigo de retorno del comando contiene un valor distinto de cero. La variable $?contiene el código de retorno de la ejecución de un comando anterior. Si go builddevuelve algo distinto de 0, hay un problema y querremos salir del script. Añade este código al forbucle, después del go buildcomando y encima de la donepalabra clave.
go-ejecutable-build.bash
... 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
Con esto, ahora tenemos un script que creará varios ejecutables a partir de nuestro paquete Go. Aquí está el script completo:
go-ejecutable-build.bash
#!/usr/bin/env bashpackage=$1if [[ -z "$package" ]]; then echo "usage: $0 package-name" exit 1fipackage_split=(${package//// })package_name=${package_split[-1]} platforms=("windows/amd64" "windows/386" "darwin/amd64")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 fidone
Verifique que su archivo coincida con el código anterior. Luego guarde el archivo y salga del editor.
Antes de poder usar el script, debemos hacerlo ejecutable con el chmodcomando:
- chmod +x go-executable-build.bash
Por último, prueba el script creando ejecutables para hello:
- ./go-executable-build.bash hello
Si todo va bien, deberías tener ejecutables en tu directorio actual. Si no hay salida, significa que la ejecución del script se realizó correctamente. Puedes verificar si se crearon los ejecutables con lsel comando:
- ls hello*
Deberías ver las tres versiones:
Example ls outputhello-darwin-amd64 hello-windows-386.exe hello-windows-amd64.exe
Para cambiar las plataformas de destino, simplemente cambie la platformsvariable en su script.
Conclusión
En este tutorial, aprendió a utilizar las herramientas de Go para obtener paquetes de sistemas de control de versiones, así como a crear y compilar ejecutables para diferentes plataformas.
También creaste un script que puedes usar para compilar de forma cruzada un solo paquete para varias plataformas.
Para asegurarse de que su aplicación funcione correctamente, puede echar un vistazo a las pruebas y la integración continua como Travis-CI y AppVeyor para probar en Windows.

Deja una respuesta