为 GopheJS 加入 Go 语言多版本运行支持

幸运草
幸运草
幸运草
878
文章
3
评论
2020年4月13日19:01:53 评论 197

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日内与变化吧联系。

幸运草
Go语言接口规则 前端框架

Go语言接口规则

Go语言接口规则 接口是一个或多个方法签名的集合。任何类型的方法集中只要拥有该接口对应的全部方法签名。就表示它 "实现" 了该接口,无须在该类型上显式声明实现了哪个接口。对应方法,是指有相同名称、参数...
Go语言中处理 HTTP 服务器 前端框架

Go语言中处理 HTTP 服务器

1 概述 包 net/http 提供了HTTP服务器端和客户端的实现。本文说明关于服务器端的部分。 快速开始: package main import (   "log"   "net/http" )...