Примечания к выпуску 0.17.0
В этом выпуске представлено 5 месяцев работы: изменения от 206 разных участников, распределенные по 925 коммитам.
Изначально предполагалось, что этот цикл выпуска будет короче, но в итоге он оказался довольно продолжительным. Была переработана система сборки, в том числе добавлен протокол сервера сборки, а компоновщик ELF был усовершенствован до такой степени, что мы ожидаем, что инкрементальная компиляция будет работать для всех пользователей x86_64-linux.
Поддерживаемые архитектуры
Zig поддерживает широкий спектр архитектур и операционных систем. В разделах Таблица поддержки и Дополнительные платформы перечислены платформы, для которых Zig может создавать программы, а в zig-bootstrap README — платформы, для которых можно легко выполнить кросс-компиляцию самого компилятора Zig.
Заметные изменения
aarch64-openbsdтеперь изначально тестируется в CI Zig, обеспечивая высококачественную поддержку в будущем.- Задания CI для
aarch64-freebsdиaarch64-netbsdтеперь выполняются не только при пуше вmaster, но и при pull-реквестах. - Обходной путь для ошибки LLVM, которая сломала большинство двоичных файлов
aarch64-windows, включая Zig компилятор. - Компилятор Zig теперь применяет обязательные методы защиты кода при работе с
aarch64-openbsd, чтобы полученные двоичные файлы действительно работали. - Теперь Zig предоставляет трассировку стека при сбоях и неудачных проверках на 32-битных процессорах ARM. Для платформ, поддерживающих только формат Thumb, еще предстоит проделать работу.
- Теперь Zig предоставляет трассировку стека при сбоях и неудачных проверках утверждений на SPARC.
- Теперь Zig обрабатывает коды операций аутентификации указателей при раскручивании стека на AArch64.
- Добавлена поддержка целевых платформ
loongarch32-linux-gnu[sf]. - Теперь Zig поддерживает 64-битные системы SPARC, особенно
sparc64-linux. Во многом это стало возможным благодаря новому компоновщику Zig для ELF, который теперь лучше поддерживает эту платформу, чем LLD. - Стандартная библиотека Zig была портирована на ABI x32 и N32 для x86-64 и 64-битных процессоров MIPS соответственно. Это нишевые ABI ILP32, которые позволяют использовать 64-битный набор команд при наличии только 32-битных указателей. Идея заключается в том, чтобы пожертвовать доступным адресным пространством ради меньшего потребления памяти и более эффективного использования кэша.
- Для некоторых игровых консолей добавлена информация о целевых платформах:
aarch64-switch,arm-gba,mipsel-psxиpowerpc-wiiu. - В Zig добавлена поддержка очень ранней версии xtensa-linux. Обратите внимание, что на данный момент эта поддержка доступна только через бэкенд C или экспериментальный бэкенд LLVM.
- Стандартная библиотека Zig теперь поддерживает
arc[eb]-linux,csky-linuxиm88k-openbsdпри использовании бэкенда C. - Стандартная библиотека Zig теперь поддерживает
microblaze[el]-linux,sh[eb]-linuxиsparc-linuxбез использования библиотеки libc. - Теперь Zig принудительно использует
-mabi=ieeelongdoubleдля всех платформ PowerPC. Это лишь формализация того, что и так было реальностью: Zig никогда не поддерживал формат IBM «double-double» дляlong doubleи, скорее всего, никогда не будет его поддерживать. В результате в этом выпуске прекращена поддержкаpowerpc-linux-gnueabi[hf], поскольку glibc поддерживает на этих платформах только формат «double-double». Платформыpowerpc-linux-musleabi[hf]по-прежнему поддерживаются, поскольку они используют формат IEEE. - В этом выпуске прекращена поддержка
powerpc64-linux-gnu. Zig всегда поддерживал только компоновку двоичных файлов ELFv2 для 64-битных процессоров PowerPC, а glibc официально не поддерживает ELFv2 с порядком байтов от старшего к младшему, а также IEEElong double, как указано выше. - Способность Zig определять модель и характеристики центрального процессора была значительно улучшена. Это касается практически всех архитектур во всех поддерживаемых операционных системах.
- Базовая модель процессора была изменена для некоторых целевых архитектур:
aarch64-haiku:cortex_a55m68k-*:M68030mips64-openbsd:octeonpowerpc-netbsd:750powerpc64-freebsd:pwr8powerpc64-linux:pwr8powerpc64-openbsd:pwr9s390x-*:arch11sparc-*:genericsparc-linux:v9sparc64-*:ultrasparcxtensa-*:esp32
- В синтаксисе запросов для целевой платформы Zig автоматическое определение версии нативной libc теперь выполняется только в том случае, если в тройке (target triple) действительно используется нативная libc (то есть компонент ABI опущен). Мы полагаем, что такое поведение лучше соответствует интуитивному представлению пользователей о работе запросов целевой платформы — особенно с учетом того, как обрабатывается компонент ОС.
Система уровней поддержки
Уровень поддержки Zig для различных целей делится на четыре уровня (Tier), где Tier 1 — самый высокий. Цель — чтобы для Tier 1 целей не было отключённых тестов. После релиза 1.0.0 это станет обязательным требованием.
Tier 1
- Все неэкспериментальные функции языка работают корректно.
- Компилятор может генерировать машинный код для этой платформы без использования LLVM.
- Встроенный фаззер работает на этой платформе (если применимо).
Tier 2
- Кроссплатформенные абстракции Стандартной библиотеки имеют реализации для этой цели.
- В случае неудачных проверок и сбоев на этой цели создаются трассировки стека.
- libc доступна для этой цели даже при кросс-компиляции (если применимо).
- CI процессы выполняют сборку тестов модуля для этой цели при каждом пуше.
Tier 3
- Компилятор может генерировать машинный код для этой цели, используя внешний бэкенд, например LLVM.
- Компоновщик может создавать объектные файлы, библиотеки и исполняемые файлы для этой цели.
Tier 4
- Компилятор может сгенерировать ассемблерный или исходный код на языке C для этой цели.
Таблица поддержки
В следующей таблице ✅ означает полную поддержку, ❌ — отсутствие поддержки, ⚠️ — частичную поддержку (например, только для некоторых подцелей или с известными проблемами). ❔ означает, что статус в основном неизвестен, обычно потому что цель редко тестируется. Наведите курсор на другие значки для получения подробностей.
Объекты, отмеченные 🪦, являются устаревшими. Компилятор Zig и стандартная библиотека поддерживают их по мере возможности, но со временем эта поддержка будет прекращена.
| Уровень | Цель | Компилятор | Компоновщик | Язык | Стд. библ. | Трасс. стека | Fuzzer | libc | CI |
|---|---|---|---|---|---|---|---|---|---|
| 1 | x86_64-linux | 🖥️⚡ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| * * * | |||||||||
| 2 | aarch64-freebsd | 🖥️🛠️ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| 2 | aarch64[_be]-linux | 🖥️🛠️ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| 2 | aarch64-maccatalyst | 🖥️🛠️ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| 2 | aarch64-macos | 🖥️🛠️ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| 2 | aarch64[_be]-netbsd | 🖥️🛠️ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| 2 | aarch64-openbsd | 🖥️🛠️ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ |
| 2 | aarch64-windows | 🖥️🛠️ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ⚠️ |
| 2 | arm-freebsd | 🖥️ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ |
| 2 | arm[eb]-linux | 🖥️ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ |
| 2 | arm[eb]-netbsd | 🖥️ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ⚠️ |
| 2 | arm-openbsd | 🖥️ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ⚠️ |
| 2 | hexagon-linux | 🖥️ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ |
| 2 | loongarch32-linux | 🖥🛠 | ✅ | ❔ | ✅ | ✅ | ❌ | ✅ | ⚠️ |
| 2 | loongarch64-linux | 🖥️🛠️ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| 2 | mips[el]-linux | 🖥️ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ |
| 2 | mips[el]-netbsd | 🖥️ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ⚠️ |
| 2 | mips64[el]-linux | 🖥️ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| 2 | mips64[el]-openbsd | 🖥️ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ⚠️ |
| 2 | powerpc-linux | 🖥️ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ⚠️ |
| 2 | powerpc-netbsd | 🖥️ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ⚠️ |
| 2 | powerpc-openbsd | 🖥️ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ⚠️ |
| 2 | powerpc64[le]-freebsd | 🖥️ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ⚠️ |
| 2 | powerpc64[le]-linux | 🖥️ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ |
| 2 | powerpc64-openbsd | 🖥️ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ⚠️ |
| 2 | riscv32-linux | 🖥️ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ |
| 2 | riscv32-netbsd | 🖥️ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ⚠️ |
| 2 | riscv64-freebsd | 🖥️🛠️ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ⚠️ |
| 2 | riscv64-linux | 🖥️🛠️ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| 2 | riscv64-netbsd | 🖥️🛠️ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ⚠️ |
| 2 | riscv64-openbsd | 🖥️🛠️ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ⚠️ |
| 2 | s390x-linux | 🖥️ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| 2 | sparc64-linux | 🖥️🛠️ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| 2 | thumb[eb]-linux | 🖥️ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ |
| 2 | wasm32-wasi | 🖥️🛠️ | ✅ | ✅ | ✅ | ⚠️ | ❌ | ✅ | ✅ |
| 2 | x86-linux | 🖥️ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ |
| 2 | x86-netbsd | 🖥️ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ |
| 2 | x86-openbsd | 🖥️ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ⚠️ |
| 2 🪦 | x86-windows | 🖥️ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ |
| 2 | x86_64-freebsd | 🖥️🛠️ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| 2 🪦 | x86_64-maccatalyst | 🖥️⚡ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ⚠️ |
| 2 🪦 | x86_64-macos | 🖥️⚡ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ⚠️ |
| 2 | x86_64-netbsd | 🖥️🛠️ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| 2 | x86_64-openbsd | 🖥️🛠️ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ |
| 2 | x86_64-windows | 🖥️🛠️ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ |
| * * * | |||||||||
| 3 | aarch64-haiku | 🖥️🛠️ | ✅ | ✅ | ✅ | ✅ | ❔ | ❌️ | ❌️ |
| 3 | aarch64-ios | 🖥️🛠️ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌️ | ❌️ |
| 3 | aarch64-serenity | 🖥️🛠️ | ✅ | ✅ | ✅ | ✅ | ❔ | ❌️ | ❌️ |
| 3 | aarch64-tvos | 🖥️🛠️ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌️ | ❌️ |
| 3 | aarch64-visionos | 🖥️🛠️ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌️ | ❌️ |
| 3 | aarch64-watchos | 🖥️🛠️ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌️ | ❌️ |
| 3 | arm-haiku | 🖥️ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌️ | ❌️ |
| 3 | mips64[el]-netbsd | 🖥️ | ✅ | ✅ | ✅ | ❌️ | ✅ | ❌️ | ❌️ |
| 3 | riscv64-haiku | 🖥️🛠️ | ✅ | ✅ | ✅ | ✅ | ❔ | ❌️ | ❌️ |
| 3 | riscv64-serenity | 🖥️🛠️ | ✅ | ✅ | ✅ | ✅ | ❔ | ❌️ | ❌️ |
| 3 🪦 | thumb-windows | 🖥️ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ❌️ |
| 3 | wasm64-wasi | 🖥️🛠️ | ✅ | ❔ | ❌️ | ⚠️ | ❌ | ❌️ | ❌️ |
| 3 🪦 | x86-freebsd | 🖥️ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ |
| 3 | x86-haiku | 🖥️ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌️ | ❌️ |
| 3 🪦 | x86-illumos | 🖥️ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌️ | ❌️ |
| 3 | x86_64-dragonfly | 🖥️🛠️ | ✅ | ✅ | ✅ | ✅ | ❔ | ❌️ | ❌️ |
| 3 | x86_64-haiku | 🖥️⚡ | ✅ | ✅ | ✅ | ✅ | ❔ | ❌️ | ❌️ |
| 3 | x86_64-illumos | 🖥️🛠️ | ✅ | ✅ | ✅ | ✅ | ❔ | ❌️ | ❌️ |
| 3 | x86_64-serenity | 🖥️⚡ | ✅ | ✅ | ✅ | ✅ | ❔ | ❌️ | ❌️ |
| * * * | |||||||||
| 4 | alpha-linux | 📄 | ❌️ | ❔ | ✅ | ✅ | ❌ | ❌️ | ❌️ |
| 4 | alpha-netbsd | 📄 | ❌️ | ❔ | ✅ | ✅ | ❌ | ❌️ | ❌️ |
| 4 | alpha-openbsd | 📄 | ❌️ | ❔ | ✅ | ✅ | ❌ | ❌️ | ❌️ |
| 4 | arc[eb]-linux | 📄 | ❌️ | ❔ | ✅ | ✅ | ❌ | ✅ | ❌️ |
| 4 | csky-linux | 📄 | ❌️ | ❔ | ✅ | ✅ | ❌ | ✅ | ❌️ |
| 4 | hppa-linux | 📄 | ❌️ | ❔ | ❌️ | ❌️ | ❌ | ❌️ | ❌️ |
| 4 | hppa-netbsd | 📄 | ❌️ | ❔ | ✅ | ❌️ | ❌ | ❌️ | ❌️ |
| 4 | hppa-openbsd | 📄 | ❌️ | ❔ | ✅ | ❌️ | ❌ | ❌️ | ❌️ |
| 4 | hppa64-linux | 📄 | ❌️ | ❔ | ❌️ | ❌️ | ❌ | ❌️ | ❌️ |
| 4 | m68k-linux | 🖥️ | ❌️ | ❔ | ✅ | ✅ | ❌ | ✅ | ❌️ |
| 4 | m68k-netbsd | 🖥️ | ❌️ | ❔ | ✅ | ✅ | ❌ | ✅ | ❌️ |
| 4 | m88k-openbsd | 📄 | ❌️ | ❔ | ✅ | ✅ | ❌ | ❌️ | ❌️ |
| 4 | microblaze[el]-linux | 📄 | ❌️ | ❔ | ✅ | ❌️ | ❌ | ❌️ | ❌️ |
| 4 | or1k-linux | 📄 | ❌️ | ❔ | ✅ | ✅ | ❌ | ❌️ | ❌️ |
| 4 | sh[eb]-linux | 📄 | ❌️ | ❔ | ✅ | ❌️ | ❌ | ❌️ | ❌️ |
| 4 | sh[eb]-netbsd | 📄 | ❌️ | ❔ | ✅ | ❌️ | ❌ | ❌️ | ❌️ |
| 4 | sh-openbsd | 📄 | ❌️ | ❔ | ✅ | ❌️ | ❌ | ❌️ | ❌️ |
| 4 | sparc-linux | 🖥️ | ❌️ | ❔ | ✅ | ✅ | ❌ | ✅ | ❌️ |
| 4 | sparc-netbsd | 🖥️ | ❌️ | ❔ | ✅ | ❌️ | ❌ | ✅ | ❌️ |
| 4 | sparc64-netbsd | 🖥️🛠️ | ⚠️ | ✅ | ✅ | ❌️ | ✅ | ✅ | ❌️ |
| 4 | sparc64-openbsd | 🖥️🛠️ | ⚠️ | ✅ | ✅ | ❌️ | ❌ | ✅ | ❌️ |
| 4 | xtensa[eb]-linux | 🖥️ | ❌️ | ❔ | ✅ | ❌️ | ❌ | ❌️ | ❌️ |
Требования к версиям ОС
В стандартной библиотеке Zig есть минимальные требования к версиям некоторых поддерживаемых операционных систем, что влияет и на сам компилятор.
| OS | Version |
|---|---|
| Darwin | 15.0+ |
| DragonFly BSD | 6.4+ |
| FreeBSD | 14.0+ |
| Linux | 5.10+ |
| NetBSD | 10.1+ |
| OpenBSD | 7.8+ |
| Windows | 10+ |
Дополнительные платформы
Zig также поддерживает различные дополнительные цели, для которых не применяется система уровней:
aarch64-driverkitaarch64[_be]-freestandingaarch64-fuchsiaaarch64-hurdaarch64-switchaarch64-uefialpha-freestandingamdgcn-amdhsaamdgcn-amdpalamdgcn-mesa3darc[eb]-freestandingarm[eb]-freestandingarm-3dsarm-fuchsiaarm-gbaarm-uefiarm-vitaavr-freestandingbpf(eb,el)-freestandingcsky-freestandingez80-freestandingez80-tioshexagon-freestandinghppa[64]-freestandingkalimba-freestandingkvx-freestandinglanai-freestandingloongarch(32,64)-freestandingloongarch(32,64)-uefim68k-freestandingm88k-freestandingmicroblaze[el]-freestandingmips[64][el]-freestandingmipsel-psxmipsel-pspmsp430-freestandingnvptx[64]-cudanvptx[64]-nvclor1k-freestandingpowerpc-wiiupowerpc[64][le]-freestandingpowerpc64-ps3propeller-freestandingriscv(32,64)[be]-freestandingriscv(32,64)-uefiriscv64-fuchsiariscv64-hurds390x-freestandingsh[eb]-freestandingsparc[64]-freestandingspirv(32,64)-openclspirv(32,64)-openglspirv(32,64)-vulkanspork8-freestandingthumb[eb]-freestandingthumb-fuchsiathumb-gbathumb-vitave-freestandingwasm(32,64)-emscriptenwasm(32,64)-freestandingx86[_16,_64]-freestandingx86[_64]-hurdx86[_64]-uefix86_64-driverkitx86_64-fuchsiax86_64-plan9x86_64-ps4x86_64-ps5xcore-freestandingxtensa[eb]-freestanding
Изменения в языке
Прогресс в обеспечении стабильности языка
С момента выхода Zig 0.16.0 был достигнут значительный прогресс в стабилизации языка. Это ключевой этап нашей дорожной карты и необходимое условие для выпуска Zig 1.0.
В частности, с момента выхода последнего релиза мы обсудили и приняли решения по многим языковым предложениям — приняли около 25 и отклонили около 125. На момент написания этой статьи в системе отслеживания проблем Codeberg оставалось открытым 23 языковых предложения, а в устаревшей системе отслеживания проблем GitHub - 61 языковое предложение. Таким образом, эта работа представляет собой значительный шаг к завершению разработки языка (хотя некоторые основные решения остаются).
Изменения в @bitCast
Zig 0.17.0 изменяет определение встроенной функции @bitCast.
Во многих случаях новое поведение эквивалентно старому: в частности, приведение целочисленного типа к другому целочисленному типу не изменилось, как и приведение целочисленного типа к packed struct или packed union.
Однако семантика вызовов @bitCast с использованием типов массивов или векторов изменилась. К сожалению, это изменение может привести к тому, что существующий код перестанет работать, но при этом не возникнет ошибка компиляции.. Поэтому при обновлении может быть полезно проверить все случаи использования @bitCast с массивами или векторами.
Новое определение @bitCast заключается в том, что оно интерпретирует логическое битовое представление значения как другой тип. Считается, что следующие типы имеют логические битовые представления:
voidbool- целые числа, за исключением
comptime_int - числа с плавающей точкой, за исключением
comptime_float - типы с целочисленной поддержкой
enum(T),packed struct(T), иpacked union(T) - массивы или векторы любого из этих типов.
Для целочисленных типов и типов с плавающей запятой логическое битовое представление начинается с младшего бита и заканчивается старшим битом. Для типов «массив» и «вектор» логические битовые представления всех элементов объединяются в последовательность, начиная с первого элемента.
На практике это означает, что новое определение @bitCast в значительной степени соответствует прежнему поведению на системах с порядком байтов little-endian. В отличие от прежнего варианта, новое поведение полностью не зависит от порядка байтов (endian-agnostic): операция выполняется одинаково независимо от того, какой порядок байтов используется на целевой системе.
Новое определение @bitCast запрещает преобразования между некоторыми типами, которые ранее были допустимы. В частности, больше не разрешены преобразования с участием типов extern struct или extern union. В большинстве случаев код, использующий подобные преобразования, нацелен на переинтерпретацию представления значения в памяти (этот прием иногда называют «type punning»); для достижения этой цели следует использовать @ptrCast или extern union.
const TwoBytes = extern struct {
b0: u8,
b1: u8,
};
test "type pun extern struct" {
const bytes: TwoBytes = .{ .b0 = 0x12, .b1 = 0xAB };
const int: u16 = @bitCast(bytes);
switch (std.lang.Endian.native) {
.little => try expectEqual(0xAB_12, int),
.big => try expectEqual(0x12_AB, int),
}
}
const std = @import("std");
const expectEqual = std.testing.expectEqual;
$ zig test bitcast_extern_struct.zig
/home/ci/.cache/act/4666100c0c49f018/hostexecutor/src/download/0.17.0/release-notes/bitcast_extern_struct.zig:7:31: error: cannot @bitCast from 'bitcast_extern_struct.TwoBytes'
const int: u16 = @bitCast(bytes);
^~~~~
/home/ci/.cache/act/4666100c0c49f018/hostexecutor/src/download/0.17.0/release-notes/bitcast_extern_struct.zig:1:25: note: struct declared here
const TwoBytes = extern struct {
~~~~~~~^~~~~~
⬇️
const TwoBytes = extern struct {
b0: u8,
b1: u8,
};
test "type pun extern struct" {
const bytes: TwoBytes = .{ .b0 = 0x12, .b1 = 0xAB };
const int_ptr: *align(1) const u16 = @ptrCast(&bytes);
switch (std.lang.Endian.native) {
.little => try expectEqual(0xAB_12, int_ptr.*),
.big => try expectEqual(0x12_AB, int_ptr.*),
}
}
const std = @import("std");
const expectEqual = std.testing.expectEqual;
$ zig test ptrcast_extern_struct.zig
1/1 ptrcast_extern_struct.test.type pun extern struct...OK
All 1 tests passed.
Формально заданная и фаззингованная грамматика
Формальная грамматика Zig (grammar.peg) и фактическая реализация языка во многих местах расходились. Вероятно, формальная грамматика никогда на 100% не соответствовала написанным вручную токенизатору и парсеру.
Теперь эта проблема устранена, что открывает путь к дальнейшим изменениям грамматики и работе над спецификацией языка.
В общих чертах подход заключался в создании инструмента, который принимает на вход файл grammar.peg и генерирует простой парсер с рекурсивным спуском. Полученный парсер используется в качестве эталона («оракула») при фаззинг-тестировании: результаты его работы сравниваются с результатами работы написанного вручную парсера std.zig.Ast.parse(). Такой подход обеспечивает наличие единого источника истины и упрощает внесение изменений в грамматику языка.
Подробности: #36094
Перенос транслятора с языка C во внешний модуль
@cImport был признан устаревшим в Zig 0.16.0 и теперь удалён. Кроме того, в этом релизе std.Build.Step.TranslateC признан устаревшим в пользу явной зависимости от официального пакета ZSF translate-c, который представляет собой ту же реализацию, что и этап сборки, но предлагает больше вариантов настройки для транслируемого кода и имеет независимый от основного инструментария Zig график выпуска.
Руководство по обновлению
zig fetch --save git+https://codeberg.org/ziglang/translate-c
--- a/build.zig
+++ b/build.zig
@@ -1,16 +1,19 @@
const std = @import("std");
+const Translator = @import("translate_c").Translator;
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
- const translate_c = b.addTranslateC(.{
- .root_source_file = b.path("src/c.h"),
+ const translate_c = b.dependency("translate_c", .{});
+
+ const translator: Translator = .init(translate_c, .{
+ .c_source_file = b.path("src/c.h"),
.target = target,
.optimize = optimize,
+ // additional options now available that go here:
+ // https://codeberg.org/ziglang/translate-c#options
});
- translate_c.linkSystemLibrary("glfw", .{});
- translate_c.linkSystemLibrary("epoxy", .{});
+ translator.linkSystemLibrary("glfw3", .{});
+ translator.linkSystemLibrary("epoxy", .{});
const exe = b.addExecutable(.{
.name = "tetris",
@@ -21,7 +24,7 @@ pub fn build(b: *std.Build) void {
.imports = &.{
.{
.name = "c",
- .module = translate_c.createModule(),
+ .module = translator.mod,
},
},
}),
Добавлены @backingInt и @fromBackingInt
Появились новые встроенные функции @backingInt и @fromBackingInt. Они заменяют собой устаревшие @intFromEnum и @enumFromInt (#35966).
Функция @backingInt работает со всеми перечислениями (enum) и битовыми упаковками (bitpack), имеющими явный базовый целочисленный тип. Она также работает с размеченными объединениями (tagged unions), возвращая базовое целое число, соответствующее активному тегу. Если перечисление или битовая упаковка имеют значение undefined, то и возвращаемое базовое целое число будет undefined.
Тип результата функции @fromBackingInt определяется автоматически; это может быть любое перечисление или битовая упаковка с явным базовым целочисленным типом. Функция принимает параметр именно этого базового целочисленного типа. Для перечислений передача базового целого числа, которое равно undefined или соответствует недопустимому значению тега, приводит к ошибке (Illegal Behavior), выявляемой механизмами проверки безопасности. Для битовых упаковок передача базового целого числа со значением undefined приводит к получению битовой упаковки со значением undefined.
Функция @bitCast теперь также выполняет проверку на недопустимые значения тегов, если целевым типом является перечисление (enum).
Также добавлена функция std.meta.BackingInt для получения типа результата @backingInt.
Теперь Zig требует, чтобы базовым целочисленным типом для пустых перечислений был noreturn, поскольку такие перечисления невозможно инстанцировать.
Пример использования
--- a/lib/std/Build.zig
+++ b/lib/std/Build.zig
@@ -145,7 +145,7 @@ pub const Graph = struct {
pub fn addGeneratedFile(graph: *Graph, owner: *Step) Configuration.GeneratedFileIndex {
graph.generated_files.append(graph.arena, owner) catch @panic("OOM");
- return @enumFromInt(graph.generated_files.items.len - 1);
+ return @fromBackingInt(@intCast(graph.generated_files.items.len - 1));
}
pub fn dupeString(graph: *const Graph, bytes: []const u8) []const u8 {
@@ -2607,7 +2607,7 @@ pub const LazyPath = union(enum) {
.src_path, .cwd_relative, .relative, .dependency => {},
.generated => |gen| {
const graph = other_step.owner.graph;
- const generated_owner_step = graph.generated_files.items[@intFromEnum(gen.index)];
+ const generated_owner_step = graph.generated_files.items[@backingInt(gen.index)];
other_step.dependOn(generated_owner_step);
},
}
zig fmt автоматически выполняет это обновление.
Добавлен @SpirvType
В SPIR-V существует ряд типов (например, изображения и сэмплеры), не имеющих аналогов в системе типов Zig. Ранее единственным способом работы с ними был встроенный ассемблер, из-за чего было невозможно объявить текстуру или буфер хранения как обычную глобальную переменную. В версии Zig 0.17.0 реализовано принятое предложение #35240, добавляющее встроенную функцию @SpirvType наряду с другими встроенными средствами создания типов:
@SpirvType(comptime options: std.lang.Type.Spirv) type
.samplerсоздаетOpTypeSampler..imageсоздаетOpTypeImage..sampled_imageсоздаетOpTypeSampledImageна основе типа изображения с использованием.sampled..runtime_arrayсоздаетOpTypeRuntimeArray.
Эти типы поддерживают индексацию и предоставляют поле len, подобно массиву.
Использование этой встроенной сущности при компиляции не для SPIR-V приводит к ошибке. Кроме того, параметры проверяются на совместимость с целевой операционной системой.
const std = @import("std");
const Image = @SpirvType(.{
.image = .{
.usage = .{ .sampled = f32 },
.format = .unknown,
.dim = .@"2d",
.depth = .not_depth,
.arrayed = false,
.multisampled = false,
.access = .unknown,
},
});
const SampledImage = @SpirvType(.{ .sampled_image = Image });
const texture = @extern(*addrspace(.constant) const SampledImage, .{
.name = "texture",
.decoration = .{ .descriptor = .{ .set = 0, .binding = 0 } },
});
const uv_in = @extern(*addrspace(.input) const @Vector(2, f32), .{
.name = "uv",
.decoration = .{ .location = 0 },
});
const color_out = @extern(*addrspace(.output) @Vector(4, f32), .{
.name = "color",
.decoration = .{ .location = 0 },
});
export fn main() callconv(.{ .spirv_fragment = .{} }) void {
color_out.* = std.spirv.imageSampleImplicitLod(texture, uv_in.*);
}
$ zig build-obj spirv_type.zig -target spirv32-vulkan
Удален синтаксис умножения массивов
Синтаксис умножения массивов (a ** b) был удален в пользу втроенной функции @splat.
Миграция:
--- a/player/chromaprint.zig
+++ b/player/chromaprint.zig
@@ -35,7 +35,7 @@ pub const Chroma = struct {
const max_index = @min(window_size / 2, freqToIndex(max_freq));
const notes: [window_size]u8 = n: {
@setEvalBranchQuota(window_size);
- var result = [1]u8{0} ** window_size;
+ var result: [window_size]u8 = @splat(0);
for (min_index..max_index) |i| {
const freq = indexToFreq(i);
const octave = freqToOctave(freq);
@@ -123,7 +123,7 @@ const RollingIntegralImage = struct {
num_rows: u32,
pub const init: RollingIntegralImage = .{
- .data = [1]Float{0} ** data_size,
+ .data = @splat(0),
.num_rows = 0,
};
Добавлена встроенная функция @divCeil
Новая встроенная функция @divCeil выполняет целочисленное деление с округлением в сторону положительной бесконечности, дополняя существующие встроенные функции @divTrunc, @divFloor и @divExact.
@divCeil(5, 3) == 2
@divCeil(-5, 3) == -1
Как и в случае с другими встроенными функциями деления, вызывающая сторона гарантирует, что делитель не равен 0, и что результат не вызовет переполнения.
Больше никаких std.math.divCeil(a, b) catch unreachable!
Теперь @hasDecl возвращает true только для публичных объявлений.
Ранее @hasDecl возвращал true для публичных объявлений и объявлений, находящихся в том же файле. Теперь поведение одинаково независимо от того, в каком файле используется @hasDecl.
const std = @import("std");
const Foo = struct {
bar: i32,
const baz = 1;
pub var quux = "xxx";
};
test "@hasDecl example" {
try std.testing.expect(!@hasDecl(Foo, "bar"));
try std.testing.expect(!@hasDecl(Foo, "baz")); // different in 0.17.0
try std.testing.expect(@hasDecl(Foo, "quux"));
}
$ zig test hasdecl.zig
1/1 hasdecl.test.@hasDecl example...OK
All 1 tests passed.
Разыменование и приведение к указателю на массив для срезов
Теперь разрешено разыменование и приведение к указателю на массив для срезов с длиной, известной на этапе компиляции (comptime).
Разрешено в текущей версии:
const slice: []const u16 = &.{ 1, 2, 3 };
const array: [3]u16 = slice.*;
const array_ptr: *const [3]u16 = slice;
Удалён синтаксис void{}
void{} больше не является допустимым синтаксисом. Вместо этого используйте {} (#15213).
Захват ошибки в errdefer удалён
errdefer |err| {
// `err` — это возвращаемая ошибка; с ней можно что-нибудь сделать!
// Как и в случае с обычными `defer` или `errdefer`, в этом блоке нельзя использовать `return` или `try`,
// поэтому изменить возвращаемую ошибку не получится, но её можно, например, залогировать.
}
Перехват (|err|) больше не разрешен (#23734).
Для миграции разделите функцию на две:
fn processOneTarget(job: Job) void {
- errdefer |err| std.debug.panic("panic: {s}", .{@errorName(err)});
+ processOneTargetInner(job) catch |err| std.debug.panic("panic: {s}", .{@errorName(err)});
+}
+fn processOneTargetInner(job: Job) !void {
const target = job.target;
Удален тип i0
i0 больше не является допустимым примитивным целочисленным типом.
Этот тип не имел смысла, поэтому прямой альтернативы для него не существует. Однако в подавляющем большинстве случаев его можно безболезненно заменить на u0.
Удалены типы глобальной компоновки internal и link_once
Теги internal и link_once из std.lang.GlobalLinkage были удалены, так как они имели неясную семантику и неполную поддержку на этапах генерации кода и компоновки (#36956). Для замены link_once, вероятнее всего, подойдет weak, а вместо internal следует просто не использовать @export для соответствующего символа.
Стандартная библиотека
- Добавлена поддержка
f128для@expи@exp2на основе работы Пин Так Питера Тана «Table-Driven Implementation of the Exponential Function in IEEE Floating-Point Arithmetic», адаптированной для работы с 128-битными числами (#31846). - Добавлен метод
std.Io.Semaphore.waitTimeout(#31924). - Добавлены вспомогательные функции
std.spirvдля сэмплирования, получения информации и записи изображений (#36187). ArrayHashMap.setKeyбольше не пересчитывает весь индекс (#32136).std.Target.parseCpuModelтеперь возвращает опциональное значение (optional) вместо ошибки.std.debug.Pdb: устранено дублирование информации о местоположении в исходном коде для встраиваемых (inline) функций (#35438).- Проведен полный аудит пространства имен
hash.crc(#35952). - В
std.fs.pathдобавлены варианты функцийrelativeиresolve, поддерживающие дописывание (appending) (#36784).
Признаны устаревшими
std.heap.memory_pool.AlignedManagedудален в пользуstd.heap.memory_pool.Aligned.std.heap.memory_pool.ExtraManagedудален в пользуstd.heap.memory_pool.Extra.- Устаревший
std.builtinв пользуstd.lang. std.meta.fieldInfoустарел в пользу@typeInfo.- Устарело
std.meta.fieldNamesв пользу@typeInfo. - Устаревший
std.meta.fieldTypesв пользу@typeInfo. - Устаревший
std.DoublyLinkedList.popв пользуstd.DoublyLinkedList.popLast. std.gpuпереименован вstd.spirv.- Удален
std.ascii.indexOfIgnoreCaseв пользуstd.ascii.findIgnoreCase. - Удален
std.ascii.indexOfIgnoreCasePosв пользуstd.ascii.findIgnoreCasePos. - Удален
std.ascii.indexOfIgnoreCasePosLinearв пользуstd.ascii.findIgnoreCasePosLinear. - Удален
std.bit_set.Integer.initEmptyв пользуstd.bit_set.Integer.empty. - Удален
std.bit_set.Integer.initFullв пользуstd.bit_set.Integer.full. - Удален
std.bit_set.Array.initEmptyв пользуstd.bit_set.Array.empty. - Удален
std.bit_set.Array.initFullв пользуstd.bit_set.Array.full. - Удален
std.enums.EnumSet.initEmptyв пользуstd.enums.EnumSet.empty. - Удален
std.enums.EnumSet.initFullв пользуstd.enums.EnumSet.full. - Удален
std.mem.containsAtLeastScalar2в пользуstd.mem.containsAtLeastScalar. - Удален
std.mem.readPackedIntNativeв пользуstd.mem.readPackedInt. - Удален
std.mem.readPackedIntForeignв пользуstd.mem.readPackedInt. - Удален
std.mem.writePackedIntNativeв пользуstd.mem.writePackedInt. - Удален
std.mem.writePackedIntForeignв пользуstd.mem.writePackedInt.
StackFallbackAllocator переработан и переименован
std.heap.StackFallbackAllocator — это абстракция, полезная для оптимизации «small vec» (вектора малого размера), при которой типичные случаи могут размещаться в предварительно выделенном буфере на стеке, а редкие требуют динамического выделения памяти в куче.
Предыдущая реализация имела ряд недостатков:
- Не было возможности задать выравнивание буфера.
- Реализация была обобщенной по размеру буфера.
- Вызов
.allocator().get()изменял тип (в отличие от всех остальных аллокаторов), что требовало проверки безопасности во время выполнения.
Теперь буфер предоставляется в качестве аргумента, как и большинство других стандартных API, которым требуется буфер.
Вследствие этого StackFallbackAllocator был переименован в BufferFirstAllocator, а std.heap.stackFallback был удален.
Руководство по миграции:
var stack align(@max(
@alignOf(std.heap.StackFallbackAllocator(0)),
@alignOf(Item)),
) = std.heap.stackFallback(@sizeOf(Item), self.gpa);
const allocator = stack.get();
⬇️
var stack_buf: [1]Item = undefined;
var stack: std.heap.BufferFirstAllocator = .init(@ptrCast(&stack_buf), gpa);
const allocator = stack.allocator();
Добавлен SafeAllocator
std.heap.DebugAllocator заменен на потокобезопасный аллокатор std.heap.SafeAllocator, обеспечивающий следующие гарантии:
- Метод
deinitсообщает обо всех утечках и освобождает всю используемую память. - Любые несоответствия при операциях выделения памяти приводят к панике или ошибке сегментации.
- Попытка освободить память, выделенную другим экземпляром
SafeAllocator, вызывает панику (если различаются значенияOptions.canary). - Повторное освобождение памяти (double free) и состояния гонки при выполнении операций (изменение размера, перераспределение или освобождение) приводят к панике или ошибке сегментации.
Поскольку базовый аллокатор не использует память повторно, данный аллокатор также не выполняет повторного использования памяти, в результате большинство операций записи после освобождения приводят либо к ошибке сегментации, либо (в конечном счете) к обнаружению проблемы и панике.
Соответственно std.heap.DebugAllocator и std.heap.Check объявлены устаревшими.
За каждым выделенным блоком памяти следует структура AllocFooter, содержащая метаданные и трассировки стека. Она защищена контрольной суммой, позволяющей выявлять повреждения из-за выхода за границы выделенной области и обнаруживать несовпадение значений-канареек (canary). Память выделяемого блока имеет минимальное выравнивание, соответствующее выравниванию AllocFooter, благодаря чему этот «подвал» (footer) располагается с фиксированным смещением, зависящим от размера выделяемого блока. Память для блока размещается одним из двух способов:
- Внутри сегментов (бакетов), заполняемых последовательно (для блоков малого размера).
- В виде отдельного блока, выделяемого непосредственно базовым аллокатором.
Для отслеживания выделенных блоков памяти каждый поток ведет таблицу соответствующих записей. Поскольку в сценариях типа «производитель-потребитель» эта таблица может изменяться другими потоками, она реализована в виде связного списка, расширяемого исключительно путем создания новых сегментов. Каждый поток также поддерживает связный список свободных записей, в который могут попадать элементы из таблиц других потоков.
Предполагается, что в операциях «производитель-потребитель» порядок доступа (семантика acquire/release) обеспечивается на внешнем уровне. Это стандартное допущение для всех потокобезопасных аллокаторов, повторно использующих память, в противном случае при повторном использовании выделенной памяти возникали бы состояния гонки данных (data races).
Для аллокатора также были добавлены два фазз-теста. Они проверяют отсутствие повторного использования памяти, а также то, что выделенная память доступна для записи и не перезаписывается. Многопоточный фазз-тест запускает ряд рабочих потоков, задействованных во всех тестовых прогонах. Я провел всестороннее тестирование с использованием инструмента TSAN.
Сборка тестов стандартной библиотеки с использованием сборки компилятора -Osafe и флага -Ddebug-allocator:
Benchmark 1 (3 runs): ./master-out/bin/zig test --zig-lib-dir lib lib/std/std.zig -femit-bin=test --test-no-exec
measurement mean ± σ min … max outliers delta
wall_time 29.4s ± 157ms 29.2s … 29.5s 0 ( 0%) 0%
peak_rss 2.24GB ± 3.49MB 2.23GB … 2.24GB 0 ( 0%) 0%
cpu_cycles 143G ± 999M 142G … 144G 0 ( 0%) 0%
instructions 268G ± 5.22M 268G … 268G 0 ( 0%) 0%
cache_references 13.1G ± 88.8M 13.0G … 13.2G 0 ( 0%) 0%
cache_misses 2.38G ± 30.7M 2.35G … 2.41G 0 ( 0%) 0%
branch_misses 634M ± 6.22M 629M … 641M 0 ( 0%) 0%
Benchmark 2 (3 runs): ./branch-out/bin/zig test --zig-lib-dir lib lib/std/std.zig -femit-bin=test --test-no-exec
measurement mean ± σ min … max outliers delta
wall_time 22.1s ± 88.6ms 22.0s … 22.2s 0 ( 0%) ⚡- 24.7% ± 1.0%
peak_rss 1.11GB ± 799KB 1.11GB … 1.11GB 0 ( 0%) ⚡- 50.3% ± 0.3%
cpu_cycles 136G ± 480M 136G … 137G 0 ( 0%) ⚡- 4.4% ± 1.2%
instructions 273G ± 2.07M 273G … 273G 0 ( 0%) 💩+ 1.6% ± 0.0%
cache_references 12.3G ± 71.3M 12.2G … 12.4G 0 ( 0%) ⚡- 6.0% ± 1.4%
cache_misses 2.02G ± 11.5M 2.01G … 2.03G 0 ( 0%) ⚡- 14.9% ± 2.2%
branch_misses 569M ± 2.65M 567M … 572M 0 ( 0%) ⚡- 10.2% ± 1.7%
ArrayList
- Функция
getLastOrNullустарела и переименована вlast - Функция
getLastустарела в пользуlastв сочетании с.? - Добавлена функция
lastPtr, возвращающая?*T
Руководство по обновлению:
if (list.getLastOrNull()) |foo| {
// ...
}
const foo = list.getLast();
⬇️
if (list.last()) |foo| {
// ...
}
const foo = list.last().?;
Стабильность указателей в ArrayList
Это улучшение, которое поможет быстрее выявлять ошибки, связанные с использованием ArrayList (#36239).
debug.SafetyLock теперь поддерживает совместную блокировку
Существующие методы lock и unlock по-прежнему работают в монопольном режиме. Их следует использовать, когда данные могут быть изменены. Новые методы lockShared и unlockShared можно использовать для разделяемой блокировки в ситуациях, когда несколько независимых пользователей читают данные, но не изменяют их.
fmt.allocPrint перенесен в mem.Allocator
try std.fmt.allocPrint(arena, "{s}={d}", .{ x, y });
⬇️
try arena.print("{s}={d}", .{ x, y });
Улучшенные возможности форматированной печати
Для спецификатора "{q}", который экранирует строки для их использования в строковых литералах с двойными кавычками, были смягчены правила экранирования: данные в кодировке UTF-8 теперь могут передаваться без искажений.
Спецификатор "{qf}" введен для экранирования двойными кавычками результата выполнения format().
Переработан std.zon.parse
std.zon.parse теперь принимает аргументы в виде структуры и выделяет память для результата из арены.
Руководство по миграции:
var diag: Diagnostics = .{};
defer diag.deinit(gpa);
const result = std.zon.fromSlice(
MyZonType,
gpa,
source,
&diag,
.{},
) catch |err| switch (err) {
error.ParseZon => std.process.fatal("input.zon: {f}", .{diag}),
error.OutOfMemory => |e| return e,
};
defer std.zon.parse.free(result);
⬇️
var diag: Diagnostics = undefined;
const result = std.zon.fromSlice(MyZonType, .{
.gpa = gpa,
.arena = arena,
.source = source,
.diagnostics = &diag,
}) catch |err| switch (err) {
error.ParseZon => diag.fatal("input.zon"),
error.OutOfMemory => |e| return e,
}
Некоторые методы были переименованы:
fromSliceAlloc➡️fromSlicefromSlice➡️fromSliceNoAlloc- Остальные методы с префиксом «from» были переименованы по той же схеме.
Были добавлены варианты «updateFrom», такие как updateFromSlice. Они обновляют значение, находящееся в памяти, перезаписывая его поля данными, указанными в источнике ZON. Это может быть полезно при использовании ZON для загрузки конфигурационных файлов с разным приоритетом — например, в текстовом редакторе, который использует как глобальный файл конфигурации, так и файл конфигурации для конкретного проекта.
Переименованы варианты bit_set и объявлен устаревшим управляемый вариант
Переименовываны типы для обеспечения единообразия, помечая предыдущие названия и управляемый вариант как устаревшие.
std.bit_set.IntegerBitSet➡️std.bit_set.Integerstd.bit_set.ArrayBitSet➡️std.bit_set.Arraystd.StaticBitset,std.bit_set.StaticBitSet➡️std.bit_set.Staticstd.DynamicBitSetUnmanaged,std.bit_set.DynamicBitSetUnmanaged➡️std.bit_set.Dynamicstd.DynamicBitSet,std.bit_set.DynamicBitSet➡️std.bit_set.DynamicManaged(устарел)
Стиль «структура из массивов» для std.lang.Type
При рефлексии типов структуры и объединения возвращают информацию в формате «структура из массивов» (#35234).
--- a/lib/compiler/Maker/ScannedConfig.zig
+++ b/lib/compiler/Maker/ScannedConfig.zig
@@ -49,9 +49,10 @@ pub fn print(sc: *const ScannedConfig, w: *Writer) Writer.Error!void {
}
fn printStruct(sc: *const ScannedConfig, s: *Serializer.Struct, comptime S: type, v: S) !void {
- inline for (@typeInfo(S).@"struct".fields) |field| {
- try s.fieldPrefix(field.name);
- try printValue(sc, s.container.serializer, field.type, @field(v, field.name));
+ const info = @typeInfo(S).@"struct";
+ inline for (info.field_names, info.field_types) |field_name, field_type| {
+ try s.fieldPrefix(field_name);
+ try printValue(sc, s.container.serializer, field_type, @field(v, field_name));
}
}
Переименован lang.OptimizeMode в lang.Optimize
Кроме того, удалите слово «release» из имен элементов перечисления (enum).
Функциональных изменений нет. Однако, несмотря на добавление в этот патч объявлений для обеспечения обратной совместимости, это изменение является ломающим (breaking change), поскольку выражения, использующие операторы == или !=, не смогут применять устаревшие имена.
std.lang:OptimizeMode➡️OptimizeDebug➡️-debugReleaseSafe➡️-safeReleaseFast➡️-fastReleaseSmall➡️-small
lang.Optimize.runtimeSafety
std.lang.Optimize.runtimeSafety предпочтительнее, чем std.debug.runtime_safety, поскольку он предоставляет информацию о вызывающем модуле, а не о модуле стандартной библиотеки.
Объявление @import("builtin") признано устаревшим
Избыточные константы cpu, os, abi и object_format в @import("builtin") объявлены устаревшими и будут удалены в версии 0.18.0. Пожалуйста, замените их использование соответствующими полями константы target:
@import("builtin").cpu➡️@import("builtin").target.cpu@import("builtin").os➡️@import("builtin").target.os@import("builtin").abi➡️@import("builtin").target.abi@import("builtin").object_format➡️@import("builtin").target.ofmt
Корректная обработка чисел с плавающей запятой в mem.eql и mem.findDiff
Функции std.mem.eql и std.mem.findDiff выполняют быструю проверку (short-circuiting), если оба входных аргумента являются срезами, указывающими на одну и ту же область памяти. Такая оптимизация корректна лишь в том случае, если оператор == для данного типа обладает свойством рефлексивности. Для чисел с плавающей запятой это условие не выполняется: например, std.math.nan(f64) != std.math.nan(f64). Изменения в данном PR отключают эту оптимизацию при работе со срезами чисел с плавающей запятой.
Тесты, которые ранее завершались неудачей, а теперь проходят успешно:
const x: [3]f64 = .{ 42.0, std.math.nan(f64), 3.1415 };
try std.testing.expect(!std.mem.eql(f64, &x, &x));
try std.testing.expectEqual(1, std.mem.findDiff(f64, &x, &x));
Устранены зависимости между Uri и net.HostName
В классе Uri метод HostName.validate для проверки host использовался непоследовательно: в resolveInPlace он применялся, а в parseAfterScheme — нет. Сам по себе этот факт был проблемой, но более серьезная трудность заключается в том, что определения допустимого имени хоста в RFC3986 (для Uri) и RFC1123 (для HostName) существенно различаются; поэтому принудительное использование HostName.validate во всех случаях сделало бы Uri менее удобным инструментом.
В связи с этим весь функционал, связанный с HostName, был удален из Uri. Метод Uri.getHost был перенесен в HostName.fromUri (без плавного перехода через механизм deprecation, поскольку семантика методов различается настолько, что пользователям необходимо самостоятельно проанализировать места их вызова), а метод Uri.getHostAlloc был удален полностью.
Руководство по миграции:
var host_buf: [HostName.max_len]u8 = undefined;
const host = try uri.getHost(&host_buf);
⬇️
var host_buf: [HostName.max_len]u8 = undefined;
// Примечание: набор ошибок отличается от предыдущего,
// поскольку fromUri выполняет проверку на допустимость имени хоста
const host = try HostName.fromUri(uri, &host_buf);
Система сборки
b.build_root(Директория) ➡️b.root(Путь)ConfigHeader.Options:include_guard_override➡️include_guardLazyPath:getDisplayName➡️format("{f}")LazyPath.basename: удалено, так как значение становится известным только на этапе сборки (make phase).b.findProgramразделено наfindProgramиfindProgramLazy, API адаптировано с учетом перспектив развития.- Исправлен
ConfigHeader: теперь выдаются сообщения о неиспользуемых значениях для всех стилей. addArtifactArg,addPrefixedArtifactArg➡️addArtifactArg2addOutputFileArg,addPrefixedOutputFileArg➡️addOutputFileArg2addFileContentArg,addPrefixedFileContentArg➡️addFileContentArg2addOutputDirectoryArg,addPrefixedOutputDirectoryArg➡️addOutputDirectoryArg2addDirectoryArg,addPrefixedDirectoryArg,addDecoratedDirectoryArg➡️addDirectoryArg2addDepFileOutputArg,addPrefixedDepFileOutputArg➡️addDepFileOutputArg2addFileArg,addPrefixedFileArg➡️addFileArg2
Разделён процесс создания и процесс конфигурирования
Теперь команда zig build выполняет код build.zig проекта в отдельном исполняемом файле — отличном от того, который отвечает за управление пакетами и выполнение графа сборки. Это ускоряет работу zig build по ряду причин (#35428):
- Исполняемый файл
makerне меняется при редактировании скриптаbuild.zig, поэтому его нужно собирать всего один раз (при первоначальной настройке) после установки Zig. - Исполняемый файл
makerсобирается с включенными оптимизациями, что становится особенно важным с появлением режимов--watchи--fuzz. - Выполнение логики
build.zigв некоторых случаях можно пропустить — в зависимости от того, какие флаги командной строки используются сzig build.
Кроме того, конфигурация теперь сериализуется в компактный бинарный формат, пригодный для использования сторонними инструментами и являющийся частью нового протокола сервера сборки (Build Server Protocol). Прежний способ решения этой задачи путем создания форка исполнителя сборки (build runner) больше не поддерживается.
Чтобы вывести конфигурацию в формате .zon в стандартный вывод (stdout), используйте флаг --print-configuration.
Система кэширования переработана
Новые возможности:
- Поддержка директорий. Добавлена возможность вызывать инвалидацию кэша (cache miss) при добавлении, удалении или переименовании записей в директориях.
- Режим метаданных. Обычно инвалидация кэша происходит только при изменении содержимого. В режиме метаданных инвалидаия кэша происходит всегда, если изменяются размер, inode или время модификации (mtime), независимо от содержимого.
Возможны все четыре комбинации (is_directory=true/false, metadata_mode=true/false). Эти функции доступны через новый API в системе сборки.
Поскольку инструментарий Zig активно использует систему кэширования, в этом выпуске формат кэша был заменен на бинарный. Это позволило уменьшить размер файлов примерно на 25%, снизив нагрузку на кэш файловой системы и упростив задачу для компьютера: теперь данные копируются непосредственно с диска, а не извлекаются путем синтаксического разбора текстовых файлов. Для отладки или ручной работы с файлами в директории zig-cache добавлена новая подкоманда zig cache-cat.
Система кэширования теперь также способна пояснить причину инвалидации кэша (cache miss). Публичный API модуля std.Build.Cache претерпел множество изменений, нарушающих обратную совместимость; впрочем, за пределами инструментов компилятора этот API используется редко, а внесенные изменения делают его менее подверженным неправильному использованию.
Отмечено, что это изменение повышает скорость обработки на 5–10% (#36822).
Представлена концепция настройки «порчи» кэша
Если кэш оказывается «испорченным» (invalidated/corrupted), это означает, что логика конфигурирования имела побочные эффекты или иным образом совершила действия, которые не могли быть отслежены системой кэширования.
Не следует путать это с наличием побочных эффектов у отдельных шагов в процессе их выполнения, речь идет именно о логике внутри самого файла build.zig. Например, шаг Run, выводящий «hello world», имеет побочные эффекты на этапе сборки (make time), поэтому установка данного флага для него не требуется. В то же время проверка наличия scdoc на этапе конфигурирования (configure time) для выбора значения по умолчанию — это действие, требующее установки такого флага.
Поддержание чистоты кэша ускоряет работу zig build, позволяет пропустить процесс конфигурирования в тех случаях, когда результат конфигурации остался бы неизменным.
При «порче» кэша (cache poisoning) процесс сборки удаляет файл конфигурации сборки сразу после его считывания, так как повторно использовать его уже нельзя.
К числу способов «порчи» кэша относятся вызов findProgram или, более напрямую, std.Build.Graph.poisonCache. Лучшей альтернативой «порче» кэша является явное объявление зависимостей конфигурации с помощью следующих новых функций:
std.Build.dependOnFileContents— указывает, что логикаbuild.zigзависит от содержимого конкретного файла.std.Build.dependOnFileMetadata— указывает, что логикаbuild.zigзависит от размера,inode, времени изменения (mtime) и содержимого конкретного файла.std.Build.dependOnDirectoryContents— указывает, что логикаbuild.zigзависит от состава элементов (файлов и подкаталогов) в конкретном каталоге.std.Build.dependOnDirectoryMetadata— указывает, что логикаbuild.zigзависит от даты последнего изменения конкретного каталога.
Продвинутые пользователи могут изменить поведение, связанное с «порчей» кэша, с помощью новой опции командной строки:
--cache-poison[=mode] Override configuration caching behavior
pure (default) Avoid false positive cache hits
poisoned Don't cache the configuration
disallowed Panics when cache would be poisoned
ignored A little poison never hurt anybody
findProgram
Выполняет немедленный (на этапе конфигурирования) поиск исполняемого файла на хост-системе, у которого может быть несколько вариантов имени.
Поиск имен осуществляется в определенном порядке: сначала проверяются пути с учетом префиксов поиска, а затем — переменная окружения PATH.
Вызов этой функции делает кэш конфигурации недействительным («портит» его), поэтому ее следует использовать только в тех случаях, когда логике конфигурирования необходимо знать о существовании программы или результатах ее выполнения. Именно поэтому теперь существует также функция findProgramLazy.
findProgramLazy
Создает анонимный Step, который ищет на хост-системе исполняемый файл, имеющий несколько возможных вариантов имени.
В отличие от findProgram, эта функция не «портит» кэш конфигурации, однако полученный результат нельзя использовать на этапе конфигурации, поэтому функция возвращает LazyPath.
Возвращает LazyPath, указывающий на найденный исполняемый файл. Поиск выполняется только в том случае, если этот LazyPath будет использован зависимым Step.
Этот API полезен в следующих ситуациях:
- Имя бинарного файла различается в разных системах (например, «python» и «python3»).
- Бинарный файл может быть получен в результате сборки из исходного кода, а не установлен глобально, и поэтому может находиться в одном из путей поиска (префиксов).
Run Step: Передача аргументов
На этапе все аргументы для передачи (passthru args) теперь объединены, на этапе настройки невозможно определить, были ли предоставлены аргументы для запуска.
--- build.zig
+++ build.zig
@
-if (b.args) |args| {
- run_cmd.addArgs(args);
-}
+run_cmd.addPassthruArgs();
Это лишает сценарии сборки определенной возможности, поскольку они больше не могут отслеживать часть аргументов. Зато это означает, что при изменении данных аргументов сценарии сборки больше не нужно пересобирать из исходного кода.
Fmt Step: Параметры
paths и exclude_paths теперь представляют собой списки LazyPath. Для их создания предусмотрен удобный метод: b.pathList.
--- build.zig
+++ build.zig
@
- const fmt_include_paths = &.{ "lib", "src", "test", "tools", "build.zig", "build.zig.zon" };
- const fmt_exclude_paths = &.{ "test/cases", "test/behavior/zon" };
+ const fmt_include_paths = b.pathList(&.{ "lib", "src", "test", "tools", "build.zig", "build.zig.zon" });
+ const fmt_exclude_paths = b.pathList(&.{ "test/cases", "test/behavior/zon" });
Step.Options: добавлен addOptionPathDirectory
Теперь при добавлении опции, представляющей собой путь к файлу, необходимо явно выбрать один из следующих вариантов (#36876):
addOptionPath(должен быть файлом)addOptionPathDirectory(должен быть директорией)addOptionPathUntracked(отказ от отслеживания зависимостей)
Эргономические улучшения для «ленивых» зависимостей
- Добавлено логирование момента получения «ленивых» зависимостей.
std.Build.dependency: добавлена поддержка «ленивых» зависимостей.- Добавлен метод
std.Build.dependencyLazy, который вместоnullможет возвращатьerror.LazyDependencyNeeded, позволяя использоватьtry. - Если пользовательские функции
buildвозвращаютerror.LazyDependencyNeeded, система сборки приступает к загрузке этих зависимостей, а не завершает процесс с ошибкой на этапе конфигурации.
Удалена возможность переопределения исполнителя сборки.
Больше не существует понятия «исполнитель сборки», он был разделён на конфигуратор и создатель
Этот вариант использования теперь обрабатывается Протоколом сервера сборки.
Управление пакетами
Весь функционал управления пакетами был перенесён из компилятора в систему сборки.
Сюда входят следующие подкоманды:
zig buildzig fetchzig initzig libczig cache-cat
Это означает, что значительная часть компонентов, ранее входивших в состав исполняемого файла компилятора, теперь поставляется в виде исходного кода. К ним относятся:
- логика загрузки пакетов;
- HTTP-клиент и сетевые функции;
- TLS (Transport Layer Security) и связанные с ним криптографические средства;
- протокол git;
- алгоритмы сжатия xz, gzip, zstd, flate, zip;
- разбор, проверка и обработка файлов
build.zig.zon.
Поскольку эти компоненты теперь являются частью компилятора, они компилируются с уровнем оптимизации -Osafe, а не -Ofast. При работе над самой системой сборки можно использовать переменную окружения ZIG_DEBUG_CMD=1, чтобы скомпилировать систему сборки в режиме отладки.
Прочие изменения:
- Исправление ошибки: отклонение зависимостей по пути, выходящих за пределы корня родительского пакета.
Возможность переопределять путь к пакетам
Аргумент командной строки --pkg-path и переменная окружения ZIG_LOCAL_PKG_DIR теперь учитываются как при выполнении команды fetch, так и при выполнении команды build.
Глобальная против локальной выборки
Теперь zig fetch загружает файлы только в глобальный кэш, как и раньше. Однако, если используется --save (или любой его вариант), то загрузка также происходит в локальный путь к пакету. При глобальной загрузке наличие build.zig не требуется. zig build всегда загружает файлы локально (в дополнение к глобальной загрузке).
Важно отметить, что это исправляет устаревший сценарий использования zig fetch.
При загрузке по пути всегда вычисляется хеш, всегда создается пересжатый архив, и всегда перезаписывается любая существующая запись в глобальном кэше.y.
Небольшое различие в PATH для аргументов DLL
Раньше при работе с Windows или Wine аргументы, связанные с артефактами и добавленные к шагам выполнения (Run steps), изменяли переменную PATH с учетом каталогов, содержащих полный набор рекурсивных зависимостей DLL. Теперь это выполняется только для argv[0]. Причины, по которым это делалось и для остальных аргументов командной строки, неясны, поскольку для запуска argv[0] загрузка этих DLL не требуется.
Протокол сервера сборки
Теперь при использовании флага --listen=- система сборки предоставляет протокол, позволяющий подключенным клиентам отслеживать граф сборки и управлять им в процессе выполнения. Этот механизм предназначен для использования сторонними инструментами, например, IDE.
Доступные на данный момент возможности:
- Получение полного доступа к статическим данным графа сборки (сформированным после этапа конфигурации), таким как список доступных этапов сборки, установленные параметры, зависимости и т. д. Некоторые элементы пока не включены — например, список имен модулей.
- Получение уведомлений о начале и завершении этапов сборки, включая информацию об ошибках и созданных файлах.
- Запрос выполнения конкретных этапов сборки.
В частности, разделение процессов создания (maker) и настройки (configurer) стало изменением, нарушающим обратную совместимость и препятствующим работе проекта ZLS с версией 0.17.0. Хотя в текущем цикле выпуска удалось добиться определенного прогресса в восстановлении функциональности, команды Zig и ZLS продолжают совместную работу над дальнейшим развитием протокола сервера сборки. Цель — не просто восстановить прежние возможности ZLS, но и превзойти их, обеспечив более высокую эффективность и расширенный функционал.
Ожидается, что в будущем значительная часть собственных инструментов системы сборки Zig перейдет на использование протокола сервера сборки (применяя принцип «dogfooding» — использование собственных продуктов). Это гарантирует, что сторонние инструменты получат доступ к аналогичным возможностям (#36497).
Также планируется, что сервер сборки будет обеспечивать мультиплексирование протокола сервера компиляции для этапов компиляции, предоставляя информацию о системе типов, средства рефакторинга и другие продвинутые возможности редактирования кода (#615).
Компилятор
Инкрементная компиляция
В версии Zig 0.17.0 была существенно улучшена реализация инкрементальной компиляции — функции, позволяющей практически мгновенно пересобирать проекты после внесения изменений в код. Было исправлено множество ошибок, а новый компоновщик ELF, представленный в предыдущем релизе, получил полноценную поддержку этой функции.
Благодаря этим улучшениям большинство проектов, ориентированных на платформу x86_64-linux, теперь могут использовать преимущества инкрементальной компиляции. Для этого добавьте аргументы -fincremental --watch к команде zig build (например, zig build -fincremental --watch): система сборки Zig будет отслеживать изменения в исходных файлах и выполнять инкрементальную пересборку в ответ на них.
Чтобы узнать больше о способах использования инкрементальной компиляции в ваших проектах или разобраться в том, как эта функция работает «под капотом», рекомендуем ознакомиться с этой статьей в блоге, написанной участником основной команды разработчиков Zig.
В будущих релизах работа над этой функцией продолжится: планируется внедрение нового компоновщика Mach-O и написанного на самом Zig бэкенда aarch64 с качественной поддержкой инкрементальной компиляции, добавление возможности использовать инкрементальную компиляцию без флага --watch, а также исправление оставшихся ошибок.
SPIR-V Backend
Собственный бэкенд SPIR-V теперь поддерживает многопоточность, как и другие бэкенды.
Режимы выполнения, такие как LocalSize и OriginUpperLeft, теперь определяются на основе соглашения о вызове функции, а не задаются через встроенный ассемблер; кроме того, новые соглашения о вызове spirv_task и spirv_mesh обеспечивают поддержку task- и mesh-шейдеров (#35676).
Объявление возможностей (capabilities) и расширений (extensions) через встроенный ассемблер с использованием инструкций OpCapability и OpExtension больше не допускается. Вместо этого они активируются через настройки целевого процессора (CPU features), то есть с помощью опции -mcpu.
В ходе этого цикла выпуска в бэкенде SPIR-V было исправлено 22 ошибки.
aarch64 Backend
Продвижение в этом направлении сдерживается необходимостью доработки компоновщика, многие из соответствующих улучшений были реализованы в ходе текущего цикла выпуска.
loongarch Backend
Реализована начальная версия собственного (self-hosted) бэкенда для архитектуры loongarch64 (#36418). На данный момент он носит экспериментальный характер и пока не пригоден для практического использования. Внести вклад в разработку этого бэкенда можно двумя способами: работая над ним напрямую или участвуя в реализации функций приведения AIR к допустимому виду (AIR Legalization Features) — это помогает быстрее довести до готовности все незавершенные бэкенды.
WebAssembly Backend
Бэкенд Zig для WebAssembly теперь проходит 2060 из 2054 (100%) тестов на соответствие поведению по сравнению с бэкендом LLVM. Однако он пока не используется по умолчанию при компиляции в режиме отладки (debug) из-за отсутствия поддержки отладочной информации (#37032).
Линкер
ELF
Этот выпуск знаменует собой значительный прогресс в деле замены устаревшего самохостируемого ELF-компоновщика Zig на новую реализацию, представленную в предыдущей версии.
Среди конкретных улучшений:
- Полная поддержка x86_64
- Полная поддержка SPARC64
- Частичная поддержка LoongArch
- Генерация статических библиотек
- Генерация разделяемых библиотек
- Выдача ошибок при обнаружении неопределенных символов в исполняемых файлах
- Генерация таблицы глобальных смещений (GOT)
- Релокации типа copy (copy relocations)
- Поддержка версий символов в стиле GNU
- Генерация отладочной информации DWARF
- Генерация хеш-таблицы символов
- Бинарные файлы с высокой степенью воспроизводимости сборки
- Произвольное выравнивание секций
- Поддержка малых размеров блоков файловой системы хоста
Хотя этот компоновщик пока не полностью сравнялся по функциональности с нашим старым ELF-компоновщиком (и поэтому по умолчанию отключен), на практике он уже способен собирать подавляющее большинство проектов на Zig, предназначенных для платформы x86_64-linux. Это открывает возможность использования инкрементальной компиляции для таких проектов: как и в версии Zig 0.16.0, в данном случае новый компоновщик включен по умолчанию.
В следующем выпуске Zig мы надеемся полностью отказаться от устаревшего ELF-компоновщика в пользу этой реализации.
COFF
Поддержка формата COFF в компоновщике была расширена следующими возможностями (#35674):
- Генерация объектных файлов (.obj) и статических библиотек (.lib)
- Генерация библиотек импорта (implib) одновременно с исполняемыми файлами/библиотеками (образами)
- Генерация таблиц данных TLS и Export для образов
- Использование объектных файлов, статических библиотек и библиотек импорта в качестве входных данных
- Выборочное включение объектных модулей из статических библиотек (только если они содержат символ, необходимый для разрешения ссылки)
- Поддержка правил COMDAT (достаточная для компоновки compiler_rt и libc; некоторые типы COMDAT пока не поддерживаются)
- Поддержка компоновки с использованием libc как в стиле GNU, так и в стиле MSVC
- Поддержка TLS
- Поддержка
__dllimport: косвенные вызовы и загрузка данных непосредственно из таблицы адресов импорта (IAT) - Автоматический выбор точки входа на основе экспортируемых символов
- Режим
-gnu: поддержка конструкторов и деструкторов (объединение секций.ctorи.dtor, а также настройка символов__CTOR_LIST__и__DTOR_LIST__) - Поддержка ряда аргументов секции
.drectve(необходимых для корректной компоновки с libc в стиле MSVC):/INCLUDE: принудительное включение символа (создание ссылки на него)/ALTERNATENAME: добавление псевдонимов (алиасов) для символов/MERGE: объединение секций (эта функция также используется для размещения определенных секций в нужных областях, например,.ctor/.dtorв.rdata)/DEFAULTLIB: добавление дополнительных входных библиотек
Новая система тестирования линкера
В Zig для тестирования компоновщиков (линкеров) внедряется подход, основанный на использовании снимков (snapshots).
Тестирование включает в себя сравнение вывода objdump (в виде снимков), фактический запуск полученных артефактов и проверку на наличие ошибок компоновки.
Запуск команды zig build -Dlink-snapshot-update переводит тесты в режим генерации снимков вместо их проверки.
Типичный порядок действий при добавлении нового теста:
- Добавьте тест.
- Выполните
zig-debug build test-link -Dtest-filter=my-test -Dlink-snapshot-update- Будет создан файл
.dmpдля всех комбинаций снимков, определенных в вызовахverifyObjdump. - Один и тот же снимок может использоваться для нескольких целевых платформ (targets) во избежание избыточности файлов в папке снимков; обновление снимка выполняется тем тестом, который запускается первым для данного имени снимка. Если между целевыми платформами существуют различия, они проявятся на этапе №4.
- Будет создан файл
- Проверьте корректность полученного снимка.
- Выполните
zig-debug build test-link -Dtest-filter=my-test- Теперь все целевые платформы будут протестированы с использованием только что созданных снимков.
- Если возникнут ошибки при сравнении со снимками, это означает, что для разных целевых платформ получились разные результаты. Следует изучить вывод, чтобы определить, являются ли эти различия допустимыми. Если это так, нужно использовать параметр
scope, чтобы при запуске с-Dlink-snapshot-updateснимки сохранялись в файлы с разными именами, учитывающими эти различия. - Снова запустите команду с
-Dlink-snapshot-update, чтобы обновить набор снимков.
SPIR-V
Компоновщик SPIR-V был переписан (#36828). Теперь он поддерживает инкрементальную компиляцию и может компоновать внешние объектные файлы .spv.
Fuzzer
Хотя изменения в системе сборки в этом выпуске косвенно связаны со встроенным фаззером Zig и его взаимодействием с системой сборки, в сам фаззер никаких изменений внесено не было.
Мы планируем сосредоточиться на улучшении фаззера в одном из будущих циклов выпуска.
Исправления ошибок
Полный список из 329 сообщений об ошибках, закрытых в ходе этого цикла выпуска:
Многие ошибки были как обнаружены, так и исправлены в рамках этого цикла выпуска. Для краткости большинство исправлений ошибок не включено в данный список изменений.
Этот выпуск содержит ошибки
Оставшиеся в Zig:
Даже в версии Zig 0.17.x работа над нетривиальным проектом на Zig может потребовать от вас участия в процессе разработки языка.
Когда Zig достигнет версии 1.0.0, наличие политики обработки ошибок станет дополнительным требованием для поддержки уровня Tier 1.
Заметные регрессии
Нам известно о следующих заметных регрессиях в версии 0.17.0:
- #37006: ошибка компиляции compiler-rt для режима программной эмуляции операций с плавающей запятой (soft float) на архитектуре x86
- #36986: ошибка компиляции
std.debug.simple_panic - #36986: слабые (weak) символы libc в Zig невозможно надежно переопределить
- #36444: разделение процессов сборки и настройки нарушает работу с файлами ответов (response files) в
std.Build.Step.Run - #37050: регрессии в бэкенде SPIR-V
Инструментарий
LLVM 22
В этом выпуске Zig используется обновленная версия LLVM 22.1.8. Это обновление также затрагивает Clang (zig cc), libc++, libc++abi, libunwind и libtsan.
Векторизация циклов отключена для обхода регрессии
В предыдущем выпуске Zig нам пришлось отключить важный этап оптимизации LLVM — векторизацию циклов, — чтобы обойти проблему некорректной компиляции, затрагивавшую компилятор Zig.
С момента внедрения этого временного решения в основную ветку LLVM было внесено исправление. Однако оно отсутствует в версии LLVM 22, используемой в Zig 0.17.0. Поэтому пока данное обходное решение остается активным.
В версии Zig 0.18.0 планируется переход на LLVM 23, что позволит нам снова включить этот этап оптимизации.
musl 1.2.5
В состав Zig 0.17.0 входит musl версии 1.2.5 с бэкпортированными исправлениями, касающимися безопасности и переносимости. Тем временем в основном проекте (upstream) уже выпущена версия 1.2.6. Переход на musl 1.2.6 запланирован для Zig 0.18.0.
При статической компоновке с musl многие функции теперь предоставляются компонентом zig libc, а не берутся из исходных файлов, скопированных из musl. Поэтому, если вы столкнетесь с ошибками в реализации musl libc, поставляемой вместе с Zig, пожалуйста, сообщайте о них в систему отслеживания ошибок Zig, а не musl — это проявление уважения к авторам исходного проекта.
glibc 2.44
Версия glibc 2.44 теперь доступна при кросс-компиляции.
Linux 7.2 Headers
Этот выпуск включает заголовочные файлы ядра Linux версии 7.2.
macOS 27.0 Headers
Этот выпуск включает системные заголовочные файлы macOS для версии 27.0.
MinGW-w64
В состав Zig 0.17 входит MinGW-w64 (коммит 31bd54ab7d5fe03c67ed2bb1a57e531b9c7f8cc4).
Однако, многие функции теперь предоставляются компонентом zig libc, а не исходными файлами, скопированными из MinGW-w64. Поэтому, если вы столкнетесь с ошибками в реализации libc от MinGW-w64, поставляемой вместе с Zig, пожалуйста, сообщайте о них в систему отслеживания ошибок Zig, а не MinGW-w64.
NetBSD 11.0 libc
NetBSD libc версии 11.0 теперь доступна при кросс-компиляции.
OpenBSD 7.9 libc
Версия 7.9 библиотеки libc для OpenBSD теперь доступна при кросс-компиляции.
WASI libc
Zig 0.17.0 продолжает поставлять WASI libc версии, соответствующей коммиту c89896107d7b57aef69dcadede47409ee4f702ee.
Однако многие функции теперь предоставляются через zig libc, а не за счет копирования исходных файлов из WASI libc.
Более того, начиная с версии Zig 0.18.0, вместо распространения стороннего кода WASI libc, Zig будет предоставлять libc для целей WASI посредством zig libc. Дополнительную информацию можно найти здесь:
zig libc
В файлах libc.txt поле gcc_dir было переименовано в cc_dir, чтобы отразить тот факт, что оно не привязано исключительно к GCC. Старое имя пока по-прежнему поддерживается, однако пользователям рекомендуется обновить свои файлы libc.txt, перейдя на новое имя (#36951).
Кроме того, для целевых платформ Linux наличие cc_dir теперь обязательно. Обратите внимание: поскольку в Android и OpenHarmony соответствующие объектные файлы хранятся в нестандартных местах, пользователям, работающим с этими системами, вероятно, потребуется указать для cc_dir тот же путь, что и для crt_dir.
zig cc
zig cc и zig c++ теперь основаны на Clang 22.1.8.
zig objdump
Это было требованием для тестирования на основе снимков состояния (snapshot testing), а также способствовало разработке компоновщика формата COFF.
Поддерживаемые возможности:
Usage: zig objdump [options] file
Options:
-h, --help Print this help and exit
--all-headers Alias for --file-headers --linker-member=2 --member-headers --section-headers --relocs --symbols
--exports[=sort] Display exported symbols.
In the case of COFF import libraries, displays the symbol list and import headers.
Specify =sort to optionally sort the import headers by symbol name.
--file-headers Display file-format specific headers
--imports Display imported symbols
--linker-member[=1|2|longnames] (Coff) Display contents of the specified archive linker member (default 2)
--member-headers Display archive member headers
--elements=[e1],[e2],-[e3],... Select which formatting elements are displayed. Intended for snapshot testing.
file-type File type summary
header-name Name that precedes a header block
member-path Display full member paths. If removed, only basenames will be used.
newlines Newlines between output sections
table-header Table headers with column names
all (default) All of the above
--only-member=[name] Only consider archive members names that contain [name]. Can be specified multiple times.
--only-section=[name] Only consider section names that contain [name]. Can be specified multiple times.
--only-symbol=[name] Only consider symbol names that contain [name]. Can be specified multiple times.
--redact=[kind] Redact the specified field kind. Intended for snapshot testing.
rva Relative virtual addresses
va Virtual addresses and file offsets
ord Symbol ordinals / hints
size Sizes and lengths
all All of the above
--relocs Display relocations
-s, --snapshot Alias for --redact=all --elements=-all
--section-headers Display section headers
--strings Display string tables
--symbols Display symbol tables
--tls Display TLS information
Пример вывода:
❯ zig objdump mathtest-dync-exe-no-llvm.dll --all-headers
mathtest-dync-exe-no-llvm.dll: PE/COFF image
COFF Header:
8664 machine (AMD64)
7 number_of_sections
6a08670a time_date_stamp
0 pointer_to_symbol_table
0 number_of_symbols
f0 size_of_optional_header
2022 flags
| EXECUTABLE_IMAGE
| LARGE_ADDRESS_AWARE
| DLL
COFF Optional Header:
20b magic (PE32+)
14.00 linker_version
14a400 size_of_code
84e00 size_of_initialized_data
0 size_of_uninitialized_data
1000 address_of_entry_point ( 180001000)
1000 base_of_code ( 180001000)
180000000 image_base
1000 section_alignment
200 file_alignment
6.00 operating_system_version
1.00 image_version
6.00 subsystem_version
0 win32_version_value
1d6000 size_of_image
400 size_of_headers
0 checksum
2 subsystem (WINDOWS_GUI)
160 dll_flags
| HIGH_ENTROPY_VA
| DYNAMIC_BASE
| NX_COMPAT
100000 size_of_stack_reserve
1000 size_of_stack_commit
100000 size_of_heap_reserve
1000 size_of_heap_commit
0 loader_flags
10 number_of_rva_and_sizes
Data Directories:
1b48d0 54 EXPORT
1b4924 8c IMPORT
0 0 RESOURCE
1cc000 633c EXCEPTION
0 0 SECURITY
1d4000 1280 BASERELOC
1bc000 1c DEBUG
0 0 ARCHITECTURE
0 0 GLOBALPTR
1aebc8 28 TLS
0 0 LOAD_CONFIG
0 0 BOUND_IMPORT
1b4c80 2d0 IAT
0 0 DELAY_IMPORT
0 0 COM_DESCRIPTOR
0 0 RESERVED
Sections in 'mathtest-dync-exe-no-llvm.dll':
Num Name RVA Virt Size Data Size & Data & Relocs & Lines # Relocs # Lines Flags
1 .text 1000 14a346 14a400 400 0 0 0 0 60000020 | CNT_CODE MEM_EXECUTE MEM_READ
2 .rdata 14c000 6fe3c 70000 14a800 0 0 0 0 40000040 | CNT_INITIALIZED_DATA MEM_READ
3 .buildid 1bc000 52 200 1ba800 0 0 0 0 40000040 | CNT_INITIALIZED_DATA MEM_READ
4 .data 1bd000 e2a0 d200 1baa00 0 0 0 0 c0000040 | CNT_INITIALIZED_DATA MEM_READ MEM_WRITE
5 .pdata 1cc000 633c 6400 1c7c00 0 0 0 0 40000040 | CNT_INITIALIZED_DATA MEM_READ
6 .tls 1d3000 20 200 1ce000 0 0 0 0 c0000040 | CNT_INITIALIZED_DATA MEM_READ MEM_WRITE
7 .reloc 1d4000 1280 1400 1ce200 0 0 0 0 42000040 | CNT_INITIALIZED_DATA MEM_DISCARDABLE MEM_READ
No symbol table found
Если этот вывод использовался для снапшот-теста, целью которого была проверка наличия определенного экспорта:
❯ zig objdump mathtest-dync-exe-no-llvm.dll --exports --only-symbol=add --redact=rva --elements=-all
Export directory:
0 flags
0 time_date_stamp
0.00 version
xxxxxxxxxxxxxxxx name_rva
1 ordinal_base
1 number_of_entries
1 number_of_names
xxxxxxxxxxxxxxxx export_address_table_rva
xxxxxxxxxxxxxxxx name_pointer_table_rva
xxxxxxxxxxxxxxxx ordinal_table_rva
1 0 xxxxxxxx | add
Функции маскирования (--redact=) и удаления элементов (--elements=) используются для исключения из выходных данных тех частей, которые не важны для конкретного теста; это позволяет избежать ложных сбоев — например, если RVA (относительный виртуальный адрес) символа изменится из-за каких-либо не связанных с тестом изменений в компоновщике. Флаг -s — это сокращенная запись, активирующая все виды маскирования и удаляющая все дополнительные элементы вывода, однако в тестах, где важны конкретные значения, этот флаг не обязателен для использования.
Компиляция ресурсов Windows
Компиляция ресурсов Windows переносится во внешний пакет
Компиляция скриптов ресурсов Windows будет вынесена из компилятора в официальный, но внешний пакет системы сборки в следующем релизе. В связи с этим соответствующие функции и поля std.Build (Build.Module.addWin32ResourceFile и т. д.) в этом релизе помечены как устаревшие.
Подкоманда zig rc останется после этого изменения, чтобы и дальше поддерживать использование набора инструментов Zig с другими системами сборки.
zig fmt
Добавлен флаг --complexity
Это простой инструмент для подсчета лексем и узлов абстрактного синтаксического дерева, который можно использовать, чтобы определить, как изменение в исходном файле увеличивает или уменьшает сложность кода, с помощью эвристического метода, более информативного, чем подсчет строк.
Например, запустим его на старом каталоге компоновщика ELF:
info: src/link/Elf/gc.zig: tokens=1538 nodes=770
info: src/link/Elf/Atom.zig: tokens=15576 nodes=7768
info: src/link/Elf/Merge.zig: tokens=2288 nodes=1092
info: src/link/Elf/Thunk.zig: tokens=1128 nodes=519
info: src/link/Elf/SharedObject.zig: tokens=4566 nodes=2236
info: src/link/Elf/eh_frame.zig: tokens=4840 nodes=2335
info: src/link/Elf/Symbol.zig: tokens=3770 nodes=1872
info: src/link/Elf/synthetic_sections.zig: tokens=13287 nodes=6375
info: src/link/Elf/Object.zig: tokens=13903 nodes=6842
info: src/link/Elf/LinkerDefined.zig: tokens=4140 nodes=2091
info: src/link/Elf/relocatable.zig: tokens=3598 nodes=1848
info: src/link/Elf/Archive.zig: tokens=2176 nodes=1028
info: src/link/Elf/ZigObject.zig: tokens=20783 nodes=10274
info: src/link/Elf/AtomList.zig: tokens=1819 nodes=933
info: src/link/Elf/relocation.zig: tokens=1289 nodes=551
info: src/link/Elf/file.zig: tokens=2330 nodes=1087
info: total: tokens=97031 nodes=47621
Другой пример: после редактирования Lld.zig для использования arena.print вместо std.fmt.allocPrint. Количество строк осталось примерно тем же, но --complexity показывает другую картину:
- до: токенов=11929, узлов=5900
- после: токенов=11832, узлов=5852 (снижение сложности исходного кода на 1%)
В будущем этот показатель может пригодиться для автоматического организатора импорта, чтобы определить, нужно ли создавать псевдоним для импорта.
Дорожная карта
- Совместно с командой ZLS доработать протокол Build Server Protocol так, чтобы он отвечал всем их потребностям.
- Завершить реализацию поддержки Windows в бэкенде x86_64, чтобы его можно было включить по умолчанию.
- Завершить разработку и стабилизировать язык.
- Завершить работу над бэкендом aarch64 и сделать его бэкендом по умолчанию для режима отладки.
- Усовершенствовать реализации компоновщика, устранив зависимость от LLD и обеспечив поддержку инкрементальной компиляции.
- Улучшить встроенный фаззер так, чтобы он мог конкурировать с AFL и другими передовыми инструментами фаззинга.
- Перейти от использования LLVM в качестве библиотеки к взаимодействию с Clang как с отдельным процессом (#16270).
- Завершить разработку системы сборки, в частности функций управления пакетами.
- Провести аудит стандартной библиотеки ( #1629).
Примечание переводчика:
Далее в оригинале следует список контрибьюторов и благодарности. Оригинал этого Release Notes по ссылке.