Stringer can't generate constants with values from C enum

461 views Asked by At

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

There are 1 answers

0
rustyx On BEST ANSWER

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:

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 .