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

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


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


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


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

    Отдельным пунктом было требование к синтаксису ЯП по дружелюбности к транформации кода. Тут может возникнуть много вопросов, поэтому сразу уточню несколько моментов:


    • Можно трансформировать и байт-код (если он поддерживается), это могло бы убрать требования к изначальному синтаксису. Однако, в общем случае это тяжелее сделать, плюс формат байт-кода может быть проприетарным или нестабильным.
    • Обязательная трансформация, которая нам нужна, это очистка кода от отладочной и неиспользуемой функциональности. Это служит не только минификации, но и убирает некоторые векторы атак;
    • Необязательная, но желательная трансформация — минификация приватных символов, это нужно больше для обфускации и минификации;
    • Необязательная, но желательная трансформация — полное удаление переносов строк, служит больше для минимизации.

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


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


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


    Платформа: Linux amber 5.9.1-arch1-1 #1 SMP PREEMPT Sat, 17 Oct 2020 13:30:37 +0000 x86_64 GNU/Linux


    ЯП Размер ELF (KiB) RSS (KiB) Пример скрипта
    TinyScheme 84 3048 (define fn(lambda () (string-append "Hello, " (read))))
    Wasm3 159 6024 N/A [1]
    MicroPython 186 1968 import builtins; fn = lambda: 'Hello, ' + builtins.read()
    Lua 247 1760 function fn() return "Hello, " .. read() end
    Chibi-Scheme 259 3828 (define fn(lambda () (string-append "Hello, " (read))))
    Squirrel 270 1808 function fn() { return "Hello, " + read(); }
    ArkScript 443 1760 (let fn(fun() (+ "Hello, " (read))))
    Gravity 500 3524 extern var read; func fn() { return "Hello, " + read(); }
    Janet 525 4152 (defn fn[] (string "Hello, " (read)))
    ChaiScript 1342 4912 def fn() { return "Hello, " + read(); }
    AngelScript 1878 4716 string fn() { return 'Hello, ' + read(); }
    Python 3543 9320 import usermod; fn = lambda: 'Hello, ' + usermod.read()

    [1] Wasm3 работает с WebAssembly, поэтому пример кода привести нельзя (это будет бинарный дамп). Но приведу пример исходника Rust, который используется для генерации этого бинарного файла (_m3-функции используется для обмена данных с интерпретатором):


    #[no_mangle]
    pub fn r#fn() -> i32 {
        let read_str = load_m3(unsafe { read() });
        return store_m3(&format!("Hello, {}", read_str));
    }

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


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

    Победителя два:


    • Wasm3, т.к. позволяет использовать разные ЯП для написания скриптов, и достаточно компактный. К сожалению, сам по себе формат WASM достаточно небогатый (например, нет поддержки строк и сборщика мусора), и хотя WASI улучшает ситуацию, многое приходится писать самим или полагаться на рантайм, добавляемый компиляторами. Также для тестового кода я реализовал небольшой менеджер памяти, чтобы обмениваться данными между песочницой и интерпретатором, ничего встроенного wasm3 пока не имеет.
    • 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 известен в своих кругах, и не будет потенциально брошен или переведен в режим минимальной поддержки, как некоторые другие потенциальные кандидаты.




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

    Комментарии 57

      0

      Chicken не рассматривали?

        0
        Chiken требует сам себя, и я не нашел исходники bootstrap-версии, чтобы скомпилировать первичный компилятор. В принципе, я не против многофазовой сборки, но без первичной С-версии это не удовлетворяет требованию максимальной переносимости.
        0
        Python зря исключили Cython мог бы быть интересен, например

        P.S. про переносы строк пропустил
          0
          У меня очень богатый опыт внедрения Python (и написание расширений на Cython), и могу сразу сказать, что он имеет достаточно большой вклад в размер конечного бинарника (мы его встраивали в железку под урезанной версией Linux). Нам пришлось его сильно резать, включая изменения исходников (насколько я помню, он требовал pthread и эта библиотека не была нам доступна, но не уверен что современный Python имеет те же требования). К сожалению, Python не удовлетворяет нашим требованиям, но в принципе я могу его включить в проект, если это интересно.
            0
            Могу ошибаться, но мне кажется, зависимость от pthread опциональна (не знаю, как проверить, не потратив уйму времени)
            +2

            После обсуждения с коллегой решил включить Python/Cython и MicroPython тесты. Добавлю ответ, когда закончу.

            0

            Добавил Python (с примером использования Cython: https://gitlab.com/nuald-grp/embedded-langs-footprint#user-content-using-cython ) и MicroPython. Как я и предполагал, Python достаточно тяжелый (и тестовая программа даже не включала всю стандартную библиотеку, а только базовый необходимый набор).


            К моему удивлению, MicroPython очень тяжело встраивать, пришлось использовать различные трюки, чтобы заставить его работать без написания больших Makefile-ов.

            0
            Так а какие минусы у других языков? Например, чем не понравился Lua?
              –1
              Lua не поддерживает минификацию исходных скриптов, т.к. чувствителен к переносу строк (да и в целом к форматированию, хотя конечно не так сильно как Python). Поэтому он был исключен из рассмотрения.

              Что касается других языков, я не говорил, что они мне не понравились. Везде есть свои плюсы и минусы, но если сравнивать по возможностям при минимальном размере, то Chibi-Scheme в лидерах. Lua + LuaRocks — достаточно интересный вариант тоже, но с другой стороны, он уже включен в проект и все желающие могут сами с ним поиграться (хотя я думаю, все заинтересованные лица уже давно знают про Lua).
                +1

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


                А почему, кстати, вы говорите именно про переносы строк? Перенос строки, пробел, точка с запятой или ещё какой разделитель все занимают по одному байту, а вам важно уменьшить число служебных символов в принципе (чему больше мешает do…end вместо фигурных скобок, чем какие‐то там новые строки), а не конкретно переносов строк.

                  +1

                  Да и Forth никак особо на переносы строк не смотрит, а по компактности программы на форте одни из лучших даже без минимизации.

                    0

                    Как я понимаю, в Forth-е нельзя просто удалить новые строки (но, возможно, замена пробелами не сломает программу). Насчет компактности я согласен, но с другой стороны еще есть вопрос читабельности. Т.е. код пишется для человека, но потом минифицируется для машины. Компактный код на Forth-е не всегда будет достаточно читабельным.

                      +1
                      Говорить о читабельности и при этом выбрать Лисп…

                      И я поддерживаю, что минимификация исходного текста по всем параметрам — скорость исполнения, размер, используемая память, проигрывает байкоду при его наличии, и является неудачным требованием. Которое ко всему прочему еще и сильно ограничило выбор языков.
                        +1

                        В форте новые строки точно можно убирать. А читабельность — смотря как писать. Лет пять назад я для развлечения писал решето Эратосфена на разных языках — по одному на каждую букву алфавита. Меньше всего получился скрипт для dc, но я его уже через день не понимал. Второй был форт — и он и сейчас с лёгкостью читается.
                        Ни до ни после я никогда на форте профессионально не писал, так что большого опыта чтения форта никак нет

                          0
                          Компактный код на Forth-е не всегда будет достаточно читабельным.

                          Мoжет такое дискуссионное обсуждение, не претендующее на полноту, кому то даст «пищу» для понимания возможностей и «выживаемости» языка в современных реалиях IT :)
                          Почему обречён язык Форт
                        –1

                        Переносы строк — это просто один из примеров, конечно использование do/end тоже может сильно влиять. Более того, замена на пробел != полное удаление. В одном из моих проектов мы делали минификацию встроенного HTML, и простое удаление переносов позволило сэкономить 5% от суммарного размера исходных файлов.


                        Обновлено, 30% — полная минификация, удаление новых строк дало 5% (HTML был автогенерирован, так что там было достаточно много новых строк).

                          0
                          В HTML нельзя просто взять и убрать переносы строк, это может изменить DOM: xahlee.info/js/js_dom_whitespace_nodes.html
                            0

                            DOM — это отдельная история, переносы строк на сам рендеринг HTML не влияют (по-крайней мере, наши тестеры и клиенты из Fortune 500 не жаловались, при всем разнообразии поддерживаемых браузеров включая IE6). Естественно, могут быть нюансы, но кросс-браузерная разработка давно заставила всех использовать только безопасное API с правильными селекторами (или просто использовать библиотеки, где это все учитывается).

                          +1

                          напомнило старую эпичную тему про "синтаксический оверхед"

                          +1
                          Lua не поддерживает минификацию исходных скриптов.

                          Читаемость/редактируемость минимизированных скриптов при этом отпадает, почему бы тогда сразу в луа-байткод не "компилировать"?
                          Ну и раз сравнение именно по размеру, ванильная lua собранная TCC+UPX в 64кБ помещается.


                          QuickJS ещё добавить к сравнению можно было бы.

                            0
                            Луа не чувствителен к переносу строк, если только речь не о многострочных строковых литералах. Более того, если нужна минификация, можно вообще скомпилировать скрипты в байт-код, и в подавляющем большинстве случаев он прозрачно подхватится.
                          +1
                          А что скажет на это Tereshkov?
                            0
                            Трудно быть беспристрастным, когда сам являюсь автором языка Umka из упомянутого обширного перечня. Однако таблица со сравнением по одному лишь размеру файла кажется несколько странной, как и то, что в ней перемешаны процедурные и функциональные языки (неужели нет априорных предпочтений на сей счёт?).
                            Кстати, формально Umka вполне удовлетворяет перечисленным требованиям. Любопытно мнение автора, почему он не попал в итоговый список.
                              0

                              Насколько я вижу, Umka чувствителен к новым строкам, их нельзя просто удалить, так что требования к возможности минификации скриптов не удовлетворяются. Насчет предпочтений процедурных vs функциональных — абсолютно нет. Если уж совсем захочется каких-то возможностей, то всегда можно организировать транспиляцию (и тогда возможность ЯП работать с машинно-генерируемым скриптом тоже пригодится, и я это включаю в категорию "дружелюбность к минификации").


                              Прошу заметить, что я не считаю, что у вашего продукта есть какие-то недостатки. Естественно, у него есть своя ниша и он там занимает достойное положение. Просто немного не подходит под мои требования. Впрочем, т.к. я уже включил Lua и собираюсь включить Python, я могу включить и ваш ЯП, если есть интерес.

                                0
                                А чем пробел ' ' принципиально отличается от новой строки '\n', который обязателен в используемом Lua (и присутствует в примерах каждого скрипта)? Или под «чувствителен к новым строкам» имеется в виду «выравнивание — часть синтаксиса» как в python?
                                  0

                                  Под «чувствителен к новым строкам» я подразумеваю, что если полность удалить переносы строк, код перестанет работать. Замены на пробелы потенциально может работать, но насколько я понимаю, это особенность Lua (признаюсь, про которую я не знал).

                                    0

                                    Мне всё же не совсем понятно, чем '\n' в данном случае будет принципиально отличаться от того же ';' как разделитель выражений. Какой-то символ-терминатор всё равно будет.

                                      +1

                                      Думаю, лучше привести примеры кода (JS):


                                      function f1() {}
                                      function f2() {}

                                      Можно объединить без разделителей (а ";" в выражениях и так нужна, хотя она и опциональная): function f1() {}function f2() {}
                                      В Scheme/Lisp вообще нет разделителей:


                                      (define a 1)
                                      (define b 1)

                                      Объединяются в одну строку: (define a 1)(define b 1)


                                      Так что все зависит от ЯП.

                                  +1
                                  В Umka, как в Go, разделителем является ';' — либо реальная, либо подразумеваемая (в конце строки). Так что просто удалить переносы строк нельзя, однако всегда можно заменить их на ';'. Впрочем, как заметил другой комментатор, какой-то разделитель всё равно нужен. Вы привели пример на Lisp, однако там в той же роли выступают скобки, причём скобка — парный символ, так что в общей сложности их оказывается больше, чем нужно для разделения.

                                  Если уж искать в Umka препятствия к минимализации, то это будет необходимость указывать типы аргументов и результата функции — очевидная издержка статической типизации. Но тогда и само понятие о минимализации надо расширять и уточнять.

                                  Umka пока не столь уж известен, чтобы я оскорбился его отсутствием в вашем списке :) Однако с первого прочтения я действительно не понял, какому именно требованию он не удовлетворил. И в целом, казалось странным, как эти требования оставили от пары сотен языков всего 8, причём довольно экзотических.
                              0

                              Под какую платформу это компилировалось?
                              И какая область применения? Для stm32 вроде жирновато, а для апельсинки и питон годится.

                                0

                                Под обычный Linux — некоторые ЯП достаточно экзотичны и имеют весьма скудную документацию. Собственно, некоторые я смог завести (чтобы подключить их в виде библиотеки) только изучив их исходный код, так что поддержка кросс-компиляции — это отдельная история, на которую у меня, к сожалению, нет времени.


                                Область применения — массовые потребительские устройства (включая бюджетные типа телефонов на KaiOS), микроконтроллеры и SoC у нас есть в планах, но далеких. Т.к. на некоторых устройствах (типа той же KaiOS) нет возможности исполнять нативный код, то одна из поддерживаемых target — это WASM, и засовывать туда 5 мегабайт пайтона сверху (которые надо будет пользователю скачать в условиях ограниченного хранилища и дорогого интернета) — это роскошь.

                                  +3

                                  А вы не думали просто использовать WASM? И компилировать в него всё что душе угодно, включая C/C++? Заодно нет оверхеда на рантайм.

                                +7

                                довольно бестолковое сравнение. На кой ляд учиывать переносы строк, если можно запускать уже скомпилированный байткод? Наприиегр в луа, при рравильном использовании local и переименовании global, это даст не только компактный размер, но и бесплатную обфускацию.


                                Но это все лирика. Главный минус статьи — отсутствие оценки потребления RAM. А это основное ограничение встраиваемых систем. В тот же STM32F103 луа поместится запросто, (особенно в верию с 1мб флеша), а вот оперативки свободной не будет уже после пары сотен строк реального кода. Почитайте как допиливали белку, чтобы ужать потребление ОЗУ на микроконтроллерах. Там и разделяемые (shared) строки, и жадное создание констант, и перепаковка полей обьектов, целый букет оптимизаций.

                                  –1

                                  Не все встраиваемые ЯП поддерживают байткод. Более того, возможно мы немного по-разному понимаем обфускацию. Для меня это возможность минимизировать и запутать код (вплоть до изменения хода выполнения кода путем вставления и реорганизации вызовов). Байткод не обязательно обфусцированный, хотя конечно, он компактнее исходного кода. luac -l -l -p дает достаточно читабельное представление байткода Lua, хотя, конечно, я верю, что есть специальные обфускаторы. Однако все это весьма специфично для конкретных ЯП и если есть возможность обфусцировать на уровне исходного кода, это предпочтительнее для нас (но, естественно, может быть неудобно для других и им лучше использовать байткод и сторонние утилиты).


                                  Согласен, что неплохо было бы показать использование RAM. К сожалению, для "Hello world" примера числа будут весьма "бестолковые" тоже, т.к. только специфические конструкции или библиотеки могут вызывать большой расход памяти. Однако какие-то числа лучше чем вообще никакие, так что я добавлю это в тесты (https://gitlab.com/nuald-grp/embedded-langs-footprint/-/issues/4)

                                  0
                                  Посмотрите ещё на mruby.
                                  И для некоторых реализаций можно выключить парсер/компилятор, оставив только VM, что положительно сказывается на объёме результирующего исполняемого файла.
                                    0

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

                                    +1
                                    Забавно, что при задаче «наименьший эффект на размер конечного бинарного файла» – ни одного языка, умещающегося в 64k (Форт, если мне не изменяет память, с необходимым набором слов помещался то ли в 4, то ли в 8 – но он, конечно, не решает задачу типизации; бейсик на 8-битных машинах обычно лежал в ROM размером 16k – на этом фоне 86-1879k кажутся огромными).

                                    ЗЫ: я понимаю, что в нынешних масштабах это несущественно, и реальная задача скорей будет вроде «не больше 2 мегабайт, но максимально удобный нашим юзерам / максимально просто интегрирующийся с нашей системой».
                                      0
                                      Спасибо автору за столь подробную подборку фреймворков скриптовых языков.
                                      Честно говоря, не ожидал, что для C такое множество решений для встраивания.
                                      Но мне интересно, почему Opject Pascal остался обделённым?
                                      Каким критериям автора он не удовлетворяет?
                                      Не подскажите?
                                        +1

                                        Object Pascal не является таким переносимым, как Си — например, так просто скомпилировать его в WASM, или для микроконтроллеров (как вышеупомяный stm32) вряд ли получится (даже если решения есть, они не такие распространенные, и могут иметь проблемы).

                                        +2
                                        А на c4 вы не смотрели?
                                          0

                                          GPL-лицензия, не подходит для коммерческого использования.

                                            0

                                            libtcc — LGPL

                                              0
                                              Там компиляция в прямой машинный код в адресном пр-ве вызывающей программы.

                                              Скриптом легко уронить хоста.
                                                0

                                                спавнить отдельный процесс,
                                                пусть там падает сколько угодно.

                                                0

                                                tcc уже несколько лет как фактически заморожен, т.к. его автор больше над ним не работает (https://bellard.org/tcc/):


                                                [Note: I am no longer working on TCC. Check the mailing list to get up to date information.]

                                                Плюс он компилирует в машинный код, что нам не особо подходит (например, не будет работать в WASM VM).

                                          0

                                          А что на счёт WebAssembly? Рантаймов разных много на любой вкус.
                                          И ЯП под это дело можно выбрать по вкусу. Например https://vlang.io/

                                            0
                                            Когда в V разгребут тонну опасных косяков и хотя бы как-то научатся освобождать выделенную память — тогда его можно будет воспринимать всерьёз.
                                              0

                                              Мы поддерживаем компиляцию в WASM, но внедрение его VM — это совершенная другая история. Мы рассматривали это, но не подошло, в частности из-за того, что не нашли подходящую под наши требования VM. Все, что мы нашли, были реализованы:


                                              • как надстройка к node.js -> V8. Слишком тяжелый рантайм, плюс сборка V8 — это отдельное приключение (возможно, Blink собирается проще, но все-равно тяжеловесный);
                                              • на Go (например, https://github.com/perlin-network/life). Go добавляет свой собственный рантайм, плюс может иметь проблемы с биткодом (https://github.com/golang/go/issues/22395 — возможно, это решено сейчас, но зная Apple, они могут это сломать в любой момент)
                                              • на Rust (например, https://github.com/bytecodealliance/wasmtime). Проблем с рантаймом нет, но зато есть с биткодом (https://github.com/rust-lang/rust/issues/35968)
                                              • компилируют на ходу (например, https://github.com/WAVM/WAVM). Включают очень тяжелый LLVM.

                                              К сожалению, мы не нашли реализацию на чистом C/C++, но если вы знаете какую-либо, дайте знать пожалуйста.

                                                0

                                                Есть один интересный проект: https://github.com/wasm3/wasm3. Это обычный интерпретатор. Некоторые фичи там еще не реализованы, но проект по мне очень перспективный. Однако в прод такое пока еще страшно отпускать.

                                                  +1

                                                  Спасибо за ссылку, действительно интересный проект. Судя по всему, он удовлетворяет нас по всем требованиям, и есть возможность биндинга нативных функций, пусть даже еще не задокументированная (https://github.com/wasm3/wasm3/pull/71). Насчет прода я не особо переживаю, если проект стоящий, то можно найти ресурсы или спонсоров, чтобы его допилили.


                                                  Я постараюсь включить его в тесты, и дам вам знать результаты.

                                                    0

                                                    Добавил тест и обновил статью. Документации достаточно мало, плюс нет API для взаимодействия, поэтому написал небольшой менеджер памяти для обмена данных (у меня совсем вылетело из головы, что в WASM-е строк и вообще работы с памятью толком нет, и многие решения основаны на том, что все запускается в JS).


                                                    В принципе, качество работы вполне удовлетворительное (правда, C++ биндинги подкачали, но это дело наживное). Будем обсуждать с коллегами, но лично я вижу два главных препятствия для того, чтобы wasm3 стал первичным кандидатом для нас:


                                                    • большой расход памяти (проверил valgrind-ом, утечек нет, просто расход большой);
                                                    • [не специфично для wasm3] требуется большой рантайм в самом WASM для хорошей функциональности (я попробовал два варианта: 1) no_std дал размер в несколько десятков байт, но весьма скудная функциональность; 2) полноценный Rust добавил сразу большой рантайм, и хотя стало комфортно программировать, WASM-файл занял несколько сотен килобайт ). Я пытался урезать, но толку мало, все-равно достаточно большие файлы без no_std.

                                                    Конечно, компилятор Rust не единственный, можно и Emscripten, но он тоже добавляет свой рантайм, а функциональность будет намного хуже чем в Rust. Впрочем, к самому проекту это отношения не имеет, это отдельная история, и можно рассмотреть те же v-lang, nim и т.п. Дополнительно остается, конечно, вопрос производительности, но этим я буду заниматься в рамках других проектов. Еще раз спасибо за ссылку, при всех сомнениях wasm3 все-равно остается хорошим кандидатом для встраивания.

                                                      0
                                                      Не очень несовсем нифига непонятны ваши цели. ТЗ нет, и мечетесь как селедки в трале. wasm он как то попендикулярен всему
                                                        0

                                                        Не совсем понял, как это wasm перпендикулярен? Байт-код — это подмножество скриптов, какая разница это бинарный формат или строковой. Lua-байткод не подходил, потому что это проприетарный формат, а оригинальный код не совсем соответствовал требованиям. Wasm стандартизирован, и имеет богатый тулчайн, вплоть до того, что мы можем спокойно модифировать сам байткод, не беспокоясь, что это сломается завтра.

                                                          +1
                                                          Wasm перпендикулярен ЯП, потому что многие ЯП имеют генерацию в код Wasm. (И должны удовлетворять требованиям отсевки, по идее???)

                                                          Какая то двойственность: этот байт код (wasm) нам подходит, а этот — не подходит; этот ЯП подходит, поскольку минимифицируется, а этот не подходит, потому что компилируется в байткод… да просто так захотелось.

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

                                                Используем в проекте его вот уже больше 10 лет, и я категорически не согласен с приведённым утверждением.
                                                Но некоторые ошибки иногда бывает сложно диагностировать.

                                                И, кстати, на Squirrel-е можно написать вот так:
                                                fn <- @() "Hello, "+read();

                                                Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                                Самое читаемое