В рамках одного из моих 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-проекте, здесь же хочу поделиться своими впечатлениями:
- 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 crypto rsa) RSA-шифрование
- (chibi json) операции с JSON
- (chibi net http-server) HTTP-сервер
К сожалению, документация не богатая, но компенсируется доступом ко всему исходному коду. Плюс, Chibi-Scheme известен в своих кругах, и не будет потенциально брошен или переведен в режим минимальной поддержки, как некоторые другие потенциальные кандидаты.
Буду рад услышать все комментарии, и рассмотреть другие ЯП в рамках вышеупомянутых требований. Исследование до сих продолжается, и возможно победитель сменится, но это уже будет зависеть от вас.