|
| 1 | +## Python bindings |
| 2 | + |
| 3 | +### Shared pointer usage |
| 4 | +#### [05-06-2020] |
| 5 | +- > When we want `cloud = pcl.PointCloud[pcl.PointXYZ]()` to be a shared_ptr by default, we set the holder class as shared_ptr. This is needed in some cases because the interface otherwise would be non-idomatic: |
| 6 | + > ```py |
| 7 | + > import pcl |
| 8 | + > |
| 9 | + > filter = pcl.filters.PassThrough[pcl.PointXYZ]() |
| 10 | + > filter.setInput(cloud) |
| 11 | + > ``` |
| 12 | + > |
| 13 | + > Here, cloud needs to be a shared_ptr. That can be done in 2 ways |
| 14 | + > 1. `cloud = pcl.PointCloud[pcl.PointXYZ]()` and the holder class as shared_ptr |
| 15 | + > 2. `cloud = pcl.make_shared[pcl.PointXYZ]()` and holder class as void |
| 16 | + > |
| 17 | + > The issue is the ease-of-use and expected semantics |
| 18 | + > ```py |
| 19 | + > cloud2 = cloud1 # Python user will assume this is a shallow copy |
| 20 | + > ``` |
| 21 | + > |
| 22 | + > This will only be true for a variable held in a shared_ptr. This is the semantics in Python. |
| 23 | + > |
| 24 | + > However, wrapping everything in shared_ptr has downsides for C++ wrapper: |
| 25 | + > ```py |
| 26 | + > import pcl |
| 27 | + > |
| 28 | + > point = pcl.PointXYZ() |
| 29 | + > cloud[100] = point |
| 30 | + > ``` |
| 31 | + > |
| 32 | + > If PointXYZ is held in a shared_ptr... things go south. If not, things go south |
| 33 | +
|
| 34 | +### Handling unions |
| 35 | +#### [04-06-2020] |
| 36 | +- > given `assert(&(union.r) == &(union.rgb));` does the following hold: |
| 37 | + > `assert id(union_wrapper.r) == id(union_wrapper.rgb) ?` |
| 38 | + Yes. Tested. |
| 39 | +- Working example: |
| 40 | + ```cpp |
| 41 | + #include <pybind11/pybind11.h> |
| 42 | + namespace py = pybind11; |
| 43 | + |
| 44 | + union RGB { |
| 45 | + int rgb; |
| 46 | + struct { |
| 47 | + int r; |
| 48 | + int g; |
| 49 | + int b; |
| 50 | + }; |
| 51 | + }; |
| 52 | + |
| 53 | + PYBIND11_MODULE(pcl, m) |
| 54 | + { |
| 55 | + py::class_<RGB>(m, "RGB") |
| 56 | + .def(py::init<>()) |
| 57 | + .def_property( |
| 58 | + "rgb", |
| 59 | + [](RGB& self) -> int { return self.rgb; }, |
| 60 | + [](RGB& self, int value) { self.rgb = value; }) |
| 61 | + .def_property( |
| 62 | + "r", |
| 63 | + [](RGB& self) -> int { return self.r; }, |
| 64 | + [](RGB& self, int value) { self.r = value; }) |
| 65 | + .def_property( |
| 66 | + "g", |
| 67 | + [](RGB& self) -> int { return self.g; }, |
| 68 | + [](RGB& self, int value) { self.g = value; }) |
| 69 | + .def_property( |
| 70 | + "b", |
| 71 | + [](RGB& self) -> int { return self.b; }, |
| 72 | + [](RGB& self, int value) { self.b = value; }); |
| 73 | + } |
| 74 | + ``` |
| 75 | +
|
| 76 | +### General |
| 77 | +#### [05-06-2020] |
| 78 | +- MetaCPP relies on Clang's LibTooling to generate all the metadata: https://github.com/mlomb/MetaCPP |
| 79 | + |
| 80 | +#### [04-06-2020] |
| 81 | +- > Was reading this yesterday: https://peerj.com/articles/cs-149.pdf |
| 82 | + > |
| 83 | + > Summary: |
| 84 | + > - They too, automatically generate Python bindings for C++ code using Boost::Python. |
| 85 | + > - The whole process is python based. |
| 86 | + > - Same design as to what we have in mind i.e., parse, process, and generate. |
| 87 | + > - Their data structure of choice for the whole process is Abstract Semantic Graph: https://github.com/StatisKit/AutoWIG/blob/master/src/py/autowig/asg.py |
| 88 | + > - The architecture is plugin-based, and somebody added a pybind plugin some months back: https://github.com/StatisKit/AutoWIG/blob/master/src/py/autowig/pybind11_generator.py |
| 89 | + > - They use libclang for frontend parsing(python API). The project was done some time back so they wrote their own py-libclang code: https://github.com/StatisKit/AutoWIG/blob/master/src/py/autowig/libclang_parser.py |
| 90 | + > - Repo: https://github.com/StatisKit/AutoWIG |
| 91 | + > |
| 92 | + > I think it can act as a good reference for the project. Have a look at the pdf and the source if you wish. |
| 93 | + > The libclang python part can be explored from their repo as of now (as python-libclang has no documentation whatsoever and the 1-2 example articles are outdated) |
| 94 | +- Problems: |
| 95 | + > Templates: |
| 96 | + > * suffixing doesn't work well. Unless you're a fan of the pseudo-Hungarian notation espoused by older devs (and by MS). It's ok for 1 (or maybe 2) arguments. |
| 97 | + > * Templates in Python represent an instantiation of C++ template. It should be easy to add/remove an instantiation without affecting needless code. It should also be visually easy to switch the template type without having to lookup the notation or count underscores |
| 98 | + > * Python has a strong syntax for this: index lookup via __getitem__ and __setitem__ |
| 99 | + > * Using strings as keys is bad because the editor can't help if spelling is wrong. Pandas MultiKey failed here. |
| 100 | +- Use of a templating engine for pybind11 code gen (jinja2>mako) |
| 101 | + |
| 102 | +#### [03-06-2020] |
| 103 | +- Ambiguity in the phrase: "full control over clang's AST" |
| 104 | + |
| 105 | +#### [02-06-2020] |
| 106 | +- Use of python bindings of libclang, for faster prototyping: https://github.com/llvm/llvm-project/blob/master/clang/bindings/python/clang/cindex.py |
| 107 | +- > protyping and exploring python bindings in which everything is runtime and can be done interactively would usually be my first approach |
| 108 | +
|
| 109 | +#### [28-05-2020] |
| 110 | +- > While reading lsst's documentation, came to find out they use a __str__ method: |
| 111 | + > ```py |
| 112 | + > cls.def("__str__", [](Class const& self) { |
| 113 | + > std::ostringstream os; |
| 114 | + > os << self; |
| 115 | + > return os.str(); |
| 116 | + > }); |
| 117 | + > ``` |
| 118 | +- > the << operator with ostreams is the most common way in C++ of extracting a string representation of a given object (I have no idea why there's no practice of implementing the cast to string method), |
| 119 | +That being said I believe you can use << with std::stringstreams, effectively allowing you to fetch a string representation of PCL objects which have operator<< (std::ostream, ....) implemented. |
| 120 | +
|
| 121 | +#### [15-05-2020] |
| 122 | +- > You can create docstring from \brief part and copy the function signature via libtooling. |
| 123 | +
|
| 124 | +#### [09-05-2020] |
| 125 | +- Start with binding PointTypes. |
| 126 | +- AST parsing helps in cases of convoluted code. |
| 127 | +- > We can keep 2 approaches in parallel: |
| 128 | + > 1. header parser on a limited number of files |
| 129 | + > 2. libtooling to replace it |
| 130 | + > 1st will allow the pipeline to be developed |
| 131 | + > 2nd will replace that |
| 132 | +- > We can make a prototype which works on manually provided API points |
| 133 | +- > From my understanding: |
| 134 | + > 1. Code -> AST -> JSON: use some tool for it first, then replace with libtooling |
| 135 | + > 2. JSON -> cpp: Python tool, language dependent |
| 136 | + > 3. CMake + compile_database.json: rest of toolchain |
| 137 | + > 4. organize properly so usage in LANG is nice |
| 138 | +
|
| 139 | +#### [05-05-2020] |
| 140 | +- > I'd put PyPi integration immediately after we get 1 module working. That'd allow us to keep shipping improved bindings after GSoC (in case the timeline gets delayed) |
| 141 | +The order in which modules are tackled should be the dependency order (because we don't have the popularity data from our users) |
| 142 | +
|
| 143 | +*** |
| 144 | +
|
| 145 | +## Javascript Bindings |
| 146 | +#### [05-05-2020] |
| 147 | +- Webassembly as an option: https://en.wikipedia.org/wiki/WebAssembly |
| 148 | +- Emscripten as an option: https://emscripten.org/ |
| 149 | +- > * Getting clang to compile to WebAsm will be the best "performance". |
| 150 | + > * Using Emscripten on the other hand is a well-travelled road, but the performance will be similar to hand written JS (or worse). |
| 151 | + > Both approaches need clang so that's a milestone we need to conquer first. |
| 152 | + |
| 153 | +*** |
| 154 | + |
| 155 | +## Jupyter Visualisation |
| 156 | +#### [05-05-2020] |
| 157 | +- > WebGL view straddles JS bindings and Python bindings. It should come before JS bindings in terms of priority keeping in mind the popularity of Python as a second language for the kind of C++ users PCL attracts (academia) |
| 158 | +- > https://jupyter.org/widgets has pythreejs which is embedding js in python. .... That's 1 step above webgl, involves using JS in Py, but is faster to get up and running.... We can tackle this based on time when we reach some stage |
0 commit comments