|
|
# Minimal C++ RPC PoC with Auto-Code Generation
|
|
|
|
|
|
Простой Proof-of-Concept реализации RPC для C++ с автоматической генерацией прокси и скелета по аннотациям в исходниках.
|
|
|
|
|
|
Проект демонстрирует:
|
|
|
|
|
|
* Парсинг исходников C++ с помощью `libclang` для поиска аннотированных классов и методов.
|
|
|
* Автоматическую генерацию файлов:
|
|
|
* `*.proxy.h/cpp` — клиентский прокси для вызова удалённых методов.
|
|
|
* `*.skeleton.h/cpp` — серверный скелет для приёма запросов и вызова реальных методов.
|
|
|
* Минимальный протокол передачи данных через **именованные каналы (FIFO)**.
|
|
|
* Поддержка только типов `int` для аргументов и возвращаемого значения (PoC).
|
|
|
|
|
|
---
|
|
|
|
|
|
## Структура проекта
|
|
|
|
|
|
```
|
|
|
project/
|
|
|
├── CMakeLists.txt
|
|
|
├── README.md
|
|
|
├── src
|
|
|
│ ├── client.cpp
|
|
|
│ ├── MyService.cpp
|
|
|
│ ├── MyService.h
|
|
|
│ ├── rpc_common.h
|
|
|
│ ├── rpc_export.h
|
|
|
│ └── server.cpp
|
|
|
├── tools
|
|
|
│ ├── generate_rpc.py
|
|
|
│ └── templates
|
|
|
│ ├── proxy.cpp.j2
|
|
|
│ ├── proxy.h.j2
|
|
|
│ ├── skeleton.cpp.j2
|
|
|
│ └── skeleton.h.j2
|
|
|
└─ build/ # создаётся при сборке
|
|
|
```
|
|
|
|
|
|
---
|
|
|
|
|
|
## Зависимости
|
|
|
|
|
|
* CMake ≥ 3.10
|
|
|
* GCC или Clang с поддержкой C++17
|
|
|
* Python 3.8+ с пакетами:
|
|
|
|
|
|
```bash
|
|
|
pip3 install jinja2 clang
|
|
|
```
|
|
|
* libclang (для Python)
|
|
|
Если GCC используется только для сборки — libclang нужен только для генератора.
|
|
|
|
|
|
**Важно**: Сам `libclang` и пакет `clang` для Python должны быть одной версии.
|
|
|
|
|
|
---
|
|
|
|
|
|
## Аннотации для экспорта
|
|
|
|
|
|
Управление тем, какие атрибуты каких классов следует экспортировать происходит с помощью
|
|
|
аннотаций в исходном коде.
|
|
|
|
|
|
См. файл [MyService.h](src/MyService.h):
|
|
|
|
|
|
```c
|
|
|
class RPC_EXPORT MyService {
|
|
|
public:
|
|
|
RPC_EXPORT
|
|
|
int add(int a, int b);
|
|
|
int minus(int a, int b);
|
|
|
};
|
|
|
```
|
|
|
|
|
|
* Экспортируем класс `MyService`:
|
|
|
* Экспортируем метод `MyService::add`;
|
|
|
* Но **не** экспортируем метод `MyService::minus`.
|
|
|
|
|
|
---
|
|
|
|
|
|
## Сборка проекта
|
|
|
|
|
|
1. Конфигурируем CMake:
|
|
|
|
|
|
```bash
|
|
|
cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -B build
|
|
|
```
|
|
|
|
|
|
Директива `CMAKE_EXPORT_COMPILE_COMMANDS=ON` нужна для корректного парсинга в `libclang`.
|
|
|
|
|
|
2. Собираем проект:
|
|
|
|
|
|
```bash
|
|
|
cmake --build build
|
|
|
```
|
|
|
|
|
|
В результате получаем два бинарника:
|
|
|
|
|
|
```
|
|
|
./build/server
|
|
|
./build/client
|
|
|
```
|
|
|
|
|
|
---
|
|
|
|
|
|
## Генерация кода
|
|
|
|
|
|
Автоматическая генерация прокси и скелета происходит **при сборке** через Python-скрипт `tools/generate_rpc.py`.
|
|
|
|
|
|
Пример ручного запуска генератора:
|
|
|
|
|
|
```bash
|
|
|
python3 tools/generate_rpc.py \
|
|
|
--out-dir build/generated \
|
|
|
--compile-commands build/compile_commands.json \
|
|
|
src/MyService.h
|
|
|
```
|
|
|
|
|
|
Сгенерированные файлы попадут в:
|
|
|
|
|
|
```
|
|
|
build/generated/
|
|
|
├─ MyService.proxy.h
|
|
|
├─ MyService.proxy.cpp
|
|
|
├─ MyService.skeleton.h
|
|
|
└─ MyService.skeleton.cpp
|
|
|
```
|
|
|
|
|
|
---
|
|
|
|
|
|
## Запуск
|
|
|
|
|
|
1. В одном терминале запускаем сервер:
|
|
|
|
|
|
```bash
|
|
|
./server
|
|
|
```
|
|
|
|
|
|
2. В другом терминале — клиент:
|
|
|
|
|
|
```bash
|
|
|
./client
|
|
|
```
|
|
|
|
|
|
**Ожидаемый вывод:**
|
|
|
|
|
|
```
|
|
|
RESULT: 15
|
|
|
```
|