跳到主要内容 使用 Boost::Python 将 C++ 库封装为 Python 扩展 | 极客日志
Python
使用 Boost::Python 将 C++ 库封装为 Python 扩展 本文介绍了在跨语言系统交互中,因不同语言对 JSON Schema 标准版本支持不一致导致的问题。解决方案是利用 C++ 编写统一的核心库,并通过 Boost::Python 将其封装为 Python 扩展模块。内容涵盖从环境配置、C++ 类封装、编译动态库、使用 distutils 构建安装到最终测试验证的完整流程。同时补充了常见链接错误排查及打包分发的建议,帮助开发者实现高性能的 Python 功能扩展。
CodeArtist 发布于 2025/2/6 0 浏览前言
在构建大型分布式系统时,为了保证数据在系统上下游的自动校验,避免数据结构异常带来的系统稳定性问题,通常会采用 JSON 格式进行数据交互。此时,可以采用 JSON Schema 来定义接口规范,并利用 JSON Schema Validator 来校验接口响应结构的合法性。
然而,系统中不同子系统的实现语言往往并非一致。虽然主流编程语言都提供了 JSON Schema Validator 的具体实现,但不同语言支持的 JSON Schema 标准版本(Draft)并不完全统一,这会给后续的系统集成带来混乱。例如:
Java: json-schema-validator 支持 Draft 4
C++: json-schema-validator 支持 Draft 7
Python: jsonschema 支持 Draft 7 目前大多数语言(如 Java, Golang, PHP, Lua 等)都支持 C/C++ 的扩展机制。因此,最佳实践是用 C/C++ 编写核心逻辑库,再为其他语言提供统一的扩展包。本文详细介绍如何利用 Boost::Python 库将 C++ 的 nlohmann_json_schema_validator 封装为 Python 扩展,并介绍如何使用 distutils 进行编译与分发。
Python 调用 C/C++ 的方式 主要有两种方式可以实现 Python 调用 C/C++ 编写的库:
ctypes :Python 内置的外部函数库,提供 C 兼容的数据类型,允许在 DLL 或共享库中调用函数。
Python Extension API :Python 官方提供的扩展机制,通过编写 C/C++ 代码生成 .so (Linux/Mac) 或 .pyd (Windows) 文件,被 Python 解释器直接加载。
ctypes 加载 so 文件 ctypes 是 Python 封装的 API 函数库。其中 cdll = <ctypes.LibraryLoader object> 是一个库加载器对象,调用 cdll.LoadLibrary 便可调用 C/C++ 的 so 库。
import ctypes
lib = ctypes.CDLL('./libmylib.so' )
lib.my_function.argtypes = [ctypes.c_int]
lib.my_function.restype = ctypes.c_int
result = lib.my_function(10 )
此处不再对如何使用 ctypes 模块加载 so 文件做过多的介绍,具体可以参考其官方文档。对于复杂的类封装和内存管理,直接使用 ctypes 较为繁琐且容易出错。
使用 Python 扩展 该方式是 Python 为整合其它语言而提供的一种扩展机制。Python 的可扩展性具有如下优点:
方便为语言增加新功能
具有高度可定制性
可以实现底层代码复用
性能更优(相比 ctypes 的边界转换开销)
该方式的具体使用可以参考 Python 官方文档 Building C and C++ Extensions 。接下来要讲的例子就是利用了'代码复用'的优点。
Python 提供了 Python/C++ API 用来实现 Python 和 C++ 的交互。然而,直接使用这些 API 来完成交互会存在很多重复工作,例如手动处理引用计数、类型转换等。Boost::Python 则对 Python/C++ API 进行了抽象和包装,使得 Python 和 C++ 的交互更加方便,类似于 pybind11 但基于 Boost 生态。
Boost::Python 封装 C/C++ 扩展 接下来我们介绍如何利用 Boost::Python 为 nlohmann_json_schema_validator 增加 Python 支持。
nlohmann_json_schema_validator 是一个基于 JSON Schema 验证 JSON 文档的 C++ 库,它本身应验证符合 JSON Schema Validation draft-7 标准。
编译 nlohmann json schema validator 库 该库支持产出可执行的 bin 文件以及可供其他项目使用的动态库。为了可以将该扩展包装成 Python 扩展,我们需要先生成该库的动态库。
首先根据 nlohmann_json_schema_validator 的编译文档编译出动态库。通常需要使用 CMake 配置,确保开启 BUILD_SHARED_LIBS 选项。
Boost::Python 封装 C/C++ 代码 在安装 Boost 的时候,虽然 Boost 的头文件中存在 Boost::Python 相关的 hpp 文件,但是默认却没有该动态库。因此,在使用 Boost::Python 之前,首先需要安装该库。
brew install boost-python3
sudo apt-get install libboost-python-dev
然后,我们用 C++ 编写 class json_validator_python 来封装 nlohmann_json_schema_validator 库,并利用 Boost::Python 来导出。
#include <iomanip>
#include <iostream>
#include <nlohmann/json-schema.hpp>
#include <boost/python.hpp>
using namespace boost::python;
class JSON_SCHEMA_VALIDATOR_API json_validator_python
{
private :
nlohmann::json_schema::json_validator validator;
public :
json_validator_python () {}
void set_root_schema (const std::string &json_string)
{
auto parsed = nlohmann::json::parse (json_string.begin (), json_string.end ());
validator.set_root_schema (parsed);
}
void validate (const std::string &json_string) const
{
auto data = nlohmann::json::parse (json_string.begin (), json_string.end ());
validator.validate (data);
}
};
BOOST_PYTHON_MODULE (json_schema_validator)
{
class_ <json_validator_python, boost::noncopyable>("json_validator_python" )
.def ("set_root_schema" , &json_validator_python::set_root_schema)
.def ("validate" , &json_validator_python::validate)
;
}
如上所示的 BOOST_PYTHON_MODULE 代码,目的是导出类及成员方法。这些导出的类和方法可以在 Python 中直接导入并实例化。关于 Boost::Python 更详细的使用,可以参考其官方文档。
编译并产出 Python 扩展 使用 g++ 进行编译。注意需要指定正确的头文件路径和库路径。
export JSON_SCHEMA_PATH=/path/to/nlohmann-json-schema-validator
export BOOST_PATH=/usr/local/opt/boost
export PYTHON_INCLUDE=$(python3-config --includes)
g++ --std=c++11 -fPIC -c jsv_python.cpp \
-I${JSON_SCHEMA_PATH} /src \
-I/usr/include/nlohmann \
-I${BOOST_PATH} /include \
-I${PYTHON_INCLUDE}
g++ --std=c++11 -shared \
-L${JSON_SCHEMA_PATH} /build/lib \
-L${BOOST_PATH} /lib \
-L$(python3-config --prefix)/lib \
-lnlohmann_json_schema_validator \
-lboost_python38 -lpython3.8 \
-o json_schema_validator.so jsv_python.o
如上的指令,会生成封装之后的 Python 扩展:json_schema_validator.so。
测试 python 扩展 在当前目录执行如下的 Python 代码,可以发现,我们封装的扩展已经可以当做 Python 扩展来导入并使用了。
import json_schema_validator as jsv
validator = jsv.json_validator_python()
isValidator = True
try :
validator.set_root_schema('{"type":"object", "properties": {"a":{"type": "string"}}}' )
validator.validate('{"a":"1"}' );
except Exception as e:
print (f"Validation Error: {e} " )
isValidator = False
print (isValidator)
使用 distutils 编译并分发扩展 为了使用方便,推荐使用 distutils 或 setuptools 模块编译 Python 扩展,这样可以自动化处理依赖路径。
from distutils.core import setup, Extension
import os
os.environ["CC" ] = "g++"
os.environ["CXX" ] = "g++"
module1 = Extension('json_schema_validator' ,
include_dirs = ['../../src' ,
'../../' ,
'/usr/local/opt/boost/include' ],
libraries = ['boost_python38' , 'python3.8' ,
'nlohmann_json_schema_validator' ],
library_dirs = ['/usr/local/opt/boost/lib' ,
'.' ],
sources = ['jsv_python.cpp' ],
extra_compile_args=['--std=c++11' ],
extra_link_args=['--std=c++11' ])
setup(
name='json-schema-validator' ,
version='1.0' ,
description='json schema validator extension' ,
ext_modules=[module1]
)
$ python3 setup.py build
$ python3 setup.py install
安装后,可能需要设置环境变量以便运行时能找到动态库:
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH :/usr/local/lib/python3.8/site-packages/json_schema_validator
常见问题与排查
1. 找不到模块错误 如果报错 ImportError: No module named json_schema_validator,请检查以下几点:
确认 setup.py 中的 name 参数与生成的 .so 文件名一致。
确认 Python 环境是否正确激活。
检查 sys.path 是否包含了安装目录。
2. 动态库链接错误 如果运行时报错 undefined symbol 或 library not found,通常是链接顺序或路径问题。
确保 -L 参数指向了包含 .so 文件的目录。
确保 -l 参数对应的库名称正确(去掉前缀 lib 和后缀 .so)。
在 macOS 上,可能需要设置 DYLD_LIBRARY_PATH 而不是 LD_LIBRARY_PATH。
3. 跨平台兼容性
Windows : 动态库后缀为 .pyd,依赖项需放在同一目录下或通过 PATH 环境变量添加。
Linux : 注意 glibc 版本兼容性,尽量在较新的系统上编译。
macOS : 注意架构兼容性(x86_64 vs arm64),建议使用 Universal 二进制或针对当前架构编译。
进阶:打包为 Wheel 为了更方便地分发,建议将扩展打包为 Wheel 格式(.whl)。这需要安装 wheel 包并使用 bdist_wheel 命令。
pip install wheel
python setup.py bdist_wheel
生成的 .whl 文件可以直接通过 pip install 安装,无需用户自行编译 C++ 代码,极大降低了部署成本。
总结 本文详细介绍了利用 Boost::Python 将 C++ 库封装为 Python 扩展的完整流程。从环境准备、C++ 代码封装、编译链接到最终的分发测试,涵盖了关键步骤。通过这种方式,开发者可以利用 C++ 的高性能特性增强 Python 应用的功能,同时保持 Python 开发的便捷性。在处理跨语言数据交互和性能敏感模块时,这种混合编程模式是非常有效的解决方案。
相关免费在线工具 curl 转代码 解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online
Base64 字符串编码/解码 将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
Base64 文件转换器 将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
Markdown转HTML 将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
HTML转Markdown 将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online
JSON 压缩 通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online