我正在开发一个为windows(当前)构建的项目,并将在未来为darwin构建。
以下是快速概述:
file1.go:
package management
type Manager interface {
Action1()
}
file2_windows.go:
package management
type WinManager struct {
some configs
}
func (WinManager) Action1() {
...
}
func InitWinManager() WinManager {
create and return inited WinManager with configs
}
handler.go:
package handle
func handle() {
...
var m Manager
if runtime.GOOS = "windows" {
m = InitWinManager()
}
...
}
Q1:如何正确避免针对特定操作系统的这种条件初始化?
关于CI的几句话 - 因为我们的构建机器在linux上运行,我需要一个.exe文件,我就像这样构建它:
GOOS=windows go generate
//go:generate goversioninfo
GOOS=windows GOARCH=amd64 go build -o application.exe
它构建得很好,我没有任何麻烦。
go test ./handle
提出了另一个问题。在运行实际测试之前,它尝试编译测试包,但由于我的构建机器的操作系统与windows不同,因此无法找到InitWinManager()
方法。
所以 Q2:如何在go test
中指定要运行的操作系统版本?
答案 0 :(得分:3)
将Windows特定代码放在file2_windows.go中。此文件仅为Windows目标生成。
package management
type Manager struct {
... Windows specific type
}
func (Manager) Action1() {
... Windows specific code
}
func InitManager() Manager {
create and return inited Manager with configs
}
将Darwin特定代码放在file2_darwin.go中。此文件仅为Darwin目标构建。
package management
type Manager struct {
... Darwin specific type
}
func (Manager) Action1() {
... Darwin specific code
}
func InitManager() Manager {
create and return inited Manager with configs
}
从处理程序函数调用InitManager:
m := InitManager()
这会在Darwin目标上调用Darwin版本,在Windows目标上调用Windows版本。
以上使用文件名约定来设置build constraints。也可以使用注释指定约束。使用
// +build windows
指定仅为Windows目标和
构建包含文件// +build darwin
指定仅为Darwin目标构建包含文件。
我假设您将Manager定义为Windows和Darwin特定管理器的通用接口。因为一次只在代码中构建一个管理器,所以不需要为此目的定义接口。如果还有其他原因需要接口,请将上面使用的类型类型更改为ManagerImpl或类似的类型。
Q2:对于与当前系统不同的目标系统,无法运行go test
。
答案 1 :(得分:2)
我认为构建标志将成为你的朋友。
有没有理由将Darwin版本的Manager编译成Windows可执行文件?可能不是,为什么甚至参考呢?反之亦然。
如果$ GOOS是Windows,你可以通过将以下行放在文件顶部来告诉go build / test只构建一个文件...
// +build windows
这意味着在Darwin上构建时将完全忽略该文件。
这对你有什么用?那么,您可以实现相同的两种不同方式,而不是实现两种管理器类型!像这样......
windowsmanager.go
// +build windows
package management
type MyManager struct {
some configs
}
func (MyManager) PlatformGnosticAction1() {
...
}
func InitMyManager() MyManager {
create and return inited windows version of MyManager with configs
}
同样,对于达尔文来说
darwinmanager.go
// +build darwin
package management
type MyManager struct {
some configs
}
func (MyManager) PlatformGnosticAction1() {
...
}
func InitMyManager() MyManager {
create and return inited darwin version of MyManager with configs
}
现在,只有一个版本的MyManager会被编译,所以调用它的代码不需要知道它们之间的区别......
handler.go
package handle
func handle() {
...
m := InitMyManager()
...
}
如果编译了文件,标签会产生影响,所以如果darwinmanager.go和windowsmanager.go之间有很多公共代码,你可能想要重构那么多的公共代码。您的标记文件,但在同一个包中。 E.G。
mymanager.go
package Manager
func (m *MyManager) APlatformAgnosticFunc() {
...
}
func (m *MyManager) AnotherPlatformAgnosticFunc() {
...
}
在标记文件中保留平台不可知内容。
你可以用文件后缀显然做类似的事情,但我从来没有尝试过。 Dave Cheney写了一篇关于这个主题的更全面的博客,你可以读到here。
希望有所帮助!
中号