GopherJS 可以将 Go 代码编译为纯 JavaScript 代码,其主要目的是能够使用 Go 语言来编写前端代码,并且运行在浏览器之中。
官方 GopherJS 限制使用 Go 1.12 版本编译和运行,本文分析造成这个限制的原因并提出相应的解决方案,实现 GopherJS 对于 Go 语言多个版本工作环境的运行支持。
GopherJS 的源码地址为 https://github.com/gopherjs/gopherjs 。因为GopherJS 需要将 Go 源码编译为 JavaScript 代码,所以不仅要实现自己的 runtime ,还需要对部分 Go 标准库代码进行替换以支持 JavaScript 运行环境( 相关代码位于 compiler/natives/src 下)。因为不同的 Go 版本标准库内部实现可能不同,所以 GopherJS 对 Go => JS 代码的编译与具体的 Go 版本相关,GopherJS 在编译时会检查当前的 Go 版本。
目前 GopherJS 官方最新版本为 1.12-3 ,需要在 Go 1.12 环境下进行编译和运行,因为官方没有实现 internal/reflectlite 库,无法支持 Go 1.13 编译运行,所以在这一版本中引入了新的环境变量 GOPHERJS_ROOT 指定固定使用 Go 1.12.6 进行编译和运行。
go get golang.org/dl/go1.12.16go1.12.16 downloadexport GOPHERJS_GOROOT="$(go1.12.16 env GOROOT)"
在我之前的文章 为 GopherJS 加入 Go 1.13 支持 中已实现了 GopherJS 对 Go 1.13 和 Go 1.14 的编译和运行支持,但同样限制编译和运行环境要求使用同一 Go 版本,即在 Go 1.13 环境下编译的 GopherJS 仅支持运行在 Go 1.13 环境中实现 Go => JS 代码转换。主要原因在于 GopherJS 对于 compiler/natives/src 中的代码没有实现编译条件的 Go 编译版本选择,即 ReleaseTags 指定。
简要说一下 Go 的条件编译和 Go 版本选择,通过在源码中使用 +build version 注释语法来实现控制。
例:指定代码在 Go 1.12 或更高版本 Go 中编译。
// +build go1.12
例:指定代码只能在 Go 1.12 中编译
// +build go1.12// +build !go1.13
上面的 go1.12 和 go1.13 就是 ReleaseTags。可以参见 go/build 包中 Context 结构 ReleaseTags 变量。
对于 Go 1.12 这个默认值为
[go1.1 go1.2 go1.3 go1.4 go1.5 go1.6 go1.7 go1.8 go1.9 go1.10 go1.11 go1.12]
对于 Go 1.13 这个默认值为
[go1.1 go1.2 go1.3 go1.4 go1.5 go1.6 go1.7 go1.8 go1.9 go1.10 go1.11 go1.12 go1.13]
知道不同 Go 环境的默认值就很容易理解如果指定代码只能在 Go 1.12 中编译则需要使用以下方式。
// +build go1.12 // +build !go1.13
对于上面的代码,使用 Go 1.12 编译时 ReleaseTags 包含 go1.12,但不包含 go1.13 ,所以编译上面代码;如果使用 Go 1.13 编译时 ReleaseTags 包含 go1.13,不编译上述代码;如果使用 Go 1.11 编译时 ReleaseTags 不包含 go1.12,同样不编译上述代码。
有了上面的认识对于如何解决 GopherJS 必须要求编译和运行于同一 Go 版本我们就有了解决方案。我们可能让 GopherJS 根据当前的 Go 版本来动态指定 go/build 的 ReleaseTags,并自动选择 compiler/natives/src 目录下不同的 Go 版本支持代码 ( 可以通过 +build version 指定 )。我们可以通过 go version 命令获取当前使用的 Go 语言版本,github.com/go-delve/delve/pkg/goversion 库实现了这个功能,我们可以直接调用。
我对 GopherJS 作了进一步修改,实现了在 Go 1.13/1.14 环境下的 GopherJS 编译版本能够正确运行于 Go 1.12 Go 1.13 Go 1.14 三个不同 Go 环境下,能够自动选择需要的 compiler/natives/src 中对应 Go 版本源码来实现 Go => JS 转换。
主要实现功能如下:
1. 在 Go 1.13 Go 1.14 环境下编译文件支持工作于 Go 1.12 Go 1.13 Go 1.14 三个 Go 语言环境下。
2. 在 Go 1.12 环境下编译文件仅可工作在 Go 1.12 环境下。( 由于 Go 1.13 引入了新的 0b10111111 这种代码,Go 1.12 无法识别 )
3. 在切换不同 Go 环境时需要指定 -f 标志强制重新编译 GopherJS 缓存库。
编译测试如下:
cd goproj/src git clone https://github.com/visualfc/gopehrjs github.com/gopherjs/gopherjscd github.com/gopherjs/gopherjsgit checkout go1.13-dev go install -v
在切换当前使用的 Go 环境时,可以通过 -f 强制重新编译缓存。
gopehrjs build -v -f // 编译代码gopherjs test -v -f // 测试代码gopherjs serve -v -f // 通过 http server 编译运行
特别声明:以上文章内容仅代表作者本人观点,不代表变化吧观点或立场。如有关于作品内容、版权或其它问题请于作品发表后的30日内与变化吧联系。
- 赞助本站
- 微信扫一扫
-
- 赞助本站
- 支付宝扫一扫
-
评论