基于pybind11 binder实现python调用c++
·
- 环境准备
- 1.安装pybingd11
- 2.binder安装
- 实践
- 1.基于ap服务的提供侧和消费侧,编译c++动态库
- 2.基于pybind11编译python绑定c++的模块
- 3.py脚本验证AP
- 4.binder使用
环境准备
python环境安装这里就不赘述了。
1.安装pybingd11
Pybind11 是一个轻量级的 C++ 库,用于将 C++ 代码暴露给 Python 调用(反之也可,但主要还是前者)。
git clone https://github.com/pybind/pybind11.git
cd pybind11
mkdir build && cd build
cmake .. -DBUILD_TESTING=ON # 启用测试库
make
sudo make install
2.binder安装
为了创建将提供 C++ 代码绑定的共享库,需要:
1.收集有关哪些类/函数可用的数据,并获取有关类遗产、成员函数的深入信息 和 Standalone Functions 类型签名。
2.生成python绑定c++代码
3.将代码编译为共享库
Binder 是旨在自动执行步骤 1 和 2 的工具。
sudo apt-get update
sudo apt-get -y install clang-10 llvm-10 libclang-10-dev llvm-10-dev
sudo apt-get -y install cmake make gcc g++
git clone https://github.com/RosettaCommons/binder
cd binder
cmake CMakeLists.txt -DLLVM_DIR=/usr/lib/llvm-10 -DClang_DIR=/usr/lib/llvm-10
make
sudo make install
实践
1.基于ap服务的提供侧和消费侧,编译c++动态库
1.1 ./include
├── myts.hpp
#include <pygeneral_client.h>
#include <pygeneral_server.h>
├── pygeneral_client.h
#include <iostream>
#define SHM_NAME "/my_shared_memory"
#define SHM_SIZE 4096
#define MESSAGE_SIZE 1024
namespace testers {
struct Message {
char data[MESSAGE_SIZE];
};
class PyGeneralClient{
public:
//一定要有函数体
virtual ~PyGeneralClient(){};
PyGeneralClient();
std::string clientcall(std::string method,std::string jsonstring);
private:
bool GetDataFromSharemem(std::string& str);
bool is_exit = false;
};
}
└── pygeneral_server.h
#include <iostream>
namespace testers {
class PyGeneralServer{
public:
//一定要有函数体
virtual ~PyGeneralServer(){};
PyGeneralServer(){};
void servercall();
private:
bool is_exit = false;
};
}
1.2 ./lib
├── libgeneral_client.so
└── libgeneral_server.so
2.基于pybind11编译python绑定c++的模块
基于pybind11编译python绑定c++的模块
2.1 手动编写python绑定c++源文件
├── automobile.cpp
#include <pybind11/pybind11.h>
namespace py = pybind11;
void init_motorcycle(py::module &);
namespace mcl {
PYBIND11_MODULE(generalpy, m) {
// Optional docstring
m.doc() = "Automobile library";
init_motorcycle(m);
}
}
├── general_py.cpp
#include <pybind11/pybind11.h>
#include <pybind11/eigen.h>
#include <pybind11/stl.h>
#include "pygeneral_client.h"
#include "pygeneral_server.h"
namespace py = pybind11;
constexpr auto byref = py::return_value_policy::reference_internal;
//第一个参数要和pybind11_add_module的第一个参数一致
void init_motorcycle(py::module &m) {
m.doc() = "optional module docstring";
//修改 头文件 后,只需在 对接py的cpp 中为我们要公开的每个新函数或变量添加一行代码。
py::class_<testers::PyGeneralClient>(m, "PyGeneralClient")
.def(py::init<>())
.def("clientcall",
py::overload_cast<std::string ,std::string >( &testers::PyGeneralClient::clientcall));
py::class_<testers::PyGeneralServer>(m, "PyGeneralServer")
.def(py::init<>())
.def("servercall",
py::overload_cast<>( &testers::PyGeneralServer::servercall));
}
2.2 编译python绑定c++模块
├── CMakeLists.txt
cmake_minimum_required(VERSION 3.1)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release)
endif()
set(CMAKE_CXX_FLAGS "-O3")
set(CMAKE_CXX_FLAGS_RELEASE "-O3")
project(generalpy)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../include)
file(GLOB PYTHON_FILES
${CMAKE_CURRENT_SOURCE_DIR}/*.cpp
)
# file (GLOB PYTHON_FILES "./*.cpp" )
# Set up such that XCode organizes the files
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${PYTHON_FILES} )
# include(pybind11.cmake)
find_package(pybind11 REQUIRED)
# find_library(AUTOMOBILE_LIB automobile HINTS )
link_directories(
${CMAKE_CURRENT_SOURCE_DIR}/../../lib
)
pybind11_add_module(generalpy
${PYTHON_FILES}
)
target_link_libraries(generalpy PUBLIC general_client general_server)
install(TARGETS generalpy
COMPONENT python
LIBRARY DESTINATION "${PYTHON_LIBRARY_DIR}"
)
├── build_py_use_so.sh
#!/bin/bash
sudo rm -rf build
mkdir build
cd build
#/home/ubuntu20/miniconda3/lib/python3.11/site-packages /opt/ros/foxy/lib/python3.8/site-packages
cmake .. -DPYTHON_LIBRARY_DIR="/usr/lib/python3.8/site-packages" -DPYTHON_EXECUTABLE="/usr/bin/python3.8"
# cmake .. -DPYTHON_LIBRARY_DIR="/home/ubuntu20/miniconda3/lib/python3.11/site-packages" -DPYTHON_EXECUTABLE="/home/ubuntu20/miniconda3/bin/python"
make
sudo make install
2.3 查看生成python调用c++模块
/usr/lib/python3.8/site-packages
generalpy.cpython-38-x86_64-linux-gnu.so
3.py脚本验证AP
3.1 启动someip通信通道
env.sh
#!/bin/sh
#########################################################
# Function :AP 通用环境变量 #
# Platform :ADC #
# Version :1.0 #
# Date :2024-07-02 #
# Author :wei.liang #
# Company :seres #
#########################################################
LOCAL_PATH=/home/dell/cmake_project/cmake_prolinux/pybing11someip_general_method/script
# LOCAL_PATH=/home/ubuntu20/code/cmake_prolinux/pybing11someip_general_method/script
# LOCAL_PATH=$(pwd)
echo $LOCAL_PATH
DEPEND_PROJECT_PATH=${LOCAL_PATH}/../sdk
#sdk路径
export KOTEI_PANSHI_SDK_ROOT_PATH=${DEPEND_PROJECT_PATH}
export SDK_PATH=${DEPEND_PROJECT_PATH}
#AA应用部署路径
#cd /opt
export APP_ROOT_PATH=${LOCAL_PATH}/../run
#服务配置信息
export CM_CONFIG_PATH=$SDK_PATH/etc/com/cm_config.json
#Qos端到端服务质量配置
export QOS_CONFIG_PATH=$SDK_PATH/etc/com/
#运行时 库依赖
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$SDK_PATH/lib/ara/exec
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$SDK_PATH/lib/ara/nm
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$SDK_PATH/lib/ara/log
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$SDK_PATH/lib/ara/phm
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$SDK_PATH/lib/ara/doip
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$SDK_PATH/lib/ara/sm
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$SDK_PATH/lib/ara/ts
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$SDK_PATH/lib/ara/com
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$SDK_PATH/lib/ara/com/RawDataStreamingLib
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$SDK_PATH/lib/ara/com/ktsomeip
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$SDK_PATH/lib/ara/com/protobuf
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$SDK_PATH/lib/ara/com/secoc
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$SDK_PATH/lib/ara/iam
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$SDK_PATH/lib/ara/per
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$SDK_PATH/lib/ara/crypto
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$SDK_PATH/lib/ara/crypto/botan/lib
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$SDK_PATH/lib/ara/diag
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$SDK_PATH/lib/ara/ucm
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$SDK_PATH/lib/LSP/system
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$SDK_PATH/lib/LSP/dltlib
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$SDK_PATH/lib/LSP/processCommunicationLib
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$SDK_PATH/lib/LSP/zmqlib
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$SDK_PATH/lib/LSP/dds
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$SDK_PATH/lib/LSP/ktIpc
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$SDK_PATH/lib/LSP/attr
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$SDK_PATH/lib/LSP/acl
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$SDK_PATH/lib/LSP/sqleet
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$SDK_PATH/lib/LSP/zlib
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$SDK_PATH/lib/ara/rest
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$SDK_PATH/lib/LSP/openssl
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$SDK_PATH/lib/LSP/libcgroup
start_com.sh
#!/bin/sh
#########################################################
# Function :单独调试 开启通信通道 #
# Platform :ADC #
# Version :1.0 #
# Date :2024-07-02 #
# Author :wei.liang #
# Company :seres #
#########################################################
source ./env.sh
echo "SDK_PATH: " $SDK_PATH
echo "KOTEI_PANSHI_SDK_ROOT_PATH: " ${KOTEI_PANSHI_SDK_ROOT_PATH}
echo "APP_ROOT_PATH: " ${APP_ROOT_PATH}
echo "PDP_ACCESS_CTRL_PATH: " ${PDP_ACCESS_CTRL_PATH}
$SDK_PATH/bin/com/kt_someipd -c $SDK_PATH/etc/com/cfg-ksomeip.json -ic $SDK_PATH/etc/com/cfg-applatform.json
3.2 启动客户侧
run_client.sh
#!/bin/bash
#间接依赖的c++动态库
CS_PATH=$(pwd)
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$CS_PATH/../../lib
source ../../script/env.sh
#编译出来的py与c++交互的库
export PYTHONPATH=$PYTHONPATH:/usr/lib/python3.8/site-packages
# export PYTHONPATH=$PYTHONPATH:/home/ubuntu20/miniconda3/lib/python3.11/site-packages
./client.py
client.py
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import signal
import sys
# print(sys.path)
# sys.path.append("../build/")
# from automobile import Motorcycle
import generalpy
import json
# 手动写的绑定代码
# c = generalpy.PyGeneralClient()
# binder生成的代码
def handler(signum, frame):
print(f"捕获信号 {signum}, 执行清理...")
sys.exit(0) # 显式退出
c = generalpy.PyGeneralClient()
data = {"name": "Alice","age": 30,"address": [{"street": "yubei","city": "chongqing"},{"street": "huangpu","city": "shanghai"}]};
json_str = json.dumps(data)
python_dict = json.loads(c.clientcall("function2",json_str))
print(f"py client recv message...")
print(python_dict["respdata"])
signal.signal(signal.SIGINT, handler)
signal.signal(signal.SIGTERM, handler)
3.3 启动服务侧
run_server.sh
#!/bin/bash
#间接依赖的c++动态库
CS_PATH=$(pwd)
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$CS_PATH/../../lib
source ../../script/env.sh
#编译出来的py与c++交互的库
export PYTHONPATH=$PYTHONPATH:/usr/lib/python3.8/site-packages
# export PYTHONPATH=$PYTHONPATH:/home/ubuntu20/miniconda3/lib/python3.11/site-packages
./server.py
server.py
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import sys
# print(sys.path)
# sys.path.append("../build/")
# from automobile import Motorcycle
import generalpy
# 手动写的绑定代码
# c = generalpy.PyGeneralServer()
# binder生成的代码
c = generalpy.PyGeneralServer()
c.servercall()
3.4 结果展示
通道启动
dell@C24197:~/cmake_project/cmake_prolinux/pybing11someip_general_method/script$ ./start_com.sh
/home/dell/cmake_project/cmake_prolinux/pybing11someip_general_method/script
SDK_PATH: /home/dell/cmake_project/cmake_prolinux/pybing11someip_general_method/script/../sdk
KOTEI_PANSHI_SDK_ROOT_PATH: /home/dell/cmake_project/cmake_prolinux/pybing11someip_general_method/script/../sdk
APP_ROOT_PATH: /home/dell/cmake_project/cmake_prolinux/pybing11someip_general_method/script/../run
PDP_ACCESS_CTRL_PATH:
2025-03-10 16:06:09 363[KT_SOMEIP] main.cpp:101 main() Start kt_someipd. ver:ksomeip.release.20240112.1.01.018
服务侧终端信息
2025/03/10 16:42:08.321195 259176293 000 ECU1 comm comm log info V 3 [/home/dell/ADC/adc10sdk/ap_sdk_src/com/src/com_sdk/dispatch/skeleton/skeleton_adapter.cpp 190 [MAIN-FLOW] comm skeleton offerservice success]
2025/03/10 16:42:08.321296 259176294 000 ECU1 comm SERV log info V 1 [create service generalMethodServ success]
2025/03/10 16:42:12.981668 259222898 000 ECU1 comm comm log verbose V 3 [/home/dell/ADC/adc10sdk/ap_sdk_src/com/src/com_sdk/dispatch/skeleton/skeleton_adapter.cpp 266 [IN/OUT] comm skeleton recv call ]
2025/03/10 16:42:12.981853 259222900 000 ECU1 comm comm log verbose V 4 [/home/dell/ADC/adc10sdk/ap_sdk_src/com/src/com_sdk/dispatch/skeleton/ksomeip/ksomeip_skeleton_instance.cpp 74 [MAIN-FLOW] comm ksomeip skeleton ProcessNextCall name : generalMethodInterface]
generalMethodServImpl::generalMethodInterface begin
2025/03/10 16:42:12.981967 259222901 000 ECU1 comm SERV log debug V 1 [generalMethodServProvide::generalMethodInterface begin]
2025/03/10 16:42:12.982007 259222902 000 ECU1 comm SERV log debug V 2 [generalMethodInterface rec from service inner data 10]
2025/03/10 16:42:12.982041 259222902 000 ECU1 comm SERV log debug V 2 [generalMethodInterface rec from client data {"DataDealMethod":"function2","DataList":"{\"name\": \"Alice\", \"age\": 30, \"address\": [{\"street\": \"yubei\", \"city\": \"chongqing\"}, {\"street\": \"huangpu\", \"city\": \"shanghai\"}]}"}]
MessageDispatcher::callFunction DataDealMethod "function2"
MessageDispatcher::callFunction DataList "{\"name\": \"Alice\", \"age\": 30, \"address\": [{\"street\": \"yubei\", \"city\": \"chongqing\"}, {\"street\": \"huangpu\", \"city\": \"shanghai\"}]}"
ControlBaseHandler::GetFuncSize 3
CBICQRec::function2 called
CBICQRec Inner JSON name: {"name": "Alice", "age": 30, "address": [{"street": "yubei", "city": "chongqing"}, {"street": "huangpu", "city": "shanghai"}]}
CBICQRec Inner JSON name: "Alice"
CBICQRec Inner JSON age: 30
CBICQRec Inner JSON city: "chongqing"
2025/03/10 16:42:12.982143 259222903 000 ECU1 comm SERV log debug V 2 [return data {"respdata":"CBICQRec::function2","retcode":0}]
generalMethodServImpl::generalMethodInterface end
2025/03/10 16:42:12.982177 259222903 000 ECU1 comm SERV log debug V 1 [generalMethodServProvide::generalMethodInterface end]
2025/03/10 16:42:12.982238 259222904 000 ECU1 comm comm log verbose V 3 [/home/dell/cmake_project/cmake_prolinux/pybing11someip_general_method/sdk/include/ara/com/internal/skeleton/methods/skeleton_method_impl.h 112 [MAIN-FLOW] comm skeleton methodadapter processnextmethodcall outputt call ok]
2025/03/10 16:42:12.982338 259222905 000 ECU1 comm comm log verbose V 14 [/home/dell/ADC/adc10sdk/ap_sdk_src/com/src/com_sdk/runtime_ktsomeip/ktsomeip_runtime_impl.cpp 230 [IN/OUT] comm ksomeip service Response. serviceid= 4099 , instanceid= 1 , InterfaceVersion 1 , method= 2 , sessionid= 1 , payloadlen= 62]
客户侧终端信息
2025/03/10 16:42:12.983399 259222915 000 ECU1 comm comm log verbose V 4 [/home/dell/cmake_project/cmake_prolinux/pybing11someip_general_method/sdk/include/ara/com/internal/proxy/methods/method_adapter.h 496 [MAIN-FLOW] comm proxy methodadapter<output> recvresponsehandle receive response sucess. sessionid= 1]
2025/03/10 16:42:12.983480 259222916 000 ECU1 comm CLE- log debug V 2 [rec message is {"respdata":"CBICQRec::function2","retcode":0}]
recv data : {"respdata":"CBICQRec::function2","retcode":0}
recv data 1: {"respdata":"CBICQRec::function2","retcode":0}
relase thread
py client recv message...
CBICQRec::function2
4.binder使用
4.1 自动生成python绑定c++的源文件
make_someip_general_method.sh 生成文件替换“2.1 手动编写python绑定c++源文件”automobile.cpp general_py.cpp。其他和"2.2 编译python绑定c++模块"、"2.3 查看生成python调用c++模块"保持一致
#!/bin/bash
# make binding gereration via bash
# Generate all_includes file
grep -rh "#include" include/* | sort -u > all_bash_includes.hpp
# Makde bindings dir from scratch \
rm -rf ./bash_bindings/ && mkdir bash_bindings/
# Make bindings code
# --root-module generalpy 生成的python模块
# --prefix $PWD/bash_bindings/ 生成的python绑定c++的代码
# --bind testers 绑定的命名空间 和被绑定的c++头文件内命名空间一致
/usr/local/bin/binder \
--root-module generalpy \
--prefix $PWD/bash_bindings/ \
--bind testers \
all_bash_includes.hpp \
-- -std=c++11 -I$PWD/include \
-DNDEBUG
# 将生成物移动到 “2.1 python绑定c++源文件”所在目录
cp bash_bindings/* ./test/python_binder
4.2 验证
修改"3.py脚本验证AP" 两个py脚本,自动生成的模块多了个命名空间testers
---------server.py-------
c = generalpy.testers.PyGeneralServer()
---------client.py-------
c = generalpy.testers.PyGeneralClient()
结果和“3.4 结果展示”一致
更多推荐
所有评论(0)