본문 바로가기

programming/python

C++ 응용프로그램에 파이썬 인터프리터 내장하기 (Qt 기반)

사용한 개발환경

Windows 10 Home 64bit

Qt 5.12.3

python v3.5.0 64bit

 

절차

Qt 프로젝트 파일 설정

 

Qt의 프로젝트 파일(.pro)에 설치된 python의 경로를 아래와 같이 INCLUDEPATH와 LIBS를 지정해준다.

 

(python3가 C:/Python35/ 에 설치되었다고 가정하면,)

 

....

FORMS += \ 
        DlgMain.ui 

INCLUDEPATH = C:\Python35\include 
LIBS += -LC:\Python35\libs -lpython35 

# Default rules for deployment.

....

 

slots 키워드 충돌 방지

python.h 헤더파일과 Qt의 slots 키워드가 충돌한다. 이를 방지하기 위해, python.h를 직접 include하지 말고 wrapper header를 만들어 include하자.

 

python_wrapper.h

#pragma once

// [Python/C API] Debug 빌드 시, "Python27_d.lib" 에러
// https://kiya.tistory.com/2
// (pyconfig.h, object.h 수정 필요)

// https://stackoverflow.com/questions/23068700/embedding-python3-in-qt-5
#   pragma push_macro("slots")
#   undef slots

#       define PY_SSIZE_T_CLEAN
#       include <Python.h>

#   pragma pop_macro("slots")

 

디버그 모드 링크에러 방지

디버그 모드로 링크하면 python35_d.lib를 링크하려고 시도하는데, 이 파일은 python 소스코드를 내려받아 빌드해야 만들 수 있다. 임시로 python35.lib로 대체하기 위해 python의 include/ 폴더에 아래 2가지 조치를 한다.

 

 

1) pyconfig.h 파일에서 아래와 같이 python35_d.lib를 python35.lib로 교체

#			if defined(_DEBUG)
//#				pragma comment(lib,"python35_d.lib")
#				pragma comment(lib,"python35.lib")
#			elif defined(Py_LIMITED_API)
#				pragma comment(lib,"python3.lib")
#			else
#				pragma comment(lib,"python35.lib")
#			endif /* _DEBUG */

 

2) object.h 파일에서 #define Py_TRACE_REFS 리마크

/* Py_DEBUG implies Py_TRACE_REFS. */
#if defined(Py_DEBUG) && !defined(Py_TRACE_REFS)
//#define Py_TRACE_REFS
#endif

 

python 스크립트 실행 함수 구현

run_py.cpp

#include "python_wrapper.h"
#include <stdio.h>

/** --------------------------------------------------------
@param[in]	pathname	python script의 경로파일명 (.py 포함)
@return
        - 0     OK
        - -1    file 열기 실패
        - <0    error code
@brief		Very High Level Embedding 방식으로 python script 실행
-------------------------------------------------------- */
int run_python(const char* pathname)
{
    //Py_SetProgramName(program);  /* optional but recommended */

    Py_Initialize();

    FILE* fp = nullptr;
    auto ret = fopen_s(&fp, pathname, "r");
    if(ret != 0) return -1;

    auto iret = PyRun_SimpleFile(fp, pathname);
    if(iret < 0) return iret;

    Py_Finalize();

    fclose(fp);

    return 0;
}

 

 

빌드와 실행

간단한 .py를 작성해 실행해본다.

 

hello.py

#-*- encoding: utf-8 -*-

print('hello, world!')

test.cpp

auto iret = run_python("D:/test/hello.py");
if (iret<0) return iret;

 

QtCreator에서 release로 빌드하여 실행해보면 .py 스크립트가 정상적으로 실행된다.

출력 문자열은 QtCreator의 Application Output에서 볼 수 있다.

 

그러나 debug 모드에서는 아래와 같이 예외가 발생한다. python 라이브러리가 debug 용이 아니라서 그런 것 같다.

 

Debug 모드에서 PyRun_SimpleFile( ) 실행 시 발생하는 예외

 

배포

python3가 설치되지 않은 시스템에 배포할 때는, python 폴더 내에 있는 python35.dll 파일을 복사하여 실행파일과 같은 폴더에 함께 배치해 줘야 한다.

 

 

참고자료

 

https://docs.python.org/ko/3/extending/embedding.html

 

1. 다른 응용 프로그램에 파이썬 내장하기 — Python 3.8.2 문서

1. 다른 응용 프로그램에 파이썬 내장하기 이전 장에서는 파이썬을 확장하는 방법, 즉 C 함수의 라이브러리를 파이썬에 연결하여 파이썬의 기능을 확장하는 방법에 관해 설명했습니다. 다른 방법도 가능합니다: 파이썬을 내장시켜 C/C++ 응용 프로그램을 풍부하게 만들 수 있습니다. 내장은 C 나 C++가 아닌 파이썬으로 응용 프로그램의 일부 기능을 구현하는 능력을 응용 프로그램에 제공합니다. 이것은 여러 목적으로 사용될 수 있습니다; 한 가지 예는 사용자가 파

docs.python.org

https://kiya.tistory.com/2

 

[Python/C API] Debug 빌드 시, "Python27_d.lib" 에러

Python/C API를 사용하기위해, 1. Python.h를 include 2. Python27.lib을 추가해야 한다. 하지만, Debug모드 빌드 시 LINK : fatal error LNK1104: cannot open file 'python27_d.lib 에러가 발생 구글링 결과 해..

kiya.tistory.com

https://stackoverflow.com/questions/23068700/embedding-python3-in-qt-5

 

Embedding Python3 in Qt 5

I would like to embed Python interpreter 3.4 into a Qt 5.2.1 application (64-bit). However I'm having build issues, I mean when I include Python header in the main.cpp it compiles fine. #include <

stackoverflow.com