【问题标题】:Stringer can't generate constants with values from C enumStringer 无法使用来自 C 枚举的值生成常量
【发布时间】:2021-12-02 14:22:00
【问题描述】:

我正在本地尝试在 CGO 项目 https://github.com/libgit2/git2go 上运行 generate。我已经成功安装了libgit2系统库,可以使用go build -tags static,system_libgit2go test -tags static,system_libgit2构建和测试项目。

当我尝试使用stringer 生成其他文件时出现问题。我显示的代码位于 master 分支中,所以我想它应该可以正常工作,问题就在我这边。

文件diff.go 有纵梁注释(删除了不重要的部分):

package git
/*
#include <git2.h>

...
*/
import "C"
import (
    "errors"
    "runtime"
    "unsafe"
)

...

type Delta int

const (
    DeltaUnmodified Delta = C.GIT_DELTA_UNMODIFIED
    DeltaAdded      Delta = C.GIT_DELTA_ADDED
    DeltaDeleted    Delta = C.GIT_DELTA_DELETED
    DeltaModified   Delta = C.GIT_DELTA_MODIFIED
    DeltaRenamed    Delta = C.GIT_DELTA_RENAMED
    DeltaCopied     Delta = C.GIT_DELTA_COPIED
    DeltaIgnored    Delta = C.GIT_DELTA_IGNORED
    DeltaUntracked  Delta = C.GIT_DELTA_UNTRACKED
    DeltaTypeChange Delta = C.GIT_DELTA_TYPECHANGE
    DeltaUnreadable Delta = C.GIT_DELTA_UNREADABLE
    DeltaConflicted Delta = C.GIT_DELTA_CONFLICTED
)

//go:generate stringer -type Delta -trimprefix Delta -tags static

...

该类型引用libgit2C枚举,/usr/include/git2/diff.h的部分:

/**
 * What type of change is described by a git_diff_delta?
 *
 * `GIT_DELTA_RENAMED` and `GIT_DELTA_COPIED` will only show up if you run
 * `git_diff_find_similar()` on the diff object.
 *
 * `GIT_DELTA_TYPECHANGE` only shows up given `GIT_DIFF_INCLUDE_TYPECHANGE`
 * in the option flags (otherwise type changes will be split into ADDED /
 * DELETED pairs).
 */
typedef enum {
    GIT_DELTA_UNMODIFIED = 0,  /**< no changes */
    GIT_DELTA_ADDED = 1,      /**< entry does not exist in old version */
    GIT_DELTA_DELETED = 2,    /**< entry does not exist in new version */
    GIT_DELTA_MODIFIED = 3,    /**< entry content changed between old and new */
    GIT_DELTA_RENAMED = 4,     /**< entry was renamed between old and new */
    GIT_DELTA_COPIED = 5,      /**< entry was copied from another old entry */
    GIT_DELTA_IGNORED = 6,     /**< entry is ignored item in workdir */
    GIT_DELTA_UNTRACKED = 7,   /**< entry is untracked item in workdir */
    GIT_DELTA_TYPECHANGE = 8,  /**< type of entry changed between old and new */
    GIT_DELTA_UNREADABLE = 9,  /**< entry is unreadable */
    GIT_DELTA_CONFLICTED = 10, /**< entry in the index is conflicted */
} git_delta_t;

当我运行命令 go generate 时出现错误:

stringer: can't happen: constant is not an integer DeltaUnmodified
diff.go:43: running "stringer": exit status 1

我尝试运行这些命令:

  • go generate ./diff.go
  • go generate -tags static,system_libgit2
  • go generate -tags static,system_libgit2 ./diff.go

但它总是显示同样的错误。

如何正确地为 Go 常量生成带有来自 C 枚举值的字符串的文件?

【问题讨论】:

    标签: c go cgo go-generate


    【解决方案1】:

    stringer 只需 parsinggo.ast 一起使用源代码来提取所需的常量值。这些值必须是在定义站点指定的整数文字(请参阅source)。

    CGo 通过为 C 代码生成 Go 垫片来工作。例如,C 常量作为const _Ciconst_... = ... shims 进入_cgo_gotypes.go 文件。

    通常 CGo 会在完成后删除生成的文件,但您可以通过显式调用它来保留它们,例如go tool cgo main.go.

    所以你应该可以做这样的事情:

    go tool cgo main.go
    mv _obj/_cgo_gotypes.go _obj/cgo_gotypes.go
    stringer -type Delta -trimprefix Delta ./_obj
    cp _obj/delta_strings.go .
    

    【讨论】:

    • 谢谢!这实际上解决了我的问题:现在我为 stringer 类型的文件运行 go tool cgo,然后删除 _obj 中的所有非 go 文件,然后将 _obj/_cgo_gotypes.go 移动到 _obj/cgo_gotypes.go(带有 C 常量的文件),然后在这些之后步骤go generate ./..../_obj 目录中工作正常,并从C enum 生成有效的_string.go 文件。
    • 好吧,我更新了答案以保留这些知识。
    猜你喜欢
    • 2015-09-02
    • 1970-01-01
    • 1970-01-01
    • 2021-01-19
    • 1970-01-01
    • 2020-11-04
    • 1970-01-01
    • 2021-06-02
    • 1970-01-01
    相关资源
    最近更新 更多