Go编译器的小修改

NeverLea · · 1566 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

解决golang有未使用的变量和包时编译报错的问题

Go语言将variable declared but not used和package imported but not used设计成错误,正常使用无可厚非,但调试代码时会非常恼人。下面,就通过修改go源码将这两类错误改为警告。利益于golang的神奇编译速度,几分钟就可以轻松搞定。

首先看看效果吧:

// 测试代码
package main

import (
    "time"
    "fmt"
)

func main() {
    var i int
    fmt.Println("hello world!")
}

// 运行结果
➜  work go run main.go
# command-line-arguments
./main.go:4:2: imported and not used: "time"
./main.go:9:6: i declared and not used
hello world!

不过,对于用来上线生产的代码,还是务必把所有的警告解决掉。

golang1.9修改方式

  • 解决variable declared but not used,通过修改go/src/cmd/compile/internal/gc/walk.go中的func walk(fn *Node)函数,其实就是把这里的Yyerror改成Warn。
➜  gc diff walk.bak walk.go
53c53
<                       yyerrorl(defn.Left.Pos, "%v declared and not used", ln.Sym)
---
>                       Warnl(defn.Left.Pos, "%v declared and not used", ln.Sym)
56c56
<                       yyerrorl(ln.Pos, "%v declared and not used", ln.Sym)
---
>                       Warnl(ln.Pos, "%v declared and not used", ln.Sym)
  • 解决package imported but not used,通过修改go/src/cmd/compile/internal/gc/main.go中的func pkgnotused(lineno src.XPos, path string, name string)函数,也就是将这里的yyerrorl改成Warnl。
➜  gc diff main.bak main.go
1089c1089
<               yyerrorl(lineno, "imported and not used: %q", path)
---
>               Warnl(lineno, "imported and not used: %q", path)
1091c1091
<               yyerrorl(lineno, "imported and not used: %q as %s", path, name)
---
>               Warnl(lineno, "imported and not used: %q as %s", path, name)

golang1.5.1修改方法

  • 解决variable declared but not used,通过修改go/src/cmd/compile/internal/gc/walk.go中的func walk(fn *Node)函数,其实就是把这里的Yyerror改成Warn。
    for l := fn.Func.Dcl; l != nil; l = l.Next {
        if l.N.Op != ONAME || l.N.Class&^PHEAP != PAUTO || l.N.Sym.Name[0] == '&' || l.N.Used {
            continue
        }
        if defn := l.N.Name.Defn; defn != nil && defn.Op == OTYPESW {
            if defn.Left.Used {
                continue
            }
            lineno = defn.Left.Lineno
            //修改此行为下面这行Yyerror("%v declared and not used", l.N.Sym)
            Warn("%v declared and not used", l.N.Sym)
            defn.Left.Used = true // suppress repeats
        } else {
            lineno = l.N.Lineno
            //修改此行为下面这行Yyerror("%v declared and not used", l.N.Sym)
            Warn("%v declared and not used", l.N.Sym)
        }
    }
  • 解决package imported but not used,通过修改go/src/cmd/compile/internal/gc/lex.go中的func pkgnotused(lineno int, path string, name string)函数,也就是将这里的yyerrorl改成Warnl。
func pkgnotused(lineno int, path string, name string) {
    // ...这里省略掉注释
    elem := path
    if i := strings.LastIndex(elem, "/"); i >= 0 {
        elem = elem[i+1:]
    }
    if name == "" || elem == name {
        //修改此行为下面一行yyerrorl(int(lineno), "imported and not used: %q", path)
        Warnl(int(lineno), "imported and not used: %q", path)
    } else {
        //修改此行为下面一行yyerrorl(int(lineno), "imported and not used: %q as %s", path, name)
        Warnl(int(lineno), "imported and not used: %q as %s", path, name)
    }
}

golang1.4及以下版本修改方式

  • 解决variable declared but not used,通过修改go/src/cmd/gc/walk.c
for(l=fn->dcl; l; l=l->next) {
    if(l->n->op != ONAME || (l->n->class&~PHEAP) != PAUTO || l->n->sym->name[0] == '&' || l->n->used)
        continue;
    if(l->n->defn && l->n->defn->op == OTYPESW) {
        if(l->n->defn->left->used)
            continue;
        lineno = l->n->defn->left->lineno;
        //修改此行为下一行 yyerror("%S declared and not used", l->n->sym);
        warn("[Warning] %S declared and not used", l->n->sym);
        l->n->defn->left->used = 1; // suppress repeats
    } else {
        lineno = l->n->lineno;
        //修改此行为下一行 yyerror("%S declared and not used", l->n->sym);
        warn("[Warning] %S declared and not used", l->n->sym);
    }
}
  • 解决package imported but not used,通过修改go/src/cmd/gc/lex.c
for(h=0; h<NHASH; h++) {
    for(s = hash[h]; s != S; s = s->link) {
        if(s->def == N || s->pkg != localpkg)
            continue;
        if(s->def->op == OPACK) {
            // throw away top-level package name leftover
            // from previous file.
            // leave s->block set to cause redeclaration
            // errors if a conflicting top-level name is
            // introduced by a different file.
            if(!s->def->used && !nsyntaxerrors) {
                //修改此行为下面两行 pkgnotused(s->def->lineno, s->def->pkg->path, s->name);
                lineno = s->def->lineno;
                warn("[Warning] imported and not used: \"%Z\"" , s->def->pkg->path);
            }
            s->def = N;
            continue;
        }

golang编译方法

修改完后,cd到go/src下运行sudo ./make.bash,稍等,搞定!

golang1.4以上的版本的编译需要另一个golang1.4或更高版本的来编译,一个简单的方法是下载一份golang1.4(或更高)的二进制版本,解压出两份来,如分别命名gomy,go15,按上面的方法修改gomy里面的代码后,设置好GOROOT_BOOTSTRAP环境变量为go15这个目录的绝对路径,cd到gomy/src下运行./make.bash,稍等,搞定!之后就可以把gomy放到你喜欢的位置,设置好GOROOT,GOPATH等环境亦是就可以使用了。

作者原创,转载请注明出处


有疑问加站长微信联系(非本文作者)

本文来自:简书

感谢作者:NeverLea

查看原文:Go编译器的小修改

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

1566 次点击  ∙  1 赞  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传