go-selfcompile

Build self-recompiling Go binaries

MIT License

Stars
39

go-selfcompile

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.

Why?

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()!

How does it work?

Plugins

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

Self-compiling Binary

Next, to use go-selfcompile in your binary you'll need to do two things:

  1. 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.

  2. 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

Examples

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?

Developing

There's an end-to-end integration flow setup in the Makefile. You can run it with make example-aplugin.

Sponsors

This project was made possible thanks to Glider Labs.

License

MIT