Hello all,

Here are some thoughts and questions about plugins in Go 1.8 (which I use 
on Linux/x86-64).

*Plugins in other languages*

In C and C++ code (on Linux), plugins are practically not exactly the same 
as e.g. shared objects (a good reference would be Drepper's *How To Write 
Shared Libraries* <https://www.akkadia.org/drepper/dsohowto.pdf> paper). In 
practice, a plugin is a (dlopen-ed) shared object *with references to 
symbols in the main program*. For example, a GCC plugin 
<https://gcc.gnu.org/onlinedocs/gccint/Plugins.html> (this is an example 
that both Ian Taylor & me know well) will call functions from GCC itself 
(such as register_callback or many others, e.g. gimple_block etc etc...). 
Likewise, a GEDIT plugin <https://wiki.gnome.org/Apps/Gedit/ShippedPlugins> 
(for example the wordcompletion 
<https://git.gnome.org/browse/gedit-plugins/tree/plugins/wordcompletion/gedit-word-completion-plugin.c>
 
one) will call GEDIT or GTK functions like gedit_debug or 
gtk_text_view_get_buffer etc...). Notice that to make that possible the 
main program (cc1plus for GCC
or gedit) has to be linked with the -rdynamic flag (to make the symbols of 
the main program visible from the plugin). Even if that is in theory 
principle, it is 

uncommon to dlopen a shared object which is not a plugin, designed and coded to 
call *symbols* from the *main program* (a program might in theory dlopen some 
plain shared library  like /usr/lib/x86_64-linux-gnu/libgdbm.so.3 but in 
practice this is never done; program loading plugins are dlopen-ing some 
shared object -the plugin- *specifically designed* for them, and *calling 
functions* from the main program, and the main program uses dlsym to find some 
specific 
symbols such as plugin_init for GCC obeying some signature convention). I 
deliberately ignore plugins loading other plugins (but I know about RTLD_GLOBAL 
flag to dlopen <http://man7.org/linux/man-pages/man3/dlopen.3.html>)
and I know about constructor function attributes 
<https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.htm> in plugins.

In JAVA, there are class loaders 
<https://en.wikipedia.org/wiki/Java_Classloader> with a sophisticated protocol 
for loading them.

In Ocaml, you have the dynlink 
<http://caml.inria.fr/pub/docs/manual-ocaml/libdynlink.html> library. The 
Dynlink.loadfile function 
<http://caml.inria.fr/pub/docs/manual-ocaml/libref/Dynlink.html> is similar to 
dlopen (and will run the plugin initialization code).
There is no equivalent of dlsym: the plugin is supposed to e.g.  register 
function values at initialization time, perhaps by passing them to 
some function of the main program. Of course the plugin can call functions from 
the main program.

*Plugins and packages in Go*

The *package* concept is a core concept of Go since every source file belongs 
to some package (with main being a special case) and often imports several 
other ones.
Practically speaking, a Go plugin is likely to call functions from some package 
defined by the main program and having itself (the plugin) some packages. So the
 tiny example in plugin documentation <https://tip.golang.org/pkg/plugin/> is a 
bit too naive (even if it is calling fmt.Printf). A *realistic example* would 
be a program having not only some main function 
in its main package, but also defining some purple package having some Foo 
public function called as purple.Foo from main and having a Bar public function
(with purple.Bar called from the plugin). The plugin would have not only some 
public F function in its main package (which should call purple.Bar from the 
main 
plugin-loading program) but also some plugin specific yellow package with a 
public Y function called (as yellow.Y) from F. I hope that such a realistic 
example will be 
given in the documentation of future Go 1.9.


Unfortunately, I know no public mechanism to say, within the source code of 
a plugin, that some imported package is (and has to be) provided by the 
main loading program.
I would suggest to re-use and extend the import comment 
<https://golang.org/cmd/go/#hdr-Import_path_checking> convention (with the 
path "*" being a notation to say *import that package from the main loading 
program*). For example, our plugin.go source code might have import 
"purple" // import "*" on a single line, and then the purple package would 
be externally linked (not incorporated in the plugin; exactly like in some 
GCC plugin calling gimple_block does not add all the existing GIMPLE 
processing code into the plugin).

Currently, a plugin which uses some package (even a standard one like fmt; 
but I am thinking of a program-supplied one like purple)  is linking it 
*twice* (once in the main program, and once in the plugin). This is 
*inefficient* (compile time of plugins -even a tiny one- is huge, and their 
shared object size is much too big) and *error prone* (it is not defined 
what happens if the version of that package is different, and there might 
be -in weird cases- infelicities with multiple initialization of the same 
package)




*A use case*In my monimelt <https://github.com/bstarynk/monimelt> program 
(which is now buildable with go tool and don't use gb anymore, since gb 
does not support plugins yet) commit 6bb8b56160749 
<https://github.com/bstarynk/monimelt/commit/6bb8b5616074942327748934e735e92de602f824>
the test-plugins/makename.go 
<https://github.com/bstarynk/monimelt/blob/master/test-plugins/makename.go> 
is a simplistic plugin which just calls a few functions from the objvalmo & 
payloadmo packages defined in the main program. But its compilation 
time with build-plugin-monimelt.sh 
<https://github.com/bstarynk/monimelt/blob/master/build-plugin-monimelt.sh> 
script is ridiculously big, since all the packages of the main program (and 
even external ones like go-sqlite) get linked both in the main program and 
the plugin. To run that test, do ./monimelt -run-plugin 
test-plugins/makename.go which will compile test-plugins/makename.go into 
makename.so using build-plugin-monimelt.sh script and open that plugin. The 
whole point of monimelt will be to generate Go source code (of plugins) at 
runtime and compile and load them (I followed the same idea in GCC MELT 
<http://gcc-melt.org/>).

BTW, I am interested in reading some white paper about the precise 
semantics of packages, and how the Go compiler works internally.

Cheers
-- 
Basile Starynkevitch <http://starynkevitch.net/Basile/> (France)

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to