golang 中不同系统不同实现的交叉编译问题

事情是这样的,在一个项目中,我需要读取系统中的某个文件的创建时间,根据时间做不同的处理,如超过一定时间后就删除掉。 查询了一下,获取文件创建时间可以使用标准库中的os 和 syscall 来完成,但是syscall该库在不同的系统中的接口是不一样的,如在Mac下是这样使用的

package main

import (
	"fmt"
	"os"
	"syscall"
)

func main() {
	f, _ := os.Stat("1.txt")
	fattr, _ := f.Sys().(*syscall.Stat_t)
	fmt.Println(fattr.Ctimespec.Sec)
}
复制代码

使用FileInfo.Sys() 返回的是一个接口类型,这个接口类型在不同的系统是不一样的,func (fs.FileInfo).Sys() interface{} 在Linux和Mac中是 *syscall.Stat_t,在windows中是*syscall.Win32FileAttributeData, 之后再获取属性的时候性能参数也不一样。。。 上面的代码是linux中是这样的

package main

import (
	"fmt"
	"os"
	"syscall"
)

func main() {
	f, _ := os.Stat("1.txt")
	fattr, _ := f.Sys().(*syscall.Stat_t)
	fmt.Println(fattr.Ctime.Sec )
}

复制代码

在windows中又下下面的这样

package main

import (
	"fmt"
	"os"
	"syscall"
)

func main() {
	f, _ := os.Stat("1.txt")
	fattr, _ := f.Sys().(*syscall.Win32FileAttributeData)
	fmt.Println(fattr.CreationTime.Nanoseconds()/1e9)
}

复制代码

如果要画一个图表示

上面的其实还不是麻烦的,只是在如果你在Mac上开发的,将来你的程序如果要在windows上运行的话,那么开的时候写上适合windows的代码,就会在ide上直接报错了,也无法直接编译。

此时需要使用交叉编译,比如需要编译一个运行在x64位的windows上,则可以使用以下编译命令 GOOS=windows GOARCH=amd64 go build main.go 就可以正常编译了。

但是一个新的问题就来了,如果我想要在linux上使用,则我需要修改代码,改成可以在linux上运行的,然后使用linux上的交叉编译命令GOOS=linux GOARCH=amd64 go build main.go,Mac下还要修改代码,这样如果要生成不同的系统可执行文件,则就是不停的修改代码,有没有一种只编写一次的,不用反复修改的? 答案是有的,我们可以使用go:build 标签的方式 我们可以在文件头部添加 //go:build 标识来表示该文件在哪些系统和架构上进行编译 如我们可以单建一个util.go 文件,将获取文件创建时间函数单独抽出来写到这个util.go文件中,假设这里面的函数适用于Mac系统

//go:build darwin

package main

import (
	"errors"
	"os"
	"syscall"
)

func GetCtime(path string) (int64, error) {
	finfo, err := os.Stat(path)
	if err != nil {
		return 0, err
	}
	fattr, ok := finfo.Sys().(*syscall.Stat_t)
	if !ok {
		return 0, errors.New("获取文件属性失败")
	}
	return fattr.Ctimespec.Sec, nil
}

复制代码

在最上面的添加一个tag, //go:build darwin表示这个文件是在darwin 系统上编译使用的 此时我们就可以再创建两个文件,分别为util_linux.go, util_windows.go 文件 然后给它们设置build 标签

//go:build linux

package main
复制代码
//go:build windows

package main
复制代码

go:build 的逻辑关系

go:build 标签可以有逻辑关系的,比如我想要设置某个文件在darwin和liunx系统同时编译,可以使用

//go:build darwin || linux 
复制代码

也可以是且(AND)和或(OR)的关系混合

扫描二维码关注公众号,回复: 14448993 查看本文章
//go:build (darwin && amd64) || linux
复制代码

自定义标签

除了GOOS和GOARCH,我们也可以自定义一些标签,如dev,release

//go:build dev
复制代码

那么在编译文件的时候,就可以使用 go build -tags "dev" . , 则就可以使用带有dev 编译标签的文件进行编译了。

猜你喜欢

转载自juejin.im/post/7128808870046072868