求助:Mac系统下unix.Mount未定义问题(Golang相关)

求助:Mac系统下unix.Mount未定义问题(Golang相关) 最近几天刚开始接触Go语言。

我在Ubuntu虚拟机上写了一些代码,编译和运行都很顺利。然后我决定在我的Mac工作站上进行开发,但同样的代码却无法编译。

出现以下错误:

./ds-as-mounter.go:57:9: undefined: unix.Mount
./ds-as-mounter.go:57:35: undefined: unix.MS_BIND

奇怪的是,unix.Unmount 却能正常使用。

我已经通过 go get -u golang.org/x/sys/unix 安装了unix包。

这是我的包开头部分:

package main

import (
	"fmt"
	"golang.org/x/sys/unix"
	"os"
	"regexp"
	"sync"
)

//....

这里是调用Mount和Unmount的地方:

func mount(src, dest string, wg *sync.WaitGroup) {
	defer wg.Done()
	//fmt.Println("Mounting", src, dest)
	err := unix.Mount(src, dest, "", unix.MS_BIND, "")
	if err != nil {
		fmt.Println(src, dest, err)
	}
}

func unmount(dest string, wg *sync.WaitGroup) {
	defer wg.Done()
	//fmt.Println("Unmounting", dest)
	err := unix.Unmount(dest, 0)
	if err != nil {
		fmt.Println("Unmount", dest, err)
	}
}

需要注意的是,编译器报错的是 unix.Mountunix.MS_BIND,而不是 unix.Unmount

我感到很困惑。如有任何帮助将不胜感激。谢谢!

go version go1.11.2 darwin/amd64

更多关于求助:Mac系统下unix.Mount未定义问题(Golang相关)的实战教程也可以访问 https://www.itying.com/category-94-b0.html

4 回复

mount 调用确实仅针对 Linux 系统实现。

这很合理,但我原本期望文档能反映这一点。

感谢您的帮助。

更多关于求助:Mac系统下unix.Mount未定义问题(Golang相关)的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


如果你在系统上执行 go doc 命令,它们确实会显示。不过在线文档是针对 Linux 生成的。

mount 调用确实仅在 Linux 系统中实现。

jb@kvin:~/g/s/g/x/s/unix $ git grep Mount\(
syscall_linux.go:func Mount(source string, target string, fstype string, flags uintptr, data string) (err error) {

Unmount 在更多平台上得到了实现。如果让我推测,我会说 Unmount 之所以"简单",是因为它在各个系统上的行为大致相同。而另一方面,Mount 需要处理大量标志和选项,这些都与具体系统和文件系统密切相关。

例如,macOS 并不支持您尝试实现的绑定挂载功能,因此无法在此系统上实现该操作。

问题在于 golang.org/x/sys/unix 包在不同操作系统上的实现不同。在 macOS 上,unix.Mountunix.MS_BIND 确实未定义,因为 macOS 使用不同的挂载机制(通过 syscall.Mount 实现)。

以下是解决方案:

1. 使用构建标签区分不同平台

创建两个文件,通过构建标签处理平台差异:

mount_linux.go(用于 Linux):

// +build linux

package main

import "golang.org/x/sys/unix"

func mount(src, dest string) error {
    return unix.Mount(src, dest, "", unix.MS_BIND, "")
}

func unmount(dest string) error {
    return unix.Unmount(dest, 0)
}

mount_darwin.go(用于 macOS):

// +build darwin

package main

import (
    "syscall"
)

func mount(src, dest string) error {
    // macOS 使用 syscall.Mount 和不同的标志
    return syscall.Mount(src, dest, "", syscall.MS_BIND, "")
}

func unmount(dest string) error {
    return syscall.Unmount(dest, 0)
}

2. 在主要代码中使用统一的函数调用

修改你的主文件:

package main

import (
    "fmt"
    "sync"
)

func mount(src, dest string, wg *sync.WaitGroup) {
    defer wg.Done()
    err := mount(src, dest)
    if err != nil {
        fmt.Println(src, dest, err)
    }
}

func unmount(dest string, wg *sync.WaitGroup) {
    defer wg.Done()
    err := unmount(dest)
    if err != nil {
        fmt.Println("Unmount", dest, err)
    }
}

3. 或者使用条件编译的常量定义

在同一个文件中处理:

package main

import (
    "fmt"
    "sync"
)

// 根据平台导入不同的包
// +build linux
import "golang.org/x/sys/unix"

// +build darwin
import "syscall"

func mount(src, dest string, wg *sync.WaitGroup) {
    defer wg.Done()
    
    var err error
    // 根据平台使用不同的挂载函数
    // +build linux
    err = unix.Mount(src, dest, "", unix.MS_BIND, "")
    
    // +build darwin  
    err = syscall.Mount(src, dest, "", syscall.MS_BIND, "")
    
    if err != nil {
        fmt.Println(src, dest, err)
    }
}

验证 macOS 上的可用常量:

在 macOS 上,可以检查 syscall 包中可用的常量:

package main

import (
    "fmt"
    "syscall"
)

func main() {
    // 检查 macOS 上可用的挂载相关常量
    fmt.Printf("MS_BIND: %v\n", syscall.MS_BIND)
}

关键点是:golang.org/x/sys/unix 包在不同操作系统上暴露的 API 不同,macOS 不支持 Linux 风格的 unix.Mount 函数,需要使用系统原生的 syscall.Mount

回到顶部