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/link:cgo: reports multiple definitions of C land function #63408

Closed
sbezverk opened this issue Oct 6, 2023 · 1 comment
Closed

cmd/link:cgo: reports multiple definitions of C land function #63408

sbezverk opened this issue Oct 6, 2023 · 1 comment

Comments

@sbezverk
Copy link

sbezverk commented Oct 6, 2023

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

$ go version
go version go1.21.2 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/sbezverk/.cache/go-build'
GOENV='/home/sbezverk/.config/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFLAGS=''
GOHOSTARCH='amd64'
GOHOSTOS='linux'
GOINSECURE=''
GOMODCACHE='/home/sbezverk/go/pkg/mod'
GONOPROXY='github.com/jalapeno/*'
GONOSUMDB='github.com/jalapeno/*'
GOOS='linux'
GOPATH='/home/sbezverk/go'
GOPRIVATE='github.com/jalapeno/*'
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/usr/local/go'
GOSUMDB='sum.golang.org'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/usr/local/go/pkg/tool/linux_amd64'
GOVCS=''
GOVERSION='go1.21.2'
GCCGO='gccgo'
GOAMD64='v1'
AR='ar'
CC='gcc'
CXX='g++'
CGO_ENABLED='1'
GOMOD='/home/sbezverk/projects/go/workspace/cgo/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 -ffile-prefix-map=/tmp/go-build3441693360=/tmp/go-build -gno-record-gcc-switches' 

What did you do?

go build -o cgo_stubs cgo.go

The following go code:

package main
 
// #include <stdio.h>
//
// extern int go_test_func(int c1, int c2);
//
// int c_test_func(int c1, int c2)
// {
//   return go_test_func(c1,c2);
// }
import "C"
 
import (
          "fmt"
)
 
//export go_test_func
func go_test_func(c1, c2 C.int) C.int {
          return c1 + c2
}
 
func main() {
          fmt.Printf("Result: %d\n", C.c_test_func(2, 2))
} 

What did you expect to see?

Successfully built binary

What did you see instead?

go build -o cgo_test cgo.go
# command-line-arguments
/usr/local/go/pkg/tool/linux_amd64/link: running gcc failed: exit status 1
/usr/bin/ld: /tmp/go-link-644125076/000001.o: in function `c_test_func':
/home/sbezverk/projects/go/workspace/cgo/cgo.go:8: multiple definition of `c_test_func'; /tmp/go-link-644125076/000000.o:/tmp/go-build/cgo.go:8: first defined here
collect2: error: ld returned 1 exit status

Further investigation:

After looking in cgo generated files, I found that in fact function “c_test_func” is defined in 2 places.

1: ./cgo.cgo2.c:29: int c_test_func(int c1, int c2)

#line 3 "/nobackup/sbezverk/projects/go/worspace/cgo_test/cgo.go"
#include <stdio.h>

extern int go_test_func(int c1, int c2);

int c_test_func(int c1, int c2)
{
return go_test_func(c1,c2);
}

2: ./_cgo_export.h:27: int c_test_func(int c1, int c2)

#line 3 "cgo.go"
#include <stdio.h>

extern int go_test_func(int c1, int c2);

int c_test_func(int c1, int c2)
{
return go_test_func(c1,c2);
}

_cgo_export.h is included in ./_cgo_export.c:4:#include "_cgo_export.h". Making it a second definition of the same function.

@cherrymui
Copy link
Member

See https://pkg.go.dev/cmd/cgo#hdr-C_references_to_Go .

Using //export in a file places a restriction on the preamble: since it is copied into two different C output files, it must not contain any definitions, only declarations. If a file contains both definitions and declarations, then the two output files will produce duplicate symbols and the linker will fail. To avoid this, definitions must be placed in preambles in other files, or in C source files.

This is an unfortunate limitation. One workaround is to define c_test_func as a weak or static function.

Closing as working as intended. Thanks.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

3 participants