头图

背景

Gtags 是 GNU global 的一个组件, 可以支持多个语言的符号生成, 索引等, 号称为最快的, 支持语言最多的符号索引工作, 可以在多个平台集成使用. Gtags 同时也支持源码变动的增量更新, 大大缩短了符号生成的时间. 目前最近的版本是 6.6.8, 版本变更相关的信息可以查看 https://www.gnu.org/software/global/whatsnew.html

Gtags 可以使用通过 --gtagslabel 配置不同的源码解析器以便支持不同的语言及格式 , 主要的解析器有:

  • default

    不配置时默认使用的内置 parser,只支持 asm, c/c++, java, php, yacc 语言.

  • ctags

    使用 exuberant-ctags 作为语言 parser,支持 40+ 种语言,只能生成定义索引不能生成引用索引。

  • new-ctags

    使用universal-ctags作为语言parser,支持 100+ 种语言,只能生成定义索引不能生成引用索引。虽然貌似universal-ctags已经支持生成引用tags,但是依然不能配合gtags工作(见这里),我也试了各种操作都没成功,也许是因为这个PR没有被merge。

  • pygments

    使用pygments作为语言parser,号称支持300+种语言。

  • native-pygments

    对于原生支持的6种语言使用内置parser,其他语言使用pygments作为parser。

当我们使用默认解析器或 pygments 解析器时, 在有些情况下解析会报错终止, 导致符号生成失败, 错误如下.

<pre>
Traceback (most recent call last):
File "/usr/local/Cellar/global/6.6.8/share/gtags/script/pygments_parser.py", line 264, in <module>

main()  

File "/usr/local/Cellar/global/6.6.8/share/gtags/script/pygments_parser.py", line 261, in main

handle_requests(langmap, parser_options)  

File "/usr/local/Cellar/global/6.6.8/share/gtags/script/pygments_parser.py", line 228, in handle_requests

print(typ, tag, lnum, path, image)  

UnicodeEncodeError: 'latin-1' codec can't encode characters in position 8-15: ordinal not in range(256)
gtags: unexpected EOF.
</pre>

解决

通过上述的堆栈信息找到 pygments_parser.py 文件中的 228 行, 发现报错的地方是一个打印语句.

def handle_requests(langmap, options):
    # Update ctags's path from the configuration file
    global EXUBERANT_CTAGS
    path = load_ctags_path()
        ...
        ...
        ...
    while True:
        path = sys.stdin.readline()
        if not path:
            break
        path = path.rstrip()
        tags = parser.parse(path)
        for (isdef, tag, lnum),image in tags.items():
            if isdef:
                typ = 'D'
            else:
                typ = 'R'
            print(typ, tag, lnum, path, image)  # 执行到这句报错了
        print(TERMINATOR, end='')
        sys.stdout.flush()

如果正常打印到控制台应该是不会错误, 应该是 gtags 中读取控制台的输出的数据解析出错了. 通过在上方增加一个调试代码, 把输出控制台的数据输出到文件中看看.

            print(typ, tag, lnum, path, image, file=open('/tmp/aa.txt', 'w'))  # 新增调试语句
            print(typ, tag, lnum, path, image)

通过输出的临时文件分析, 可以确定的是如果源码的路径参数(path 字段)存在非 ascii 字符时, 解析就会报错停止. 于是把原来的打印语句中的 path 参数进行 utf-8 编码.

            print(typ, tag, lnum, path.encode('utf-8'), image)

进行以上修改后, 路径中存在非 ascii 字符时解析也能成功了.

本来还想着提交一个 pr 到 global , 但是看了下 global 的源码并不在 github 上管理. 如果要提交修改需要发邮件申请 contributor, 先作罢吧.

参考


alps2006
4 声望0 粉丝

从事音视频即时通信领域开发, 喜欢瞎折腾.


引用和评论

0 条评论