Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cmd/cgo: "initializer element is not constant" for #define structs #58638

Closed
mori-nobuteru opened this issue Feb 22, 2023 · 5 comments
Closed
Labels
compiler/runtime Issues related to the Go compiler and/or runtime. FrozenDueToAge NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.

Comments

@mori-nobuteru
Copy link

mori-nobuteru commented Feb 22, 2023

What version of Go are you using (go version)?

$ go version
go version go1.20.1 linux/amd64

Does this issue reproduce with the latest release?

Yes

What operating system and processor architecture are you using (go env)?

go env Output
$ go env
GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/home/ubuntu/.cache/go-build"
GOENV="/home/ubuntu/.config/go/env"
GOEXE=""
GOEXPERIMENT=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOINSECURE=""
GOMODCACHE="/home/ubuntu/go/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="linux"
GOPATH="/home/ubuntu/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/usr/local/go"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64"
GOVCS=""
GOVERSION="go1.20.1"
GCCGO="gccgo"
GOAMD64="v1"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD="/home/ubuntu/ctest/go.mod"
GOWORK=""
CGO_CFLAGS="-O2 -g"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-O2 -g"
CGO_FFLAGS="-O2 -g"
CGO_LDFLAGS="-O2 -g"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build85441351=/tmp/go-build -gno-record-gcc-switches"

What did you do?

I'm trying to link against the quickjs library. The library builds successfully on my machine, but my Go code fails to compile once the header file for this library is included. I've created a minimal reproduction here that requires only a header file to illustrate the issue:

// ctest.h
#include <stdint.h>

enum {
    JS_TAG_UNDEFINED   = 3,
};

typedef union JSValueUnion {
    int32_t int32;
    double float64;
    void *ptr;
} JSValueUnion;

typedef struct JSValue {
    JSValueUnion u;
    int64_t tag;
} JSValue;

#define JS_MKVAL(tag, val) (JSValue){ (JSValueUnion){ .int32 = val }, tag }
#define JS_UNDEFINED JS_MKVAL(JS_TAG_UNDEFINED, 0)
// ctest.go
package ctest

/*
#include "ctest.h"
*/
import "C"
import "fmt"

func MyTest() {
	var s C.JSValue = C.JS_UNDEFINED
	fmt.Println(s)
}

The code above comes from the quick js library. The goal is to use a macro to define that initializes a struct.

What did you expect to see?

I expected this code to compile on Linux, like it does on MacOS.

What did you see instead?

In file included from ./ctest.go:4:
./ctest.h:18:37: error: initializer element is not constant
   18 | #define JS_MKVAL(tag, val) (JSValue){ (JSValueUnion){ .int32 = val }, tag }
      |                                     ^
./ctest.h:19:22: note: in expansion of macro 'JS_MKVAL'
   19 | #define JS_UNDEFINED JS_MKVAL(JS_TAG_UNDEFINED, 0)
      |                      ^~~~~~~~
cgo-dwarf-inference:2:12: note: in expansion of macro 'JS_UNDEFINED'
@mori-nobuteru
Copy link
Author

mori-nobuteru commented Feb 22, 2023

I was able to get this to compile by using Clang (go env -w CC="clang"), but it'd be nice for it to work out-of-the-box as well. Another thing to add is that I built the quickjs library with GCC, and it handled the header correctly, so this seems like an issue with Cgo's configuration than with GCC itself, but I could be wrong.

@thanm thanm added the NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. label Feb 22, 2023
@thanm
Copy link
Contributor

thanm commented Feb 22, 2023

@golang/compiler

@ianlancetaylor ianlancetaylor changed the title cgo: "initializer element is not constant" for #define structs. cmd/cgo: "initializer element is not constant" for #define structs Feb 22, 2023
@gopherbot gopherbot added the compiler/runtime Issues related to the Go compiler and/or runtime. label Feb 22, 2023
@ianlancetaylor
Copy link
Contributor

This doesn't have anything to do with cgo or Go. A pure C file

#include "ctest.h"
JSValue x = JS_UNDEFINED;

will report the same error when using GCC.

@ianlancetaylor ianlancetaylor closed this as not planned Won't fix, can't repro, duplicate, stale Feb 22, 2023
@mori-nobuteru
Copy link
Author

mori-nobuteru commented Feb 23, 2023

@ianlancetaylor The error you get when compiling your code is slightly different:

ctest.h:19:37: error: initializer element is not constant
   19 | #define JS_MKVAL(tag, val) (JSValue){ (JSValueUnion){ .int32 = val }, tag }
      |                                     ^
ctest.h:20:22: note: in expansion of macro ‘JS_MKVAL’
   20 | #define JS_UNDEFINED JS_MKVAL(JS_TAG_UNDEFINED, 0)
      |                      ^~~~~~~~
ctest.c:3:13: note: in expansion of macro ‘JS_UNDEFINED’
    3 | JSValue x = JS_UNDEFINED;

You'll notice your const assignment is actually part of the error. No where in my Cgo example do I create a const assignment, so it's unclear where the error is coming from.

For instance, if you write a C function similar to my Go function, GCC will compile it:

#include "ctest.h"

int main() {
  JSValue x = JS_UNDEFINED;
}

@ianlancetaylor
Copy link
Contributor

The error string is coming from the cgo tool. It's because the cgo tool itself needs to determine the type of the value. It does by writing out

__typeof__(JS_UNDEFINED) *__cgo__1;

It compiles that as C code, and looks at the DWARF debug info to determine type. Unfortunately, that code doesn't compile when using GCC.

I think that to make this work with GCC you are going to write something like

/*
#include "ctest.h"

static JSValue undef() { return JS_UNDEFINED; }
*/
import "C"
import "fmt"

func MyTest() {
	var s C.JSValue = C.undef()
	fmt.Println(s)
}

@golang golang locked and limited conversation to collaborators Feb 23, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
compiler/runtime Issues related to the Go compiler and/or runtime. FrozenDueToAge NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Projects
None yet
Development

No branches or pull requests

4 participants