Сравнение встраиваемых ЯП по размеру в исполняемом файле

от автора

В рамках одного из моих SDK-проектов нам понадобилось добавить скриптование, которое бы оказало наименьший эффект на размер конечного бинарного файла, но при этом предоставляло хорошую фунциональность. Это дало старт проекту, который описан в этой статье. Прошу заметить, что т.к. в SDK у нас есть определенные требования, они частично перенеслись на язык скриптования, поэтому в проекте не участвовали некоторые достаточно известные встраиваемые ЯП (но Lua включен для сравнения).

Сайт проекта доступен по ссылке https://gitlab.com/nuald-grp/embedded-langs-footprint Скажу сразу, что на данный момент для меня лично победителем является Chibi-Scheme. Подробности для заинтересовавшихся под катом.

Требования были следующие:

  • Максимальная переносимость (только C/C++).
  • Достаточно строгая типизация (не позволяющая складывать апельсины с яблоками), соответственно реализации ECMAScript не рассматривались.
  • Удобство минимизации самих скриптов (например, чтобы можно было безопасно удалить все переносы строк), соответственно реализации Forth, Lua и Python не рассматривались.
  • Лицензия, дружелюбная к коммерческим проектам.

Изначальный список был взят с проекта, в котором они пытаются учесть все возможные встраиваемые ЯП: https://github.com/dbohdan/embedded-scripting-languages Возможно, список не полный, и не содержит дополнительные ЯП, которые могли бы удовлетворять вышеуказанным требованиям. Если вы знаете о таких, пожалуйста, дайте мне знать либо в личку, либо комментарием.

Тестовый код для всех ЯП включал в себя создание и вызов функции, которая складывает "Hello, " и результат вызова внешней (C/C++) функции, возвращающей "world". Код функции представлен в таблице как образец синтаксиса. Конечный исполняемый файл скомпилирован с оптимизацией по размеру и с удалением всех ненужных символов (GCC -s).

Также должен отметить, что хотя изначальный список был достаточно большой, в итоге вышеуказанным требованиям удовлетворили всего 8 ЯП (Lua в списке только для сравнения):

ЯП Размер (байты) Пример скрипта
TinyScheme 86824 (define fn(lambda () (string-append "Hello, " (read))))
Lua 252880 function fn() return "Hello, " .. read() end
Chibi-Scheme 261480 (define fn(lambda () (string-append "Hello, " (read))))
Squirrel 277008 function fn() { return "Hello, " + read(); }
ArkScript 449792 (let fn(fun() (+ "Hello, " (read))))
Gravity 507896 extern var read; func fn() { return "Hello, " + read(); }
Janet 537560 (defn fn[] (string "Hello, " (read)))
ChaiScript 1374976 def fn() { return "Hello, " + read(); }
AngelScript 1923960 string fn() { return 'Hello, ' + read(); }

Описание и документация по этим ЯП приведены в GitLab-проекте, здесь же хочу поделиться своими впечатлениями:

  • TinyScheme реализует лишь подмножество R5RS, используется в GIMP. Если бы не было Chibi-Scheme с полноценной поддержкой R7RS, возможно стал бы победителем. Также немного смущает хостинг на SourceForge используя SVN репозиторий с одной только trunk-веткой.
  • ChaiScript очень интересный — наверное самый простой по удобству встраивания, плюс поддерживается крупными компаниями. К сожалению, тот факт, что он состоит только из заголовочных файлов, очень сильно замедляет компиляцию (мой Dell XPS 13 компилирует минимум 2-3 минуты). Также, он достаточно сильно увеличивает размер исполняемого файла.
  • Gravity может понравиться любителям Swift. Достаточно интересный ЯП, но к сожалению, не так много документации. Ориентирован на мобильную разработку.
  • Squirrel достаточно компактный, но достаточно сложно встраивать (любая ошибка в работе со стеком вызовов приводит к краху приложения — у них недостаточно хорошая система обработки ошибок).

Chibi-Scheme стал победителем, т.к. поддерживает современный компактный Scheme (R7RS) и имеет достаточно большую дополнительную библиотеку (плюс стандартная библиотека Scheme и возможность использовать уже написанный код). Естественно, встраивание библиотек увеличит конечный код, но даже без библиотек он может полноценно работать (тестовый код не встраивал init-7.scm полностью, а только добавил процедуру string-append).

Встраивание внешних процедур достаточно простое (хотя я вставил лямбду, Chibi-Scheme полноценно работает с чистым C):

res = sexp_define_foreign(*ctx, sexp_context_env(*ctx), "read", 0,                           [](sexp ctx, sexp self, sexp_sint_t n) -> sexp {                             return sexp_c_string(ctx, "world", -1);                           });

Из интересных дополнительных модулей хотел бы отметить:

К сожалению, документация небогатая, но компенсируется доступом ко всему исходному коду. Плюс, Chibi-Scheme известен в своих кругах, и не будет потенциально брошен или переведен в режим минимальной поддержки, как некоторые другие потенциальные кандидаты.


Буду рад услышать все комментарии, и рассмотреть другие ЯП в рамках вышеупомянутых требований. Исследование до сих продолжается, и возможно победитель сменится, но это уже будет зависеть от вас.

ссылка на оригинал статьи https://habr.com/ru/post/524190/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *