CastleJo의 개발일지

파이썬에서 직접 만든 C, C++ 라이브러리 사용하기 (cdll)

|

본 포스팅은 리눅스 환경에서 진행했습니다.

cdll 라이브러리

잘 만들어진 C나 C++파일을 가지고 있을 때, 이를 파이썬 코드로 이식해야 할 경우가 있을때가 있다.

이때 특별한 이유를 가지고있지 않다면, 직접 c코드를 파이썬 코드로 변환하지 말고 cdll 라이브러리를 써보자.

cdll 라이브러리가 뭘까? 파이썬 공식 문서에 정확한 설명이 있다. 파이썬용 외부 함수 라이브러리 이다.

해당 포스트에서는 아래와 같은 내용을 다룰 것이다.

  1. C++ 클래스 생성
  2. Makefile 생성
  3. .dll 파일 생성
  4. Python에서 dll 파일 불러오기

해당 포스트에서 포인터형 변수 전달은 다루지 않습니다.

C++ 클래스 생성

평소 알던대로 해주면 된다.
하지만 한가지 과정을 더 추가해줘야 한다.
C의 구조체에서는 멤버 메소드를 가질 수 없다. 하지만 C++에선 이것이 가능하다.
따라서 C++로 멤버 메소드를 만들었으면, 이를 C로 전환해주는 과정을 거쳐야 한다.

일단 예시를 보자. 그냥 숫자를 지정하고, 호출된 횟수를 불러올 수 있는 간단한 클래스이다.

class Number{
private:
    int num;
    int count;
public:
    Number(){
        this.num = 0;
        this.count = 0;
    }

public:
    void setNum(int n){
        this.num = n;
        this.count++;
    }

    int getNum(){
        this.count++;
        return this.num;
    }

    void showCount(){
        printf("Now Count : %d\n",this.count);
    }
};

간단하지만 생성자와 리턴타입이 정수인 함수, 없는 함수 두개를 만들었다.
하지만 이를 DLL로 만들기 전에 추가적인 코드를 작성해줘야 한다.

extern "C" {
    Number* Number_new(){
        return new Number();
    }

    void Number_setNum(Number* f, int n){
        f->setNum(n);
    }

    int Number_getNum(Number* f){
        return f->getNum();
    }

    void Number_showCount(Number* f){
        f->showCount();
    }
}

extern “C”, 네임 맹글링을 하지 않겠다는 의미이다.
dll과 같은 컴파일된 파일을 상호간에 사용해야 할 때 이용한다.
따라서 구조체와 함수포인터와 같은 방식으로 변경해줘야 한다.

이렇게 하면 C++ 파일 작성은 끝났다.

Makefile 생성

계속 so 라이브러리를 만들면서.. 타이핑하기 귀찮았다.
그래서 메이크파일을 만들었다. 학교에서 배우고 다시는 안쓸줄알았는데.

본 포스트에서 상세한 설명은 안 넣을 예정이다.

CC = g++
TARGET = number.dll
LIB = -lmath #필요 없지만, 종속 라이브러리를 넣을 땐 이렇게 한다.

$(TARGET) : number.o
	$(CC) --shared $(LIB) -o $@ $?
	rm *.o

number.o : number.cpp
	$(CC) -fPIC -c $?

clean :
	rm $(TARGET)

number.cpp를 오브젝트파일로 바꾸고, .so파일을 생성한 뒤 오브젝트파일을 삭제한다.
make clean을 하면 타겟을 지운다.

.dll 파일 생성

사실 위에서 다뤘다. 순서를 좀 잘못매긴거같다.
왜 .so 파일이 아니고 .dll파일을 만들었냐
so는 프로그램이 시작될 때 자동으로 연결되고, 응용프로그램이 시작될 때 같이 있어야 한다.

dll파일은 호출되는 순간 필요하다.
이 차이로, 시작부터 적재할 필요가 없다고 생각되는 라이브러리는 dll파일로 만들어서 넣었다.

Python에서 dll 파일 불러오기

일단 코드를 보자

from ctypes import cdll

class Number(object):
 
    def __init__( self , libPath):
        self.lib = cdll.LoadLibrary(libPath)
        self.obj = self.lib.Number_new()

    def getNumber(self):
        return self.lib.getNum()
    
    def setNumber(self, n):
        self.lib.Number_setNum(n)
    
    def showCount(self)
        self.lib.Number_showCount()

if __name__ == '__main__':
 
    f = Number(libPath='./temperature.dll')

    f.setNumber(3)
    print(f.getNumber())
    print(f.showCount())

여기서 중요한 점은, libPath는 이렇게 상대경로로 넣어주던가 환경변수로 설정을 해야한다. 공유 라이브러리이기 때문에..
이러면 파이썬으로 클래스 불러오기가 성공했다.
해당 클래스에 입맛대로 살을 더 붙여도 된다.

여담

파이썬으로 만드는것보다 이런 방식이 더 속도가 빠르다고 하다.
Numpy도 이런식이라던데.. 까보지는 않아서 모르겠다.