参考景色借刀破的文章并在GPT帮助下使用Swig封装C++格式API用于Python调用

前置条件:

  • VS2022
  • Python环境(用conda创建或者下载对应版本的环境都可)
  • SWIG
  • iconv文件(.lib与.h)从借刀破提供的仓库中下载
    (注:本文遵循景色教程中版本使用Python3.7.2与SWIG4.0.0)

xxx.i文件模板为:

/*
 * xxxapi.i
 * 用 SWIG 把 C++ API 封装成 Python 模块
 */

/*
 * 1. 定义模块名
 *
 * Python 导入方式:
 *     import xxxmdapi
 *
 * directors="1":
 *     开启 Python 继承 C++ 回调类的能力。
 *     因为 XXXSpi 里面有 OnRspXXX / OnRtnXXX 这类 virtual 回调。
 */
%module(directors="1") xxxapi


/*
 * 2. 这些 include 会原样写进生成的 xxxapi_wrap.cxx
 *
 * 作用:
 *     让 C++ 编译器知道 XXXApi、XXXSpi、各种行情结构体的定义。
 */
%{
#include "XXX.h"
#include "XXXApi.h"
#include "iconv.h"
%}


/*
 * 3. char[] / char* 输出编码转换
 *
 * 国产行情接口很多 char 字段可能是 GB2312/GBK。
 * Python3 使用 UTF-8。
 *
 * 这段会把 C++ char 数组转换成 Python str。
 * 如果字段只是 InstrumentID、ExchangeID 这种 ASCII,保留也没问题。
 */
%typemap(out) char[ANY], char[] {
    if ($1) {
        iconv_t cd = iconv_open("utf-8", "gb2312");
        if (cd != reinterpret_cast<iconv_t>(-1)) {
            char buf[4096] = {};
            char **in = &$1;
            char *out = buf;
            size_t inlen = strlen($1);
            size_t outlen = sizeof(buf);

            if (iconv(cd, (const char **) in, &inlen, &out, &outlen) != static_cast<size_t>(-1)) {
                size_t size = strlen(buf);
                resultobj = SWIG_FromCharPtrAndSize(buf, size);
            }

            iconv_close(cd);
        }
    }
}


/*
 * 4. 指定回调类启用 director
 *
 * 这是最关键的一行。
 * 没有它,Python 继承 XXXSpi 后,C++ 回调不会进入 Python。
 */
%feature("director") XXXSpi;


/*
 * 5. SWIG 标准类型支持
 */
%include "stdint.i"      // 支持 uint16_t / uint32_t / int64_t 等
%include "typemaps.i"    // 支持常见指针参数转换
%include "std_string.i"  // 支持 std::string


/*
 * 6. 真正暴露给 Python 的头文件
 *
 * 顺序:先结构体,后 API。
 */
%include "XXX.h"
%include "XXX.h"

运行swig命令时想切换到想要使用的python环境下
visual studio操作时注意细节
在这里插入图片描述

  1. 问题:生成的_swag.cxx文件中报错信息为未定义标识符 “SWIG_FromCharPtrAndSize”
    解决方法:
    将SWIG_FromCharPtrAndSize改为PyUnicode_FromStringAndSize
    原因:

    PyString_FromStringAndSize is replaced with PyUnicode_FromStringAndSize in Python3, and SWIG_FromCharPtrAndSize will choose the right one with the check “#if PY_VERSION_HEX >= 0x0300000”.
    出处

  2. 生成解决方案报错:“size_t libiconv(libiconv_t,char **,size_t *,char **,size_t *)”: 无法将参数 2 从“const char **”转换为“char **”
    if (iconv(cd, (const char **) in, &inlen, &out, &outlen) != static_cast<size_t>(-1))一句中删除(const char **)

  3. demo中报错:swig/python detected a memory leak of type ‘uint32_t *’, no destructor found.
    .i文件中配置加入SWIG,模板中第5点

  4. python list问题,在.i中加入具体处理方式 转换list(根据具体代码)

  5. 运行demo时,if判断中一个常量未定义
    解决方法:
    需要在.i中使用constant命令导出
    原因:
    在cpp文件中#define定义的常量不一定会被自动导出

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐