cpp混合python编程
项目结构
.
├── CMakeLists.txt
├── main.cpp
├── scripts
│ ├── __pycache__
│ └── test.py
└── vendor
└── python_env
注意点:不要把 venv
当作 PYTHONHOME
,只用作依赖库存放,并在运行时将它加入 sys.path
构建 python 虚拟环境
python -m venv python_env
source python_env/bin/active
pip install pybind11
CMakeLists.txt
cmake_minimum_required(VERSION 3.15)
project(CppPythonEmbedded)
set(CMAKE_CXX_STANDARD 17)
# 设置 Python 路径为本地虚拟环境
set(Python3_ROOT_DIR "${CMAKE_SOURCE_DIR}/vendor/python_env")
set(Python3_EXECUTABLE "${Python3_ROOT_DIR}/bin/python3")
# 查找本地 Python
find_package(Python3 REQUIRED COMPONENTS Interpreter Development)
# 查找本地 pybind11
execute_process(
COMMAND ${Python3_EXECUTABLE} -m pybind11 --includes
OUTPUT_VARIABLE PYBIND11_INCLUDES
OUTPUT_STRIP_TRAILING_WHITESPACE
)
execute_process(
COMMAND ${Python3_EXECUTABLE} -m pybind11 --cmakedir
OUTPUT_VARIABLE PYBIND11_DIR
OUTPUT_STRIP_TRAILING_WHITESPACE
)
list(APPEND CMAKE_PREFIX_PATH ${PYBIND11_DIR})
find_package(pybind11 REQUIRED)
# 添加可执行文件
add_executable(main main.cpp)
# 链接 pybind11 嵌入库
target_link_libraries(main PRIVATE pybind11::embed)
# 包含 Python 头文件
target_include_directories(main PRIVATE ${Python3_INCLUDE_DIRS})
target_link_libraries(main PRIVATE ${Python3_LIBRARIES})
简单脚本执行
main.cpp
#include <iostream>
#include <pybind11/embed.h>
namespace py = pybind11;
int main() {
py::scoped_interpreter guard{};
py::module sys = py::module::import("sys");
// 添加 venv site-packages
sys.attr("path").attr("insert")(0, "./vendor/python_env/lib/python3.12/site-packages");
// 添加脚本目录
sys.attr("path").attr("insert")(0, "./scripts");
py::module example = py::module::import("test");
auto res_add = example.attr("add")(1, 1).cast<int>();
auto res_mult = example.attr("multiply")(2, 3).cast<int>();
std::cout << "add: " << res_add << std::endl;
std::cout << "mult: " << res_mult << std::endl;
}
test.py
def add(a, b):
return a + b
def multiply(a, b):
return a * b
构建运行
./build/main
add: 2
mult: 6
引入依赖
比如使用 matplotlib
使用依赖:
pip install matplotlib
main.cpp
#include <pybind11/embed.h>
#include <pybind11/stl.h>
#include <iostream>
namespace py = pybind11;
int main() {
// -----------------------------
// 设置 Python 环境(跨平台)
// -----------------------------
#ifdef _WIN32
// Windows 下可用 embeddable Python 或系统 Python
// _putenv_s("PYTHONHOME", ".\\vendor\\python_env"); // 不建议直接指向 venv
#else
// Linux/macOS
// setenv("PYTHONHOME", "/usr", 1); // 可选,系统 Python 默认
#endif
py::scoped_interpreter guard{};
py::module sys = py::module::import("sys");
// 添加 scripts
sys.attr("path").attr("insert")(0, "./scripts");
// 添加虚拟环境 site-packages
#ifdef _WIN32
sys.attr("path").attr("insert")(0, ".\\vendor\\python_env\\Lib\\site-packages");
#else
sys.attr("path").attr("insert")(0, "./vendor/python_env/lib/python3.12/site-packages");
#endif
py::module plot_example = py::module::import("plot_test");
std::string filename = plot_example.attr("plot_sin")().cast<std::string>();
std::cout << "Saved plot to " << filename << std::endl;
}
plot_test.py
import matplotlib.pyplot as plt
import numpy as np
def plot_sin():
x = np.linspace(0, 2*np.pi, 100)
y = np.sin(x)
plt.plot(x, y)
plt.title("Sine Wave")
plt.xlabel("x")
plt.ylabel("sin(x)")
plt.savefig("sin_wave.png") # 保存图像
return "sin_wave.png"
comment:
- Valine
- LiveRe
- ChangYan