Use litgen online

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.

  1. To launch the online tool, click on the rocket icon at the top right of this page, or use this link

  2. The interactive environment will open in a new tab. Wait for it to be ready

  3. Once it is launched, click on “Run Cell” to run each of the cells:

Run cell

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) + ")"; }
};