При разработке программного обеспечения очень важно учитывать операционную систему и архитектуру процессора, для которого вы будете компилировать ваш бинарный файл. Поскольку часто бывает очень трудно или просто невозможно запустить один бинарный файл на разных ОС/архитектурах, довольно распространенной практикой является сборка итогового бинарного файла для набора различных платформ для максимального увеличения аудитории вашей программы. Однако это может оказаться затруднительным, когда платформа, которую вы используете для разработки, отличается от платформы, где вы хотите развернуть вашу программу. В прошлом, например, при разработке программы на Windows и ее последующем развертывании на компьютере с Linux или macOS могла требоваться настройка инструмента для сборки для каждой среды, где вам требуется бинарный файл. Кроме того, вам нужно поддерживать ваш инструментарий в синхронизированном состоянии, а также учитывать другие моменты, что будет приводить к росту издержек и затруднит совместное тестирование и распространение.
Go решает эту проблему посредством поддержки различных платформ напрямую в инструменте go build
, а также в остальной цепочке инструментов Go. Используя переменные среды и теги сборки, вы можете контролировать, для какой ОС и архитектуры предназначен ваш бинарный файл, а также реализовать рабочий процесс, который позволит быстро добавлять предназначенный для конкретной платформы код без внесения изменений в базу вашего кода.
В этом руководстве вы создадите пример приложения, которое будет соединять строки в путь файла, создадите и будете избирательно включать предназначенные для конкретной платформы сниппеты кода, а также выполните сборку бинарных файлов для различных операционных систем и архитектур в вашей собственной системе, что позволит вам понять, как использовать этот мощный функционал языка программирования Go.
Для выполнения примера из этой статьи вам потребуется следующее:
GOOS
и GOARCH
Прежде чем продемонстрировать, как вы можете контролировать процесс сборки бинарных файлов для различных платформ, давайте узнаем, для каких платформ Go в состоянии выполнять сборку, а также как Go ссылается на эти платформы, используя переменные среды GOOS
и GOARCH
.
Инструменты Go имеют команду, которая может вывести список поддерживаемых Go платформ для сборки. Этот список может меняться с каждым новым релизом Go, так что описанные здесь комбинации могут быть иными в другой версии Go. На момент написания настоящего руководства текущая версия Go — 1.13
.
Чтобы просмотреть список поддерживаемых платформ, запустите следующую команду:
- go tool dist list
Вы получите примерно следующий результат:
Outputaix/ppc64 freebsd/amd64 linux/mipsle openbsd/386
android/386 freebsd/arm linux/ppc64 openbsd/amd64
android/amd64 illumos/amd64 linux/ppc64le openbsd/arm
android/arm js/wasm linux/s390x openbsd/arm64
android/arm64 linux/386 nacl/386 plan9/386
darwin/386 linux/amd64 nacl/amd64p32 plan9/amd64
darwin/amd64 linux/arm nacl/arm plan9/arm
darwin/arm linux/arm64 netbsd/386 solaris/amd64
darwin/arm64 linux/mips netbsd/amd64 windows/386
dragonfly/amd64 linux/mips64 netbsd/arm windows/amd64
freebsd/386 linux/mips64le netbsd/arm64 windows/arm
Данный вывод — это набор пар ключ-значение, разделенных /
. Первая часть комбинации перед символом /
— это операционная система. В Go эти операционные системы — это возможные значения для переменной среды GOOS
, произносится “goose”, название которой означает операционная система Go. Вторая часть, идущая после /
, — это архитектура. Как и в случае с операционной системой, это все возможные значения для переменной среды: GOARCH
. Это сокращение произносится “gore-ch” и означает архитектура Go.
Давайте разберем одну из этих комбинаций, чтобы понять, что это означает и как работает, воспользовавшись linux/386
в качестве примера. Пара ключ-значение начинается с переменной GOOS
, которая в этом случае будет linux
, то есть ОС Linux. Для GOARCH
здесь указано значение 386
, что означает микропроцессор Intel 80386.
Существует множество доступных для команды go build
платформ, но в большинстве случаев вы будете использовать linux
, windows
или darwin
в качестве значения для GOOS
. Это позволяет покрыть три важнейшие платформы OS: Linux, Windows и macOS, которая основана на операционной системе Darwin и поэтому называется darwin
. Однако Go позволяет охватить и менее популярные платформы, например nacl
, т. е. Native Client от Google.
Когда вы запускаете команду, например go build
, Go использует GOOS
и GOARCH
для определения способа сборки бинарного файла. Чтобы узнать, какая конфигурация у вашей платформы, вы можете использовать команду go env
и передать GOOS
и GOARCH
в качестве аргументов:
- go env GOOS GOARCH
При тестировании этого примера мы запускаем эту команду в macOS на компьютере с архитектурой AMD64, поэтому мы получим следующее:
Outputdarwin
amd64
Здесь вывод команды указывает нам, что в нашей системе GOOS=darwin
и GOARCH=amd64
.
Теперь вы знаете, что такое GOOS
и GOARCH
в Go, а также их возможные значения. Далее вы выполните сборку программы для использования в качестве примера использования этих переменных среды и меток сборки для получения бинарных файлов для других платформ.
filepath.Join()
Прежде чем начать сборку бинарных файлов для других платформ, мы создадим пример программы. Для этой задачи отлично подходит функция Join
в пакете path/filepath
в стандартной библиотеке Go. Эта функция получает ряд строк и возвращает одну строку, к которой добавлен соответствующий разделитель пути файла.
Это отличный пример программы, поскольку работа программы зависит от того, в какой ОС она запущена. Для Windows разделитель пути файла — это обратный слэш \
, а в системах Unix используется прямой слэш /
.
Давайте начнем сборку приложения, которое использует filepath.Join()
, а затем вы напишете свою собственную реализацию функции Join()
, которая настраивает код в соответствии с платформой.
Во-первых, создайте папку в директории src
с именем вашего приложения:
- mkdir app
Перейдите в эту директорию:
- cd app
Далее создайте новый файл в текстовом редакторе по вашему выбору с именем main.go
. В этом обучающем руководстве мы будем использовать Nano:
- nano main.go
После открытия файла добавьте следующий код:
package main
import (
"fmt"
"path/filepath"
)
func main() {
s := filepath.Join("a", "b", "c")
fmt.Println(s)
}
Функция main()
в этом файле использует filepath.Join()
для конкатенации трех строк вместе с правильным платформо-зависимым разделителем пути.
Сохраните и закройте файл, а затем запустите программу:
- go run main.go
При запуске этой программы вы получите разный вывод в зависимости от того, какую платформу вы используете. В Windows вы увидите, что строки будут разделены \
:
Outputa\b\c
В системах Unix, в том числе macOS и Linux, вы получите следующее:
Outputa/b/c
Это означает, что из-за разных протоколов файловой системы, используемых в этих операционных системах, программа должна будет выполнять разный код для различных платформ. Однако поскольку в ней уже используется разный разделитель пути файла в зависимости от операционной системы, мы знаем, что filepath.Join()
уже учитывает различие в платформе. Это вызвано тем, что цепь инструментов Go автоматически определяет GOOS
и GOARCH
на вашем компьютере и использует эту информацию для применения сниппета кода с правильными маркерами сборки и разделителем файла.
Давайте рассмотрим, откуда функция filepath.Join()
получает нужный разделитель. Запустите следующую команду для просмотра соответствующего сниппета из стандартной библиотеки Go:
- less /usr/local/go/src/os/path_unix.go
В результате вы увидите содержимое path_unix.go
. Найдите следующую часть файла:
. . .
// +build aix darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris
package os
const (
PathSeparator = '/' // OS-specific path separator
PathListSeparator = ':' // OS-specific path list separator
)
. . .
В этом разделе определяется PathSeparator
для всех разновидностей Unix-систем, которые поддерживает Go. Обратите внимание на все маркеры сборки сверху, каждый из которых является одним из возможных значений платформ Unix для GOOS
. Когда GOOS
соответствует этим терминам, ваша программа будет выводить разделитель файла в стиле Unix.
Нажмите q
для возврата к командной строке.
Далее откройте файл, который определяет поведение filepath.Join()
при использовании в Windows:
- less /usr/local/go/src/os/path_windows.go
Вы увидите следующее:
. . .
package os
const (
PathSeparator = '\\' // OS-specific path separator
PathListSeparator = ';' // OS-specific path list separator
)
. . .
Хотя здесь значение PathSeparator
будет \\
, код будет отображать отдельный обратный слэш (\
), необходимый для путей файлов в Windows, поскольку первый обратный слэш требуется только в качестве символа перехода.
Обратите внимание, что в отличие от файла Unix, сверху нет меток сборки. Это объясняется тем, что GOOS
и GOARCH
также могут быть переданы команде go build
, добавив нижнее подчеркивание (_
) и значение переменной среды в качестве суффикса для имени файла. Мы обсудим это подробнее в разделе Использование суффиксов имен файлов GOOS и GOARCH. Здесь часть _windows
названия имени path_windows.go
заставляет файл вести себя так, будто у него есть маркер сборки // +build windows
в верхней части файла. В связи с этим, когда ваша программа запускается в Windows, она будет использовать константы PathSeparator
и PathListSeparator
из сниппета кода path_windows.go
.
Чтобы вернуться к командной строке, выйдите из less
, нажав q
.
На этом шаге вы создали программу, показывающую, как Go автоматически преобразовывает GOOS
и GOARCH
в маркеры сборки. Держа это в уме, вы можете обновить вашу программу и написать свою собственную реализацию filepath.Join()
, используя маркеры сборки, чтобы вручную задать правильный PathSeparator
для платформ Windows и Unix.
Теперь, когда вы знаете, как стандартная библиотека Go имплементирует специфичный для платформы код, вы можете использовать маркеры сборки, чтобы сделать это в вашей собственной программе app
. Для этого вам нужно будет написать свою собственную реализацию filepath.Join()
.
Откройте ваш файл main.go
:
- nano main.go
Замените содержимое main.go
на следующее, используя свою собственную функцию с именем Join()
:
package main
import (
"fmt"
"strings"
)
func Join(parts ...string) string {
return strings.Join(parts, PathSeparator)
}
func main() {
s := Join("a", "b", "c")
fmt.Println(s)
}
Функция Join
получает ряд частей
и объединяет их вместе с помощью метода strings.Join()
из пакета strings
для конкатенации частей
, используя PathSeparator
.
Вы еще не определили PathSeparator
, поэтому давайте сделаем это в другом файле. Сохраните и выйдите из main.go
, откройте ваш любимый редактор и создайте новый файл с именем path.go
:
nano path.go
Определите PathSeparator
и установите его равным разделителю пути файла Unix /
:
package main
const PathSeparator = "/"
Скомпилируйте и запустите приложение:
- go build
- ./app
Вывод должен выглядеть следующим образом:
Outputa/b/c
Это значит, что программа успешно запускается для получения пути файла в стиле Unix. Однако это еще не то, что нам нужно: вывод всегда будет a/b/c
, вне зависимости от того, на какой платформе программа запущена. Чтобы добавить функционал создания пути файла в стиле Windows, вам нужно добавить версию PathSeparator
для Windows и указать команде go build
, какую версию следует использовать. В следующем разделе вы сможете воспользоваться маркерами сборки, чтобы выполнить эту задачу.
GOOS
или GOARCH
Чтобы учитывать платформы Windows, вы создадите альтернативный файл для path.go
и будете использовать маркеры сборки, чтобы убедиться, что сниппеты кода запускаются, только когда GOOS
и GOARCH
принадлежат к соответствующей платформе.
Однако сначала нужно добавить маркер сборки в path.go
, чтобы указать ему на необходимость выполнять сборку для любых платформ, кроме Windows. Откройте файл:
- nano path.go
Добавьте в файл выделенный маркер сборки:
// +build !windows
package main
const PathSeparator = "/"
Маркеры сборки Go позволяют использовать инвертирование, что означает, что вы можете указать Go выполнить сборку этого файла для любой платформы, кроме Windows. Чтобы инвертировать маркер доступа, добавьте !
перед маркером.
Сохраните и закройте файл.
Теперь, если бы вы захотели запустить эту программу в Windows, то получили бы следующую ошибку:
Output./main.go:9:29: undefined: PathSeparator
В данном случае Go не сможет включить path.go
для определения переменной PathSeparator
.
Теперь, когда вы убедились, что path.go
не будет запускаться, когда для GOOS
используется значение Windows, добавьте новый файл, windows.go
:
- nano windows.go
В файле windows.go
необходимо определить PathSeparator
для Windows, а также маркер сборки, чтобы команда go build
смогла понимать, что это реализация для Windows:
// +build windows
package main
const PathSeparator = "\\"
Сохраните файл и выйдите из текстового редактора. Теперь приложение может компилироваться одним образом для Windows, а другим образом для всех остальных платформ.
Хотя теперь сборка бинарных файлов будет выполняться корректно для соответствующих платформ, есть и другие изменения, которые нужно внести для выполнения компиляции для платформы, к которой у вас нет доступа. Для этого на следующем шаге нам нужно будет изменить локальные переменные GOOS
и GOARCH
.
GOOS
и GOARCH
Ранее вы запускали команду go env GOOS GOARCH
для получения информации о том, в какой ОС и с какой архитектурой вы работаете. При запуске команды go env
выполняется поиск двух переменных среды GOOS
и GOARCH
; если их удалось найти, будут использоваться их значения, но если они не были найдены, Go будет использовать для них информацию для текущей платформы. Это означает, что вы можете изменить значения GOOS
или GOARCH
, чтобы они не совпадали по умолчанию с данными локальной операционной системы и архитектуры.
Команда go build
ведет себя примерно так же, как и команда go env
. Вы можете задать для переменных среды GOOS
или GOARCH
значение для получения сборки для другой платформы с помощью команды go build
.
Если вы не используете систему Windows, создайте бинарный файл windows
для app
, установив для переменной среды GOOS
значение windows
при запуске команды go build
:
- GOOS=windows go build
Теперь вы можете вывести файлы в вашей текущей директории:
- ls
Вывод списка файлов в директории теперь показывает, что в директории проекта есть исполняемый файл app.exe
для Windows:
Outputapp app.exe main.go path.go windows.go
Используя команду file
, вы можете получить дополнительную информацию об этом файле, подтвердив его сборку:
- file app.exe
Вы получите следующий результат:
Outputapp.exe: PE32+ executable (console) x86-64 (stripped to external PDB), for MS Windows
Также вы можете задать значение для одной или обеих переменных среды во время сборки. Запустите следующую команду:
- GOOS=linux GOARCH=ppc64 go build
Теперь ваш исполняемый файл app
будет заменен файлом для другой архитектуры. Запустите команду file
для этого бинарного файла:
- file app
Вывод будет выглядеть следующим образом:
app: ELF 64-bit MSB executable, 64-bit PowerPC or cisco 7500, version 1 (SYSV), statically linked, not stripped
Задав значения для ваших локальных переменных среды GOOS
и GOARCH
, вы можете выполнить сборку бинарных файлов для любой из совместимых с Go платформ без сложной конфигурации или настройки. Далее вы будете использовать соглашения для имен файлов, чтобы четко организовать ваши файлы, и выполнять сборку для конкретных платформ автоматически без маркеров для сборки.
GOOS
и GOARCH
Как вы уже видели ранее, в стандартной библиотеке Go активно используются маркеры сборки для упрощения кода, что позволяет разделять реализации для разных платформ в разных файлах. Когда вы открывали файл os/path_unix.go
, там был маркер сборки, который содержал список всех возможных комбинаций, рассматриваемых в качестве Unix-платформ. Однако в файле os/path_windows.go
отсутствуют маркеры для сборки, поскольку суффикса в имени файла достаточно, чтобы Go мог понять, для какой платформы предназначен этот файл.
Давайте рассмотрим синтаксис этого элемента. При присвоении имени файла .go
вы можете добавить GOOS
и GOARCH
в качестве суффиксов к имени файла в этом порядке, отделяя значения нижним подчеркиванием (_
). Если у вас есть файл Go с именем filename.go
, вы можете указать ОС и архитектуру, изменив имя файла на filename_GOOS_GOARCH.go
. Например, если вы хотите скомпилировать его для Windows с 64-битной архитектурой ARM, вы должны использовать имя файла filename_windows_arm64.go
. Такое соглашение о наименованиях помогает поддерживать код в организованном виде.
Обновите вашу программу для использования суффиксов имени файла вместо маркеров сборки. Во-первых, переименуйте файл path.go
и windows.go
для использования соглашения, используемого в пакете os
:
- mv path.go path_unix.go
- mv windows.go path_windows.go
После изменения имен двух файлов вы можете удалить маркер сборки, который вы добавили в path_windows.go
:
- nano path_windows.go
Удалите // +build windows
, чтобы ваш файл выглядел следующим образом:
package main
const PathSeparator = "\\"
Сохраните и закройте файл.
Поскольку unix
— это недействительное значение для GOOS
, суффикс _unix.go
не будет иметь значение для компилятора Go. Однако он передает предполагаемое назначение файла. Как и в файле os/path_unix.go
, ваш файл path_unix.go
все еще требует использования маркеров для сборки, поэтому этот файл будет сохранен без изменений.
Используя соглашение о наименовании файлов, вы удалили ненужные маркеры сборки из исходного кода и сделали файловую систему более понятной и четкой.
Возможность генерации бинарных файлов для различных платформ, не требующих зависимостей, является очень ценной функцией цепочки инструментов Go. В этом обучающем руководстве вы использовали эту возможность, добавляя маркеры сборки и суффиксы для имен файлов, чтобы пометить определенные сниппеты кода, которые будут компилироваться только для определенных архитектур. Вы создали собственную платформо-зависимую программу, а затем выполняли манипуляции с переменными среды GOOS
и GOARCH
для получения бинарных файлов для других платформ, помимо вашей текущей платформы. Это очень ценная возможность, поскольку очень часто используется процесс непрерывной интеграции, который автоматически запускается с помощью этих переменных среды для сборки бинарных файлов для всех платформ.
Для дальнейшего знакомства с go build
вы можете ознакомиться с нашим руководством по настройке бинарных файлов в Go с помощью маркеров сборки. Если вы хотите узнать больше о языке программирования Go в целом, ознакомьтесь с нашей серией статей о программировании на языке Go.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!
This comment has been deleted