我已经阅读了一些使用syscall
的Go代码,用于与基础操作系统(例如Linux或Windows)进行低级交互。
我想使用相同的程序包进行本机Windows开发,但阅读其文档说它不推荐使用golang/x/sys
:
$ go doc syscall
package syscall // import "syscall"
Package syscall contains an interface to the low-level operating system
primitives.
...
Deprecated: this package is locked down. Callers should use the
corresponding package in the golang.org/x/sys repository instead. That is
also where updates required by new systems or versions should be applied.
See https://golang.org/s/go1.4-syscall for more information.
现在,阅读golang/x/sys
的文档并检查其代码,它高度依赖并鼓励使用syscall
软件包:
https://github.com/golang/sys/blob/master/windows/svc/example/beep.go
package main
import (
"syscall"
)
var (
beepFunc = syscall.MustLoadDLL("user32.dll").MustFindProc("MessageBeep")
)
func beep() {
beepFunc.Call(0xffffffff)
}
和
https://godoc.org/golang.org/x/sys/windows#example-LoadLibrary
...
r, _, _ := syscall.Syscall(uintptr(proc), 0, 0, 0, 0)
...
为什么golang/x/sys
依赖并鼓励使用它打算替换的软件包?
答案 0 :(得分:4)
免责声明:我是Go语言的新手(尽管不是低级OS编程的人)。不过,这里的路径似乎很清楚。
作为一个生态系统,不仅是语言本身,而且还包括所有各种库,请尝试 1 进行移植。但是直接系统调用几乎是不可移植的。因此,这里会自动出现张力。
为了做任何有用的事情,Go运行时需要操作系统提供的 各种服务,例如创建OS级线程,发送和接收信号,打开文件和网络连接等等。 。从如何在操作系统A,B和C上完成操作,到现在,这些操作中的许多操作已被抽象化,成为大多数或所有OS支持的通用概念 。这些抽象基于各种操作系统中的实际机制。
他们甚至可以在内部分层执行此操作。例如,查看Go source for the os
package会显示file.go
,file_plan9.go
,file_posix.go
,file_unix.go
和file_windows.go
源文件。 file_posix.go
的顶部显示了一个+build
指令:
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build aix darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris windows
很明显,此代码本身不是 完全可移植的,但是它为os
实现的例程由os.File
抽象包装,对于所有符合POSIX的系统都足够。例如,这减少了必须在特定于Unix / Linux的files_unix.go
文件中进行处理的代码量。
在某种程度上,可以将操作系统级别的操作包装为更抽象,更可移植的操作,然后,各种内置的Go软件包即可执行此操作。您不需要知道是否存在用于打开设备文件,文本文件,二进制文件的不同系统调用,或者长路径名与短路径名的打开:您只需调用os.Create
或os.Open
,它会在幕后进行任何必要的工作。
这整个想法与系统调用无关。创建新的UID名称空间的Linux系统调用没有Windows等效项。 2 Windows WaitForMultipleObjects
系统调用在Linux上没有等效项。 stat / lstat调用的低级详细信息因一个系统而异,依此类推。
在Go的早期版本中,曾尝试使用syscall
软件包来对此进行书写。但是您引用的链接https://golang.org/s/go1.4-syscall将这种尝试描述为(如果没有失败的话)至少是过度拉伸的话。 “问题”部分的最后一个单词是“问题”。
同一链接上的建议说syscall
软件包从Go 1.4开始将被冻结(或大部分被冻结):不要在其中添加新功能。但是中的功能足以实现新的,实验性的golang.org/x/sys/*
包或至少其中一些功能。如果这样做可以满足实验性新程序包的需要,那么借用现有的,已正式弃用的syscall
程序包对实验程序包没有任何危害。
golang.org/x/
中的内容是实验性的:可以随意使用它们,但是请注意,与标准软件包中的内容不同,版本更新中没有兼容性保证。因此,要回答您问题的最后一行:
为什么
golang/x/sys
依靠[鼓励]并鼓励使用要替换的软件包?
依赖 syscall
,因为这很好。不过,它根本不“鼓励使用” syscall
。只要足够,它就会使用。如果由于任何原因而变得不够用,它将停止依赖它。
回答一个您没有问过的问题(但是我回答了):假设您想要有关文件的特定于Unix的stat
信息,例如其inode号。您可以选择:
info, err := os.Stat(path) // or os.Lstat(path), etc
if err != nil { ... handle error ... }
raw, ok := info.Sys().(*syscall.Stat_t)
if !ok { ... do whatever is appropriate ... }
inodeNumber := raw.Ino
或:
var info unix.Stat
err := unix.Stat(path, &info) // or unix.Lstat, etc
if err != nil { ... handle error ... }
inodeNumber := unix.Ino
第一段代码的优点是,您可以获得有关文件的所有 other (便携式)信息,例如,文件的模式,大小和时间戳。您也许知道,也许没有得到索引节点号。 !ok
案例告诉您是否这样做。这里的主要缺点是,这样做需要更多的代码。
第二个代码块的优点是它可以说出您的意思。您可以从stat
调用中获取所有信息,也可以不获取任何信息。缺点很明显:
因此,这取决于您,其中哪个更重要。
1 或者这是一个隐喻,或者我只是将其拟人化了。有一个古老的规则:不要对计算机进行拟人化,他们讨厌那样!
2 Linux UID名称空间从容器内的UID映射到容器外的UID。也就是说,在容器内部,文件可能归UID 1234拥有。如果该文件位于也安装在容器外部的文件系统中,则该文件可以由另一个所有者(也许是5678)拥有。容器的“一侧”在该侧的名称空间中进行了更改;更改是通过名称空间映射对ID进行映射或反向映射的结果。
(例如,同样的技巧也适用于NFS UID映射。上面的Docker容器示例仅是一种用途,但可能是当今最引人注目的一种。)