This is the mail archive of the
cygwin-talk
mailing list for the cygwin project.
Re: how come #include "*.cpp" works?
mwoehlke wrote:
I'm writing a program to dump structures from core dumps generated from
symbol-less binaries (i.e. no easy looking at structures, etc, in gdb).
It works great; you give it a structure name and an address and it
reads, decodes, and prints the structure, as well as referenced objects
like strings (the idea being to dump whole hierarchies of structures at
once).
Anyway... what I do is have an "OBJ" ABC and subclass it for each type
of structure I want this program to be able to understand. What I want
to do is have some system that entails the fewest *lines* of code
(macros to turn one line into lots of *actual* code are OK) that can a:
construct an object by name, and b: provide me a list of names of
classes which can be created (i.e. if you enter an invalid one, it will
tell you valid ones). Any thoughts? (Maybe dropping a hippo on the code
will make it as small as I want it to be? ;-))
Below is what I ultimately wound up using. Thanks again to Dave Korn for
the assistance in coming up with this solution!
The final requirements for this solution are:
1: An updated list of class headers in Makefile.
2: Classes must be declared with 'CREATABLE_CLASS(name)' instead of
'class name : virtual public OBJECT'.
3: A create_<name> function must be written. If all objects were
constructed the same, this could have been lumped into the declaration
CREATABLE_CLASS macro, however not all constructors take the same
arguments, which is why 'create_<name>' takes an argc/argv pair. IOW
this requirement cannot be eliminated.
The list-in-code (including pointers to create functions) is maintained
via (1), which is the only "overhead" other than (3) and the actual
class declaration... and if I really wanted to, I could get rid of this
as well (but to be worth it, I would want/need a way to determine what
files are actually used to build the executable, and I think this is one
case where I /prefer/ to update the list by hand).
Thus, except for Makefile, it achieves the objective of having a list
which is entirely generated and does not need to be maintained by hand.
=== For declaring an object
#define CREATABLE_CLASS(name) \
extern class OBJECT* create_##name( int argc, const char* argv[] ); \
class name : virtual public OBJECT
=== Example declaration
CREATABLE_CLASS( STRING )
{
public:
STRING( long ptr, long lim = MAX_STR );
virtual ~STRING();
...
protected:
char* _data;
};
=== For creating object.def (in Makefile)
objects.def : $(classes)
cat $(classes) | grep CREATABLE_CLASS > $@
(This requires '$(classes)' to be kept up to date, but that's OK because
'$(classes)' becomes part of '$(objects)', which defines the
prerequisites for the executable - i.e. this isn't really adding any
work, although I suppose I could go one step further and generate the
object prerequisites as well; this would certainly be do-able)
=== So main.cpp doesn't need the headers for every class
#undef CREATABLE_CLASS
#define CREATABLE_CLASS(name) \
extern class T_OBJ* create_##name( int argc, const char* argv[] );
#include "objects.def"
=== And finally for the list
#undef CREATABLE_CLASS
#define CREATABLE_CLASS(name) { #name, create_##name },
typedef OBJECT *(*OBJ_CREATOR)( int argc, const char* argv[] );
typedef struct {
const char* name;
OBJ_CREATOR create;
} OBJECT_LIST_ENTRY;
OBJECT_LIST_ENTRY createable_object[] = {
#include "objects.def"
{ NULL, NULL }
};
(The last '{ NULL, NULL }' entry is needed to have something after the
comma that the macro generates.)
--
Matthew
Doom doom dooM doo-DooM dOOm DOom doOM... DOOM! -- Gir