5

Is there a way to produce a C static library from Go code, but without Go runtime function definitions?

Rationale:

  • Project A creates a C static library with go build -buildmode=c-archive, libA.a .
  • Works well: project B uses pure C and is able to easily create an executable, statically linking with libA.a, all is fine.
  • Problem 1: project C happens to also use Go, but would like to use libA.a as a regular C library. Now it has a link problem: the Go runtime functions such as e.g. _cgo_panic are now defined both in project C runtime (as it uses Go) and in libA.a.
  • Problem 2: project D uses pure C, same as B. Yet it wants to use two different libraries from project A, e.g. libA.a and some libA2.a. Sadly, it does not link either, because Go runtime functions are now defined in both libA.a and libA2.a.

The problems faced by project C and project D could be easily resolved if project A could produce its libraries without the Go runtime definitions inside. Project C could just link with libA.a. Project D would link with libA.a, libA2.a and some libGo.a that would contain definitions of all the Go runtime stuff.

What I tried:

  • Using linker flags at 'project C' level, such as -Wl,--allow-multiple-definition. Now its build fails with a cryptic message 'function symbol table not sorted by program counter'.
  • Manually removing go.o from 'libA.a' (as it's just an "ar" archive): didn't work as 'go.o' also contained implementations of my exported functions, so I've removed too much.
  • Using go build -buildmode=c-shared. As expected, it produces a dynamic library which uses another format, so I could not directly use it as a static library.

Any solution at the client side (such as finding a proper way to ignore duplicate definitions at the link stage for project C) would be also considered a valid answer.
I can also accept a negative answer (no solution) if it provides enough evidence.

Update: see a related question Is there a way to include multiple c-archive packages in a single binary

Alexander
  • 2,761
  • 1
  • 28
  • 33
  • Go code requires the go runtime, and loading multiple instances of the go runtime is not supported. You cannot use go in this way. – JimB Apr 24 '21 at 18:18
  • Thanks, this is probably the answer. Is this documented anywhere? – Alexander Apr 24 '21 at 20:51
  • As far as I know it's only documented by omission, I would not expect it to work unless it was specifically allowed. It would not be a trivial task to get multiple go runtime instances to cooperate within the same process space. – JimB Apr 27 '21 at 16:15

1 Answers1

0

With the current implementation it's not going to work to use -buildmode=c-archive multiple times and put the results into multiple shared libraries, as you've discovered. The essential problem is that there has to be only one Go runtime, but you have multiple runtimes. When using -buildmode=c-archive there's no way to isolate the different runtimes.

The -buildmode=c-shared libraries differ from buildmode=c-archive in that they are built with -Bsymbolic which forces all their local references to be local. The effect is that we have multiple Go runtimes, but they don't refer to each other so there is no confusion.

You could try adding -Wl,-Bsymbolic to build each shared library that includes Go code in c-archive if your C code doesn't mind being linked with -Bsymbolic.

I wish you luck.

syntaqx
  • 2,636
  • 23
  • 29
  • Thanks for the answer. I've tried the following: go build -buildmode=c-archive -ldflags="-extldflags '-Wl,-Bsymbolic'" to build my library. It looks like there was no effect. Do you see any other way of propagating the linker flags? – Alexander Apr 28 '21 at 13:11
  • Those flags are meant for your C code, not for Go, `clang -Wl,-Bsymbolic -shared ...` or `g++ -shared -Wl,-Bsymbolic -Wall ...`. The go archives will be the same as before, you're just using symbolic references to the global definitions. – syntaqx Apr 28 '21 at 18:22
  • I've been adding the flags to my CGO_CFLAGS and CGO_LDFLAGS at the client side as well. – Alexander Apr 29 '21 at 07:40