[python] 파이썬에서 C / C ++를 호출 하시겠습니까?

C 또는 C ++ 라이브러리에 파이썬 바인딩을 구성하는 가장 빠른 방법은 무엇입니까?

(중요한 경우 Windows를 사용하고 있습니다.)



답변

Boost.Python을 살펴 봐야 합니다. 다음은 웹 사이트에서 가져온 짧은 소개입니다.

Boost Python Library는 Python과 C ++를 인터페이스하기위한 프레임 워크입니다. C ++ 컴파일러만으로도 특별한 도구를 사용하지 않고도 C ++ 클래스 함수와 객체를 파이썬에 빠르고 완벽하게 노출시킬 수 있습니다. C ++ 인터페이스를 방해하지 않고 감싸도록 설계되었으므로 C ++ 코드를 변경하기 위해 전혀 변경하지 않아도되므로 Boost.Python은 타사 라이브러리를 Python에 노출시키는 데 이상적입니다. 라이브러리에서 고급 메타 프로그래밍 기술을 사용하면 사용자의 구문이 단순 해져 래핑 코드가 일종의 선언적 인터페이스 정의 언어 (IDL)를 살펴볼 수 있습니다.


답변

ctypes 모듈은 표준 라이브러리의 일부이므로 swig 보다 안정적이고 널리 사용 가능하므로 항상 문제가 발생 합니다.

ctypes를 사용하면 파이썬에 대한 컴파일 시간 종속성을 충족시켜야하며 바인딩은 ctypes가있는 모든 파이썬에서 컴파일됩니다.

foo.cpp라는 파일에서 대화하려는 간단한 C ++ 예제 클래스가 있다고 가정하십시오.

#include <iostream>

class Foo{
    public:
        void bar(){
            std::cout << "Hello" << std::endl;
        }
};

ctype은 C 함수와 만 대화 할 수 있으므로 extern “C”로 선언하는 함수를 제공해야합니다.

extern "C" {
    Foo* Foo_new(){ return new Foo(); }
    void Foo_bar(Foo* foo){ foo->bar(); }
}

다음으로 이것을 공유 라이브러리로 컴파일해야합니다

g++ -c -fPIC foo.cpp -o foo.o
g++ -shared -Wl,-soname,libfoo.so -o libfoo.so  foo.o

그리고 마지막으로 파이썬 래퍼를 작성해야합니다 (예 : fooWrapper.py)

from ctypes import cdll
lib = cdll.LoadLibrary('./libfoo.so')

class Foo(object):
    def __init__(self):
        self.obj = lib.Foo_new()

    def bar(self):
        lib.Foo_bar(self.obj)

일단 당신이 그것을 호출 할 수 있습니다

f = Foo()
f.bar() #and you will see "Hello" on the screen


답변

가장 빠른 방법은 SWIG를 사용하는 것 입니다.

SWIG 튜토리얼의 예 :

/* File : example.c */
int fact(int n) {
    if (n <= 1) return 1;
    else return n*fact(n-1);
}

인터페이스 파일 :

/* example.i */
%module example
%{
/* Put header files here or function declarations like below */
extern int fact(int n);
%}

extern int fact(int n);

유닉스에서 파이썬 모듈 만들기 :

swig -python example.i
gcc -fPIC -c example.c example_wrap.c -I/usr/local/include/python2.7
gcc -shared example.o example_wrap.o -o _example.so

용법:

>>> import example
>>> example.fact(5)
120

python-dev가 있어야합니다. 또한 일부 시스템에서 파이썬 헤더 파일은 설치 방법에 따라 /usr/include/python2.7에 있습니다.

튜토리얼에서 :

SWIG는 거의 모든 언어 기능을 지원하는 상당히 완전한 C ++ 컴파일러입니다. 여기에는 전처리, 포인터, 클래스, 상속 및 C ++ 템플릿이 포함됩니다. SWIG를 사용하여 구조와 클래스를 대상 언어의 프록시 클래스로 패키지하여 기본 기능을 매우 자연스럽게 노출 할 수 있습니다.


답변

높은 수준의 데이터 유형 (파이썬 목록과 다차원 STL 벡터)을 연결하기 위해이 페이지에서 Python <-> C ++ 바인딩으로 여행을 시작했습니다. 🙂

ctypesboost.python (및 소프트웨어 엔지니어 아님)을 기반으로 솔루션을 시도한 결과 높은 수준의 데이터 유형 바인딩이 필요할 때 복잡하다는 것을 알았습니다 .SWIG 을 찾았습니다. 는 이러한 경우에 훨씬 더 간단 .

따라서이 예에서는 SWIG를 사용하며 Linux에서 테스트되었지만 SWIG를 사용할 수 있으며 Windows에서도 널리 사용됩니다.

목표는 2D STL 벡터 형태의 행렬을 가져와 각 행의 평균을 1D STL 벡터로 반환하는 Python에서 C ++ 함수를 사용할 수있게하는 것입니다.

C ++ 코드 ( “code.cpp”)는 다음과 같습니다.

#include <vector>
#include "code.h"

using namespace std;

vector<double> average (vector< vector<double> > i_matrix) {

  // Compute average of each row..
  vector <double> averages;
  for (int r = 0; r < i_matrix.size(); r++){
    double rsum = 0.0;
    double ncols= i_matrix[r].size();
    for (int c = 0; c< i_matrix[r].size(); c++){
      rsum += i_matrix[r][c];
    }
    averages.push_back(rsum/ncols);
  }
  return averages;
}

동등한 헤더 ( “code.h”)는 다음과 같습니다.

#ifndef _code
#define _code

#include <vector>

std::vector<double> average (std::vector< std::vector<double> > i_matrix);

#endif

먼저 C ++ 코드를 컴파일하여 객체 파일을 만듭니다.

g++ -c -fPIC code.cpp

그런 다음 C ++ 함수에 대한 SWIG 인터페이스 정의 파일 ( “code.i”)을 정의합니다 .

%module code
%{
#include "code.h"
%}
%include "std_vector.i"
namespace std {

  /* On a side note, the names VecDouble and VecVecdouble can be changed, but the order of first the inner vector matters! */
  %template(VecDouble) vector<double>;
  %template(VecVecdouble) vector< vector<double> >;
}

%include "code.h"

SWIG를 사용하여 SWIG 인터페이스 정의 파일에서 C ++ 인터페이스 소스 코드를 생성합니다.

swig -c++ -python code.i

마지막으로 생성 된 C ++ 인터페이스 소스 파일을 컴파일하고 모든 것을 연결하여 Python에서 직접 가져올 수있는 공유 라이브러리 ( “_”)를 생성합니다.

g++ -c -fPIC code_wrap.cxx  -I/usr/include/python2.7 -I/usr/lib/python2.7
g++ -shared -Wl,-soname,_code.so -o _code.so code.o code_wrap.o

이제 파이썬 스크립트에서 함수를 사용할 수 있습니다 :

#!/usr/bin/env python

import code
a= [[3,5,7],[8,10,12]]
print a
b = code.average(a)
print "Assignment done"
print a
print b


답변

또한 pybind11가벼운 버전의 Boost.Python 과 유사하며 모든 최신 C ++ 컴파일러와 호환됩니다.

https://pybind11.readthedocs.io/en/latest/


답변

pyrex 또는 Cython을 확인하십시오 . C / C ++와 Python 간의 인터페이스를위한 Python과 유사한 언어입니다.


답변

최신 C ++의 경우 cppyy를 사용하십시오.
http://cppyy.readthedocs.io/en/latest/

Clang / LLVM의 C ++ 인터프리터 인 Cling을 기반으로합니다. 바인딩은 런타임에 있으며 추가 중간 언어가 필요하지 않습니다. Clang 덕분에 C ++ 17을 지원합니다.

pip를 사용하여 설치하십시오.

    $ pip install cppyy

소규모 프로젝트의 경우 관련 라이브러리와 관심있는 헤더를로드하기 만하면됩니다. 예를 들어 ctypes 예제의 코드는이 스레드이지만 헤더와 코드 섹션으로 나뉩니다.

    $ cat foo.h
    class Foo {
    public:
        void bar();
    };

    $ cat foo.cpp
    #include "foo.h"
    #include <iostream>

    void Foo::bar() { std::cout << "Hello" << std::endl; }

그것을 컴파일하십시오 :

    $ g++ -c -fPIC foo.cpp -o foo.o
    $ g++ -shared -Wl,-soname,libfoo.so -o libfoo.so  foo.o

그것을 사용하십시오 :

    $ python
    >>> import cppyy
    >>> cppyy.include("foo.h")
    >>> cppyy.load_library("foo")
    >>> from cppyy.gbl import Foo
    >>> f = Foo()
    >>> f.bar()
    Hello
    >>>

준비된 리플렉션 정보 및 cmake 프래그먼트를 자동으로로드하여 대규모 프로젝트가 지원되므로이를 통해 설치된 패키지 사용자가 간단하게 실행할 수 있습니다.

    $ python
    >>> import cppyy
    >>> f = cppyy.gbl.Foo()
    >>> f.bar()
    Hello
    >>>

LLVM 덕분에 자동 템플릿 인스턴스화와 같은 고급 기능이 가능합니다. 예제를 계속하려면 :

    >>> v = cppyy.gbl.std.vector[cppyy.gbl.Foo]()
    >>> v.push_back(f)
    >>> len(v)
    1
    >>> v[0].bar()
    Hello
    >>>

참고 : 저는 cppyy의 저자입니다.