• Stars
    star
    318
  • Rank 129,012 (Top 3 %)
  • Language
    Go
  • License
    MIT License
  • Created over 7 years ago
  • Updated 10 days ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Playing around with Go 1.8 plugin system

Go Plugin Example

The code in this repository shows how to use the new plugin package in Go 1.8 (see https://tip.golang.org/pkg/plugin/). A Go plugin is package compiled with the -buildmode=plugin which creates a shared object (.so) library file instead of the standar archive (.a) library file. As you will see here, using the standar library's plugin package, Go can dynamically load the shared object file at runtime to access exported elements such as functions an variables.

You can read the related article on Medium.

Requirements

The plugin system requires Go version 1.8. At this time, it is only supports plugin on Linux. Attempt to compile plugins on OSX, for instance, will result in -buildmode=plugin not supported on darwin/amd64 error.

A Pluggable Greeting System

The demo in this repository implements a simple greeting system. Each plugin package (directories ./eng and ./chi) implements code that prints a greeting meesage in a different lanaguage. File ./greeter.go uses the new Go plugin package to load the pluggable modules and displays the proper message using passed command-line parameters.

For instance, when the program is executed it prints a greeting in English or Chinese using the passed parameter to select the plugin to load for the appropriate language.

> go run greeter.go english
Hello Universe

Or to do it in Chinese:

> go run greeter.go chinese
你好宇宙

As you can see, the capability of the driver program is dynamically expanded by the plugins allowing it to display a greeting message in different language without the need to recompile the program.

Let us see how this is done.

The Plugin

To create a pluggable package is simple. Simply create a regular Go package designated as main. Use the capitalization rule to indicate functions and variables that are exported as part of the plugin. This is shown below in file ./eng/greeter.go. This plugin is responsible for displaying a message in English.

File ./eng/greeter.go

package main

import "fmt"

type greeting string

func (g greeting) Greet() {
	fmt.Println("Hello Universe")
}

// this is exported
var Greeter greeting

Notice a few things about the pluggable module:

  • Pluggable packages are basically regular Go packages
  • The package must be marked main
  • The exported variables and functions can be of any type (I found no documented restrictions)

The previous code exports variable Greeter of type greeting. As we will see later, the code that will consume this exported value must have a compatible type for assertion. One way this can be handled is to have an interface with the same method set. (The plugin package in directory ./chi is exactly the same code except the message is in Chinese.)

Compiling the Plugins

The plugin package is compiled using the normal Go toolchain. The only requirement is to use the buildmode=plugin compilation flag as shown below:

go build -buildmode=plugin -o eng/eng.so eng/greeter.go
go build -buildmode=plugin -o chi/chi.so chi/greeter.go

The compilation step will create ./eng/eng.so and ./chi/chi.so plugin files respectively.

Using the Plugins

Once the plugin modules are available, they can be loaded dynamically using the Go standard library's plugin package. Let us examine file ./greeter.go, the driver program that loads and uses the plugin at runtime. Loading and using a shared object library is done in several steps as outlined below:

1. Import package plugin

import (
	...
	"plugin"
)

2. Define/select type for imported elements (optional)

The exported elements, from the pluggable package, can be of any type. The consumer code, loading the plugin, must have a compatible type defined (or pre-defined in case of built-in types) for assertion. In this example we define interface type Greeter as a type that will be asserted against the exported variable from the plugin module.

type Greeter interface {
	Greet()
}

3. Determine the .so file to load

The .so file must be in a location accessible from you program in order to open it. In this example, the file .so files are located in directories ./eng and ./chi. and are selected based on the value of a command-line argument. The selected name is then assigned to variable mod.

func main() {
	// determine module to load
	lang := "english"
	if len(os.Args) == 2 {
		lang = os.Args[1]
	}
	var mod string
	switch lang {
	case "english":
		mod = "./eng/eng.so"
	case "chinese":
		mod = "./chi/chi.so"
	default:
		fmt.Println("don't speak that language")
		os.Exit(1)
	}
...

4. Open the plugin package

Using the Go standard library's plugin package, we can now open the plugin module. That step creates a value of type *plugin.Plugin. It is used later to manage access to the plugin's exported elements.

func main(){
...
	// load module
	// 1. open the so file to load the symbols
	plug, err := plugin.Open(mod)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
...

6. Lookup a Symbol

Next, we use the *plugin.Plugin value to search for symbols that matches the name of the exported elements from the plugin module. In our example plugin (./eng/greeter.go, seen earlier), we exported a variable called Greeter. Therefore, we use plug.Lookup("Greeter") to locate that symbol. The loaded symbol is then assigned to variable symGreeter (of type package.Symbol).

func main(){
...
	// 2. look up a symbol (an exported function or variable)
	// in this case, variable Greeter
	symGreeter, err := plug.Lookup("Greeter")
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
...

7. Assert the symbol's type and use it

Once we have the symbol loaded, we still have one additional step before we can use it. We must use type assertion to validate that the symbol is of an expected type and (optionally) assign its value to a variable of that type. In this example, we assert symbol symGreeter to be of interface type Greeter with symGreeter.(Greeter). Since the exported symbol from the plugin module ./eng/eng.so is a variable with method Greet attached, the assertion is true and the value is assigned to variable greeter. Lastly, we invoke the method from the plugin module with greeter.Greet().

func main(){
...
	// 3. Assert that loaded symbol is of a desired type
	// in this case interface type Greeter (defined above)
	var greeter Greeter
	greeter, ok := symGreeter.(Greeter)
	if !ok {
		fmt.Println("unexpected type from module symbol")
		os.Exit(1)
	}

	// 4. use the module
	greeter.Greet()

}

More Repositories

1

go-cshared-examples

Calling Go Functions from Other Languages using C Shared Libraries
Dart
849
star
2

automi

A stream processing API for Go (alpha)
Go
791
star
3

ktop

A top-like tool for your Kubernetes clusters
Go
676
star
4

gosh

Gosh - a pluggable framework for building command shell programs
Go
525
star
5

go-grpc

A collection of gRPC and Go examples showcasing features of the framework
Go
240
star
6

learning-go

Source code repository for my book "Learning Go Programming"
Go
232
star
7

go4vl

A Go library for working with the Video for Linux API (V4L2).
C
228
star
8

go-networking

Code sample for Learning Network Programming with Go
Go
213
star
9

gowfs

A Go client binding for Hadoop HDFS using WebHDFS.
Go
134
star
10

clamshell-cli

A framework to build command-line console applications in Java
Java
134
star
11

k8s-client-examples

Building stuff with the Kubernetes API
Go
116
star
12

gexe

Script-like OS interaction wrapped in the security and type safety of the Go programming language
Go
71
star
13

iot-dev

Example IoT projects
Go
68
star
14

jmx-cli

[Project Inactive] Jmx-Cli is a command-line interface console for JMX
Java
66
star
15

go-ntp-client

A Network Time Protocol client in Go
Go
50
star
16

gomes

Pure Go Framework API for Apache Mesos
Go
33
star
17

workbench

My code collection for testing new ideas, blog examples, etc
Java
32
star
18

go-tar

Examples using archive/tar compress/gz Go packages
Go
17
star
19

go-binary

Examples using encoding/binary package
Go
16
star
20

streaming-runtime-go

Go
11
star
21

docker.io-recipes

Some favorite Docker.Io recipes
9
star
22

go-tutorials

A place for quick Go tutorials
Go
5
star
23

dapr-examples

Examples of Dapr distributed services in Go
Go
5
star
24

startype

Roundtrip automatic conversion of Starlark-Go API types to regular Go types and back🤩
Go
4
star
25

go-algorithms

Classic CS algorithms examples in Go
Go
4
star
26

embedding-starlark

Examples of how to embed Starlark in Go programs using the Starlark-Go project
Go
4
star
27

mesos-http

Example of Mesos HTTP API
Protocol Buffer
3
star
28

jmx-logger

JMX Logger for JUL and Log4J (old project & little support)
Java
3
star
29

go-httpmux-example

Example to show use of the new enhanced http.ServeMux router in Go v1.22.0 or later
Go
2
star
30

kob

kob simplifies the programmatic construction of Kubernetes API object graphs
Go
2
star
31

gophercon2022

GopherCon 2022 - reveal.js presentation
JavaScript
2
star
32

timeapp

A simple application to print time based on configured time layout (perfect Kubernetes sample app)
Go
2
star
33

go-in-10

Go
2
star
34

mqt

MQT = Mesos Query Tool
Go
1
star
35

cloudy-apps

Cloud native application examples
Go
1
star
36

emojiis

Emojiis is a Go module for emoji icon search
Go
1
star
37

knative-workbench

Playing around with knative examples
Go
1
star
38

libstorage-client

Sample code on writing libstorage client code
Go
1
star
39

mango

Playground for an automated build tool in Go
Go
1
star
40

pourover

simple http reverse proxy
Go
1
star
41

vladimirvivien

1
star
42

go-tour

Examples and test code I use to tour the Go language and packages
Go
1
star
43

homebrew-oss-tools

Homebrew repository for distributing OSS binaries.
Ruby
1
star
44

go-workbench

A playground for Go proof of concepts
Go
1
star
45

horizon

Framework for building distributed apps
Go
1
star
46

e2eframework-controller-example

Repository for showing how to test Kubebuilder's Cronjob example controller using the e2e-framework - https://github.com/kubernetes-sigs/e2e-framework
Go
1
star