go: cmd/cgo: undefined reference for C function with -buildmode=c-archive
What version of Go are you using (go version
)?
go version go1.10.3 darwin/amd64
Does this issue reproduce with the latest release?
Yes
What operating system and processor architecture are you using (go env
)?
GOARCH=“amd64” GOBIN=“” GOCACHE=“/Users/Andari/Library/Caches/go-build” GOEXE=“” GOHOSTARCH=“amd64” GOHOSTOS=“darwin” GOOS=“darwin” GOPATH=“/Users/Andari/go” GORACE=“” GOROOT=“/usr/local/Cellar/go/1.10.3/libexec” GOTMPDIR=“” GOTOOLDIR=“/usr/local/Cellar/go/1.10.3/libexec/pkg/tool/darwin_amd64” GCCGO=“gccgo” CC=“clang” CXX=“clang++” 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” GOGCCFLAGS=“-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/lw/5pzww_8n38g1lv_kqqmqfvqr0000gn/T/go-build228325343=/tmp/go-build -gno-record-gcc-switches -fno-common”
What did you do?
I was experimenting with C interfacing:
// int cadd(int a, int b);
import "C"
...
// using the function somewhere
I built it with go build -buildmode=c-archive GoAdd.go
What did you expect to see?
The build to be successful.
What did you see instead?
Undefined symbols for architecture x86_64: “_cadd”, referenced from: __cgo_ece3f0761be9_Cfunc_cadd in _x002.o
Why would linking be neccessary, if I am generating an archive which I link together with the cadd implementing object file later?
About this issue
- Original URL
- State: open
- Created 6 years ago
- Reactions: 2
- Comments: 22 (8 by maintainers)
Commits related to this issue
- Fix linker error if go_library with cgo references unresolved symbol Before this commit, if a go_library referenced an unresolved C symbol, the build would fail with an error about an undefined symbo... — committed to fmeum/rules_go by fmeum 2 years ago
- Fix linker error if go_library with cgo references unresolved symbol Before this commit, if a go_library referenced an unresolved C symbol, the build would fail with an error about an undefined symbo... — committed to fmeum/rules_go by fmeum 2 years ago
- Fix linker error if go_library with cgo references unresolved symbol Before this commit, if a go_library referenced an unresolved C symbol, the build would fail with an error about an undefined symbo... — committed to fmeum/rules_go by fmeum 2 years ago
- Fix linker error if go_library with cgo references unresolved symbol Before this commit, if a go_library referenced an unresolved C symbol, the build would fail with an error about an undefined symbo... — committed to fmeum/rules_go by fmeum 2 years ago
- Fix linker error if go_library with cgo references unresolved symbol (#3174) Before this commit, if a go_library referenced an unresolved C symbol, the build would fail with an error about an undefi... — committed to bazelbuild/rules_go by fmeum 2 years ago
I was able to achieve the requested result (a Go static library which can be invoked by a C main program and can, in turn, call exposed C functions in the main program) by doing the following:
In the Go code, export functions as normal with the
//export
directive:Import cgo, and in the import declarations, declare the external C functions you want to call from Go.
Then, the important part: the cgo code needs to be compiled with the linker flag
-unresolved-symbols=ignore-all
(for Linux GCC, on Mac the equivalent flag is-undefined,dynamic_lookup
). You could probably do this at the build command somehow, but its more clear to add it to the cgo declaration like this:These linker flags allow the Go code to successfully compile without having the external C functions defined anywhere, as they get looked up later when the C program they’re in gets linked with the Go library.
Then, finally, build the Go static library with
-buildmode=c-archive
(specifically, my build command isgo build -o mylib.a -buildmode=c-archive src.go
) and link it to a C program in which the extern function(s) are defined.So far this seems to work correctly for me, but I’d like to know from Go experts if there is anything wrong with this solution. Will certain features of Go, like goroutines/scheduling or memory management, not work correctly? They appear to be working, but I don’t know enough about the technical details of Go to be sure…
omg, finally i foud
is wrong but the follow is rigth
just don’t add space after “//”
Until there is a better option, you can get it working by compiling the C code with -c and use that to compile the Go code and than link together those. For that, you have to have the declarations of the functions exported from the Go source. I did that by hand. I was even lazy enough to simply use int on both sides, which works on most architectures.
I would suggest to create a feature request to be able to use this:
@hajimehoshi I had your same problem and I created a fake dll library to link using
dlltool
. Es.dlltool
is part of MinGW the.def
file contains all the symbols you need. Hope this could help you.@NickNaso I don’t know for sure – I’m not very experienced with MSVC – but perhaps try the
/FORCE:UNRESOLVED
argument instead of the-unresolved-symbols=ignore-all
argument. It appears to do something similar, at least by what the documentation says.Alternatively, you might be able to use MinGW + GCC on Windows to compile with GCC instead of MSVC. Then the LDFLAGS should be the same as on Linux.
Good luck!
@zelbrium I don’t think there is anything wrong with your solution. There are some oddball cases where it might fail if you want to use internal linking (
-ldflags=-linkmode=internal
), but that is not the default, and there is no reason for you to use it.