Description of problem: nbdkit-plugin.h uses extern on a number of functions and causes missing symbol errors when compiling in a c++ nbdkit plugin due to c++ name mangling. Example fix Use an ifdef to check for __cpluscplus and define LANG "C" if found else set it to blank. On the extern lines change from extern void nbdkit_error (const char *msg, ...) to extern LANG void nbdkit_error (const char *msg, ...)
Fixed upstream: https://github.com/libguestfs/nbdkit/commit/3647fe831a5c6d12832c4e48d1337489fd44fa59
The upstream fix doesn't catch this register plugin macro #define NBDKIT_REGISTER_PLUGIN(plugin) \ extern struct nbdkit_plugin * \ plugin_init (void) \ { \ (plugin)._struct_size = sizeof (plugin); \ (plugin)._api_version = NBDKIT_API_VERSION; \ (plugin)._thread_model = THREAD_MODEL; \ return &(plugin); \ } leaves the user to call extern "C" { NBDKIT_REGISTER_PLUGIN(myplugin) } when they call it for nbdkit to pick it up. Was also hesitant to extern "C" around the other include files #include <stdarg.h> #include <stdint.h>
Well I can _nearly_ get this to work, but when I try to compile a plugin with g++, I get: test-cxx-plugin.cpp:149:1: sorry, unimplemented: non-trivial designated initializers not supported Apparently you're not allowed to partially declare a struct in C++, so this isn't legal (or is legal but G++ doesn't support it, I'm not sure which): static struct nbdkit_plugin plugin = { name : "cxx", version : PACKAGE_VERSION, load : cxx_load, open : cxx_open, get_size : cxx_get_size, pread : cxx_pread, };
Created attachment 1246711 [details] 0001-Really-fix-C-support-in-the-nbdkit-plugin.h-header-f.patch Interim patch (not working).
(In reply to Richard W.M. Jones from comment #3) > Apparently you're not allowed to partially declare a struct in C++, > so this isn't legal (or is legal but G++ doesn't support it, I'm not > sure which): > > static struct nbdkit_plugin plugin = { > > name : "cxx", It is a language shortcoming of C++. http://stackoverflow.com/questions/11516657/c-structure-initialization discusses various alternatives, none of them very satisfying for a POD type (which this is). You're pretty much limited to default initialization and per-member assignments, which makes it hard to create a pre-initialized static struct.
Quoting from the link in comment 5, this might be viable: I found this way of doing it for global variables, that does not require to modify the original structure definition : struct address { int street_no; char *street_name; char *city; char *prov; char *postal_code; }; then declare the variable of a new type inherited from the original struct type and use the constructor for fields initialisation : struct temp_address : address { temp_address() { city = "Hamilton"; prov = "Ontario"; } } temp_address;
OK I posted a proper fix (unfortunately rather complex): https://www.redhat.com/archives/libguestfs/2017-February/msg00004.html
(In reply to Eric Blake from comment #6) > Quoting from the link in comment 5, this might be viable: > > I found this way of doing it for global variables, that does not require to > modify the original structure definition : > > struct address { > int street_no; > char *street_name; > char *city; > char *prov; > char *postal_code; > }; > > then declare the variable of a new type inherited from the original struct > type and use the constructor for fields initialisation : > > struct temp_address : address { temp_address() { > city = "Hamilton"; > prov = "Ontario"; > } } temp_address; Hmm OK, I'll see if that works ... The way I did it in the patch above was the use __attribute__((constructor)) to include a function that would run before plugin_init was called.
you can also use a static initializer function example of anon namespace initializer namespace { nbdkit_plugin create_my_plugin() { nbdkit_plugin plugin = nbdkit_plugin(); plugin.name = plugin_name; plugin.load = plugin_load; plugin.unload = plugin_unload; plugin.config = plugin_config; plugin.config_complete = plugin_config_complete; plugin.config_help = plugin_config_help; plugin.open = plugin_open; plugin.close = plugin_close; plugin.get_size = plugin_get_size; plugin.pread = plugin_pread; plugin.pwrite = plugin_pwrite; plugin.flush = plugin_flush; plugin.trim = plugin_trim; return plugin; } } static struct nbdkit_plugin = create_my_plugin(); example of c++11 lambda initializer static nbdkit_plugin plugin = []() -> nbdkit_plugin { nbdkit_plugin plugin = nbdkit_plugin(); plugin.name = plugin_name; plugin.load = plugin_load; plugin.unload = plugin_unload; plugin.config = plugin_config; plugin.config_complete = plugin_config_complete; plugin.config_help = plugin_config_help; plugin.open = plugin_open; plugin.close = plugin_close; plugin.get_size = plugin_get_size; plugin.pread = plugin_pread; plugin.pwrite = plugin_pwrite; plugin.flush = plugin_flush; plugin.trim = plugin_trim; return plugin; }();
Patch v2 posted: https://www.redhat.com/archives/libguestfs/2017-February/msg00007.html
Yeah I guess comment 9 is better. Patch v3 posted: https://www.redhat.com/archives/libguestfs/2017-February/msg00009.html
OK I pushed the v3 patch upstream.