You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+38-16
Original file line number
Diff line number
Diff line change
@@ -1,10 +1,23 @@
1
-
# pybind11
1
+
# pybind11 as a scripting engine
2
+
3
+
This tutorial explains in 14 steps how to use `pybind11` for creating a Python scripting engine for a Qt application.
4
+
5
+
It first explains how to create a module that can be imported in Python, continues by prosenting different aspects of running inside of a C++ (Qt) application a Python script that can access (and modify) the status of the main application.
6
+
7
+
Each step contains code that can be individually compiled, run, and – of course – modified.
8
+
9
+
You should probably go through each step in the order presented below, since the commands are (briefly) introduced only once.
2
10
3
11
## Getting pybind11
4
12
5
-
By default, the samples in this repositories use a pre-compiled version of pybind11.
13
+
There are three ways for getting pybind11:
6
14
7
-
You will have to first get pybind11, compile it, and install it:
15
+
-_Embedding_ it in your project as a Git submodule.
16
+
- Installing pybind11 through your package manager (or downloading binaries that are installed in the system path).
17
+
- Compiling pybind11 in a separate directory.
18
+
19
+
20
+
The samples in this repositories use a pre-compiled version of pybind11. If you're not getting pybind11 from your distribution repositories:
8
21
9
22
- get the code from github
10
23
- compile it:
@@ -21,43 +34,52 @@ You need:
21
34
- a development environment for C++ (g++ or clang; cmake, ...)
22
35
- the Python bindings (`libpython3-dev`, `python-cxx-dev`, ...)
23
36
24
-
Our [first example](add/) directly uses the compiler, all other examples will need a modern version of `cmake` being installed (pybind11 should have cmake 3.4)
37
+
Our [first example](add/) directly uses the compiler, all other examples will need a modern version of `cmake` being installed (pybind11 needs cmake 3.4)
25
38
26
39
## Sample projects
27
40
28
-
-[`add/`](add/): using a c++ module to add two numbers in Python
29
-
-[`add-cmake`](add-cmake/): the first example plus cmake
30
-
-[`classes/`](classes/): let Python use C++ classes
41
+
-[`add/`](add/): create a module providing a C++ `add` function that can be add two numbers.
42
+
-[`add-cmake`](add-cmake/): the first example with CMake (all further examples use CMake).
43
+
-[`classes/`](classes/): let Python use C++ classes.
31
44
-[`eval-file/`](eval-file/): C++ evaluates a Python script in an external files that modifies the state of a C++ variable.
32
-
-[`eval-set-object/`](eval-set-object/): Create two objects of type `Foo` and pass them to a Python script (defined as a string in the C++ code)
33
-
-[`eval-set-object-module/`](eval-set-object-module/): Create a `.so` module for the `Foo` type, load it get the Python script to access it.
45
+
-[`eval-set-object/`](eval-set-object/): Create two objects of type `Foo` and pass them by value or by reference to a Python script (defined as a string in the C++ code)
46
+
-[`eval-set-object-module/`](eval-set-object-module/): Create a `.so` module for the `Foo` type, load it in the Python interpreter and let the Python script access it.
34
47
-[`eval-file-pyqt5/`](eval-file-pyqt5/): The C++ code runs an external Python script that shows a PyQt5 alert.
48
+
-[`eval-file-pyqt5-set-value/`](eval-file-pyqt5-set-value/): Setting a C++ value from a PyQt5 input dialog.
- how to use cmake with pybind11 <https://github.com/pybind/pybind11/pull/1098>
41
55
42
56
## Notes
43
57
44
58
- pybind11 runs python code as if it was run in Python's `exec()` call. The visibility of the global and local variables works in the same way: <https://gist.github.com/dean0x7d/df5ce97e4a1a05be4d56d1378726ff92>
59
+
- read https://github.com/GooFit/GooFit/blob/master/python/goofit/Variable.cpp as an example for...
45
60
46
61
## alternatives
47
62
48
63
-[cppy](https://pypi.python.org/pypi/cppyy) is an automatic Python-C++ bindings generator designed for large scale programs in high performance computing that use modern C++.
49
64
50
65
## todo
51
66
52
-
document all directories:
67
+
-[ ] adapt all `CMakeLists.txt` files to require Python 3.7. (`eval-set-object-module` does somehow require it)
68
+
-[ ] use pyside2 on top of pyqt5
69
+
-[ ] can python use the c++ qt widgets (add an entry to the menus, add keyboard shortcuts); can we have callbacks back to python code from the c++ app?
70
+
-[ ] in the qt5-pyqt example there is a "visibility" warning.
This second example shows how to use cmake to simplify the compilation of the [add example](../add).
3
+
This second example shows how to use cmake to compile the [add example](../add).
4
4
5
-
Using `cmake` avoid us the use of the complex `g++` call in the [add example](../add).
6
-
7
-
Like all examples in this repository we're not binding `pybind11` as a git submodule but compile it separately in `~/bin`
5
+
All further examples, will use cmake.
8
6
9
7
The `pybind11_DIR` passed to the cmake commands tells the compiler where to find the library.
10
8
11
-
There is an official demo project that fetches pybind11 as a git submodule: <https://github.com/pybind/cmake_example>.
9
+
This sample uses a "pre-compiled" version of pybind11. If you prefer using git submodules, please refer to the official demo project that fetches pybind11 as a git submodule: <https://github.com/pybind/cmake_example>.
# A python script running a PyQt5 input dialog and setting a c++ variable with the value
1
+
# Setting a C++ value from a PyQt5 input dialog
2
+
3
+
The C++ program defines a `set_the_answer` lambda that can receive the new value and passes it as `local` to the `input-number.py` script.
4
+
5
+
The Python script creates an (PyQt) application that is showing an input dialog. If the _Ok_ button is pressed, the `set_the_answer()` function passes the value to the C++ code.
6
+
7
+
It is to be noted that `pybind11` is passing the `set_the_answer()` as a local to the _eval_ (exec, in reality) Python context: we need to explicitely pass the function to the `get_the_value()` to make it visible inside of it.
8
+
(This is becaue Python executes the code as if it was in a class environment... I've been told.)
Copy file name to clipboardExpand all lines: eval-file/README.md
+55-3
Original file line number
Diff line number
Diff line change
@@ -1,17 +1,69 @@
1
1
# Eval a python script that modifies a C++ object
2
2
3
-
From the C++ code we run a Python script that modifies the state of a C++ variable by calling a C++ function.
3
+
This example shows how to create a C++ program that _runs_ a Python script that has access to variables and functions defined in the C++ program itself.
4
4
5
-
In the C++ program we define a `local` list that contains the variable and the function passed to the Python file when evaluating it.
5
+
The first step is to include the `pybind11`'s `embed.h` library:
6
+
7
+
```cpp
8
+
#include<pybind11/embed.h>
9
+
```
10
+
11
+
We then need to load the Python interpreter:
12
+
13
+
```cpp
14
+
py::scoped_interpreter guard{};
15
+
```
16
+
17
+
We do not directly use it and it will be automatically destroyed when it goes out of scope.
18
+
19
+
In the _local_ environment variable, we create a variable and a function that will be injected in the the Python script's environment:
20
+
21
+
```cpp
22
+
auto local = py::dict();
23
+
local["y"] = ...;
24
+
local["set_the_answer"] = ...;
25
+
```
26
+
27
+
The `scope` variable _contains_ the scope of the main module of our interpreter:
# C++ launches a Python script that loads a shared library module and sets a c++ variable
1
+
# C++ creates and loads a module and runs a Python script that uses the module to modify its own state
2
2
3
-
- Use the C++ foo.[h|cpp] files to create a `.so` shared object (module)
4
-
- Load the module from the C++ main program Python.
5
-
- Call the Python script from the C++ code and pass one variable by value and the other by reference.
6
-
- The Python script modifies the variable.
7
-
- The c++ code checks that the values has been modified
3
+
The C++ `foo.h` and `foo.cpp` provide the `fooapi` Python module (a `.so` shared object defining the `Foo` class with a `bar` member variable (an integer initialized to `1`).
4
+
5
+
The `main.cpp` program includes the `foo.h` library and imports the `fooapi` into the Python interpreter.
6
+
7
+
It calls the usual Python script with two variables, one by copy and one by reference.
The output from the Python script shows that the bar in `foo_copy` initially has the value `1`, but then gets the value `5`.
19
+
20
+
Outside of the script, back in the C++ code, the two asserts confirm that the bar in `foo_1` (passted by copy) still has the value `1` and the one in `foo_2` is now `5`.
21
+
22
+
## References
23
+
10
24
see http://pybind11.readthedocs.io/en/master/advanced/embedding.html
Copy file name to clipboardExpand all lines: eval-set-object/src/main.cpp
+9-5
Original file line number
Diff line number
Diff line change
@@ -17,21 +17,25 @@ PYBIND11_EMBEDDED_MODULE(foo_module, m) {
17
17
18
18
intmain()
19
19
{
20
-
py::scoped_interpreter guard{};// start the interpreter and keep it alive
20
+
py::scoped_interpreter guard{};
21
21
22
-
Foo foo1, foo2;
22
+
Foo foo_1, foo_2;
23
23
24
24
auto module = py::module::import("foo_module");
25
25
26
-
auto locals = py::dict("foo_copy"_a=foo1, "foo_ref"_a=py::cast(foo2, py::return_value_policy::reference), **module.attr("__dict__")); // foo1 by value, foo2 by reference
0 commit comments