конвертер кода c в python
C/C++ из Python (ctypes)
Про то как вызывать Python из C написал в прошлой статье, теперь поговорим как делать наоборот и вызывать C/C++ из Python3. Раз начал писать об этом, то раскроем всю тему до конца. Тем более, что ни чего сложного здесь нет тоже.
Здесь все просто, Python умеет вызывать C функции без каких либо проблем.
Исходник компилируется в динамическую библиотеку и готов к бою.
Переходим к Python. В примере показывается как передать аргументы функции, получить результат работы от функции, а так же как получить и изменить значения глобальных переменных.
Все возможные типы данных и их обозначения можно посмотреть в документации Python.
Работа со структурами
C — объявление структуры в test.h:
Функция по работе с нашей структурой:
Здесь немного сложнее, т.к. ctypes может только работать с C функциями. Это для нас не проблема, просто C обвяжем код C++.
Методы класса C++ и обвязка на C:
Но есть один нюанс, обвязку надо объявить как extern C. Чтобы ++ компилятор не перегрузил имена функций обвязки. Если он это сделает, то мы не сможем через ctypes работать с нашими функциями.
test.hpp:
С Python все так же просто.
Плюсы и минусы ctypes
Плюсы:
Минусы:
Код постарался закомментировать понятно, чтобы здесь писать поменьше )
Надеюсь будет полезно.
Благодарность
DollaR84 за его помощь.
Palich239 за найденные ошибки.
UniSharping: конвертирование кода C# в Java и Python
С 70-х годов развивается Simplified English, цель которого — определение подмножества языка, понятного широкому кругу неносителей языка. Рекомендуется, например, для технической документации. Автоматические переводчики на таком подмножестве будут работать заведомо корректнее, в идеале генерируя текст, не требующий ручной корректуры.
Если применить этот подход к C# для задачи автоматической конвертации кода в другие языки программирования, то можно выделить подмножество конструкций языка, системных библиотек и технологий, которые потенциально могут транслироваться в широкий круг других языков. Причём конвертации не однократной (миграция), а постоянной для расширения интеграционных возможностей проекта на C# — чтобы в любой момент можно было получить рабочий код на другом языке без необходимости какой-либо его правки.
Ограничение C#.NET для решения этой задачи мы назвали U# (Universal Sharp), а процесс конвертации и его инструмент — UniSharping. Исполняемые модули, настройки и документация выложены на GitHub, система бесплатна для некоммерческого использования (Non-Commercial Freeware).
Ограничений U# в конструкциях языка оказалось немного – это атавизмы goto и case goto, а также yield, не моделируемый адекватно в автоматическом режиме. Не рекомендуется (хотя и можно) использовать struct, есть нюансы с наименованиями – всё это подробно описывается в отдельном документе. Парсер U# выдаёт ошибки и предупреждения, и для гарантии корректной генерации следует так подкорректировать исходный код C#, чтобы они в идеале совсем исчезли. Если всё-таки нужно сохранить исходный вариант, то можно использовать директивы препроцессора #if JAVA || PHP … #else … #endif. Данные ограничения действуют на уровне движка U# и не подлежат коррекции извне, как и список поддерживаемых языков.
А вот ограничения на уровне системных библиотек заданы не жёстко и конфигурируются извне через специальные текстовые файлы, определяющие, как переводить на соответствующий язык тот или иной класс и его члены. Если есть прямой аналог, то он и указывается, если ситуация сложнее, то пишется или фрагмент кода конечного языка, или вообще специальный (сервисный) класс, решающий нужную задачу. В совсем уж сложных случаях приходится «хардкодить» на уровне движка, но такие ситуации довольно редки (с десяток). Порядок настройки на системные классы и их члены описываются в отдельном документе. Вот список поддержанных классов C# и их членов с аналогами на Java и Python в текущей версии на сайте, там же есть online-демо.
Что касается технологий, то сейчас список ограничен консольным приложением и юнит-тестами (UnitTest). Ну и отдельные Lib-проекты, как частный случай, переводятся в соответствующие конструкции нужного языка.
Для успешного перевода исходный проект C# (solution) должен иметь некоторую запускаемую часть, проверяющую работоспособность в рамках исходного C#. Хорошо, если это обширная система авто-тестов (стандартных UnitTest в разных реализациях или самописных), но по минимуму должно быть хотя бы консольное приложение, которое при запуске без какого-либо пользовательского вмешательства отрабатывает правильно. Необходимость этого очевидна – после генерации на конечный язык можно сразу проверить работоспособность. В идеале все тесты должны работать аналогично C#.
История проекта
Идея такого конвертера витала давно. Мой основной проект SDK Pullenti по обработке естественного языка — идеальный кандидат для конвертации: большой объём сложного и постоянно совершенствуемого кода. Для интеграции с Java приходилось оборачивать в web-сервисы, tcp-сервера и пр.
Летом прошлого года нашлось время и силы для создания первого варианта. Он переводил проект Pullenti на Java, а также сам себя на Java.
Следующие полгода конвертер развивался на нескольких внутренних проектах, которые были в компании, в основном посредством расширения системных классов.
Весной 2018 появилась мысль поддержать и Python, что и было реализовано к лету. Но включение второго языка не было предусмотрено в начальной версии и получилось коряво. Пришлось летом полностью переделать движок для потенциальной возможности нескольких конечных языков. Также настройки на системные классы из хардкода были вынесены во внешние текстовые файлы. Надеюсь, это множество будет расширяться не без вашей помощи.
Дальнейшие планы пока таковы:
Кому это может пригодиться
Я не исключаю, что в принципе возможна конвертация и web-проектов (с ограничениями, естественно), но у меня нет для этого нужных навыков и информации. Если кто видит такую возможность, то её вполне можно реализовать в UniSharping.
Отмечу, для для реального сложного проекта C# поддержка Java или другого языка потребует некоторых усилий по модификации кода, выделении в проекте портируемой части, «обкладывание» её юнит-тестами. Также настройка ещё неподдержанных системных классов и методов и исправление ошибок самого UniSharping (с моей помощью) — работа ещё та. Но процесс сходящийся, в конце которого проект ожидает бонус «кросс-программности».
Shed Skin — экспериментальный транслятор из Python в C++
Введение
Shed Skin — это экспериментальный транслятор из Python в C++, разработанный для повышения скорости выполнения программ на Python с интенсивными вычислениями. Он преобразует программы, написанные на ограниченном подмножестве языка Python, в C++. Код C++ можно скомпилировать в исполняемый код, который может быть как отдельной программой, так и модулем расширения, легко импортируемым и используемым в обычной программе на Python.
Shed Skin использует методы сопоставления типов, используемых в программе на Python, чтобы сгенерировать явные декларации типов, необходимые для версии на C++. Поскольку C++ — язык со статической типизацией, Shed Skin требует, чтобы код на Python был написан так, чтобы все переменные имели определенный тип.
Помимо ограничений на типизацию и подмножество языка, поддерживаемые программы не могут свободно использовать стандартную библиотеку Python, хотя поддерживается около 25 общеупотребительных модулей, такие как random и re (см. Ограничения Библиотеки).
Вдобавок, технология определения типов, используемая Shed Skin, в данный момент не очень хорошо масштабируется для программ, размер которых превышает несколько тысяч строк кода (максимальный размер транслируемой программы — около 6,000 строк (sloccount)). В целом, это означает, что Shed Skin на данный момент больше подходит для трансляции небольших программ и модулей расширения, которые не используют интенсивно особенности динамической типизации Python или стандартную и внешние библиотеки. Смотри ниже сборник из 75 нетривиальных программ-примеров.
Поскольку Shed Skin находится всё еще в ранней стадии разработки, он может серьёзно улучшиться. В настоящий момент, Вы, возможно, столкнётесь с какими-либо ошибками в процессе его использования. Пожалуйста, отправьте нам отчет о них, чтобы мы смогли их исправить!
В настоящее время Shed Skin совместим с версиями Python с 2.4 по 2.7, ведёт себя как 2.6, и работает на Windows и большинстве UNIX-платформ, таких как GNU/Linux и OSX.
Ограничения на типизацию
Shed Skin транслирует обычные, но статически типизированные программы, на C++. Ограничение на статическую типизацию означает, что переменные могут иметь только один, неизменный тип. Так, например, код
недопустим. Однако, как в C++, типы могут быть абстрактными, так, например, код
где A и B имеют общий базовый класс, допустим.
Ограничение на типизацию также означает, что элементы одной коллекции (list, set, и т.д.) не могут иметь разные типы (потому что типы их членов также должны быть статическими). Таким образом, код:
недопустим. Ключи и значения словарей могут иметь разные типы:
В текущей версии Shed Skin смешанные типы также разрешены в кортежах длины два:
В будущем, возможно, будут разрешены смешанные типы в кортежах большей длины.
Тип None можно смешивать только с нескалярными типами (то есть, не с int, float, bool или complex):
Целые числа и числа с плавающей точкой (integers и floats) обычно можно смешивать (целые числа становятся числами с плавающей точкой). Если это невозможно, Shed Skin выдаст сообщение об ошибке.
Ограничения на подмножество языка Python
Shed Skin всегда будет поддерживать только подмножество всех особенностей языка Python. В данный момент следующие особенности не поддерживаются:
Некоторые другие особенности поддерживаются только частично:
Ограничения на библиотеки
На данный момент, в большой степени поддерживаются следующие 25 модулей. Некоторые из них, такие как os.path, были транслированы на C++ с помощью Shed Skin.
Заметим, что любой другой модуль, такой, как pygame, pyqt или pickle, можно использовать в совокупности с модулем расширения, сгенерированным с помощью Shed Skin. Примеры такого использования см. среди примеров к Shed Skin.
Установка
Имеется два вида установщиков: сапораспаковывающийся инсталятор Windows и архив UNIX. Но, конечно, лучше, если Shed Skin установлек с помощью менеджера пакетов вашей инсталяции GNU/Linux (Shed Skin доступен по крайней мере на Debian, Ubuntu, Fedora и Arch).
Windows
Чтобы установить Windows-версию, просто загрузите и запустите инсталятор. Если вы используете ActivePython или другой нестандартный дистрибутив Python, или MingW, сначала удалите его. Также имейте в виду, что, вероятно, в 64-битной версии Python недостаёт какого-то файла, так что сборка модулей расширения невозможна. Вместо 64-битной используйте 32-битную версию Python.
Инсталяция через менеджер пакетов
Пример команды для Ubuntu:
Ручная инсталяция
Чтобы установить дистрибутив из архива UNIX вручную, сделайте следующее:
Зависимости
Чтобы скомпилировать и запустить программы, сгенерированные shedskin, необходимы следующие библиотеки:
Чтобы установить эти библиотеки под Ubuntu, введите:
Если сборщик мусора Boehm недоступен через ваш менеджер пакетов, используйте такой способ. Загрузите с вебсайта, например, версию 7.2alpha6, распакуйте её, и установите следующим образом:
Если библиотека PCRE недоступна через ваш менеджер пакетов, воспользуйтесь следущим способом. Загрузите с вебсайта, например, версию 8.12, распакуйте её и установите следующим образом:
Ручная установка
Чтобы установить Shed Skin из архива UNIX на систему OSX, сделайте следущее:
Зависимости
Чтобы cкомпилировать и запустить программы, сгенерированные shedskin, необходимы следующие библиотеки:
Если сборщик мусора Boehm недоступен через ваш менеджер пакетов, используйте такой способ. Загрузите с вебсайта, например, версию 7.2alpha6, распакуйте её, и установите следующим образом:
Если библиотека PCRE недоступна через ваш менеджер пакетов, воспользуйтесь следущим способом. Загрузите с вебсайта, например, версию 8.12, распакуйте её и установите следующим образом:
Трансляция обычной программы
На Windows сначала выполните (двойным щелчком) файл init.bat в директории, куда Вы установили Shed Skin.
Чтобы скомпилировать следующую простую тестовую программу с именем test.py:
print ‘hello, world!’
введите:
shedskin test
Создадутся два файла C++ с именами test.cpp и test.hpp, а также Makefile.
Чтобы создать исполняемый файл с именем test (или test.exe), введите:
Создание модуля расширения
Чтобы скомпилировать следующую программу с именем simple_module.py как модуль расширения:
Чтобы команда ‘make’ выполнилась успешно на не-Windows системе, убедитесь, что у Вас установлены отладочные файлы Python (на Debian установите python-dev; на Fedora установите python-devel).
Заметьте, что чтобы было возможно определение типов, ваш модуль должен вызывать только свои собственные функции. Такой эффект достигается в примере за счет того, что вызовы помещены внутрь условия if __name__==’__main__’, так что они не вызываются, если модуль импортируют. Функции могут вызываться только косвенно, то есть, если func2 вызывает func1, вызов func1 может быть опущен.
Модуль расширения теперь можно просто проимпортировать и использовать как обычно:
Ограничения
Имеются существенные отличия между использованием компилированного модуля расширения и оригиналом.
Можно передавать и возвращать только встроенные скалярные типы и контейнеры (int, float, complex, bool, str, list, tuple, dict, set), а также None и экземпляры классов, определённых пользователем. Так, например, анонимные функции и итераторы в настоящее время не поддерживаются.
Встроенные объекты а также их содержимое полностью преобразуются на каждый вызов/возврат функции из типов Shed Skin в CPython и наоборот. Это означает, что нельзя менять встроенные объекты CPython со стороны Shed Skin и наоборот, и преобразование может быть медленным Экземпляры классов, определённых пользователем можно передавать/возвращать без каких-либо преобразований и менять с любой стороны.
Глобальные переменные преобразуются только один раз, во время инициализации, из Shed Skin в CPython. Это означает, что значения версии CPython и версии Shed Skin могут меняться независимо друг от друга. Этой проблемы можно избежать, используя только константные глабольные переменные, или добавляя функции-геттеры и сеттеры.
Множественные (взаимодействующие) модули расширения в настоящий момент не поддерживаются. Также, импорт и одновременное использование питоновской и транслированной версии может не работать.
Интеграция с Numpy
Shed Skin в настоящее время не имеет прямой поддержки Numpy. Однако, возможно передавть массив Numpy array в транслированный модуль расширения Shed Skin как список (list), используя его метод tolist. Заметьте, что это весьма неэффективно (см. выше), так что это можно использовать, если большое количество времени тратится внутри модуля расширения. Рассмотрим следующий пример:
После трансляции этого модуля как модуля расширения с помощью Shed Skin, мы можем передать массив Numpy следующим образом:
Распространение бинарных кодов
Windows
Чтобы использовать сгенерированный бинарный код Windows на другой системе или запустить его без запуска init.bat, поместите следующие файлы в директорию вместе с бинарным файлом:
shedskin-0.9\shedskin\gc.dll
shedskin-0.9\shedskin-libpcre-0.dll
shedskin-0.9\bin\libgcc_s_dw-1.dll
shedskin-0.9\bin\libstdc++.dll
Чтобы использовать сгенерированный бинарный файл на другой системе, убедитесь, что там установлены libgc и libpcre3. Если это не так, и Вы не можете установить их глобально на систему, Вы можете поместить копии этих библиотек в ту же директорию, где лежит бинарь, с помощью следующих команд:
Заметьте, что обе системы должны быть 32- или 64-битными. Если это не так, Shed Skin необходимо установить на другой системе, чтобы пересобрать бинарник.
Multiprocessing
Предположим, мы определили следующую функцию в файле под названием meuk.py:
Чтобы транслировать этот файл в модуль расширения, введите:
Чтобы использовать получившийся модуль расширения с модулем стандартной библиотеки multiprocessing, просто добавьте wrapper на Python:
Вызов кода на C/C++
Чтобы вызвать код на C/C++, сделайте следующее:
Дайте Shed Skin информацию о типизации с помощью модели типов кода C/C++. Предположим, нам нужно вызвать простую функцию, которая возвращает список n наименьших простых чисел, больших, чем заданное число. Следующая модель типов, содержащаяся в файле stuff.py, достаточна, чтобы Shed Skin произвел сопоставление типов:
Чтобы произвести фактическое сопоставление типов, напишите тестовую программу с названием test.py, которая использует эту модель типов, а затем транслируйте её:
Кроме test.py, этот код также транслирует stuff.py на C++. Теперь вы можете писать вручную код C/C++ в файле stuff.cpp. Чтобы избежать его перезаписи во время следующей трансляции файла test.py, переместите stuff.* в директорию lib/ Shed Skin.
Стандартная библиотека
Переместив stuff.* в lib/, мы фактически добавили поддержку произвольного библиотечного модуля к Shed Skin. Другие программы, транслированные Shed Skin, теперь могут импортировать нашу библиотеку и использовать more_primes. Фактически, в директории lib/ находятся модели типов и имплементации всех поддерживаемых модулей. Как Вы можете заметить, некоторые были частично преобразованы в C++ в помощью Shed Skin.
Типы Shed Skin
Shed Skin заново реализует Python встроенные типы с помощью набора своих классов на C++. Они имеют такой же интерфейс, как их Python-овские коллеги, так что их легко использовать (при условии, что у вас есть базовые знания C++). Подробности об определениях классов см. в файле lib/builtin.hpp. Если у вас есть сомнения, преобразуйте аналогичный код на Python в C++ и посмотрите на результат!
Опции командной строки
Команда shedskin поддерживает следующие опции:
Например, чтобы транслировать файл test.py как модуль расширения, введите shedskin –e test или shedskin ––extmod test.
Советы и приёмы по улучшению производительности
Советы
Небольшие аллокации памяти (например, создание нового кортежа, списка или экземпляра класса) обычно сильно не замедляют программу на Python. Однако, после трансляции в C++, часто они становятся узким местом. Это происходит потому что на каждую аллокацию памяти, память запрашивается у системы, она должна быть очищена сборщиком мусора, и большое количество последующих аллокаций памяти скорее всего вызовет отсутствие в кэше. Ключевой подход к высокой производительности — часто уменьшение числа мелких аллокаций, например, заменой небольшого генераторного выражения на цикл или устранение промежуточных кортежей в некоторых вычислениях.
Однако, заметьте, что для идиоматических for a, b in enumerate(..), for a, b in enumerate(..) и for a, b in somedict.iteritems(), промежуточные маленькие объекты выкидываются оптимизатором, и строки длины 1 кешируются.
Некоторые особенности Python (которые могут замедлить сгенерированный код) не всегда необходимы, и их можно выключить. См. раздел «Опции командной строки» для подробностей. Выключение проверки диапазонов обычно является очень безопасной оптимизацией и могут существенно помочь в случае кода, где часто используется операция взятия по индексу.
Доступ через атрибут в сгенерированном коде быстрее, чем взятие по индексу. Например, v.x * v.y * v.z быстрее, чем v[0] * v[1] * v[2].
Shed Skin берет флаги для компилятора C++ из файлов FLAGS* в директории, куда установлен Shed Skin. Эти флаги можно изменить, либо модифицировать с помощью локального файла с именем FLAGS.
При оптимизации очень полезно знать, сколько времени расходуется в каждой части вашей программы. Программу Gprof2Dot можно использовать для создания красивых трафиков как для отдельной программы, так и для оригинального кода на Python. Программу OProfile можно использовать для профилирования модуля расширения.
Чтобы использовать Gprof2dot, загрузите файл gprof2dot.py с вебсайта и проинсталируйте Graphviz. Затем:
Чтобы использовать OProfile, установите его и используйте следующим образом.
Приёмы
Следующие два фрагмента кода работают одинаково, но поддерживается только второй:
Порядок вычисления аргументов функции или оператора print меняется при трансляции в C++, так что лучше всего не рассчитывать на него:
Кортежи с разным типом элементов и длиной > 2 в настоящее время не поддерживаются. Однако, их можно эмулировать:
Блочные комментарии, окружённые #< и #>, Shed Skin игнорирует. Эту особенность можно использовать для комментирования кода, который не может быть скомпилирован. Например, следующий фрагмент выведет точку только при запуске под CPython:
Версия 0.9.4, 16 июня 2013, Mark Dufour и James Coughlan
Конвертация кода с Python в С++ или С
Приветствую уважаемых гуру. Не может ли мне кто нибудь помочь с конвертированием кода на Python в С++?
и в каком месте тебе не понятен этот код? яб даже не сказал, что тут много питоно-специфического. просто чистое описалово алгоритма «как есть»
Есть же готовые либы для MSR206/MSR605 https://github.com/PenturaLabs/MSR605
Ну выдерни оттуда декод/энкод.
По ссылке только декод, и то странный. По хорошему мне нужен енкод\декод ISO-7811.
Что интересно, decode поворачивает биты, а encode не поворачивает (это делает write_raw). Из-за этого кодек получился не симметричный.
Что, опять в гугле забанили?
Нет, не забанили. Сам то этим пользовался?
тут оно не надо даже, алгоритм элементарный.
Так я и не спорю, просто у меня мозг плавится от синтаксиса типа:
Это просто подсчет бит, ничего сложного. Вот накидал побыстрому енкод:
А человеческим языком описания алгоритма нет нигде что ли? Это ж смерти подобно из этого говна в нормальный ЯП конвертировать! Проще с нуля написать.
Eddy_Em, залогинься ты уже наконец.
Я не пользовался, ибо на питоне почти ничего не писал.
И да, в ссылке говорится, что в PyPy конпелятор в Си, который карашо работает в том случае, если коде не использует всякие там либы.
В твоем коде, вроде бы, именно такой случай, так что рекомендую попробовать.
Обычное функци-анальное программирование на Python, ничего особенного.
Это просто переворот бит задом наперед. Бежим в цикле по всем битам и меняем их местами.
Дык надо не cython, a PyPy!
У него есть C-backend!
Ну так если умеешь, покажи уже что оно нагенерит, а то не хочется самому ставить.
Ну конечно не умею, но ради интереса могу попробовать!
Уже бы давно попробовал и нам бы показал, что там PyPy нагенерит.
PyPy генерит похожую дичь с Python.h и PyObject, насколько я понял.
Извини, анон, но спать тоже надо.
nuitka генерирует лютую хрень в духе cyphon.
shedskin генерирует лютую нерабочую хрень (не может распарсить mapping.index).
Не, у него есть jit, что какбе ускоряет процесс, то есть питон ускоряется!
А ещё там есть есть хрень для «сборки» исходников PyPy, назывеается rpython, вот она генерирует Си на основе анализа графа вызовов с добавлением в исходники всего библиотечного кода.
Попробую вечером сделать, вчера потратил время на другие генераторы кода.