Как использовать условную компиляцию в Go

Go

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

В Go нет предварительной обработки, нет системы определения макросов, и его нельзя использовать как язык C.#defineчтобы контролировать, включен ли код для конкретной платформы. Вместо этого Go используетпакет go/buildСистема маркировки, определенная в (system of tags) и соглашения об именах (naming convention)а такжеgo toolСоответствующая поддержка, чтобы разрешить Go Go Packages для компиляции конкретного кода.

Эта статья объясняет условную компиляцию, как добиться, и как использовать его в своих собственных проектах.

во-первыхgo list

Прежде чем обсуждать условную компиляцию, нам нужно кратко обсудитьgo listЗаказ.go listПозволяет получить доступ к структурам данных внутри пакета для управления процессом сборки.

go listбольшинство параметров иgo build,go test,go installТо же самое, но он не выполняет компиляцию. использовать-fПараметры форматирования, мы можем заполнить абзацtext/templateкод шаблона, он будет в содержащемgo/build.PackageКонтекст структуры выполняется.
В следующем примере вы можете получить имена всех файлов исходного кода, которые будут скомпилированы.

% go list -f '{{.GoFiles}}' os/exec
[exec.go lp_unix.go]

Этот пример запрашивает мою текущую среду выполненияlinux/armВнизos/execФайлы в пакете, который будет скомпилирован. Есть два файла результатов:exec.goсодержит общий код, общий для всех платформ,lp_unix.goсодержитunix-likeуникальный для системыexec.LookPathвыполнить.

Если я выполню указанную выше команду в системе Windows, результат будет следующим:

C:\go> go list -f '{{.GoFiles}}' os/exec
[exec.go lp_windows.go]

Этот короткий пример демонстрирует систему условной компиляции Go, известную какОграничения сборки, о чем подробнее будет сказано далее.

Создать теги

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

Комментарии для тегов сборки следует размещать как можно ближе к началу исходного файла.

Когда Go компилирует пакет, он анализирует каждый исходный файл в пакете и ищет теги сборки. Тег определяет, скомпилирован исходный файл или нет.

Вкладка Build следует трем принципам:

  1. Варианты, разделенные пробелом, представляют собой отношение ИЛИ (ИЛИ)
  2. Варианты, разделенные запятыми, - И (И)
  3. Каждый вариант состоит из букв и цифр. если ему предшествует!, значит наоборот
// +build darwin freebsd netbsd openbsd

В приведенном выше примере тег сборки появляется в верхней части исходного файла, указывая на то, что исходный файл будет поддерживать толькоkqueueСкомпилировано на BSD-системах.

Исходный файл может содержать несколько тегов сборки. Правила сборки — это логика и взаимосвязь каждого отдельного правила. Следующий пример означает, что файл будет находиться вlinux/386илиdarwin/386платформа будет скомпилирована.

// +build linux darwin
// +build 386

Дополнительные примечания к примечаниям

Распространенная ошибка при первом использовании тегов сборки заключается в следующем:

// +build !linux
package mypkg // 错误

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

// +build !linux

package mypkg // 正确

Примечание переводчика yoko, в исходном тексте здесь есть описание, что при выполнении go vet в правильном формате будет сообщено о следующей ошибке
+build comment appears too late in file
Я сделал простой тест, и выполнение go vet в правильном формате не сообщит об ошибке, наоборот, неправильный формат сообщит о следующей ошибке
+build comment must appear before package clause and be followed by a blank line
Я думаю, это должна быть новая версия go to go ветеринар был улучшен, и среда, когда я тестировал ее, былаgo version go1.12.5 darwin/amd64

Вот пример, включающий лицензии, теги сборки и объявления пакетов:

% head headspin.go
// Copyright 2013 Way out enterprises. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build someos someotheros thirdos,!amd64

// Package headspin implements calculates numbers so large
// they will make your head spin.
package headspin

Суффиксы файлов

Второй метод условной компиляции — через имя исходного файла. Эта схема проще, чем построение схемы этикетки.

go/buildВ документации к пакету есть описание соглашения об именах. Проще говоря, если имя файла содержит_$GOOS.goсуффикс, то файл исходного кода будет скомпилирован только на соответствующей платформе. Другие платформы игнорируют этот файл. Еще одна конвенция_$GOARCH.go. Эти два суффикса можно комбинировать, но порядок гарантирован, правильный формат_$GOOS_$GOARCH.go, неправильный формат_$GOARCH_$GOOS.go.

Вот несколько примеров суффиксов имен файлов:

mypkg_freebsd_arm.go // 只在 freebsd/arm 系统编译
mypkg_plan9.go       // 只在 plan9 编译

Недостаточно, чтобы исходный файл имел суффикс, например следующее имя файла:

_linux.go
_freebsd_386.go

Даже в системах Linux или FreeBSD эти два файла игнорируются, потому чтоgo/buildПакет игнорирует все имена файлов, начинающиеся с.и_стартовый файл.

Используйте теги сборки или суффиксы имен файлов

Теги сборки и суффиксы имен файлов функционально перекрываются. Например, названныйmypkg_linux.goФайл, а затем конструкция, содержащая метку// +build linuxБудет больше.

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

mypkg_linux.go         // 只在 linux 系统编译
mypkg_windows_amd64.go // 只在 windows amd 64位 平台编译

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

// 在所有类unix平台编译
% grep '+build' $HOME/go/src/pkg/os/exec/lp_unix.go
// +build darwin dragonfly freebsd linux netbsd openbsd

// 在非Windows平台编译
% grep '+build' $HOME/go/src/pkg/os/types_notwin.go
// +build !windows

Суммировать

Эта статья посвящена только исходным файлам Go. Фактически, теги сборки и суффиксы имен файлов могут применяться к любому исходному файлу, который может скомпилировать инструмент go, включая.cи.sдокумент. В стандартной библиотеке GO, особенно в пакетах Runtime, Syscall, OS и NET, содержится большое количество этого примера.

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

Наконец, в этой статье обсуждаетсяgo tool, на самом деле функция условной компиляции не ограничивается этим инструментом. ты можешь пройтиgo/buildПакет создает ваши собственные инструменты для анализа суффиксов имен файлов и создания синтаксиса тегов.

Эта статья переведена из книги Дэйва Чейни «Как использовать условную компиляцию с инструментом go build».Dave.Cheney.net/2013/10/12/…