Skip to content

Commit

Permalink
Docs design (emscripten-forge#62)
Browse files Browse the repository at this point in the history
* design section

* embed

* pin xeus
  • Loading branch information
DerThorsten authored Mar 27, 2024
1 parent 60157a0 commit 560be08
Show file tree
Hide file tree
Showing 5 changed files with 146 additions and 2 deletions.
2 changes: 1 addition & 1 deletion build_mkdocs.sh
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ if [ ! -d "$WASM_ENV_PREFIX" ]; then
--yes \
python pybind11 nlohmann_json pybind11_json numpy \
bzip2 sqlite zlib libffi exceptiongroup \
xeus xeus-lite xeus-python "xeus-javascript>=0.3.2" xtl "ipython=8.22.2=py311had7285e_1" "traitlets>=5.14.2"
"xeus<4" "xeus-lite<2" xeus-python "xeus-javascript>=0.3.2" xtl "ipython=8.22.2=py311had7285e_1" "traitlets>=5.14.2"

else
echo "Wasm env $WASM_ENV_NAME already exists"
Expand Down
97 changes: 97 additions & 0 deletions docs/design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
# Design

## Main Idea
### pybind11
[Pybind11](https://github.com/pybind/pybind11) is a library that exposes C++ types in Python. It is a wrapper around the Python C API that allows for seamless integration of C++ and Python.
To export a C++ class like the following to Python, you would use pybind11:

```C++
// foo.h
class Foo {
public:
void say_hello() {
std::cout << "Hello, World!" << std::endl;
}
};
```
```C++
// main.cpp
#include <foo.h>
#include <pybind11/pybind11.h>
PYBIND11_MODULE(example, m) {
py::class_<Foo>(m, "Foo")
.def(py::init<>())
.def("say_hello", &Foo::say_hello);
}
```
Not only can Python call C++ functions, but C++ can also call Python functions. In particular, one can interact
with Python objects. An object is represented by the `py::object` type on the C++ side.

```C++
// main.cpp
py::object sys = py::module::import("sys");
py::object version = sys.attr("version");
std::string version_string = version.cast<std::string>();
std::cout << "Python version: " << version_string << std::endl;

```




### embind
There is a simmilar for emscripten called [embind](https://emscripten.org/docs/porting/connecting_cpp_and_javascript/embind.html). It allows you to expose C++ types to JavaScript.

```C++
// main.cpp
#include <foo.h>
#include <emscripten/bind.h>
using namespace emscripten;
// Binding code
EMSCRIPTEN_BINDINGS(my_class_example) {
class_<Foo>("Foo")
.constructor<>()
.function("say_hello", &Foo::say_hello)
;
}
```
To access JavasScript from C++, you would use the `emscripten::val` type. This is the pendant to `py::object` in pybind11.
```C++
emscripten::val console = emscripten::val::global("console");
console.call<void>("log", "Hello, World!");
```

### pyjs
The main idea of pyjs is, to export emscripten `emscripten::val` objects to Python with pybind11 and to export pybind11 `py::object` objects to JavaScript with embind.

That way, we get a seamless integration of Python and JavaScript with relatively little effort and high level C++
code.



## Error Handling

To catch JavaScript exceptions from Python, we wrap all JavaScript code in a try-catch block. If an exception is thrown, we catch it and raise a Python exception with the same message.
The Python exceptions are directly translated to JavaScript exceptions.



## Memory Management
Any C++ class that is exported via embind needs to be deleted by hand with `delete` method. This is because the JavaScript garbage collector does not know about the C++ objects.
Therefore all `py::object` objects that are created from javascript objects need to be deleted by hand. This is done by calling the `delete` method on the `pyobject` object JavaScript side.


## Performance

Compared to pyodide, pyjs is slowwer when crossing the language barrier. Yet itm is fast enough for all practical purposes.

## Packaging

Pyjs is exclusively via [emscripten-forge](https://github.com/emscripten-forge/recipes).

## Testing

To test pyjs without manually inspecting a web page, we use [pyjs-code-runner](https://github.com/emscripten-forge/pyjs-code-runner). This is a tool that runs a Python script in a headless browser and returns the output.
46 changes: 46 additions & 0 deletions docs/embed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Embedding pyjs in C++
Not only can `pyjs` be used as a standalone Python interpreter, but it can also be embedded in a C++ program. This allows you to run Python code in a C++ program.
Pyjs is compiled as a static library that can be linked to a C++ program (when compiled with emscripten).


To include `pyjs` in a C++ program, the following code is needed:

```C++

#include <emscripten/bind.h>
#include <pybind11/embed.h>

#include <pyjs/export_pyjs_module.hpp>
#include <pyjs/export_js_module.hpp>

// export the python core module of pyjs
PYBIND11_EMBEDDED_MODULE(pyjs_core, m) {
pyjs::export_pyjs_module(m);
}

// export the javascript module of pyjs
EMSCRIPTEN_BINDINGS(my_module) {
pyjs::export_js_module();
}

```
In the CMakelists.txt file, the following lines are needed to link the `pyjs` library:
```CMake
find_package(pyjs ${pyjs_REQUIRED_VERSION} REQUIRED)
target_link_libraries(my_target PRIVATE pyjs)
target_link_options(my_target
PUBLIC "SHELL: -s LZ4=1"
PUBLIC "SHELL: --post-js ${pyjs_PRO_JS_PATH}"
PUBLIC "SHELL: --pre-js ${pyjs_PRE_JS_PATH}"
PUBLIC "SHELL: -s MAIN_MODULE=1"
PUBLIC "SHELL: -s WASM_BIGINT"
PUBLIC "-s DEFAULT_LIBRARY_FUNCS_TO_INCLUDE=\"['\$Browser', '\$ERRNO_CODES']\" "
)
```
As described in the [deployment](../installation) section, the needs to be packed.
See the [pack the environment](../installation/#pack-the-environment)-section for instructions on to pack the environment with [`empack`](https://github.com/emscripten-forge/empack).

2 changes: 1 addition & 1 deletion docs/installation.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Installation
# Deploying pyjs

## Prerequisites:

Expand Down
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ theme:


plugins:
- autorefs
- mkdocstrings:
handlers:
python:
Expand Down

0 comments on commit 560be08

Please sign in to comment.