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: probable cgo gcc linker issue "undefined reference" #29296

Closed
denisvolin opened this issue Dec 16, 2018 · 9 comments

Comments

@denisvolin
Copy link

commented Dec 16, 2018

What version of Go are you using: 1.11.4;

Does this issue reproduce with the latest release: yes;

What operating system and processor architecture are you using:

GOARCH="amd64"
GOBIN="/home/{username}/Go/bin"
GOCACHE="/home/{username}/.cache/go-build"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/home/{username}/Go"
GOPROXY=""
GORACE=""
GOROOT="/usr/local/go"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64"
GCCGO="gccgo"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD=""
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 -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build393278239=/tmp/go-build -gno-record-gcc-switches"

(It's Ubuntu 18.04.1 LTS)

What did you do:

I'm building a cgo wrapper around some library and encounter probably a gcc linker issue, but since cgo calls linker implicitly I have not figured out how to implement the known workaround: https://stackoverflow.com/questions/12272864/linker-error-on-linux-undefined-reference-to

Basically, the issue is that if you put the libraries after the object in the command line, the gcc ``linker may decide that it needs nothing from a particular library at the stage of the link where it scans the library, and then it won't rescan the library later after it finds some undefined symbols in the object files´´.

And this situation happens only with a single symbol from the library.

The package that I'm building has both cgo pseudo-directives: CFLAGS -I and LDFLAGS -L for both amd64 and 386 architectures supported by the library being wrapped.

Other symbols works just fine.

UPD: More over if I create a new package dedicated to that single one symbol, it still reports the
very same issue.

UPD: nm -g lib{library name}.so confirms the symbol is present.

UPD: compiled a separate buffer shared library which is supposed to be proxying the symbol wrapping it under the new name; gcc compiled it just fine; no questions asked; then I've added -I, -L and -l flags to the original go (cgo) package and rerouted the call to use proxy; same failure it still argues about the undefined reference to the original (wrapped) symbol; nm -D libwrapper.so perfectly fine reports presence of both symbols.

What did you expect to see?

Ehm.. nothing... Successful building output.

What did you see instead?

The error output says:
/tmp/go-build067792519/b001/_x030.o: In function _cgo_742289945843_Cfunc_{symbol name}': /tmp/go-build/cgo-gcc-prolog:44: undefined reference to {symbol name}'
collect2: error: ld returned 1 exit status

@ianlancetaylor ianlancetaylor changed the title Probable cgo gcc linker issue "undefined reference" cmd/cgo: probable cgo gcc linker issue "undefined reference" Dec 17, 2018
@ianlancetaylor

This comment has been minimized.

Copy link
Contributor

commented Dec 17, 2018

Can you show us a small self-contained example that demonstrates the problem?

@denisvolin

This comment has been minimized.

Copy link
Author

commented Dec 17, 2018

Can you show us a small self-contained example that demonstrates the problem?

I wish I could direct you to the library in question for testing, but unless you are a Russian national, residing inside the borders, me doing so will bring me to the prosecutor office faster, than I'd be able to type the F-word, due to the nature of the library in correspondence with export legislation.

So, let's try the code samples and package structure.

Let's say the package is called wrapper and it has internal folder cwrap for wrapper shared library, which was build with -c -fPIC and linked with the original library as -shared.

cwrap.h contains inclusions to support the original library call;

extern.h:

extern void wrappedCall(void *);

cwrap.c contains implementation of the wrappedCall function calling OriginalCloseObjectFunction,
accepting the pointer to some struct;

inside the parent wrapper package folder there are two files:

wrapper.go:

// +build darwin,cgo dragonfly,cgo freebsd,cgo linux,cgo netbsd,cgo openbsd,cgo

package wrapper

// #cgo LDFLAGS: -L${SRCDIR}/cwrap -lcwrap
import "C"

and call.go:

// +build darwin,cgo dragonfly,cgo freebsd,cgo linux,cgo netbsd,cgo openbsd,cgo

package wrapper

import "unsafe"

// #include "cwrap/extern.h"
import "C"

// CallClose wraps calling C.OriginalCloseObjectFunction; always returns nil.
func CallClose(ptr unsafe.Pointer) error {
    C.wrappedCall(ptr)
    return nil
}

Now, calling go vet or go build inside the wrapper folder results in:

wrapper/cwrap/libcwrap.so: undefined reference to `OriginalCloseObjectFunction`
collect2: error: ld returned 1 exit status
@denisvolin

This comment has been minimized.

Copy link
Author

commented Dec 17, 2018

UPD: On the original developer library support forum there's a mention for the same issue which was solved by placing -L and -l flags data after the .o, just as I supposed in the original statement; and the person who posted the problem there was also using Ubuntu, may be it's an Ubuntu thing I'm starting to think...

@denisvolin

This comment has been minimized.

Copy link
Author

commented Dec 17, 2018

So, the question is: how can I redefine the linker arguments for building the code?

@ianlancetaylor

This comment has been minimized.

Copy link
Contributor

commented Dec 18, 2018

You don't need to show us the original code. Just show us a small self-contained example that demonstrates the problem. You described it but it will be easier to see it in code.

From your description I don't understand why there is a problem. But since there is a problem, I would suggest changing LDFLAGS from -lcwrap to simply cwrap.o. If it really has to be a library, then perhaps -Wl,--push-state -Wl,--whole-archive -lcwrap -Wl,--pop-state.

@denisvolin

This comment has been minimized.

Copy link
Author

commented Dec 19, 2018

You don't need to show us the original code. Just show us a small self-contained example that demonstrates the problem. You described it but it will be easier to see it in code.

From your description I don't understand why there is a problem. But since there is a problem, I would suggest changing LDFLAGS from -lcwrap to simply cwrap.o. If it really has to be a library, then perhaps -Wl,--push-state -Wl,--whole-archive -lcwrap -Wl,--pop-state.

I've tried both approaches: compiled library with mentioned flags and switched to cwrap.o solution, and, yet, anyway it issues the undefined reference error on go build. And in my previous answer I have almost the exact contents of the package in question, I just replaced names with something else. CallClose looks exactly the way it looks in the package, it's just names that differ, the contents of the cwrap.c looks like:

void wrappedCall(void * ptr) {
    OriginalCloseObjectFunction((CASTED_POINTER_TYPE)(ptr));
}

Just a single line wrapper.

For some unknown reason in the whole library, I'm wrapping, the only symbol causing this issue is that one, and, yet, since it is really a memory freer, a closer 5 different objects rely on it to be called. I can't avoid it. I tried to create a separate go package dedicated to that symbol; I tried wrapping the symbol in a library, both shared and static, I've tried your previous suggestions, all of them — once engaged with cgo — result in an undefined reference gcc linker error, whilst if I wrap the original library in a static or shared one, I have no problems in building it with the same gcc linker.

I've looked up go help build and called go build -x to find out the everything looks normal up until the very end, where all generated in previous steps .o files are getting linked, the command line looks perfect in terms of my previous ideas, the .o files are exactly before any -l mentioned data.

I understand that this is some kind of undefined incompatibility between the shared library, I'm wrapping, and cgo, and yet I have no idea how to figure out what exactly is going on.

That OriginalCloseObjectFunction symbol is just being constantly missed from the linking, though nm finds it perfectly fine anyway.

I've tried to change -compiler option to =gccgo, and it resulted in cmd/go: gccgo: exec: "gccgo": executable file not found in $PATH, if called from the some subpackage of subpackge of subpackage, and in single line output on -x option: WORK=/tmp/go-build527216309 if called from src/some-package/.

@denisvolin

This comment has been minimized.

Copy link
Author

commented Dec 19, 2018

Issue is closed.
I'm once again a blind idiot.
There's nothing to do with the go, but with the idiot trying to use it.
My apologies.
nm listed not the OriginalCloseObjectFunction, but rather a OriginulCloseObjectFunction;
I'll be addressing my optometrist and the library being wrapped developer.
Once again, I'm sorry.

@denisvolin denisvolin closed this Dec 19, 2018
@ianlancetaylor

This comment has been minimized.

Copy link
Contributor

commented Dec 19, 2018

No worries, thanks for following up.

@jiahao98

This comment has been minimized.

Copy link

commented Aug 3, 2019

No worries, thanks for following up.

You, I have the same problem. Can you tell me how to solve it?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
3 participants
You can’t perform that action at this time.