espp/lib at main · esp-cpp/espp · GitHub
Skip to content

Latest commit

 

History

History

README.md

ESPP Library

Table of Contents

Description

This folder contains the configuration needed to cross-compile the central (cross-platform) components of espp for the following platforms:

  • PC (Linux, MacOS, Windows)
    • C++
    • Python (through pybind 11)

Not all components of espp are cross-platform, so this library only references the cross-platform components of espp. The cross-platform components are those which do not depend on any specific hardware or platform.

Note: some components could be cross platform (e.g. various peripheral drivers and such), but are not currently exposed via this library.

Some examples can be found in these folders:

  • ../pc: This folder contains c++ various example code which uses the espp library.
  • ../python: This folder contains python code which uses the espp library.

All the examples in these folders require that the espp library is built first, as described below.

Building for PC (C++ & Python)

To build the library for use on PC (with C++ and Python), simply build with cmake:

mkdir build
cd build
cmake ..
cmake --build . --config Release --target install

This is conveniently scripted up for you into ./build.sh and ./build.ps1 scripts you can simply run from your terminal.

This will build and install the following files:

  • ./pc/libespp_pc - C++ static library for use with other C++ code.
  • ./pc/include - All the header files need for using the library from C++ code.
  • ./pc/espp.so - C++ shared library for python binding for use with python code.

Updating the python bindings

You should only need to regenerate / update the python bindings if the espp code itself changes, and only if the changed code is exposed via this cross-platform library - meaning it's part of the ./include/espp.hpp or otherwise pointed to by espp.cmake.

We use litgen to automatically parse specific header files and generate python bindings for them in c++ using pybind11.

Relevant files:

  • ./autogenerate_bindings.py: This is the script which configures litgen and generates the appropriate code. Inside this script is where we tell litgen which header files to generate python bindings for. Note that the ordering of the header file list is important.
  • ./python_bindings/pybind_espp.cpp: This is where the generated pybind11 c++ code will go. It will need to be modified after generation (see below).

Setup

Create a virtual environment, and install the required packages:

python3 -m venv env
source env/bin/activate
pip install -r requirements.txt

Generating python bindings

# start the environment
source env/bin/activate
python autogenerate_bindings.py

No manual editing of the generated file is required, and no build/compile step is needed to fix it. autogenerate_bindings.py strips C++20 requires-clauses at parse time (so Vector2d and friends parse), then post-processes the generated pybind_espp.cpp entirely with static string/regex passes (_postprocess_generated) to fix every litgen/srcmlcpp bug that used to be fixed by hand:

  • bogus implicit default constructors (Logger, Task, the RTSP packetizers, ...),
  • template-class nested args (RangeMapper<int>, Bezier<espp::Vector2f>, Vector2d<float>),
  • static/instance method duplicates (Task::get_id),
  • std::shared_ptr holders + bases (the RTP packetizer hierarchy, JpegFrame),
  • unqualified RTSP nested types / nested-struct statics in named-ctor defaults (espp::RtspClient::frame_callback_t, espp::RtspServer::Config::default_*, ...),
  • def_readwritedef_readonly for non-copyable members (RtspSession::Track sockets).

The litgen dependency is unpinned and recent versions (0.20–0.22) regressed nested-scope/template generation, which is why this automation is needed.

fix_generated_bindings.py is kept only as an optional diagnostic: if a future litgen version introduces new unqualified names, configure the build with cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -S . -B build and run it — it compiles the generated file and reports clang's 'Y'; did you mean 'espp::X::Y'? suggestions so you can extend the static maps in autogenerate_bindings.py.

Hand-written components (cdr, rtps)

cdr and rtps are not generated by litgen — they are bound by hand in ./python_bindings/cdr_bindings.cpp and ./python_bindings/rtps_bindings.cpp (registered via py_init_cdr / py_init_rtps in module.cpp). litgen cannot bind them usefully (output-reference reads, non-owning std::span, std::function callbacks), and the hand-written shims give a clean, GIL-correct Python API (CdrWriter/CdrReader, RtpsParticipant with publish(topic, bytes) and ReaderConfig.on_sample = callable(bytes)). Edit those files directly; regeneration never touches them.