在 Go 中封装平台特定代码的正确方法是什么?

What is the right approach to encapsulate platform specific code in Go?

我想开发一个小的 Go 应用程序,它向演示文稿的听众显示使用的快捷键。

要连接到键盘事件,我将不得不使用一些特定于平台的代码。 封装特定平台代码的 Go 方法是什么?我一直在搜索编译器开关或平台模块等关键字,但我真的找不到相关内容。

平台特定代码的解决方案是build constraints

注意: 在 Go 1.17 之前,语法是以 // +build 开头的注释行,但 Go 1.17 引入了 //go:build pragma 现在是首选方式。

A build constraint, also known as a build tag, is a line comment that begins

//go:build

that lists the conditions under which a file should be included in the package. Constraints may appear in any kind of source file (not just Go), but they must appear near the top of the file, preceded only by blank lines and other line comments. These rules mean that in Go files a build constraint must appear before the package clause.

所以基本上每个平台特定的 Go 代码都应该放在不同的文件中,您可以用它们的目标标记每个 Go 文件。

例如,如果文件包含 Linux 特定代码(例如系统调用),则以:

开头
//go:build linux

如果文件包含 Windows 个特定的系统调用,则以:

开头
//go:build windows

还有很多可用的“选项”,请阅读链接文档。例如,您可以指定对 OS、体系结构、Go 版本、正在使用的编译器的约束。您还可以指定将用逻辑 OR 或 AND 解释的多个约束,或者您可以使用否定(例如,此代码适用于除 linux 之外的每个目标平台)。

您甚至可以使用以下约束将 .go 文件标记为忽略:

//go:build ignore

请注意,构建约束是特定于编译器的。如果特定编译器无法识别构建约束,则编译器将忽略该文件。例如,Go AppEngine SDK 带有一个内置的、经过修改的 Go 编译器,它还可以识别

//go:build appengine

约束,这意味着源文件仅适用于 Google App Engine 平台。 “常规”Go 编译器将忽略该文件,如果有人试图在没有 Go AppEngine SDK 的情况下构建代码,您可能不会遇到一堆编译器错误。

虽然 绝对是对 OP 关于条件编译的问题的正确权威回答,但在这种特定情况下,更简单的方法可能是值得的。

Go 是一种旨在在每个平台上编译相同(使用相同的编译器)的语言,以鼓励跨平台代码和库重用。 Go 不是 C/C++,为此必须花时间编写明确的跨平台代码。

当然,平台不可知性仅适用于 Go 的运行时,并且您正在尝试捕获按键,对此没有真正的单一平台不可知解决方案。

因此,我对这个用例的更简单的建议类似于以下内容:

package main

import (
    "runtime"
    kp "kplib"
)

func main () {
    switch runtime.GOOS {
    case "windows":
        kp.WinKey()
    case "darwin":
        kp.MacKey()
    case "linux":
        kp.UnixKey()
    default:
        kp.TryKey()
    }
}

有了隐含的保证,假设的 kplib 将在任何地方编译(只要确保在给定平台上调用正确的方法!)。

要制作代码 platform-specific,您可以选择 build constraintsFor more info

Windows

//go:build windows
// +build windows

不是Windows

//go:build !windows
// +build !windows

不是 Windows & 达尔文

//go:build !windows && !darwin
// +build !windows,!darwin

Mac

//go:build darwin
// +build darwin

Linux

//go:build linux
// +build linux

例子

//go:build windows
// +build windows

package main

func main() {
   // windows specific code
}

或者您可以将代码放在单独的文件中,用于不同的 OS 和 file naming convention

例如:-

路径

  • path.go
  • path_windows.go
  • path_darwin.go
  • path_linux.go

Building go applications for different OS & Architecture