diff --git a/cmd/genbindings/emitgo.go b/cmd/genbindings/emitgo.go index 5490e2aa..2cb07b8d 100644 --- a/cmd/genbindings/emitgo.go +++ b/cmd/genbindings/emitgo.go @@ -5,8 +5,10 @@ import ( "fmt" "go/format" "log" + "math" "path" "sort" + "strconv" "strings" ) @@ -643,7 +645,7 @@ func (gfs *goFileState) emitCabiToGo(assignExpr string, rt CppParameter, rvalue } -func emitGo(src *CppParsedHeader, headerName string, packageName string) (string, error) { +func emitGo(src *CppParsedHeader, headerName string, packageName string) (string, string, error) { ret := strings.Builder{} ret.WriteString(`package ` + path.Base(packageName) + ` @@ -664,6 +666,8 @@ import "C" currentPackageName: packageName, } + var bigints []string + // Check if short-named enums are allowed. // We only allow short names if there are no conflicts anywhere in the whole // file. This doesn't fully defend against cross-file conflicts but those @@ -716,13 +720,41 @@ import "C" if len(e.Entries) > 0 { - ret.WriteString("const (\n") + var smallvalues []string for _, ee := range e.Entries { - ret.WriteString(titleCase(cabiClassName(goEnumShortName+"::"+ee.EntryName)) + " " + goEnumName + " = " + ee.EntryValue + "\n") + + isBigInt := false + + if e.UnderlyingType.IntType() { + // Int-type enums need special handling in case of 64-bit + // overflow, that would prevent using miqt on 32-bit platforms + + entryValueI64, err := strconv.ParseInt(ee.EntryValue, 10, 64) + if err != nil { + panic("Enum " + ee.EntryName + " has non-parseable integer value") + } + + if entryValueI64 > math.MaxInt32 || entryValueI64 < math.MinInt32 { + isBigInt = true + } + } + + enumConstDeclaration := titleCase(cabiClassName(goEnumShortName+"::"+ee.EntryName)) + " " + goEnumName + " = " + ee.EntryValue + + if isBigInt { + bigints = append(bigints, "const "+enumConstDeclaration+"\n") + } else { + smallvalues = append(smallvalues, enumConstDeclaration+"\n") + } + } + + if len(smallvalues) > 0 { + ret.WriteString("const (\n") + ret.WriteString(strings.Join(smallvalues, "")) + ret.WriteString("\n)\n\n") } - ret.WriteString("\n)\n\n") } } @@ -1085,5 +1117,14 @@ import "C" formattedSrc = []byte(goSrc) } - return string(formattedSrc), nil + // Determine if we need to produce a _64bit.go file + bigintSrc := "" + if len(bigints) > 0 { + bigintSrc = `//go:build !386 && !arm +// +build !386,!arm + +package ` + path.Base(packageName) + "\n\n" + strings.Join(bigints, "") + "\n" + } + + return string(formattedSrc), bigintSrc, nil } diff --git a/cmd/genbindings/main.go b/cmd/genbindings/main.go index c951ae27..308915cc 100644 --- a/cmd/genbindings/main.go +++ b/cmd/genbindings/main.go @@ -222,7 +222,7 @@ func generate(packageName string, srcDirs []string, allowHeaderFn func(string) b counter++ } - goSrc, err := emitGo(parsed, filepath.Base(parsed.Filename), packageName) + goSrc, go64Src, err := emitGo(parsed, filepath.Base(parsed.Filename), packageName) if err != nil { panic(err) } @@ -232,6 +232,13 @@ func generate(packageName string, srcDirs []string, allowHeaderFn func(string) b panic(err) } + if len(go64Src) > 0 { + err = os.WriteFile(outputName+"_64bit.go", []byte(go64Src), 0644) + if err != nil { + panic(err) + } + } + bindingCppSrc, err := emitBindingCpp(parsed, filepath.Base(parsed.Filename)) if err != nil { panic(err)