Каким должен быть компилятор будущего?

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

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

Мы считаем, что нашли ответ. Встречайте AsmX G3 v29.

Это не просто обновление. Это кульминация нашей эволюции: отточив в предыдущих версиях стабильность и скорость генерации кода, мы перешли на следующий уровень. AsmX теперь берет на себя самую сложную и рутинную часть работы — упаковку и подготовку к дистрибуции.

С этого дня AsmX G3 v29 — это первый в своем роде компилятор с нативной поддержкой упаковки для Debian-based систем (.deb).

Что это значит на практике?

  • Никаких сторонних утилит. Забудьте о сложных сборочных скриптах и ручной конфигурации пакетов.

  • Одна команда — полный цикл. Вы пишете код, а AsmX компилирует его, правильно упаковывает со всеми зависимостями и готовит к загрузке в репозитории.

  • Экосистемный подход. Мы понимаем, что Linux — это мир разнообразия. Поэтому мы реализовали нативную поддержку самых влиятельных форматов пакетов, покрывая огромную часть дистрибутивов от Ubuntu и Mint.

Добро пожаловать в будущее компиляции. Оно уже здесь.

Введение

Мы не просто выпускаем обновления. Мы переосмысливаем процесс разработки. Пока другие обсуждают, мы создаём. Пока скептики сомневаются, мы пишем код. AsmX G3 v29 — это не очередной релиз. Это наш ответ на вопрос: «Как должен выглядеть компилятор в 2025 году?». Это инструмент, который даёт разработчикам полный контроль над железом, от машинного кода до готовых к дистрибуции пакетов. Это философия, где производительность, простота и открытость — не компромисс, а стандарт.

Этот релиз — результат тысяч строк кода, бессонных ночей и обратной связи от сообщества. Мы услышали ваши вопросы, критику и предложения. Мы не пошли на компромиссы с нашим видением, но сделали AsmX ближе к реальным задачам: от низкоуровневого программирования до создания приложений, готовых к установке на миллионы Linux-систем. С поддержкой .deb-пакетов мы открываем двери для разработчиков, которые хотят не просто писать код, а распространять его по всему миру.

Приготовьтесь. AsmX G3 v29 — это не просто компилятор. Это мост между вашим кодом и реальным миром который не просто создает программы, а доставляет их пользователю. Это наш вызов индустрии — и приглашение вам присоединиться к созданию будущего.

О главном: Прямые ответы на острые вопросы

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

1. «Не ясен кому этот проект нужен (то есть нет заказчика)...»

Заказчик? Скажите, кто был заказчиком у Кернигана и Ритчи, когда они в стенах Bell Labs создавали C? Кто заказывал Линусу Торвальдсу ядро операционной системы, которое сегодня работает на большинстве серверов мира? Великие проекты рождаются не из коммерческих заказов, а из инженерной необходимости и видения будущего. Мы создаем инструмент для тех, кто понимает, что производительность и полный контроль — это не опция, а фундаментальное требование.

Пользователи приходят туда, где есть технология, решающая реальные задачи. Kotlin годами был нишевым языком, пока его не признали стандартом для Android. Мы играем вдолгую. А что касается денег — да, я не против продавать этот продукт. Но он будет стоить дорого, потому что инновации, тысячи часов работы и бессонные ночи инженеров имеют свою цену.

2. «...сначала делают функциональную модель с элементами математики... Этого шага нет.»

Мы инженеры, а не теоретики. Наша "математическая модель" — это работающий код, подкрепленный исчерпывающими тестами. Мы не тратим время на построение абстрактных гипотез, популярных в академических кругах с их Haskell и монадами. Наша лаборатория — это кодовая база, а наши доказательства — это работающие тесты, такие как опубликованный набор hwm/units. Мы проверяем идеи на практике, в реальных условиях, потому что только так создаются инструменты, которыми действительно можно пользоваться, а не только восхищаться на бумаге. Это не "отсутствие шага", это другой, более прагматичный подход.

3. «Код проекта... ужасен... таблицы описания процессоров должны быть отделены от алгоритмов...»

Давайте говорить на языке фактов, а не эмоций. Описание архитектуры (ISA) и алгоритмы её кодирования в модуле hwm (Hardware Machine) уже разделены.

  • Описание архитектуры находится в файле tbl.cts. Это декларативные таблицы, которые определяют инструкции и их варианты.

  • Алгоритм кодирования находится в main.cts. Это логика, которая берет описание из tbl и преобразует его в машинный код.

  • База данных регистров (rdb) co-лоцирована в main.cts для производительности и удобства, но логически это отдельная сущность.

Они существуют в разных файлах и выполняют разные, четко очерченные роли. Это и есть правильное разделение ответственности.

Теперь о JSON. Использовать его здесь — значит добровольно добавить хрупкий слой парсинга и потерять всю мощь и безопасность строгой типизации, которую нам дает TypeScript. Преобразование "сырых" данных из JSON в сложные, вложенные типизированные интерфейсы — это лишний шаг, который только увеличивает вероятность ошибок. Вы просили больше TypeScript — вы его получили, и мы используем его сильные стороны по максимуму. Мы выбираем инженерную надежность, а не слепое следование трендам.

4. «...про оптимизацию алгоритмов в вашем проекте – ни слова.»

Оптимизация чего именно? Абстрактных алгоритмов? Если речь о высокоуровневых оптимизациях, таких как формы SSA (Static Single Assignment), то на уровне ассемблера они просто неуместны. AsmX — это инструмент для прямого управления железом. Его философия — не исправлять за программистом неэффективный код, а дать ему возможность написать изначально оптимальный.

Мы даем в руки хирурга скальпель, а не автоматизированный медицинский дрон. Интеграция с LLVM превратила бы проект в громоздкую, многоязыковую систему и лишила бы нас главного — полного контроля. Мы выбираем чистоту, скорость и прямоту. Оптимизация заложена в самой архитектуре компилятора, которая генерирует предсказуемый и эффективный машинный код без "черных ящиков".

Вперед, в 64-битное будущее: Почему мы не оглядываемся назад

Давайте начистоту: 32-битные системы — это прошлое. Технологический долг. Мы не создаем продукты для прошлого.

Начинать сегодня с поддержки x86 — это все равно что проектировать автомобиль с карбюратором. Зачем? Чтобы потом героически решать проблемы перехода на 64-битную архитектуру? Нет, спасибо. Мы сразу строим на современном фундаменте — amd64 (x86_64), потому что именно здесь находится настоящее и будущее высокой производительности.

Гиганты индустрии, такие как gcc и clang, вынуждены тащить за собой огромный багаж совместимости, включая поддержку 32-битных систем. Этот "лишний вес" замедляет их и усложняет. Мы же свободны от этого. Наш фокус на amd64 — это не ограничение, а стратегическое преимущество. Мы создаем легкий, быстрый и современный инструмент для мира, который уже давно стал 64-битным.

Микроархитектуры: Почему мы говорим «Нет» безумию уровней

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

Многие из вас, вероятно, слышали о так называемых "уровнях" x86-64: v2, v3, v4. Это попытка классифицировать поколения процессоров по набору поддерживаемых инструкций. На первый взгляд, идея кажется здравой. Вот таблица, которая иллюстрирует этот подход:

Вы можете даже проверить, какие уровни поддерживает ваша собственная система, выполнив команду:

$ /lib64/ld-linux-x86-64.so.2 --help
Subdirectories of glibc-hwcaps directories, in priority order:
  x86-64-v4 (supported, searched)
  x86-64-v3 (supported, searched)
  x86-64-v2 (supported, searched)

Надпись (supported, searched) означает, что ваша система готова работать с этими наборами инструкций.

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

Посмотрите на это письмо от Линуса Торвальдса, создателя Linux. Это не просто мнение, это приговор.

Давайте разберем, почему он так категоричен, и почему мы разделяем его позицию на 100%.

1. Это искусственная и неофициальная модель.
Линус пишет: "The whole "v2", "v3", "v4" etc naming seems to be some crazy glibc artifact... as far as I can tell, the "microarchitecture levels" garbage... is's entirely unofficial".

Эти уровни — не стандарт Intel или AMD. Это внутренняя классификация, придуманная разработчиками glibc для своих нужд. Пытаться сделать ее универсальным стандартом — значит строить дом на чужом, шатком фундаменте.

2. Линеаризация возможностей процессора — это фундаментально неверно.
"Trying to linearize those bits is technically wrong, since these things simply aren't some kind of linear progression."

Архитектура процессора — это не лестница, где каждая следующая ступенька включает в себя все предыдущие. Это сложное дерево возможностей. Процессор может поддерживать инструкцию из "v3" (например, AVX2), но не иметь какой-то другой, более старой. Попытка втиснуть это многообразие в жесткие, линейные уровни — это самообман. Модель сломана в своей основе.

3. Это "упрощение", которое на самом деле всё усложняет.
Это ключевой аргумент Линуса: "And worse, it's a "simplification" that literally adds complexity. Now instead of asking "does this CPU support the cmpxchgb16 instruction?", the question instead becomes "what the hell does 'v3' mean again?"

Вместо прямого и честного вопроса к оборудованию ("Поддерживаешь ли ты X?"), разработчик вынужден обращаться к непрозрачной, искусственной таблице и вспоминать, что же именно скрывается за меткой v3. Это путь к ошибкам, путанице и неоптимальным решениям.

Наш подход: Инженерная ��равда вместо хрупких абстракций

Правильный путь, о котором говорит Линус, — это ориентироваться на CPUID биты. Это механизм, с помощью которого процессор сам сообщает, какие наборы инструкций (ISA sets) он поддерживает. Это единственный источник правды.

Поэтому в AsmX G3 мы не будем играть в эти уровни. Наша стратегия — дать разработчику возможность явно указывать, какие наборы инструкций он хочет использовать: SSE2, AVX, AVX512, BMI2 и так далее. Это прозрачно, точно и напрямую отражает возможности железа.

Если в будущем появится SSE6, он станет доступен на новых процессорах как новый, отдельный набор инструкций. Пытаться "втиснуть" его в существующую иерархию уровней было бы абсурдом.

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

«So no. We are NOT introducing that idiocy in the kernel.»

И мы говорим то же самое:
Так что нет. Мы НЕ вводим этот идиотизм в наш компилятор.

Изменения в TAPI: Более гибкий парсинг командной строки

TAPI — это наш внутренний парсер аргументов терминала, который лежит в основе обработки всех флагов и команд. В v29 мы значительно улучшили его, сделав более удобным и устойчивым к ошибкам. Вот ключевые изменения:

  • Поддержка дефисов в длинных флагах. Раньше для длинных опций использовался символ @ (например, --llvm@version). Теперь мы перешли на стандартный подход с дефисами: --llvm-version. Это делает CLI более интуитивным и совместимым с другими инструментами, такими как gcc или clang. Внутренняя логика TAPI адаптирована под это: флаги очищаются от префиксов (--) и заменяются на подчеркивания для нормализации (например, --llvm-version становится llvm_version).

  • Добавлена обработка неизвестных флагов. Если флаг не распознан, TAPI теперь выбрасывает явную ошибку: asmx: error: unrecognized command-line option ‘--unknown-flag’. Это помогает отлавливать опечатки на ранних этапах и предотвращает тихие сбои.

  • Новые флаги для удобства и отладки:

    • --emergency-panic: Включает режим аварийной паники при ошибках. Если компилятор завершается с неясной причиной, выводится полный стек-трейс и диагностика. Полезно для баг-репортов: отправьте это в issues (если они открыты), но укажите детали и скриншоты.

    • -q / --quiet: Подавляет все выводы, кроме сообщений от LLVM.js. Идеально для автоматизации или когда нужен чистый результат без логов.

    • -a / --aliases: Выводит список доступных алиасов (например, для архитектур: x86_64x86-64, x64, intel64, amd64). Полезно для быстрой справки.

    • --help=llvm: Отображает только флаги, связанные с LLVM (например, --llvm-version, --llvm-dumpversion, --llvm-repository).

    • --help=common: Показывает общие опции.

    • --help=package: Выводит флаги для упаковки (подробнее ниже).

    • --export-json-isa: Экспортирует набор инструкций (ISA) в JSON-файл для выбранной архитектуры. Полезно для анализа или интеграции с другими инструментами.

Эти изменения делают TAPI более зрелым: теперь он не только парсит, но и валидирует ввод, снижая вероятность ошибок.

Изменения в проекте и kernel: Стабильность и новые возможности

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

  1. JournalService: Новый менеджер логов. Это как упрощенный journalctl для AsmX. Он классифицирует сообщения (error, warn, info и т.д.) и позволяет контролировать вывод. Поддерживает эмодзи-префиксы для визуальной ясности (✔ для успеха, ⚠ для предупреждений). В тихом режиме (--quiet) подавляет все, кроме критичного. Пока не контролирует выводы LLVM.js, но это в планах. Представьте: вместо хаоса в терминале — структурированный лог, где ошибки подсвечены красным, а успехи — зелёным. Это инструмент для отладки.

  2. Улучшенный --dumpversion. Теперь выводит полную версию с ревизией: Version: v29 (rev 1.0). Полезно для трекинга обновлений в скриптах или CI/CD.

  3. Расширенная информация о CPU. При запуске компилятор выводит точные данные: архитектуру (например, amd64-unknown-linux-gnu) и микроархитектуру (например, Meteor Lake для Intel 14-го поколения). Мы парсим os.cpus() и сопоставляем с известными поколениями процессоров. Это помогает в отладке: "Ага, на Raptor Lake код работает быстрее благодаря AVX-512". Нет предположений — только факты от железа.

  4. Переход на --target вместо --march. Для указания архитектуры теперь используйте --target amd64 (или алиасы вроде x86_64). Это более стандартный термин, как в clang. Старый флаг удален для чистоты кода — меньше путаницы, больше скорости.

  5. Общий дефолтный вывод для всех бэкендов. Теперь имя выходного файла по умолчанию — a.out для всех архитектур (раньше зависело от бэкенда). Логика вынесена в kernel: const outname = terminal_arguments.objname || GVE.GCR_DEFAULT_OUTPUT_FILENAME_FOR_ALL_BACKENDS;. Это унифицирует поведение — компилируй на amd64 или в будущем на arm64, результат предсказуем.

  6. Новый слой: __asmx_prepare_pipeline_factory_fn. Это пайплайн для обработки флагов: заменяет алиасы (например, x64amd64), проверяет наличие бэкендов и пакетов в директориях ./backend/targets и ./backend/packages. Если архитектура или тип пакета не поддерживается, ошибка с подсказкой: Server.journal.error("The ${pair_v} architecture is not supported");. Код использует fs.readdirSync для сканирования и aliases.getTargetAlias для нормализации. В будущем — рефакторинг: разбить на модули.

  7. Счетчик предупреждений и ошибок. Теперь в конце компиляции выводится: 0 Warnings, 0 Errors. (или актуальные числа). Реализовано через JournalService: this.count_warnings += 1; в throw_warning(), и printWarningStats(). Пока это в kernel и ZGEN; в JITC добавим позже.

Революция в дистрибуции: Как AsmX научился упаковывать код в .deb пакеты — и почему это меняет всё

Это то событие, которое для меня как прорыв в космос. Помните, как SpaceX впервые посадила Falcon 9? Вот так же и здесь: AsmX G3 v29 не просто компилирует код — он упаковывает его в полноценные .deb пакеты, готовые к установке на Ubuntu, Debian, Mint и другие. Это не фича на полке; это мост от сырых бинарников к реальному миру дистрибуции. Я просидел над этим неделями, разбирая форматы архивов, скрипты и зависимости. И это круто, потому что решает проблему: "Скомпилировал — а как распространить?" Теперь просто: скомпилируй, упакуй, установи через dpkg. Без лишних инструментов, прямо из AsmX.

Давайте разберём это как инженеры: шаг за шагом, от формата .deb до нашего кода. Я объясню, как работает .deb под капотом, почему мы выбрали именно этот подход, и покажу иллюстрации структур. Без пафоса — просто факты и код, чтобы вы могли повторить или улучшить.

Почему .deb? И почему именно сейчас?

.deb — это стандарт для Debian-based систем, которые доминируют в серверах и десктопах (Ubuntu — 30% рынка Linux). Формат простой, но мощный: позволяет встраивать зависимости, скрипты, иконки и даже desktop-интеграцию. Мы начали с него, потому что он решает 80% случаев: от простых утилит до приложений с GUI. В будущем добавим другие типы пакетов, но .deb — это база.

В AsmX мы реализовали это в ./backend/packages/deb/builder.cjs и драйвере ./backend/packages/driver.cjs. Нет зависимостей от dpkg-deb или fakeroot — всё на чистом Node.js с fs, zlib и crypto. Почему? Чтобы AsmX работал везде, даже без Debian-tools. Это даёт контроль: мы генерируем пакеты на Windows или macOS для Linux-целей.

Как устроен .deb-пакет: Разбор формата от А до Я

устройство .deb пакета
устройство .deb пакета

Давайте нырнем в технические детали. Я не люблю поверхностные объяснения — они как ракеты без топлива: выглядят круто, но не взлетают. Поэтому разберём формат .deb шаг за шагом, с примерами кода из нашего проекта и иллюстрациями структур. Это не академический трактат, а инженерный гид: вы сможете взять это и реализовать сами, если захотите.

.deb — это не просто ZIP с метаданными. Это ar-архив (да, тот самый формат от Unix, используемый в библиотеках вроде .a), содержащий ровно три файла:

  1. debian-binary: Текстовый файл с версией формата (всегда "2.0\n"). Это маркер, чтобы инструменты вроде dpkg знали, что перед ними валидный .deb. В ar-архиве файл должен называться точно debian-binary (без расширений).

  2. control.tar.gz: Сжатый tar-архив с метаданными пакета. Здесь контрольные файлы: control (описание пакета), скрипты вроде postinst (что делать после установки) и postrm (после удаления).

  • data.tar.gz: Сжатый tar-архив с самими данными — вашим исполняемым файлом, иконками, desktop-файлами и всем остальным.

Посмотреть содержимое control можно:

$ dpkg -f myapp_1.0.0_amd64.deb
Package: myapp
Version: 1.0.0
Architecture: amd64
Maintainer: AsmX Developer 
Description: An application created with the AsmX compiler.
Section: devel
Priority: optional
Installed-Size: 2
Depends: libc6

Структура выглядит так (ASCII-арт для ясности):

.deb (ar-архив)
├── debian-binary   (Buffer: '2.0\n')
├── control.tar.gz  (gzip(tar(DEBIAN/)))
│   └── DEBIAN/
│       ├── control     (метаданные: имя, версия, зависимости)
│       ├── postinst    (опционально: скрипт после установки)
│       └── postrm      (опционально: скрипт после удаления)
└── data.tar.gz     (gzip(tar(файлы приложения/)))
    ├── usr/
    │   ├── bin/        (исполняемый файл)
    │   ├── share/
    │   │   ├── applications/  (.desktop файл)
    │   │   └── icons/...      (иконка .png)
    └── ...

Почему ar? Потому что он простой: последовательность файлов с заголовками, без сжатия. Это позволяет быстро извлекать части без распаковки всего. В AsmX мы генерируем это в createArArchive из builder.ts:

async function createArArchive(
  outputPath: string,
  files: { name: string; content: Buffer }[]
): Promise<void> {
  let arContent = Buffer.from('!\n'); // Магический заголовок ar

  for (const file of files) {
    const header = Buffer.alloc(60); // Заголовок 60 байт
    header.write(file.name.padEnd(16), 0); // File identifier
    // File modification timestamp
    header.write(Math.floor(Date.now() / 1000).toString().padEnd(12), 16); 
    header.write('0'.padEnd(6), 28); // Owner ID
    header.write('0'.padEnd(6), 34); // Group ID
    header.write('100644'.padEnd(8), 40); // File mode
    header.write(file.content.length.toString().padEnd(10), 48); // File size
    header.write('\x60\n', 58); // Ending characters

    arContent = Buffer.concat([arContent, header, file.content]);
    if (file.content.length % 2 !== 0) { // Паддинг до чётного размера
      arContent = Buffer.concat([arContent, Buffer.from('\n')]); // Padding
    }
  }

  await fs.writeFile(outputPath, arContent);
}

Этот код — сердце упаковщика. Мы создаём буфер для заголовка (фиксированные позиции полей — классика Unix), конкатенируем с контентом и добавляем паддинг (ar требует чётные размеры). Нет внешних библиотек — чистый Node.js для портативности.

Теперь разберём ar-архив подробнее. Он начинается с магической строки !\n (8 байт). Затем — последовательность файлов, каждый с 60-байтным заголовком:

Offset

Length

Name

Format

0

16

Имя файла (паддинг пробелами до 16)

ASCII

16

12

Timestamp (секунды с эпохи, строкой, паддинг пробелами)

Decimal

28

6

Owner ID

Decimal

34

6

Group ID

Decimal

40

8

Mode (восьмеричное, как в chmod)

Octal

48

10

Размер файла (bytes)

Decimal

58

2

Ending characters

0x60 0x0A

Можем посмотреть ar заголовок:

$ dd if=myapp_1.0.0_amd64.deb bs=1 count=68 2>/dev/null | hexdump -C
00000000  21 3c 61 72 63 68 3e 0a  64 65 62 69 61 6e 2d 62  |!.debian-b|
00000010  69 6e 61 72 79 20 20 20  31 37 35 36 39 39 34 36  |inary   17569946|
00000020  30 30 20 20 30 20 20 20  20 20 30 20 20 20 20 20  |00  0     0     |
00000030  31 30 30 36 34 34 20 20  34 20 20 20 20 20 20 20  |100644  4       |
00000040  20 20 60 0a                                       |  `.|
00000044

Объяснение команды:

  • dd if=myapp_1.0.0_amd64.deb: Указываеn входной файл.

  • bs=1: Устанавливает размер блока в 1 байт.

  • count=68: Указывает, что нужно прочитать 68 байтов. (8 байтов с magic и 60 байтов сам заголовок)

  • 2&gt;/dev/null: Игнорирует сообщения об ошибках, если они есть.

  • | hexdump -C: Передает вывод в hexdump для отображения в шестнадцатеричном и ASCII формате.

После заголовка — контент файла, затем паддинг \n если размер нечётный. Всё последовательно — никаких индексов или деревьев. Простота = надёжность.

В AsmX мы вызываем это так:

await createArArchive(outputPath, [
  { name: 'debian-binary', content: debianBinary },
  { name: 'control.tar.gz', content: controlTarGz },
  { name: 'data.tar.gz', content: dataTarGz }
]);

Это генерирует валидный .deb, который dpkg -i примет без вопросов.

Tar-архив: Фундамент data.tar и control.tar

.tar archive and .tar.gz
.tar archive and .tar.gz

Tar (Tape ARchive) — это контейнер для файлов и директорий, без сжатия. В .deb мы используем USTAR-вариант (POSIX-стандарт). Каждый файл в tar имеет 512-байтный заголовок, за которым следует контент (паддинг до 512-байтных блоков).

Field

Size (bytes)

Byte Offset

Description

name

100

0

File name

mode

8

100

File permissions

uid

8

108

User ID

gid

8

116

Group ID

size

12

124

File size in bytes

mtime

12

136

Modification time (UNIX timestamp)

chksum

8

148

Header checksum

typeflag

1

156

File type (e.g., regular file, directory)

linkname

100

157

Name of linked file (if symbolic link)

magic

6

257

Format identifier (e.g., ustar)

version

2

263

Format version (00)

uname

32

265

User name

gname

32

297

Group name

devmajor

8

329

Major device number (if special file)

devminor

8

337

Minor device number (if special file)

prefix

155

345

Prefix for file name (for long file names)

Padding

12

500

Padding to make the header 512 bytes

Чек-сумма вычисляется суммируя все байты заголовка (заменяя поле суммы на пробелы) и записывая как восьмеричное число. В нашем коде (tar-utils):

function calculateTarChecksum(header: Buffer): number {
  let sum = 0;
  for (let i = 0; i < 512; i++) {
    if (i >= 148 && i < 156) {
      sum += 32; // Spaces in checksum field
    } else {
      sum += header[i];
    }
  }
  return sum;
}

Для создания tar мы сканируем директорию (FsUtils.getAllFiles), и строим последовательность: заголовок + контент + паддинг. В конце — два нулевых блока (1024 байта) для завершения.

export async function createTar(
  sourceDir: string,
  excludeDirs: string[] = []
): Promise<Buffer> {
  const files = await FsUtils.getAllFiles(sourceDir, excludeDirs);
  let tarContent = Buffer.alloc(0);

  for (const file of files) {
    const relativePath = path.relative(sourceDir, file).replace(/\\/g, '/');
    const stats = await fs.stat(file);
    const content = await fs.readFile(file);
    const header = createTarHeader(relativePath, stats.size, stats.mode);
    tarContent = Buffer.concat([tarContent, header, content]);

    const padding = 512 - (content.length % 512);
    if (padding < 512) {
      tarContent = Buffer.concat([tarContent, Buffer.alloc(padding)]);
    }
  }

  tarContent = Buffer.concat([tarContent, Buffer.alloc(1024)]);
  return tarContent;
}

Это создаёт raw tar. Затем сжимаем в gz.

Сжатие: .tar.gz с помощью zlib

Gz — это gzip-сжатие, стандарт для Unix. Мы используем встроенный zlib.gzip в Node.js:

export function gzip(data: Buffer): Promise<Buffer> {
  return new Promise((resolve, reject) => {
    zlib.gzip(data, (err, result) => {
      if (err) return reject(err);
      resolve(result);
    });
  });
}

// В builder
const controlTar = await createTar(debianDir);
const controlTarGz = await gzip(controlTar);

Gzip добавляет заголовок (10 байт: магический ID, метод сжатия и т.д.), сжатые данные (DEFLATE) и футер (CRC32 + размер). Мы не углубляемся в DEFLATE (это LZ77 + Huffman), но важно: это lossless, быстрое и эффективное для текстов/бинарников.

Как AsmX строит .deb: Обзор builder и driver

Diagram showing an example file structure of a .deb file
Diagram showing an example file structure of a .deb file

В AsmX процесс создания .deb-пакета реализован через два ключевых модуля: driver (driver.ts) и DebBuilder (builder.ts). Это не просто обёртка над dpkg-deb, а полноценный генератор пакетов, работающий на чистом Node.js без внешних зависимостей. Давайте разберём, как это устроено, шаг за шагом, с примерами кода и пояснениями.

Роль driver

driver.ts — это точка входа, которая обрабатывает аргументы командной строки, проверяет окружение и координирует сборку. Он отвечает за:

  1. Проверку окружения: Убеждается, что сборка выполняется на Linux (требование для .deb), проверяет наличие ldd для анализа зависимостей ELF.

  2. Парсинг аргументов: Собирает флаги вроде --package-name, --package-version, --package-icon и передаёт их в DebBuilder.

  3. Анализ зависимостей: Использует ldd для динамических библиотек или fallback на статические сборки.

  4. Вызов DebBuilder: Передаёт конфигурацию и запускает процесс упаковки.

Роль DebBuilder

DebBuilder (builder.ts) — это рабочая лошадка, которая формирует .deb-пакет. Она:

  1. Создаёт временную директорию: Использует FsUtils.createTempDirectoryRecursive для изоляции.

  2. Генерирует структуру:

    • Копирует бинарник в usr/bin/.

    • Создаёт .desktop-файл (если --package-desktop).

    • Копирует иконку в usr/share/icons/hicolor/ (если --package-icon).

    • Формирует DEBIAN/control и скрипты (postinst, postrm).

  3. Строит архивы:

    • control.tar.gz с метаданными.

    • data.tar.gz с файлами приложения.

    • ar-архив для финального .deb.

  4. Чистит за собой: Удаляет временные файлы.

Ключевые моменты

  • Размер пакета: calculateInstalledSize рекурсивно суммирует размеры файлов в dataDir (в байтах, потом делим на 1024 для Installed-Size в KB).

  • Права файлов: Бинарники — 755 (rwxr-xr-x), остальные — 644 (rw-r--r--).

  • Зависимости: Автоматически определяются через ldd. Если бинарник статический, Depends остаётся пустым.

  • Имена файлов: Валидируются regex’ами (^[a-z0-9][a-z0-9.-]*$ для имени, \d+\.\d+\.\d+ для версии).

Пример вызова

asmx main.asmx --release --target amd64 -o myapp --package \
  --package-type deb \
  --package-name my-application --package-version 1.0.0 \
  --package-description "My awesome app" --package-author "Dev <dev@example.com>" \
  --package-icon icon.png --package-desktop

Вывод: my-application_1.0.0_amd64.deb, готовый к установке через dpkg -i.

Флаги для пакетов в AsmX

AsmX предоставляет набор флагов командной строки для настройки .deb-пакетов, позволяя гибко задавать метаданные, GUI-интеграцию и зависимости. Эти флаги обрабатываются в driver.ts и передаются в DebBuilder для формирования пакета. Вот полный разбор флагов, их функциональности и примеров использования.

Name

Type

Description

--package

bool

Включает режим упаковки. Без него AsmX только компилирует бинарник

--package-type

string

Указывает тип пакета (deb для Debian/Ubuntu)

--package-name

string

Имя пакета. Должно соответствовать regex ^[a-z0-9][a-z0-9.-]*$

--package-version

string

Версия пакета. Требуется формат \d+\.\d+\.\d+ (например, 1.0.0)

--package-description

string

Описание пакета для control

--package-author

string

Имя и email автора для Maintainer

--package-icon

path

Путь к иконке (.png, рекомендуется 256x256). Копируется в /usr/share/icons/hicolor/

--package-desktop

bool

Создаёт .desktop-файл для GUI-меню в /usr/share/applications/

Как флаги обрабатываются

Флаги парсятся в driver.ts с помощью TAPI (Terminal Argument Parser Interface) и формируют объект DebConfig:

export interface DebConfig extends BasePackageConfig {
  type: 'deb';
  deb: {
    maintainer?: string;
    section?: string;
    priority?: string;
    depends?: string[];
    suggests?: string[];
    conflicts?: string[];
    replaces?: string[];
    postinst?: string;
    postrm?: string;
  };
}

Валидация:

  • --package-name: Проверяется через /^[a-z0-9][a-z0-9.-]*$/. Имя не должно начинаться или заканчиваться точкой/дефисом, чтобы соответствовать стандартам dpkg.

  • --package-version: Требуется формат /^\d+\.\d+\.\d+$/. В будущем возможно расширение до поддержки версий вида 1.0.0-1 или 1.0.0~beta1.

Подводные камни

  • Имя пакета: dpkg отклонит пакет, если имя содержит заглавные буквы или нарушает формат. Например, MyApp недопустимо — используйте myapp или my-app.

  • Иконка: Должна быть .png, желательно 256x256. Некорректный формат или размер может привести к тому, что GNOME/KDE не отобразят иконку.

  • Версия: Формат \d+\.\d+\.\d+ обязателен. Неверный формат (например, 1.0) вызовет ошибку валидации.

AsmX G3 как AUR-пакет

Мы рады объявить, что asmx-g3-git теперь доступен в Arch User Repository (AUR)! Это важный шаг для интеграции AsmX в экосистему Arch Linux, позволяя пользователям устанавливать и обновлять наш компилятор через стандартные инструменты, такие как yay или paru. Пакет asmx-g3-git предоставляет последнюю версию из Git-репозитория, включая все новейшие фичи и исправления.

Что такое AUR и почему это важно?

AUR — это сообщественный репозиторий для Arch Linux, где пользователи публикуют PKGBUILD-скрипты для сборки и установки программ. Публикация asmx-g3-git, asmx-stable и asmx-official в AUR делает компилятор доступным для широкой аудитории, упрощая установку и обновление без необходимости ручного клонирования репозитория или настройки окружения. Это шаг к тому, чтобы AsmX стал частью повседневного инструментария разработчиков на Arch-based системах.

Доступные пакеты

  • asmx-g3-git: Bleeding-edge версия, основанная на последнем состоянии Git-репозитория (https://github.com/AsmXFoundation/AsmX-G3.git). Подходит для разработчиков, которые хотят тестировать новейшие фичи, такие как поддержка .deb-пакетов, улучшенный TAPI.

  • asmx-stable: Стабильная версия, привязанная к конкретным релизам (+v29-rev1.0). Рекомендуется для пользователей, которым нужна надёжность в проектах, где стабильность важнее экспериментов.

  • asmx-official: Официальная версия, поддерживаемая командой AsmX. Может включать дополнительные проверки качества, документацию или оптимизации для продакшен-окружений. Идеальна для enterprise-пользователей или тех, кто хочет гарантированную совместимость.

Как установить пакеты

  1. Убедитесь, что у вас установлен AUR-хелпер, например yay или paru.

  2. Выполните команду:

    yay -S asmx-g3-git   # Для bleeding-edge версии
    yay -S asmx-stable   # Для стабильной версии
    yay -S asmx-official # Для официальной версии

    paru -S asmx-g3-git
    paru -S asmx-stable
    paru -S asmx-officialИли, если используете paru:

    paru -S asmx-g3-git
    paru -S asmx-stable
    paru -S asmx-official
  3. Пакет автоматически:

    • Скачает исходный код из репозитория https://github.com/AsmXFoundation/AsmX-G3.git.

    • Установит зависимости (nodejs, bash, npm, jq, typescript).

    • Компилирует проект с помощью npm run build (для asmx-g3-git) или использует готовые бинарники (для asmx-stable и asmx-official).

    • Установит бинарник asmx в /usr/bin/ и документацию в /usr/share/doc/asmx-g3-git/.

Что делает PKGBUILD

PKGBUILD для asmx-g3-git обеспечивает чистую и надёжную установку:

  • Источник: Клонирует Git-репозиторий AsmX (git+https://github.com/AsmXFoundation/AsmX-G3.git).

  • Зависимости:

    • Для работы: nodejs, bash.

    • Для сборки: git, npm, jq (для обработки package.json), typescript.

  • Сборка:

    • Устанавливает локальные зависимости для разработки (typescript, @types/node).

    • Выполняет npm install --ignore-scripts для минимизации лишних действий.

    • Компилирует проект через npm run build.

  • Установка:

    • Копирует модуль в /usr/lib/node_modules/asmx-g3/.

    • Создаёт симлинк /usr/bin/asmx для удобного вызова.

    • Устанавливает корректные права (755 для бинарника, 644 для остальных файлов).

    • Чистит package.json от внутренних npm-полей (с помощью jq) и ссылок на временные пути.

    • Устанавливает документацию (README.md) в /usr/share/doc/asmx-g3-git/.

  • Версия: Формируется динамически через Git: r&lt;количество коммитов&gt;.&lt;короткий хэш&gt; (например, r17.c89a3ce).

Преимущества

  • Удобство: Установка через AUR интегрирует AsmX в систему, делая его доступным из терминала командой asmx.

  • Выбор: Три пакета (asmx-g3-git, asmx-stable, asmx-official) дают гибкость — от экспериментов до продакшена.

  • Обновления: AUR-хелперы отслеживают новые коммиты (asmx-g3-git) или релизы (asmx-stable, asmx-official), упрощая обновления.

  • Сообщество: Публикация в AUR привлекает Arch-пользователей, расширяя аудиторию и собирая обратную связь.

Подводные камни

  • Git-версия: asmx-g3-git — это bleeding-edge, поэтому возможны нестабильные изменения. Для надёжности выбирайте asmx-stable или asmx-official.

  • Зависимости: Убедитесь, что nodejs, npm и typescript обновлены до последних версий, чтобы избежать ошибок сборки. Также требуется jq для обработки package.json.

  • AUR-хелперы: Используйте проверенные инструменты (yay, paru) для надёжной установки.

  • Права: Если симлинк /usr/bin/asmx не работает, проверьте права на /usr/lib/node_modules/asmx-g3/bin/asmx (должно быть 755).

  • Выбор пакета: Если вы не уверены, какой пакет выбрать, начните с asmx-stable для баланса между новыми фичами и надёжностью.

Как внести вклад

AUR-пакет — это открытый проект. Если вы нашли баг или хотите улучшить PKGBUILD, создайте issue или pull request на странице AUR или в репозитории AsmXFoundation/AsmX-G3. Мы ценим вклад сообщества!

Заключение

AsmX G3 v29 — это не просто обновление, а эволюционный скачок. Мы не только улучшили ядро компилятора, добавив стабильность и новые возможности, но и сделали огромный шаг в сторону дистрибуции. Поддержка .deb-пакетов позволяет превратить ваш код в полноценное приложение, готовое к установке на Debian-based системах. Публикация трёх пакетов в AUR — asmx-g3-git для экспериментаторов, asmx-stable для надёжных проектов и asmx-official для продакшена — открывает AsmX для Arch-сообщества и упрощает установку, делая AsmX частью экосистемы Linux.

Мы остаёмся верны нашей философии: полный контроль, никаких чёрных ящиков, максимальная производительность. Отказ от устаревших 32-битных систем и искусственных микроархитектурных уровней (v2, v3, v4) в пользу прямого использования CPUID — это наш ответ на вызовы современности. Мы строим инструмент для инженеров, которые ценят точность и готовы брать на себя ответственность за свой код.

Но это не конец. Впереди — поддержка новых форматов пакетов. AsmX — это проект для тех, кто смотрит в будущее. Код открыт, AUR-пакет доступен, сообщество растёт. Ждём ваших идей, отправляйте баг-репорты. Мы не ждём одобрения — мы строим. Присоединяйтесь к нам, и давайте создадим будущее вместе.

Комментарии (6)


  1. eugenk
    05.09.2025 05:26

    Бред какой-то...


  1. Shermike
    05.09.2025 05:26

    Если речь о высокоуровневых оптимизациях, таких как формы SSA (Static Single Assignment), то на уровне ассемблера они просто неуместны.

    SSA - это не оптимизация, а просто популярная форма IR.

    А вообще, у меня складывается ощущение, что это какой-то троллинг. Трудно поверить, чтобы кто-то это все делал всерьез. Например, какой смысл уделять время такой нерелавантой тут вещи, как парсер командной строки, зачем тут генерация deb пакета и тд? Это все такое вторичное в контексте проекта компилятора.

    Ну и наконец зачем делать сотни пустых коммитов в репозитории:)