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

cgo: multiple definition of cgo functions error when linking go-compiled c-archive library #20639

Closed
reusee opened this issue Jun 10, 2017 · 4 comments

Comments

@reusee
Copy link

reusee commented Jun 10, 2017

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

go version devel +c99483feb8 Sat Jun 3 17:04:56 2017 +0000 linux/amd64

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

GOARCH="amd64"
GOBIN=""
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/home/reus"
GORACE=""
GOROOT="/home/reus/go"
GOTOOLDIR="/home/reus/go/pkg/tool/linux_amd64"
GCCGO="gccgo"
CC="gcc"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build884024617=/tmp/go-build -gno-record-gcc-switches"
CXX="g++"
CGO_ENABLED="1"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"

What did you do?

lib.go

package main

import (
	"C"
	"fmt"
)

func main() {
}

//export Foo
func Foo() {
	fmt.Printf("Foo!\n")
}

lib.c

extern void Foo();

void foo() {
  Foo();
}

build static library

 go build -buildmode=c-archive -o foo.a 

call.go

package main

/*
extern void foo();

#cgo LDFLAGS: ./foo.a
*/
import "C"

func main() {
	C.foo()
}

build call.go

go build call.go

What did you expect to see?

no build error

What did you see instead?

# command-line-arguments
./foo.a(go.o): In function `_cgo_topofstack':
/home/reus/go/src/runtime/asm_amd64.s:2327: multiple definition of `_cgo_topofstack'
/tmp/go-build074487992/command-line-arguments/_obj/_cgo_main.o:/tmp/go-build/command-line-arguments/_obj/_cgo_main.c:5: first defined here
./foo.a(go.o): In function `_cgo_panic':
/home/reus/go/src/runtime/cgo/callbacks.go:45: multiple definition of `_cgo_panic'
/tmp/go-build074487992/command-line-arguments/_obj/_cgo_main.o:/tmp/go-build/command-line-arguments/_obj/_cgo_main.c:6: first defined here
./foo.a(go.o): In function `crosscall2':
/home/reus/go/src/runtime/cgo/asm_amd64.s:12: multiple definition of `crosscall2'
/tmp/go-build074487992/command-line-arguments/_obj/_cgo_main.o:/tmp/go-build/command-line-arguments/_obj/_cgo_main.c:2: first defined here
./foo.a(000001.o): In function `_cgo_wait_runtime_init_done':
/home/reus/go/src/runtime/cgo/gcc_libinit.c:35: multiple definition of `_cgo_wait_runtime_init_done'
/tmp/go-build074487992/command-line-arguments/_obj/_cgo_main.o:/tmp/go-build/command-line-arguments/_obj/_cgo_main.c:3: first defined here
./foo.a(000001.o): In function `_cgo_release_context':
/home/reus/go/src/runtime/cgo/gcc_context.c:11: multiple definition of `_cgo_release_context'
/tmp/go-build074487992/command-line-arguments/_obj/_cgo_main.o:/tmp/go-build/command-line-arguments/_obj/_cgo_main.c:4: first defined here
collect2: error: ld returned 1 exit status

@ianlancetaylor
Copy link
Member

-buildmode=c-archive is designed for linking Go code into a C program. You are trying to use it to link Go code into a Go program. That can't work. That's not what it's for.

What are you really trying to do?

@KDr2
Copy link

KDr2 commented Jun 23, 2017

@iangudger but the below simple example doesn't work either:

$ cat mde.go
package main

/*
int Add(int i) {
        return i + 1;
}
*/
import "C"
import "fmt"

func main() {
}

//export Foo
func Foo() {
        fmt.Printf("Foo!\n")
        C.Add(1)
}

$ go build -buildmode=c-archive mde.go
# command-line-arguments
/tmp/go-build123475493/command-line-arguments/_obj/mde.cgo2.o: In function `Add':
./mde.go:5: multiple definition of `Add'
/tmp/go-build123475493/command-line-arguments/_obj/_cgo_export.o:/data/kdr2/.../mde.go:5: first defined here
collect2: error: ld returned 1 exit status

@ianlancetaylor
Copy link
Member

The simple example is an unfortunate limitation, but a documented one. Quoting https://golang.org/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.

@KDr2
Copy link

KDr2 commented Jun 24, 2017

Got it, thanks.

@golang golang locked and limited conversation to collaborators Apr 11, 2019
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

5 participants