development

파이썬에서 C / C ++를 호출합니까?

big-blog 2020. 2. 13. 00:49
반응형

파이썬에서 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를 사용하면 구조와 클래스를 대상 언어의 프록시 클래스로 패키지하여 기본 기능을 매우 자연스럽게 노출 할 수 있습니다.


이 페이지에서 Python <-> C ++ 바인딩에 대한 여정을 시작했습니다. 높은 수준의 데이터 형식 (Python 목록과 다차원 STL 벡터)을 연결하려는 목적으로 :-)

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

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


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

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


파이썬이 과학자가 필요로한다고 주장하는이 논문 은 기본적으로 다음과 같이 말합니다. 그런 다음 부품 속도를 높이려면 SWIG를 사용하여이 부품을 C로 변환하십시오.


최신 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의 저자입니다.


나는 그것을 사용한 적이 없지만 ctypes에 대해 좋은 것을 들었습니다 . C ++에서 사용하려는 경우를 통해 name mangling을 피하십시오 extern "C". 의견을 주셔서 감사합니다. Florian Bösch.


나는 파이썬의 cffi가 옵션 일 수 있다고 생각합니다.

목표는 Python에서 C 코드를 호출하는 것입니다. 당신은 제 3 언어를 배우지 않고도 그렇게 할 수 있어야합니다. 모든 대안은 자신의 언어 (Cython, SWIG) 또는 API (ctypes)를 배워야합니다. 그래서 우리는 파이썬과 C를 알고 있다고 가정하고 배우는 데 필요한 추가 비트를 최소화하려고 시도했습니다.

http://cffi.readthedocs.org/en/release-0.7/


문제는 올바르게 이해하면 Python에서 C 함수를 호출하는 방법입니다. 그렇다면 가장 좋은 방법은 Ctypes입니다 (파이썬의 모든 변형에서 BTW 이식 가능).

>>> from ctypes import *
>>> libc = cdll.msvcrt
>>> print libc.time(None)
1438069008
>>> printf = libc.printf
>>> printf("Hello, %s\n", "World!")
Hello, World!
14
>>> printf("%d bottles of beer\n", 42)
42 bottles of beer
19

자세한 가이드는 내 블로그 기사 를 참조 하십시오 .


공식 파이썬 문서 중 하나에는 C / C ++를 사용하여 파이썬확장하는 것에 대한 세부 정보가 들어 있습니다 . SWIG를 사용하지 않아도 매우 간단하며 Windows에서 완벽하게 작동합니다.


Java 래퍼 작성을 예상하지 않는 한 Cython은 확실히 갈 길입니다.이 경우 SWIG가 더 좋습니다.

runcython커맨드 라인 유틸리티를 사용하는 것이 좋습니다 . Cython을 사용하는 프로세스가 매우 쉽습니다. 구조화 된 데이터를 C ++로 전달해야하는 경우 Google의 프로토 타입 라이브러리를 살펴보면 매우 편리합니다.

다음은 두 도구를 모두 사용하는 최소 예제입니다.

https://github.com/nicodjimenez/python2cpp

그것이 유용한 출발점이 될 수 있기를 바랍니다.


먼저 특정 목적이 무엇인지 결정해야합니다. 파이썬 인터프리터 확장 및 임베드 에 대한 공식 파이썬 문서 는 위에서 언급 했으므로 바이너리 확장에 대한 좋은 개요를 추가 할 수 있습니다 . 사용 사례는 3 가지 범주로 나눌 수 있습니다.

  • 가속기 모듈 : CPython에서 실행되는 동등한 순수 Python 코드보다 빠르게 실행합니다.
  • 래퍼 모듈 : 기존 C 인터페이스를 Python 코드에 노출합니다.
  • 낮은 수준의 시스템 액세스 : CPython 런타임, 운영 체제 또는 기본 하드웨어의 낮은 수준의 기능에 액세스합니다.

다른 관심사에 대한 더 넓은 관점을 제공하고 초기 질문이 약간 모호하기 때문에 ( "C 또는 C ++ 라이브러리에 대한")이 정보가 흥미로울 것입니다. 위의 링크에서 바이너리 확장과 그 대안을 사용할 때의 단점에 대해 읽을 수 있습니다.

제안 된 다른 답변 외에도 가속기 모듈을 원한다면 Numba 을 사용해보십시오 . "가져 오기 시간, 런타임 또는 정적으로 (포함 된 pycc 도구를 사용하여) LLVM 컴파일러 인프라를 사용하여 최적화 된 기계 코드를 생성하여 작동합니다."

참고 URL : https://stackoverflow.com/questions/145270/calling-cc-from-python



반응형