Возможно ли скомпилировать Python в машинный код?

StackOverflow https://stackoverflow.com/questions/138521

  •  02-07-2019
  •  | 
  •  

Вопрос

Насколько осуществимо было бы скомпилировать Python (возможно, через промежуточное представление C) в машинный код?

Предположительно, его потребуется связать с библиотекой времени выполнения Python, и любые части стандартной библиотеки Python, которые сами являются Python, также необходимо будет скомпилировать (и связать с ними).

Кроме того, вам потребуется подключить интерпретатор Python, если вы хотите выполнять динамическую оценку выражений, но, возможно, подмножество Python, которое не позволяет этого, все равно будет полезно.

Даст ли это какие-либо преимущества в скорости и/или использовании памяти?Предположительно, время запуска интерпретатора Python будет устранено (хотя разделяемые библиотеки по-прежнему будут нуждаться в загрузке при запуске).

Это было полезно?

Решение

Пытаться ШедСкин Компилятор Python-C++, но он далек от совершенства.Также есть Psyco - Python JIT, если нужно только ускорение.Но ИМХО это того не стоит.Для частей кода, критичных к скорости, лучшим решением будет написать их как расширения C/C++.

Другие советы

Как говорит @Greg Hewgill, есть веские причины, почему это не всегда возможно.Однако некоторые виды кода (например, алгоритмический код) можно превратить в «настоящий» машинный код.

Есть несколько вариантов:

  • Использовать Псико, который динамически генерирует машинный код.Однако вам следует тщательно выбирать, какие методы/функции конвертировать.
  • Использовать Китон, который представляет собой Python-нравиться язык, скомпилированный в расширение Python C
  • Использовать PyPy, в котором есть переводчик с RPython ( ограниченное подмножество Python, который не поддерживает некоторые из наиболее «динамичных» функций Python) на C или LLVM.
    • PyPy все еще остается экспериментальным.
    • не все расширения будут присутствовать

После этого вы можете использовать один из существующих пакетов (freeze, Py2exe, PyInstaller), чтобы поместить все в один бинарный файл.

В целом:на ваш вопрос нет общего ответа.Если у вас есть код Python, производительность которого критична, постарайтесь использовать как можно больше встроенных функций (или задайте вопрос «Как мне сделать мой код Python быстрее»).Если это не поможет, попробуйте идентифицировать код, перенести его на C (или Cython) и использовать расширение.

py2c ( http://code.google.com/p/py2c) может преобразовать код Python в C/C ++ I Solo разработчик Py2c.

Нуитка — это компилятор Python в C++, который связывается с libpython.Судя по всему, это относительно новый проект.Автор утверждает, улучшение скорости поверх CPython в тесте pystone.

PyPy — это проект по переопределению Python в Python с использованием компиляции в собственный код в качестве одной из стратегий реализации (другие варианты — виртуальная машина с JIT, использование JVM и т. д.).Их скомпилированные версии C работают в среднем медленнее, чем CPython, но для некоторых программ намного быстрее.

Шедскин — экспериментальный компилятор Python-C++.

Пирекс — это язык, специально разработанный для написания модулей расширения Python.Он создан для того, чтобы преодолеть разрыв между красивым, высокоуровневым и простым в использовании миром Python и беспорядочным, низкоуровневым миром C.

Пирекс это подмножество языка Python, которое компилируется в C, созданное человеком, который первым создал список понятий для Питона.В основном он был разработан для создания оберток, но может использоваться и в более общем контексте. Китон это более активно поддерживаемая версия Pyrex.

На первый взгляд это может показаться разумным, однако в Python есть множество обычных вещей, которые невозможно напрямую сопоставить с представлением C без переноса значительной части поддержки среды выполнения Python.Например, на ум приходит утиное печатание.Многие функции в Python, считывающие ввод, могут принимать файл. или файловый объект, если он поддерживает определенные операции, например.read() или readline().Если вы подумаете о том, что потребуется, чтобы отобразить этот тип поддержки в C, вы начнете представлять себе именно те вещи, которые уже делает система времени выполнения Python.

Есть такие утилиты, как py2exe это объединит программу Python и среду выполнения в один исполняемый файл (насколько это возможно).

Некоторые дополнительные ссылки:

У Jython есть компилятор, предназначенный для байт-кода JVM.Байт-код полностью динамичен, как и сам язык Python!Очень круто.(Да, как следует из ответа Грега Хьюгилла, байт-код использует среду выполнения Jython, поэтому файл jar Jython должен распространяться вместе с вашим приложением.)

Псико это своего рода JIT-компилятор:динамический компилятор для Python выполняет код в 2–100 раз быстрее, но требует много памяти.

Суммируя:он запускает существующее программное обеспечение Python намного быстрее, без каких-либо изменений в исходном коде, но не компилируется в объектный код так, как это делает компилятор C.

Ответ: «Да, это возможно».Вы можете взять код Python и попытаться скомпилировать его в эквивалентный код C, используя API CPython.На самом деле раньше существовал проект Python2C, который делал именно это, но я не слышал о нем уже много лет (еще во времена Python 1.5 я в последний раз видел его).

Вы можете попытаться максимально перевести код Python на собственный язык C и вернуться к API CPython, когда вам понадобятся реальные функции Python.Я сам обдумывал эту идею последние месяц или два.Однако это очень большая работа, и огромное количество функций Python очень сложно перевести на C:вложенные функции, генераторы, что угодно, кроме простых классов с простыми методами, все, что связано с изменением глобальных переменных модуля снаружи модуля и т. д. и т. п.

Это не компилирует Python в машинный код.Но позволяет создать общую библиотеку для вызова кода Python.

Если то, что вы ищете, — это простой способ запуска кода Python из C, не полагаясь на execp.Вы можете создать общую библиотеку из кода Python, обернутого несколькими вызовами API для встраивания Python.Что ж, приложение представляет собой общую библиотеку, .так что вы можете использовать ее во многих других библиотеках/приложениях.

Вот простой пример создания общей библиотеки, которую вы можете связать с программой на C.Общая библиотека выполняет код Python.

Файл Python, который будет выполнен, 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

Вы можете попробовать это с python2 -c "import pythoncalledfromc; pythoncalledfromc.main('HELLO').Он выведет:

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

Общая библиотека будет определяться следующим образом: callpython.h:

#ifndef CALL_PYTHON
#define CALL_PYTHON

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

#endif

Связанный callpython.c является:

// 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();
}

Вы можете скомпилировать его с помощью следующей команды:

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

Создайте файл с именем callpythonfromc.c который содержит следующее:

#include "callpython.h"

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

Скомпилируйте его и запустите:

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

Это очень простой пример.Это может сработать, но в зависимости от библиотеки может быть сложно сериализовать структуры данных C в Python и из Python в C.Можно что-то автоматизировать...

Нуитка может быть полезно.

Также есть онемба но они оба не стремятся делать именно то, что вы хотите.Генерация заголовка C из кода Python возможна, но только если вы укажете, как преобразовать типы Python в типы C, или сможете вывести эту информацию.Видеть астроид питона для анализатора Python.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top