Use litgen online#
This page shows an example of conversion of C++ code into C++ bindings code and python stubs. You can open it in an online interactive environment (mybinder), where you can edit the code below.
To launch the online tool, click on the rocket icon at the top right of this page, or use this link
The interactive environment will open in a new tab. Wait for it to be ready
Once it is launched, click on “Run Cell” to run each of the cells:
You can edit the C++ code as well as the options below. The generated code will be displayed under the cell, once you clicked “Run Cell”. You will then be able to see:
The generated python stubs (aka declarations)
The generated C++ bindings code for pybind11
The generated C++ bindings code for nanobind
The generated glue code (if needed)
import litgen
from litgen.demo import litgen_demo
options = litgen.LitgenOptions()
# This namespace will not be outputted as a python module
options.namespaces_root = ["MyNamespace"]
# All functions, modules and namespaces names are converted to snake case
options.python_convert_to_snake_case = True
# This is an API marker in the C++ code (for shared libraries code)
options.srcmlcpp_options.functions_api_prefixes = "^MY_API$"
# Also create bindings for functions that do not have the API marker
options.fn_exclude_non_api = False
# Optional comment that can be added to non API functions
options.fn_non_api_comment = ""
# "Box" immutable functions parameter when they should be modifiable
options.fn_params_replace_modifiable_immutable_by_boxed__regex = r".*"
# Which numeric and string preprocessor do we want to export
options.macro_define_include_by_name__regex = "^MY_"
code = """
// This namespace is not outputed as a submodule, since it is marked as Root (see options.namespaces_root)
namespace MyNamespace
{
// Multiplies a list of double by a given factor, returns updated list
std::vector<double> MultiplyDoubles(const std::vector<double>& v, float k);
// changes the value of the bool parameter (passed by modifiable reference)
// (This function will use a BoxedBool in the python code, so that its value can be modified)
void SwitchBoolValue(bool &v);
// Standalone comment blocs are also exported
// This function includes an API marker which will be ignored when generating the bindings
MY_API int MySubstract(int a, int b); // eol doc is also included in bindings doc
namespace MyMath // This namespace is not ignored and introduces a new python module
{
// div and mul: divide or multiply float numbers
// (This comment concerns the two grouped
// functions below, and will be exported as such)
float Div(float a, float b); // Divide
float Mul(float a, float b); // Multiply
}
// Stores Pixel coordinates
struct Pixel
{
// Coordinates
double x = 2., y = 3.;
// Draw a pixel
void Draw(Image& i);
private:
double _Norm(); // this will not be exported as it is private
};
// This macro value be exported, as it matches the regex macro_define_include_by_name__regex
#define MY_VALUE 123
}
"""
litgen_demo.demo(
options, code, show_cpp=False, show_pydef=True, height=80
)
#################### <generated_from:BoxedTypes> ####################
class BoxedBool:
value: bool
def __init__(self, v: bool = False) -> None:
pass
def __repr__(self) -> str:
pass
#################### </generated_from:BoxedTypes> ####################
def multiply_doubles(v: List[float], k: float) -> List[float]:
""" Multiplies a list of double by a given factor, returns updated list"""
pass
def switch_bool_value(v: BoxedBool) -> None:
""" changes the value of the bool parameter (passed by modifiable reference)
(This function will use a BoxedBool in the python code, so that its value can be modified)
"""
pass
# Standalone comment blocs are also exported
# This function includes an API marker which will be ignored when generating the bindings
def my_substract(a: int, b: int) -> MY_API int:
""" eol doc is also included in bindings doc"""
pass
class Pixel:
""" Stores Pixel coordinates"""
# Coordinates
x: float = 2.
# Coordinates
y: float = 3.
def draw(self, i: Image) -> None:
""" Draw a pixel"""
pass
def __init__(self, x: float = 2., y: float = 3.) -> None:
"""Auto-generated default constructor with named params"""
pass
# This macro value be exported, as it matches the regex macro_define_include_by_name__regex
MY_VALUE = 123
# <submodule my_math>
class my_math: # Proxy class that introduces typings for the *submodule* my_math
pass # (This corresponds to a C++ namespace. All method are static!)
"""This namespace is not ignored and introduces a new python module"""
# div and mul: divide or multiply float numbers
# (This comment concerns the two grouped
# functions below, and will be exported as such)
@staticmethod
def div(a: float, b: float) -> float:
""" Divide"""
pass
@staticmethod
def mul(a: float, b: float) -> float:
""" Multiply"""
pass
# </submodule my_math>
//////////////////// <generated_from:BoxedTypes> ////////////////////
auto pyClassBoxedBool =
py::class_<BoxedBool>
(m, "BoxedBool", "")
.def_readwrite("value", &BoxedBool::value, "")
.def(py::init<bool>(),
py::arg("v") = false)
.def("__repr__",
&BoxedBool::__repr__)
;
//////////////////// </generated_from:BoxedTypes> ////////////////////
m.def("multiply_doubles",
MyNamespace::MultiplyDoubles,
py::arg("v"), py::arg("k"),
"Multiplies a list of double by a given factor, returns updated list");
m.def("switch_bool_value",
[](BoxedBool & v)
{
auto SwitchBoolValue_adapt_modifiable_immutable = [](BoxedBool & v)
{
bool & v_boxed_value = v.value;
MyNamespace::SwitchBoolValue(v_boxed_value);
};
SwitchBoolValue_adapt_modifiable_immutable(v);
},
py::arg("v"),
" changes the value of the bool parameter (passed by modifiable reference)\n (This function will use a BoxedBool in the python code, so that its value can be modified)");
m.def("my_substract",
MyNamespace::MySubstract,
py::arg("a"), py::arg("b"),
"eol doc is also included in bindings doc");
auto pyClassPixel =
py::class_<MyNamespace::Pixel>
(m, "Pixel", "Stores Pixel coordinates")
.def(py::init<>([](
double x = 2., double y = 3.)
{
auto r = std::make_unique<MyNamespace::Pixel>();
r->x = x;
r->y = y;
return r;
})
, py::arg("x") = 2., py::arg("y") = 3.
)
.def_readwrite("x", &MyNamespace::Pixel::x, "Coordinates")
.def_readwrite("y", &MyNamespace::Pixel::y, "Coordinates")
.def("draw",
&MyNamespace::Pixel::Draw,
py::arg("i"),
"Draw a pixel")
;
m.attr("MY_VALUE") = 123;
{ // <namespace MyMath>
py::module_ pyNsMyMath = m.def_submodule("my_math", "This namespace is not ignored and introduces a new python module");
pyNsMyMath.def("div",
MyNamespace::MyMath::Div,
py::arg("a"), py::arg("b"),
"Divide");
pyNsMyMath.def("mul",
MyNamespace::MyMath::Mul,
py::arg("a"), py::arg("b"),
"Multiply");
} // </namespace MyMath>
//////////////////// <generated_from:BoxedTypes> ////////////////////
auto pyClassBoxedBool =
nb::class_<BoxedBool>
(m, "BoxedBool", "")
.def_rw("value", &BoxedBool::value, "")
.def(nb::init<bool>(),
nb::arg("v") = false)
.def("__repr__",
&BoxedBool::__repr__)
;
//////////////////// </generated_from:BoxedTypes> ////////////////////
m.def("multiply_doubles",
MyNamespace::MultiplyDoubles,
nb::arg("v"), nb::arg("k"),
"Multiplies a list of double by a given factor, returns updated list");
m.def("switch_bool_value",
[](BoxedBool & v)
{
auto SwitchBoolValue_adapt_modifiable_immutable = [](BoxedBool & v)
{
bool & v_boxed_value = v.value;
MyNamespace::SwitchBoolValue(v_boxed_value);
};
SwitchBoolValue_adapt_modifiable_immutable(v);
},
nb::arg("v"),
" changes the value of the bool parameter (passed by modifiable reference)\n (This function will use a BoxedBool in the python code, so that its value can be modified)");
m.def("my_substract",
MyNamespace::MySubstract,
nb::arg("a"), nb::arg("b"),
"eol doc is also included in bindings doc");
auto pyClassPixel =
nb::class_<MyNamespace::Pixel>
(m, "Pixel", "Stores Pixel coordinates")
.def("__init__", [](MyNamespace::Pixel * self, double x = 2., double y = 3.)
{
new (self) MyNamespace::Pixel(); // placement new
auto r = self;
r->x = x;
r->y = y;
},
nb::arg("x") = 2., nb::arg("y") = 3.
)
.def_rw("x", &MyNamespace::Pixel::x, "Coordinates")
.def_rw("y", &MyNamespace::Pixel::y, "Coordinates")
.def("draw",
&MyNamespace::Pixel::Draw,
nb::arg("i"),
"Draw a pixel")
;
m.attr("MY_VALUE") = 123;
{ // <namespace MyMath>
nb::module_ pyNsMyMath = m.def_submodule("my_math", "This namespace is not ignored and introduces a new python module");
pyNsMyMath.def("div",
MyNamespace::MyMath::Div,
nb::arg("a"), nb::arg("b"),
"Divide");
pyNsMyMath.def("mul",
MyNamespace::MyMath::Mul,
nb::arg("a"), nb::arg("b"),
"Multiply");
} // </namespace MyMath>
struct BoxedBool
{
bool value;
BoxedBool(bool v = false) : value(v) {}
std::string __repr__() const { return std::string("BoxedBool(") + std::to_string(value) + ")"; }
};