├── .gitignore ├── .travis.yml ├── AUTHORS ├── COPYING ├── HACKING ├── MANIFEST.in ├── NEWS ├── README.rst ├── benchmarks ├── bench.py ├── plotresults.py ├── testapi-pybindgen.py ├── testapi.cc ├── testapi.h ├── testapi.sip ├── testapi_boost.cc ├── testapi_swig.i └── wscript ├── bzr-plugins └── gnulog.py ├── doc ├── Makefile ├── _static │ └── first-example.zip ├── apiref.rst ├── castxmlparser.rst ├── codesink.rst ├── conf.py ├── container.rst ├── cppattribute.rst ├── cppclass.rst ├── cppclass_typehandlers.rst ├── cppexception.rst ├── cppmethod.rst ├── enum.rst ├── figures │ ├── Makefile │ ├── work-flow-basic.dia │ ├── work-flow-basic.png │ ├── work-flow-gccxml-apidefs.dia │ ├── work-flow-gccxml-apidefs.png │ ├── work-flow-gccxml.dia │ └── work-flow-gccxml.png ├── function.rst ├── index.rst ├── make.bat ├── module.rst ├── settings.rst ├── tutorial.rst ├── typehandlers.rst └── utils.rst ├── examples ├── a │ ├── a.cc │ ├── a.h │ ├── a_test.py │ ├── module-autogen.py │ ├── module-autoscan.py │ ├── modulegen.py │ └── wscript ├── b │ ├── b.cc │ ├── b.h │ ├── b_test.py │ ├── modulegen.py │ └── wscript ├── boost_shared_ptr │ ├── bsp.cc │ ├── bsp.h │ ├── bsp_test.py │ ├── modulegen.py │ └── wscript ├── buffer │ ├── c.cc │ ├── c.h │ ├── c_test.py │ ├── modulegen.py │ └── wscript ├── c │ ├── c.cc │ ├── c.h │ ├── c_test.py │ ├── modulegen.py │ └── wscript ├── callback │ ├── c.cc │ ├── c.h │ ├── c_test.py │ ├── modulegen.py │ └── wscript ├── d │ ├── d.cc │ ├── d.h │ ├── d_test.py │ ├── modulegen.py │ └── wscript ├── e │ ├── e.cc │ ├── e.h │ ├── e_test.py │ ├── modulegen.py │ └── wscript ├── f │ ├── f.cc │ ├── f.h │ ├── f_test.py │ ├── modulegen.py │ └── wscript ├── g │ ├── g.cc │ ├── g.h │ ├── g_test.py │ ├── modulegen.py │ └── wscript ├── h │ ├── h.cc │ ├── h.h │ ├── h_test.py │ ├── modulegen.py │ └── wscript ├── import_from_module │ ├── a.h │ ├── amodulegen.py │ ├── b.h │ ├── b_test.py │ ├── bmodulegen.py │ └── wscript ├── std_shared_ptr │ ├── modulegen.py │ ├── sp.cc │ ├── sp.h │ ├── sp_test.py │ └── wscript └── wscript ├── generate-ChangeLog ├── include └── stdint.h ├── pybindgen ├── __init__.py ├── castxmlparser.py ├── container.py ├── converter_functions.py ├── cppattribute.py ├── cppclass.py ├── cppclass_container.py ├── cppcustomattribute.py ├── cppexception.py ├── cppmethod.py ├── enum.py ├── function.py ├── module.py ├── overloading.py ├── pytypeobject.py ├── settings.py ├── typehandlers │ ├── __init__.py │ ├── base.py │ ├── booltype.py │ ├── codesink.py │ ├── ctypeparser │ │ ├── __init__.py │ │ └── tokenizer.py │ ├── doubletype.py │ ├── floattype.py │ ├── inttype.py │ ├── pyobjecttype.py │ ├── smart_ptr.py │ ├── stringtype.py │ └── voidtype.py ├── utils.py ├── wrapper_registry.py └── wscript ├── setup.cfg ├── setup.py ├── tests ├── boost │ ├── bar.cc │ ├── bar.h │ ├── barmodulegen.py │ ├── bartest.py │ ├── test.py │ └── wscript ├── c-hello │ ├── hello.c │ ├── hello.h │ ├── hellomodulegen.py │ ├── hellotest.py │ └── wscript ├── foo.cc ├── foo.h ├── foomodulegen-auto-split.py ├── foomodulegen-auto.py ├── foomodulegen.py ├── foomodulegen3.py ├── foomodulegen4.py ├── foomodulegen_common.py ├── footest.py ├── test-generation.py ├── test.py └── wscript ├── tox.ini ├── waf ├── waf-tools ├── boost.py ├── cflags.py ├── command.py ├── pkgconfig.py └── shellcmd.py ├── waf.bat ├── wscript └── wutils.py /.gitignore: -------------------------------------------------------------------------------- 1 | .lock-* 2 | .waf* 3 | build 4 | ChangeLog 5 | MANIFEST 6 | pybindgen*.tar.bz2 7 | pybindgen/version.py 8 | doc/_build 9 | doc/figures/work-flow-basic.png 10 | doc/figures/work-flow-gccxml-apidefs.png 11 | doc/figures/work-flow-gccxml.png 12 | *.pyc 13 | *.pyo 14 | *~ 15 | *.bak 16 | .lock-waf_linux2_build 17 | .eggs/ 18 | PyBindGen.egg-info/ 19 | dist/ 20 | .venv/ 21 | /foomodulegen3.pstat 22 | /foomodulegen4.pstat 23 | /hellomodulegen.pstat 24 | 25 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | arch: 3 | - ppc64le 4 | - amd64 5 | 6 | python: 7 | - 2.7 8 | - 3.6 9 | - 3.7 10 | - 3.8 11 | 12 | 13 | sudo: false 14 | 15 | install: 16 | - travis_retry pip install tox 17 | 18 | script: 19 | - python setup.py -V && ./waf configure && ./waf check 20 | 21 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Gustavo J. A. M. Carneiro 2 | -------------------------------------------------------------------------------- /HACKING: -------------------------------------------------------------------------------- 1 | == Needed tools == 2 | 3 | You need to install python, with development headers, and a C/C++ compiler. 4 | 5 | 6 | == Project style / goals / development guidelines == 7 | 8 | Code style rules: 9 | 10 | * Should generate clean C or C++ code 11 | - Near what a human programmer would write; 12 | * Do not depend on C++ language features except when wrapping C++ APIs 13 | - It should be possible to generate pure C modules for wrapping pure C libraries; 14 | * No C++ templates allowed (except if wrapping them) 15 | * Macros should be used rarely, and should be small if used at all 16 | - Shift the complexity into Python side, keep the C/C++ simple (even if large); 17 | * Generated code should not require any external library 18 | - Whenever possible, do not create functions, expand the needed code from the Python code generator instead; 19 | 20 | == Submitting patches == 21 | 22 | 1. First, make sure all unit tests pass: waf clean && waf check 23 | 2. Report the feature/bug in launchpad: https://bugs.launchpad.net/pybindgen/+filebug 24 | 3. Attach a patch or branch to the bug report 25 | 26 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include wutils.py waf waf.bat wscript 2 | recursive-include tests *.py wscript *.cc *.c *.h 3 | recursive-include examples *.py wscript *.cc *.h 4 | recursive-include include *.h 5 | recursive-include waf-tools *.py 6 | recursive-include benchmarks *.py wscript *.i *.sip *.h *.cc 7 | recursive-include pybindgen *.py wscript 8 | include README.rst 9 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | About 2 | ===== 3 | PyBindGen is (surprise!) a python bindings generator. The main features are: 4 | 5 | * Generates clean C or C++ code, nearly as readable as code written 6 | manually by a developer; 7 | * Generated code is self contained and does not require any external 8 | libraries or macros; after generating the python module only python 9 | header files are required, nothing else; 10 | * Does not require Boost.Python (no C++ template magic, also works in C); 11 | * The interface for code generation is a simple Python API, not some 12 | obscure interface definition language. Additionally PyBindGen can 13 | parse header files with gccxml, if gccxml and pygccxml are 14 | installed in the system (note: pygccxml has not been ported to Python 3 yet); 15 | * Can be easily extended with new type handlers; 16 | * Type handlers can allocate memory and register cleanup code to free; 17 | * Supports in, out, and inout parameters (e.g. with pointers or C++ references); 18 | * Supports multiple return values (e.g. due to out/inout parameters); 19 | * Supports wrapping of simple C++ classes; 20 | * Supports virtual methods in classes; 21 | * Supports reference counted classes and, to some extent, smart pointers; 22 | * Multiple inheritance; 23 | * Wrapping templated classes; 24 | 25 | Notable features NOT implemented: 26 | 27 | * Converting exceptions from Python to C++ (only from C++ to Python is currently supported); 28 | * Callbacks. 29 | 30 | Supported Python versions 31 | ========================= 32 | 33 | See the `documentation `_. 34 | 35 | Installation 36 | ============ 37 | 38 | NOTE: if checking out pybindgen from bazaar, do not forget to see the 39 | file HACKING for additional instructions. 40 | 41 | Before proceeding make sure the system requirements are met. PyBindGen requires: 42 | 43 | 1. Python (http://www.python.org) 44 | 2. Python development files (the `python-dev` package in Ubuntu/Debian, for example) 45 | 3. A C/C++ Compilation tool-chain (`apt-get install build-essential`) 46 | 4. (optional) GCCXML and `PyGCCXML `_ 47 | 48 | You can install PyBindGen using either the `setup.py` or WAF. Note: to 49 | be able to run all tests, which involve code generation, and 50 | subsequent compilation, you need to use WAF. 51 | 52 | Installation using setup.py: 53 | ---------------------------- 54 | 55 | python setup.py install 56 | 57 | Installation using WAF 58 | ---------------------- 59 | 60 | PyBindGen uses `WAF `_ as main build system. 61 | However, WAF does not have to be previously installed, as it is 62 | shipped with PyBindGen in a single `waf` script. 63 | 64 | To install PyBindGen, issue the following commands (win32 users should omit the ./ prefix in commands): 65 | 66 | 1. ./waf configure 67 | - optionally you may add the option --prefix /foo/bar. To select a non-defaul python version, use the PYTHON environment variable, e.g.:: 68 | 69 | PYTHON=/usr/bin/python2.4 ./waf configure 70 | 71 | 2. ./waf 72 | - possible options: `-jN` for parallel build, `-p` for progress bar 73 | 3. ./waf check 74 | - optional step, runs the unit tests 75 | 4. ./waf --examples 76 | - optional step, compiles the examples 77 | 5. ./waf install 78 | - may require sudo 79 | 80 | 81 | Windows specific notes 82 | ---------------------- 83 | 84 | WAF concurrency bugs 85 | ++++++++++++++++++++ 86 | 87 | 88 | WAF automatically detects the number of cores and tries to activate 89 | multiple build threads accordingly. However, this concurrency support 90 | appears to be buggy on Windows, therefore you should disable it with the 91 | -j1 option, if you have multiple CPUs: 92 | 93 | waf check -j1 94 | 95 | Compiler selection 96 | ++++++++++++++++++ 97 | 98 | Note that if you are compiling on win32, WAF will look for MSVC 99 | (MicroSoft Visual C) by default and give up on finding a C/C++ 100 | compiler if not found. If you do not have MSVC installed but instead 101 | have MinGW or CygWin GCC, you have to tell WAF to look for GCC in the 102 | configure stage: 103 | 104 | waf configure --check-c-compiler=gcc --check-cxx-compiler=g++ 105 | 106 | Installation 107 | ++++++++++++ 108 | 109 | On win32, `waf install` installs to a Temp folder by default. To have 110 | it install for a certain Python version, use the --prefix option to 111 | waf configure. For instance: 112 | 113 | waf configure --prefix C:\Python26 114 | waf install 115 | 116 | 117 | 118 | Installation failsafe 119 | --------------------- 120 | 121 | If by any chance you have trouble with WAF and are just looking to 122 | install PyBindGen, you should know that PyBindGen is entirely 123 | self-contained in the `pybindgen` directory. You can simply 124 | recursively copy the entire pybindgen folder into Python's 125 | site-packages directory, and that's it! PyBindGen is a pure Python 126 | package and does not actually require a C/C++ compiler; a C++ compiler is only 127 | used for code generation unit tests and compiling the example modules, and it is not needed to generate code. 128 | 129 | 130 | Documentation 131 | ============= 132 | 133 | The following documentation is available: 134 | 135 | 1. `API docs (with introductory tutorial) `_ 136 | 2. Many simple examples in the `examples` directory 137 | 3. Advanced examples in the unit tests (`tests/`) 138 | 4. The source code! 139 | 140 | .. image:: https://travis-ci.org/gjcarneiro/pybindgen.svg?branch=master 141 | :target: https://travis-ci.org/gjcarneiro/pybindgen 142 | 143 | -------------------------------------------------------------------------------- /benchmarks/bench.py: -------------------------------------------------------------------------------- 1 | 2 | import sys 3 | import os 4 | from xml.dom.minidom import getDOMImplementation 5 | from timeit import Timer 6 | import subprocess 7 | 8 | sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), 9 | '..', 'build', 'default', 'benchmarks')) 10 | 11 | 12 | TIMES = 10000000 13 | TIMES1 = TIMES/4 14 | 15 | import testapi_pybindgen 16 | import testapi_boost 17 | import testapi_swig 18 | import testapi_sip 19 | 20 | 21 | def bench(mod, dom, elem): 22 | def bench(): 23 | return mod.func1() 24 | tst = elem.appendChild(dom.createElement('test')) 25 | tst.setAttribute("description", "call function with no arguments") 26 | tst.setAttribute("time", repr(Timer(bench).timeit(TIMES))) 27 | print "%s (%s): %s" % (tst.tagName, tst.getAttribute('description'), tst.getAttribute('time')) 28 | 29 | def bench(): 30 | return mod.func2(1.0, 2.0, 3.0) 31 | tst = elem.appendChild(dom.createElement('test')) 32 | tst.setAttribute("description", "call function taking 3 doubles") 33 | tst.setAttribute("time", repr(Timer(bench).timeit(TIMES))) 34 | print "%s (%s): %s" % (tst.tagName, tst.getAttribute('description'), tst.getAttribute('time')) 35 | 36 | def bench(): 37 | return mod.Multiplier() 38 | tst = elem.appendChild(dom.createElement('test')) 39 | tst.setAttribute("description", "call class constructor with no arguments") 40 | tst.setAttribute("time", repr(Timer(bench).timeit(TIMES))) 41 | print "%s (%s): %s" % (tst.tagName, tst.getAttribute('description'), tst.getAttribute('time')) 42 | 43 | def bench(): 44 | return mod.Multiplier(3.0) 45 | tst = elem.appendChild(dom.createElement('test')) 46 | tst.setAttribute("description", "call class constructor with double") 47 | tst.setAttribute("time", repr(Timer(bench).timeit(TIMES))) 48 | print "%s (%s): %s" % (tst.tagName, tst.getAttribute('description'), tst.getAttribute('time')) 49 | 50 | obj = mod.Multiplier(3.0) 51 | def bench(): 52 | return obj.GetFactor() 53 | tst = elem.appendChild(dom.createElement('test')) 54 | tst.setAttribute("description", "call simple method") 55 | tst.setAttribute("time", repr(Timer(bench).timeit(TIMES))) 56 | print "%s (%s): %s" % (tst.tagName, tst.getAttribute('description'), tst.getAttribute('time')) 57 | 58 | obj = mod.Multiplier(3.0) 59 | def bench(): 60 | return obj.SetFactor() 61 | tst = elem.appendChild(dom.createElement('test')) 62 | tst.setAttribute("description", "call overloaded method 1") 63 | tst.setAttribute("time", repr(Timer(bench).timeit(TIMES))) 64 | print "%s (%s): %s" % (tst.tagName, tst.getAttribute('description'), tst.getAttribute('time')) 65 | 66 | obj = mod.Multiplier(3.0) 67 | def bench(): 68 | return obj.SetFactor(1.0) 69 | tst = elem.appendChild(dom.createElement('test')) 70 | tst.setAttribute("description", "call overloaded method 2") 71 | tst.setAttribute("time", repr(Timer(bench).timeit(TIMES))) 72 | print "%s (%s): %s" % (tst.tagName, tst.getAttribute('description'), tst.getAttribute('time')) 73 | 74 | obj = mod.Multiplier(3.0) 75 | def bench(): 76 | return obj.Multiply(5.0) 77 | tst = elem.appendChild(dom.createElement('test')) 78 | tst.setAttribute("description", "call non-overridden virtual method with double") 79 | tst.setAttribute("time", repr(Timer(bench).timeit(TIMES))) 80 | print "%s (%s): %s" % (tst.tagName, tst.getAttribute('description'), tst.getAttribute('time')) 81 | 82 | class M(mod.Multiplier): 83 | def Multiply(self, value): 84 | return super(M, self).Multiply(value) 85 | obj = M(2.0) 86 | def bench(): 87 | return obj.Multiply(5.0) 88 | 89 | tst = elem.appendChild(dom.createElement('test')) 90 | tst.setAttribute("description", "call python-overridden virtual method from Python") 91 | tst.setAttribute("time", repr(Timer(bench).timeit(TIMES1))) 92 | print "%s (%s): %s" % (tst.tagName, tst.getAttribute('description'), tst.getAttribute('time')) 93 | 94 | def bench(): 95 | return mod.call_virtual_from_cpp(obj, 5.0) 96 | tst = elem.appendChild(dom.createElement('test')) 97 | tst.setAttribute("description", "call python-overridden virtual method from C++") 98 | tst.setAttribute("time", repr(Timer(bench).timeit(TIMES1))) 99 | print "%s (%s): %s" % (tst.tagName, tst.getAttribute('description'), tst.getAttribute('time')) 100 | 101 | 102 | def main(): 103 | impl = getDOMImplementation() 104 | dom = impl.createDocument(None, "pybindgen-benchmarks", None) 105 | top = dom.documentElement 106 | 107 | env = top.appendChild(dom.createElement('environment')) 108 | env.appendChild(dom.createElement('compiler')).appendChild(dom.createTextNode( 109 | subprocess.Popen(["g++", "-v"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT).communicate()[0])) 110 | env.appendChild(dom.createElement('python')).appendChild(dom.createTextNode( 111 | sys.version)) 112 | env.appendChild(dom.createElement('swig')).appendChild(dom.createTextNode( 113 | subprocess.Popen(["swig", "-version"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT).communicate()[0])) 114 | env.appendChild(dom.createElement('boost_python')).appendChild(dom.createTextNode( 115 | subprocess.Popen(["dpkg", "-s", "libboost-python-dev"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT).communicate()[0])) 116 | env.appendChild(dom.createElement('pybindgen')).appendChild(dom.createTextNode( 117 | subprocess.Popen(["bzr", "version-info", '--check-clean'], 118 | stdout=subprocess.PIPE, stderr=subprocess.STDOUT).communicate()[0])) 119 | 120 | env.appendChild(dom.createElement('cpu')).appendChild(dom.createTextNode( 121 | file("/proc/cpuinfo").read())) 122 | 123 | if len(sys.argv) == 3: 124 | env.appendChild(dom.createElement('CXXFLAGS')).appendChild(dom.createTextNode(sys.argv[2])) 125 | 126 | 127 | res = top.appendChild(dom.createElement('results')) 128 | 129 | 130 | print "pybindgen results:" 131 | pbg = res.appendChild(dom.createElement('pybindgen')) 132 | pbg.setAttribute("module-file-size", repr(os.stat("build/default/benchmarks/testapi_pybindgen.so").st_size)) 133 | bench(testapi_pybindgen, dom, pbg) 134 | 135 | print "boost_python results:" 136 | bp = res.appendChild(dom.createElement('boost_python')) 137 | bp.setAttribute("module-file-size", repr(os.stat("build/default/benchmarks/testapi_boost.so").st_size)) 138 | bench(testapi_boost, dom, bp) 139 | 140 | print "swig results:" 141 | sw = res.appendChild(dom.createElement('swig')) 142 | sw.setAttribute("module-file-size", repr(os.stat("build/default/benchmarks/_testapi_swig.so").st_size)) 143 | sw.setAttribute("module-python-file-size", repr(os.stat("build/default/benchmarks/testapi_swig.py").st_size)) 144 | bench(testapi_swig, dom, sw) 145 | 146 | print "sip results:" 147 | sip = res.appendChild(dom.createElement('sip')) 148 | sip.setAttribute("module-file-size", repr(os.stat("build/default/benchmarks/testapi_sip.so").st_size)) 149 | bench(testapi_sip, dom, sip) 150 | 151 | if len(sys.argv) == 3: 152 | f = open(sys.argv[1], "wb") 153 | dom.writexml(f, "", " ", "\n") 154 | f.close() 155 | 156 | 157 | 158 | if __name__ == '__main__': 159 | main() 160 | -------------------------------------------------------------------------------- /benchmarks/plotresults.py: -------------------------------------------------------------------------------- 1 | 2 | import pylab 3 | from xml.dom.minidom import parse, Node 4 | import sys 5 | import numpy as np 6 | import shutil 7 | import os 8 | 9 | DPI = 75 10 | 11 | def getText(nodelist): 12 | rc = "" 13 | for node in nodelist: 14 | if node.nodeType == node.TEXT_NODE: 15 | rc = rc + node.data 16 | return rc 17 | 18 | def main(argv): 19 | input_fname = sys.argv[1] 20 | dom = parse(input_fname) 21 | outdir = sys.argv[2] 22 | res = dom.getElementsByTagName("results")[0] 23 | tools = [e for e in res.childNodes if e.nodeType == Node.ELEMENT_NODE] 24 | 25 | # get the pybindgen revno 26 | pbg_env = dom.getElementsByTagName("environment")[0].getElementsByTagName("pybindgen")[0] 27 | pbg_txt = getText(pbg_env.childNodes).split("\n") 28 | for l in pbg_txt: 29 | k, s, v = l.partition(':') 30 | k = k.strip() 31 | if k == 'revno': 32 | v = v.strip() 33 | revno = v 34 | break 35 | 36 | num_tests = len(tools[0].getElementsByTagName("test")) 37 | shutil.rmtree(outdir, True) 38 | os.mkdir(outdir) 39 | shutil.copy2(input_fname, outdir) 40 | 41 | figures = [] 42 | 43 | 44 | sizes = [float(t.getAttribute('module-file-size')) for t in tools] 45 | labels= [t.tagName for t in tools] 46 | ind = range(len(sizes)) 47 | pylab.bar(ind, sizes) 48 | pylab.xticks([0.5+x for x in ind], labels) 49 | pylab.title("Extension module file size (B)") 50 | fname = "sizes.png" 51 | pylab.savefig(os.path.join(outdir, fname), dpi=DPI) 52 | figures.append(fname) 53 | 54 | 55 | for t in range(num_tests): 56 | pylab.figure() 57 | labels = [] 58 | values = [] 59 | for x, tool in enumerate(tools): 60 | labels.append(tool.tagName) 61 | values.append(float(tool.getElementsByTagName("test")[t].getAttribute('time'))) 62 | ind = range(len(values)) 63 | pylab.bar(ind, values) 64 | pylab.xticks([0.5+x for x in ind], labels) 65 | 66 | desc = tools[0].getElementsByTagName("test")[t].getAttribute("description") 67 | pylab.title(desc) 68 | 69 | fname = "%s.png" % (desc) 70 | pylab.savefig(os.path.join(outdir, fname), dpi=DPI) 71 | figures.append(fname) 72 | 73 | index_html = file("%s/index.html" % outdir, "wt") 74 | print >> index_html, """ 75 | 76 | 77 | PyBindGen Benchmarks 78 | 79 | 80 | 81 | 82 |
Details in the Raw XML file. 83 | Source files for the benchmarks. 84 |
85 | 86 | """ % (os.path.basename(input_fname), revno) 87 | 88 | for fig in figures: 89 | print >> index_html, """ 90 |
91 | 92 |
93 | """ % (fig,) 94 | 95 | print >> index_html, """ 96 | 97 | """ 98 | 99 | index_html.close() 100 | 101 | 102 | 103 | if __name__ == '__main__': 104 | main(sys.argv) 105 | 106 | -------------------------------------------------------------------------------- /benchmarks/testapi-pybindgen.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | import sys 4 | 5 | from pybindgen import Module, retval, param, FileCodeSink 6 | import pybindgen.settings 7 | 8 | def my_module_gen(out_file): 9 | 10 | pybindgen.settings.deprecated_virtuals = False 11 | 12 | mod = Module('testapi_pybindgen') 13 | mod.add_include('"testapi.h"') 14 | 15 | mod.add_function('func1', None, []) 16 | mod.add_function('func2', 'double', [param('double', 'x'), 17 | param('double', 'y'), 18 | param('double', 'z'), 19 | ]) 20 | 21 | Multiplier = mod.add_class('Multiplier', allow_subclassing=True) 22 | Multiplier.add_constructor([]) 23 | Multiplier.add_constructor([param('double', 'factor')]) 24 | 25 | Multiplier.add_method('GetFactor', 'double', [], is_const=True) 26 | Multiplier.add_method('SetFactor', 'void', [param('double', 'f')], is_const=True) 27 | Multiplier.add_method('SetFactor', 'void', [], is_const=True) 28 | Multiplier.add_method('Multiply', 'double', [param('double', 'value')], is_virtual=True, is_const=True) 29 | 30 | mod.add_function('call_virtual_from_cpp', 'double', [param('Multiplier const *', 'obj'), param('double', 'value')]) 31 | 32 | 33 | mod.generate(FileCodeSink(out_file)) 34 | 35 | if __name__ == '__main__': 36 | my_module_gen(sys.stdout) 37 | -------------------------------------------------------------------------------- /benchmarks/testapi.cc: -------------------------------------------------------------------------------- 1 | // -*- Mode: C++; c-file-style: "stroustrup"; indent-tabs-mode:nil; -*- 2 | #include "testapi.h" 3 | 4 | void func1 (void) 5 | { 6 | } 7 | 8 | double func2 (double x, double y, double z) 9 | { 10 | return x + y + z; 11 | } 12 | 13 | 14 | Multiplier::Multiplier () 15 | : m_factor (1.0) 16 | { 17 | } 18 | 19 | Multiplier::Multiplier (double factor) 20 | : m_factor (factor) 21 | { 22 | } 23 | 24 | Multiplier::~Multiplier () 25 | { 26 | } 27 | 28 | double Multiplier::GetFactor () const 29 | { 30 | return m_factor; 31 | } 32 | 33 | void Multiplier::SetFactor (double f) 34 | { 35 | m_factor = f; 36 | } 37 | 38 | void Multiplier::SetFactor () 39 | { 40 | m_factor = 1.0; 41 | } 42 | 43 | double 44 | Multiplier::Multiply (double value) const 45 | { 46 | return value*m_factor; 47 | } 48 | 49 | 50 | double 51 | call_virtual_from_cpp (Multiplier const *obj, double value) 52 | { 53 | return obj->Multiply (value); 54 | } 55 | 56 | -------------------------------------------------------------------------------- /benchmarks/testapi.h: -------------------------------------------------------------------------------- 1 | // -*- Mode: C++; c-file-style: "stroustrup"; indent-tabs-mode:nil; -*- 2 | #ifndef TESTAPI_H_ 3 | # define TESTAPI_H_ 4 | 5 | 6 | void func1 (void); 7 | 8 | double func2 (double x, double y, double z); 9 | 10 | 11 | class Multiplier 12 | { 13 | double m_factor; 14 | 15 | public: 16 | Multiplier (); 17 | Multiplier (double factor); 18 | virtual ~Multiplier (); 19 | 20 | void SetFactor (double f); 21 | void SetFactor (void); 22 | double GetFactor () const; 23 | virtual double Multiply (double value) const; 24 | }; 25 | 26 | double call_virtual_from_cpp (Multiplier const *obj, double value); 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /benchmarks/testapi.sip: -------------------------------------------------------------------------------- 1 | // -*- Mode: C++; c-file-style: "stroustrup"; indent-tabs-mode:nil; -*- 2 | 3 | %Module testapi_sip 0 4 | 5 | 6 | void func1 (); 7 | double func2 (double x, double y, double z); 8 | 9 | 10 | class Multiplier 11 | { 12 | 13 | %TypeHeaderCode 14 | #include "testapi.h" 15 | %End 16 | 17 | public: 18 | Multiplier (); 19 | Multiplier (double factor); 20 | virtual ~Multiplier (); 21 | 22 | void SetFactor (double f); 23 | void SetFactor (); 24 | double GetFactor () const; 25 | virtual double Multiply (double value) const; 26 | }; 27 | 28 | double call_virtual_from_cpp (const Multiplier *obj, double value); 29 | -------------------------------------------------------------------------------- /benchmarks/testapi_boost.cc: -------------------------------------------------------------------------------- 1 | // -*- Mode: C++; c-file-style: "stroustrup"; indent-tabs-mode:nil; -*- 2 | #include "testapi.h" 3 | 4 | #include 5 | 6 | using namespace boost::python; 7 | 8 | void (Multiplier::*factor1) () = &Multiplier::SetFactor; 9 | void (Multiplier::*factor2) (double) = &Multiplier::SetFactor; 10 | 11 | struct MultiplierWrap : Multiplier, wrapper 12 | { 13 | MultiplierWrap () : Multiplier () 14 | { 15 | } 16 | MultiplierWrap (double factor) : Multiplier (factor) 17 | { 18 | } 19 | 20 | double Multiply (double value) const 21 | { 22 | return this->get_override("Multiply") (value); 23 | } 24 | 25 | double default_Multiply (double value) const 26 | { 27 | return this->Multiplier::Multiply (value); 28 | } 29 | 30 | }; 31 | 32 | BOOST_PYTHON_MODULE(testapi_boost) 33 | { 34 | def("func1", func1); 35 | def("func2", func2); 36 | def("call_virtual_from_cpp", call_virtual_from_cpp); 37 | 38 | class_("Multiplier") 39 | .def(init()) 40 | .def("GetFactor", &Multiplier::GetFactor) 41 | .def("SetFactor", factor1) 42 | .def("SetFactor", factor2) 43 | .def("Multiply", &Multiplier::Multiply, &MultiplierWrap::default_Multiply) 44 | ; 45 | 46 | } 47 | 48 | -------------------------------------------------------------------------------- /benchmarks/testapi_swig.i: -------------------------------------------------------------------------------- 1 | /* example.i */ 2 | 3 | %module(directors="1") testapi_swig 4 | %feature("director"); 5 | 6 | %{ 7 | 8 | #include "testapi.h" 9 | 10 | %} 11 | 12 | extern void func1(void); 13 | extern double func2(double x, double y, double z); 14 | 15 | class Multiplier 16 | { 17 | double m_factor; 18 | 19 | public: 20 | Multiplier (); 21 | virtual ~Multiplier (); 22 | Multiplier (double factor); 23 | void SetFactor (double f); 24 | void SetFactor (void); 25 | double GetFactor () const; 26 | virtual double Multiply (double value) const; 27 | }; 28 | 29 | extern double call_virtual_from_cpp (Multiplier const *obj, double value); 30 | 31 | -------------------------------------------------------------------------------- /benchmarks/wscript: -------------------------------------------------------------------------------- 1 | ## -*- python -*- 2 | 3 | def configure(conf): 4 | pass 5 | 6 | def build(bld): 7 | 8 | # 9 | # PyBindGen 10 | # 11 | gen = bld( 12 | features='command', 13 | source='testapi-pybindgen.py', 14 | target='testapimodule.cc', 15 | command='${PYTHON} ${SRC[0]} > ${TGT[0]}') 16 | 17 | obj = bld('cxx', 'shlib', 'pyext') 18 | obj.source = [ 19 | 'testapi.cc', 20 | 'testapimodule.cc' 21 | ] 22 | obj.target = 'testapi_pybindgen' 23 | obj.install_path = None # do not install 24 | obj.includes = '.' 25 | 26 | 27 | # 28 | # Boost::Python 29 | # 30 | obj = ('cxx', 'shlib', 'pyext') 31 | obj.source = [ 32 | 'testapi.cc', 33 | 'testapi_boost.cc' 34 | ] 35 | obj.target = 'testapi_boost' 36 | obj.install_path = None # do not install 37 | obj.includes = '.' 38 | obj.env.append_value('LIB', 'boost_python-mt') 39 | 40 | 41 | # 42 | # SWIG 43 | # 44 | 45 | gen = bld( 46 | features='command', 47 | source='testapi_swig.i', 48 | target='testapi_swig_module.cc', 49 | command='swig -c++ -o ${TGT[0]} -python ${SRC[0]}') 50 | 51 | obj = bld('cxx', 'shlib', 'pyext') 52 | obj.source = [ 53 | 'testapi.cc', 54 | 'testapi_swig_module.cc' 55 | ] 56 | obj.target = '_testapi_swig' 57 | obj.install_path = None # do not install 58 | obj.includes = '.' 59 | 60 | 61 | # 62 | # SIP 63 | # 64 | gen = bld( 65 | features='command', 66 | source='testapi.sip', 67 | target='sipAPItestapi_sip.h siptestapi_sipcmodule.cpp siptestapi_sipMultiplier.cpp', 68 | command='sip -c default/benchmarks ${SRC[0]}') 69 | 70 | obj = bld('cxx', 'shlib', 'pyext') 71 | obj.source = [ 72 | 'testapi.cc', 73 | 'siptestapi_sipcmodule.cpp', 74 | 'siptestapi_sipMultiplier.cpp', 75 | ] 76 | obj.target = 'testapi_sip' 77 | obj.install_path = None # do not install 78 | obj.includes = '.' 79 | 80 | # SIP does not like -fvisibility=hidden :-( 81 | l = list(obj.env['CXXFLAGS_PYEXT']) 82 | l.remove("-fvisibility=hidden") 83 | obj.env['CXXFLAGS_PYEXT'] = l 84 | -------------------------------------------------------------------------------- /doc/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | PAPER = 8 | 9 | # Internal variables. 10 | PAPEROPT_a4 = -D latex_paper_size=a4 11 | PAPEROPT_letter = -D latex_paper_size=letter 12 | ALLSPHINXOPTS = -d _build/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 13 | 14 | .PHONY: help clean html dirhtml pickle json htmlhelp qthelp latex changes linkcheck doctest 15 | 16 | help: 17 | @echo "Please use \`make ' where is one of" 18 | @echo " html to make standalone HTML files" 19 | @echo " dirhtml to make HTML files named index.html in directories" 20 | @echo " pickle to make pickle files" 21 | @echo " json to make JSON files" 22 | @echo " htmlhelp to make HTML files and a HTML help project" 23 | @echo " qthelp to make HTML files and a qthelp project" 24 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 25 | @echo " changes to make an overview of all changed/added/deprecated items" 26 | @echo " linkcheck to check all external links for integrity" 27 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 28 | 29 | clean: 30 | -rm -rf _build/* 31 | -cd figures && make clean 32 | 33 | html: 34 | cd figures && $(MAKE) 35 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) _build/html 36 | @echo 37 | @echo "Build finished. The HTML pages are in _build/html." 38 | 39 | dirhtml: 40 | cd figures && $(MAKE) 41 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) _build/dirhtml 42 | @echo 43 | @echo "Build finished. The HTML pages are in _build/dirhtml." 44 | 45 | pickle: 46 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) _build/pickle 47 | @echo 48 | @echo "Build finished; now you can process the pickle files." 49 | 50 | json: 51 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) _build/json 52 | @echo 53 | @echo "Build finished; now you can process the JSON files." 54 | 55 | htmlhelp: 56 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) _build/htmlhelp 57 | @echo 58 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 59 | ".hhp project file in _build/htmlhelp." 60 | 61 | qthelp: 62 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) _build/qthelp 63 | @echo 64 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 65 | ".qhcp project file in _build/qthelp, like this:" 66 | @echo "# qcollectiongenerator _build/qthelp/PyBindGen.qhcp" 67 | @echo "To view the help file:" 68 | @echo "# assistant -collectionFile _build/qthelp/PyBindGen.qhc" 69 | 70 | latex: 71 | cd figures && $(MAKE) 72 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) _build/latex 73 | @echo 74 | @echo "Build finished; the LaTeX files are in _build/latex." 75 | @echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \ 76 | "run these through (pdf)latex." 77 | 78 | changes: 79 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) _build/changes 80 | @echo 81 | @echo "The overview file is in _build/changes." 82 | 83 | linkcheck: 84 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) _build/linkcheck 85 | @echo 86 | @echo "Link check complete; look for any errors in the above output " \ 87 | "or in _build/linkcheck/output.txt." 88 | 89 | doctest: 90 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) _build/doctest 91 | @echo "Testing of doctests in the sources finished, look at the " \ 92 | "results in _build/doctest/output.txt." 93 | -------------------------------------------------------------------------------- /doc/_static/first-example.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gjcarneiro/pybindgen/926ee3b86d05d16e38480aece23cef365e39c224/doc/_static/first-example.zip -------------------------------------------------------------------------------- /doc/apiref.rst: -------------------------------------------------------------------------------- 1 | 2 | PyBindGen API Reference 3 | ======================= 4 | 5 | 6 | Higher layers 7 | ----------------------- 8 | 9 | .. toctree:: 10 | :maxdepth: 2 11 | 12 | module 13 | function 14 | enum 15 | cppclass 16 | cppmethod 17 | cppattribute 18 | cppexception 19 | container 20 | 21 | castxmlparser 22 | settings 23 | 24 | 25 | Lower layers 26 | ----------------------- 27 | .. toctree:: 28 | :maxdepth: 2 29 | 30 | utils 31 | typehandlers 32 | cppclass_typehandlers 33 | codesink 34 | -------------------------------------------------------------------------------- /doc/castxmlparser.rst: -------------------------------------------------------------------------------- 1 | 2 | ========================================================== 3 | castxmlparser: scan header files to extract API definitions 4 | ========================================================== 5 | 6 | 7 | .. automodule:: pybindgen.castxmlparser 8 | :members: 9 | :undoc-members: 10 | :show-inheritance: 11 | -------------------------------------------------------------------------------- /doc/codesink.rst: -------------------------------------------------------------------------------- 1 | 2 | ================================================================= 3 | typehandlers.codesink: classes that receive generated source code 4 | ================================================================= 5 | 6 | 7 | .. automodule:: pybindgen.typehandlers.codesink 8 | :members: 9 | :undoc-members: 10 | :show-inheritance: 11 | -------------------------------------------------------------------------------- /doc/conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # PyBindGen documentation build configuration file, created by 4 | # sphinx-quickstart on Tue Dec 8 16:06:11 2009. 5 | # 6 | # This file is execfile()d with the current directory set to its containing dir. 7 | # 8 | # Note that not all possible configuration values are present in this 9 | # autogenerated file. 10 | # 11 | # All configuration values have a default; values that are commented out 12 | # serve to show the default. 13 | 14 | import sys, os 15 | 16 | sys.path.insert(0, os.path.join('..')) 17 | 18 | 19 | # If extensions (or modules to document with autodoc) are in another directory, 20 | # add these directories to sys.path here. If the directory is relative to the 21 | # documentation root, use os.path.abspath to make it absolute, like shown here. 22 | #sys.path.append(os.path.abspath('.')) 23 | 24 | # -- General configuration ----------------------------------------------------- 25 | 26 | # Add any Sphinx extension module names here, as strings. They can be extensions 27 | # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. 28 | extensions = ['sphinx.ext.autodoc', 'sphinx.ext.intersphinx', 'sphinx.ext.todo', 'sphinx.ext.coverage'] 29 | 30 | # Add any paths that contain templates here, relative to this directory. 31 | templates_path = ['_templates'] 32 | 33 | # The suffix of source filenames. 34 | source_suffix = '.rst' 35 | 36 | # The encoding of source files. 37 | #source_encoding = 'utf-8' 38 | 39 | # The master toctree document. 40 | master_doc = 'index' 41 | 42 | # General information about the project. 43 | project = u'PyBindGen' 44 | copyright = u'2008-20014, Gustavo Carneiro' 45 | 46 | # The version info for the project you're documenting, acts as replacement for 47 | # |version| and |release|, also used in various other places throughout the 48 | # built documents. 49 | # 50 | # The short X.Y version. 51 | version = '0.17.0' 52 | # The full version, including alpha/beta/rc tags. 53 | release = '0.17.0' 54 | 55 | # The language for content autogenerated by Sphinx. Refer to documentation 56 | # for a list of supported languages. 57 | #language = None 58 | 59 | # There are two options for replacing |today|: either, you set today to some 60 | # non-false value, then it is used: 61 | #today = '' 62 | # Else, today_fmt is used as the format for a strftime call. 63 | #today_fmt = '%B %d, %Y' 64 | 65 | # List of documents that shouldn't be included in the build. 66 | #unused_docs = [] 67 | 68 | # List of directories, relative to source directory, that shouldn't be searched 69 | # for source files. 70 | exclude_trees = ['_build'] 71 | 72 | # The reST default role (used for this markup: `text`) to use for all documents. 73 | #default_role = None 74 | 75 | # If true, '()' will be appended to :func: etc. cross-reference text. 76 | #add_function_parentheses = True 77 | 78 | # If true, the current module name will be prepended to all description 79 | # unit titles (such as .. function::). 80 | #add_module_names = True 81 | 82 | # If true, sectionauthor and moduleauthor directives will be shown in the 83 | # output. They are ignored by default. 84 | #show_authors = False 85 | 86 | # The name of the Pygments (syntax highlighting) style to use. 87 | pygments_style = 'sphinx' 88 | 89 | # A list of ignored prefixes for module index sorting. 90 | #modindex_common_prefix = [] 91 | 92 | 93 | # -- Options for HTML output --------------------------------------------------- 94 | 95 | # The theme to use for HTML and HTML Help pages. Major themes that come with 96 | # Sphinx are currently 'default' and 'sphinxdoc'. 97 | html_theme = 'default' 98 | 99 | # Theme options are theme-specific and customize the look and feel of a theme 100 | # further. For a list of options available for each theme, see the 101 | # documentation. 102 | #html_theme_options = {} 103 | 104 | # Add any paths that contain custom themes here, relative to this directory. 105 | #html_theme_path = [] 106 | 107 | # The name for this set of Sphinx documents. If None, it defaults to 108 | # " v documentation". 109 | #html_title = None 110 | 111 | # A shorter title for the navigation bar. Default is the same as html_title. 112 | #html_short_title = None 113 | 114 | # The name of an image file (relative to this directory) to place at the top 115 | # of the sidebar. 116 | #html_logo = None 117 | 118 | # The name of an image file (within the static path) to use as favicon of the 119 | # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 120 | # pixels large. 121 | #html_favicon = None 122 | 123 | # Add any paths that contain custom static files (such as style sheets) here, 124 | # relative to this directory. They are copied after the builtin static files, 125 | # so a file named "default.css" will overwrite the builtin "default.css". 126 | html_static_path = ['_static'] 127 | 128 | # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, 129 | # using the given strftime format. 130 | #html_last_updated_fmt = '%b %d, %Y' 131 | 132 | # If true, SmartyPants will be used to convert quotes and dashes to 133 | # typographically correct entities. 134 | #html_use_smartypants = True 135 | 136 | # Custom sidebar templates, maps document names to template names. 137 | #html_sidebars = {} 138 | 139 | # Additional templates that should be rendered to pages, maps page names to 140 | # template names. 141 | #html_additional_pages = {} 142 | 143 | # If false, no module index is generated. 144 | #html_use_modindex = True 145 | 146 | # If false, no index is generated. 147 | #html_use_index = True 148 | 149 | # If true, the index is split into individual pages for each letter. 150 | #html_split_index = False 151 | 152 | # If true, links to the reST sources are added to the pages. 153 | html_show_sourcelink = True 154 | 155 | # If true, an OpenSearch description file will be output, and all pages will 156 | # contain a tag referring to it. The value of this option must be the 157 | # base URL from which the finished HTML is served. 158 | #html_use_opensearch = '' 159 | 160 | # If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml"). 161 | #html_file_suffix = '' 162 | 163 | # Output file base name for HTML help builder. 164 | htmlhelp_basename = 'PyBindGendoc' 165 | 166 | 167 | # -- Options for LaTeX output -------------------------------------------------- 168 | 169 | # The paper size ('letter' or 'a4'). 170 | #latex_paper_size = 'letter' 171 | 172 | # The font size ('10pt', '11pt' or '12pt'). 173 | #latex_font_size = '10pt' 174 | 175 | # Grouping the document tree into LaTeX files. List of tuples 176 | # (source start file, target name, title, author, documentclass [howto/manual]). 177 | latex_documents = [ 178 | ('index', 'PyBindGen.tex', u'PyBindGen Documentation', 179 | u'Gustavo J. A. M. Carneiro, Mathieu Lacage', 'manual'), 180 | ] 181 | 182 | # The name of an image file (relative to this directory) to place at the top of 183 | # the title page. 184 | #latex_logo = None 185 | 186 | # For "manual" documents, if this is true, then toplevel headings are parts, 187 | # not chapters. 188 | #latex_use_parts = False 189 | 190 | # Additional stuff for the LaTeX preamble. 191 | #latex_preamble = '' 192 | 193 | # Documents to append as an appendix to all manuals. 194 | #latex_appendices = [] 195 | 196 | # If false, no module index is generated. 197 | #latex_use_modindex = True 198 | 199 | 200 | # Example configuration for intersphinx: refer to the Python standard library. 201 | intersphinx_mapping = {'http://docs.python.org/': None, 202 | } 203 | 204 | 205 | autoclass_content = "both" 206 | 207 | -------------------------------------------------------------------------------- /doc/container.rst: -------------------------------------------------------------------------------- 1 | 2 | ========================================================== 3 | container: wrap STL containers 4 | ========================================================== 5 | 6 | 7 | .. automodule:: pybindgen.container 8 | :members: 9 | :undoc-members: 10 | :show-inheritance: 11 | -------------------------------------------------------------------------------- /doc/cppattribute.rst: -------------------------------------------------------------------------------- 1 | 2 | ============================================== 3 | cppattribute: wrap class/instance attributes 4 | ============================================== 5 | 6 | 7 | .. automodule:: pybindgen.cppattribute 8 | :members: 9 | :undoc-members: 10 | :show-inheritance: 11 | -------------------------------------------------------------------------------- /doc/cppclass.rst: -------------------------------------------------------------------------------- 1 | 2 | ========================================== 3 | cppclass: wrap C++ classes or C structures 4 | ========================================== 5 | 6 | 7 | .. automodule:: pybindgen.cppclass 8 | :members: 9 | :undoc-members: 10 | :show-inheritance: 11 | -------------------------------------------------------------------------------- /doc/cppclass_typehandlers.rst: -------------------------------------------------------------------------------- 1 | 2 | ====================================================================== 3 | cppclass_typehandlers: type handlers for C++ classes (or C structures) 4 | ====================================================================== 5 | 6 | 7 | .. automodule:: pybindgen.cppclass_typehandlers 8 | :members: 9 | :undoc-members: 10 | :show-inheritance: 11 | -------------------------------------------------------------------------------- /doc/cppexception.rst: -------------------------------------------------------------------------------- 1 | 2 | ================================================== 3 | cppexception: translate C++ exceptions into Python 4 | ================================================== 5 | 6 | 7 | .. automodule:: pybindgen.cppexception 8 | :members: 9 | :undoc-members: 10 | :show-inheritance: 11 | -------------------------------------------------------------------------------- /doc/cppmethod.rst: -------------------------------------------------------------------------------- 1 | 2 | ============================================== 3 | cppmethod: wrap class methods and constructors 4 | ============================================== 5 | 6 | 7 | .. automodule:: pybindgen.cppmethod 8 | :members: 9 | :undoc-members: 10 | :show-inheritance: 11 | -------------------------------------------------------------------------------- /doc/enum.rst: -------------------------------------------------------------------------------- 1 | 2 | ========================================================== 3 | enum: wrap enumrations 4 | ========================================================== 5 | 6 | 7 | .. automodule:: pybindgen.enum 8 | :members: 9 | :undoc-members: 10 | :show-inheritance: 11 | -------------------------------------------------------------------------------- /doc/figures/Makefile: -------------------------------------------------------------------------------- 1 | 2 | figures_dia=$(shell echo *.dia) 3 | figures_png=$(figures_dia:.dia=.png) 4 | 5 | 6 | all: $(figures_png) 7 | 8 | %.png: %.dia 9 | dia $< -e $@ 10 | 11 | 12 | clean: 13 | -rm -f $(figures_png) 14 | -------------------------------------------------------------------------------- /doc/figures/work-flow-basic.dia: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gjcarneiro/pybindgen/926ee3b86d05d16e38480aece23cef365e39c224/doc/figures/work-flow-basic.dia -------------------------------------------------------------------------------- /doc/figures/work-flow-basic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gjcarneiro/pybindgen/926ee3b86d05d16e38480aece23cef365e39c224/doc/figures/work-flow-basic.png -------------------------------------------------------------------------------- /doc/figures/work-flow-gccxml-apidefs.dia: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gjcarneiro/pybindgen/926ee3b86d05d16e38480aece23cef365e39c224/doc/figures/work-flow-gccxml-apidefs.dia -------------------------------------------------------------------------------- /doc/figures/work-flow-gccxml-apidefs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gjcarneiro/pybindgen/926ee3b86d05d16e38480aece23cef365e39c224/doc/figures/work-flow-gccxml-apidefs.png -------------------------------------------------------------------------------- /doc/figures/work-flow-gccxml.dia: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gjcarneiro/pybindgen/926ee3b86d05d16e38480aece23cef365e39c224/doc/figures/work-flow-gccxml.dia -------------------------------------------------------------------------------- /doc/figures/work-flow-gccxml.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gjcarneiro/pybindgen/926ee3b86d05d16e38480aece23cef365e39c224/doc/figures/work-flow-gccxml.png -------------------------------------------------------------------------------- /doc/function.rst: -------------------------------------------------------------------------------- 1 | 2 | ================================= 3 | function: C/C++ function wrappers 4 | ================================= 5 | 6 | 7 | .. automodule:: pybindgen.function 8 | :members: 9 | :undoc-members: 10 | :show-inheritance: 11 | -------------------------------------------------------------------------------- /doc/index.rst: -------------------------------------------------------------------------------- 1 | .. PyBindGen documentation master file, created by 2 | sphinx-quickstart on Tue Dec 8 16:06:11 2009. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to PyBindGen's documentation! 7 | ===================================== 8 | 9 | Contents: 10 | 11 | .. toctree:: 12 | :maxdepth: 3 13 | 14 | tutorial 15 | apiref 16 | 17 | 18 | Indices and tables 19 | ================== 20 | 21 | * :ref:`genindex` 22 | * :ref:`modindex` 23 | * :ref:`search` 24 | 25 | -------------------------------------------------------------------------------- /doc/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | REM Command file for Sphinx documentation 4 | 5 | set SPHINXBUILD=sphinx-build 6 | set ALLSPHINXOPTS=-d _build/doctrees %SPHINXOPTS% . 7 | if NOT "%PAPER%" == "" ( 8 | set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% 9 | ) 10 | 11 | if "%1" == "" goto help 12 | 13 | if "%1" == "help" ( 14 | :help 15 | echo.Please use `make ^` where ^ is one of 16 | echo. html to make standalone HTML files 17 | echo. dirhtml to make HTML files named index.html in directories 18 | echo. pickle to make pickle files 19 | echo. json to make JSON files 20 | echo. htmlhelp to make HTML files and a HTML help project 21 | echo. qthelp to make HTML files and a qthelp project 22 | echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter 23 | echo. changes to make an overview over all changed/added/deprecated items 24 | echo. linkcheck to check all external links for integrity 25 | echo. doctest to run all doctests embedded in the documentation if enabled 26 | goto end 27 | ) 28 | 29 | if "%1" == "clean" ( 30 | for /d %%i in (_build\*) do rmdir /q /s %%i 31 | del /q /s _build\* 32 | goto end 33 | ) 34 | 35 | if "%1" == "html" ( 36 | %SPHINXBUILD% -b html %ALLSPHINXOPTS% _build/html 37 | echo. 38 | echo.Build finished. The HTML pages are in _build/html. 39 | goto end 40 | ) 41 | 42 | if "%1" == "dirhtml" ( 43 | %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% _build/dirhtml 44 | echo. 45 | echo.Build finished. The HTML pages are in _build/dirhtml. 46 | goto end 47 | ) 48 | 49 | if "%1" == "pickle" ( 50 | %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% _build/pickle 51 | echo. 52 | echo.Build finished; now you can process the pickle files. 53 | goto end 54 | ) 55 | 56 | if "%1" == "json" ( 57 | %SPHINXBUILD% -b json %ALLSPHINXOPTS% _build/json 58 | echo. 59 | echo.Build finished; now you can process the JSON files. 60 | goto end 61 | ) 62 | 63 | if "%1" == "htmlhelp" ( 64 | %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% _build/htmlhelp 65 | echo. 66 | echo.Build finished; now you can run HTML Help Workshop with the ^ 67 | .hhp project file in _build/htmlhelp. 68 | goto end 69 | ) 70 | 71 | if "%1" == "qthelp" ( 72 | %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% _build/qthelp 73 | echo. 74 | echo.Build finished; now you can run "qcollectiongenerator" with the ^ 75 | .qhcp project file in _build/qthelp, like this: 76 | echo.^> qcollectiongenerator _build\qthelp\PyBindGen.qhcp 77 | echo.To view the help file: 78 | echo.^> assistant -collectionFile _build\qthelp\PyBindGen.ghc 79 | goto end 80 | ) 81 | 82 | if "%1" == "latex" ( 83 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% _build/latex 84 | echo. 85 | echo.Build finished; the LaTeX files are in _build/latex. 86 | goto end 87 | ) 88 | 89 | if "%1" == "changes" ( 90 | %SPHINXBUILD% -b changes %ALLSPHINXOPTS% _build/changes 91 | echo. 92 | echo.The overview file is in _build/changes. 93 | goto end 94 | ) 95 | 96 | if "%1" == "linkcheck" ( 97 | %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% _build/linkcheck 98 | echo. 99 | echo.Link check complete; look for any errors in the above output ^ 100 | or in _build/linkcheck/output.txt. 101 | goto end 102 | ) 103 | 104 | if "%1" == "doctest" ( 105 | %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% _build/doctest 106 | echo. 107 | echo.Testing of doctests in the sources finished, look at the ^ 108 | results in _build/doctest/output.txt. 109 | goto end 110 | ) 111 | 112 | :end 113 | -------------------------------------------------------------------------------- /doc/module.rst: -------------------------------------------------------------------------------- 1 | 2 | ============================================================== 3 | module: generate Python modules and submodules 4 | ============================================================== 5 | 6 | 7 | .. automodule:: pybindgen.module 8 | :members: 9 | :undoc-members: 10 | :show-inheritance: 11 | -------------------------------------------------------------------------------- /doc/settings.rst: -------------------------------------------------------------------------------- 1 | 2 | ============================================== 3 | settings: pybindgen global settings 4 | ============================================== 5 | 6 | 7 | .. automodule:: pybindgen.settings 8 | :members: 9 | :undoc-members: 10 | :show-inheritance: 11 | 12 | .. data:: pybindgen.settings.wrapper_registry 13 | 14 | A :class:`pybindgen.wrapper_registry.WrapperRegistry` subclass to use for creating 15 | wrapper registries. A wrapper registry ensures that at most one 16 | python wrapper exists for each C/C++ object. 17 | 18 | 19 | .. autoclass:: pybindgen.wrapper_registry.WrapperRegistry 20 | :members: 21 | :undoc-members: 22 | :show-inheritance: 23 | .. autoclass:: pybindgen.settings.NullWrapperRegistry 24 | :show-inheritance: 25 | .. autoclass:: pybindgen.settings.StdMapWrapperRegistry 26 | :show-inheritance: 27 | -------------------------------------------------------------------------------- /doc/typehandlers.rst: -------------------------------------------------------------------------------- 1 | 2 | ================================================================================= 3 | typehandlers.base: abstract base classes for type handlers and wrapper generators 4 | ================================================================================= 5 | 6 | 7 | .. automodule:: pybindgen.typehandlers.base 8 | :members: 9 | :undoc-members: 10 | :show-inheritance: 11 | -------------------------------------------------------------------------------- /doc/utils.rst: -------------------------------------------------------------------------------- 1 | 2 | ========================= 3 | utils: internal utilities 4 | ========================= 5 | 6 | 7 | .. automodule:: pybindgen.utils 8 | :members: 9 | :undoc-members: 10 | :show-inheritance: 11 | -------------------------------------------------------------------------------- /examples/a/a.cc: -------------------------------------------------------------------------------- 1 | #include "a.h" 2 | #include 3 | 4 | void ADoA (void) 5 | { 6 | std::cout << "ADoA" << std::endl; 7 | } 8 | 9 | void ADoB (uint32_t b) 10 | { 11 | std::cout << "ADoB=" << b << std::endl; 12 | } 13 | 14 | uint32_t ADoC (void) 15 | { 16 | std::cout << "ADoC" << std::endl; 17 | return 1; 18 | } 19 | -------------------------------------------------------------------------------- /examples/a/a.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void ADoA (void); 4 | 5 | void ADoB (uint32_t b); 6 | 7 | uint32_t ADoC (void); 8 | -------------------------------------------------------------------------------- /examples/a/a_test.py: -------------------------------------------------------------------------------- 1 | import sys 2 | sys.path.insert(0, "../../build/examples/a") 3 | from a import * 4 | 5 | ADoA () 6 | ADoB (1) 7 | a = ADoC () 8 | print(a) 9 | 10 | -------------------------------------------------------------------------------- /examples/a/module-autogen.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | import sys 4 | 5 | import pybindgen 6 | from pybindgen import FileCodeSink 7 | from pybindgen.castxmlparser import ModuleParser 8 | 9 | def my_module_gen(): 10 | module_parser = ModuleParser('a1', '::') 11 | module = module_parser.parse([sys.argv[1]]) 12 | module.add_include('"a.h"') 13 | 14 | module.generate(FileCodeSink(sys.stdout)) 15 | 16 | if __name__ == '__main__': 17 | my_module_gen() 18 | -------------------------------------------------------------------------------- /examples/a/module-autoscan.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | import sys 4 | 5 | from pybindgen import FileCodeSink 6 | from pybindgen.castxmlparser import ModuleParser 7 | 8 | def my_module_gen(): 9 | module_parser = ModuleParser('a2', '::') 10 | module_parser.parse([sys.argv[1]], includes=['"a.h"'], pygen_sink=FileCodeSink(sys.stdout)) 11 | 12 | if __name__ == '__main__': 13 | my_module_gen() 14 | -------------------------------------------------------------------------------- /examples/a/modulegen.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | import sys 4 | 5 | import pybindgen 6 | from pybindgen import ReturnValue, Parameter, FileCodeSink 7 | from pybindgen.module import Module 8 | from pybindgen.function import Function 9 | 10 | def my_module_gen(out_file): 11 | 12 | mod = Module('a') 13 | mod.add_include('"a.h"') 14 | 15 | mod.add_function('ADoA', None, []) 16 | mod.add_function('ADoB', None, [Parameter.new('uint32_t', 'b')]) 17 | mod.add_function('ADoC', ReturnValue.new('uint32_t'), []) 18 | 19 | mod.generate(FileCodeSink(out_file) ) 20 | 21 | if __name__ == '__main__': 22 | my_module_gen(sys.stdout) 23 | -------------------------------------------------------------------------------- /examples/a/wscript: -------------------------------------------------------------------------------- 1 | ## -*- python -*- 2 | 3 | def build(bld): 4 | ## manual code generation using simple pybindgen API calls 5 | gen = bld( 6 | features='command', 7 | source='modulegen.py', 8 | target='amodule.cc', 9 | command='${PYTHON} ${SRC[0]} > ${TGT[0]}') 10 | 11 | if bld.env['CXX']: 12 | obj = bld(features=['cxx', 'cxxshlib', 'pyext']) 13 | obj.source = [ 14 | 'a.cc', 15 | 'amodule.cc' 16 | ] 17 | obj.target = 'a' 18 | obj.install_path = None # do not install 19 | obj.includes = '.' 20 | 21 | 22 | if bld.env['ENABLE_PYGCCXML']: 23 | ## gccxml direct generation method 24 | bld( 25 | features='command', 26 | source='module-autogen.py a.h', 27 | target='a1module.cc', 28 | command='${PYTHON} ${SRC[0]} ${SRC[1]} > ${TGT[0]}') 29 | 30 | obj = bld(features=['cxx', 'cxxshlib', 'pyext']) 31 | obj.source = [ 32 | 'a.cc', 33 | 'a1module.cc' 34 | ] 35 | obj.target = 'a1' 36 | obj.install_path = None # do not install 37 | obj.includes = '.' 38 | 39 | 40 | ## gccxml indirect generation method 41 | bld( 42 | features='command', 43 | source='module-autoscan.py a.h', 44 | target='a2modulegen.py', 45 | command='${PYTHON} ${SRC[0]} ${SRC[1]} > ${TGT[0]}') 46 | 47 | bld( 48 | features='command', 49 | source='a2modulegen.py', 50 | target='a2module.cc', 51 | command='${PYTHON} ${SRC[0]} > ${TGT[0]}') 52 | 53 | obj = bld(features=['cxx', 'cxxshlib', 'pyext']) 54 | obj.source = [ 55 | 'a.cc', 56 | 'a2module.cc' 57 | ] 58 | obj.target = 'a2' 59 | obj.install_path = None # do not install 60 | obj.includes = '.' 61 | -------------------------------------------------------------------------------- /examples/b/b.cc: -------------------------------------------------------------------------------- 1 | #include "b.h" 2 | #include 3 | 4 | void BDoA (struct B b) 5 | { 6 | std::cout << "BDoA b_a=" << b.b_a << ", b_b=" << b.b_b << std::endl; 7 | } 8 | struct B BDoB (void) 9 | { 10 | std::cout << "BDoB" << std::endl; 11 | struct B b; 12 | b.b_a = 1; 13 | b.b_b = 2; 14 | return b; 15 | } 16 | -------------------------------------------------------------------------------- /examples/b/b.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct B 4 | { 5 | uint32_t b_a; 6 | uint32_t b_b; 7 | }; 8 | 9 | void BDoA (struct B b); 10 | struct B BDoB (void); 11 | -------------------------------------------------------------------------------- /examples/b/b_test.py: -------------------------------------------------------------------------------- 1 | import sys 2 | sys.path.insert(0, "../../build/examples/b") 3 | from b import * 4 | 5 | b = B () 6 | b.b_a = 10 7 | b.b_b = 5 8 | BDoA (b) 9 | b = BDoB () 10 | -------------------------------------------------------------------------------- /examples/b/modulegen.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | import sys 4 | 5 | import pybindgen 6 | from pybindgen import ReturnValue, Parameter, Module, Function, FileCodeSink 7 | from pybindgen import CppMethod, CppConstructor, CppClass, Enum 8 | 9 | 10 | def my_module_gen(out_file): 11 | 12 | mod = Module('b') 13 | mod.add_include('"b.h"') 14 | 15 | B = mod.add_class('B') 16 | B.add_constructor([]) 17 | B.add_copy_constructor() 18 | B.add_instance_attribute('b_a', ReturnValue.new('uint32_t')) 19 | B.add_instance_attribute('b_b', ReturnValue.new('uint32_t')) 20 | 21 | mod.add_function('BDoA', None, [Parameter.new('B', 'b')]) 22 | mod.add_function('BDoB', ReturnValue.new('B'), []) 23 | 24 | mod.generate(FileCodeSink(out_file) ) 25 | 26 | if __name__ == '__main__': 27 | my_module_gen(sys.stdout) 28 | -------------------------------------------------------------------------------- /examples/b/wscript: -------------------------------------------------------------------------------- 1 | ## -*- python -*- 2 | 3 | def build(bld): 4 | 5 | gen = bld( 6 | features='command', 7 | source='modulegen.py', 8 | target='bmodule.cc', 9 | command='${PYTHON} ${SRC[0]} > ${TGT[0]}') 10 | 11 | if bld.env['CXX']: 12 | obj = bld(features=['cxx', 'cxxshlib', 'pyext']) 13 | obj.source = [ 14 | 'b.cc', 15 | 'bmodule.cc' 16 | ] 17 | obj.target = 'b' 18 | obj.install_path = None # do not install 19 | obj.includes = '.' 20 | -------------------------------------------------------------------------------- /examples/boost_shared_ptr/bsp.cc: -------------------------------------------------------------------------------- 1 | #include "bsp.h" 2 | 3 | boost::shared_ptr g_foo; 4 | 5 | void function_that_takes_foo(boost::shared_ptr foo) 6 | { 7 | g_foo = foo; 8 | } 9 | 10 | boost::shared_ptr function_that_returns_foo() 11 | { 12 | return g_foo; 13 | } 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /examples/boost_shared_ptr/bsp.h: -------------------------------------------------------------------------------- 1 | // -*- Mode: C++; c-file-style: "stroustrup"; indent-tabs-mode:nil; -*- 2 | #ifndef BSP_H_ 3 | # define BSP_H_ 4 | 5 | #include 6 | #include 7 | 8 | 9 | class Foo 10 | { 11 | std::string m_datum; 12 | public: 13 | 14 | Foo () : m_datum ("") {} 15 | 16 | Foo (std::string const &datum) : m_datum (datum) {} 17 | 18 | const std::string get_datum () const { return m_datum; } 19 | 20 | void set_datum (std::string const &datum) { m_datum = datum; } 21 | 22 | virtual ~Foo() {} 23 | 24 | }; 25 | 26 | void function_that_takes_foo (boost::shared_ptr foo); 27 | boost::shared_ptr function_that_returns_foo (); 28 | 29 | #endif /* !FOO_H_ */ 30 | -------------------------------------------------------------------------------- /examples/boost_shared_ptr/bsp_test.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os.path 3 | sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), 4 | '..', '..', 'build', 'examples', 'boost_shared_ptr')) 5 | 6 | import bsp 7 | 8 | 9 | f = bsp.Foo("hello123") 10 | bsp.function_that_takes_foo(f) 11 | f1 = bsp.function_that_returns_foo() 12 | print f1.get_datum() 13 | f.set_datum("xxxx") 14 | print f1.get_datum() 15 | 16 | -------------------------------------------------------------------------------- /examples/boost_shared_ptr/modulegen.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | import sys, os 4 | sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), 5 | '..', '..')) 6 | 7 | #import pybindgen 8 | #import pybindgen.utils 9 | #from pybindgen.typehandlers import base as typehandlers 10 | from pybindgen import Module, FileCodeSink, param, retval 11 | #from pybindgen import CppMethod, CppConstructor, CppClass, Enum 12 | #from pybindgen.function import CustomFunctionWrapper 13 | #from pybindgen.cppmethod import CustomCppMethodWrapper 14 | from pybindgen import cppclass 15 | from pybindgen.typehandlers.smart_ptr import BoostSharedPtr 16 | 17 | #from pybindgen import param, retval 18 | 19 | import pybindgen.settings 20 | pybindgen.settings.deprecated_virtuals = False 21 | 22 | 23 | def my_module_gen(out_file): 24 | 25 | mod = Module('bsp') 26 | 27 | mod.add_include ('"bsp.h"') 28 | 29 | Foo = mod.add_class('Foo', memory_policy=BoostSharedPtr('::Foo')) 30 | 31 | Foo.add_constructor([param('std::string', 'datum')]) 32 | Foo.add_constructor([]) 33 | Foo.add_method('get_datum', retval('const std::string'), []) 34 | Foo.add_method('set_datum', None, [param('const std::string', 'datum')]) 35 | 36 | 37 | mod.add_function('function_that_takes_foo', None, 38 | [param('boost::shared_ptr', 'foo')]) 39 | 40 | mod.add_function('function_that_returns_foo', retval('boost::shared_ptr'), []) 41 | 42 | ## ---- finally, generate the whole thing ---- 43 | mod.generate(FileCodeSink(out_file)) 44 | 45 | 46 | if __name__ == '__main__': 47 | my_module_gen(sys.stdout) 48 | 49 | -------------------------------------------------------------------------------- /examples/boost_shared_ptr/wscript: -------------------------------------------------------------------------------- 1 | ## -*- python -*- 2 | 3 | def build(bld): 4 | 5 | gen = bld( 6 | features='command', 7 | source='modulegen.py', 8 | target='bspmodule.cc', 9 | command='${PYTHON} ${SRC[0]} > ${TGT[0]}') 10 | 11 | if bld.env['CXX']: 12 | obj = bld(features=['cxx', 'cxxshlib', 'pyext']) 13 | obj.source = [ 14 | 'bsp.cc', 15 | 'bspmodule.cc' 16 | ] 17 | obj.target = 'bsp' 18 | obj.install_path = None # do not install 19 | obj.includes = '.' 20 | 21 | -------------------------------------------------------------------------------- /examples/buffer/c.cc: -------------------------------------------------------------------------------- 1 | #include "c.h" 2 | 3 | static const int LEN = 1024*1024; 4 | 5 | static unsigned short int buffer[LEN] = {0,}; 6 | 7 | unsigned short int* GetBuffer() 8 | { 9 | return buffer; 10 | } 11 | 12 | int GetBufferLen() 13 | { 14 | return LEN; 15 | } 16 | 17 | unsigned short int GetBufferChecksum() 18 | { 19 | unsigned short int sum = 0; 20 | for (int i = 0; i < LEN; sum += buffer[i++]); 21 | return sum; 22 | } 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /examples/buffer/c.h: -------------------------------------------------------------------------------- 1 | 2 | unsigned short* GetBuffer(); 3 | int GetBufferLen(); 4 | unsigned short GetBufferChecksum(); 5 | 6 | 7 | -------------------------------------------------------------------------------- /examples/buffer/c_test.py: -------------------------------------------------------------------------------- 1 | import sys 2 | sys.path.insert(0, "../../build/examples/buffer") 3 | import c 4 | 5 | print c.GetBufferLen() 6 | print c.GetBufferChecksum() 7 | buf = c.GetBuffer() 8 | buf[10] = chr(123) 9 | print c.GetBufferChecksum() 10 | print buf[10] 11 | -------------------------------------------------------------------------------- /examples/buffer/modulegen.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | import sys 4 | 5 | import pybindgen 6 | from pybindgen import ReturnValue, Parameter, Module, Function, FileCodeSink 7 | from pybindgen import CppMethod, CppConstructor, CppClass, Enum 8 | from pybindgen.typehandlers.base import ForwardWrapperBase 9 | 10 | 11 | class BufferReturn(ReturnValue): 12 | CTYPES = [] 13 | 14 | def __init__(self, ctype, length_expression): 15 | super(BufferReturn, self).__init__(ctype, is_const=False) 16 | self.length_expression = length_expression 17 | 18 | def convert_c_to_python(self, wrapper): 19 | pybuf = wrapper.after_call.declare_variable("PyObject*", "pybuf") 20 | wrapper.after_call.write_code("%s = PyBuffer_FromReadWriteMemory(retval, (%s)*sizeof(short int));" % (pybuf, self.length_expression)) 21 | wrapper.build_params.add_parameter("N", [pybuf], prepend=True) 22 | 23 | 24 | def my_module_gen(out_file): 25 | 26 | mod = Module('c') 27 | mod.add_include('"c.h"') 28 | 29 | mod.add_function("GetBuffer", BufferReturn("unsigned short int*", "GetBufferLen()"), []) 30 | mod.add_function("GetBufferLen", ReturnValue.new("int"), []) 31 | mod.add_function("GetBufferChecksum", ReturnValue.new("unsigned short"), []) 32 | 33 | mod.generate(FileCodeSink(out_file)) 34 | 35 | if __name__ == '__main__': 36 | my_module_gen(sys.stdout) 37 | -------------------------------------------------------------------------------- /examples/buffer/wscript: -------------------------------------------------------------------------------- 1 | ## -*- python -*- 2 | 3 | def build(bld): 4 | 5 | gen = bld( 6 | features='command', 7 | source='modulegen.py', 8 | target='cmodule.cc', 9 | command='${PYTHON} ${SRC[0]} > ${TGT[0]}') 10 | 11 | if bld.env['CXX']: 12 | obj = bld(features=['cxx', 'cxxshlib', 'pyext']) 13 | obj.source = [ 14 | 'c.cc', 15 | 'cmodule.cc' 16 | ] 17 | obj.target = 'c' 18 | obj.install_path = None # do not install 19 | obj.includes = '.' 20 | 21 | -------------------------------------------------------------------------------- /examples/c/c.cc: -------------------------------------------------------------------------------- 1 | #include "c.h" 2 | #include 3 | 4 | C::C () 5 | : m_c (0) 6 | { 7 | std::cout << "C::C" << std::endl; 8 | } 9 | C::C (uint32_t c) 10 | : m_c (c) 11 | { 12 | std::cout << "C::C (uint32_t)" << std::endl; 13 | } 14 | C::~C () 15 | { 16 | std::cout << "C::~C" << std::endl; 17 | } 18 | 19 | void 20 | C::DoA (void) 21 | { 22 | std::cout << "C::DoA" << std::endl; 23 | } 24 | void 25 | C::DoB (void) 26 | { 27 | std::cout << "C::DoB" << std::endl; 28 | } 29 | 30 | void 31 | C::DoC (uint32_t c) 32 | { 33 | std::cout << "C::DoC=" << c << std::endl; 34 | m_c = c; 35 | } 36 | uint32_t 37 | C::DoD (void) 38 | { 39 | std::cout << "C::DoD" << std::endl; 40 | return m_c; 41 | } 42 | 43 | void 44 | C::DoE (void) 45 | { 46 | std::cout << "C::DoE" << std::endl; 47 | } 48 | -------------------------------------------------------------------------------- /examples/c/c.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | class C 4 | { 5 | public: 6 | C (); 7 | C (uint32_t c); 8 | virtual ~C (); 9 | 10 | static void DoA (void); 11 | void DoB (void); 12 | void DoC (uint32_t c); 13 | uint32_t DoD (void); 14 | virtual void DoE (void); 15 | private: 16 | uint32_t m_c; 17 | }; 18 | -------------------------------------------------------------------------------- /examples/c/c_test.py: -------------------------------------------------------------------------------- 1 | import sys 2 | sys.path.insert(0, "../../build/examples/c") 3 | from c import * 4 | 5 | c = C (10) 6 | C.DoA () 7 | c.DoB () 8 | c.DoC (5) 9 | c_v = c.DoD () 10 | c.DoE () 11 | 12 | -------------------------------------------------------------------------------- /examples/c/modulegen.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | import sys 4 | 5 | import pybindgen 6 | from pybindgen import ReturnValue, Parameter, Module, Function, FileCodeSink 7 | from pybindgen import CppMethod, CppConstructor, CppClass, Enum 8 | 9 | 10 | def my_module_gen(out_file): 11 | 12 | mod = Module('c') 13 | mod.add_include('"c.h"') 14 | 15 | C = mod.add_class('C') 16 | C.add_constructor([]) 17 | C.add_constructor([Parameter.new('uint32_t', 'c')]) 18 | C.add_method('DoA', None, [], is_static=True) 19 | C.add_method('DoB', None, []) 20 | C.add_method('DoC', None, [Parameter.new('uint32_t', 'c')]) 21 | C.add_method('DoD', ReturnValue.new('uint32_t'), []) 22 | C.add_method('DoE', None, [], is_virtual=True) 23 | 24 | mod.generate(FileCodeSink(out_file) ) 25 | 26 | if __name__ == '__main__': 27 | my_module_gen(sys.stdout) 28 | -------------------------------------------------------------------------------- /examples/c/wscript: -------------------------------------------------------------------------------- 1 | ## -*- python -*- 2 | 3 | def build(bld): 4 | 5 | gen = bld( 6 | features='command', 7 | source='modulegen.py', 8 | target='cmodule.cc', 9 | command='${PYTHON} ${SRC[0]} > ${TGT[0]}') 10 | 11 | if bld.env['CXX']: 12 | obj = bld(features=['cxx', 'cxxshlib', 'pyext']) 13 | obj.source = [ 14 | 'c.cc', 15 | 'cmodule.cc' 16 | ] 17 | obj.target = 'c' 18 | obj.install_path = None # do not install 19 | obj.includes = '.' 20 | 21 | -------------------------------------------------------------------------------- /examples/callback/c.cc: -------------------------------------------------------------------------------- 1 | #include "c.h" 2 | 3 | void visit (Visitor visitor, void *data) 4 | { 5 | for (int i = 0; i < 10; i++) 6 | visitor (i, data); 7 | } 8 | 9 | 10 | -------------------------------------------------------------------------------- /examples/callback/c.h: -------------------------------------------------------------------------------- 1 | 2 | typedef void (*Visitor) (int value, void *data); 3 | 4 | 5 | void visit (Visitor visitor, void *data); 6 | 7 | -------------------------------------------------------------------------------- /examples/callback/c_test.py: -------------------------------------------------------------------------------- 1 | import sys 2 | sys.path.insert(0, "../../build/examples/callback") 3 | import c 4 | 5 | def visitor(value): 6 | print value 7 | 8 | c.visit(visitor) 9 | 10 | -------------------------------------------------------------------------------- /examples/callback/modulegen.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | import sys 4 | 5 | import pybindgen 6 | from pybindgen import ReturnValue, Parameter, Module, Function, FileCodeSink 7 | from pybindgen import CppMethod, CppConstructor, CppClass, Enum 8 | from pybindgen.typehandlers.base import ForwardWrapperBase 9 | 10 | 11 | class VisitorParam(Parameter): 12 | 13 | DIRECTIONS = [Parameter.DIRECTION_IN] 14 | CTYPES = ['Visitor'] 15 | 16 | def convert_python_to_c(self, wrapper): 17 | assert isinstance(wrapper, ForwardWrapperBase) 18 | 19 | py_cb = wrapper.declarations.declare_variable("PyObject*", self.name) 20 | wrapper.parse_params.add_parameter('O', ['&'+py_cb], self.name) 21 | 22 | wrapper.before_call.write_error_check("!PyCallable_Check(%s)" % py_cb, 23 | """PyErr_SetString(PyExc_TypeError, "visitor parameter must be callable");""") 24 | wrapper.call_params.append("_wrap_Visit") 25 | wrapper.before_call.write_code("Py_INCREF(%s);" % py_cb) 26 | wrapper.before_call.add_cleanup_code("Py_DECREF(%s);" % py_cb) 27 | wrapper.call_params.append(py_cb) 28 | 29 | 30 | def convert_c_to_python(self, wrapper): 31 | raise NotImplementedError 32 | 33 | 34 | 35 | def my_module_gen(out_file): 36 | 37 | mod = Module('c') 38 | mod.add_include('"c.h"') 39 | 40 | mod.header.writeln("""void _wrap_Visit(int value, void *data);""") 41 | mod.body.writeln(""" 42 | void _wrap_Visit(int value, void *data) 43 | { 44 | PyObject *callback = (PyObject*) data; 45 | PyObject_CallFunction(callback, (char*) "i", value); 46 | } 47 | """) 48 | 49 | mod.add_function("visit", None, [Parameter.new("Visitor", "visitor")] 50 | # the 'data' parameter is inserted automatically 51 | # by the custom callback type handler 52 | ) 53 | 54 | mod.generate(FileCodeSink(out_file)) 55 | 56 | if __name__ == '__main__': 57 | my_module_gen(sys.stdout) 58 | -------------------------------------------------------------------------------- /examples/callback/wscript: -------------------------------------------------------------------------------- 1 | ## -*- python -*- 2 | 3 | def build(bld): 4 | 5 | gen = bld( 6 | features='command', 7 | source='modulegen.py', 8 | target='cmodule.cc', 9 | command='${PYTHON} ${SRC[0]} > ${TGT[0]}') 10 | 11 | if bld.env['CXX']: 12 | obj = bld(features=['cxx', 'cxxshlib', 'pyext']) 13 | obj.source = [ 14 | 'c.cc', 15 | 'cmodule.cc' 16 | ] 17 | obj.target = 'c' 18 | obj.install_path = None # do not install 19 | obj.includes = '.' 20 | 21 | -------------------------------------------------------------------------------- /examples/d/d.cc: -------------------------------------------------------------------------------- 1 | #include "d.h" 2 | #include 3 | 4 | struct D *DCreate (void) 5 | { 6 | std::cout << "DCreate" << std::endl; 7 | return new D (); 8 | } 9 | void DDoA (struct D *d) 10 | { 11 | std::cout << "DDoA" << std::endl; 12 | d++; 13 | } 14 | void DDoB (struct D &d) 15 | { 16 | std::cout << "DDoB" << std::endl; 17 | d.d++; 18 | } 19 | void DDoC (const struct D &d) 20 | { 21 | std::cout << "DDoC: " << d.d << std::endl; 22 | } 23 | void DDestroy (struct D *d) 24 | { 25 | std::cout << "DDestroy" << std::endl; 26 | d++; 27 | } 28 | -------------------------------------------------------------------------------- /examples/d/d.h: -------------------------------------------------------------------------------- 1 | struct D 2 | { 3 | bool d; 4 | }; 5 | 6 | 7 | struct D *DCreate (void); 8 | void DDoA (struct D *d); 9 | void DDoB (struct D &d); 10 | void DDoC (const struct D &d); 11 | void DDestroy (struct D *d); 12 | -------------------------------------------------------------------------------- /examples/d/d_test.py: -------------------------------------------------------------------------------- 1 | import sys 2 | sys.path.insert(0, "../../build/examples/d") 3 | from d import * 4 | 5 | 6 | d = D () 7 | print d.d 8 | DDoA (d) 9 | DDoB (d) 10 | DDoC (d) 11 | 12 | -------------------------------------------------------------------------------- /examples/d/modulegen.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | import sys 4 | 5 | import pybindgen 6 | from pybindgen import ReturnValue, Parameter, Module, Function, FileCodeSink 7 | from pybindgen import CppMethod, CppConstructor, CppClass, Enum 8 | from pybindgen import cppclass 9 | 10 | def my_module_gen(out_file): 11 | 12 | mod = Module('d') 13 | mod.add_include('"d.h"') 14 | 15 | D = mod.add_class('D', memory_policy=cppclass.FreeFunctionPolicy('DDestroy')) 16 | D.add_instance_attribute('d', ReturnValue.new('bool')) 17 | D.add_function_as_constructor("DCreate", ReturnValue.new("D*", caller_owns_return=True), []) 18 | mod.add_function('DDoA', None, [Parameter.new('D*', 'd', transfer_ownership=False)]) 19 | mod.add_function('DDoB', None, [Parameter.new('D&', 'd', direction=Parameter.DIRECTION_IN)]) 20 | mod.add_function('DDoC', None, [Parameter.new('const D&', 'd', 21 | direction=Parameter.DIRECTION_IN)]) 22 | 23 | 24 | mod.generate(FileCodeSink(out_file) ) 25 | 26 | if __name__ == '__main__': 27 | my_module_gen(sys.stdout) 28 | -------------------------------------------------------------------------------- /examples/d/wscript: -------------------------------------------------------------------------------- 1 | ## -*- python -*- 2 | 3 | def build(bld): 4 | 5 | gen = bld( 6 | features='command', 7 | source='modulegen.py', 8 | target='dmodule.cc', 9 | command='${PYTHON} ${SRC[0]} > ${TGT[0]}') 10 | 11 | if bld.env['CXX']: 12 | obj = bld(features=['cxx', 'cxxshlib', 'pyext']) 13 | obj.source = [ 14 | 'd.cc', 15 | 'dmodule.cc' 16 | ] 17 | obj.target = 'd' 18 | obj.install_path = None # do not install 19 | obj.includes = '.' 20 | 21 | -------------------------------------------------------------------------------- /examples/e/e.cc: -------------------------------------------------------------------------------- 1 | #include "e.h" 2 | #include 3 | 4 | E::E () 5 | : m_count (0) 6 | { 7 | std::cout << "E::E" << std::endl; 8 | } 9 | void 10 | E::Ref (void) const 11 | { 12 | std::cout << "E::Ref" << std::endl; 13 | m_count++; 14 | } 15 | void 16 | E::Unref (void) const 17 | { 18 | std::cout << "E::Unref" << std::endl; 19 | m_count--; 20 | if (m_count == 0) 21 | { 22 | delete this; 23 | } 24 | } 25 | void 26 | E::Do (void) 27 | { 28 | std::cout << "E::Do" << std::endl; 29 | } 30 | E::~E () 31 | { 32 | std::cout << "E::~E" << std::endl; 33 | } 34 | 35 | E * 36 | E::CreateWithoutRef (void) 37 | { 38 | std::cout << "E::CreateWithoutRef" << std::endl; 39 | return new E (); 40 | } 41 | 42 | E * 43 | E::CreateWithRef (void) 44 | { 45 | std::cout << "E::CreateWithRef" << std::endl; 46 | E *e = new E (); 47 | e->Ref (); 48 | return e; 49 | } 50 | -------------------------------------------------------------------------------- /examples/e/e.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | class E 4 | { 5 | public: 6 | void Ref (void) const; 7 | void Unref (void) const; 8 | void Do (void); 9 | 10 | static E *CreateWithoutRef (void); 11 | static E *CreateWithRef (void); 12 | private: 13 | E (); 14 | ~E (); 15 | mutable uint32_t m_count; 16 | }; 17 | -------------------------------------------------------------------------------- /examples/e/e_test.py: -------------------------------------------------------------------------------- 1 | import sys 2 | sys.path.insert(0, "../../build/examples/e") 3 | from e import * 4 | 5 | e = E () 6 | e.Do () 7 | 8 | -------------------------------------------------------------------------------- /examples/e/modulegen.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | import sys 4 | 5 | import pybindgen 6 | from pybindgen import ReturnValue, Parameter, Module, Function, FileCodeSink 7 | from pybindgen import CppMethod, CppConstructor, CppClass, Enum 8 | from pybindgen import cppclass 9 | 10 | def my_module_gen(out_file): 11 | 12 | mod = Module('e') 13 | mod.add_include('"e.h"') 14 | 15 | E = mod.add_class('E', memory_policy=cppclass.ReferenceCountingMethodsPolicy(decref_method='Unref', incref_method='Ref')) 16 | if 1: 17 | E.add_function_as_constructor("E::CreateWithRef", ReturnValue.new("E*", caller_owns_return=True), []) 18 | else: 19 | ## alternative: 20 | E.add_function_as_constructor("E::CreateWithoutRef", ReturnValue.new("E*", caller_owns_return=False), []) 21 | E.add_method("Do", None, []) 22 | 23 | 24 | mod.generate(FileCodeSink(out_file) ) 25 | 26 | if __name__ == '__main__': 27 | my_module_gen(sys.stdout) 28 | -------------------------------------------------------------------------------- /examples/e/wscript: -------------------------------------------------------------------------------- 1 | ## -*- python -*- 2 | 3 | def build(bld): 4 | 5 | gen = bld( 6 | features='command', 7 | source='modulegen.py', 8 | target='emodule.cc', 9 | command='${PYTHON} ${SRC[0]} > ${TGT[0]}') 10 | 11 | if bld.env['CXX']: 12 | obj = bld(features=['cxx', 'cxxshlib', 'pyext']) 13 | obj.source = [ 14 | 'e.cc', 15 | 'emodule.cc' 16 | ] 17 | obj.target = 'e' 18 | obj.install_path = None # do not install 19 | obj.includes = '.' 20 | 21 | -------------------------------------------------------------------------------- /examples/f/f.cc: -------------------------------------------------------------------------------- 1 | #include "f.h" 2 | #include 3 | 4 | FBase::~FBase () 5 | {} 6 | void 7 | FBase::DoB (void) 8 | { 9 | std::cout << "FBase::DoB" << std::endl; 10 | PrivDoB (); 11 | } 12 | -------------------------------------------------------------------------------- /examples/f/f.h: -------------------------------------------------------------------------------- 1 | class FBase 2 | { 3 | public: 4 | virtual ~FBase (); 5 | virtual void DoA (void) = 0; 6 | void DoB (void); 7 | private: 8 | virtual void PrivDoB (void) = 0; 9 | }; 10 | -------------------------------------------------------------------------------- /examples/f/f_test.py: -------------------------------------------------------------------------------- 1 | import sys 2 | sys.path.insert(0, "../../build/examples/f") 3 | from f import * 4 | 5 | 6 | class FDerived(FBase): 7 | def DoA (self): 8 | print "FDerived::DoA" 9 | def PrivDoB (self): 10 | print "FDerived::PrivDoB" 11 | 12 | f = FDerived () 13 | f.DoA () 14 | f.DoB () 15 | 16 | -------------------------------------------------------------------------------- /examples/f/modulegen.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | import sys 4 | 5 | import pybindgen 6 | from pybindgen import ReturnValue, Parameter, Module, Function, FileCodeSink 7 | from pybindgen import CppMethod, CppConstructor, CppClass, Enum 8 | 9 | import pybindgen.settings 10 | pybindgen.settings.deprecated_virtuals = False 11 | 12 | 13 | def my_module_gen(out_file): 14 | mod = Module('f') 15 | mod.add_include('"f.h"') 16 | 17 | FBase = mod.add_class('FBase', allow_subclassing=True) 18 | 19 | FBase.add_constructor([]) 20 | FBase.add_method('DoA', None, [], is_virtual=True, is_pure_virtual=True) 21 | FBase.add_method('PrivDoB', None, [], is_virtual=True, is_pure_virtual=True, visibility='private') 22 | FBase.add_method('DoB', None, []) 23 | 24 | mod.generate(FileCodeSink(out_file) ) 25 | 26 | if __name__ == '__main__': 27 | my_module_gen(sys.stdout) 28 | -------------------------------------------------------------------------------- /examples/f/wscript: -------------------------------------------------------------------------------- 1 | ## -*- python -*- 2 | 3 | def build(bld): 4 | 5 | gen = bld( 6 | features='command', 7 | source='modulegen.py', 8 | target='fmodule.cc', 9 | command='${PYTHON} ${SRC[0]} > ${TGT[0]}') 10 | 11 | if bld.env['CXX']: 12 | obj = bld(features=['cxx', 'cxxshlib', 'pyext']) 13 | obj.source = [ 14 | 'f.cc', 15 | 'fmodule.cc' 16 | ] 17 | obj.target = 'f' 18 | obj.install_path = None # do not install 19 | obj.includes = '.' 20 | 21 | -------------------------------------------------------------------------------- /examples/g/g.cc: -------------------------------------------------------------------------------- 1 | #include "g.h" 2 | 3 | #include 4 | 5 | void GDoA (void) 6 | { 7 | std::cout << "GDoA" << std::endl; 8 | } 9 | 10 | void G::GDoB (void) 11 | { 12 | std::cout << "G::GDoB" << std::endl; 13 | } 14 | 15 | void G::GInner::GDoC (void) 16 | { 17 | std::cout << "G::Inner::GDoC" << std::endl; 18 | } 19 | 20 | -------------------------------------------------------------------------------- /examples/g/g.h: -------------------------------------------------------------------------------- 1 | 2 | void GDoA (void); 3 | 4 | namespace G 5 | { 6 | 7 | void GDoB (void); 8 | 9 | namespace GInner { 10 | 11 | void GDoC (void); 12 | 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /examples/g/g_test.py: -------------------------------------------------------------------------------- 1 | import sys 2 | sys.path.insert(0, "../../build/examples/g") 3 | from g import * 4 | from g.G import GDoB 5 | from g.G.GInner import GDoC 6 | 7 | GDoA() 8 | G.GDoB() 9 | GDoB() 10 | G.GInner.GDoC() 11 | GDoC() 12 | 13 | -------------------------------------------------------------------------------- /examples/g/modulegen.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | import sys 4 | 5 | import pybindgen 6 | from pybindgen import ReturnValue, Parameter, Module, Function, FileCodeSink 7 | 8 | def my_module_gen(out_file): 9 | mod = Module('g') 10 | mod.add_include('"g.h"') 11 | 12 | mod.add_function('GDoA', None, []) 13 | G = mod.add_cpp_namespace("G") 14 | G.add_function('GDoB', None, []) 15 | GInner = G.add_cpp_namespace("GInner") 16 | GInner.add_function('GDoC', None, []) 17 | 18 | G.add_include('') 19 | 20 | ofstream = G.add_class('ofstream', foreign_cpp_namespace='::std') 21 | ofstream.add_enum('openmode', [ 22 | ('app', 'std::ios_base::app'), 23 | ('ate', 'std::ios_base::ate'), 24 | ('binary', 'std::ios_base::binary'), 25 | ('in', 'std::ios_base::in'), 26 | ('out', 'std::ios_base::out'), 27 | ('trunc', 'std::ios_base::trunc'), 28 | ]) 29 | ofstream.add_constructor([Parameter.new("const char *", 'filename'), 30 | Parameter.new("::std::ofstream::openmode", 'mode', default_value="std::ios_base::out")]) 31 | ofstream.add_method('close', None, []) 32 | 33 | mod.generate(FileCodeSink(out_file)) 34 | 35 | if __name__ == '__main__': 36 | my_module_gen(sys.stdout) 37 | -------------------------------------------------------------------------------- /examples/g/wscript: -------------------------------------------------------------------------------- 1 | ## -*- python -*- 2 | 3 | def build(bld): 4 | 5 | gen = bld( 6 | features='command', 7 | source='modulegen.py', 8 | target='gmodule.cc', 9 | command='${PYTHON} ${SRC[0]} > ${TGT[0]}') 10 | 11 | if bld.env['CXX']: 12 | obj = bld(features=['cxx', 'cxxshlib', 'pyext']) 13 | obj.source = [ 14 | 'g.cc', 15 | 'gmodule.cc' 16 | ] 17 | obj.target = 'g' 18 | obj.install_path = None # do not install 19 | obj.includes = '.' 20 | 21 | -------------------------------------------------------------------------------- /examples/h/h.cc: -------------------------------------------------------------------------------- 1 | #include "h.h" 2 | 3 | #include 4 | 5 | void H::Do (void) 6 | { 7 | std::cout << "H::Do" << std::endl; 8 | } 9 | 10 | void H::Inner::Do (void) 11 | { 12 | std::cout << "H::Inner::Do" << std::endl; 13 | } 14 | 15 | void H::Inner::MostInner::Do (void) 16 | { 17 | std::cout << "H::Inner::MostInner::Do" << std::endl; 18 | } 19 | 20 | -------------------------------------------------------------------------------- /examples/h/h.h: -------------------------------------------------------------------------------- 1 | 2 | class H 3 | { 4 | public: 5 | void Do (void); 6 | class Inner 7 | { 8 | public: 9 | void Do (void); 10 | 11 | class MostInner 12 | { 13 | public: 14 | void Do (void); 15 | }; 16 | }; 17 | }; 18 | -------------------------------------------------------------------------------- /examples/h/h_test.py: -------------------------------------------------------------------------------- 1 | import sys 2 | sys.path.insert(0, "../../build/examples/h") 3 | from h import * 4 | 5 | h = H() 6 | h.Do() 7 | inner = H.Inner() 8 | inner.Do() 9 | most_inner = H.Inner.MostInner() 10 | most_inner.Do() 11 | 12 | -------------------------------------------------------------------------------- /examples/h/modulegen.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | import sys 4 | 5 | import pybindgen 6 | from pybindgen import ReturnValue, Parameter, Module, CppClass, CppMethod, CppConstructor, FileCodeSink 7 | 8 | def my_module_gen(out_file): 9 | 10 | mod = Module('h') 11 | mod.add_include('"h.h"') 12 | 13 | H = mod.add_class('H') 14 | H.add_constructor([]) 15 | H.add_method('Do', None, []) 16 | 17 | Inner = mod.add_class('Inner', outer_class=H) 18 | Inner.add_constructor([]) 19 | Inner.add_method('Do', None, []) 20 | 21 | MostInner = mod.add_class('MostInner', outer_class=Inner) 22 | MostInner.add_constructor([]) 23 | MostInner.add_method('Do', None, []) 24 | 25 | mod.generate(FileCodeSink(out_file)) 26 | 27 | if __name__ == '__main__': 28 | my_module_gen(sys.stdout) 29 | -------------------------------------------------------------------------------- /examples/h/wscript: -------------------------------------------------------------------------------- 1 | ## -*- python -*- 2 | 3 | def build(bld): 4 | 5 | gen = bld( 6 | features='command', 7 | source='modulegen.py', 8 | target='hmodule.cc', 9 | command='${PYTHON} ${SRC[0]} > ${TGT[0]}') 10 | 11 | if bld.env['CXX']: 12 | obj = bld(features=['cxx', 'cxxshlib', 'pyext']) 13 | obj.source = [ 14 | 'h.cc', 15 | 'hmodule.cc' 16 | ] 17 | obj.target = 'h' 18 | obj.install_path = None # do not install 19 | obj.includes = '.' 20 | 21 | -------------------------------------------------------------------------------- /examples/import_from_module/a.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | class Base { 4 | public: 5 | Base() { std::cerr << "Base::Base()" << std::endl; } 6 | virtual ~Base() { std::cerr << "Base::~Base()" << std::endl; } 7 | virtual void do_something() const { std::cerr << "Base::do_something()" << std::endl; } 8 | }; 9 | 10 | -------------------------------------------------------------------------------- /examples/import_from_module/amodulegen.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | import sys 4 | 5 | import pybindgen 6 | from pybindgen import ReturnValue, Parameter, Module, Function, FileCodeSink 7 | from pybindgen import CppMethod, CppConstructor, CppClass, Enum 8 | 9 | 10 | def my_module_gen(out_file): 11 | mod = Module('a') 12 | mod.add_include('"a.h"') 13 | 14 | # Base 15 | Base = mod.add_class("Base", allow_subclassing = True) 16 | Base.add_constructor([]) 17 | Base.add_method("do_something", None, [], is_virtual=True) 18 | 19 | mod.generate(FileCodeSink(out_file) ) 20 | 21 | if __name__ == '__main__': 22 | my_module_gen(sys.stdout) 23 | -------------------------------------------------------------------------------- /examples/import_from_module/b.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "a.h" 4 | 5 | class Derived: public Base { 6 | public: 7 | Derived(): Base() { std::cerr << "Derived::Derived()" << std::endl; } 8 | virtual ~Derived() { std::cerr << "Derived::~Derived()" << std::endl; } 9 | virtual void do_something() const { std::cerr << "Derived::do_something()" << std::endl; } 10 | }; 11 | 12 | -------------------------------------------------------------------------------- /examples/import_from_module/b_test.py: -------------------------------------------------------------------------------- 1 | import sys 2 | sys.path.insert(0, "../../build/examples/import_from_module") 3 | 4 | from b import Derived 5 | 6 | obj = Derived() 7 | obj.do_something() 8 | 9 | -------------------------------------------------------------------------------- /examples/import_from_module/bmodulegen.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | import sys 4 | 5 | import pybindgen 6 | from pybindgen import ReturnValue, Parameter, Module, Function, FileCodeSink 7 | from pybindgen import CppMethod, CppConstructor, CppClass, Enum 8 | 9 | 10 | def my_module_gen(out_file): 11 | mod = Module('b') 12 | mod.add_include('"b.h"') 13 | 14 | # Base 15 | Base = mod.add_class("Base", allow_subclassing = True, import_from_module='a') 16 | Base.add_constructor([]) 17 | Base.add_method("do_something", None, [], is_virtual=True) 18 | 19 | # Derived 20 | Derived = mod.add_class("Derived", allow_subclassing=True, parent=Base) 21 | Derived.add_constructor([]) 22 | Derived.add_method("do_something", None, [], is_virtual=True) 23 | 24 | mod.generate(FileCodeSink(out_file) ) 25 | 26 | if __name__ == '__main__': 27 | my_module_gen(sys.stdout) 28 | -------------------------------------------------------------------------------- /examples/import_from_module/wscript: -------------------------------------------------------------------------------- 1 | ## -*- python -*- 2 | 3 | def build(bld): 4 | 5 | # ---- Module A ---- 6 | 7 | gen = bld( 8 | features='command', 9 | source='amodulegen.py', 10 | target='amodule.cc', 11 | command='${PYTHON} ${SRC[0]} > ${TGT[0]}') 12 | 13 | if bld.env['CXX']: 14 | obj = bld(features=['cxx', 'cxxshlib', 'pyext']) 15 | obj.source = [ 16 | 'amodule.cc' 17 | ] 18 | obj.target = 'a' 19 | obj.install_path = None # do not install 20 | obj.includes = '.' 21 | 22 | # ---- Module B ---- 23 | 24 | gen = bld( 25 | features='command', 26 | source='bmodulegen.py', 27 | target='bmodule.cc', 28 | command='${PYTHON} ${SRC[0]} > ${TGT[0]}') 29 | 30 | if bld.env['CXX']: 31 | obj = bld(features=['cxx', 'cxxshlib', 'pyext']) 32 | obj.source = [ 33 | 'bmodule.cc' 34 | ] 35 | obj.target = 'b' 36 | obj.install_path = None # do not install 37 | obj.includes = '.' 38 | 39 | -------------------------------------------------------------------------------- /examples/std_shared_ptr/modulegen.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | import sys, os 4 | sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), 5 | '..', '..')) 6 | 7 | #import pybindgen 8 | #import pybindgen.utils 9 | #from pybindgen.typehandlers import base as typehandlers 10 | from pybindgen import Module, FileCodeSink, param, retval 11 | #from pybindgen import CppMethod, CppConstructor, CppClass, Enum 12 | #from pybindgen.function import CustomFunctionWrapper 13 | #from pybindgen.cppmethod import CustomCppMethodWrapper 14 | from pybindgen import cppclass 15 | from pybindgen.typehandlers.smart_ptr import StdSharedPtr 16 | 17 | #from pybindgen import param, retval 18 | 19 | import pybindgen.settings 20 | pybindgen.settings.deprecated_virtuals = False 21 | 22 | 23 | def my_module_gen(out_file): 24 | 25 | mod = Module('sp') 26 | 27 | mod.add_include ('"sp.h"') 28 | 29 | Foo = mod.add_class('Foo', memory_policy=StdSharedPtr('::Foo')) 30 | 31 | Foo.add_constructor([param('std::string', 'datum')]) 32 | Foo.add_constructor([]) 33 | Foo.add_method('get_datum', retval('const std::string'), []) 34 | Foo.add_method('set_datum', None, [param('const std::string', 'datum')]) 35 | 36 | 37 | mod.add_function('function_that_takes_foo', None, 38 | [param('std::shared_ptr', 'foo')]) 39 | 40 | mod.add_function('function_that_returns_foo', retval('std::shared_ptr'), []) 41 | 42 | ## ---- finally, generate the whole thing ---- 43 | mod.generate(FileCodeSink(out_file)) 44 | 45 | 46 | if __name__ == '__main__': 47 | my_module_gen(sys.stdout) 48 | 49 | -------------------------------------------------------------------------------- /examples/std_shared_ptr/sp.cc: -------------------------------------------------------------------------------- 1 | #include "sp.h" 2 | 3 | std::shared_ptr g_foo; 4 | 5 | void function_that_takes_foo(std::shared_ptr foo) 6 | { 7 | g_foo = foo; 8 | } 9 | 10 | std::shared_ptr function_that_returns_foo() 11 | { 12 | return g_foo; 13 | } 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /examples/std_shared_ptr/sp.h: -------------------------------------------------------------------------------- 1 | // -*- Mode: C++; c-file-style: "stroustrup"; indent-tabs-mode:nil; -*- 2 | #ifndef SP_H_ 3 | # define SP_H_ 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | 10 | class Foo 11 | { 12 | std::string m_datum; 13 | public: 14 | 15 | Foo () : m_datum ("") { 16 | std::cout << "Created empty foo" << std::endl; 17 | } 18 | 19 | Foo (std::string const &datum) : m_datum (datum) { 20 | std::cout << "Created foo with datum " << datum << std::endl; 21 | } 22 | 23 | const std::string get_datum () const { return m_datum; } 24 | 25 | void set_datum (std::string const &datum) { m_datum = datum; } 26 | 27 | virtual ~Foo() { 28 | std::cout << "Destroyed foo with datum " << m_datum << std::endl; 29 | } 30 | 31 | }; 32 | 33 | void function_that_takes_foo (std::shared_ptr foo); 34 | std::shared_ptr function_that_returns_foo (); 35 | 36 | #endif /* !FOO_H_ */ 37 | -------------------------------------------------------------------------------- /examples/std_shared_ptr/sp_test.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os.path 3 | sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), 4 | '..', '..', 'build', 'examples', 'std_shared_ptr')) 5 | 6 | import sp 7 | 8 | def factory(): 9 | return sp.Foo('factory') 10 | 11 | def use(): 12 | a = factory() 13 | print a.get_datum() 14 | 15 | use() 16 | 17 | f = sp.Foo("hello123") 18 | sp.function_that_takes_foo(f) 19 | f1 = sp.function_that_returns_foo() 20 | print f1.get_datum() 21 | f.set_datum("xxxx") 22 | print f1.get_datum() 23 | 24 | -------------------------------------------------------------------------------- /examples/std_shared_ptr/wscript: -------------------------------------------------------------------------------- 1 | ## -*- python -*- 2 | 3 | def build(bld): 4 | 5 | gen = bld( 6 | features='command', 7 | source='modulegen.py', 8 | target='spmodule.cc', 9 | command='${PYTHON} ${SRC[0]} > ${TGT[0]}') 10 | 11 | if bld.env['CXX']: 12 | # TODO() ADD -std=c++11 flag so that 13 | # contains std::shared_ptr 14 | obj = bld(features=['cxx', 'cxxshlib', 'pyext']) 15 | obj.env.append_value("CXXFLAGS", "-std=c++11") 16 | obj.source = [ 17 | 'sp.cc', 18 | 'spmodule.cc' 19 | ] 20 | obj.target = 'sp' 21 | obj.install_path = None # do not install 22 | obj.includes = '.' 23 | 24 | -------------------------------------------------------------------------------- /examples/wscript: -------------------------------------------------------------------------------- 1 | ## -*- python -*- 2 | 3 | def options(opt): 4 | pass#opt.tool_options('boost') 5 | 6 | def build(bld): 7 | bld.recurse('a b c d e f g h') 8 | bld.recurse('callback') 9 | #bld.recurse('buffer') # doesn't work on python3 10 | if bld.env['ENABLE_BOOST_SHARED_PTR']: 11 | bld.recurse('boost_shared_ptr') 12 | bld.recurse('import_from_module') 13 | 14 | if bld.env["ENABLE_CXX11"]: 15 | bld.recurse('std_shared_ptr') 16 | 17 | def configure(conf): 18 | if conf.check_compilation_flag('-std=c++11'): 19 | conf.env["ENABLE_CXX11"] = True 20 | -------------------------------------------------------------------------------- /generate-ChangeLog: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | ChangeLog=$(dirname $0)/ChangeLog 4 | 5 | chmod u+w $ChangeLog 2> /dev/null 6 | git log > $ChangeLog 7 | chmod a-w $ChangeLog 8 | -------------------------------------------------------------------------------- /pybindgen/__init__.py: -------------------------------------------------------------------------------- 1 | from pybindgen.typehandlers.base import ReturnValue, Parameter 2 | from pybindgen.module import Module 3 | from pybindgen.function import Function 4 | from pybindgen.typehandlers.codesink import CodeSink, FileCodeSink 5 | from pybindgen.cppclass import CppMethod, CppClass, CppConstructor 6 | from pybindgen.enum import Enum 7 | from pybindgen.utils import write_preamble, param, retval 8 | try: 9 | from pybindgen.version import version as __version__ 10 | except ImportError: # the version.py file is generated and may not exist 11 | pass 12 | -------------------------------------------------------------------------------- /pybindgen/converter_functions.py: -------------------------------------------------------------------------------- 1 | """ 2 | Generates simple converter functions that convert a single value from 3 | python to C or C to python. These can be useful in certain 4 | specialized contexts, such as converting list elements. 5 | """ 6 | 7 | from pybindgen.typehandlers.base import ReverseWrapperBase, ForwardWrapperBase 8 | from pybindgen.typehandlers import ctypeparser 9 | 10 | class PythonToCConverter(ReverseWrapperBase): 11 | ''' 12 | Utility function that converts a single Python object into a C 13 | value. The generated function can be used as a 'converter 14 | function' with the O& converter of PyArg_ParseTuple*. 15 | ''' 16 | NO_GIL_LOCKING = True 17 | 18 | def __init__(self, value_type, c_function_name): 19 | """ 20 | value_type -- a ReturnValue object handling the value type; 21 | class_ -- the class (CppClass object) 22 | attribute_name -- name of attribute 23 | getter -- None, or name of a method of the class used to get the value 24 | """ 25 | self.c_function_name = c_function_name 26 | 27 | if value_type.type_traits.type_is_reference: 28 | value_type.type_traits = ctypeparser.TypeTraits(str(value_type.type_traits.target)) 29 | value_type.ctype = str(value_type.ctype) 30 | 31 | self.type_no_ref = str(value_type.type_traits.ctype_no_modifiers) 32 | super(PythonToCConverter, self).__init__(value_type, [], error_return="return 0;") 33 | 34 | def generate_python_call(self): 35 | pass 36 | 37 | def generate(self, code_sink, wrapper_name, dummy_decl_modifiers=('static',), 38 | dummy_decl_post_modifiers=()): 39 | """ 40 | code_sink -- a CodeSink instance that will receive the generated code 41 | """ 42 | 43 | self.declarations.declare_variable('PyObject*', 'py_retval') 44 | self.before_call.write_code( 45 | 'py_retval = Py_BuildValue((char *) "(O)", value);') 46 | self.before_call.add_cleanup_code('Py_DECREF(py_retval);') 47 | 48 | save_return_value_value = self.return_value.value 49 | save_return_value_REQUIRES_ASSIGNMENT_CONSTRUCTOR = self.return_value.REQUIRES_ASSIGNMENT_CONSTRUCTOR 50 | self.return_value.value = "*address" 51 | self.return_value.REQUIRES_ASSIGNMENT_CONSTRUCTOR = False 52 | try: 53 | self.return_value.convert_python_to_c(self) 54 | finally: 55 | self.return_value.value = save_return_value_value 56 | self.return_value.REQUIRES_ASSIGNMENT_CONSTRUCTOR = save_return_value_REQUIRES_ASSIGNMENT_CONSTRUCTOR 57 | 58 | parse_tuple_params = ['py_retval'] 59 | params = self.parse_params.get_parameters() 60 | assert params[0][0] == '"' 61 | params[0] = '(char *) ' + params[0] 62 | parse_tuple_params.extend(params) 63 | self.before_call.write_error_check('!PyArg_ParseTuple(%s)' % 64 | (', '.join(parse_tuple_params),)) 65 | 66 | ## cleanup and return 67 | self.after_call.write_cleanup() 68 | self.after_call.write_code('return 1;') 69 | 70 | ## now generate the function itself 71 | code_sink.writeln("int %s(PyObject *value, %s *address)" 72 | % (wrapper_name, self.type_no_ref)) 73 | code_sink.writeln('{') 74 | code_sink.indent() 75 | 76 | self.declarations.get_code_sink().flush_to(code_sink) 77 | code_sink.writeln() 78 | self.before_call.sink.flush_to(code_sink) 79 | self.after_call.sink.flush_to(code_sink) 80 | 81 | code_sink.unindent() 82 | code_sink.writeln('}') 83 | 84 | def get_prototype(self): 85 | return "int %s(PyObject *value, %s *address)" % (self.c_function_name, self.type_no_ref) 86 | 87 | 88 | 89 | class CToPythonConverter(ForwardWrapperBase): 90 | ''' 91 | Utility function that converts a C value to a PyObject*. 92 | ''' 93 | 94 | def __init__(self, value_type, c_function_name): 95 | """ 96 | value_type -- a ReturnValue object handling the value type; 97 | class_ -- the class (CppClass object) 98 | attribute_name -- name of attribute 99 | getter -- None, or name of a method of the class used to get the value 100 | """ 101 | super(CToPythonConverter, self).__init__(value_type, [], parse_error_return="return 0;", error_return="return 0;", 102 | no_c_retval=True) 103 | self.c_function_name = c_function_name 104 | self.unblock_threads = False 105 | 106 | def generate(self, code_sink): 107 | 108 | save_return_value_value = self.return_value.value 109 | self.return_value.value = "*cvalue" 110 | try: 111 | self.return_value.convert_c_to_python(self) 112 | finally: 113 | self.return_value.value = save_return_value_value 114 | 115 | code_sink.writeln(self.get_prototype()) 116 | code_sink.writeln("{") 117 | code_sink.indent() 118 | 119 | 120 | params = self.build_params.get_parameters() 121 | if params: 122 | if params == ['""']: 123 | self.after_call.write_code('Py_INCREF(Py_None);') 124 | self.after_call.write_code('py_retval = Py_None;') 125 | else: 126 | assert params[0][0] == '"' 127 | params[0] = "(char *) " + params[0] 128 | self.after_call.write_code('py_retval = Py_BuildValue(%s);' % 129 | (', '.join(params),)) 130 | 131 | ## cleanup and return 132 | self.after_call.write_cleanup() 133 | self.after_call.write_code('return py_retval;') 134 | 135 | self.declarations.get_code_sink().flush_to(code_sink) 136 | code_sink.writeln() 137 | self.before_parse.sink.flush_to(code_sink) 138 | self.before_call.sink.flush_to(code_sink) 139 | self.after_call.sink.flush_to(code_sink) 140 | code_sink.unindent() 141 | code_sink.writeln("}") 142 | 143 | def get_prototype(self): 144 | return "PyObject* %s(%s *cvalue)" % (self.c_function_name, self.return_value.ctype) 145 | -------------------------------------------------------------------------------- /pybindgen/cppcustomattribute.py: -------------------------------------------------------------------------------- 1 | from .cppattribute import PyGetter, PySetter 2 | from .typehandlers import codesink 3 | from . import settings 4 | from . import utils 5 | 6 | class CppCustomInstanceAttributeGetter(PyGetter): 7 | ''' 8 | A getter for a C++ instance attribute. 9 | ''' 10 | def __init__(self, value_type, class_, attribute_name, getter, template_parameters = []): 11 | """ 12 | :param value_type: a ReturnValue object handling the value type; 13 | :param class_: the class (CppClass object) 14 | :param attribute_name: name of attribute 15 | :param getter: None, or name of a method of the class used to get the value 16 | """ 17 | super(CppCustomInstanceAttributeGetter, self).__init__( 18 | value_type, [], "return NULL;", "return NULL;", no_c_retval=True) 19 | self.class_ = class_ 20 | self.attribute_name = attribute_name 21 | self.getter = getter 22 | self.c_function_name = "_wrap_%s__get_%s" % (self.class_.pystruct, 23 | self.attribute_name) 24 | if template_parameters == []: 25 | value_type.value = "%s(*((%s *)self)->obj)" % (self.getter, self.class_.pystruct) 26 | else: 27 | value_type.value = "%s<%s" % (self.getter, template_parameters[0]) 28 | if len(template_parameters) > 1: 29 | for x in template_parameters[1:]: 30 | value_type.value += ", %s " % x 31 | value_type.value += ">(*((%s *)self)->obj)" % self.class_.pystruct 32 | 33 | def generate_call(self): 34 | "virtual method implementation; do not call" 35 | pass 36 | 37 | def generate(self, code_sink): 38 | """ 39 | :param code_sink: a CodeSink instance that will receive the generated code 40 | """ 41 | tmp_sink = codesink.MemoryCodeSink() 42 | self.generate_body(tmp_sink) 43 | code_sink.writeln("static PyObject* %s(%s *self, void * PYBINDGEN_UNUSED(closure))" 44 | % (self.c_function_name, self.class_.pystruct)) 45 | code_sink.writeln('{') 46 | code_sink.indent() 47 | tmp_sink.flush_to(code_sink) 48 | code_sink.unindent() 49 | code_sink.writeln('}') 50 | 51 | class CppCustomInstanceAttributeSetter(PySetter): 52 | ''' 53 | A setter for a C++ instance attribute. 54 | ''' 55 | def __init__(self, value_type, class_, attribute_name, setter=None, 56 | template_parameters = []): 57 | """ 58 | :param value_type: a ReturnValue object handling the value type; 59 | :param class_: the class (CppClass object) 60 | :param attribute_name: name of attribute 61 | :param setter: None, or name of a method of the class used to set the value 62 | """ 63 | super(CppCustomInstanceAttributeSetter, self).__init__( 64 | value_type, [], "return -1;") 65 | self.class_ = class_ 66 | self.attribute_name = attribute_name 67 | self.setter = setter 68 | self.template_parameters = template_parameters 69 | self.c_function_name = "_wrap_%s__set_%s" % (self.class_.pystruct, 70 | self.attribute_name) 71 | 72 | def generate(self, code_sink): 73 | """ 74 | :param code_sink: a CodeSink instance that will receive the generated code 75 | """ 76 | 77 | self.declarations.declare_variable('PyObject*', 'py_retval') 78 | self.before_call.write_code( 79 | 'py_retval = Py_BuildValue((char *) "(O)", value);') 80 | self.before_call.add_cleanup_code('Py_DECREF(py_retval);') 81 | 82 | if self.setter is not None: 83 | ## if we have a setter method, redirect the value to a temporary variable 84 | if not self.return_value.REQUIRES_ASSIGNMENT_CONSTRUCTOR: 85 | value_var = self.declarations.declare_variable(self.return_value.ctype, 'tmp_value') 86 | else: 87 | value_var = self.declarations.reserve_variable('tmp_value') 88 | self.return_value.value = value_var 89 | else: 90 | ## else the value is written directly to a C++ instance attribute 91 | self.return_value.value = "self->obj->%s" % self.attribute_name 92 | self.return_value.REQUIRES_ASSIGNMENT_CONSTRUCTOR = False 93 | 94 | self.return_value.convert_python_to_c(self) 95 | 96 | parse_tuple_params = ['py_retval'] 97 | params = self.parse_params.get_parameters() 98 | assert params[0][0] == '"' 99 | params[0] = '(char *) ' + params[0] 100 | parse_tuple_params.extend(params) 101 | self.before_call.write_error_check('!PyArg_ParseTuple(%s)' % 102 | (', '.join(parse_tuple_params),)) 103 | 104 | if self.setter is not None: 105 | ## if we have a setter method, now is the time to call it 106 | if len(self.template_parameters) == 0: 107 | code = "%s(*((%s *)self)->obj, %s);" % (self.setter, self.class_.pystruct, value_var) 108 | else: 109 | code = "%s<%s" % (self.setter, self.template_parameters[0]) 110 | if len(self.template_parameters) > 1: 111 | for x in self.template_parameters[1:]: 112 | code += ", %s " % x 113 | code += ">(*((%s *)self)->obj, %s);" % (self.class_.pystruct, value_var) 114 | self.after_call.write_code(code) 115 | 116 | ## cleanup and return 117 | self.after_call.write_cleanup() 118 | self.after_call.write_code('return 0;') 119 | 120 | ## now generate the function itself 121 | code_sink.writeln("static int %s(%s *self, PyObject *value, void * PYBINDGEN_UNUSED(closure))" 122 | % (self.c_function_name, self.class_.pystruct)) 123 | code_sink.writeln('{') 124 | code_sink.indent() 125 | 126 | self.declarations.get_code_sink().flush_to(code_sink) 127 | code_sink.writeln() 128 | self.before_call.sink.flush_to(code_sink) 129 | self.after_call.sink.flush_to(code_sink) 130 | 131 | code_sink.unindent() 132 | code_sink.writeln('}') 133 | -------------------------------------------------------------------------------- /pybindgen/cppexception.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | from pybindgen import settings 4 | from pybindgen import utils 5 | 6 | 7 | class CppException(object): 8 | def __init__(self, name, parent=None, outer_class=None, custom_name=None, 9 | foreign_cpp_namespace=None, message_rvalue=None, is_standard_error=False): 10 | """ 11 | :param name: exception class name 12 | :param parent: optional parent class wrapper 13 | 14 | :param custom_name: an alternative name to give to this 15 | exception class at python-side; if omitted, the name of 16 | the class in the python module will be the same name as 17 | the class in C++ (minus namespace). 18 | 19 | :param is_standard_error: if True (default false), throws a 20 | standard Python Exception with the same name instead 21 | of creating anew exception. If custom_name is set, 22 | it uses the standard exception with that name instead. 23 | 24 | :param foreign_cpp_namespace: if set, the class is assumed to 25 | belong to the given C++ namespace, regardless of the 26 | C++ namespace of the python module it will be added to. 27 | For instance, this can be useful to wrap std classes, 28 | like std::ofstream, without having to create an extra 29 | python submodule. 30 | 31 | :param message_rvalue: if not None, this parameter is a string 32 | that contains an rvalue C expression that evaluates to 33 | the exception message. The Python % operator will be 34 | used to substitute %(EXC)s for the caught exception 35 | variable name. The rvalue expression must return a 36 | string of type "char const*", a pointer owned by the 37 | exception instance. 38 | """ 39 | self.name = name 40 | self.full_name = None 41 | self.parent = parent 42 | self._module = None 43 | self.outer_class = outer_class 44 | self.custom_name = custom_name 45 | self.mangled_name = None 46 | self.mangled_full_name = None 47 | self.pytypestruct = None 48 | self.foreign_cpp_namespace = foreign_cpp_namespace 49 | self.message_rvalue = message_rvalue 50 | self.is_standard_error = is_standard_error 51 | 52 | 53 | def __repr__(self): 54 | return "" % self.full_name 55 | 56 | def write_convert_to_python(self, code_block, variable_name): 57 | if self.message_rvalue is None: 58 | code_block.write_code('PyErr_SetNone((PyObject *) %s);' % self.pytypestruct) 59 | else: 60 | code_block.write_code('PyErr_SetString((PyObject *) %s, %s);' 61 | % (self.pytypestruct, (self.message_rvalue % dict(EXC=variable_name)))) 62 | 63 | def get_module(self): 64 | """Get the Module object this type belongs to""" 65 | return self._module 66 | 67 | def set_module(self, module): 68 | """Set the Module object this type belongs to""" 69 | self._module = module 70 | self._update_names() 71 | 72 | module = property(get_module, set_module) 73 | 74 | def _update_names(self): 75 | 76 | prefix = settings.name_prefix.capitalize() 77 | 78 | if self.outer_class is None: 79 | if self.foreign_cpp_namespace: 80 | self.full_name = self.foreign_cpp_namespace + '::' + self.name 81 | else: 82 | if self._module.cpp_namespace_prefix: 83 | if self._module.cpp_namespace_prefix == '::': 84 | self.full_name = '::' + self.name 85 | else: 86 | self.full_name = self._module.cpp_namespace_prefix + '::' + self.name 87 | else: 88 | self.full_name = self.name 89 | else: 90 | assert not self.foreign_cpp_namespace 91 | self.full_name = '::'.join([self.outer_class.full_name, self.name]) 92 | 93 | def make_upper(s): 94 | if s and s[0].islower(): 95 | return s[0].upper()+s[1:] 96 | else: 97 | return s 98 | 99 | def flatten(name): 100 | "make a name like::This look LikeThis" 101 | return ''.join([make_upper(utils.mangle_name(s)) for s in name.split('::')]) 102 | 103 | self.mangled_name = flatten(self.name) 104 | self.mangled_full_name = utils.mangle_name(self.full_name) 105 | 106 | if self.is_standard_error: 107 | self.pytypestruct = "PyExc_%s" % self.python_name 108 | else: 109 | self.pytypestruct = "Py%s%s_Type" % (prefix, self.mangled_full_name) 110 | 111 | def _get_python_name(self): 112 | if self.custom_name is None: 113 | class_python_name = self.name 114 | else: 115 | class_python_name = self.custom_name 116 | return class_python_name 117 | 118 | python_name = property(_get_python_name) 119 | 120 | def _get_python_full_name(self): 121 | if self.outer_class is None: 122 | mod_path = self._module.get_module_path() 123 | mod_path.append(self.python_name) 124 | return '.'.join(mod_path) 125 | else: 126 | return '%s.%s' % (self.outer_class.pytype.slots['tp_name'], self.python_name) 127 | python_full_name = property(_get_python_full_name) 128 | 129 | 130 | def generate_forward_declarations(self, code_sink, dummy_module): 131 | if self.is_standard_error: 132 | return 133 | 134 | code_sink.writeln() 135 | code_sink.writeln('extern PyTypeObject *%s;' % (self.pytypestruct,)) 136 | code_sink.writeln() 137 | 138 | 139 | def generate(self, code_sink, module, docstring=None): 140 | """Generates the class to a code sink""" 141 | 142 | # skip generation if translating to a standard Exception 143 | if self.is_standard_error: 144 | return 145 | 146 | code_sink.writeln('PyTypeObject *%s;' % (self.pytypestruct,)) 147 | ## --- register the class type in the module --- 148 | module.after_init.write_code("/* Register the '%s' exception */" % self.full_name) 149 | if self.parent is None: 150 | parent = 'NULL' 151 | else: 152 | parent = "(PyObject*) "+self.parent.pytypestruct 153 | module.after_init.write_error_check('(%s = (PyTypeObject*) PyErr_NewException((char*)"%s", %s, NULL)) == NULL' 154 | % (self.pytypestruct, self.python_full_name, parent)) 155 | if docstring: 156 | module.after_init.write_code("%s->tp_doc = (char*)\"%s\";" % (self.pytypestruct, docstring)) 157 | 158 | if self.outer_class is None: 159 | module.after_init.write_code( 160 | 'Py_INCREF((PyObject *) %s);\n' 161 | 'PyModule_AddObject(m, (char *) \"%s\", (PyObject *) %s);' % ( 162 | self.pytypestruct, self.python_name, self.pytypestruct)) 163 | else: 164 | module.after_init.write_code( 165 | 'Py_INCREF((PyObject *) %s);\n' 166 | 'PyDict_SetItemString((PyObject*) %s.tp_dict, (char *) \"%s\", (PyObject *) %s);' % ( 167 | self.pytypestruct, self.outer_class.pytypestruct, self.python_name, self.pytypestruct)) 168 | -------------------------------------------------------------------------------- /pybindgen/enum.py: -------------------------------------------------------------------------------- 1 | """ 2 | Wraps enumerations 3 | """ 4 | 5 | import sys 6 | PY3 = (sys.version_info[0] >= 3) 7 | if PY3: 8 | string_types = str, 9 | else: 10 | string_types = basestring, 11 | 12 | 13 | from pybindgen.typehandlers import inttype 14 | from pybindgen.typehandlers.base import return_type_matcher, param_type_matcher 15 | from pybindgen.cppclass import CppClass 16 | 17 | class Enum(object): 18 | """ 19 | Class that adds support for a C/C++ enum type 20 | """ 21 | def __init__(self, name, values, values_prefix='', cpp_namespace=None, outer_class=None, 22 | import_from_module=None): 23 | """ 24 | Creates a new enum wrapper, which should be added to a module with module.add_enum(). 25 | 26 | :param name: C name of the enum type 27 | :param values: a list of strings with all enumeration value names, or list of (name, C-value-expr) tuples. 28 | :param values_prefix: prefix to add to value names, or None 29 | :param cpp_namespace: optional C++ namespace identifier, or None. 30 | Note: this namespace is *in addition to* 31 | whatever namespace of the module the enum 32 | belongs to. Typically this parameter is to 33 | be used when wrapping enums declared inside 34 | C++ classes. 35 | :param import_from_module: if not None, the enum is defined in 36 | another module, this parameter gives the name of the module 37 | """ 38 | assert isinstance(name, string_types) 39 | assert '::' not in name 40 | assert outer_class is None or isinstance(outer_class, CppClass) 41 | self.outer_class = outer_class 42 | for val in values: 43 | if not isinstance(val, string_types + (tuple,)): 44 | raise TypeError 45 | 46 | #if not name: 47 | # raise ValueError 48 | self.name = name 49 | self.full_name = None 50 | self.values = list(values) 51 | self.values_prefix = values_prefix 52 | self.cpp_namespace = cpp_namespace 53 | self._module = None 54 | self.ThisEnumParameter = None 55 | self.ThisEnumReturn = None 56 | self.import_from_module = import_from_module 57 | 58 | def get_module(self): 59 | """Get the Module object this class belongs to""" 60 | return self._module 61 | 62 | def set_module(self, module): 63 | """Set the Module object this class belongs to; can only be set once""" 64 | assert self._module is None 65 | self._module = module 66 | 67 | if not self.name: 68 | return 69 | 70 | if self.outer_class is None: 71 | if self._module.cpp_namespace_prefix: 72 | if self._module.cpp_namespace_prefix == '::': 73 | self.full_name = '::' + self.name 74 | else: 75 | self.full_name = self._module.cpp_namespace_prefix + '::' + self.name 76 | else: 77 | self.full_name = self.name 78 | else: 79 | self.full_name = '::'.join([self.outer_class.full_name, self.name]) 80 | 81 | ## Register type handlers for the enum type 82 | assert self.name 83 | assert self.full_name 84 | class ThisEnumParameter(inttype.IntParam): 85 | CTYPES = [] 86 | full_type_name = self.full_name 87 | def __init__(self, ctype, name, *args, **kwargs): 88 | super(ThisEnumParameter, self).__init__(self.full_type_name, name, *args, **kwargs) 89 | 90 | class ThisEnumReturn(inttype.IntReturn): 91 | CTYPES = [] 92 | full_type_name = self.full_name 93 | def __init__(self, ctype, *args, **kwargs): 94 | super(ThisEnumReturn, self).__init__(self.full_type_name, *args, **kwargs) 95 | 96 | class ThisEnumRefParameter(inttype.IntRefParam): 97 | CTYPES = [] 98 | full_type_name = self.full_name + " &" 99 | def __init__(self, ctype, name, *args, **kwargs): 100 | super(ThisEnumRefParameter, self).__init__(self.full_type_name, name, *args, **kwargs) 101 | 102 | class ThisEnumPtrParameter(inttype.IntPtrParam): 103 | CTYPES = [] 104 | full_type_name = self.full_name + " *" 105 | def __init__(self, ctype, name, *args, **kwargs): 106 | super(ThisEnumPtrParameter, self).__init__(self.full_type_name, name, *args, **kwargs) 107 | 108 | self.ThisEnumParameter = ThisEnumParameter 109 | self.ThisEnumReturn = ThisEnumReturn 110 | self.ThisEnumRefParameter = ThisEnumRefParameter 111 | self.ThisEnumPtrParameter = ThisEnumPtrParameter 112 | 113 | param_type_matcher.register(self.full_name, self.ThisEnumParameter) 114 | return_type_matcher.register(self.full_name, self.ThisEnumReturn) 115 | param_type_matcher.register(self.full_name + ' &', self.ThisEnumRefParameter) 116 | param_type_matcher.register(self.full_name + ' *', self.ThisEnumPtrParameter) 117 | 118 | if self.name != self.full_name: 119 | try: 120 | param_type_matcher.register(self.name, self.ThisEnumParameter) 121 | except ValueError: 122 | pass 123 | try: 124 | return_type_matcher.register(self.name, self.ThisEnumReturn) 125 | except ValueError: 126 | pass 127 | try: 128 | param_type_matcher.register(self.name+' &', self.ThisEnumRefParameter) 129 | except ValueError: 130 | pass 131 | try: 132 | param_type_matcher.register(self.name+' *', self.ThisEnumPtrParameter) 133 | except ValueError: 134 | pass 135 | 136 | 137 | module = property(get_module, set_module) 138 | 139 | def generate(self, unused_code_sink): 140 | if self.import_from_module: 141 | return #........ RET 142 | 143 | module = self.module 144 | if self.outer_class is None: 145 | namespace = [] 146 | if module.cpp_namespace_prefix: 147 | namespace.append(module.cpp_namespace_prefix) 148 | if self.cpp_namespace: 149 | namespace.append(self.cpp_namespace) 150 | for value in self.values: 151 | if isinstance(value, tuple): 152 | name, real_value = value 153 | module.after_init.write_code( 154 | "PyModule_AddIntConstant(m, (char *) \"%s\", %s);" % (name, real_value)) 155 | else: 156 | module.after_init.write_code( 157 | "PyModule_AddIntConstant(m, (char *) \"%s\", %s);" 158 | % (value, '::'.join(namespace + [self.values_prefix + value]))) 159 | else: 160 | module.after_init.write_code("{") 161 | module.after_init.indent() 162 | module.after_init.write_code("PyObject *tmp_value;") 163 | for value in self.values: 164 | if isinstance(value, tuple): 165 | value_name, value_str = value 166 | else: 167 | value_name = value 168 | value_str = "%s::%s" % (self.outer_class.full_name, value) 169 | module.after_init.write_code( 170 | ' // %s\n' 171 | 'tmp_value = PyLong_FromLong(%s);\n' 172 | 'PyDict_SetItemString((PyObject*) %s.tp_dict, \"%s\", tmp_value);\n' 173 | 'Py_DECREF(tmp_value);' 174 | % ( 175 | value_str, value_str, self.outer_class.pytypestruct, value_name)) 176 | module.after_init.unindent() 177 | module.after_init.write_code("}") 178 | 179 | def generate_declaration(self, sink, module): 180 | pass 181 | 182 | -------------------------------------------------------------------------------- /pybindgen/settings.py: -------------------------------------------------------------------------------- 1 | # pylint: disable-msg=W0105 2 | 3 | from pybindgen.wrapper_registry import NullWrapperRegistry, StdMapWrapperRegistry 4 | 5 | """ 6 | 7 | Global settings to the code generator. 8 | 9 | """ 10 | 11 | name_prefix = '' 12 | """ 13 | Prefix applied to global declarations, such as instance and type 14 | structures. 15 | """ 16 | 17 | automatic_type_narrowing = False 18 | """ 19 | Default value for the automatic_type_narrowing parameter of C++ classes. 20 | """ 21 | 22 | allow_subclassing = False 23 | """ 24 | Allow generated classes to be subclassed by default. 25 | """ 26 | 27 | unblock_threads = False 28 | """ 29 | Generate code to support threads. 30 | When True, by default methods/functions/constructors will unblock 31 | threads around the funcion call, i.e. allows other Python threads to 32 | run during the call. 33 | """ 34 | 35 | 36 | error_handler = None 37 | """ 38 | Custom error handling. 39 | Error handler, or None. When it is None, code generation exceptions 40 | propagate to the caller. Else it can be a 41 | :class:`pybindgen.settings.ErrorHandler` subclass instance that handles the error. 42 | """ 43 | import sys 44 | if sys.version_info[0] >= 3: 45 | min_python_version=(3, 1) 46 | else: 47 | min_python_version=(2, 3) 48 | """ 49 | Minimum python version the generated code must support. 50 | """ 51 | 52 | wrapper_registry = NullWrapperRegistry 53 | """ 54 | A :class:`WrapperRegistry` subclass to use for creating 55 | wrapper registries. A wrapper registry ensures that at most one 56 | python wrapper exists for each C/C++ object. 57 | """ 58 | 59 | deprecated_virtuals = False 60 | """ 61 | Prior to PyBindGen version 0.14, the code generated to handle C++ 62 | virtual methods required Python user code to define a _foo method in 63 | order to implement the virtual method foo. Since 0.14, PyBindGen 64 | changed so that virtual method foo is implemented in Python by 65 | defining a method foo, i.e. no underscore prefix is needed anymore. 66 | Setting deprecated_virtuals to True will force the old virtual method 67 | behaviour. But this is really deprecated; newer code should set 68 | deprecated_virtuals to False. 69 | """ 70 | 71 | 72 | gcc_rtti_abi_complete = True 73 | """ 74 | If True, and GCC >= 3 is detected at compile time, pybindgen will try 75 | to use abi::__si_class_type_info to determine the closest registered 76 | type for pointers to objects of unknown type. Notably, Mac OS X Lion 77 | has GCC > 3 but which breaks this internal API, in which case it 78 | should be disabled (set this option to False). 79 | """ 80 | 81 | def _get_deprecated_virtuals(): 82 | if deprecated_virtuals is None: 83 | import warnings 84 | warnings.warn("The option pybindgen.settings.deprecated_virtuals has not been set." 85 | " I am going to assume the value of False, change it to True if it breaks your APIs." 86 | " The option will eventually disappear (the deprecated behaviour will eventually disappear).", 87 | DeprecationWarning) 88 | return False 89 | return deprecated_virtuals 90 | 91 | 92 | class ErrorHandler(object): 93 | def handle_error(self, wrapper, exception, traceback_): 94 | """ 95 | Handles a code generation error. Should return True to tell 96 | pybindgen to ignore the error and move on to the next wrapper. 97 | Returning False will cause pybindgen to allow the exception to 98 | propagate, thus aborting the code generation procedure. 99 | """ 100 | raise NotImplementedError 101 | 102 | -------------------------------------------------------------------------------- /pybindgen/typehandlers/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | from pybindgen.typehandlers import base 3 | 4 | from pybindgen.typehandlers import voidtype 5 | from pybindgen.typehandlers import inttype 6 | from pybindgen.typehandlers import stringtype 7 | from pybindgen.typehandlers import booltype 8 | from pybindgen.typehandlers import doubletype 9 | from pybindgen.typehandlers import floattype 10 | from pybindgen.typehandlers import pyobjecttype 11 | from pybindgen.typehandlers import smart_ptr 12 | 13 | 14 | from pybindgen.typehandlers.base import add_type_alias 15 | 16 | -------------------------------------------------------------------------------- /pybindgen/typehandlers/booltype.py: -------------------------------------------------------------------------------- 1 | # docstrings not neede here (the type handler interfaces are fully 2 | # documented in base.py) pylint: disable-msg=C0111 3 | 4 | from .base import ReturnValue, Parameter, \ 5 | ReverseWrapperBase, ForwardWrapperBase 6 | 7 | 8 | class BoolParam(Parameter): 9 | 10 | DIRECTIONS = [Parameter.DIRECTION_IN] 11 | CTYPES = ['bool'] 12 | 13 | def convert_c_to_python(self, wrapper): 14 | assert isinstance(wrapper, ReverseWrapperBase) 15 | wrapper.build_params.add_parameter('N', ["PyBool_FromLong(%s)" % (self.value,)]) 16 | 17 | def convert_python_to_c(self, wrapper): 18 | assert isinstance(wrapper, ForwardWrapperBase) 19 | name = wrapper.declarations.declare_variable(self.ctype_no_const, self.name) 20 | if self.default_value is None: 21 | py_name = wrapper.declarations.declare_variable('PyObject *', 'py_'+self.name) 22 | else: 23 | py_name = wrapper.declarations.declare_variable('PyObject *', 'py_'+self.name, 'NULL') 24 | wrapper.parse_params.add_parameter('O', ['&'+py_name], self.value, optional=(self.default_value is not None)) 25 | if self.default_value: 26 | wrapper.before_call.write_code("%s = %s? (bool) PyObject_IsTrue(%s) : %s;" % (name, py_name, py_name, self.default_value)) 27 | else: 28 | wrapper.before_call.write_code("%s = (bool) PyObject_IsTrue(%s);" % (name, py_name)) 29 | wrapper.call_params.append(name) 30 | 31 | 32 | class BoolReturn(ReturnValue): 33 | 34 | CTYPES = ['bool'] 35 | 36 | def get_c_error_return(self): 37 | return "return false;" 38 | 39 | def convert_python_to_c(self, wrapper): 40 | py_name = wrapper.declarations.declare_variable('PyObject *', 'py_boolretval') 41 | wrapper.parse_params.add_parameter("O", ["&"+py_name], prepend=True) 42 | wrapper.after_call.write_code( 43 | "%s = PyObject_IsTrue(%s);" % (self.value, py_name)) 44 | 45 | def convert_c_to_python(self, wrapper): 46 | wrapper.build_params.add_parameter( 47 | "N", ["PyBool_FromLong(%s)" % self.value], prepend=True) 48 | 49 | 50 | class BoolPtrParam(Parameter): 51 | 52 | DIRECTIONS = [Parameter.DIRECTION_IN, Parameter.DIRECTION_OUT, 53 | Parameter.DIRECTION_IN|Parameter.DIRECTION_OUT] 54 | CTYPES = ['bool*'] 55 | 56 | def convert_c_to_python(self, wrapper): 57 | if self.direction & self.DIRECTION_IN: 58 | wrapper.build_params.add_parameter( 59 | 'N', ["PyBool_FromLong(*%s)" % (self.value,)]) 60 | if self.direction & self.DIRECTION_OUT: 61 | py_name = wrapper.declarations.declare_variable( 62 | 'PyObject *', 'py_'+self.name) 63 | wrapper.parse_params.add_parameter("O", ["&"+py_name], self.value) 64 | wrapper.after_call.write_code( 65 | "*%s = PyObject_IsTrue(%s);" % (self.value, py_name,)) 66 | 67 | def convert_python_to_c(self, wrapper): 68 | #assert self.ctype == 'bool*' 69 | base_ctype = self.type_traits.target or self.ctype_no_const 70 | name = wrapper.declarations.declare_variable(str(base_ctype), self.name) 71 | wrapper.call_params.append('&'+name) 72 | if self.direction & self.DIRECTION_IN: 73 | py_name = wrapper.declarations.declare_variable("PyObject*", 'py_'+self.name) 74 | wrapper.parse_params.add_parameter("O", ["&"+py_name], self.value) 75 | wrapper.before_call.write_code( 76 | "%s = PyObject_IsTrue(%s);" % (name, py_name,)) 77 | if self.direction & self.DIRECTION_OUT: 78 | wrapper.build_params.add_parameter( 79 | 'N', ["PyBool_FromLong(%s)" % name]) 80 | 81 | 82 | class BoolRefParam(Parameter): 83 | 84 | DIRECTIONS = [Parameter.DIRECTION_IN, Parameter.DIRECTION_OUT, 85 | Parameter.DIRECTION_IN|Parameter.DIRECTION_OUT] 86 | CTYPES = ['bool&'] 87 | 88 | def convert_c_to_python(self, wrapper): 89 | if self.direction & self.DIRECTION_IN: 90 | wrapper.build_params.add_parameter( 91 | 'N', ["PyBool_FromLong(%s)" % (self.value,)]) 92 | if self.direction & self.DIRECTION_OUT: 93 | py_name = wrapper.declarations.declare_variable( 94 | 'PyObject *', 'py_'+self.name) 95 | wrapper.parse_params.add_parameter("O", ["&"+py_name], self.name) 96 | wrapper.after_call.write_code( 97 | "%s = PyObject_IsTrue(%s);" % (self.value, py_name,)) 98 | 99 | def convert_python_to_c(self, wrapper): 100 | #assert self.ctype == 'bool&' 101 | name = wrapper.declarations.declare_variable("bool", self.name) 102 | wrapper.call_params.append(name) 103 | if self.direction & self.DIRECTION_IN: 104 | py_name = wrapper.declarations.declare_variable("PyObject*", 'py_'+self.name) 105 | wrapper.parse_params.add_parameter("O", ["&"+py_name], self.value) 106 | wrapper.before_call.write_code( 107 | "%s = PyObject_IsTrue(%s);" % (name, py_name,)) 108 | if self.direction & self.DIRECTION_OUT: 109 | wrapper.build_params.add_parameter( 110 | 'N', ["PyBool_FromLong(%s)" % (name,)]) 111 | -------------------------------------------------------------------------------- /pybindgen/typehandlers/codesink.py: -------------------------------------------------------------------------------- 1 | """ 2 | Objects that receive generated C/C++ code lines, reindents them, and 3 | writes them to a file, memory, or another code sink object. 4 | """ 5 | import sys 6 | PY3 = (sys.version_info[0] >= 3) 7 | 8 | if PY3: 9 | string_types = str, 10 | else: 11 | string_types = basestring, 12 | 13 | DEBUG = 0 14 | 15 | if DEBUG: 16 | import traceback 17 | import sys 18 | 19 | class CodeSink(object): 20 | """Abstract base class for code sinks""" 21 | def __init__(self): 22 | r'''Constructor 23 | 24 | >>> sink = MemoryCodeSink() 25 | >>> sink.writeln("foo();") 26 | >>> sink.writeln("if (true) {") 27 | >>> sink.indent() 28 | >>> sink.writeln("bar();") 29 | >>> sink.unindent() 30 | >>> sink.writeln("zbr();") 31 | >>> print sink.flush().rstrip() 32 | foo(); 33 | if (true) { 34 | bar(); 35 | zbr(); 36 | 37 | >>> sink = MemoryCodeSink() 38 | >>> sink.writeln("foo();") 39 | >>> sink.writeln() 40 | >>> sink.writeln("bar();") 41 | >>> print len(sink.flush().split("\n")) 42 | 4 43 | ''' 44 | self.indent_level = 0 # current indent level 45 | self.indent_stack = [] # previous indent levels 46 | if DEBUG: 47 | self._last_unindent_stack = None # for debugging 48 | 49 | def _format_code(self, code): 50 | """Utility method for subclasses to use for formatting code 51 | (splits lines and indents them)""" 52 | assert isinstance(code, string_types) 53 | l = [] 54 | for line in code.split('\n'): 55 | l.append(' '*self.indent_level + line) 56 | return l 57 | 58 | def writeln(self, line=''): 59 | """Write one or more lines of code""" 60 | raise NotImplementedError 61 | 62 | def indent(self, level=4): 63 | '''Add a certain ammount of indentation to all lines written 64 | from now on and until unindent() is called''' 65 | self.indent_stack.append(self.indent_level) 66 | self.indent_level += level 67 | 68 | def unindent(self): 69 | '''Revert indentation level to the value before last indent() call''' 70 | if DEBUG: 71 | try: 72 | self.indent_level = self.indent_stack.pop() 73 | except IndexError: 74 | if self._last_unindent_stack is not None: 75 | for line in traceback.format_list(self._last_unindent_stack): 76 | sys.stderr.write(line) 77 | raise 78 | self._last_unindent_stack = traceback.extract_stack() 79 | else: 80 | self.indent_level = self.indent_stack.pop() 81 | 82 | 83 | class FileCodeSink(CodeSink): 84 | """A code sink that writes to a file-like object""" 85 | def __init__(self, file_): 86 | """ 87 | :param file_: a file like object 88 | """ 89 | CodeSink.__init__(self) 90 | self.file = file_ 91 | 92 | def __repr__(self): 93 | return "" % (self.file.name,) 94 | 95 | def writeln(self, line=''): 96 | """Write one or more lines of code""" 97 | self.file.write('\n'.join(self._format_code(line))) 98 | self.file.write('\n') 99 | 100 | def __lt__(self, other): 101 | if isinstance(other, FileCodeSink): 102 | return self.file.name < other.file.name 103 | 104 | class MemoryCodeSink(CodeSink): 105 | """A code sink that keeps the code in memory, 106 | and can later flush the code to another code sink""" 107 | def __init__(self): 108 | "Constructor" 109 | CodeSink.__init__(self) 110 | self.lines = [] 111 | 112 | def writeln(self, line=''): 113 | """Write one or more lines of code""" 114 | self.lines.extend(self._format_code(line)) 115 | 116 | def flush_to(self, sink): 117 | """Flushes code to another code sink 118 | :param sink: another CodeSink instance 119 | """ 120 | assert isinstance(sink, CodeSink) 121 | for line in self.lines: 122 | sink.writeln(line.rstrip()) 123 | self.lines = [] 124 | 125 | def flush(self): 126 | "Flushes the code and returns the formatted output as a return value string" 127 | l = [] 128 | for line in self.lines: 129 | l.extend(self._format_code(line)) 130 | self.lines = [] 131 | return "\n".join(l) + '\n' 132 | 133 | 134 | class NullCodeSink(CodeSink): 135 | """A code sink that discards all content. Useful to 'test' if code 136 | generation would work without actually generating anything.""" 137 | 138 | def __init__(self): 139 | "Constructor" 140 | CodeSink.__init__(self) 141 | 142 | def writeln(self, line=''): 143 | """Write one or more lines of code""" 144 | pass 145 | 146 | def flush_to(self, sink): 147 | """Flushes code to another code sink 148 | :param sink: another CodeSink instance 149 | """ 150 | raise TypeError("Cannot flush a NullCodeSink; it has no content!") 151 | 152 | def flush(self): 153 | "Flushes the code and returns the formatted output as a return value string" 154 | raise TypeError("Cannot flush a NullCodeSink; it has no content!") 155 | -------------------------------------------------------------------------------- /pybindgen/typehandlers/doubletype.py: -------------------------------------------------------------------------------- 1 | # docstrings not neede here (the type handler doubleerfaces are fully 2 | # documented in base.py) pylint: disable-msg=C0111 3 | 4 | from .base import ReturnValue, Parameter, \ 5 | ReverseWrapperBase, ForwardWrapperBase 6 | 7 | class DoubleParam(Parameter): 8 | 9 | DIRECTIONS = [Parameter.DIRECTION_IN] 10 | CTYPES = ['double'] 11 | 12 | def convert_c_to_python(self, wrapper): 13 | assert isinstance(wrapper, ReverseWrapperBase) 14 | wrapper.build_params.add_parameter('d', [self.value]) 15 | 16 | def convert_python_to_c(self, wrapper): 17 | assert isinstance(wrapper, ForwardWrapperBase) 18 | name = wrapper.declarations.declare_variable(self.ctype_no_const, self.name, self.default_value) 19 | assert "const" not in self.ctype_no_const 20 | wrapper.parse_params.add_parameter('d', ['&'+name], self.value, optional=bool(self.default_value)) 21 | wrapper.call_params.append(name) 22 | 23 | 24 | class DoubleReturn(ReturnValue): 25 | 26 | CTYPES = ['double'] 27 | 28 | def get_c_error_return(self): 29 | return "return 0;" 30 | 31 | def convert_python_to_c(self, wrapper): 32 | wrapper.parse_params.add_parameter("d", ["&"+self.value], prepend=True) 33 | 34 | def convert_c_to_python(self, wrapper): 35 | wrapper.build_params.add_parameter("d", [self.value], prepend=True) 36 | 37 | 38 | class DoublePtrParam(Parameter): 39 | 40 | DIRECTIONS = [Parameter.DIRECTION_IN, Parameter.DIRECTION_OUT, 41 | Parameter.DIRECTION_IN|Parameter.DIRECTION_OUT] 42 | CTYPES = ['double*'] 43 | 44 | def convert_c_to_python(self, wrapper): 45 | if self.direction & self.DIRECTION_IN: 46 | wrapper.build_params.add_parameter('d', ['*'+self.value]) 47 | if self.direction & self.DIRECTION_OUT: 48 | wrapper.parse_params.add_parameter("d", [self.value], self.name) 49 | 50 | def convert_python_to_c(self, wrapper): 51 | base_ctype = self.type_traits.target or self.ctype_no_const 52 | name = wrapper.declarations.declare_variable(str(base_ctype), self.name + "xxxxx") 53 | wrapper.call_params.append('&'+name) 54 | if self.direction & self.DIRECTION_IN: 55 | wrapper.parse_params.add_parameter('d', ['&'+name], self.name) 56 | if self.direction & self.DIRECTION_OUT: 57 | wrapper.build_params.add_parameter("d", [name]) 58 | 59 | 60 | 61 | class DoubleRefParam(Parameter): 62 | 63 | DIRECTIONS = [Parameter.DIRECTION_IN, Parameter.DIRECTION_OUT, 64 | Parameter.DIRECTION_IN|Parameter.DIRECTION_OUT] 65 | CTYPES = ['double&'] 66 | 67 | def convert_c_to_python(self, wrapper): 68 | if self.direction & self.DIRECTION_IN: 69 | wrapper.build_params.add_parameter('d', [self.value]) 70 | if self.direction & self.DIRECTION_OUT: 71 | wrapper.parse_params.add_parameter("d", [self.value], self.name) 72 | 73 | def convert_python_to_c(self, wrapper): 74 | #assert self.ctype == 'double&' 75 | name = wrapper.declarations.declare_variable('double', self.name) 76 | wrapper.call_params.append(name) 77 | if self.direction & self.DIRECTION_IN: 78 | wrapper.parse_params.add_parameter('d', ['&'+name], self.name) 79 | if self.direction & self.DIRECTION_OUT: 80 | wrapper.build_params.add_parameter("d", [name]) 81 | -------------------------------------------------------------------------------- /pybindgen/typehandlers/floattype.py: -------------------------------------------------------------------------------- 1 | # docstrings not neede here (the type handler floaterfaces are fully 2 | # documented in base.py) pylint: disable-msg=C0111 3 | 4 | from .base import ReturnValue, Parameter, \ 5 | ReverseWrapperBase, ForwardWrapperBase 6 | from .ctypeparser import parse_type 7 | 8 | 9 | class FloatParam(Parameter): 10 | 11 | DIRECTIONS = [Parameter.DIRECTION_IN] 12 | CTYPES = ['float'] 13 | 14 | def convert_c_to_python(self, wrapper): 15 | assert isinstance(wrapper, ReverseWrapperBase) 16 | wrapper.build_params.add_parameter('f', [self.value]) 17 | 18 | def convert_python_to_c(self, wrapper): 19 | assert isinstance(wrapper, ForwardWrapperBase) 20 | name = wrapper.declarations.declare_variable(self.ctype_no_const, self.name) 21 | wrapper.parse_params.add_parameter('f', ['&'+name], self.value) 22 | wrapper.call_params.append(name) 23 | 24 | 25 | class FloatReturn(ReturnValue): 26 | 27 | CTYPES = ['float'] 28 | 29 | def get_c_error_return(self): 30 | return "return 0;" 31 | 32 | def convert_python_to_c(self, wrapper): 33 | wrapper.parse_params.add_parameter("f", ["&"+self.value], prepend=True) 34 | 35 | def convert_c_to_python(self, wrapper): 36 | wrapper.build_params.add_parameter("f", [self.value], prepend=True) 37 | 38 | 39 | class FloatPtrParam(Parameter): 40 | 41 | DIRECTIONS = [Parameter.DIRECTION_IN, Parameter.DIRECTION_OUT, 42 | Parameter.DIRECTION_IN|Parameter.DIRECTION_OUT] 43 | CTYPES = ['float*'] 44 | 45 | def __init__(self, ctype, name, direction=Parameter.DIRECTION_IN, is_const=False, default_value=None, array_length=None): 46 | super(FloatPtrParam, self).__init__(ctype, name, direction, is_const, default_value) 47 | self.array_length = array_length 48 | 49 | def convert_c_to_python(self, wrapper): 50 | if self.direction & self.DIRECTION_IN: 51 | wrapper.build_params.add_parameter('f', ['*'+self.value]) 52 | 53 | if self.direction & self.DIRECTION_OUT: 54 | wrapper.parse_params.add_parameter("f", [self.value], self.name) 55 | 56 | def convert_python_to_c(self, wrapper): 57 | #assert self.ctype == 'float*' 58 | base_ctype = self.type_traits.target or self.ctype_no_const 59 | if self.array_length is None: 60 | name = wrapper.declarations.declare_variable(str(base_ctype), self.name) 61 | wrapper.call_params.append('&'+name) 62 | if self.direction & self.DIRECTION_IN: 63 | wrapper.parse_params.add_parameter('f', ['&'+name], self.name) 64 | if self.direction & self.DIRECTION_OUT: 65 | wrapper.build_params.add_parameter("f", [name]) 66 | else: 67 | name = wrapper.declarations.declare_variable(str(base_ctype), self.name, array="[%i]" % self.array_length) 68 | py_list = wrapper.declarations.declare_variable("PyObject*", "py_list") 69 | idx = wrapper.declarations.declare_variable("int", "idx") 70 | wrapper.call_params.append(name) 71 | if self.direction & self.DIRECTION_IN: 72 | elem = wrapper.declarations.declare_variable("PyObject*", "element") 73 | wrapper.parse_params.add_parameter('O!', ['&PyList_Type', '&'+py_list], self.name) 74 | wrapper.before_call.write_error_check( 75 | 'PyList_Size(%s) != %i' % (py_list, self.array_length), 76 | 'PyErr_SetString(PyExc_TypeError, "Parameter `%s\' must be a list of %i floats");' 77 | % (self.name, self.array_length)) 78 | 79 | wrapper.before_call.write_code( 80 | "for (%s = 0; %s < %i; %s++) {" % (idx, idx, self.array_length, idx)) 81 | wrapper.before_call.indent() 82 | 83 | wrapper.before_call.write_code("%(elem)s = PyList_GET_ITEM(%(py_list)s, %(idx)s);" % vars()) 84 | wrapper.before_call.write_error_check( 85 | '!PyFloat_Check(element)', 86 | 'PyErr_SetString(PyExc_TypeError, "Parameter `%s\' must be a list of %i floats");' 87 | % (self.name, self.array_length)) 88 | wrapper.before_call.write_code("%(name)s[%(idx)s] = (float) PyFloat_AsDouble(%(elem)s);" % vars()) 89 | 90 | wrapper.before_call.unindent() 91 | wrapper.before_call.write_code('}') 92 | 93 | if self.direction & self.DIRECTION_OUT: 94 | wrapper.after_call.write_code("%s = PyList_New(%i);" % (py_list, self.array_length)) 95 | 96 | wrapper.after_call.write_code( 97 | "for (%s = 0; %s < %i; %s++) {" % (idx, idx, self.array_length, idx)) 98 | wrapper.after_call.indent() 99 | wrapper.after_call.write_code("PyList_SET_ITEM(%(py_list)s, %(idx)s, PyFloat_FromDouble(%(name)s[%(idx)s]));" % vars()) 100 | wrapper.after_call.unindent() 101 | wrapper.after_call.write_code('}') 102 | 103 | wrapper.build_params.add_parameter("N", [py_list]) 104 | 105 | 106 | class FloatRefParam(Parameter): 107 | 108 | DIRECTIONS = [Parameter.DIRECTION_IN, Parameter.DIRECTION_OUT, 109 | Parameter.DIRECTION_IN|Parameter.DIRECTION_OUT] 110 | CTYPES = ['float&'] 111 | 112 | def convert_c_to_python(self, wrapper): 113 | if self.direction & self.DIRECTION_IN: 114 | wrapper.build_params.add_parameter('f', [self.value]) 115 | if self.direction & self.DIRECTION_OUT: 116 | wrapper.parse_params.add_parameter("f", [self.value], self.name) 117 | 118 | def convert_python_to_c(self, wrapper): 119 | #assert self.ctype == 'float&' 120 | name = wrapper.declarations.declare_variable(self.ctype_no_const[:-1], self.name) 121 | wrapper.call_params.append(name) 122 | if self.direction & self.DIRECTION_IN: 123 | wrapper.parse_params.add_parameter('f', ['&'+name], self.name) 124 | if self.direction & self.DIRECTION_OUT: 125 | wrapper.build_params.add_parameter("f", [name]) 126 | -------------------------------------------------------------------------------- /pybindgen/typehandlers/pyobjecttype.py: -------------------------------------------------------------------------------- 1 | # docstrings not neede here (the type handler doubleerfaces are fully 2 | # documented in base.py) pylint: disable-msg=C0111 3 | 4 | from .base import ReturnValue, Parameter, \ 5 | ReverseWrapperBase, ForwardWrapperBase 6 | 7 | 8 | class PyObjectParam(Parameter): 9 | 10 | DIRECTIONS = [Parameter.DIRECTION_IN] 11 | CTYPES = ['PyObject*'] 12 | 13 | def __init__(self, ctype, name, transfer_ownership, is_const=False): 14 | """ 15 | :param ctype: C type, normally 'PyObject*' 16 | :param name: parameter name 17 | :param transfer_ownership: this parameter transfer the ownership of 18 | the pointed-to object to the called 19 | function 20 | """ 21 | super(PyObjectParam, self).__init__( 22 | ctype, name, direction=Parameter.DIRECTION_IN, is_const=is_const) 23 | self.transfer_ownership = transfer_ownership 24 | 25 | def convert_c_to_python(self, wrapper): 26 | assert isinstance(wrapper, ReverseWrapperBase) 27 | if self.transfer_ownership: 28 | wrapper.build_params.add_parameter('N', [self.value]) 29 | else: 30 | wrapper.build_params.add_parameter('O', [self.value]) 31 | 32 | def convert_python_to_c(self, wrapper): 33 | assert isinstance(wrapper, ForwardWrapperBase) 34 | name = wrapper.declarations.declare_variable(self.ctype_no_const, self.name) 35 | wrapper.parse_params.add_parameter('O', ['&'+name], self.name) 36 | wrapper.call_params.append(name) 37 | if self.transfer_ownership: 38 | wrapper.before_call.write_code("Py_INCREF((PyObject*) %s);" % name) 39 | 40 | 41 | class PyObjectReturnValue(ReturnValue): 42 | 43 | CTYPES = ['PyObject*'] 44 | 45 | def __init__(self, ctype, caller_owns_return, is_const=False): 46 | """ 47 | :param ctype: C type, normally 'MyClass*' 48 | :param caller_owns_return: if true, ownership of the object pointer 49 | is transferred to the caller 50 | """ 51 | super(PyObjectReturnValue, self).__init__(ctype, is_const) 52 | self.caller_owns_return = caller_owns_return 53 | 54 | def get_c_error_return(self): 55 | return "return NULL;" 56 | 57 | def convert_python_to_c(self, wrapper): 58 | wrapper.parse_params.add_parameter("O", ["&"+self.value], prepend=True) 59 | if self.caller_owns_return: 60 | wrapper.after_call.write_code("Py_INCREF((PyObject*) %s);" % self.value) 61 | 62 | def convert_c_to_python(self, wrapper): 63 | wrapper.build_params.add_parameter( 64 | (self.caller_owns_return and "N" or "O"), 65 | [self.value], prepend=True) 66 | -------------------------------------------------------------------------------- /pybindgen/typehandlers/voidtype.py: -------------------------------------------------------------------------------- 1 | # docstrings not neede here (the type handler interfaces are fully 2 | # documented in base.py) pylint: disable-msg=C0111 3 | 4 | from .base import ReturnValue 5 | 6 | 7 | class VoidReturn(ReturnValue): 8 | 9 | CTYPES = ['void'] 10 | 11 | def get_c_error_return(self): 12 | return "return;" 13 | 14 | def convert_python_to_c(self, wrapper): 15 | wrapper.parse_params.add_parameter("", [], prepend=True) 16 | 17 | def convert_c_to_python(self, wrapper): 18 | pass 19 | -------------------------------------------------------------------------------- /pybindgen/wrapper_registry.py: -------------------------------------------------------------------------------- 1 | """ 2 | The class that generates code to keep track of existing python 3 | wrappers for a given root class. 4 | """ 5 | 6 | from pybindgen.typehandlers.base import NotSupportedError 7 | 8 | 9 | class WrapperRegistry(object): 10 | """ 11 | Abstract base class for wrapepr registries. 12 | """ 13 | 14 | def __init__(self, base_name): 15 | self.base_name = base_name 16 | 17 | def generate_forward_declarations(self, code_sink, module): 18 | raise NotImplementedError 19 | 20 | def generate(self, code_sink, module, import_from_module): 21 | raise NotImplementedError 22 | 23 | def write_register_new_wrapper(self, code_block, wrapper_lvalue, object_rvalue): 24 | raise NotImplementedError 25 | 26 | def write_lookup_wrapper(self, code_block, wrapper_type, wrapper_lvalue, object_rvalue): 27 | raise NotImplementedError 28 | 29 | def write_unregister_wrapper(self, code_block, wrapper_lvalue, object_rvalue): 30 | raise NotImplementedError 31 | 32 | 33 | class NullWrapperRegistry(WrapperRegistry): 34 | """ 35 | A 'null' wrapper registry class. It produces no code, and does 36 | not guarantee that more than one wrapper cannot be created for 37 | each object. Use this class to disable wrapper registries entirely. 38 | """ 39 | 40 | def __init__(self, base_name): 41 | super(NullWrapperRegistry, self).__init__(base_name) 42 | 43 | def generate_forward_declarations(self, code_sink, module, import_from_module): 44 | pass 45 | 46 | def generate(self, code_sink, module): 47 | pass 48 | def generate_import(self, code_sink, module, import_from_module): 49 | pass 50 | 51 | def write_register_new_wrapper(self, code_block, wrapper_lvalue, object_rvalue): 52 | pass 53 | 54 | def write_lookup_wrapper(self, code_block, wrapper_type, wrapper_lvalue, object_rvalue): 55 | raise NotSupportedError 56 | 57 | def write_unregister_wrapper(self, code_block, wrapper_lvalue, object_rvalue): 58 | pass 59 | 60 | 61 | class StdMapWrapperRegistry(WrapperRegistry): 62 | """ 63 | A wrapper registry that uses std::map as implementation. Do not 64 | use this if generating pure C wrapping code, else the code will 65 | not compile. 66 | """ 67 | 68 | 69 | def __init__(self, base_name): 70 | super(StdMapWrapperRegistry, self).__init__(base_name) 71 | self.map_name = "%s_wrapper_registry" % base_name 72 | 73 | def generate_forward_declarations(self, code_sink, module, import_from_module): 74 | module.add_include("") 75 | module.add_include("") 76 | #code_sink.writeln("#include ") 77 | #code_sink.writeln("#include ") 78 | if import_from_module: 79 | code_sink.writeln("extern std::map *_%s;" % self.map_name) 80 | code_sink.writeln("#define %s (*_%s)" % (self.map_name, self.map_name)) 81 | else: 82 | code_sink.writeln("extern std::map %s;" % self.map_name) 83 | 84 | def generate(self, code_sink, module): 85 | code_sink.writeln("std::map %s;" % self.map_name) 86 | # register the map in the module namespace 87 | module.after_init.write_code("PyModule_AddObject(m, (char *) \"_%s\", PyCObject_FromVoidPtr(&%s, NULL));" 88 | % (self.map_name, self.map_name)) 89 | 90 | def generate_import(self, code_sink, code_block, module_pyobj_var): 91 | code_sink.writeln("std::map *_%s;" % self.map_name) 92 | code_block.write_code("PyObject *_cobj = PyObject_GetAttrString(%s, (char*) \"_%s\");" 93 | % (module_pyobj_var, self.map_name)) 94 | code_block.write_code("if (_cobj == NULL) {\n" 95 | " _%(MAP)s = NULL;\n" 96 | " PyErr_Clear();\n" 97 | "} else {\n" 98 | " _%(MAP)s = reinterpret_cast< std::map *> (PyCObject_AsVoidPtr (_cobj));\n" 99 | " Py_DECREF(_cobj);\n" 100 | "}" 101 | % dict(MAP=self.map_name)) 102 | 103 | def write_register_new_wrapper(self, code_block, wrapper_lvalue, object_rvalue): 104 | code_block.write_code("%s[(void *) %s] = (PyObject *) %s;" % (self.map_name, object_rvalue, wrapper_lvalue)) 105 | #code_block.write_code('std::cerr << "Register Wrapper: obj=" <<(void *) %s << ", wrapper=" << %s << std::endl;' 106 | # % (object_rvalue, wrapper_lvalue)) 107 | 108 | def write_lookup_wrapper(self, code_block, wrapper_type, wrapper_lvalue, object_rvalue): 109 | iterator = code_block.declare_variable("std::map::const_iterator", "wrapper_lookup_iter") 110 | #code_block.write_code('std::cerr << "Lookup Wrapper: obj=" <<(void *) %s << " map size: " << %s.size() << std::endl;' 111 | # % (object_rvalue, self.map_name)) 112 | code_block.write_code("%s = %s.find((void *) %s);" % (iterator, self.map_name, object_rvalue)) 113 | code_block.write_code("if (%(ITER)s == %(MAP)s.end()) {\n" 114 | " %(WRAPPER)s = NULL;\n" 115 | "} else {\n" 116 | " %(WRAPPER)s = (%(TYPE)s *) %(ITER)s->second;\n" 117 | " Py_INCREF(%(WRAPPER)s);\n" 118 | "}\n" 119 | % dict(ITER=iterator, MAP=self.map_name, WRAPPER=wrapper_lvalue, TYPE=wrapper_type)) 120 | 121 | def write_unregister_wrapper(self, code_block, wrapper_lvalue, object_rvalue): 122 | #code_block.write_code('std::cerr << "Erase Wrapper: obj=" <<(void *) %s << std::endl;' 123 | # % (object_rvalue)) 124 | iterator = code_block.declare_variable("std::map::iterator", "wrapper_lookup_iter") 125 | code_block.write_code("%(ITER)s = %(MAP)s.find((void *) %(OBJECT_VALUE)s);\n" 126 | "if (%(ITER)s != %(MAP)s.end()) {\n" 127 | " %(MAP)s.erase(%(ITER)s);\n" 128 | "}\n" 129 | % dict(ITER=iterator, MAP=self.map_name, WRAPPER=wrapper_lvalue, OBJECT_VALUE=object_rvalue)) 130 | -------------------------------------------------------------------------------- /pybindgen/wscript: -------------------------------------------------------------------------------- 1 | ## -*- python -*- 2 | 3 | def build(bld): 4 | 5 | obj = bld('py') 6 | obj.source = obj.path.ant_glob('*.py') 7 | obj.source.append('version.py') 8 | obj.install_path = '${PYTHONDIR}/pybindgen' 9 | obj.prio = 50 10 | 11 | obj = bld('py') 12 | obj.source = obj.path.ant_glob('typehandlers/*.py') 13 | obj.install_path = '${PYTHONDIR}/pybindgen/typehandlers' 14 | obj.prio = 50 15 | 16 | obj = bld('py') 17 | obj.source = obj.path.ant_glob('typehandlers/ctypeparser/*.py') 18 | obj.install_path = '${PYTHONDIR}/pybindgen/typehandlers/ctypeparser' 19 | obj.prio = 50 20 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [bdist_wheel] 2 | universal = 1 3 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from setuptools import setup 3 | 4 | with open('README.rst') as file_: 5 | LONG_DESCRIPTION = file_.read() 6 | 7 | 8 | setup(name='PyBindGen', 9 | use_scm_version={"version_scheme": "post-release", 10 | "write_to": "pybindgen/version.py"}, 11 | setup_requires=['setuptools_scm'], 12 | description='Python Bindings Generator', 13 | author='Gustavo Carneiro', 14 | author_email='gjcarneiro@gmail.com', 15 | url='https://github.com/gjcarneiro/pybindgen', 16 | packages=['pybindgen', 17 | 'pybindgen.typehandlers', 18 | 'pybindgen.typehandlers.ctypeparser', 19 | ], 20 | long_description=LONG_DESCRIPTION, 21 | classifiers=[ 22 | 'Development Status :: 4 - Beta', 23 | 'Intended Audience :: Developers', 24 | 'Topic :: Software Development :: Build Tools', 25 | 'License :: OSI Approved :: GNU Lesser General Public License v2 or later (LGPLv2+)', 26 | 'Programming Language :: Python :: 2', 27 | 'Programming Language :: Python :: 3', 28 | ], 29 | ) 30 | -------------------------------------------------------------------------------- /tests/boost/bar.cc: -------------------------------------------------------------------------------- 1 | #include "bar.h" 2 | 3 | boost::shared_ptr g_foo; 4 | 5 | void function_that_takes_foo(boost::shared_ptr foo) 6 | { 7 | g_foo = foo; 8 | } 9 | 10 | boost::shared_ptr function_that_returns_foo() 11 | { 12 | return g_foo; 13 | } 14 | 15 | int Foo::instance_count = 0; 16 | 17 | 18 | -------------------------------------------------------------------------------- /tests/boost/bar.h: -------------------------------------------------------------------------------- 1 | // -*- Mode: C++; c-file-style: "stroustrup"; indent-tabs-mode:nil; -*- 2 | #ifndef BAR_H_ 3 | # define BAR_H_ 4 | 5 | #include 6 | #include 7 | 8 | 9 | class Foo 10 | { 11 | std::string m_datum; 12 | bool m_initialized; 13 | public: 14 | static int instance_count; 15 | 16 | Foo () : m_datum (""), m_initialized (false) 17 | { Foo::instance_count++; } 18 | 19 | Foo (std::string const &datum) : m_datum (datum), m_initialized (false) 20 | { Foo::instance_count++; } 21 | const std::string get_datum () const { return m_datum; } 22 | 23 | Foo (Foo const & other) : m_datum (other.get_datum ()), m_initialized (false) 24 | { Foo::instance_count++; } 25 | 26 | void initialize () { m_initialized = true; } 27 | bool is_initialized () const { return m_initialized; } 28 | 29 | virtual ~Foo() { Foo::instance_count--; } 30 | 31 | }; 32 | 33 | inline std::ostream & operator << (std::ostream &os, Foo const &foo) 34 | { 35 | os << foo.get_datum (); 36 | return os; 37 | } 38 | 39 | 40 | void function_that_takes_foo (boost::shared_ptr foo); 41 | boost::shared_ptr function_that_returns_foo (); 42 | 43 | 44 | class ClassThatTakesFoo 45 | { 46 | boost::shared_ptr m_foo; 47 | public: 48 | ClassThatTakesFoo(boost::shared_ptr foo) : m_foo(foo) {} 49 | boost::shared_ptr get_foo () const { return m_foo; } 50 | 51 | virtual boost::shared_ptr get_modified_foo (boost::shared_ptr foo) const { return m_foo; } 52 | virtual ~ClassThatTakesFoo() {} 53 | }; 54 | 55 | 56 | #endif /* !FOO_H_ */ 57 | -------------------------------------------------------------------------------- /tests/boost/barmodulegen.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | from __future__ import unicode_literals, print_function 3 | 4 | import sys 5 | import re 6 | 7 | import pybindgen 8 | import pybindgen.utils 9 | from pybindgen.typehandlers import base as typehandlers 10 | from pybindgen.typehandlers.smart_ptr import BoostSharedPtr 11 | from pybindgen import ReturnValue, Parameter, Module, Function, FileCodeSink 12 | from pybindgen import CppMethod, CppConstructor, CppClass, Enum 13 | from pybindgen.function import CustomFunctionWrapper 14 | from pybindgen.cppmethod import CustomCppMethodWrapper 15 | from pybindgen import cppclass 16 | 17 | from pybindgen import param, retval 18 | 19 | import pybindgen.settings 20 | pybindgen.settings.deprecated_virtuals = False 21 | 22 | 23 | def my_module_gen(out_file): 24 | 25 | mod = Module('bar') 26 | 27 | mod.add_include ('"bar.h"') 28 | 29 | Foo = mod.add_class('Foo', automatic_type_narrowing=True, 30 | memory_policy=BoostSharedPtr('::Foo')) 31 | 32 | Foo.add_static_attribute('instance_count', ReturnValue.new('int')) 33 | Foo.add_constructor([Parameter.new('std::string', 'datum')]) 34 | Foo.add_constructor([]) 35 | Foo.add_method('get_datum', ReturnValue.new('const std::string'), []) 36 | Foo.add_method('is_initialized', ReturnValue.new('bool'), [], is_const=True) 37 | Foo.add_output_stream_operator() 38 | 39 | 40 | mod.add_function('function_that_takes_foo', ReturnValue.new('void'), 41 | [param('boost::shared_ptr', 'foo')]) 42 | mod.add_function('function_that_returns_foo', retval('boost::shared_ptr'), []) 43 | 44 | cls = mod.add_class('ClassThatTakesFoo', allow_subclassing=True) 45 | cls.add_constructor([Parameter.new('boost::shared_ptr', 'foo')]) 46 | cls.add_method('get_foo', ReturnValue.new('boost::shared_ptr'), []) 47 | cls.add_method('get_modified_foo', retval('boost::shared_ptr'), 48 | [param('boost::shared_ptr', 'foo')], 49 | is_virtual=True, is_const=True) 50 | 51 | 52 | 53 | #### --- error handler --- 54 | class MyErrorHandler(pybindgen.settings.ErrorHandler): 55 | def __init__(self): 56 | super(MyErrorHandler, self).__init__() 57 | self.num_errors = 0 58 | def handle_error(self, wrapper, exception, traceback_): 59 | print("exception %s in wrapper %s" % (exception, wrapper), file=sys.stderr) 60 | self.num_errors += 1 61 | if 0: # verbose? 62 | import traceback 63 | traceback.print_tb(traceback_) 64 | return True 65 | pybindgen.settings.error_handler = MyErrorHandler() 66 | 67 | ## ---- finally, generate the whole thing ---- 68 | mod.generate(FileCodeSink(out_file)) 69 | 70 | 71 | if __name__ == '__main__': 72 | import os 73 | if "PYBINDGEN_ENABLE_PROFILING" in os.environ: 74 | try: 75 | import cProfile as profile 76 | except ImportError: 77 | my_module_gen(sys.stdout) 78 | else: 79 | print("** running under profiler", file=sys.stderr) 80 | profile.run('my_module_gen(sys.stdout)', 'foomodulegen.pstat') 81 | else: 82 | my_module_gen(sys.stdout) 83 | 84 | -------------------------------------------------------------------------------- /tests/boost/bartest.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import weakref 3 | import gc 4 | import os.path 5 | import copy 6 | sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), 7 | '..', '..', 'build', 'tests', 'boost')) 8 | import bar 9 | 10 | import unittest 11 | 12 | 13 | class TestBar(unittest.TestCase): 14 | 15 | def test_basic_gc(self): 16 | count0 = bar.Foo.instance_count 17 | 18 | f = bar.Foo("hello") 19 | self.assertEqual(bar.Foo.instance_count, count0 + 1) 20 | self.assertEqual(f.get_datum(), "hello") 21 | del f 22 | while gc.collect(): 23 | pass 24 | self.assertEqual(bar.Foo.instance_count, count0) 25 | 26 | 27 | def test_function_takes_foo(self): 28 | count0 = bar.Foo.instance_count 29 | 30 | f = bar.Foo("hello123") 31 | self.assertEqual(bar.Foo.instance_count, count0 + 1) 32 | self.assertEqual(f.get_datum(), "hello123") 33 | bar.function_that_takes_foo(f) 34 | del f 35 | while gc.collect(): 36 | pass 37 | self.assertEqual(bar.Foo.instance_count, count0+1) # the object stays alive 38 | 39 | 40 | f1 = bar.function_that_returns_foo() 41 | self.assertEqual(f1.get_datum(), "hello123") 42 | 43 | self.assertEqual(bar.Foo.instance_count, count0+1) 44 | del f1 45 | while gc.collect(): 46 | pass 47 | self.assertEqual(bar.Foo.instance_count, count0+1) # the object stays alive 48 | 49 | 50 | def test_class_takes_foo(self): 51 | count0 = bar.Foo.instance_count 52 | 53 | 54 | f = bar.Foo("hello12") 55 | self.assertEqual(bar.Foo.instance_count, count0 + 1) 56 | self.assertEqual(f.get_datum(), "hello12") 57 | takes = bar.ClassThatTakesFoo(f) 58 | del f 59 | while gc.collect(): 60 | pass 61 | self.assertEqual(bar.Foo.instance_count, count0+1) # the object stays alive 62 | 63 | 64 | f1 = takes.get_foo() 65 | self.assertEqual(f1.get_datum(), "hello12") 66 | 67 | self.assertEqual(bar.Foo.instance_count, count0+1) 68 | del f1, takes 69 | while gc.collect(): 70 | pass 71 | self.assertEqual(bar.Foo.instance_count, count0) 72 | 73 | 74 | def test_class_takes_foo_subclassing(self): 75 | 76 | count0 = bar.Foo.instance_count 77 | 78 | 79 | f = bar.Foo("hello45") 80 | self.assertEqual(bar.Foo.instance_count, count0 + 1) 81 | self.assertEqual(f.get_datum(), "hello45") 82 | 83 | class Takes(bar.ClassThatTakesFoo): 84 | def get_modified_foo(self, foo): 85 | d = foo.get_datum() 86 | return bar.Foo(d+"xxx") 87 | 88 | takes = Takes(f) 89 | del f 90 | while gc.collect(): 91 | pass 92 | self.assertEqual(bar.Foo.instance_count, count0+1) 93 | 94 | 95 | f1 = takes.get_foo() 96 | self.assertEqual(f1.get_datum(), "hello45") 97 | 98 | self.assertEqual(bar.Foo.instance_count, count0+1) 99 | 100 | f2 = bar.Foo("helloyyy") 101 | self.assertEqual(bar.Foo.instance_count, count0+2) 102 | f3 = takes.get_modified_foo(f2) 103 | self.assertEqual(bar.Foo.instance_count, count0+3) 104 | self.assertEqual(f3.get_datum(), "helloyyyxxx") 105 | 106 | del f1, f2, f3, takes 107 | while gc.collect(): 108 | pass 109 | self.assertEqual(bar.Foo.instance_count, count0) 110 | 111 | 112 | if __name__ == '__main__': 113 | unittest.main() 114 | -------------------------------------------------------------------------------- /tests/boost/test.py: -------------------------------------------------------------------------------- 1 | import pybindgen.typehandlers.base as typehandlers 2 | from pybindgen.typehandlers import stringtype, ctypeparser 3 | import pybindgen.typehandlers.codesink as codesink 4 | from pybindgen import module, cppclass, overloading, utils 5 | 6 | 7 | import unittest 8 | import doctest 9 | import re 10 | 11 | 12 | class SmartPointerTransformation(typehandlers.TypeTransformation): 13 | def __init__(self): 14 | self.rx = re.compile(r'(?:::)?MySmartPointer<\s*(\w+)\s*>') 15 | 16 | def get_untransformed_name(self, name): 17 | m = self.rx.match(name) 18 | if m is None: 19 | return None 20 | else: 21 | return m.group(1)+' *' 22 | 23 | def create_type_handler(self, type_handler, *args, **kwargs): 24 | ctype = self.get_untransformed_name(args[0]) 25 | handler = type_handler(ctype, *args[1:], **kwargs) 26 | handler.has_been_transformed = True 27 | return handler 28 | 29 | 30 | typehandlers.param_type_matcher.register_transformation( 31 | SmartPointerTransformation()) 32 | 33 | class TestParam(typehandlers.Parameter): 34 | 35 | DIRECTIONS = [typehandlers.Parameter.DIRECTION_IN] 36 | CTYPES = ['testtype*'] 37 | has_been_transformed = False 38 | 39 | def convert_c_to_python(self, wrapper): 40 | assert isinstance(wrapper, typehandlers.ReverseWrapperBase) 41 | wrapper.build_params.add_parameter('i', [self.name]) 42 | 43 | def convert_python_to_c(self, wrapper): 44 | assert isinstance(wrapper, typehandlers.ForwardWrapperBase) 45 | name = wrapper.declarations.declare_variable(self.ctype, self.name) 46 | wrapper.parse_params.add_parameter('i', ['&'+name], self.name) 47 | wrapper.call_params.append(name) 48 | 49 | 50 | class ParamLookupTests(unittest.TestCase): 51 | 52 | def testLookup(self): 53 | handler = typehandlers.Parameter.new('testtype*', 'name') 54 | self.assert_(isinstance(handler, TestParam)) 55 | self.assertRaises(typehandlers.TypeLookupError, typehandlers.Parameter.new, 'non_existent_type', 'name') 56 | 57 | def testLookupTransformed(self): 58 | transformed = typehandlers.Parameter.new('MySmartPointer', 'name') 59 | self.assert_(isinstance(transformed, TestParam)) 60 | self.assert_(transformed.has_been_transformed) 61 | 62 | 63 | 64 | if __name__ == '__main__': 65 | suite = unittest.TestSuite() 66 | suite.addTest(unittest.TestLoader().loadTestsFromTestCase(ParamLookupTests)) 67 | runner = unittest.TextTestRunner() 68 | runner.run(suite) 69 | -------------------------------------------------------------------------------- /tests/boost/wscript: -------------------------------------------------------------------------------- 1 | ## -*- python -*- 2 | #from waflib import Task 3 | 4 | import sys 5 | import os.path 6 | import os 7 | import subprocess 8 | 9 | # uncomment to enable profiling information 10 | # epydoc uses the profile data to generate call graphs 11 | #os.environ["PYBINDGEN_ENABLE_PROFILING"] = "" 12 | 13 | if 0: 14 | DEPRECATION_ERRORS = '-Werror::DeprecationWarning' # deprecations become errors 15 | else: 16 | DEPRECATION_ERRORS = '-Wdefault::DeprecationWarning' # normal python behaviour 17 | 18 | 19 | def build(bld): 20 | env = bld.env 21 | 22 | env['TOP_SRCDIR'] = bld.srcnode.abspath() 23 | 24 | bindgen = bld( 25 | features='command', 26 | source='barmodulegen.py', 27 | target='barmodule.cc', 28 | command='${PYTHON} %s ${SRC[0]} ${TOP_SRCDIR} > ${TGT[0]}' % (DEPRECATION_ERRORS,)) 29 | 30 | if env['CXX'] and env['ENABLE_BOOST_SHARED_PTR'] == True: 31 | obj = bld(features='cxx cxxshlib pyext') 32 | obj.source = [ 33 | 'bar.cc', 34 | 'barmodule.cc' 35 | ] 36 | obj.target = 'bar' 37 | obj.install_path = None 38 | obj.env.append_value("INCLUDES", '.') 39 | 40 | 41 | -------------------------------------------------------------------------------- /tests/c-hello/hello.c: -------------------------------------------------------------------------------- 1 | #include "hello.h" 2 | #include 3 | #include 4 | #include 5 | 6 | Bool hello_print_message(const char *message) 7 | { 8 | printf("Hello: %s\n", message); 9 | return 0; 10 | } 11 | 12 | double hello_sum(double x, double y) 13 | { 14 | return x + y; 15 | } 16 | 17 | 18 | struct _HelloFoo 19 | { 20 | int refcount; 21 | char *data; 22 | }; 23 | 24 | HelloFoo* 25 | hello_foo_new(void) 26 | { 27 | HelloFoo *foo; 28 | foo = (HelloFoo *) malloc(sizeof(HelloFoo)); 29 | foo->refcount = 1; 30 | foo->data = NULL; 31 | return foo; 32 | } 33 | 34 | HelloFoo* 35 | hello_foo_new_from_data(const char *data) 36 | { 37 | HelloFoo* foo; 38 | 39 | foo = hello_foo_new(); 40 | hello_foo_set_data(foo, data); 41 | return foo; 42 | } 43 | 44 | HelloFoo* 45 | hello_foo_new_with_spaces (int num_spaces) 46 | { 47 | int i; 48 | HelloFoo *foo; 49 | foo = hello_foo_new(); 50 | foo->data = malloc(num_spaces + 1); 51 | for (i = 0; i < num_spaces; i++) 52 | foo->data[i] = ' '; 53 | foo->data[i] = '\0'; 54 | return foo; 55 | } 56 | 57 | void 58 | hello_foo_ref(HelloFoo *foo) 59 | { 60 | foo->refcount++; 61 | } 62 | 63 | void 64 | hello_foo_unref(HelloFoo *foo) 65 | { 66 | if (--foo->refcount > 0) 67 | return; 68 | 69 | if (foo->data) 70 | free(foo->data); 71 | free(foo); 72 | } 73 | 74 | void 75 | hello_foo_set_data(HelloFoo *foo, 76 | const char *data) 77 | { 78 | if (foo->data) 79 | free(foo->data); 80 | foo->data = strdup(data); 81 | } 82 | 83 | const char * 84 | hello_foo_get_data(HelloFoo *foo) 85 | { 86 | return foo->data; 87 | } 88 | 89 | const HelloFoo* hello_foo_get_self (HelloFoo *foo) 90 | { 91 | return foo; 92 | } 93 | 94 | int hello_get_hash (const HelloFoo *foo) 95 | { 96 | if (foo) 97 | { 98 | return (int) (long) foo; 99 | } else { 100 | return -1; 101 | } 102 | } 103 | 104 | -------------------------------------------------------------------------------- /tests/c-hello/hello.h: -------------------------------------------------------------------------------- 1 | #ifndef __HELLO_H__ 2 | #define __HELLO_H__ 3 | 4 | #ifdef __cplusplus 5 | extern "C" 6 | { 7 | #endif 8 | 9 | typedef int Bool; 10 | 11 | Bool hello_print_message (const char *message); 12 | double hello_sum (double x, 13 | double y); 14 | 15 | typedef struct _HelloFoo HelloFoo; 16 | 17 | 18 | HelloFoo* hello_foo_new (void); 19 | HelloFoo* hello_foo_new_from_data (const char *data); 20 | HelloFoo* hello_foo_new_with_spaces (int num_spaces); 21 | void hello_foo_ref (HelloFoo *foo); 22 | void hello_foo_unref (HelloFoo *foo); 23 | void hello_foo_set_data (HelloFoo *foo, 24 | const char *data); 25 | const char * hello_foo_get_data (HelloFoo *foo); 26 | 27 | const HelloFoo* hello_foo_get_self (HelloFoo *foo); 28 | 29 | 30 | /* -#- @foo(null_ok=true, default_value=NULL) -#- */ 31 | int hello_get_hash (const HelloFoo *foo); 32 | 33 | 34 | #ifdef __cplusplus 35 | } 36 | #endif 37 | 38 | #endif /* __HELLO_H__ */ 39 | -------------------------------------------------------------------------------- /tests/c-hello/hellomodulegen.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | import sys 4 | import re 5 | 6 | import pybindgen 7 | from pybindgen import FileCodeSink 8 | from pybindgen.castxmlparser import ModuleParser 9 | 10 | 11 | constructor_rx = re.compile("hello_foo_new(_.*)?") 12 | method_rx = re.compile("hello_foo(_.*)?") 13 | 14 | def pre_scan_hook(dummy_module_parser, 15 | pygccxml_definition, 16 | global_annotations, 17 | parameter_annotations): 18 | if pygccxml_definition.name == "_HelloFoo": 19 | global_annotations['free_function'] = 'hello_foo_unref' 20 | global_annotations['incref_function'] = 'hello_foo_ref' 21 | global_annotations['decref_function'] = 'hello_foo_unref' 22 | global_annotations['custom_name'] = 'Foo' 23 | 24 | ## constructor? 25 | m = constructor_rx.match(pygccxml_definition.name) 26 | if m: 27 | global_annotations['is_constructor_of'] = 'HelloFoo' 28 | return 29 | 30 | ## method? 31 | m = method_rx.match(pygccxml_definition.name) 32 | if m: 33 | method_name = m.group(1)[1:] 34 | if method_name in ['ref', 'unref']: 35 | global_annotations['ignore'] = 'true' 36 | return 37 | global_annotations['as_method'] = m.group(1)[1:] 38 | global_annotations['of_class'] = 'HelloFoo' 39 | parameter_annotations['foo'] = {'transfer_ownership': 'false'} 40 | 41 | 42 | 43 | def my_module_gen(out_file, pygccxml_mode): 44 | out = FileCodeSink(out_file) 45 | #pybindgen.write_preamble(out) 46 | out.writeln("#include \"hello.h\"") 47 | module_parser = ModuleParser('hello') 48 | module_parser.add_pre_scan_hook(pre_scan_hook) 49 | module = module_parser.parse(sys.argv[2:]) 50 | module.generate(out) 51 | 52 | 53 | if __name__ == '__main__': 54 | try: 55 | import cProfile as profile 56 | except ImportError: 57 | my_module_gen(sys.stdout, sys.argv[1]) 58 | else: 59 | sys.stderr.write("** running under profiler\n") 60 | profile.run('my_module_gen(sys.stdout, sys.argv[1])', 'hellomodulegen.pstat') 61 | -------------------------------------------------------------------------------- /tests/c-hello/hellotest.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import gc 3 | import os.path 4 | sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), 5 | '..', '..', 'build', 'default', 'tests', 'c-hello')) 6 | import hello 7 | import unittest 8 | 9 | 10 | class TestHello(unittest.TestCase): 11 | 12 | def test_func(self): 13 | x = hello.sum(1, 2) 14 | self.assertEqual(x, 3) 15 | 16 | def test_foo(self): 17 | foo = hello.Foo() 18 | data = foo.get_data() 19 | self.assertEqual(data, None) 20 | del foo 21 | while gc.collect(): 22 | pass 23 | 24 | def test_foo2(self): 25 | foo = hello.Foo("123") 26 | data = foo.get_data() 27 | self.assertEqual(data, "123") 28 | del foo 29 | while gc.collect(): 30 | pass 31 | 32 | def test_foo3(self): 33 | foo = hello.Foo(3) 34 | data = foo.get_data() 35 | self.assertEqual(data, " ") 36 | del foo 37 | while gc.collect(): 38 | pass 39 | 40 | def test_null_ok(self): 41 | foo = hello.Foo(3) 42 | 43 | h1 = hello.get_hash(foo) 44 | self.assertNotEqual(h1, -1) 45 | 46 | h2 = hello.get_hash(None) 47 | self.assertEqual(h2, -1) 48 | 49 | h3 = hello.get_hash() 50 | self.assertEqual(h3, -1) 51 | 52 | 53 | if __name__ == '__main__': 54 | unittest.main() 55 | -------------------------------------------------------------------------------- /tests/c-hello/wscript: -------------------------------------------------------------------------------- 1 | ## -*- python -*- 2 | #import Action 3 | #import Object 4 | #import Params 5 | #import Task 6 | import os 7 | 8 | if 0: 9 | DEPRECATION_ERRORS = '-Werror::DeprecationWarning' # deprecations become errors 10 | else: 11 | DEPRECATION_ERRORS = '-Wdefault::DeprecationWarning' # normal python behaviour 12 | 13 | def build(bld): 14 | if not bld.env['ENABLE_PYGCCXML']: 15 | print("gccxml not available; skipping the C hello demo") 16 | return 17 | 18 | bindgen = bld( 19 | features='command', 20 | source='hellomodulegen.py hello.h', 21 | target='hellomodule.c', 22 | command='${PYTHON} %s ${SRC[0]} ${PYGCCXML_MODE} ${SRC[1]} > ${TGT[0]}' % (DEPRECATION_ERRORS,)) 23 | 24 | os.environ["PYTHONPATH"] = os.pathsep.join([os.environ.get("PYTHONPATH", ''), bindgen.path.get_bld().abspath()]) 25 | 26 | if bld.env['CXX']: 27 | obj = bld(features='c cshlib pyext') 28 | obj.source = [ 29 | 'hello.c', 30 | 'hellomodule.c' 31 | ] 32 | obj.target = 'hello' 33 | obj.install_path = None # do not install 34 | obj.env.append_value("INCLUDES", '.') 35 | 36 | -------------------------------------------------------------------------------- /tests/foomodulegen-auto-split.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | from __future__ import unicode_literals, print_function 3 | 4 | import sys 5 | import os.path 6 | 7 | import pybindgen 8 | from pybindgen.typehandlers import base as typehandlers 9 | from pybindgen import (ReturnValue, Parameter, Module, Function, FileCodeSink) 10 | from pybindgen import (CppMethod, CppConstructor, CppClass, Enum) 11 | from pybindgen.function import CustomFunctionWrapper 12 | from pybindgen.cppmethod import CustomCppMethodWrapper 13 | from pybindgen.castxmlparser import ModuleParser, PygenClassifier, PygenSection 14 | 15 | import foomodulegen_common 16 | 17 | 18 | 19 | 20 | def my_module_gen(): 21 | 22 | class MyPygenClassifier(PygenClassifier): 23 | def classify(self, pygccxml_definition): 24 | if pygccxml_definition.name and pygccxml_definition.name.lower() <= 'l': 25 | return 'foomodulegen_module1' 26 | else: 27 | return 'foomodulegen_module2' 28 | 29 | pygen = [ 30 | PygenSection('__main__', FileCodeSink(open(sys.argv[3], "wt"))), 31 | PygenSection('foomodulegen_module1', FileCodeSink(open(sys.argv[4], "wt")), 32 | 'foomodulegen_module1_local'), 33 | PygenSection('foomodulegen_module2', FileCodeSink(open(sys.argv[5], "wt")), 34 | 'foomodulegen_module2_local'), 35 | ] 36 | module_parser = ModuleParser('foo4', '::') 37 | module_parser.enable_anonymous_containers = True 38 | 39 | gccxml_options = dict( 40 | include_paths=eval(sys.argv[2]), 41 | ) 42 | 43 | module_parser.parse_init([sys.argv[1]], includes=['"foo.h"'], pygen_sink=pygen, pygen_classifier=MyPygenClassifier(), 44 | gccxml_options=gccxml_options) 45 | module = module_parser.module 46 | foomodulegen_common.customize_module_pre(module) 47 | module.add_exception('exception', foreign_cpp_namespace='std', message_rvalue='%(EXC)s.what()') 48 | module_parser.scan_types() 49 | module_parser.scan_methods() 50 | module_parser.scan_functions() 51 | module_parser.parse_finalize() 52 | 53 | for sect in pygen: 54 | sect.code_sink.file.close() 55 | 56 | 57 | if __name__ == '__main__': 58 | import os 59 | if "PYBINDGEN_ENABLE_PROFILING" in os.environ: 60 | try: 61 | import cProfile as profile 62 | except ImportError: 63 | my_module_gen() 64 | else: 65 | print("** running under profiler", file=sys.stderr) 66 | profile.run('my_module_gen()', 'foomodulegen-auto-split.pstat') 67 | else: 68 | my_module_gen() 69 | 70 | -------------------------------------------------------------------------------- /tests/foomodulegen-auto.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | from __future__ import unicode_literals, print_function, absolute_import 3 | 4 | import sys 5 | import os 6 | import logging 7 | 8 | import pybindgen 9 | from pybindgen.typehandlers import base as typehandlers 10 | from pybindgen import (ReturnValue, Parameter, Module, Function, FileCodeSink) 11 | from pybindgen import (CppMethod, CppConstructor, CppClass, Enum) 12 | from pybindgen.function import CustomFunctionWrapper 13 | from pybindgen.cppmethod import CustomCppMethodWrapper 14 | from pybindgen.castxmlparser import ModuleParser 15 | 16 | import foomodulegen_common 17 | 18 | 19 | def my_module_gen(): 20 | pygccxml_mode = sys.argv[4] 21 | 22 | out = FileCodeSink(sys.stdout) 23 | pygen_file = open(sys.argv[3], "wt") 24 | module_parser = ModuleParser('foo2', '::') 25 | module_parser.enable_anonymous_containers = True 26 | 27 | print("PYTHON_INCLUDES:", repr(sys.argv[2]), file=sys.stderr) 28 | kwargs = { 29 | "{mode}_options".format(mode=pygccxml_mode): dict( 30 | include_paths=eval(sys.argv[2]), 31 | ) 32 | } 33 | module_parser.parse_init([sys.argv[1]], includes=['"foo.h"'], pygen_sink=FileCodeSink(pygen_file), 34 | **kwargs) 35 | module = module_parser.module 36 | foomodulegen_common.customize_module_pre(module) 37 | 38 | module.add_exception('exception', foreign_cpp_namespace='std', message_rvalue='%(EXC)s.what()') 39 | module_parser.scan_types() 40 | module_parser.scan_methods() 41 | module_parser.scan_functions() 42 | module_parser.parse_finalize() 43 | 44 | pygen_file.close() 45 | 46 | foomodulegen_common.customize_module(module) 47 | 48 | module.generate(out) 49 | 50 | def main(): 51 | logging.basicConfig(level=logging.DEBUG) 52 | if sys.argv[1] == '-d': 53 | del sys.argv[1] 54 | import pdb 55 | pdb.set_trace() 56 | my_module_gen() 57 | else: 58 | import os 59 | if "PYBINDGEN_ENABLE_PROFILING" in os.environ: 60 | try: 61 | import cProfile as profile 62 | except ImportError: 63 | my_module_gen() 64 | else: 65 | print("** running under profiler", file=sys.stderr) 66 | profile.run('my_module_gen()', 'foomodulegen-auto.pstat') 67 | else: 68 | my_module_gen() 69 | 70 | if __name__ == '__main__': 71 | main() 72 | 73 | -------------------------------------------------------------------------------- /tests/foomodulegen3.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | from __future__ import unicode_literals, print_function 3 | import sys 4 | import warnings 5 | 6 | import pybindgen 7 | import pybindgen.settings 8 | from pybindgen import (FileCodeSink) 9 | 10 | import foomodulegen_generated 11 | import foomodulegen_common 12 | 13 | 14 | 15 | class ErrorHandler(pybindgen.settings.ErrorHandler): 16 | def handle_error(self, wrapper, exception, dummy_traceback_): 17 | warnings.warn("exception >>> %r in wrapper %s" % (exception, wrapper)) 18 | return True 19 | pybindgen.settings.error_handler = ErrorHandler() 20 | 21 | 22 | 23 | def my_module_gen(): 24 | out = FileCodeSink(sys.stdout) 25 | root_module = foomodulegen_generated.module_init() 26 | root_module.add_exception('exception', foreign_cpp_namespace='std', message_rvalue='%(EXC)s.what()') 27 | foomodulegen_common.customize_module_pre(root_module) 28 | 29 | ## this is a very special case when we want to change the name of 30 | ## the python module to allow parallel testing of the same basic 31 | ## module 'foo' generated by 3 different code paths; normally 32 | ## users don't need this. 33 | root_module.name = 'foo3' 34 | 35 | foomodulegen_generated.register_types(root_module) 36 | foomodulegen_generated.register_methods(root_module) 37 | foomodulegen_generated.register_functions(root_module) 38 | foomodulegen_common.customize_module(root_module) 39 | 40 | root_module.generate(out) 41 | 42 | 43 | if __name__ == '__main__': 44 | try: 45 | import cProfile as profile 46 | except ImportError: 47 | my_module_gen() 48 | else: 49 | print("** running under profiler", file=sys.stderr) 50 | profile.run('my_module_gen()', 'foomodulegen3.pstat') 51 | 52 | -------------------------------------------------------------------------------- /tests/foomodulegen4.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | from __future__ import unicode_literals, print_function 3 | 4 | import sys 5 | import os.path 6 | 7 | import pybindgen 8 | from pybindgen.module import MultiSectionFactory 9 | from pybindgen import (FileCodeSink) 10 | 11 | import foomodulegen_split 12 | import foomodulegen_module1, foomodulegen_module2 13 | import foomodulegen_common 14 | 15 | # TODO(cnicolaou): get the multi section tests working 16 | 17 | class MyMultiSectionFactory(MultiSectionFactory): 18 | 19 | def __init__(self, dir): 20 | self.main_file_name = os.path.join(dir, "foomodule4.cc") 21 | self.main_sink = FileCodeSink(open(self.main_file_name, "wt")) 22 | self.header_name = "foomodule4.h" 23 | header_file_name = os.path.join(dir, self.header_name) 24 | self.header_sink = FileCodeSink(open(header_file_name, "wt")) 25 | self.section_sinks = {} 26 | 27 | def get_section_code_sink(self, section_name): 28 | if section_name == '__main__': 29 | return self.main_sink 30 | try: 31 | return self.section_sinks[section_name] 32 | except KeyError: 33 | file_name = os.path.join(os.path.dirname(self.main_file_name), "%s.cc" % section_name) 34 | sink = FileCodeSink(open(file_name, "wt")) 35 | self.section_sinks[section_name] = sink 36 | return sink 37 | 38 | def get_main_code_sink(self): 39 | return self.main_sink 40 | 41 | def get_common_header_code_sink(self): 42 | return self.header_sink 43 | 44 | def get_common_header_include(self): 45 | return '"%s"' % self.header_name 46 | 47 | def close(self): 48 | self.header_sink.file.close() 49 | self.main_sink.file.close() 50 | for sink in self.section_sinks.values(): 51 | sink.file.close() 52 | 53 | def my_module_gen(): 54 | out = MyMultiSectionFactory(os.path.dirname(sys.argv[1])) 55 | root_module = foomodulegen_split.module_init() 56 | root_module.add_exception('exception', foreign_cpp_namespace='std', message_rvalue='%(EXC)s.what()') 57 | foomodulegen_common.customize_module_pre(root_module) 58 | 59 | foomodulegen_split.register_types(root_module) 60 | foomodulegen_split.register_methods(root_module) 61 | foomodulegen_split.register_functions(root_module) 62 | foomodulegen_common.customize_module(root_module) 63 | 64 | root_module.generate(out) 65 | 66 | out.close() 67 | 68 | 69 | 70 | if __name__ == '__main__': 71 | try: 72 | import cProfile as profile 73 | except ImportError: 74 | my_module_gen() 75 | else: 76 | print("** running under profiler", file=sys.stderr) 77 | profile.run('my_module_gen()', 'foomodulegen4.pstat') 78 | 79 | -------------------------------------------------------------------------------- /tests/foomodulegen_common.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | from __future__ import unicode_literals, print_function 3 | 4 | import sys 5 | import re 6 | 7 | import pybindgen 8 | import pybindgen.settings 9 | pybindgen.settings.deprecated_virtuals = False 10 | 11 | from pybindgen.typehandlers import base as typehandlers 12 | from pybindgen import ReturnValue, Parameter, Module, Function, FileCodeSink 13 | from pybindgen import CppMethod, CppConstructor, CppClass, Enum 14 | from pybindgen.function import CustomFunctionWrapper 15 | from pybindgen.cppmethod import CustomCppMethodWrapper 16 | 17 | 18 | 19 | class PointerHolderTransformation(typehandlers.TypeTransformation): 20 | def __init__(self): 21 | self.rx = re.compile(r'(?:::)?PointerHolder<\s*(\w+)\s*>') 22 | 23 | def get_untransformed_name(self, name): 24 | m = self.rx.match(name) 25 | if m is None: 26 | return None 27 | else: 28 | return m.group(1)+' *' 29 | 30 | def create_type_handler(self, type_handler, *args, **kwargs): 31 | if issubclass(type_handler, Parameter): 32 | kwargs['transfer_ownership'] = False 33 | elif issubclass(type_handler, ReturnValue): 34 | kwargs['caller_owns_return'] = True 35 | else: 36 | raise AssertionError 37 | handler = type_handler(*args, **kwargs) 38 | handler.set_transformation(self, self.get_untransformed_name(args[0])) 39 | return handler 40 | 41 | def untransform(self, type_handler, declarations, code_block, expression): 42 | return '(%s).thePointer' % (expression,) 43 | 44 | def transform(self, type_handler, declarations, code_block, expression): 45 | assert type_handler.untransformed_ctype[-1] == '*' 46 | var = declarations.declare_variable( 47 | 'PointerHolder<%s>' % type_handler.untransformed_ctype[:-1], 'tmp') 48 | return '(%s.thePointer = (%s), %s)' % (var, expression, var) 49 | 50 | transf = PointerHolderTransformation() 51 | typehandlers.return_type_matcher.register_transformation(transf) 52 | typehandlers.param_type_matcher.register_transformation(transf) 53 | del transf 54 | 55 | def customize_module_pre(module): 56 | standard_error = module.add_exception('out_of_range', foreign_cpp_namespace='std', 57 | custom_name='IndexError', is_standard_error=True) 58 | 59 | 60 | def customize_module(module): 61 | pybindgen.settings.wrapper_registry = pybindgen.settings.StdMapWrapperRegistry 62 | 63 | wrapper_body = ''' 64 | static PyObject * 65 | _wrap_foofunction_that_takes_foo_from_string(PyObject * PYBINDGEN_UNUSED(dummy), PyObject *args, 66 | PyObject *kwargs, PyObject **return_exception) 67 | { 68 | PyObject *py_retval; 69 | char *datum; 70 | const char *keywords[] = {"foo", NULL}; 71 | 72 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "s", (char **) keywords, &datum)) { 73 | { 74 | PyObject *exc_type, *traceback; 75 | PyErr_Fetch(&exc_type, return_exception, &traceback); 76 | Py_XDECREF(exc_type); 77 | Py_XDECREF(traceback); 78 | } 79 | return NULL; 80 | } 81 | function_that_takes_foo(Foo(datum)); 82 | Py_INCREF(Py_None); 83 | py_retval = Py_None; 84 | return py_retval; 85 | } 86 | ''' 87 | 88 | if len(module.classes) == 0: 89 | # Some tests, eg. foomodulegen4.py, don't have Bar and Foo classes 90 | # defined. 91 | return 92 | 93 | module.add_custom_function_wrapper('function_that_takes_foo', 94 | '_wrap_foofunction_that_takes_foo_from_string', 95 | wrapper_body, 96 | docstring="I'm awake you rascals!") 97 | 98 | 99 | ## test a custom method wrapper 100 | Bar, = [cls for cls in module.classes if cls.name == 'Bar'] 101 | wrapper_body = ''' 102 | static PyObject * 103 | _wrap_PyBar_Hooray_lenx(PyBar *PYBINDGEN_UNUSED(dummy), PyObject *args, PyObject *kwargs, 104 | PyObject **return_exception) 105 | { 106 | PyObject *py_retval; 107 | int x; 108 | const char *keywords[] = {"x", NULL}; 109 | 110 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "i", (char **) keywords, &x)) { 111 | PyObject *exc_type, *traceback; 112 | PyErr_Fetch(&exc_type, return_exception, &traceback); 113 | Py_XDECREF(exc_type); 114 | Py_XDECREF(traceback); 115 | return NULL; 116 | } 117 | 118 | std::string retval; 119 | retval = Bar::Hooray(); 120 | py_retval = Py_BuildValue((char *) "i", int(retval.size() + x)); 121 | return py_retval; 122 | } 123 | ''' 124 | Bar.add_custom_method_wrapper("Hooray", "_wrap_PyBar_Hooray_lenx", 125 | wrapper_body, 126 | flags=["METH_VARARGS", "METH_KEYWORDS", "METH_STATIC"], 127 | docstring='Zzzz.... Have good dreams.') 128 | 129 | 130 | Foo, = [cls for cls in module.classes if cls.name == 'Foo'] 131 | def Foo_instance_creation_function(dummy_cpp_class, code_block, lvalue, 132 | parameters, construct_type_name): 133 | code_block.write_code( 134 | "%s = new %s(%s);" % (lvalue, construct_type_name, parameters)) 135 | code_block.write_code("%s->initialize();" % (lvalue,)) 136 | Foo.set_instance_creation_function(Foo_instance_creation_function) 137 | 138 | VectorLike2, = [cls for cls in module.classes if cls.name == 'VectorLike2'] 139 | VectorLike2.add_container_traits(ReturnValue.new('double'), begin_method='Begin', end_method='End', iterator_type='Iterator') 140 | 141 | MapLike, = [cls for cls in module.classes if cls.name == 'MapLike'] 142 | MapLike.add_container_traits((ReturnValue.new('int'), ReturnValue.new('double')), 143 | begin_method='Begin', end_method='End', iterator_type='Iterator', 144 | is_mapping=True) 145 | 146 | # just a compilation test, this won't actually work in runtime 147 | #module.add_include('') 148 | #module.add_class(name="FILE", foreign_cpp_namespace="", import_from_module="__builtin__ named file") 149 | #module.add_enum("reg_errcode_t", ["REG_NOERROR", "REG_NOMATCH"], import_from_module="__builtin__") 150 | 151 | -------------------------------------------------------------------------------- /tests/test.py: -------------------------------------------------------------------------------- 1 | from __future__ import unicode_literals, print_function 2 | import pybindgen.typehandlers.base as typehandlers 3 | from pybindgen.typehandlers import stringtype, ctypeparser 4 | import pybindgen.typehandlers.codesink as codesink 5 | from pybindgen import module, cppclass, overloading, utils 6 | 7 | 8 | import unittest 9 | import doctest 10 | import re 11 | import sys 12 | 13 | 14 | class SmartPointerTransformation(typehandlers.TypeTransformation): 15 | def __init__(self): 16 | self.rx = re.compile(r'(?:::)?MySmartPointer<\s*(\w+)\s*>') 17 | 18 | def get_untransformed_name(self, name): 19 | m = self.rx.match(name) 20 | if m is None: 21 | return None 22 | else: 23 | return m.group(1)+' *' 24 | 25 | def create_type_handler(self, type_handler, *args, **kwargs): 26 | ctype = self.get_untransformed_name(args[0]) 27 | handler = type_handler(ctype, *args[1:], **kwargs) 28 | handler.has_been_transformed = True 29 | return handler 30 | 31 | 32 | typehandlers.param_type_matcher.register_transformation( 33 | SmartPointerTransformation()) 34 | 35 | class TestParam(typehandlers.Parameter): 36 | 37 | DIRECTIONS = [typehandlers.Parameter.DIRECTION_IN] 38 | CTYPES = ['testtype*'] 39 | has_been_transformed = False 40 | 41 | def convert_c_to_python(self, wrapper): 42 | assert isinstance(wrapper, typehandlers.ReverseWrapperBase) 43 | wrapper.build_params.add_parameter('i', [self.name]) 44 | 45 | def convert_python_to_c(self, wrapper): 46 | assert isinstance(wrapper, typehandlers.ForwardWrapperBase) 47 | name = wrapper.declarations.declare_variable(self.ctype, self.name) 48 | wrapper.parse_params.add_parameter('i', ['&'+name], self.name) 49 | wrapper.call_params.append(name) 50 | 51 | 52 | class ParamLookupTests(unittest.TestCase): 53 | 54 | def testLookup(self): 55 | handler = typehandlers.Parameter.new('testtype*', 'name') 56 | self.assertTrue(isinstance(handler, TestParam)) 57 | self.assertRaises(typehandlers.TypeLookupError, typehandlers.Parameter.new, 'non_existent_type', 'name') 58 | 59 | def testLookupTransformed(self): 60 | transformed = typehandlers.Parameter.new('MySmartPointer', 'name') 61 | self.assertTrue(isinstance(transformed, TestParam)) 62 | self.assertTrue(transformed.has_been_transformed) 63 | 64 | 65 | 66 | if __name__ == '__main__': 67 | suite = unittest.TestSuite() 68 | 69 | # FIXME: due to python 2 to python 3 transition, most of the 70 | # doctests are failing for trivial reasons. Don't run these tests 71 | # for the time being, until I have time to fix them. 72 | if 0: # sys.version_info[0] < 3: # the doctests only work in Python 2 73 | for mod in [ 74 | typehandlers, 75 | codesink, 76 | module, 77 | cppclass, 78 | overloading, 79 | #utils, 80 | stringtype, 81 | ctypeparser, 82 | ]: 83 | suite.addTest(doctest.DocTestSuite(mod)) 84 | 85 | suite.addTest(doctest.DocTestSuite(ctypeparser)) 86 | suite.addTest(unittest.TestLoader().loadTestsFromTestCase(ParamLookupTests)) 87 | runner = unittest.TextTestRunner() 88 | runner.run(suite) 89 | 90 | -------------------------------------------------------------------------------- /tests/wscript: -------------------------------------------------------------------------------- 1 | ## -*- python -*- 2 | #import Action 3 | #import Object 4 | #import Params 5 | #from waflib import Task 6 | 7 | import sys 8 | import os.path 9 | import os 10 | import subprocess 11 | 12 | # uncomment to enable profiling information 13 | # epydoc uses the profile data to generate call graphs 14 | #os.environ["PYBINDGEN_ENABLE_PROFILING"] = "" 15 | 16 | 17 | if 0: 18 | DEPRECATION_ERRORS = '-Werror::DeprecationWarning' # deprecations become errors 19 | else: 20 | DEPRECATION_ERRORS = '-Wdefault::DeprecationWarning' # normal python behaviour 21 | 22 | 23 | def build(bld): 24 | env = bld.env 25 | 26 | env['TOP_SRCDIR'] = bld.srcnode.abspath() 27 | 28 | if 0: 29 | gen = bld( 30 | features='command', 31 | source='test-generation.py', 32 | target='test.cc', 33 | command='${PYTHON} ${SRC[0]} ${TOP_SRCDIR} > ${TGT[0]}') 34 | 35 | if env['CXX']: 36 | obj = bld(features='cxx pyext') 37 | obj.source = 'test.cc' 38 | if env['CXX_NAME'] == 'gcc': 39 | obj.env.append_value('CXXFLAGS', ['-Werror', '-Wno-unused']) 40 | 41 | # manual code generation using simple pybindgen API calls 42 | bindgen = bld( 43 | features='command', 44 | source='foomodulegen.py', 45 | target='foomodule.cc', 46 | command='${PYTHON} %s ${SRC[0]} ${TOP_SRCDIR} > ${TGT[0]}' % (DEPRECATION_ERRORS,)) 47 | 48 | if env['CXX']: 49 | obj = bld(features='cxx cxxshlib pyext') 50 | obj.source = [ 51 | 'foo.cc', 52 | 'foomodule.cc' 53 | ] 54 | obj.target = 'foo' 55 | obj.install_path = None 56 | obj.env.append_value("INCLUDES", '.') 57 | 58 | ## automatic code scanning using gccxml 59 | if env['ENABLE_PYGCCXML']: 60 | ### Same thing, but using gccxml autoscanning 61 | 62 | bld( 63 | features='command', 64 | source='foomodulegen-auto.py foo.h', 65 | target='foomodule2.cc foomodulegen_generated.py', 66 | command='${PYTHON} %s ${SRC[0]} ${SRC[1]} ${cpp_path_repr} ${TGT[1]} ${PYGCCXML_MODE} > ${TGT[0]}' % (DEPRECATION_ERRORS,), 67 | variables=dict(cpp_path_repr=repr(bindgen.env['INCLUDES']+bindgen.env['INCLUDES_PYEXT']))) 68 | 69 | obj = bld(features='cxx cxxshlib pyext') 70 | obj.source = [ 71 | 'foo.cc', 72 | 'foomodule2.cc' 73 | ] 74 | obj.target = 'foo2' 75 | obj.install_path = None 76 | obj.env.append_value("INCLUDES", '.') 77 | 78 | ### Now using the generated python script 79 | 80 | bld( 81 | features='command', 82 | source='foomodulegen3.py foomodulegen_generated.py', 83 | target='foomodule3.cc', 84 | command='${PYTHON} %s ${SRC[0]} ${TGT[0]} > ${TGT[0]}' % (DEPRECATION_ERRORS,)) 85 | 86 | ## yes, this global manipulation of PYTHONPATH is kind of evil :-/ 87 | ## TODO: add WAF command-output support for customising command OS environment 88 | os.environ["PYTHONPATH"] = os.pathsep.join([os.environ.get("PYTHONPATH", ''), bindgen.path.get_bld().abspath()]) 89 | 90 | obj = bld(features='cxx cxxshlib pyext') 91 | obj.source = [ 92 | 'foo.cc', 93 | 'foomodule3.cc' 94 | ] 95 | obj.target = 'foo3' 96 | obj.install_path = None # do not install 97 | obj.env.append_value("INCLUDES", '.') 98 | 99 | ## --- 100 | 101 | bld( 102 | features='command', 103 | source='foomodulegen-auto-split.py foo.h', 104 | target='foomodulegen_split.py foomodulegen_module1.py foomodulegen_module2.py', 105 | command='${PYTHON} %s ${SRC[0]} ${SRC[1]} ${cpp_path_repr} ${TGT[0]} ${TGT[1]} ${TGT[2]} ${PYGCCXML_MODE}' % (DEPRECATION_ERRORS,), 106 | variables=dict(cpp_path_repr=repr(bindgen.env['INCLUDES']+bindgen.env['INCLUDES_PYEXT']))) 107 | 108 | bld( 109 | features='command', 110 | source=[ 111 | 'foomodulegen4.py', 112 | 'foomodulegen_split.py', 113 | 'foomodulegen_module1.py', 114 | 'foomodulegen_module2.py', 115 | ], 116 | target=[ 117 | 'foomodule4.cc', 118 | 'foomodule4.h', 119 | 'foomodulegen_module1.cc', 120 | 'foomodulegen_module2.cc', 121 | ], 122 | command='${PYTHON} %s ${SRC[0]} ${TGT[0]}' % (DEPRECATION_ERRORS,)) 123 | 124 | obj = bld(features='cxx cxxshlib pyext') 125 | obj.source = [ 126 | 'foo.cc', 127 | 'foomodule4.cc', 128 | 'foomodulegen_module1.cc', 129 | 'foomodulegen_module2.cc', 130 | ] 131 | obj.target = 'foo4' 132 | obj.install_path = None # do not install 133 | obj.env.append_value("INCLUDES", '.') 134 | 135 | ## pure C tests 136 | bld.recurse('c-hello') 137 | 138 | ## boost tests 139 | bld.recurse('boost') 140 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | envlist = py27,py36,py37,py38 3 | 4 | [testenv] 5 | deps= 6 | commands= ./waf distclean 7 | ./waf configure {posargs} 8 | ./waf check -v 9 | -------------------------------------------------------------------------------- /waf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gjcarneiro/pybindgen/926ee3b86d05d16e38480aece23cef365e39c224/waf -------------------------------------------------------------------------------- /waf-tools/cflags.py: -------------------------------------------------------------------------------- 1 | from waflib import Logs 2 | from waflib import Options 3 | from waflib import Utils 4 | 5 | 6 | class CompilerTraits(object): 7 | def get_warnings_flags(self, level): 8 | """get_warnings_flags(level) -> list of cflags""" 9 | raise NotImplementedError 10 | 11 | def get_optimization_flags(self, level): 12 | """get_optimization_flags(level) -> list of cflags""" 13 | raise NotImplementedError 14 | 15 | def get_debug_flags(self, level): 16 | """get_debug_flags(level) -> (list of cflags, list of cppdefines)""" 17 | raise NotImplementedError 18 | 19 | 20 | class GccTraits(CompilerTraits): 21 | def __init__(self): 22 | super(GccTraits, self).__init__() 23 | # cumulative list of warnings per level 24 | self.warnings_flags = [['-Wall'], ['-Werror'], ['-Wextra']] 25 | 26 | def get_warnings_flags(self, level): 27 | warnings = [] 28 | for l in range(level): 29 | if l < len(self.warnings_flags): 30 | warnings.extend(self.warnings_flags[l]) 31 | else: 32 | break 33 | return warnings 34 | 35 | def get_optimization_flags(self, level): 36 | if level == 0: 37 | return ['-O0'] 38 | elif level == 1: 39 | return ['-O'] 40 | elif level == 2: 41 | return ['-O2'] 42 | elif level == 3: 43 | return ['-O3'] 44 | 45 | def get_debug_flags(self, level): 46 | if level == 0: 47 | return (['-g0'], ['NDEBUG']) 48 | elif level == 1: 49 | return (['-g'], []) 50 | elif level >= 2: 51 | return (['-ggdb', '-g3'], ['_DEBUG']) 52 | 53 | 54 | class IccTraits(CompilerTraits): 55 | def __init__(self): 56 | super(IccTraits, self).__init__() 57 | # cumulative list of warnings per level 58 | # icc is _very_ verbose with -Wall, -Werror is barely achievable 59 | self.warnings_flags = [[], [], ['-Wall']] 60 | 61 | def get_warnings_flags(self, level): 62 | warnings = [] 63 | for l in range(level): 64 | if l < len(self.warnings_flags): 65 | warnings.extend(self.warnings_flags[l]) 66 | else: 67 | break 68 | return warnings 69 | 70 | def get_optimization_flags(self, level): 71 | if level == 0: 72 | return ['-O0'] 73 | elif level == 1: 74 | return ['-O'] 75 | elif level == 2: 76 | return ['-O2'] 77 | elif level == 3: 78 | return ['-O3'] 79 | 80 | def get_debug_flags(self, level): 81 | if level == 0: 82 | return (['-g0'], ['NDEBUG']) 83 | elif level == 1: 84 | return (['-g'], []) 85 | elif level >= 2: 86 | return (['-ggdb', '-g3'], ['_DEBUG']) 87 | 88 | 89 | 90 | class MsvcTraits(CompilerTraits): 91 | def __init__(self): 92 | super(MsvcTraits, self).__init__() 93 | # cumulative list of warnings per level 94 | self.warnings_flags = [['/W2'], ['/WX'], ['/Wall']] 95 | 96 | def get_warnings_flags(self, level): 97 | warnings = [] 98 | for l in range(level): 99 | if l < len(self.warnings_flags): 100 | warnings.extend(self.warnings_flags[l]) 101 | else: 102 | break 103 | return warnings 104 | 105 | def get_optimization_flags(self, level): 106 | if level == 0: 107 | return ['/Od'] 108 | elif level == 1: 109 | return [] 110 | elif level == 2: 111 | return ['/O2'] 112 | elif level == 3: 113 | return ['/Ox'] 114 | 115 | def get_debug_flags(self, level): 116 | if level == 0: 117 | return ([], ['NDEBUG']) 118 | elif level == 1: 119 | return (['/ZI', '/RTC1'], []) 120 | elif level >= 2: 121 | return (['/ZI', '/RTC1'], ['_DEBUG']) 122 | 123 | 124 | gcc = GccTraits() 125 | icc = IccTraits() 126 | msvc = MsvcTraits() 127 | 128 | # how to map env['COMPILER_CC'] or env['COMPILER_CXX'] into a traits object 129 | compiler_mapping = { 130 | 'gcc': gcc, 131 | 'g++': gcc, 132 | 'msvc': msvc, 133 | 'icc': icc, 134 | 'icpc': icc, 135 | } 136 | 137 | profiles = { 138 | # profile name: [optimization_level, warnings_level, debug_level] 139 | 'default': [2, 1, 1], 140 | 'debug': [0, 2, 3], 141 | 'release': [3, 1, 0], 142 | } 143 | 144 | default_profile = 'default' 145 | 146 | def options(opt): 147 | assert default_profile in profiles 148 | opt.add_option('-d', '--build-profile', 149 | action='store', 150 | default=default_profile, 151 | help=("Specify the build profile. " 152 | "Build profiles control the default compilation flags" 153 | " used for C/C++ programs, if CCFLAGS/CXXFLAGS are not" 154 | " set set in the environment. [Allowed Values: %s]" 155 | % ", ".join([repr(p) for p in list(profiles.keys())])), 156 | choices=list(profiles.keys()), 157 | dest='build_profile') 158 | 159 | def configure(conf): 160 | cc = conf.env['COMPILER_CC'] or None 161 | cxx = conf.env['COMPILER_CXX'] or None 162 | if not (cc or cxx): 163 | raise Utils.WafError("neither COMPILER_CC nor COMPILER_CXX are defined; " 164 | "maybe the compiler_cc or compiler_cxx tool has not been configured yet?") 165 | 166 | try: 167 | compiler = compiler_mapping[cc] 168 | except KeyError: 169 | try: 170 | compiler = compiler_mapping[cxx] 171 | except KeyError: 172 | Logs.warn("No compiler flags support for compiler %r or %r" 173 | % (cc, cxx)) 174 | return 175 | 176 | opt_level, warn_level, dbg_level = profiles[Options.options.build_profile] 177 | 178 | optimizations = compiler.get_optimization_flags(opt_level) 179 | debug, debug_defs = compiler.get_debug_flags(dbg_level) 180 | warnings = compiler.get_warnings_flags(warn_level) 181 | 182 | if cc and not conf.env['CCFLAGS']: 183 | conf.env.append_value('CCFLAGS', optimizations) 184 | conf.env.append_value('CCFLAGS', debug) 185 | conf.env.append_value('CCFLAGS', warnings) 186 | conf.env.append_value('CCDEFINES', debug_defs) 187 | if cxx and not conf.env['CXXFLAGS']: 188 | conf.env.append_value('CXXFLAGS', optimizations) 189 | conf.env.append_value('CXXFLAGS', debug) 190 | conf.env.append_value('CXXFLAGS', warnings) 191 | conf.env.append_value('CXXDEFINES', debug_defs) 192 | -------------------------------------------------------------------------------- /waf-tools/command.py: -------------------------------------------------------------------------------- 1 | from waflib import TaskGen# import feature, taskgen_method, before_method, task_gen 2 | from waflib import Node, Task, Utils, Build 3 | import subprocess 4 | from waflib import Options 5 | 6 | import shellcmd 7 | #shellcmd.subprocess = pproc # the WAF version of the subprocess module is supposedly less buggy 8 | 9 | from waflib.Logs import debug, error 10 | shellcmd.debug = debug 11 | 12 | from waflib import Task 13 | 14 | import re 15 | 16 | 17 | arg_rx = re.compile(r"(?P\$\$)|(?P\$\{(?P\w+)(?P.*?)\})", re.M) 18 | 19 | def nice_path(input): 20 | return input.path_from(input.ctx.launch_node()) 21 | 22 | class command(Task.Task): 23 | color = "BLUE" 24 | def __init__(self, env, generator): 25 | Task.Task.__init__(self, env=env, normal=1, generator=generator) 26 | 27 | def __str__(self): 28 | "string to display to the user" 29 | src_str = ' '.join([nice_path(a) for a in self.inputs]) 30 | tgt_str = ' '.join([nice_path(a) for a in self.outputs]) 31 | if self.outputs: 32 | sep = ' -> ' 33 | else: 34 | sep = '' 35 | 36 | pipeline = shellcmd.Pipeline() 37 | pipeline.parse(self.generator.command) 38 | cmd = pipeline.get_abbreviated_command() 39 | return 'command (%s): %s%s%s\n' % (cmd, src_str, sep, tgt_str) 40 | 41 | def _subst_arg(self, arg, direction, namespace): 42 | """ 43 | @param arg: the command argument (or stdin/stdout/stderr) to substitute 44 | @param direction: direction of the argument: 'in', 'out', or None 45 | """ 46 | def repl(match): 47 | if match.group('dollar'): 48 | return "$" 49 | elif match.group('subst'): 50 | var = match.group('var') 51 | code = match.group('code') 52 | result = eval(var+code, namespace) 53 | if isinstance(result, Node.Node): 54 | if var == 'TGT': 55 | return result.get_bld().abspath() 56 | elif var == 'SRC': 57 | return result.srcpath() 58 | else: 59 | raise ValueError("Bad subst variable %r" % var) 60 | elif result is self.inputs: 61 | if len(self.inputs) == 1: 62 | return result[0].srcpath() 63 | else: 64 | raise ValueError("${SRC} requested but have multiple sources; which one?") 65 | elif result is self.outputs: 66 | if len(self.outputs) == 1: 67 | return result[0].get_bld().abspath() 68 | else: 69 | raise ValueError("${TGT} requested but have multiple targets; which one?") 70 | elif isinstance(result, list): 71 | assert len(result) == 1 72 | return result[0] 73 | else: 74 | return result 75 | return None 76 | 77 | return arg_rx.sub(repl, arg) 78 | 79 | def run(self): 80 | pipeline = shellcmd.Pipeline() 81 | pipeline.parse(self.generator.command) 82 | namespace = self.env.get_merged_dict() 83 | if self.generator.variables is not None: 84 | namespace.update(self.generator.variables) 85 | namespace.update(env=self.env, SRC=self.inputs, TGT=self.outputs) 86 | for cmd in pipeline.pipeline: 87 | if isinstance(cmd, shellcmd.Command): 88 | if isinstance(cmd.stdin, str): 89 | cmd.stdin = self._subst_arg(cmd.stdin, 'in', namespace) 90 | if isinstance(cmd.stdout, str): 91 | cmd.stdout = self._subst_arg(cmd.stdout, 'out', namespace) 92 | if isinstance(cmd.stderr, str): 93 | cmd.stderr = self._subst_arg(cmd.stderr, 'out', namespace) 94 | for argI in range(len(cmd.argv)): 95 | cmd.argv[argI] = self._subst_arg(cmd.argv[argI], None, namespace) 96 | if cmd.env_vars is not None: 97 | env_vars = dict() 98 | for name, value in list(cmd.env_vars.items()): 99 | env_vars[name] = self._subst_arg(value, None, namespace) 100 | cmd.env_vars = env_vars 101 | elif isinstance(cmd, shellcmd.Chdir): 102 | cmd.dir = self._subst_arg(cmd.dir, None, namespace) 103 | return pipeline.run(verbose=(Options.options.verbose > 0)) 104 | 105 | @TaskGen.taskgen_method 106 | @TaskGen.feature('command') 107 | def init_command(self): 108 | Utils.def_attrs(self, 109 | # other variables that can be used in the command: ${VARIABLE} 110 | variables = None, 111 | rule='') 112 | 113 | 114 | @TaskGen.taskgen_method 115 | @TaskGen.feature('command') 116 | @TaskGen.before_method('process_source') 117 | def process_rule(self): 118 | if not 'command' in self.features: 119 | return 120 | # now create one instance 121 | tsk = self.create_task('command') 122 | if getattr(self, 'target', None): 123 | if isinstance(self.target, str): 124 | self.target = self.target.split() 125 | if not isinstance(self.target, list): 126 | self.target = [self.target] 127 | for x in self.target: 128 | if isinstance(x, str): 129 | tsk.outputs.append(self.path.find_or_declare(x)) 130 | else: 131 | x.parent.mkdir() # if a node was given, create the required folders 132 | tsk.outputs.append(x) 133 | if getattr(self, 'install_path', None): 134 | # from waf 1.5 135 | # although convenient, it does not 1. allow to name the target file and 2. symlinks 136 | # TODO remove in waf 1.7 137 | self.bld.install_files(self.install_path, tsk.outputs) 138 | 139 | if getattr(self, 'source', None): 140 | tsk.inputs = self.to_nodes(self.source) 141 | # bypass the execution of process_source by setting the source to an empty list 142 | self.source = [] 143 | 144 | elif getattr(self, 'deps', None): 145 | def scan(self): 146 | nodes = [] 147 | for x in self.generator.to_list(self.generator.deps): 148 | node = self.generator.path.find_resource(x) 149 | if not node: 150 | self.generator.bld.fatal('Could not find %r (was it declared?)' % x) 151 | nodes.append(node) 152 | return [nodes, []] 153 | cls.scan = scan 154 | 155 | setattr(tsk, "dep_vars", getattr(self, "dep_vars", None)) 156 | -------------------------------------------------------------------------------- /waf-tools/pkgconfig.py: -------------------------------------------------------------------------------- 1 | # -*- mode: python; encoding: utf-8 -*- 2 | # Gustavo Carneiro (gjamc) 2008 3 | 4 | import Options 5 | import Configure 6 | import subprocess 7 | import config_c 8 | import sys 9 | 10 | def configure(conf): 11 | pkg_config = conf.find_program('pkg-config', var='PKG_CONFIG') 12 | if not pkg_config: return 13 | 14 | @Configure.conf 15 | def pkg_check_modules(conf, uselib_name, expression, mandatory=True): 16 | pkg_config = conf.env['PKG_CONFIG'] 17 | if not pkg_config: 18 | if mandatory: 19 | conf.fatal("pkg-config is not available") 20 | else: 21 | return False 22 | 23 | if Options.options.verbose: 24 | extra_msg = ' (%s)' % expression 25 | else: 26 | extra_msg = '' 27 | 28 | conf.start_msg('Checking for pkg-config flags for %s%s' % (uselib_name, extra_msg)) 29 | 30 | argv = [pkg_config, '--cflags', '--libs', expression] 31 | cmd = subprocess.Popen(argv, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 32 | out, err = cmd.communicate() 33 | retval = cmd.wait() 34 | 35 | conf.to_log('%r: %r (exit code %i)\n%s' % (argv, out, retval, err)) 36 | 37 | if retval != 0: 38 | conf.end_msg(False) 39 | sys.stderr.write(err) 40 | else: 41 | if Options.options.verbose: 42 | conf.end_msg(out) 43 | else: 44 | conf.end_msg(True) 45 | 46 | if retval == 0: 47 | conf.parse_flags(out, uselib_name, conf.env) 48 | conf.env[uselib_name] = True 49 | return True 50 | 51 | else: 52 | 53 | conf.env[uselib_name] = False 54 | if mandatory: 55 | raise Configure.ConfigurationError('pkg-config check failed') 56 | else: 57 | return False 58 | 59 | @Configure.conf 60 | def pkg_check_module_variable(conf, module, variable): 61 | pkg_config = conf.env['PKG_CONFIG'] 62 | if not pkg_config: 63 | conf.fatal("pkg-config is not available") 64 | 65 | argv = [pkg_config, '--variable', variable, module] 66 | cmd = subprocess.Popen(argv, stdout=subprocess.PIPE) 67 | out, dummy = cmd.communicate() 68 | retval = cmd.wait() 69 | out = out.rstrip() # strip the trailing newline 70 | 71 | msg_checking = ("Checking for pkg-config variable %r in %s" % (variable, module,)) 72 | conf.check_message_custom(msg_checking, '', out) 73 | conf.log.write('%r: %r (exit code %i)\n' % (argv, out, retval)) 74 | 75 | if retval == 0: 76 | return out 77 | else: 78 | raise Configure.ConfigurationError('pkg-config check failed') 79 | -------------------------------------------------------------------------------- /waf.bat: -------------------------------------------------------------------------------- 1 | @python -x waf %* & exit /b 2 | -------------------------------------------------------------------------------- /wutils.py: -------------------------------------------------------------------------------- 1 | import os.path 2 | import sys 3 | import subprocess 4 | import re 5 | 6 | 7 | def get_version(path=None): 8 | filename = os.path.join(os.path.dirname(__file__), 'pybindgen', 'version.py') 9 | if os.path.exists(filename): 10 | # Read the version.py from the version file 11 | with open(filename, "rt") as versionpy: 12 | for line in versionpy: 13 | try: 14 | head, rest = line.split("version = ") 15 | except ValueError: 16 | continue 17 | return eval(rest) 18 | return version_str 19 | return 'unknown' 20 | --------------------------------------------------------------------------------