Двоичный файл — подмножество языка, и подмножество обязано называть себя, а не отвечать «неизвестная команда»
Двоичный flang, который ставят Homebrew и asdf, знает 6 команд. Свидетель на Node знает 12. Разница законна: втащить io в C означало бы втащить хозяина с эффектами, а ast, facts, lock и package — ещё четыре слоя, которых в замыкании компилятора нет. Незаконно другое: на обещанный документацией flang lock двоичный отвечал неизвестная команда «lock» — ответ, который читается как опечатка. Человек не узнавал ни того, что команда существует, ни того, где она живёт, и уходил с мыслью, что ошибся в написании.
Из трёх возможных решений выбрано третье:
- дотянуть двоичный до 12 команд — отдельная большая работа, и
ioв неё не влезает вовсе (эффекты); - промолчать — то, что было;
- назвать разницу: двоичный отвергает такой вызов кодом 2 и говорит, что за команда и где она есть; краткая справка называет разницу числом; страницы установки и
man flangговорят то же самое.
Правило шире этого случая: урезанная сборка обязана отличать «такой команды нет нигде» от «эта команда есть, но не здесь». Первое — опечатка, второе — выбор дистрибутива, и человеку они говорят разное.
Чтобы разница не разъехалась снова, она стережётся с обеих сторон: проверка берёт перечень команд у эталона на flang и требует, чтобы каждая у собранного двоичного либо работала, либо была названа отсутствующей. Ответа «неизвестная команда» не должно остаться ни на одной команде свидетеля.
Чем подтверждено. Ветка work/instrument, 19 августа 2026, на двоичном, собранном в чистом каталоге (git archive в пустой, затем make -C bootstrap). До правки: lock, ast, facts, io, package — «неизвестная команда», код 2. После: каждая названа своим делом и адресом полного инструментария. Проверка — flang/test/self-bootstrap.test.mjs, тест «каждая команда свидетеля у двоичного либо работает, либо названа отсутствующей».
Чем ограничено. Числа 6 и 12 — на версии 0.5.0, и второе успело измениться прямо во время работы: пока правка шла, в ствол приехала команда package, и полный инструментарий стал знать двенадцать вместо одиннадцати. Само правило от версии не зависит; числа надо перемерять, а не переписывать.
Поправка от 19 августа 2026: чисел 6 и 12 больше нет, и разница переехала. Перемерено на двоичном, собранном из свежего клона main (git clone --depth 1, make -C bootstrap -j4): ./bootstrap/flang --help называет десять команд, и это не список обещаний — каждая из пяти, которые прежде отвергались кодом 2, работает по-настоящему:
flang lock proba.flang → {"схема":2,"вход":…,"печать":"dcf9b0c5…"} код 0
flang ast proba.flang → {"flang":1,"module":"Проба",…} код 0
flang facts proba.flang --claims '[]' → {"ok":true,"results":[]} код 0
flang io proba.flang → FLANG_UNKNOWN_PLAN: «нет ни одного плана» код 3
flang package proba.flang → FLANG_PACKAGE: «нет объявления flang.package»
Последние две отвечают отказом ПО СУЩЕСТВУ («в этой программе нечего исполнять», «не хватает объявления»), а не «команды нет», — то есть команда втащена, просто пример её не кормит. Справки двоичного файла и пакета на Node перечисляют один и тот же набор.
Разница между сборками при этом никуда не делась — она переехала с команд на цели печати. flang emit проба.flang --target rust двоичный отвергает словами «цели „rust“ в этом бинарнике нет; втащена одна — „c“», а тот же вызов у пакета на Node печатает Cargo.toml и три .rs. Правило заметки — урезанная сборка обязана отличать «такой команды нет нигде» от «есть, но не здесь» — сработало ровно там, куда разница переехала.
Урок не в числах, а в том, что числа в заметке про интерфейс живут недели: эти прожили месяц и стали неверны обе. Страницы, которые их повторяли (установка и её улики), пришлось переписывать по перемеру, а не по памяти.
Поправка от 20 августа 2026: целей в двоичном стало две, и «втащена одна — „c“» больше не верно. Здесь стояло: «flang emit проба.flang --target rust двоичный отвергает словами „цели «rust» в этом бинарнике нет; втащена одна — «c»“». Печать в Go втащена в замыкание (flang/self/emit-go.flang, строка использует в compiler.flang), и --target go теперь печатает по-настоящему: корпус из 163 программ, расхождение со свидетелем на 159 из них — только блок границы входа, то есть ровно то же, чем расходится цель c. Отвергаются оставшиеся шесть.
Правило заметки от этого не изменилось, а вот НАЗВАННАЯ РАЗНИЦА изменилась, и менять её пришлось в четырёх местах сразу: краткая справка двоичного, справка emit, текст отказа на неизвестной цели и man flang. Числа в заметке про интерфейс живут недели — это второй раз, когда они устарели.
Связано: the-price-of-a-print-target-is-reference-debt-not-name-collisions, measuring-a-stale-artifact, cli-help-diverges-between-the-two-implementations, what-is-deferred