Stringer无法从C枚举生成具有值的常量。

huangapple go评论92阅读模式
英文:

Stringer can't generate constants with values from C enum

问题

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

问题出现在我尝试使用stringer生成额外文件时。我展示的代码位于主分支中,所以我认为它应该能正常工作,问题可能出在我这边。

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

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

...

这个类型引用了libgit2的C枚举,位于/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

但始终显示相同的错误。

如何正确使用stringer为具有来自C枚举的值的Go常量生成文件?

英文:

I'm trying run generate on CGO project https://github.com/libgit2/git2go locally. I have successfully installed libgit2 system library and can build and test the project with go build -tags static,system_libgit2 and go test -tags static,system_libgit2.

The problem occurs when I try to generate additional files with stringer. The code I'm showing is located in master branch, so I suppose it should work correctly and the problem is on my side.

The file diff.go has stringer annotation (removed unimportant parts):

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

...

This type is referencing to libgit2 C enum, the part of /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;

When I run command go generate I'm getting error:

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

I tried to run these commands:

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

But it always shows the same error.

How to correctly generate file with stringer for Go constants with values from C enum?

答案1

得分: 1

stringer通过使用go.ast解析Go源代码来提取所需的常量值。这些值必须是在定义处指定的整数字面量(参见源代码)。

CGo通过为C代码生成Go的包装代码来工作。例如,C常量会作为const _Ciconst_... = ...的包装代码放入_cgo_gotypes.go文件中。

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

因此,你可以像这样操作:

<!-- language: lang-none -->

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 works by simply parsing Go source with go.ast to extract the needed constant values. The values must be integer literals specified at the definition site (see source).

CGo works by generating Go shims for C code. For example, C constants go into the _cgo_gotypes.go file as const _Ciconst_... = ... shims.

Normally CGo deletes generated files when done, but you can keep them by invoking it explicitly, e.g. go tool cgo main.go.

So you should be able to do something like this:

<!-- language: lang-none -->

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 .

huangapple
  • 本文由 发表于 2021年10月14日 15:37:42
  • 转载请务必保留本文链接:https://go.coder-hub.com/69566767.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定