avatarNicole Willson

Free AI web copilot to create summaries, insights and extended knowledge, download it at here

4324

Abstract

span> <span class="hljs-params">(c *calculator)</span></span> Calculate(num... <span class="hljs-type">int</span>) { ans := <span class="hljs-number">0</span> <span class="hljs-keyword">for</span> _, n := <span class="hljs-keyword">range</span> num { ans += n } fmt.Println(ans) }

<span class="hljs-keyword">var</span> Calculator calculator</pre></div><p id="c1d0">We exposed a struct which implements the method Calculate. This is required for the discovery and registration of the plugin. Now to compile this and make it a shared-object we need to build the library as a plugin.</p><div id="b6b4"><pre><span class="hljs-attribute">go build -o -buildmode</span>=plugin .</pre></div><p id="198a">After this, we will have a shared object file(in our case “<i>add.so</i>”) which we can dynamically load at runtime in our main application.</p><figure id="5129"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*HEBnzWVkvUP0JjhOsfOH7Q.png"><figcaption>updated file structure of the library</figcaption></figure><p id="5408">Now to dynamically load the library into our main application at run time we need use the plugin system of Golang.</p><div id="0960"><pre><span class="hljs-keyword">import</span> ( <span class="hljs-string">"fmt"</span> <span class="hljs-string">"os"</span> <span class="hljs-string">"plugin"</span> )

<span class="hljs-keyword">type</span> Calculator <span class="hljs-keyword">interface</span> { Calculate(num... <span class="hljs-type">int</span>) }

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> { calculatorPlugin, err := plugin.Open(<span class="hljs-string">"/abs/path/to/shared/object/file"</span>) <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> { fmt.Println(<span class="hljs-string">"error while opening shared object file"</span>) os.Exit(<span class="hljs-number">1</span>) }

symCalculator, err := calculatorPlugin.Lookup(<span class="hljs-string">"Calculator"</span>) <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> { fmt.Println(<span class="hljs-string">"error while lookup"</span>) os.Exit(<span class="hljs-number">1</span>) }

<span class="hljs-keyword">var</span> calculator Calculator calculator, ok := symCalculator.(Calculator) <span class="hljs-keyword">if</span> !ok { fmt.Println(<span class="hljs-string">"unexpected type from module symbol"</span>) os.Exit(<span class="hljs-number">1</span>) }

calculator.Calculate(<span class="hljs-number">3</span>,<span class="hljs-number">4</span>) }</pre></div><p id="f4f9">In this case if we are making any changes to library, we don’t need to re-compile our main application. We only need to recompile the library’s shared object and rerun our main application.</p><p id="a32d">Due to the different characteristics, the advantages and disadvantages of static and dynamic libraries are also obvious; binaries that rely only on static libraries and are generated by static linking can be executed independently because they contain all the dependencies, but the compilation result is also larger. Dynamic libraries can be shared among multiple executables, which can reduce the memory footprint, and their linking process is often triggered during loading or running, so they can contain some modules that can be hot-plugged and reduce the memory footprint. Compiling binaries using static linking has very obvious deployment advantages, and the final compiled product will run directly on most machines. The deployment benefits of static linking are far more important than the lower memory footprint, that’s why Golang uses static linking as the default linking method.</p><h1 id="d290">Issues with Dynamic-linking (shared library plugins) in Go</h1><p id="91cd">Plugins using shared libraries and the plugin package work well for Golang, as the previous section demonstrates. However, this approach also has some serious downsides. The most important downside is that Golang is very picky about keeping the main application and the shared libraries it loads compatible.</p><p id="285c">As an experiment, try using different versions of a common d

Options

ependency in the plugin application and the main application, rebuild the main application and run it. Most likely you’ll get this error:</p><div id="443c"><pre><span class="hljs-comment">"plugin was built with a different version of package XXX"</span></pre></div><figure id="d928"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/0*ow5zqQqWHmQoZqaC.gif"><figcaption></figcaption></figure><p id="35aa">The reason for this is that Golang wants all the versions of all packages in the main application and plugins to match exactly. It’s clear what motivates this: safety.</p><p id="7b0e">Consider C and C++ as counter-examples. In these languages, an application can load a shared library with dlopen and subsequently use dlsym to obtain symbols from it. dlsym is extremely weakly typed; it takes a symbol name and returns a void*. It’s up to the user to cast this to a concrete function type. If the function type changes because of a version update, the result can very likely be some sort of segmentation fault or even memory corruption.</p><p id="80a8">Since Golang relies on shared libraries from plugins, it has the same inherent safety issues. It tries to protect programmers from shooting themselves in the foot by ensuring that the application has been built with the same versions of packages as all its plugins. This helps avoid mismatch. In addition, the version of the Golang compiler used to build the application and plugins must match exactly.</p><p id="74b9">However, this protection comes with downsides — making developing plugins somewhat cumbersome. Having to rebuild all plugins whenever any common packages change — even in ways that don’t affect the plugin interface — is a heavy burden. Especially, considering that by their very nature plugins are typically developed separately from the main application; they may live in separate repositories, have separate release cadences etc.</p><h1 id="bfc1">Alternative approaches to shared library plugins in Golang</h1><p id="c642">Given that the plugin package was only added to Go in <a href="https://golang.org/doc/go1.8">version 1.8</a> and the limitation described previously, it’s not surprising that the Go ecosystem saw the emergence of alternative plugin approaches.</p><p id="87e5">One of the innovative approaches involves plugins via RPC. In this method instead of loading the plugins into the host process we load them in a separate process which then communicates to host via RPC or just TCP on localhost. It has several important upsides:</p><ul><li>Isolation: crash in a plugin does not bring the whole application down.</li><li>Interoperability between languages: if RPC is the interface, do you care what language the plugin is written in?</li><li>Distribution: if plugins interface via the network, we can easily distribute them to run on different machines for gains in performance, reliability, and so on.</li></ul><p id="f78c">Moreover, Golang makes this particularly easy by having a fairly capable RPC package right in the standard library: net/rpc.</p><p id="4495">One of the most widely used RPC-based plugin systems is <a href="https://github.com/hashicorp/go-plugin">hashicorp/go-plugin</a>. Hashicorp is well known for creating great Golang software, and apparently, they use go-plugin for many of their systems, so it’s battle-tested (though its documentation could be better 😛)</p><p id="1a23">Golang-plugin runs on top of net/rpc but also supports gRPC. Advanced RPC protocols like gRPC are well suitable for plugins because they include versioning out-of-the-box, tackling the difficult interoperability problem between different versions of plugins vs. the main application.</p><p id="c8a4">However, this is also<b> not a perfect solution </b>as we talk about the fourth fundamental of plugin systems- “<b>Extension APIs</b>”. In a complex system, a plugin might make lot of Extension APIs calls which will end up increasing the latency if we are making network calls via RPC or TCP.</p><h1 id="1c76">Conclusion</h1><p id="03fb">Golang still has a long way to go when it comes to Dynamic-linking (shared library plugins). No solution discussed in this blog can be considered perfect. One needs to consider the pros and cons of each solution available as per their specific requirements.</p></article></body>

A Handy List of My Writing on Medium

The cover of my debut novel Tidepool, designed by Shayne Leighton.

Thanks for visiting! Below is a listing of my work on Medium and some information about my debut novel Tidepool. If you want to learn more about what I’m up to in my writing life, sign up for my mailing list and get a short story (never published anywhere) as a thank-you gift.

Tidepool: Now Available Everywhere!

My debut novel Tidepool came out from Parliament House Press in August 2021 and was a finalist for a Bram Stoker Award for Superior Achievement in a First Novel and the Ladies of Horror Fiction Award for Best Debut. If you’re interested in Lovecraftian horror with a dash of American Horror Story, you’ll love Tidepool.

Hardback, paperback, eBook, and audiobook available from Amazon. Also available from most online bookstores.

Read more about it here!

My novella The Shadow Dancers of Brixton Hill is coming out from Cemetery Gates Media in summer 2023. More information as I get it.

The Weekly Knob Presents Writer Nicole Willson in Author’s Gold

The Weekly Knob’s editors were kind enough to ask me to write a little about myself and five of my favorite Knob stories; read all about it here.

50-Word Horror Stories (A 52-Week Challenge from the Writing Cooperative)

I made this into its own publication because this list page is getting crazy long. Read and/or follow here.

Selected Short Fiction for the Hinged.press (formerly The Weekly Knob) Prompt Challenge (Or Just Because)

(I’m in the process of changing these URLs over to Hinged.press, the new home of the publication formerly known as The Weekly Knob. Thanks for your patience.)

Turn All Things to Honey (Prompt: Honey) The Elimination Round (Prompt: Rice) Forever in Blue Jeans (Prompt: Jeans) Mr. Griswold’s Dreadful Things (Prompt: Prank) How to Get A Head in Death (Prompt: Necktie) Lighter Than Air (Prompt: Blimp) Every Home Should Have One (Prompt: Dragon) We’ll Take a Cup o’ Kindness Yet (Smell ya later, 2020) Send in the Clown (Prompt: Red Nose) The World Spinner (Prompt: Plate) Ding Dong Ditch (Prompt: Doorbell) The Rogues’ Tea Party (Prompt: Bookmark) Chained Melody (Prompt: Chain) The Devil’s Fingers (Prompt: Banana) Escape Velocity (Prompt: Swings) It Never Sleeps (Prompt: Rust) Made of Meat, Made of Tin (Prompt: Staples) Your Friend ’Til the End (Prompt: Teddy Bear) (Narrated by Nicole for The Weekly Knob’s YouTube channel) I Melt With You (Prompt: Fire) Meeting the Mother-in-Law (Prompt: Water) Fresh Air (Prompt: Air) The Callback (Prompt: Conch Shell) Last Supper (Prompt: Dinner Party) Going, Going, Gone (Prompt: Eraser) Stick (Prompt: Enamel Pin) Why Can’t I Be You? (Prompt: Mixtape) Gramma’s Teeth (Prompt: Dentures) Turn Me On, Dead Man (Prompt: Batteries) (Power Prompt winner!) True Tales to Tell (Prompt: Meat Hook) The Bloody Bride (Trope: Ax-Crazy) Odor of Chrysanthemums (Written for Chalkboard’s Write or Die challenge) The Greatest Trick of All (Prompt: Handcuffs) Jarred Alive (Prompt: Mason Jar) Priceless (Prompt: Barbie Doll) The Good Townspeople (Prompt: Rope) I Can Help (Prompt: Nail Clippers) The Dreadful Bargain (Prompt: Fountain) Who Steals My Purse Steals Trash (Prompt: Wallet) Rabbit, Rabbit (Prompt: Chocolate Egg) Drinking the Devil Under the Table (Prompt: Beer) The Masterpiece (Prompt: Painting) Killing Time in Room 309 (Prompt: Shower Curtain) The Amazing True Story of Mary Lincoln’s Teapot (Prompt: Teapot) Sharp-Dressed Man (Prompt: Bow Tie) The Good Listener (Prompt: Rotary Dial Phone) Winston Porter on the Ropes (Prompt: Jump Rope) The Oak Street Coffee-and-Chainsaws Club (Prompt: Chainsaw) Meat (Prompt: Spiderweb) The Night Watchman (Prompt: Flashlight) Riddle Me This (Prompt: Dixie (Paper) Cup) Winston Porter’s Heir Apparent (Prompt: Sunglasses) Sticker Shock (Prompt: Price Tag) One Man’s Trash (Prompt: Shopping Cart) The Fish Out of Water (Prompt: Aquarium) Dancing to Wake the Dead (Prompt: Tap Shoes) Mr. Bent’s Strange Talent (Prompt: Measuring Tape) If Wishes Were Motorcycles (Prompt: The photo in the story. Written for the Throw Down Challenge.) Winston Porter Gets Played for a Fool (Prompt: Xylophone) The Case of the Very Grating Roommate (Prompt: Cheese Grater) A Time to Come Clean (Prompt: Soap) The Bendy People (Prompt: Twist Tie) Ball of Confusion (Prompt: Saran Wrap) Your Friend ’Til the End (Prompt: Teddy Bear) Winston Porter Kicks the Bucket (Prompt: Bucket) Accept No Substitutes (Prompt: Artificial Plant) Trust Issues (Prompt: Valentine’s Card. Written for the Knob’s Members-Only Valentine’s Day Issue.) Arc of Iron (Prompt: Dumbbell) Doctor’s Orders (Prompt: Tire Iron) The Great Dust-Up (Prompt: Feather Duster) Should Old Acquaintance Be Forgot New Year’s Day (Prompt: Screwdriver) The Gingerbread Woman (Prompt: Gingerbread) Old Eunice (Prompt: Bobby Pin) A Little Girl and a Big Guitar (Prompt: Guitar) Transparency (Prompt: Scotch Tape) The Lady or the Tower (Prompt: Hair Brush) Sarah the Spy (Prompt: Notebook) Welcome to the Neighborhood (Prompt: Extension Cord) Rivers of Red (Prompt: Doorknob. Written for the Weekly Knob’s Scary Story edition.) The Cut Direct (Prompt: Scissors) Winston Porter Rolls the Dice (Prompt: Dice) The Balloon on the Train (Prompt: Balloon) Birthday Girl (Prompt: Candle) Button, Button (Prompt: Button) The Unwanted Gift (Prompt: Mirror) The One Who Hides the Weapons (Prompt: Fly Swatter) Winston Porter Loses His Marbles (Prompt: Marbles) You May Already Be A Winner (Prompt: Junk Mail)

Posts for the Ninja Writers May 2017 Post-A-Day Challenge + Assorted Nonfiction

(Some of these served double duty as posts for other weekly challenges.)

There’s No Party Like a Twitter Pitch Party Ten Interesting(?) Things About Me Persistence: The Long Game 5/31: Challenge’s End 5/30: Why I Love Harriet the Spy 5/29: To End All You’ve Become 5/28: The Rain on the Parade 5/27: The Case of the Very Grating Roommate 5/26: Ups and Downs and Ups 5/22: The Feast of Unintended Consequences 5/21: Burnout 5/20: Race Against Time, Part 2: The Recall 5/17: Things to Watch Out for When Querying 5/16: Rejection Collection 5/15: Rock-a-Bye 5/14: Things That Are Awesome: Pictures of You 5/13: A Time to Come Clean 5/12: No, I Do NOT Prefer Writing By Hand 5/11: Stupid Writing Quirks #1 5/10: The Flounce 5/9: Ill-Gotten Nabokov 5/8: Four Lies and One Truth 5/7: Memories from the Moon 5/6: Colin Throws A Curveball 5/5: Stuff That’s in My Writing Space 5/4: How to Get Me to Read Your Novel 5/3: 2017: The Year I Became a Full-Fledged Twit 5/2: Better Late Than Never 5/1: Behind That Door

The Old Autograph Book Series

A series of stories I’m writing based off of the contents of an old autograph book I bought back in 2002. Now also a Medium series!

Short Fiction
Fiction
Writing Prompts
Short Story
Horror Fiction
Recommended from ReadMedium