Как создавать исполняемые файлы Go для нескольких платформ в Ubuntu 16.04
Введение
Язык программирования Go поставляется с богатым набором инструментов, который делает получение пакетов и сборку исполняемых файлов невероятно простыми. Одной из самых мощных функций Go является возможность кросс-сборки исполняемых файлов для любой иностранной платформы, поддерживаемой Go. Это значительно упрощает тестирование и распространение пакетов, поскольку вам не нужно иметь доступ к определенной платформе, чтобы распространять для нее свой пакет.
В этом руководстве вы будете использовать инструменты Go для получения пакета из системы контроля версий и автоматической установки его исполняемого файла. Затем вы вручную соберете и установите исполняемый файл, чтобы ознакомиться с процессом. Затем вы создадите исполняемый файл для другой архитектуры и автоматизируете процесс сборки для создания исполняемых файлов для нескольких платформ. Когда вы закончите, вы будете знать, как создавать исполняемые файлы для Windows и macOS, а также для других платформ, которые вы хотите поддерживать.
Предпосылки
Чтобы следовать этому руководству, вам понадобятся:
- Один сервер Ubuntu 16.04, настроенный в соответствии с руководством по первоначальной настройке сервера Ubuntu 16.04, включая пользователя без полномочий root и брандмауэр.
- Go установлен, как описано в разделе Как установить Go 1.6 в Ubuntu 16.04.
Шаг 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
получить пакет и его зависимости или обновить эти зависимости, если они уже присутствуют на машине.
В этом руководстве мы установим инструкции Caddyx, мы будем использовать github.com/mholt/caddy/caddy
для пути импорта пакета. Используйте go get
, чтобы получить и установить Caddy:
- go get -u github.com/mholt/caddy/caddy
Выполнение команды займет некоторое время, но вы не увидите никакого прогресса, пока она извлекает пакет и устанавливает его. Отсутствие вывода на самом деле означает, что команда выполнена успешно.
Когда команда завершится, вы найдете исходный код Caddy, доступный по адресу $GOPATH/src/github.com/mholt/caddy
. Кроме того, поскольку у Caddy есть исполняемый файл, он был автоматически создан и сохранен в каталоге $GOPATH/bin
. Убедитесь в этом, используя what
, чтобы напечатать местоположение исполняемого файла:
- which caddy
Вы увидите следующий вывод:
Output/home/sammy/work/bin/caddy
Примечание. Команда go get
устанавливает пакеты из стандартной ветки репозитория Git, которая во многих случаях является master
или веткой, находящейся в разработке. Обязательно ознакомьтесь с инструкциями, которые обычно находятся в файле README
репозитория, прежде чем использовать go get
.
Вы можете использовать команды Git, такие как git checkout
, чтобы выбрать другую ветку в источниках, полученных с помощью команды go get
. Просмотрите руководство How to Use Git Branches, чтобы узнать больше о том, как переключать ветки.
Давайте рассмотрим процесс установки пакетов Go более подробно, начав с создания исполняемых файлов из уже полученных пакетов.
Шаг 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 — Установка исполняемого файла
Создание исполняемого файла создает исполняемый файл в текущем каталоге или каталоге по вашему выбору. Установка исполняемого файла — это процесс создания исполняемого файла и его сохранения в $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
, исполняемый файл будет доступен из любой точки вашей операционной системы. Вы можете проверить его местоположение с помощью команды what
:
- which caddy
Вы увидите следующий вывод:
Output of which/home/sammy/work/bin/caddy
Теперь, когда вы понимаете, как работают go get
, go build
и go install
и как они связаны, давайте рассмотрим один из самых популярные функции Go: создание исполняемых файлов для других целевых платформ.
Шаг 4 — Создание исполняемых файлов для разных архитектур
Команда go build
позволяет создать исполняемый файл для любой целевой платформы, поддерживаемой Go, на вашей платформе. Это означает, что вы можете тестировать, выпускать и распространять свое приложение без создания исполняемых файлов на целевых платформах, которые вы хотите использовать.
Кросс-компиляция работает путем установки необходимых переменных среды, которые определяют целевую операционную систему и архитектуру. Мы используем переменную GOOS
для целевой операционной системы и GOARCH
для целевой архитектуры. Чтобы создать исполняемый файл, команда будет иметь следующую форму:
- env GOOS=target-OS GOARCH=target-architecture go build package-import-path
Команда env
запускает программу в измененной среде. Это позволяет использовать переменные среды только для текущего выполнения команды. Переменные сбрасываются или сбрасываются после выполнения команды.
В следующей таблице показаны возможные комбинации GOOS
и GOARCH
, которые вы можете использовать:
GOOS - Target Operating System |
GOARCH - Target Platform |
---|---|
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 |
Предупреждение. Для кросс-компиляции исполняемых файлов для Android требуется Android NDK и некоторые дополнительные настройки, которые выходят за рамки этого руководства.
Используя значения в таблице, мы можем собрать Caddy для 64-битной Windows следующим образом:
- env GOOS=windows GOARCH=amd64 go build github.com/mholt/caddy/caddy
И снова отсутствие вывода указывает на то, что операция прошла успешно. Исполняемый файл будет создан в текущем каталоге, используя в качестве имени имя пакета. Однако, поскольку мы создали этот исполняемый файл для Windows, имя заканчивается суффиксом .exe
.
У вас должен быть файл caddy.exe
в вашем текущем каталоге, который вы можете проверить с помощью команды ls
.
- ls caddy.exe
Вы увидите файл caddy.exe
, указанный в выводе:
Outputcaddy.exe
Примечание. Вы можете использовать флаг -o
, чтобы переименовать исполняемый файл или поместить его в другое место. Однако при создании исполняемого файла для Windows и предоставлении другого имени обязательно явно укажите суффикс .exe
при установке имени исполняемого файла.
Давайте рассмотрим сценарий этого процесса, чтобы упростить выпуск программного обеспечения для нескольких целевых сред.
Шаг 5 — Создание скрипта для автоматизации кросс-компиляции
Процесс создания исполняемых файлов для многих платформ может быть немного утомительным, но мы можем создать сценарий, чтобы упростить задачу.
Сценарий примет путь импорта пакета в качестве аргумента, переберет предопределенный список пар операционной системы и платформы и сгенерирует исполняемый файл для каждой пары, поместив вывод в текущий каталог. Каждому исполняемому файлу будет присвоено имя пакета, за которым следует целевая платформа и архитектура в формате package-OS-architecture
. Это будет универсальный скрипт, который вы сможете использовать в любом проекте.
Перейдите в свой домашний каталог и создайте новый файл с именем go-executable-build.bash
в текстовом редакторе:
- cd ~
- nano go-executable-build.bash
Мы начнем наш скрипт со строки shebang. Эта строка определяет, какой интерпретатор будет анализировать этот скрипт, когда он запускается как исполняемый файл. Добавьте следующую строку, чтобы указать, что bash
должен выполнить этот скрипт:
#!/usr/bin/env bash
Мы хотим использовать путь импорта пакета в качестве аргумента командной строки. Для этого мы будем использовать переменную $n
, где n
— неотрицательное число. Переменная $0
содержит имя сценария, который вы выполнили, а $1
и выше будут содержать предоставленные пользователем аргументы. Добавьте эту строку в скрипт, который возьмет первый аргумент из командной строки и сохранит его в переменной с именем package
:
...
package=$1
Затем убедитесь, что пользователь предоставил это значение. Если значение не указано, выйдите из скрипта с сообщением, объясняющим, как использовать скрипт:
...
if [[ -z "$package" ]]; then
echo "usage: $0 <package-name>"
exit 1
fi
Этот оператор if
проверяет значение переменной $package
. Если он не установлен, мы используем echo
для вывода правильного использования, а затем завершаем скрипт с помощью exit
. exit
принимает в качестве аргумента возвращаемое значение, которое должно быть 0
для успешного выполнения и любое ненулевое значение для неудачного выполнения. Здесь мы используем 1
, так как сценарий не удался.
Примечание. Если вы хотите, чтобы этот скрипт работал с предопределенным пакетом, измените переменную package
, чтобы она указывала на этот путь импорта:
...
package="github.com/user/hello"
Далее мы хотим извлечь имя пакета из пути. Путь импорта пакета ограничен символами /
, а имя пакета находится в конце пути. Во-первых, мы разделим путь импорта пакета на массив, используя /
в качестве разделителя:
package_split=(${package//\// })
Имя пакета должно быть последним элементом этого нового массива $package_split
. В Bash вы можете использовать отрицательный индекс массива для доступа к массиву с конца, а не с начала. Добавьте эту строку, чтобы получить имя пакета из массива и сохранить его в переменной с именем package_name
:
...
package_name=${package_split[-1]}
Теперь вам нужно решить, для каких платформ и архитектур вы хотите создавать исполняемые файлы. В этом руководстве мы создадим исполняемые файлы для 64-разрядной версии Windows, 32-разрядной версии Windows и 64-разрядной версии macOS. Мы поместим эти цели в массив в формате ОС/Платформа
, чтобы мы могли разделить каждую пару на GOOS
и GOARCH
, используя тот же метод, который мы использовали для извлечения имени пакета из пути. Добавьте платформы в скрипт:
...
platforms=("windows/amd64" "windows/386" "darwin/amd64")
Далее мы пройдемся по массиву платформ, разделим каждую запись платформы на значения для переменных среды GOOS
и GOARCH
и используем их для создания исполняемого файла. Мы можем сделать это с помощью следующего цикла for
:
...
for platform in "${platforms[@]}"
do
...
done
Переменная platform
будет содержать запись из массива platforms
на каждой итерации. Нам нужно разделить platform
на две переменные — GOOS
и GOARCH
. Добавьте следующие строки в цикл for
:
for platform in "${platforms[@]}"
do
platform_split=(${platform//\// })
GOOS=${platform_split[0]}
GOARCH=${platform_split[1]}
done
Далее мы сгенерируем имя исполняемого файла, объединив имя пакета с ОС и архитектурой. При сборке для Windows нам также нужно добавить суффикс .exe
к имени файла. Добавьте этот код в цикл for
:
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
:
...
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
.
...
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. Вот готовый скрипт:
#!/usr/bin/env bash
package=$1
if [[ -z "$package" ]]; then
echo "usage: $0 <package-name>"
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 для получения пакетов из систем контроля версий, а также для сборки и кросс-компиляции исполняемых файлов для разных платформ.
Вы также создали скрипт, который можно использовать для кросс-компиляции одного пакета для многих платформ.
Чтобы убедиться, что ваше приложение работает правильно, вы можете проверить AppVeyor в Windows.
Если вы заинтересованы в Caddy и в том, как его использовать, взгляните на Как разместить веб-сайт с помощью Caddy в Ubuntu 16.04.