IntroductionDownloadTutorial DocumentationChangelogContact

xPP C++ Metaprocessor


Note: This documentation is incomplete and already outdated. We're working on a php-based help system which will make inputing the doc and updating it much less time consuming, stay tuned.


Documentation

Installation

Just unzip the file in the directory of your choice, preferably somewhere in your PATH. Make sure the “templates” subdirectory is also unzipped there, as well as its subdirectories.

Command Line

-i:inputfile

Specifies the input file to process. File can either be an xhd or an xpp file (see Instrumenting a Class for how to create these).

-o:outputsubdir

Specifies the output subdirectory to output files in. If a file is normally in “../”, if will be written in “outputsubdir/../”

-t:templatedir

Adds a custom template directory to the search list

-d:symbol=value

Defines a global symbol. Templates may retreive these as variables.

-fl:outlist.txt

Creates a file with the list of files generated by xpp

-file:file.txt[,class]

Preprocess the content of file.txt, optionally using the given class as a context, otherwise using the first class in the xpp, and print the result on the standard output.

-stdin[:class]

Preprocesses the standard input, optionally using the given class as a context, otherwise using the first class in the xpp, and print the result on the standard output.

-q

Quiet, only output errors

-vq

Very quiet, only output the result of -file / -stdin

-np

No parsing, assume C++ files have not changed

-npp

Np preprocessing, do not generate the template target files

-y

Do not ask confirmation before overwriting a generated file.

Limitations, Conventions and Glossary

Although xPP will work no matter how many classes you have in one file, it is limited to the instrumentation of only one of these classes per file pair (one cpp and one h file with the same base filename). This convention pervades the use of the program, and only those classes that are fully declared within one file pair (with no #include within the declaration) will be handled correctly.

Because the word class may mean a lot of slightly different things, we need to make our vocabulary more precise. Traditionally, the way to remove the ambiguity in its meaning has been to introduce the term interface, thus an interface is a sort of “logical class”, as in an XPCOM interface, a COM interface, etc., which may be implemented using several actual C++ classes, and the word class refers to these, as in :

class ClassName : public Ancestor { ... };

There remain however an ambiguity in the sense that by class we may mean solely the above, or this :

class Ancestor { ... };
class ClassName : public Ancestor { ... };

That is, we sometimes use the word class to refer to the entire construction resulting from the instantiation of our class, that is, we sometimes mean the class, along with all its inherited behavior, and sometimes we mean the single C++ class, disregarding its ancestry and descendancy.

To clear this confusion up whenever it may arise, we will use the word class when its signification is not ambiguous or when the term requires being general, and we will call a single C++ classes, excluding its ancestry or descendancy, a class layers (as an analogy with layers in photo compositing softwares). Thus, our two class layers amount to one class named “ClassName”, and if we ever add an interface to it (say, an XPCOM interface), it will be implemented using class layers, which will then be part of that same “ClassName” class.

With this in mind, we can define the rest of the glossary :

Meta Template

An xPP template, called “meta” template so as to make it distinct from C++ templates. Meta templates implement automatic interfaces via the description of their class layers in an xml language that has access to information about the hierarchy of that class, its methods, parameters, and data members.

Meta Macro

An inline meta template embedded in a C++ comment.

Template Meta Template (TMT)

We're in trouble, what is a meta template about a template ? A meta-meta-template ? Anyway, a “template meta template” is a meta template to handle C++ templates as parameter types for a given interface meta template. Lost yet ? Well, for instance the DataServer meta template needs to know about the parameters types it manipulates, but because there could be any number of user-defined C++ template types that it does not know about, it handles these thru the use of “template meta templates” so that you can add more if you need. Let's call them TMTs for short.

XPP File

An xPP project file, it contains the list of all the instrumented classes in your project and a link to their XHD file.

XHD File

A per-class file read and then rewritten by xPP upon each preprocessing run. This file contains customization options for the meta templates. See Building for Multiple Targets for more information

Classdecl

An xPP xml function used in meta macros to declare a class. This is going to be used quite often in this document and so it might as well be listed here. This function creates the class declaration code, along with the specified inheritance, and sends its extra parameters into the XHD. See Xml Dictionary and Building for Multiple Targets for more information.

Instrumented Class

Instrumented classes are those classes that xPP knows about. Each of this class has an associated xhd file, but not all these classes use a classdecl metamacro (class that only need to be known by xPP but not be changed by it do not require inline xml in the code).



Instrumenting a Class

Instrumenting a class is the first step to use xPP, you begin with one class, and gradually instrument more as needed: xPP does not need to know all about your code. For automatic templates, xPP only needs to know about the program's “end points”, where its interfaces are exposed to the world. For generic inline metamacros, xPP does not need to know anything else than what your metacode refers to.

Since our class is going to be partially declared by xPP (via its classdecl), and since xPP needs a valid class definition to be able to generate source code (in order to understand the class declaration), there is a bit of a chicken and egg problem, but fortunately, it is not very difficult to get an instrumented class started, this involves 3 or 4 steps (replace “classname” with your own class name) :

1. If you do not yet have an xpp project file, create one with the following code (otherwise, insert a new class entry) :

<xpp precompfile=”stdafx.h”>
    <class name=”ClassName” file=”ClassName.xhd”/>
</xpp>

note that precompfile=”stdafx.h” is for default VC settings, you may ommit it or change it to whatever your project requires or simple ommit it.

2. Optional, if you only need xPP to analyze this class so that it can know about it when dealing with other classes, you do not need to perform step 2. If you wish xPP to modify your class so that it changes its ancestry antomatically to accommodate the needs of the templates, you need to perform this step.

2a. * If you are creating a new class :

Create a clean, empty implementation of your class, enclose it in a classdecl, and add an automatic header (<autoheader/>) so that xPP can keep the compiler happy :

cclassname.h :

#ifndef _CCLASSNAME_H
#define _CCLASSNAME_H

/*<?<autoheader/>*/
/*?>*/

/*<?<classdecl name=”ClassName” implname=”CClassName” inherit=”Ancestor1;private Ancestor2”/>*/
class CClassName : public Ancestor1, private Ancestor2 {
/*?>*/
};

#endif

cclassname.cpp :

#include “stdafx.h”
#include “cclassname.h”



2b. * If you are instrumenting an existing class :

Enclose your class declaration in a classdecl, for instance, if your class declaration is :

class CClassName : public Ancestor1, private Ancestor2 {

Then you should change it to :

/*<?<classdecl name=”ClassName” implname=”CClassName” inherit=”Ancestor1;private Ancestor2/>*/
class CClassName : public Ancestor1, public Ancestor2 {
/*?>*/

3. Create a minimal XHD file for your class. This is what will let xpp know about your class. If you have not performed step 2, xpp will not create any code for this class, it will simply parse it in order for its structure to be accessible to the templates.

classname.xhd :

<xhd>
  <class name=”ClassName” implementation=”CClassName”
    class_header=”cclassname.h” class_module=”cclassname.cpp”>
  </class>
</xhd>

4. Setup a custom build step within your environment, so that your xpp file gets compiled with your project. For instance, in Visual C++, this would be something like :

Commands :

xpreproc /i:$(InputDir)\$(InputName).xpp /y
echo 1 > "$(OutDir)\$(InputName).out"

Outputs :

$(OutDir)\$(InputName).out

note that the .out timestamp file trick is only needed because there is no template associated with our class yet, but after we add one, we can just include one or all of the generated files in the Outputs field instead of creating a timestamp file.



But if you are using automake on unix, you can set up a custom Automake.am such that including the xpp files to your list of source files will
automatically compile all the resulting .cpp. Here is an example of this for a project named “xpptest” with a custom template directory :

AUTOMAKE_OPTIONS=foreign

bin_PROGRAMS = all-xpp xpptest
xpptest_SOURCES = xpptest.xpp xpptest.cpp cclassname.cpp

# set the include path found by configure
INCLUDES= $(all_includes)

# the library search path.
xpptest_LDFLAGS = $(all_libraries)
xpptest_DEPENDENCIES =
LDADD = `cat xpp.output | grep \.cpp$$ | sed s/cpp$$/o/`

XPPDIR = /usr/local/bin
XPPEXE = $(XPPDIR)/xpp
PROGTEMPLATES = -t:../xpptemplates
XPPTEMPLATES = $(XPPDIR)/templates

all-xpp:
for i in *.xpp; do $(XPPEXE) -i:"$$i" -y $(PROGTEMPLATES) -filelist:xpp.output ; done
for i in $(shell cat xpp.output | grep .cpp$$); do $(CXXCOMPILE) "$$i" -c; done

You should be able to compile your project and either see the xPP progress bar (in win32) or the log of the preprocessing on the screen (in linux) as it works on your classes. On VisualC, depending on your setup, it may be needed to right click the xpp file in the project tree and compile it manually



Adding and Removing Interfaces

To add an interface, simple add it in a classdecl parameter named “factory”. For instance :

/*<?<classdecl name=”ClassName” implname=”CClassName” inherit=”Ancestor1;private Ancestor2” factory=”XPCOM”/>*/
class CClassName : public Ancestor1, private Ancestor2 {
/*?>*/

After recompilation of the xpp file, your classdecl will look like this :

/*<?<classdecl name=”ClassName” implname=”CClassName” inherit=”Ancestor1;private Ancestor2” factory=”XPCOM”/>*/
class CClassName : public Ancestor1, private Ancestor2, nsIClassNameX {
/*?>*/

The files nsIClassNameX.cpp, nsIClassNameX.h and nsIClassName.idl will have been generated, you will need xpidl from the mozilla source code to compile the idl file (sorry, getting the XPCOM environment going remains a pain), and the cpp file should be included in your project. You will notice that your autoheader function automatically added a #include “nsIClassNameX.h” so that the class can actually compile.

Currently available meta templates are :

OleControlModule

Creates a plugin infrastructure for ActiveX, this should be used on one class while using OleControl on another

OleControl

Provides an OLE Control interface, for ActiveX & co.

npMozilla

Creates a plugin infrastructure for mozilla, this should be used on one class while using XPCom on another.

XPCOM

Provides an XPCOM interface thru the creation of an idl and of a class layer that binds to the result of its compilation


Interface

A mixed Pure Virtual / Wasabi Dispatchable meta template, this one will do a pure virtual unless you add dispatchable=”1” to your classdecl.

ScriptObject

A Wasabi script object meta template, to automatize the exposure of widgets to the scripting system.

DataServer

Automatically exposes data thru accessors. Also create events to be trapped by inheritors.

Currently available TMTs :

Wasabi PtrList



XML Syntax

xPP's template language is pure xml, this means that it obeys the syntactic requirements of xml, which are not always very nice to work with, however the format is particularly well adapted to the inline manipulation and generation of text.

The language is case insensitive, and there is no punctuation. The source is organized hierarchically, control structures such as if, else, foreach, etc. use the structure of the xml to perform their task and get their arguments.

Functions are xml tags and come in three flavors, Singleton, Compound or Mixed. Here is a <singleton/>. And here is a <compound/>function</compound>. Mixed mode functions support both uses. For instance, the foreach enumerator is compound, as it is a control structure which contains more code to execute. The function <autoheader/> however is a singleton, it merely spits text that depends on the context and does not hold anything. The <set/> function however can be used both ways, such as <set id=”varid” value=”hello, world”/> or <set id=”varid”>hello, world</set>.

FOREACH

Any piece of xPP code runs within a context. By default, this context is that of the class which is being processed by xPP. For instance, at the beginning of a metatemplate, the context is set to the class for which this template is being run. There are several kind of contexts and many contexts can overlap, for instance, if a template enumerates the parameters of a function of a class, the enumeration code is in all three contexts simultaneously: that of the particular class the template is run on, and the particular method and parameter pointed to by the enumeration process.

Context is changed by using the <foreach> control structure, using the objects=”context” parameter. For instance <foreach objects=”classes”></foreach> will run the content of the tag pair for each class that xPP knows about. <foreach object=”params”></foreach> will iterate all the parameters of the method in the current context, and will generate an error if there is no method context (ie, no enumeration is proceeding, or a simple class enumeration is : a parameter context requires a method context).

Type : Compound.

Parameters :

objects : The context of the enumeration
              Possible values :
                  classes             : enumerates all classes known by xPP
                  methods           : enumerates all methods from the class in the current context
                  params             : enumerates all parameters from the method in the current context (requires a method context!)
                  templateparam  : enumerates all template parameters from the parameter in the current context (requires a parameter context!)

Example :

<foreach objects=”methods”>
    Method <forindex/> is named <method data=”name”/><br/>
</foreach>

Result :

Method 0 is named ClassName
Method 1 is named ~ClassName
Method 1 is named DoSomething
Method 2 is named DoSomethingElse
...

IF

Tests a condition.

Type : Compound.

Parameters :

object : the type of object you wish to perform a test on, possible objects depend on the current context. Use this parameter in conjunction with the isoftype or inherits parameters)
                Possible values :
                    class                : tests a property of the class in the current context
                    method            : tests a property of the method in the current context
                    param              : tests a property of the parameter in the current context
                    templateparam : tests a property of the template parameter in the current context

isoftype : tests a flag on the object, can hold multiple flags separated by |, in which cas an OR operator is used by default (see the op parameter)
   
            Possible values for class object :
                    - no flag yet
                Possible values for method objects :
                    ctor               : tests if the method in the current context is a constructor
                    dtor               : tests if the method in the current context is a desstructor
                    defaultctor     : tests if the method in the current context is the default (parameterless) constructor
                    virtual            : tests if the method in the current context is a virtual function
                    static             : tests if the method in the current context is a static function
                    inline             : tests if the method in the current context is an inline function
                    pure              : tests if the method in the current context is a pure virtual function
                    raw               : tests if the method in the current context is neither virtual nor static nor inline
                    void              : tests if the method in the current context returns void
                    voidparam     : tests if the method in the current context is parameterless
                    public            : tests if the method in the current context is public
                    private           : tests if the method in the current context is private
                    protected       : tests if the method in the current context is protected
                    script             : tests if the method in the current context was marked with the SCRIPT passive macro
                    event             : tests if the method in the current context was marked with the EVENT passive macro
                    multiple          : tests if the method in the current context has sibblings named the same with different parameters
                    firstofmultiple : tests if the method in the current context is the first of several with the same name but different parameters
               Possible values for param and templateparam objects :
                    template        : tests if the param in the current context is of a template type (ie, std::list<something>)
                    pointer          : tests if the param in the current context is a pointer (ie, something*)
                    reference      : tests if the param in the current context is a reference (ie, something&)
                    in                  : tests if the param in the current context has been marked with the IN passive macro
                    out                : tests if the param in the current context has been marked with the OUT passive macro
                    inout              : tests if the param in the current context has been marked with the INOUT passive macro

op : operator to use when specifying multiple types in the isoftype parameter.
                Possible values :
                    and               : all type tests must be succeed
                    or                 : at least one type test must succeed

not : 1 to reverse the results of the test

inherit : tests if the class in the current context directly inherits the class provided in the parameter.

text : tests the properties of the text in the parameter (use in conjunction with the match parameter)

match : performs a regexp match test on the text provided in the text parameter.

Example :

<if object=”method” isoftype=”void” not=”1”>return</if><method data=”name”/>();

Result if the method is void :

MethodName();

Result if the method returns a value :

return MethodName();

ELSE

Perform code if an IF's result was false.

Type : Compound.

Parameters : none

Example :

<if object=”method” isoftype=”void”>
    // method <method data=”name”/> is void<br/>
    <else>
        // method <method data=”name”/> returns type <method data=”returntype”/><br/>
    </else>
</if>

Result if the method is void :

// method MethodName is void

Result if the method returns an int :

// method MethodName returns type int



XML Dictionary

-todo-

XML Common Modifiers

-todo-

Practical Examples

Here are some of the things you can do.

Testing Inheritance to Pick Appropriate Code

If you need to make a part of your source code be commented out when your class is not inheriting a specific ancestor, you would normally use a #define DERIVE_MYANCESTOR which you would or would not set and then #ifdef on that. This is not always safe, since one may forget to re-enable the #define when restoring the ancestor, or to disable it when no longer inheriting, and then go on never noticing it. With xPP you can instead do:

/*<?
  <br/>
  <if object="class" inherits="nsI$(class.name)X">
    // XPCOM interface - get a pointer to the mozilla nsIMyClass
    nsITestClass *test = this;
    // ... and do stuff with it
    <else>
      // ** XPCom interface is disabled **
    </else>
  </if>
  <br/><br/>
*/

// ** XPCom interface is disabled **

/*?>*/

Or alternatively :

/*<?<if object=”class” inherits=”nsI$(class.name)X” not=”1”/>#if 0</if>*/
#if 0
/*?>*/

// XPCOM interface - get a pointer to the mozilla nsIMyClass
nsITestClass *test = this;
// ... and do stuff with it

/*<?<if object=”class” inherits=”nsI$(class.name)X” not=”1”/>#endif</if>*/
#endif
/*?>*/


Building for Multiple Targets

-todo-

Automatically Exposing Data via Accessors

The DataServer template can be used to easily expose data members via read and/or write accessors, as well as implement events to notify you when these member change. Exposing template types can be customized by creating a data template (see directory templates/data). Try adding “DataServer” in your list of factories, and look for YourClassDS.cpp/h after processing. To expose a member, simply precede it with READ, WRITE, or READWRITE. Other templates in your stack will interpret these flags for themselves too, for instance the XPCOM interface will create the appropriate properties for your data in the idl file.