Reflection of an external component

I have an idea for a program I want to write, that requires some plugin functionality. I want to write it in Go, but I am not sure if it is possible.

Basically I want my main program to be able to load in a number of plugins, that are required to implement a specific interface. The plugins should be placed in a specific plugin folder.

I have never used reflection (reflect package) in Go before, and my initial search did not return any examples of how to “load” a “component” from a specific path. Is that even possible in Go?

Example in C# : reflection - Loading DLLs at runtime in C# - Stack Overflow

mainExecutable
       |
       ------- plugin folder
                    |
                    ------- plugin 1
                    |
                    ------- plugin 2
                    |
                   ...
                    ------- plugin n

Go programs compile into monolithic binaries. Normally they don’t load any dynamic dependencies into the runtime, other than doing system calls or wrappers for third-party native libraries (database drivers, GUI, etc.).

Your best options would be:

  1. Embed a scripting language like Lua and have users write plugins in that language. Some Go programs already do that, e.g. the Micro editor.
  2. Build plugins as separate programs (and then they don’t even need to be implemented in Go) and interface with them in some other way – stdin/stdout, HTTP, etc. I’d look at Language Server Protocol as an example of this approach.

Hmm…I was afraid of that…

I guess option 2 seems like the way I will have to go then. Maybe every plugin will have to create a JSON file, or something. I will have to think about that…Thanks!

Have you tried this: plugin package - plugin - Go Packages ?

You can compile golang program to a *.so or *.dll (for windows). Here is an example:

In the image above, I create a shared library called plugin1.so, and it exposes 2 symbols V and F. This can be compiled independently from the root main.go. In the root main.go, I can load it using plugin.Open("plugin1.so") and call the F function.

Notice that this happen dynamically. I compile both program independent to each other.

2 Likes

That looks VERY interesting! I will definitely take a look at that…

Also check out the build (run) constraints (tags/options), e.g. like this:

//go:build full

I use this at the top of a main_full.go file that is only built (or run) when I pass in a compile option like this:

go build -o quando.exe -ldflags -H=windowsgui -tags=full .

The main_full itself then references the modules that are only built/run for that tag.

You can also have multiple tag options as well.

These aren’t run time options after deployment (compilation) - though as a developer you can run with them (basically recompiles without creating a reusable executable).

I hope this suits your use case.