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: const initializer C: extern const is not a constant #51044

Closed
zyxkad opened this issue Feb 7, 2022 · 9 comments
Closed

cmd/cgo: const initializer C: extern const is not a constant #51044

zyxkad opened this issue Feb 7, 2022 · 9 comments
Labels
FrozenDueToAge help wanted NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Milestone

Comments

@zyxkad
Copy link

zyxkad commented Feb 7, 2022

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

$ go version
go version go1.17.2 darwin/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
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOVERSION="go1.17.2"
GCCGO="gccgo"
AR="ar"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
CGO_CFLAGS="-g -O2 -std=c17"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2 -std=c++17"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -arch x86_64 -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/fh/sxp5v53x66j5_p6_9rxtx6b80000gp/T/go-build3209812224=/tmp/go-build -gno-record-gcc-switches -fno-common"

What did you do?

consttest.go

package testc

// #include "consttest.h"
import "C"

const (
  CONST_VAR int = (int)(C.CONST_VAR)
)

consttest.h

#ifndef __CGO_CONSTTEST_H__
#define __CGO_CONSTTEST_H__

#ifdef __cplusplus
extern "C"{
#endif // __cplusplus

extern const int CONST_VAR;

#ifdef __cplusplus
}
#endif // __cplusplus

#endif // __CGO_CONSTTEST_H__

consttest.cpp

#include "consttest.h"
const int CONST_VAR = 1;

consttest_test.go

package testc_test

import "testing"
import (
  . "localhost/testc"
)

func TestConstVar(t *testing.T){
  t.Log("CONST_VAR:", CONST_VAR)
}

What did you expect to see?

=== RUN   TestConstVar
    consttest_test.go:10: CONST_VAR: 1
--- PASS: TestConstVar (0.00s)
PASS
ok  	localhost/testc

What did you see instead?

# localhost/testc
./consttest.go:8:3: const initializer int(*_Cvar_CONST_VAR) is not a constant
FAIL	localhost/testc [build failed]
FAIL
@zyxkad
Copy link
Author

zyxkad commented Feb 7, 2022

If I change extern const int CONST_VAR; to const int CONST_VAR = 1; it will work.

But in fact, I was mapping c++ enum to golang, I can't use namespace in the header file

@beoran
Copy link

beoran commented Feb 7, 2022

Afaik, CGO does not support C++. You will have to make a pure C wrapper first

@zyxkad
Copy link
Author

zyxkad commented Feb 7, 2022

Afaik, CGO does not support C++. You will have to make a pure C wrapper first

Yes, I'm making c wrapper, but how can I warp c++ enum to c (constantly)?
If I use extern const, as you see, that not actually const in golang

@ianlancetaylor ianlancetaylor added help wanted NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. labels Feb 7, 2022
@ianlancetaylor ianlancetaylor added this to the Backlog milestone Feb 7, 2022
@beoran
Copy link

beoran commented Feb 7, 2022

An extern int in C is much like a global variable, so I think that is why it maps to a variable in Go. The concept of a const in Go, where they are compile time constants), and in C(++) where const are in fact run time immutable variable, is fundamentally different. The one cannot always be mapped to the other.

@ianlancetaylor
Copy link
Contributor

A C extern const has to be a Go variable, not a Go constant, but beyond that it ought to work. I haven't tried the test case above, but I don't see why it should fail. But evidently it does, so this seems like a bug.

@zyxkad
Copy link
Author

zyxkad commented Feb 7, 2022

A C extern const has to be a Go variable, not a Go constant, but beyond that it ought to work. I haven't tried the test case above, but I don't see why it should fail. But evidently it does, so this seems like a bug.

I cannot understand why extern const is a variable, not a constant.
Do you worry about how to get the value from C?
Or because you think It can change when runtime?


And it cannot work, if I use

var (
  CONST_VAR int = (int)(C.CONST_VAR)
)

It will work. but how about want to use const, not var

@ianlancetaylor
Copy link
Contributor

Go does not have the concept of an "external constant." In Go, all constant values are known at the point where the constant is declared. When the cgo tool see a C extern const, it can only see the header file, not the C file. It can't see the actual value of the constant. So there is no way to represent a C extern const as a Go const. It can only be represented as a Go variable.

@ianlancetaylor
Copy link
Contributor

Oh, now I see that I misunderstood the example. The code

const (
  CONST_VAR int = (int)(C.CONST_VAR)
)

can't work in Go for a C extern const.

@zyxkad
Copy link
Author

zyxkad commented Feb 7, 2022

Ok, I think I can understand now, but It's hard to change my habit, I'll close it now

@zyxkad zyxkad closed this as completed Feb 7, 2022
@golang golang locked and limited conversation to collaborators Feb 7, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
FrozenDueToAge help wanted 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