Hi
I made another version of the c_wrapper.py program. I have attached the
program, a new smaller diff to doxymlparser.py and output from running
the program. The output can compile now:
> python c_wrapper.py out/xml/classwx_button.xm
> g++ `wx-config --libs` `wx-config --cxxflags` -c wrapped_wxButton.cpp
I have not tried hooking it up to Haskell, as I cannot compile wxHaskell
with the svn-checkout of wxWidgets and as I could not find the
doxygen-directory in my older version of wxWidgets (2.8.7) which do work
with wxHaskell.
Also I think we should consider how to proceed.
Should we proceed with making a python program like c_wrapper.py ?
And how much work is there in this? I guess we need to:
* Finish the c_wrapper.py script. It will properly need a lot of
debugging before working properly.
* Re-hook wxHaskell up to the output of c_wrapper.py script. This may
take some time, as function names and some parameters will change. And a
lot of code will have small changes, so there is a lot of possibility
for error :-(
* Convince the wxWidgets team to maintain the script. I guess this
involves not just talking to the wxWidges team, but also show that other
people will find the c-wrapper useful.
Especially the second task seems big, but the others are not small
either.
If people are interested in working on c_wrapper.py, I would be happy to
put it into our Darcs repo.
Greetings,
Mads Lindstrøm
Mads Lindstrøm wrote:
> Hi
>
> Kevin Ollivier wrote:
> > Hi Eric,
> >
> > On Apr 9, 2009, at 11:18 AM, Eric Kow wrote:
> >
> > > On Thu, Apr 09, 2009 at 18:57:29 +0100, Eric Kow wrote:
> > >> This is where Kevin Ollivier of wxWidgets pointed out something
> > >> interesting: in the current wxWidgets trunk, it should be possible to
> > >> automatically generate the C bindings from the Doxygen XML output.
> > >> In
> > >> fact, he has already done something similar for Python, metadata to
> > >> Python objects:
> > >>
> > >> http://trac.wxwidgets.org/browser/wxWidgets/trunk/docs/doxygen/doxymlparser.py
> > >
> > > Following up on this, I did
> > >
> > > svn checkout http://svn.wxwidgets.org/svn/wx/wxWidgets/trunk
> > > wxWidgets
> > > cd wxWidgets/doc/doxygen
> > > ./regen.sh
> > > python doxymlparser.py --report out/xml/classwx_button.xml
> > >
> > > Attached is the XML file (input) and the output of this script.
> > >
> > > Here is a small extract of the output:
> > >
> > > Class: wxButton
> > > Bases: wxControl
> > > Inlcudes: []
> > > Brief Description:
> > >
> > > And...
> > >
> > > Method: SetLabel
> > > Return Type: void
> > > Params: [{u'type': u'const&', u'declname': u'label'}]
> > > Prototype: void wxButton::SetLabel(const wxString &label)
> > > Brief Description:
> > >
> > > What can we do with this?
> >
> > As a start, with a few lines of Python code after the
> > doxyparser.parse(file) calls in the script, you can do something like:
> >
> > # start code to autogenerate wxc.h
> > wxc_header = ""
> >
> > for aclass in doxyparse.classes:
> > for amethod in methods:
> > self_ref = "TSelf"
> > if amethod.name == "Create":
> > self_ref = "TClass"
> > wxc_header += "%s(%s) " % (self_ref, aclass.name)
> > else:
> > wxc_header += "%s " %
> > (wxc_type_for_type(amethod.return_type)
> >
> > wxc_header += "%s_%s( %s _obj" % (aclass.name, amethod.name,
> > self_ref + (" + aclass.name + ")")
> >
> > for param in amethod.params:
> > wxc_header += ", %s %s" %
> > (wxc_type_for_type(param["type"]), "_" +
> > param["declname"])
> > # Note: uncomment this if you support adding default
> > values
> > # if "defval" in param:
> > # wxc_header += "=" + param["defval"]
> > wxc_header += " );\n"
> >
> > wxc_file = open("wxc.h", "wb")
> > wxc_file.write(wxc_header)
> > wxc_file.close()
> >
> > # end code
> >
> > This is all just pseudo-code, and methods like wxc_type_for_type would
> > need implemented, and you'd also need to probably work out some
> > special logic for constructors, a list of classes to exclude, etc. but
> > this should give you an idea of how to start things off. Ideally you'd
> > actually have your own generate_c_bindings.py file that does an
> > "import doxyparser", then runs "doxyparse.parse()" itself rather than
> > extending the doxymlparser.py script, but anyway, just some ideas.
>
> I have made an initial attempt at a c_wrapper.py program. It is far from
> finished, but like the XSLT program, I did it to see if it was feasible.
> I have attached the program.
>
> My initial imprecision is that this could work out. Python is a very
> nice language, and it was a joy to make my little program. I am already
> further along than with the XSLT program, and I have spend a third of
> the time. And more importantly, it did not feel painful at all.
>
> I had to change doxymlparser.py a bit though, otherwise we get
> type-names like constwxString:
>
> > svn diff:
>
> Index: doxymlparser.py
> ===================================================================
> --- doxymlparser.py (revision 60099)
> +++ doxymlparser.py (working copy)
> @@ -98,7 +98,11 @@
> if child.nodeType == child.ELEMENT_NODE and child.nodeName == "ref":
> text += getTextValue(child)
> if child.nodeType == child.TEXT_NODE:
> - text += child.nodeValue.strip()
> + #text += child.nodeValue.strip()
> + # We changed line above to remove qualifiers. Maybe we need
> another field on parameters?
> + for token in string.split(child.nodeValue.strip()):
> + if (token != "virtual" and token != "static" and token !=
> "const"):
> + text += token
>
> return text
>
> Kevin, what do you think about this change?
>
>
> The output looks like:
>
> > python c_wrapper.py out/xml/classwx_button.xml | indent
>
> /* Constructor */
> wxButton wxButton_wxButton ();
> /* Constructor */
> wxButton wxButton_wxButton (wxWindow * _parent, wxWindowID _id,
> wxString & _label, wxPoint & _pos,
> wxSize & _size, long _style,
> wxValidator & _validator, wxString & _name);
> void wxButton_Destruct (wxButton * _obj);
> bool wxButton_Create (wxButton _obj, wxWindow * _parent, wxWindowID _id,
> wxString & _label, wxPoint & _pos, wxSize & _size,
> long _style, wxValidator & _validator,
> wxString & _name);
> wxString wxButton_GetLabel (wxButton _obj);
> wxWindow *wxButton_SetDefault (wxButton _obj);
> void wxButton_SetLabel (wxButton _obj, wxString & _label);
> wxSize wxButton_GetDefaultSize (wxButton _obj);
>
>
> Greetings,
>
> Mads Lindstrøm
>
"""
Name: c_wrapper.py
Author: Mads Lindstroem
License: wxWidgets License
"""
#!/usr/bin/env python
import doxymlparser
import optparse
import sys
import os
import string
parser = optparse.OptionParser(usage="usage: %prog <doxyml files to parse>\n" , version="%prog 1.0")
options, arguments = parser.parse_args()
# Intersperses elem between each list element
def intersperse(elem, alist):
ret = []
first = True
for i in alist:
if (not first) :
ret.append(elem)
ret.append(i)
first = False
return ret
def wxc_type_for_type(type):
return type
def is_constructor(amethod, aclass):
return amethod.name == aclass.name
def is_destructor(amethod, aclass):
return amethod.name == "~" + aclass.name
def is_void(atype):
return atype == "void"
def is_buildin_type(atype):
#FIXME: needs more than bool
return atype == "bool"
def param_name(aparam):
return "_" + aparam["declname"]
def keep_alpha(s):
return filter(lambda y: y.isalpha(), s)
# Mangles the method name if two methods has the same name.
# Otherwise the method name is returned unchanged.
#
# We mangle by addding all parameter-types to the method name.
def mangled_method_name(amethod, aclass):
if len(filter(lambda x: x.name == amethod.name, aclass.methods)) == 1:
return amethod.name
else:
# Methods in C++ can vary only in being const
if amethod.return_type.find("const") == -1:
constReturn = ""
else:
constReturn = "_const"
return amethod.name + "".join(intersperse("_", \
map(lambda x: keep_alpha(x["type"]), amethod.params))) \
+ constReturn
#str(len(amethod.params))
def prototype(amethod, aclass):
prot = "";
className = wxc_type_for_type(aclass.name)
if is_constructor(amethod, aclass):
prot += "/* Constructor */\n"
prot += "%s * %s_%s(" % (className, className, mangled_method_name(amethod, aclass))
set_comma = False
elif is_destructor(amethod, aclass) :
prot += "void %s_Destruct(%s * _obj" % (className, className)
set_comma = True
else:
if is_void(amethod.return_type):
prot += "void "
elif is_buildin_type(amethod.return_type):
prot += wxc_type_for_type(amethod.return_type) + " "
else:
prot += wxc_type_for_type(amethod.return_type) + " " #"* "
prot += "%s_%s(%s * _obj" % (aclass.name, mangled_method_name(amethod, aclass), className)
set_comma = True
for param in amethod.params:
if set_comma:
prot += ", "
prot += "%s %s" % (wxc_type_for_type(param["type"]), param_name(param))
set_comma = True
prot += " )"
return prot
def write_and_indent(contents, filename):
wxc_file = open(filename, "wb")
wxc_file.write(contents)
wxc_file.close()
# FIXME: Everybody may not have indent installed. We need to handle failure gracefully/silently.
os.system("indent " + filename)
def make_header_file(aclass, filename):
gaurd = string.replace(string.upper(filename), ".", "_")
wxc_header = "#ifndef %s\n #define %s\n" % (gaurd, gaurd)
# Warning: #Include-s must come before extern "C", otherwise we get
# "error: template with C linkage", see
# http://www.gidforums.com/t-9853.html
wxc_header += """
#include "wx/wx.h"
#ifdef __cplusplus
extern "C" {
#endif
"""
for amethod in aclass.methods:
wxc_header += "extern " + prototype(amethod, aclass)
wxc_header += ";\n"
wxc_header += """
#ifdef __cplusplus
}
#endif
"""
wxc_header += "#endif //" + gaurd
write_and_indent(wxc_header, filename)
def invoke_params(amethod):
return "(%s)" % ("".join(intersperse(", ", map (param_name, amethod.params))))
def make_cpp_file(aclass, header_filename, cpp_filename):
wxc_cpp = "#include \"" + header_filename + "\"\n\n"
for amethod in aclass.methods:
wxc_cpp += "\n\n"
wxc_cpp += prototype(amethod, aclass)
wxc_cpp += "{"
if is_constructor(amethod, aclass):
wxc_cpp += "new %s %s;" % (aclass.name, invoke_params(amethod))
elif is_destructor(amethod, aclass):
wxc_cpp += "delete (_obj);"
elif is_void(amethod.return_type):
wxc_cpp += "_obj->%s %s;" % (amethod.name, invoke_params(amethod))
elif (amethod.return_type == "bool"):
wxc_cpp += "return _obj->%s %s;" % (amethod.name, invoke_params(amethod))
else:
wxc_cpp += "return _obj->%s %s ;" % (amethod.name, invoke_params(amethod))
wxc_cpp += "}"
write_and_indent(wxc_cpp, cpp_filename)
def make_files(doxyparse):
for aclass in doxyparse.classes:
base_filename = "wrapped_" + os.path.basename(aclass.name)
header_filename = base_filename + ".h"
cpp_filename = base_filename + ".cpp"
make_header_file(aclass, header_filename)
make_cpp_file(aclass, header_filename, cpp_filename)
if __name__ == "__main__":
if len(arguments) < 1:
parser.print_usage()
sys.exit(1)
doxyparse = doxymlparser.DoxyMLParser()
for arg in arguments:
doxyparse.parse(arg)
make_files(doxyparse)
# for aclass in doxyparse.classes:
# print str(aclass)
# We need smarter include file handling, but doxymlparser.py ignores includes.
# http://www.haskell.org/haskellwiki/IO_inside
# http://www.haskell.org/haskellwiki/CPlusPlus_from_Haskell
# rm -f wrapped_* && python c_wrapper.py out/xml/classwx_button.xml
# g++ `wx-config --libs` `wx-config --cxxflags` -c wrapped_wxButton.cpp
# ghc --make wrapped_wxButton.o Main.hs
Index: doxymlparser.py
===================================================================
--- doxymlparser.py (revision 60099)
+++ doxymlparser.py (working copy)
@@ -54,7 +54,7 @@
str_repr = """
Class: %s
Bases: %s
-Inlcudes: %s
+Includes: %s
Brief Description:
%s
@@ -98,9 +98,10 @@
if child.nodeType == child.ELEMENT_NODE and child.nodeName == "ref":
text += getTextValue(child)
if child.nodeType == child.TEXT_NODE:
- text += child.nodeValue.strip()
+ text += child.nodeValue.strip() + " "
+ # Changed line above to get space between qualifies and parameter names
- return text
+ return text.strip()
def doxyMLToText(node):
return text
#include "wrapped_wxButton.h"
/* Constructor */
wxButton *
wxButton_wxButton ()
{
new wxButton ();
}
/* Constructor */
wxButton *
wxButton_wxButtonwxWindow_wxWindowID_constwxString_constwxPoint_constwxSize_long_constwxValidator_constwxString
(wxWindow * _parent, wxWindowID _id, const wxString & _label,
const wxPoint & _pos, const wxSize & _size, long _style,
const wxValidator & _validator, const wxString & _name)
{
new wxButton (_parent, _id, _label, _pos, _size, _style, _validator, _name);
}
void
wxButton_Destruct (wxButton * _obj)
{
delete (_obj);
}
bool
wxButton_Create (wxButton * _obj, wxWindow * _parent, wxWindowID _id,
const wxString & _label, const wxPoint & _pos,
const wxSize & _size, long _style,
const wxValidator & _validator, const wxString & _name)
{
return _obj->Create (_parent, _id, _label, _pos, _size, _style, _validator,
_name);
}
wxString
wxButton_GetLabel (wxButton * _obj)
{
return _obj->GetLabel ();
}
wxWindow *
wxButton_SetDefault (wxButton * _obj)
{
return _obj->SetDefault ();
}
void
wxButton_SetLabel (wxButton * _obj, const wxString & _label)
{
_obj->SetLabel (_label);
}
wxSize
wxButton_GetDefaultSize (wxButton * _obj)
{
return _obj->GetDefaultSize ();
}
#ifndef WRAPPED_WXBUTTON_H
#define WRAPPED_WXBUTTON_H
#include "wx/wx.h"
#ifdef __cplusplus
extern "C"
{
#endif
extern /* Constructor */
wxButton *wxButton_wxButton ();
extern /* Constructor */
wxButton
*wxButton_wxButtonwxWindow_wxWindowID_constwxString_constwxPoint_constwxSize_long_constwxValidator_constwxString
(wxWindow * _parent, wxWindowID _id, const wxString & _label,
const wxPoint & _pos, const wxSize & _size, long _style,
const wxValidator & _validator, const wxString & _name);
extern void wxButton_Destruct (wxButton * _obj);
extern bool wxButton_Create (wxButton * _obj, wxWindow * _parent,
wxWindowID _id, const wxString & _label,
const wxPoint & _pos, const wxSize & _size,
long _style, const wxValidator & _validator,
const wxString & _name);
extern wxString wxButton_GetLabel (wxButton * _obj);
extern wxWindow *wxButton_SetDefault (wxButton * _obj);
extern void wxButton_SetLabel (wxButton * _obj, const wxString & _label);
extern wxSize wxButton_GetDefaultSize (wxButton * _obj);
#ifdef __cplusplus
}
#endif
#endif //WRAPPED_WXBUTTON_H
------------------------------------------------------------------------------
This SF.net email is sponsored by:
High Quality Requirements in a Collaborative Environment.
Download a free trial of Rational Requirements Composer Now!
http://p.sf.net/sfu/www-ibm-com
_______________________________________________
wxhaskell-users mailing list
wxhaskell-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/wxhaskell-users