This is NOT the latest version, which is available at: current

Change picture:

Choose file:

Programming with C interface to Dao

Limin Fu (phoolimingmailcom)

  1. Introduction
  2. Build A Simple Extension
  3. Wrapping C/C++ Functions
  4. Wrapping C/C++ Types
  5. Embedding Dao
  6. Advanced Using of The C Interfaces

This document is licensed under GNU Free Documentation License .

1 Introduction

 Top
This document covers the methods for extending and embedding of Dao through C interfaces defined in the header file dao.h . The C interfaces are designed in such a way that the extension or the application that embeds Dao can be built using only the header file dao.h , namely, without linking against the Dao library. This is achieved though an intermediate wrapping layer, to skip this layer, one needs only to define DAO_DIRECT_API before including dao.h . However, the direct interfaces and the interfaces with a wrapping layer are identical, so it is just a matter of choice to use the direct interface or the wrapped one.
Obviously, one can also use other header files of the Dao library, to interact more directly with Dao, but the other header files may change from release to release, while dao.h is intended to be more stable. Using only dao.h makes it easier for the extension or application to work with updated Dao library. Moreover, there is a tool that can wrap C/C++ libraries in a semi-automated way, and this tool is updated whenever dao.h is changed. So if the extension is built using this tool, whenever dao.h is changed, it is only necessary to run again this tool to generate the extension.

2 Build A Simple Extension

 Top
  1. Callable Function for Dao
  2. The Dao Value Structure: DValue
  3. A Simple and Complete Example
  4. Adding Multiple Functions

A Dao extension is a module written in C that can provide extended functionalities for Dao. A Dao extension should always define two mandatory variables and one mandatory function. The first of the two variables is an integer signature of the header file dao.h that is used to build the extension, and the second is a global variable as the wrapping layer for the indirect interfaces. These two variables can be defined using macro DAO_INIT_MODULE . The mandatory function is the function to be called when the module is loaded. This function should be named as DaoOnLoad() with the following form,
int  DaoOnLoad(  DaoVmSpace  *vmSpace  )
{
     ...
}
The only parameter of this functions is a structure DaoVmSpace , which is the virtual machine space (VM Space) that defines an environment for the virtual machine. In the function body of DaoOnLoad() , one should add the wrapped constants, functions and C/C++ types to the DaoVmSpace (or the current namespace of the VM space). The returned value of this function is not used yet, it is reserved for future use. Now I will first introduce the form of a C function that is callable in Dao, then I will show how to add such functions to the DaoVmSpace .

2.1 Callable Function for Dao

 Top

A C function that is to be called in Dao must has the following form,
void  cfunction(  DaoContext  *ctx,  DValue  p[],  intN  );
Where DaoContext is the structure for storing execution context, and DValue is the basic structure used in the Dao library to store data. ctx is the current context that invokes the C function, and p is an array of parameters passed to this call and N is the number of parameters presented in the call. p may contain more elements than N , if the function is called without one or more parameters that have default values. While the C function receives data directly through p , the returned data for Dao must be put into ctx using some functions.

2.2 The Dao Value Structure: DValue

 Top

The DValue structure is shown below, and it has the follow simple fields: the t field indicates the type of the data; the m field is mainly for internal use, and should be set to zero; the v field contains the value of the data.
struct  DValue
{
     uchar_t  t;
     uchar_t  m;
     union  {
          int                        i;  /* int */
          float                    f;  /* float */
          double                  d;  /* double */
          complex16          *c;  /* complex */
          DString              *s;  /* string */
          DaoBase              *p;  /* NOT one of the above data types */
          DaoArray            *array;
          DaoList              *list;
          DaoMap                *map;
          DaoPair              *pair;
          DaoTuple            *tuple;
          DaoRoutine        *routine;
          DaoFunction      *func;
          DaoObject          *object;
          DaoClass            *klass;
          DaoCData            *cdata;
          DaoContext        *context;
          DaoStream          *stream;
          DaoNameSpace    *ns;
          DaoVmProcess    *vmp;
     }  v  ;
};


2.3 A Simple and Complete Example

 Top
#include"dao.h"
DAO_INIT_MODULE;
void  salute(  DaoContext  *ctx,  DValue  p[],  intN  )
{
     DaoContext_PutMBString(  ctx,  "hello"  );
}
int  DaoOnLoad(  DaoVmSpace  *vms  )
{
     DaoVmSpace_AddFunc(  vms,  salute,  "salute()=>string"  );
     return0;
}
In this example, there are only two functions which have not been introduced before. The first function DaoContext_PutMBString() is used to put a string as returned value to the execution context, in this case, salute() will return "hello". There are other functions that can be used to put different types of data into an execution context, they all have "DaoContext_Put" as part of their names. Please look into the header file dao.h for the complete list of such functions. The second function DaoVmSpace_AddFunc() is used to register the salute() function to the VM space vms with function prototype defined as "salute()=>string". The function prototype should be written in the same way as a Dao routine, in this case, this prototype tells the VM space that this added function will have "salute()" as its name in Dao codes, and it will return a string as returned value.
After compiling this code into a "mod_salute.dll" or "mod_salute.so" file, one can use this module as the following,
load  mod_salute;
stdio.println(  salute());


2.4 Adding Multiple Functions

 Top

If the extension defines multiple functions, these functions can be grouped together and added to the VM space by one call. To do this, one just has to create an array of DaoFuncItem , in which the first field is the function pointer of the Dao-callable C function, and the second field is the function prototype used by Dao. This array must be ended by an item containing null fields. For example, the following is the DaoFuncItem array for the wrapped OpenGL functions defined in the DaoOpenGL module,
static  DaoFuncItem  dao_Funcs[]  = 
{
    {  dao__glClearIndex,  "glClearIndex( c : float )"  },
    {  dao__glClearColor,  "glClearColor( red : float, green : float, blue : float, alpha : float )"  },
    {  dao__glClear,  "glClear( mask : int )"  },
    {  dao__glIndexMask,  "glIndexMask( mask : int )"  },
    {  dao__glColorMask,  "glColorMask( red : int, green : int, blue : int, alpha : int )"  },
    {  dao__glAlphaFunc,  "glAlphaFunc( func : int, ref : float )"  },
    {  dao__glBlendFunc,  "glBlendFunc( sfactor : int, dfactor : int )"  },
    {  dao__glLogicOp,  "glLogicOp( opcode : int )"  },
    ......
    {  NULL,  NULL  }
};

Then the DaoFuncItem array can be passed to function DaoVmSpace_AddFuncList() to added all the functions in the array to a VM space,
DaoVmSpace_AddFuncList(  vmSpace,  dao_Funcs  );


3 Wrapping C/C++ Functions

 Top

To wrap a C function, one only has to create a Dao-callable C function and call the C function to be wrapped with simple conversions of parameter/returned values. For example, if we have the following sin() function to be wrapped,
double  sin(  double  x  );
Then the wrapping of sin() is as simple as the following,
void  dao_sin(  DaoContext  *ctx,  DValue  p[],  intN  )
{
     DaoContext_PutDouble(  ctx,  p[0].v.d  );
}
...
int  DaoOnLoad(  DaoVmSpace  *vms  )
{
     ...
     DaoVmSpace_AddFunc(  vms,  dao_sin,  "sin( x : double ) => double"  );
     return0;
}
One don't have to worry if the accessing of the parameter of a double value by p[0].v.d is valid, because this functions is registered as "sin( x : double ) => double", so that the Dao VM will perform parameter checking (at both compiling time and running time) and guarantee that the function will be called with a double as parameter.
Note that there is a tool that can do this type of wrapping automatically, please refer to the relevant documentation to see how this tool can be used. If used properly, this tool can also wrap C structures and C++ classes.

4 Wrapping C/C++ Types

 Top
  1. Dao Typer Structure
  2. A Simple Example

What about using C structures or C++ classes in Dao? This section will explain the basics for wrapping C/C++ types.

4.1 Dao Typer Structure

 Top
Basically, a C/C++ type can be used in Dao as long as it is associated with a typer structure and is registered into the VM space. The typer structure is defined as the following,
/* Typer structure, contains type information of each Dao type: */
struct  DaoTypeBase
{
     DaoTypeCore      *priv;  /* data used internally; */
     constchar        *name;  /* type name; */
     DaoNumItem        *numItems;  /* constant number list */
     DaoFuncItem      *funcItems;  /* method list: should end with a null item */
    
     /* typers for super types, to create c type hierarchy;
     * mainly useful for wrapping c++ libraries. */

     DaoTypeBase      *supers[  DAO_MAX_CDATA_SUPER  ];
    
     DaoBase*          (*New)();    /* function to allocate structure; */
     void                  (*Delete)(  DaoBase  *self  );  /* function to free structure; */
};
The typer includes some basic properties of the C/C++ type, and its wrapped member constant numbers and methods. Normally, the function pointers to allocate and free the C/C++ type should also be supplied. If there is a method in the method list funcItems having the same name as the type name ( name field), the New field will not be used. If the Delete field is missing, the type will be freed by the standard C function free() . Optionally, if the C/C++ type has parent type(s), the typer structures of such parent types can be filled in the supers field (the last item in this field must be NULL), so that the inheritance relations in C/C++ are also valid in Dao, and the method invocation of parent methods and the casting to a parent type will be handled properly by the Dao VM.
The Dao VM stores C/C++ types in wrapped form, which is defined as structure DaoCData . The DaoCData structure has a field named data , which is a pointer pointing to the stored C/C++ data. The stored C/C++ data can be set using DaoCData_SetData( DaoCData *cdata, void *d ) and retrieved using DaoCData_GetData( DaoCData *cdata ) .

4.2 A Simple Example

 Top

Suppose we have the following simple C type name "foo" and a simple C function named "bar" that operates on "foo" type,
typedefstruct  foo  {  int  value;  }  foo;
foo*  foo_new()
{
     return  malloc(  sizeof(  foo  )  );
}
void  bar(  foo  *f  )
{
     printf(  "bar() is called with foo object: %p\n",  f  );
}


4.2.1 Basic Wrapping
 Top
The wrapping of the "foo" is the following,
static  DaoTypeBase  fooTyper  =
{
     NULL,
     "foo",
     NULL,  /* no constant number */
     NULL,  /* no method */
     {  NULL  },  /* no parent type */
     foo_new,
     NULL/* free by free() */
};
The this typer can be registered in a Dao VM space by,
DaoVmSpace_AddType(  vmSpace,  &  fooTyper  );
Then the type name can be used in Dao, for example, to create a "foo" object, one can do,
f  =  foo();

The function bar() can be wrapped and add into VM space by,
staticvoid  dao_bar(  DaoContext  *ctx,  DValue  p[],  intN  )
{
     foo  *f  =  DaoCData_GetData(  p[0].v.cdata  );
     bar(  f  );
}
...
DaoVmSpace_AddFunc(  vms,  dao_bar,  "bar( f : foo )"  );
...


4.2.2 bar() As Method of foo?
 Top
Since the "bar()" function operates on "foo" object, what about declaring "bar()" as a method of "foo" type, so that instead of calling "bar( foo_object )", one can call "foo_object.bar()"?
This can be done easily, one needs only to modify the typer of foo as the following,
static  DaoFuncItem  fooMeth[]  =
{
     {  dao_bar,    "bar( self : foo )"  },
     {  NULL,  NULL  }
};
static  DaoTypeBase  fooTyper  =
{
     NULL,
     "foo",
     NULL,  /* no constant number */
     fooMeth,  /* one method bar() */
     {  NULL  },  /* no parent type */
     foo_new,
     NULL/* free by free() */
};
The first parameter in the function prototype of the method must be named as "self", if one wants "foo_object" to be passed to "bar()" as the first parameter when "foo_object.bar()" is called.
With this modification, one can do the following in Dao,
f  =  foo();
f.bar();


4.2.3 Setters and Getters
 Top

Setters and getters can be easily implemented for more conveniently accessing fields of C/C++ types. Continue the previous example, the setter and getter of the "value" field of "foo" can be defined as,
staticvoid  foo_SETF_value(  DaoContext  *ctx,  DValue  p[],  intN  )
{
     foo  *f  =  DaoCData_GetData(  p[0].v.cdata  );
     f.value  =  p[1].v.i;
}
staticvoid  foo_GETF_value(  DaoContext  *ctx,  DValue  p[],  intN  )
{
     foo  *f  =  DaoCData_GetData(  p[0].v.cdata  );
     DaoContext_PutInteger(  ctx,  f.value  );
}
Then the folloing two lines should be added to the "fooMeth",
{  foo_SETF_value,    "_SETF_value( self : foo, v : int )"  },
{  foo_GETF_value,    "_GETF_value( self : foo ) => int"  },
Then in Dao, the "value" of "foo" can be set and got as,
f  =  foo();
f.value  =  123;
a  =  f.value;


5 Embedding Dao

 Top

So far, some basics of the C programming interfaces have been introduced in the context of extending dao, now in this section, I will give a brief introduction on how to embed the Dao virtual machine into other applications. Embedding Dao can make an appplication programmable, and allow some components of the application to be controlled in a programmable way, or allow the functionalities of the application to become extendable by the Dao language.
The interfaces I introduced so far for extending are also valid for embedding, the only differences are that the macro DAO_INIT_MODULE is no longer necessary here and there is no need to provide function DaoOnLoad() . To embed Dao, the very first thing is to include the header file "dao.h", similar to extending, you should define "DAO_DIRECT_API" before including "dao.h" if the direct interfaces are to be used. If indirect interfaces are used, one global variable must be defined, which is __dao (two underscore symbols),
DAO_DLL  DaoAPI  __dao;
you can also simply use the macro DAO_INIT_MODULE .
If you are not going to compile Dao together with your application, then the next thing is to open the Dao library file using a macro defined in dao.h ,
void  *handle  =  DaoLoadLibrary(  "/usr/local/dao/dao.so"  );
then function DaoInit() must be called to initialize the Dao library, this function will return a structure of DaoVmSpace , which can be used to load modules or compile Dao source codes. If direct interefaces are used, this function can be called directly,
DaoVmSpace  *vmSpace  =  DaoInit(  NULL  );
Otherwise, one has to do the following,
DaoInitFunc  pfunc  =  (DaoInitFunc)DaoFindSymbol(  handle,  "DaoInit"  );
DaoVmSpace  *vmSpace  =  (*pfunc)(  &  __dao  );
In the second way, calling DaoInit() with the address of __dao as parameter will allow the function pointer fields of __dao to be filled, so that the interfaces can be accessed through a wrapper layer provided by __dao , which allows the application to be built without linking against the Dao library.
Once a structure of DaoVmSpace is abtained, this structure can be used to set execution options for Dao, and add wrapped C functions and types to Dao as introduced in the previous sections. Loading modules or compiling Dao source codes can also be handled by this structure, for example,
if(  !  DaoVmSpace_Load(  vmSpace,  "script.dao"  )  return;
if(  !  DaoVmSpace_Execute(  vmSpace,  0  )  )  return;


6 Advanced Using of The C Interfaces

 Top

As mentioned before, it is possible to retain or define inheritance relationships between C/C++ types. Moreover, in Dao, one can derive sub-classes from C/C++ types just in the same way as deriving from Dao classes. It is even possible to wrap a C++ class in such way that its virtual methods can be overrode by Dao routines when deriving a Dao class from the C++ class. For C structures that contain fields of function pointers, in certain cases, these C structures can be wrapped as if they are C++ class and have virtual methods of the same name as their function pointer fields. These techniques are a bit complicated, and will not explain here. Anyone who are interested can refer to the source codes for some Dao modules (e.g. module for VTK5), or can use the automated tool ("tools/autobind.dao") to generate such wrappers and then examine the generated codes.
view count 127 times
created at 2009-09-18, 04:53 GMT

123 4
56 78910 11
121314151617 18
192021222324 25
2627282930

klabim: ... Ok, I found it. It can be so easy by reading the documentation :- ). I have overseen the keyword glob ... (Aug.21,18:09)

klabim: sharing vars between scripts Hi, how can I share a variable between 2 scripts in an embedded environment? For example: script 1: ... (Aug.21,17:55)

This site is powered by Dao
Copyright (C) 2009,2010, daovm.net.
Webmaster: admin@daovm.net