Programing

파이썬을 기계 코드로 컴파일하는 것이 가능합니까?

lottogame 2020. 7. 13. 08:11
반응형

파이썬을 기계 코드로 컴파일하는 것이 가능합니까?


파이썬을 (중간 C 표현을 통해) 머신 코드로 컴파일하는 것이 얼마나 가능합니까?

아마도 그것은 파이썬 런타임 라이브러리에 연결될 필요가있을 것이며, 파이썬 자체 인 파이썬 표준 라이브러리의 어떤 부분도 컴파일 (링크)되어야합니다.

또한 표현식의 동적 평가를 원한다면 Python 인터프리터를 번들로 제공해야하지만, 이것을 허용하지 않은 Python의 하위 세트는 여전히 유용 할 것입니다.

속도 및 / 또는 메모리 사용 이점을 제공합니까? 아마도 파이썬 인터프리터의 시작 시간이 제거 될 것입니다 (공유 라이브러리는 여전히 시작시로드해야하지만).


ShedSkin Python-to-C ++ 컴파일러를 사용해보십시오 .하지만 완벽하지는 않습니다. 또한 속도 향상 만 필요한 경우 Psyco-Python JIT가 있습니다. 그러나 IMHO는 노력할 가치가 없습니다. 코드의 속도에 중요한 부분은 C / C ++ 확장으로 작성하는 것이 가장 좋습니다.


@Greg Hewgill이 말했듯이 이것이 항상 가능하지 않은 이유는 충분합니다. 그러나 특정 알고리즘 (예 : 매우 알고리즘적인 코드)을 "실제"기계 코드로 변환 할 수 있습니다.

몇 가지 옵션이 있습니다.

  • 머신 코드를 동적으로 방출하는 Psyco를 사용하십시오 . 하지만 변환 할 메소드 / 함수를 신중하게 선택해야합니다.
  • 사용 사이 썬 Python-이며, 같은 파이썬 C 확장으로 컴파일 언어
  • RPython ( Python의 가장 "동적"기능을 지원하지 않는 Python 제한된 서브 세트 )에서 C 또는 LLVM으로 의 변환기가있는 PyPy를 사용하십시오 .
    • PyPy는 여전히 실험 중입니다
    • 모든 확장이 존재하지는 않습니다

그런 다음 기존 패키지 중 하나 (freeze, Py2exe, PyInstaller)를 사용하여 모든 것을 하나의 바이너리에 넣을 수 있습니다.

대체로 귀하의 질문에 대한 일반적인 답변은 없습니다. 성능이 중요한 Python 코드가있는 경우 가능한 한 많은 내장 기능을 사용하십시오 (또는 "Python 코드를 더 빠르게 만드는 방법"질문). 그래도 도움이되지 않으면 코드를 식별하고 C (또는 Cython)로 이식하고 확장을 사용하십시오.


py2c ( http://code.google.com/p/py2c )는 파이썬 코드를 c / c ++로 변환 할 수 있습니다. 나는 py2c의 솔로 개발자입니다.


Nuitka 는 libpython과 연결되는 Python to C ++ 컴파일러입니다. 비교적 새로운 프로젝트 인 것 같습니다. 필자 는 pystone 벤치 마크에서 CPython보다 속도가 향상 되었다고 주장합니다 .


PyPy 는 구현 전략 (JIT가있는 VM, JVM을 사용하는 VM 등) 중 하나로 네이티브 코드로 컴파일을 사용하여 Python에서 Python을 다시 구현하는 프로젝트입니다. 컴파일 된 C 버전은 평균적으로 CPython보다 느리지 만 일부 프로그램의 경우 훨씬 빠릅니다.

Shedskin 은 실험적인 Python-to-C ++ 컴파일러입니다.

Pyrex 는 Python 확장 모듈을 작성하기 위해 특별히 설계된 언어입니다. 그것은 훌륭하고 사용하기 쉬운 파이썬 세계와 지저분한 저수준 C 세계 사이의 격차를 메우기 위해 설계되었습니다.


Pyrex 는 Python에 대한 목록 이해처음 만든 사람이 C로 컴파일하는 Python 언어의 하위 집합입니다 . 주로 래퍼 작성을 위해 개발되었지만보다 일반적인 상황에서 사용할 수 있습니다. Cython 은 파이렉스의보다 적극적으로 유지되는 포크입니다.


이것은 언뜻보기에는 합리적으로 보일 수 있지만 Python에는 많은 Python 런타임 지원을 수행하지 않고 C 표현에 직접 매핑 할 수없는 많은 평범한 것들이 있습니다. 예를 들어, 오리 타이핑이 떠 오릅니다. 입력을 읽는 파이썬의 많은 함수 는 특정 연산을 지원 하는 한 파일 이나 파일과 같은 객체를 취할 수 있습니다 . read () 또는 readline (). 이 유형의 지원을 C에 매핑하는 데 무엇이 필요한지 생각하면 Python 런타임 시스템이 이미 수행하는 작업을 정확하게 상상하기 시작합니다.

파이썬 프로그램과 런타임을 단일 실행 파일로 묶을 수있는 py2exe 와 같은 유틸리티가 있습니다 (가능한 한).


몇 가지 추가 참조 :


자이 썬은 JVM 바이트 코드를 목표로하는 컴파일러를 가지고있다. 바이트 코드는 파이썬 언어와 마찬가지로 완전히 동적입니다! 매우 시원합니다. (예, Greg Hewgill의 답변에서 알 수 있듯이 바이트 코드는 Jython 런타임을 사용하므로 Jython jar 파일은 앱과 함께 배포해야합니다.)


Psyco 는 일종의 JIT (Just-In-Time) 컴파일러입니다. Python 용 동적 컴파일러는 코드를 2-100 배 빠르게 실행하지만 많은 메모리가 필요합니다.

In short: it run your existing Python software much faster, with no change in your source but it doesn't compile to object code the same way a C compiler would.


The answer is "Yes, it is possible". You could take Python code and attempt to compile it into the equivalent C code using the CPython API. In fact, there used to be a Python2C project that did just that, but I haven't heard about it in many years (back in the Python 1.5 days is when I last saw it.)

You could attempt to translate the Python code into native C as much as possible, and fall back to the CPython API when you need actual Python features. I've been toying with that idea myself the last month or two. It is, however, an awful lot of work, and an enormous amount of Python features are very hard to translate into C: nested functions, generators, anything but simple classes with simple methods, anything involving modifying module globals from outside the module, etc, etc.


This doesn't compile Python to machine code. But allows to create a shared library to call Python code.

If what you are looking for is an easy way to run Python code from C without relying on execp stuff. You could generate a shared library from python code wrapped with a few calls to Python embedding API. Well the application is a shared library, an .so that you can use in many other libraries/applications.

Here is a simple example which create a shared library, that you can link with a C program. The shared library executes Python code.

The python file that will be executed is pythoncalledfromc.py:

# -*- encoding:utf-8 -*-
# this file must be named "pythoncalledfrom.py"

def main(string):  # args must a string
    print "python is called from c"
    print "string sent by «c» code is:"
    print string
    print "end of «c» code input"
    return 0xc0c4  # return something

You can try it with python2 -c "import pythoncalledfromc; pythoncalledfromc.main('HELLO'). It will output:

python is called from c
string sent by «c» code is:
HELLO
end of «c» code input

The shared library will be defined by the following by callpython.h:

#ifndef CALL_PYTHON
#define CALL_PYTHON

void callpython_init(void);
int callpython(char ** arguments);
void callpython_finalize(void);

#endif

The associated callpython.c is:

// gcc `python2.7-config --ldflags` `python2.7-config --cflags` callpython.c -lpython2.7 -shared -fPIC -o callpython.so

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <python2.7/Python.h>

#include "callpython.h"

#define PYTHON_EXEC_STRING_LENGTH 52
#define PYTHON_EXEC_STRING "import pythoncalledfromc; pythoncalledfromc.main(\"%s\")"


void callpython_init(void) {
     Py_Initialize();
}

int callpython(char ** arguments) {
  int arguments_string_size = (int) strlen(*arguments);
  char * python_script_to_execute = malloc(arguments_string_size + PYTHON_EXEC_STRING_LENGTH);
  PyObject *__main__, *locals;
  PyObject * result = NULL;

  if (python_script_to_execute == NULL)
    return -1;

  __main__ = PyImport_AddModule("__main__");
  if (__main__ == NULL)
    return -1;

  locals = PyModule_GetDict(__main__);

  sprintf(python_script_to_execute, PYTHON_EXEC_STRING, *arguments);
  result = PyRun_String(python_script_to_execute, Py_file_input, locals, locals);
  if(result == NULL)
    return -1;
  return 0;
}

void callpython_finalize(void) {
  Py_Finalize();
}

You can compile it with the following command:

gcc `python2.7-config --ldflags` `python2.7-config --cflags` callpython.c -lpython2.7 -shared -fPIC -o callpython.so

Create a file named callpythonfromc.c that contains the following:

#include "callpython.h"

int main(void) {
  char * example = "HELLO";
  callpython_init();
  callpython(&example);
  callpython_finalize();
  return 0;
}

Compile it and run:

gcc callpythonfromc.c callpython.so -o callpythonfromc
PYTHONPATH=`pwd` LD_LIBRARY_PATH=`pwd` ./callpythonfromc

This is a very basic example. It can work, but depending on the library it might be still difficult to serialize C data structures to Python and from Python to C. Things can be automated somewhat...

Nuitka might be helpful.

Also there is numba but they both don't aim to do what you want exactly. Generating a C header from Python code is possible, but only if you specify the how to convert the Python types to C types or can infer that information. See python astroid for a Python ast analyzer.


Try Python → 11l → C++ transpiler.

참고URL : https://stackoverflow.com/questions/138521/is-it-feasible-to-compile-python-to-machine-code

반응형