Поиск по сайту:

Как создавать исполняемые файлы 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:

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

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

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

  1. 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 и укажите путь импорта пакета:

  1. go build github.com/mholt/caddy/caddy

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

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

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

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

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

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

Шаг 3 — Установка исполняемого файла

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

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

  1. go install github.com/mholt/caddy/caddy

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

  1. which caddy

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

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

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

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

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

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

  1. 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 следующим образом:

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

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

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

  1. ls caddy.exe

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

Output
caddy.exe

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

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

Шаг 5 — Создание скрипта для автоматизации кросс-компиляции

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

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

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

  1. cd ~
  2. 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:

  1. chmod +x go-executable-build.bash

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

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

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

  1. ls caddy*

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

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

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

Заключение

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

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

Чтобы убедиться, что ваше приложение работает правильно, вы можете проверить AppVeyor в Windows.

Если вы заинтересованы в Caddy и в том, как его использовать, взгляните на Как разместить веб-сайт с помощью Caddy в Ubuntu 16.04.