Как собрать исполняемые файлы Go для нескольких платформ в Ubuntu 16.04

Вступление

Go programming language поставляется с богатым набором инструментов, который делает получение пакетов и создание исполняемых файлов невероятно простым. Одна из самых мощных функций Go - возможность кросс-сборки исполняемых файлов для любой поддерживаемой Go иностранной платформы. Это значительно упрощает тестирование и распространение пакетов, потому что вам не нужен доступ к конкретной платформе, чтобы распространять для нее свой пакет.

В этом руководстве вы будете использовать инструменты Go, чтобы получить пакет из системы управления версиями и автоматически установить его исполняемый файл. Затем вы вручную создадите и установите исполняемый файл, чтобы вы могли быть знакомы с процессом. Затем вы создадите исполняемый файл для другой архитектуры и автоматизируете процесс сборки для создания исполняемых файлов для нескольких платформ. Когда вы закончите, вы узнаете, как создавать исполняемые файлы для Windows и macOS, а также для других платформ, которые вы хотите поддерживать.

Предпосылки

Чтобы следовать этому уроку, вам понадобится:

[[step-1 -—- install-go-programs-from-version-control]] == Шаг 1. Установка программ Go из системы контроля версий

Прежде чем мы сможем создать исполняемые файлы из пакета Go, мы должны получить его исходный код. Инструментgo get может получать пакеты из систем контроля версий, таких как GitHub. Под капотомgo get клонирует пакеты в подкаталоги каталога$GOPATH/src/. Затем, если применимо, он устанавливает пакет, создавая его исполняемый файл и помещая его в каталог$GOPATH/bin. Если вы настроили Go, как описано в необходимых руководствах, каталог$GOPATH/bin будет включен в переменную окружения$PATH, что гарантирует, что вы можете использовать установленные пакеты из любой точки вашей системы.

Синтаксис командыgo get:go get package-import-path. package-import-path - это строка, которая уникально идентифицирует пакет. Часто это расположение пакета в удаленном репозитории, таком как Github, или в каталоге в каталоге$GOPATH/src/ на вашем компьютере.

Обычноgo get используется с флагом-u, который инструктируетgo get получить пакет и его зависимости или обновить эти зависимости, если они уже присутствуют на машине.

В этом руководстве мы установимCaddy, веб-сервер, написанный на Go. ДляCaddy’s instructionsx мы будем использоватьgithub.com/mholt/caddy/caddy в качестве пути импорта пакета. Используйтеgo get для загрузки и установки Caddy:

go get -u github.com/mholt/caddy/caddy

Выполнение команды займет некоторое время, но вы не увидите никакого прогресса, пока она извлекает пакет и устанавливает его. Отсутствие вывода фактически указывает на то, что команда выполнена успешно.

Когда команда завершится, вы обнаружите, что исходный код Кэдди доступен в$GOPATH/src/github.com/mholt/caddy. Кроме того, поскольку у Caddy есть исполняемый файл, он был автоматически создан и сохранен в каталоге$GOPATH/bin. Убедитесь в этом, используяwhich для вывода местоположения исполняемого файла:

which caddy

Вы увидите следующий вывод:

Output/home/sammy/work/bin/caddy

[.Примечание]##

Note: командаgo get устанавливает пакеты из ветки по умолчанию репозитория Git, которая во многих случаях являетсяmaster или ветвью в разработке. Обязательно ознакомьтесь с инструкциями, которые обычно находятся в файле репозиторияREADME, прежде чем использоватьgo get.

Вы можете использовать команды Git, напримерgit checkout, чтобы выбрать другую ветку для источников, полученных с помощью командыgo get. Просмотрите руководствоHow to Use Git Branches, чтобы узнать больше о том, как переключать ветки.

Давайте рассмотрим процесс установки пакетов Go более подробно, начиная с создания исполняемых файлов из пакетов, которые мы уже получили.

[[step-2 -—- сборка исполняемого файла]] == Шаг 2 - Создание исполняемого файла

Командаgo get загрузила исходный код и установила исполняемый файл Caddy за одну команду. Но вы можете захотеть пересобрать исполняемый файл самостоятельно или создать исполняемый файл из своего собственного кода. Командаgo build создает исполняемые файлы.

Хотя мы уже установили Caddy, давайте создадим его заново вручную, чтобы мы могли освоиться с этим процессом. Выполнитеgo build и укажите путь импорта пакета:

go build github.com/mholt/caddy/caddy

Как и прежде, отсутствие вывода указывает на успешную работу. Исполняемый файл будет создан в вашем текущем каталоге с тем же именем, что и каталог, содержащий пакет. В этом случае исполняемый файл будет называтьсяcaddy.

Если вы находитесь в каталоге пакета, вы можете опустить путь к пакету и просто запуститьgo build.

Чтобы указать другое имя или расположение для исполняемого файла, используйте флаг-o. Давайте создадим исполняемый файл с именемcaddy-server и поместим его в каталогbuild в текущем рабочем каталоге:

go build -o build/caddy-server github.com/mholt/caddy/caddy

Эта команда создает исполняемый файл, а также создает каталог./build, если он не существует.

Теперь давайте посмотрим на установку исполняемых файлов.

[[шаг-3 -—- установка исполняемого файла]] == Шаг 3 - Установка исполняемого файла

Сборка исполняемого файла создает исполняемый файл в текущем каталоге или каталоге по вашему выбору. Установка исполняемого файла - это процесс создания исполняемого файла и его сохранения в$GOPATH/bin. Командаgo install работает так же, какgo build, ноgo install заботится о размещении выходного файла в нужном для вас месте.

Чтобы установить исполняемый файл, используйтеgo install, за которым следует путь для импорта пакета. Еще раз, используйте Caddy, чтобы попробовать это:

go install github.com/mholt/caddy/caddy

Как и в случае сgo build, вы не увидите вывода, если команда выполнена успешно. И, как и прежде, исполняемый файл создается с тем же именем, что и каталог, содержащий пакет. Но на этот раз исполняемый файл хранится в$GOPATH/bin. Если$GOPATH/bin является частью вашей переменной среды$PATH, исполняемый файл будет доступен из любой точки вашей операционной системы. Вы можете проверить его местоположение с помощью командыwhich:

which caddy

Вы увидите следующий вывод:

Output of which/home/sammy/work/bin/caddy

Теперь, когда вы понимаете, как работаютgo get,go build иgo install и как они связаны, давайте рассмотрим одну из самых популярных функций Go: создание исполняемых файлов для других целевых платформ.

[[шаг-4 -—- создание-исполняемых-файлов-для-разных-архитектур]] == Шаг 4 - Создание исполняемых файлов для разных архитектур

Командаgo build позволяет создавать исполняемый файл для любой поддерживаемой Go целевой платформыon your platform. Это означает, что вы можете тестировать, выпускать и распространять свое приложение, не создавая исполняемые файлы на целевых платформах, которые вы хотите использовать.

Кросс-компиляция работает путем установки необходимых переменных среды, которые определяют целевую операционную систему и архитектуру. Мы используем переменнуюGOOS для целевой операционной системы иGOARCH для целевой архитектуры. Чтобы создать исполняемый файл, команда примет следующую форму:

env GOOS=target-OS GOARCH=target-architecture go build package-import-path

Командаenv запускает программу в измененной среде. Это позволяет использовать переменные окружения только для текущего выполнения команды. Переменные сбрасываются или сбрасываются после выполнения команды.

В следующей таблице показаны возможные комбинацииGOOS иGOARCH, которые вы можете использовать:

GOOS - целевая операционная система GOARCH - Целевая платформа

android

arm

darwin

386

darwin

amd64

darwin

arm

darwin

arm64

dragonfly

amd64

freebsd

386

freebsd

amd64

freebsd

arm

linux

386

linux

amd64

linux

arm

linux

arm64

linux

ppc64

linux

ppc64le

linux

mips

linux

mipsle

linux

mips64

linux

mips64le

netbsd

386

netbsd

amd64

netbsd

arm

openbsd

386

openbsd

amd64

openbsd

arm

plan9

386

plan9

amd64

solaris

amd64

windows

386

windows

amd64

[.предупреждение]##

Warning: Для кросс-компиляции исполняемых файлов для Android требуетсяAndroid NDK и некоторая дополнительная настройка, выходящая за рамки данного руководства.

Используя значения в таблице, мы можем собрать Caddy для Windows 64-bit следующим образом:

env GOOS=windows GOARCH=amd64 go build github.com/mholt/caddy/caddy

Еще раз, отсутствие вывода указывает на то, что операция прошла успешно. Исполняемый файл будет создан в текущем каталоге, используя имя пакета в качестве имени. Однако, поскольку мы создали этот исполняемый файл для Windows, его имя заканчивается суффиксом.exe.

У вас должен быть файлcaddy.exe в вашем текущем каталоге, что вы можете проверить с помощью командыls.

ls caddy.exe

Вы увидите файлcaddy.exe, указанный в выводе:

Outputcaddy.exe

[.note] #Note: Вы можете использовать флаг-o, чтобы переименовать исполняемый файл или поместить его в другое место. Однако при создании исполняемого файла для Windows и предоставлении другого имени не забудьте явно указать суффикс `.exe` при установке имени исполняемого файла.
#

Давайте посмотрим на сценарии этого процесса, чтобы упростить выпуск программного обеспечения для нескольких целевых сред.

[[step-5 -—- Creating-a-script-to-automate-cross-compilation]] == Шаг 5 - Создание сценария для автоматизации кросс-компиляции

Процесс создания исполняемых файлов для многих платформ может быть немного утомительным, но мы можем создать сценарий, чтобы упростить задачу.

Сценарий примет путь импорта пакета в качестве аргумента, перебирает предварительно определенный список пар операционной системы и платформы и генерирует исполняемый файл для каждой пары, помещая выходные данные в текущий каталог. Каждому исполняемому файлу будет присвоено имя пакета, за которым следует целевая платформа и архитектура в формеpackage-OS-architecture. Это будет универсальный скрипт, который вы можете использовать в любом проекте.

Перейдите в домашний каталог и создайте новый файл с именемgo-executable-build.bash в текстовом редакторе:

cd ~
nano go-executable-build.bash

Мы начнем наш скрипт со строкиshebang. Эта строка определяет, какой интерпретатор будет анализировать этот скрипт, когда он запускается как исполняемый файл. Добавьте следующую строку, чтобы указать, чтоbash должен выполнить этот сценарий:

go-executable-build.bash

#!/usr/bin/env bash

Мы хотим взять путь импорта пакета в качестве аргумента командной строки. Для этого мы будем использовать переменную$n, гдеn - неотрицательное число. Переменная$0 содержит имя выполняемого вами скрипта, а$1 и выше будут содержать аргументы, предоставленные пользователем. Добавьте эту строку в сценарий, который получит первый аргумент из командной строки и сохранит его в переменной с именемpackage:

go-executable-build.bash

...
package=$1

Далее убедитесь, что пользователь предоставил это значение. Если значение не указано, выйдите из сценария с сообщением, объясняющим, как использовать сценарий:

go-executable-build.bash

...

if [[z "$package" ]]; then
  echo "usage: $0 "
  exit 1
fi

Этот операторif проверяет значение переменной$package. Если он не установлен, мы используемecho для вывода правильного использования, а затем завершаем сценарий, используяexit. exit принимает в качестве аргумента возвращаемое значение, которое должно быть0 для успешных выполнений и любое ненулевое значение для неудачных выполнений. Мы используем здесь1, так как сценарий не удался.

[.Примечание]##

Note: если вы хотите, чтобы этот сценарий работал с предопределенным пакетом, измените переменнуюpackage, чтобы она указывала на этот путь импорта:

go-executable-build.bash

...
package="github.com/user/hello"

Далее мы хотим извлечь имя пакета из пути. Путь импорта пакета разделен символами/, а имя пакета находится в конце пути. Сначала мы разделим путь импорта пакета на массив, используя/ в качестве разделителя:

go-executable-build.bash

package_split=(${package//\// })

Имя пакета должно быть последним элементом этого нового массива$package_split. В Bash вы можете использовать отрицательный индекс массива для доступа к массиву с конца, а не с начала. Добавьте эту строку, чтобы получить имя пакета из массива и сохранить его в переменной с именемpackage_name:

go-executable-build.bash

...
package_name=${package_split[-1]}

Теперь вам нужно решить, для каких платформ и архитектур вы хотите создавать исполняемые файлы. В этом руководстве мы создадим исполняемые файлы для 64-битной Windows, 32-битной Windows и 64-битной MacOS. Мы поместим эти цели в массив с форматомOS/Platform, поэтому мы можем разделить каждую пару на переменныеGOOS иGOARCH, используя тот же метод, который мы использовали для извлечения имени пакета из пути . Добавьте платформы в скрипт:

go-executable-build.bash

...
platforms=("windows/amd64" "windows/386" "darwin/amd64")

Затем мы пройдемся по массиву платформ, разделим каждую запись платформы на значения для переменных средыGOOS иGOARCH и будем использовать их для создания исполняемого файла. Мы можем сделать это с помощью следующего циклаfor:

go-executable-build.bash

...
for platform in "${platforms[@]}"
do
    ...
done

Переменнаяplatform будет содержать запись из массиваplatforms на каждой итерации. Нам нужно разделитьplatform на две переменные -GOOS иGOARCH. Добавьте в циклfor следующие строки:

go-executable-build.bash

for platform in "${platforms[@]}"
do
    platform_split=(${platform//\// })
    GOOS=${platform_split[0]}
    GOARCH=${platform_split[1]}

done

Далее мы сгенерируем имя исполняемого файла, объединив имя пакета с ОС и архитектурой. Когда мы создаем для Windows, нам также необходимо добавить суффикс.exe к имени файла. Добавьте этот код в циклfor:

go-executable-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'
    fi
done

Установив переменные, мы используемgo build для создания исполняемого файла. Добавьте эту строку в тело циклаfor прямо над ключевым словомdone:

go-executable-build.bash

...
    if [ $GOOS = "windows" ]; then
        output_name+='.exe'
    fi

    env GOOS=$GOOS GOARCH=$GOARCH go build -o $output_name $package

done

Наконец, мы должны проверить, не было ли ошибок при сборке исполняемого файла. Например, мы можем столкнуться с ошибкой, если попытаемся создать пакет, для которого у нас нет источников. Мы можем проверить код возврата командыgo build на ненулевое значение. Переменная$? содержит код возврата от выполнения предыдущей команды. Еслиgo build возвращает что-либо, кроме0, возникла проблема, и мы хотим выйти из скрипта. Добавьте этот код в циклfor после командыgo build и над ключевым словомdone.

go-executable-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

Теперь у нас есть скрипт, который будет собирать несколько исполняемых файлов из нашего пакета Go. Вот законченный скрипт:

go-executable-build.bash

#!/usr/bin/env bash

package=$1
if [[z "$package" ]]; then
  echo "usage: $0 "
  exit 1
fi
package_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
    fi
done

Убедитесь, что ваш файл соответствует предыдущему коду. Затем сохраните файл и выйдите из редактора.

Прежде чем мы сможем использовать скрипт, мы должны сделать его исполняемым с помощью командыchmod:

chmod +x go-executable-build.bash

Наконец, протестируйте скрипт, создав исполняемые файлы для Caddy:

./go-executable-build.bash github.com/mholt/caddy/caddy

Если все идет хорошо, у вас должны быть исполняемые файлы в вашем текущем каталоге. Отсутствие вывода указывает на успешное выполнение скрипта. Вы можете проверить, созданы ли исполняемые файлы, используя командуls:

ls caddy*

Вы должны увидеть все три версии:

Example ls outputcaddy-darwin-amd64 caddy-windows-386.exe caddy-windows-amd64.exe

Чтобы изменить целевые платформы, просто измените переменнуюplatforms в своем скрипте.

Заключение

Из этого руководства вы узнали, как использовать инструменты Go для получения пакетов из систем контроля версий, а также для сборки и кросс-компиляции исполняемых файлов для разных платформ.

Вы также создали скрипт, который можно использовать для кросс-компиляции одного пакета для многих платформ.

Чтобы убедиться, что ваше приложение работает правильно, вы можете взглянуть наtesting иcontinuous integration, напримерTravis-CI иAppVeyor, для тестирования в Windows.

Если вас интересует Caddy и способы его использования, взгляните наHow to Host a Website with Caddy on Ubuntu 16.04.

Related