简体   繁体   English

在无法访问库源的情况下使用 swig c++ 到 python

[英]Using swig c++ to python with no access to library source

I'm new to swig and tried scouring the documentation for an answer but I either missed it or didn't recognize the answer when I saw it.我是 swig 的新手,并尝试搜索文档以寻找答案,但我要么错过了它,要么在看到它时没有认出答案。

I have a large C++ library from a third party for which I have no source code except the header.我有一个来自第三方的大型 C++ 库,除了头文件我没有源代码。 I need to access a few of the APIs from python and several of the APIs have function prototypes similar to:我需要从 python 访问一些 API,其中一些 API 具有类似于以下内容的函数原型:

int foo(int& a, int& b, int& c);

I've created a .i file that looks like:我创建了一个 .i 文件,如下所示:

%module myWrapper 
%{   
  #include libraryHeader.h
%}
extern int foo(int& m1, int& m2, int& bf);

This goes through swig, the g++ compiler and linker with no problems.这通过 swig、g++ 编译器和链接器没有问题。 I can import the module into python but when I call it I get the following error:我可以将模块导入 python,但是当我调用它时,出现以下错误:

TypeError: in method 'foo', argument 1 of type 'int &'类型错误:在方法“foo”中,“int &”类型的参数 1

I've declared 3 int variables like m1 = 0;我已经声明了 3 个 int 变量,如 m1 = 0; m2 = 0; m2 = 0; bf = 0 so I am passing something in. Is there a way to do this using the typemaps.i library or explicitly using typemaps? bf = 0 所以我传入了一些东西。有没有办法使用 typemaps.i 库或明确使用 typemaps 来做到这一点? The documentation seems a bit vague on the subject.文档在这个主题上似乎有点含糊。

Thanks in advance, Paul提前致谢,保罗

SWIG needs hints where parameters are not simply inputs. SWIG 需要提示参数不是简单的输入。 These hints are provided by typemaps.这些提示由类型映射提供。 You either need to define typemaps or use pre-defined ones (seetypemaps.i ).您需要定义类型映射或使用预定义的类型映射(请参阅typemaps.i )。

Here's an example:下面是一个例子:

%module test

%{
    int foo(int& a, int& b, int& c)
    {
        int ret = a + b + c;
        a = 10;
        b = 20;
        c = 30;
        return ret;
    }
%}

%include <typemaps.i>
int foo(int& INOUT, int& INOUT, int& INOUT);

With the INOUT typemap, Python can pass integers into a function with for int* or int& , and the return value will be a tuple of the original return value and any output arguments.使用INOUT映射,Python 可以将整数传递给带有 for int*int&的函数,返回值将是原始返回值和任何输出参数的元组。 Compiling the SWIG result above and using in Python looks like this:编译上面的 SWIG 结果并在 Python 中使用如下所示:

>>> import test
>>> test.foo(1,2,3)
[6, 10, 20, 30]

You can update variables with code like this:您可以使用如下代码更新变量:

>>> a,b,c = 1,2,3
>>> r,a,b,c = test.foo(a,b,c)
>>> r
6
>>> a,b,c
(10, 20, 30)

Note you can also %apply existing typemaps to types so if using %include "libraryHeader.h" instead of directly declaring functions you can use the following to generically apply the INOUT typemap to all int& parameters:请注意,您还可以%apply现有类型映射应用于类型,因此如果使用%include "libraryHeader.h"而不是直接声明函数,您可以使用以下内容将INOUT类型%include "libraryHeader.h"一般应用于所有int&参数:

%apply int &INOUT { int& };
%include "libraryHeader.h"

I've answered my own question with the help of others on this thread and stubbornness.我已经在这个线程和固执的其他人的帮助下回答了我自己的问题。 I created a .i file that looks like:我创建了一个 .i 文件,如下所示:

%module myWrapper

%include "typemaps.i"

%{
 #include "libraryHeader.h"
 typedef unsigned int MY_RESULT;
%}

typedef unsigned int MY_RESULT;
extern MY_RESULT MyGetVersion(int& OUTPUT, int& OUTPUT, int& OUTPUT, int& 
OUTPUT);
extern MY_RESULT MyGetDeviceDriverVersion(int deviceType, int& OUTPUT, int& 
OUTPUT, int& OUTPUT, int& OUTPUT);

It swigs, compiles and links cleanly and a very simple python test script returns the expected results.它干净利落地执行、编译和链接,一个非常简单的 python 测试脚本返回预期的结果。 The script looks like:该脚本如下所示:

#!/usr/bin/python3

import myWrapper

ret = 0    # function return value
maj = 0    # major version
min = 0    # minor version
bugFix = 0 # bug fix number
build = 0  # build

#
# Because of the typemap defined in myWrapper.i, we don't need to supply function arguments. 
# The results are returned by the function call as seen below...
#
ret, maj, min, bugFix, build = myWrapper.MyGetVersion()

#
# See what we got 
#
print('function return: '+str(ret)+' Maj: '+str(maj)+' Min: '+str(min)+' BugFix:'+str(bugFix)+' Build: '+str(build))

#
# This call returns the same information that the call above does but adds an input argument
# that specifies the Device Catagory. 0 is PCI
#
ret, maj, min, bugFix, build = myWrapper.MyGetDeviceDriverVersion(0)

print('function return: '+str(ret)+' Maj: '+str(maj)+' Min: '+str(min)+' BugFix: '+str(bugFix)+' Build: '+str(build))

The result of running this script provides the expected results:运行此脚本的结果提供了预期的结果:

function return: 0 Maj: 5 Min: 31 BugFix: 0 Build: 109
function return: 0 Maj: 4 Min: 26 BugFix: 4 Build: 253

Thank you all very much for the help and I hope that this answer can help someone else.非常感谢大家的帮助,我希望这个答案可以帮助别人。

Paul保罗

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM