I am shipping several executables compiled with Go. Each executable by itself doesn't contain a lot of code but each of them uses a common library that includes logging, configuration management, a communication layer, etc...
This leads to each executable being between 15-20mb sometimes for as little as 1000 own lines of code.
Is there a way in Go (currently available or planned for a future release) that will allow separating the application into several files (i.e. dlls in Windows, .so Linux/Mac)?
I know I can compile the library and then use it as external binary but then I will not get the benefits of the type system and the Go compiler optimization. Am I wrong here and there is a way to do it?
The short answer: Kind of?
It sounds like what you're trying to accomplish is a shared library.
The Go compiler has been able to produce shared libraries since 1.5 with the -buildmode=c-shared
build flag:
go build -o helloworld.so -buildmode=c-shared
And, as of Go 1.10, the functionality is additionally supported on Windows
So, compiling to DLL is also a one-liner:
go build -o helloworld.dll -buildmode=c-shared
The problem that you're going to run into is actually using those libraries, especially in a cross operating system way:
In *nix, you can use CGO to accomplish this:
package example
// #cgo LDFLAGS: -lfoo
//
// #include <foo.h>
import "C"
func main() {
C.bar()
}
Windows gets its own Wiki (who's surprised?).
I'll leave you with a few thoughts on this:
CGO_ENABLED=0
saves you a ton of space from your binaries. Keeping it enabled (which you need to use these features), isn't doing you any favors.My last point, then I'll stop preaching at you: Focus on writing code. Binary size should not be your concern unless you're trying to fit on embedded devices.
Good luck friend.
Are the things you are shipping closely related to each other? If so, it might make more sense to combine them into a single executable that takes commands on the command line to decide which "executable" to start executing.
So instead of shipping 'cmd1' and 'cmd2' and 'cmd3', you just ship one program that can be invoked this way
$ prog cmd1
$ prog cmd2
$ prog cmd3
You have to do a bit of extra work to parse the first argument and decide which sub-command to launch.