How to write a program which can support plugin

Z

Zheng Da

I don't know where should I ask the question, so send the email to this
group.
I choose this group, because I want to write the program with c++ :)
I want to write a program which support multiprotocol, but do not want
to write code for all protocols which I want to support. I plan I give
a interface and others give a module which implements a protocol, and
then the module can be inserted into my program without recompiling my
program.
How should I write the program to support this function?
Thank you.
 
B

benben

Zheng Da said:
I don't know where should I ask the question, so send the email to this
group.
I choose this group, because I want to write the program with c++ :)
I want to write a program which support multiprotocol, but do not want
to write code for all protocols which I want to support. I plan I give
a interface and others give a module which implements a protocol, and
then the module can be inserted into my program without recompiling my
program.
How should I write the program to support this function?
Thank you.

well, before all you must define terms like "module" and "plugin" and
"protocol". Then you think about how you C++ system can support them, and
then with more specific questions, you can revisit this group and you will
be greeted with much better answers than this one. The language really
doesn't have direct support for any of what you want. Take a look at things
like shared library, or COM or CORBA.

ben
 
A

Alan Johnson

Zheng said:
I don't know where should I ask the question, so send the email to this
group.
I choose this group, because I want to write the program with c++ :)
I want to write a program which support multiprotocol, but do not want
to write code for all protocols which I want to support. I plan I give
a interface and others give a module which implements a protocol, and
then the module can be inserted into my program without recompiling my
program.
How should I write the program to support this function?
Thank you.

There are two halves to your question. First, how do you support that
from a language standpoint? Second, how do you support that from a
platform standpoint?

From a language standpoint, the best way (in my opinion) to support
that sort of behavior is to define your interface as an abstract base
class (or if appropriate, a set of abstract base classes). An /abstract
class/ is one that contains at least one pure virtual function. It is
my recommendation that your interface contain only pure virtual
functions. Example:

class protocol_interface
{
public :
virtual void do_something_neat() = 0 ;
virtual int get_some_information() = 0 ;
virtual bool is_whatever() = 0 ;
} ;

Then, when people go to write a specific protocol, they will derive from
your interface, and implement the functions. For example:

class my_boring_protocol : public protocol_interface
{
public :
void do_something_neat() { std::cout << "This is neat!" << std::endl ; }
int get_some_information() { return 42 ; }
bool is_whatever() { return false ; }
} ;


Somewhere in your application you will have a protocol_interface pointer
that you use to control the protocol. Assume for a minute that you
managed to get it to point at an instance of my_boring_protocol, then it
would be my_boring_protocol's implementation that was being used.

So, how do you get your application's protocol_interface pointer to
point at an instance of my_boring_protocol, since it did not know know
about the existence of my_boring_protocol when it was compiled? That is
where the platform specific part of your question kicks in.
Unfortunately, I can't fully answer that for you because I don't know
what platform you are using, nor is that on topic for this newsgroup.
However, whatever platform you are using probably has some concept of
shared objects or shared libraries. On Windows these are called DLLs,
and on most Unix variants these are .so files.

Whatever your platform, it probably has some function that let's you
load an arbitrary shared object, and get the address of an arbitrary
function inside it. What you'll likely want to do is have a function
that returns a protocol_interface pointer that points to an instance of
the type of protocol that that shared object manages. For example:

my_boring_protocol mbp_inst ;

extern "C"
protocol_interface *get_instance() { return &mbp_inst ; }

If the instance returned in dynamically allocated, you probably need to
also have a function to destroy the instance when you are done with it.

Finally, if you are are using Windows, I've written a working example
you are free to copy and mess around with. The following package
contains all the code and a Visual Studio project to build it:
http://www.stanford.edu/~alanwj/examples/protocol_plugins_example.zip

-Alan
 
B

benben

From a language standpoint, the best way (in my opinion) to support
that sort of behavior is to define your interface as an abstract base
class (or if appropriate, a set of abstract base classes). An /abstract
class/ is one that contains at least one pure virtual function. It is
my recommendation that your interface contain only pure virtual
functions. Example:

class protocol_interface
{
public :
virtual void do_something_neat() = 0 ;
virtual int get_some_information() = 0 ;
virtual bool is_whatever() = 0 ;
} ;

Ok, unless the object can be disposed of by other means, it's desirable to
provide a destructor for the protocol_interface class, i.e.

class protocol_interface
{
public:
virtual void do_something_neat() = 0 ;
virtual int get_some_information() = 0 ;
virtual bool is_whatever() = 0 ;

virtual ~protocol_interface(){}
};

Note that the destructor cannot be pure virtual.
Then, when people go to write a specific protocol, they will derive from
your interface, and implement the functions. For example:

class my_boring_protocol : public protocol_interface
{
public :
void do_something_neat() { std::cout << "This is neat!" << std::endl ; }
int get_some_information() { return 42 ; }
bool is_whatever() { return false ; }
} ;


Somewhere in your application you will have a protocol_interface pointer
that you use to control the protocol. Assume for a minute that you
managed to get it to point at an instance of my_boring_protocol, then it
would be my_boring_protocol's implementation that was being used.

To correctly dispatch virtual function calls, the caller must have an
agreement on the plugin object's in memory layout. However, object layout is
implementation-defined. Further, the user must cast from protocol_interface*
to my_boring_protocol*. An obvious solution is to dynamic_cast<> the
pointer. However, different compilers implement dynamic_cast<> and object
layout differently. Therefore to properly cast the pointer all modules must
be compiled by the same compiler.
So, how do you get your application's protocol_interface pointer to
point at an instance of my_boring_protocol, since it did not know know
about the existence of my_boring_protocol when it was compiled? That is
where the platform specific part of your question kicks in.
Unfortunately, I can't fully answer that for you because I don't know
what platform you are using, nor is that on topic for this newsgroup.
However, whatever platform you are using probably has some concept of
shared objects or shared libraries. On Windows these are called DLLs,
and on most Unix variants these are .so files.

With dynamically linked library, it is hard to guarantee that there is a
single RTTI in-memory representation even if you use the same compiler for
all plugin modules. The impact is subtle but can be substantial.
Whatever your platform, it probably has some function that let's you
load an arbitrary shared object, and get the address of an arbitrary
function inside it. What you'll likely want to do is have a function
that returns a protocol_interface pointer that points to an instance of
the type of protocol that that shared object manages. For example:

my_boring_protocol mbp_inst ;

extern "C"
protocol_interface *get_instance() { return &mbp_inst ; }

If the instance returned in dynamically allocated, you probably need to
also have a function to destroy the instance when you are done with it.

Finally, if you are are using Windows, I've written a working example
you are free to copy and mess around with. The following package
contains all the code and a Visual Studio project to build it:
http://www.stanford.edu/~alanwj/examples/protocol_plugins_example.zip

And if windows is the intended platform exclusively, then the Component
Object Model does exactly you have described.

Warm regards,
Ben
 
V

Vyacheslav Kononenko

Zheng said:
I don't know where should I ask the question, so send the email to this
group.
I choose this group, because I want to write the program with c++ :)
I want to write a program which support multiprotocol, but do not want
to write code for all protocols which I want to support. I plan I give
a interface and others give a module which implements a protocol, and
then the module can be inserted into my program without recompiling my
program.
How should I write the program to support this function?
Thank you.

I think there are two generic ways to achieve such functionality. One
way to use shared/dynamic library. Another one is to use embedded
scripting language interpreter like tcl or perl or something else. Or
you can use both. Each way has it's own pluses and minuses so you need
to decide which way is better for your particular case.

Regards,
Vyacheslav
 
Z

Zheng Da

Thank you for your advice.
It seems I have to learn much about how to use shared/dynamic library,
or how to use embedded
scripting language to give such a support.
 
A

Alan Johnson

benben said:
Ok, unless the object can be disposed of by other means, it's desirable to
provide a destructor for the protocol_interface class, i.e.

class protocol_interface
{
public:
virtual void do_something_neat() = 0 ;
virtual int get_some_information() = 0 ;
virtual bool is_whatever() = 0 ;

virtual ~protocol_interface(){}
};

Note that the destructor cannot be pure virtual.

I disagree here. Generally, it is a bad idea to be deleting pointers
that came from the depths of some other module that your application
doesn't fully understand. The destructor's here should never be called
(at least not in a virtual fashion), so it is just clutter to include
them, and possibly misleading to people who maintain your code later.
To correctly dispatch virtual function calls, the caller must have an
agreement on the plugin object's in memory layout. However, object layout is
implementation-defined.

I agree that this issue isn't something I've put a whole lot of thought
into, other than requiring that everything be compiled with the same
compiler (or compilers that implement things in a compatible way with
your application).
Further, the user must cast from protocol_interface*
to my_boring_protocol*. An obvious solution is to dynamic_cast<> the
pointer. However, different compilers implement dynamic_cast<> and object
layout differently. Therefore to properly cast the pointer all modules must
be compiled by the same compiler.

Why would you ever need the my_boring_protocol*? The application
doesn't even know what my_boring_protocol is, so there's nothing it
could do with a pointer to it.
With dynamically linked library, it is hard to guarantee that there is a
single RTTI in-memory representation even if you use the same compiler for
all plugin modules. The impact is subtle but can be substantial.




And if windows is the intended platform exclusively, then the Component
Object Model does exactly you have described.

Agreed, COM is basically what I was basing the whole description on.
 
B

benben

Alan Johnson said:
I disagree here. Generally, it is a bad idea to be deleting pointers
that came from the depths of some other module that your application
doesn't fully understand. The destructor's here should never be called
(at least not in a virtual fashion), so it is just clutter to include
them, and possibly misleading to people who maintain your code later.

Objects have to be destroyed at some stage, by one mean or another. If not,
you leak memory. IMO, the object itself (or, techinically, the class that
constructs the object) knows how to destroy itself better than other
entities. You can, of course, call a global function provided by the module
to do the job, with two major downsides:

1. If the caller loads two plugins which define exactly same set of global
functions to link against, then the caller must resolve the module, get a
function pointer then call the function. Now this not only is tedious but it
also bundles the module with the object. In other words, you may destroy the
object incorrectly by calling a global function from a plugin module other
than the one that allocates and constructs the object to be destroyed.

2. Without a virtual destructor, the implementation of the global function
can be quite messy. At best, it must manage to get the exact type of the
object and with some tricks cast the pointer back to the type and destroy
it.
I agree that this issue isn't something I've put a whole lot of thought
into, other than requiring that everything be compiled with the same
compiler (or compilers that implement things in a compatible way with
your application).


Why would you ever need the my_boring_protocol*? The application
doesn't even know what my_boring_protocol is, so there's nothing it
could do with a pointer to it.

Frankly, I don't know. But if it is not meant to be used why did you define
it?
 
Z

Zheng Da

Could you give an example which uses embedded scripting language
interpreter to give the support for plugin?
I searched with google, and found the solution everyone gives is use
the dynamic library.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,297
Messages
2,571,536
Members
48,284
Latest member
alphabetsalphabets

Latest Threads

Top