Build self-recompiling Go binaries
MIT License
Build self-recompiling Go binaries for embedding new plugins at runtime.
Status: v0
(no stability guarantee); this is a proof of concept, if you'd
like to depend on go-selfcompile then please open an issue with your API
requirements.
Check the project's upcoming milestones to get a feel for what's prioritized.
If you ship a Go-built binary to a user and want to make it easy to install third-party plugins, what do you do?
Until now, the user would need to install the Go compiler and runtime, make a stub to import the plugin, re-build the binary with the new dependency and use that.
go-selfcompile facilitates bundling the Go compiler and runtime, creating the
plugin import stub, recompiling, and replacing the original binary with just a
call to SelfCompile.Compile()
!
Let's start with plugins: We define a plugin as a package which does something
inside init() { ... }
. Your system would provide some way for plugins to
register themselves on init, then all you'll need to do is import them and off
you go.
Example of a plugin: example/aplugin
Next, to use go-selfcompile in your binary you'll need to do two things:
Generate the bundled asset container for the Go compiler and runtime.
You'll need our handy go-selfcompile
binary that you can install with
go get github.com/shazow/go-selfcompile/...
.
Somewhere near your func main() { ... }
, add a go generate stanza:
//go:generate go-selfcompile --skip-source
Now run go generate
to build the bundle container.
Add the SelfCompile handler in your command line flow. Check the documentation for all the options, but a bare minimum would look something like this:
c := selfcompile.SelfCompile{
Install: "github.com/shazow/go-selfcompile/example/abinary",
RestoreAssets: RestoreAssets,
}
// Add a plugin from the CLI call
c.Plugin(plugin)
// Initiate the compiling with the plugin stubs
if err := c.Compile(); err != nil { ... }
// Delete the temporary directory used for compiling
if err := c.Cleanup(); err != nil { ... }
Example of a self-compiling binary: example/abinary
If you're trying out the built-in examples, it will look something like this:
$ example-abinary
Just doing binary things
$ example-abinary --plugin "github.com/shazow/go-selfcompile/example/aplugin"
Installing plugin: github.com/shazow/go-selfcompile/example/aplugin
[selfcompile] 2015/10/03 15:10:08 Initializing workdir: /tmp/go-selfcompile690079187
[selfcompile] 2015/10/03 15:10:21 Compiling workdir: /tmp/go-selfcompile690079187
[selfcompile] 2015/10/03 15:10:43 Replacing binary: /usr/local/bin/example-abinary
[selfcompile] 2015/10/03 15:10:44 Cleaning up: /tmp/go-selfcompile690079187
Success.
$ example-abinary
aplugin activated.
Just doing binary things
Fancy, right?
There's an end-to-end integration flow setup in the Makefile
. You can run it with make example-aplugin
.
This project was made possible thanks to Glider Labs.
MIT