Compare commits

..

No commits in common. "master" and "0.14.0" have entirely different histories.

10783 changed files with 555222 additions and 1461381 deletions

View File

@ -1,13 +0,0 @@
contact_links:
- name: Language Proposal
about: "Please do not submit a proposal to change the language"
url: https://ziglang.org/code-of-conduct
- name: Question
about: "Please use one of the community spaces instead for questions or general discussions."
url: https://ziglang.org/community
- name: C Translation
about: "Issues related to `zig translate-c` and `@cImport` are tracked separately."
url: https://codeberg.org/ziglang/translate-c
- name: Copilot and Other LLMs
about: "Please do not use GitHub Copilot or any other LLM to write an issue."
url: https://ziglang.org/code-of-conduct

View File

@ -1,196 +0,0 @@
name: ci
on:
pull_request:
push:
branches:
- master
workflow_dispatch:
concurrency:
group: ${{ github.head_ref || github.run_id }}-${{ github.actor }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
permissions:
contents: read
jobs:
aarch64-linux-debug:
runs-on: [self-hosted, aarch64-linux]
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Build and Test
run: sh ci/aarch64-linux-debug.sh
timeout-minutes: 180
aarch64-linux-release:
runs-on: [self-hosted, aarch64-linux]
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Build and Test
run: sh ci/aarch64-linux-release.sh
timeout-minutes: 120
aarch64-macos-debug:
runs-on: [self-hosted, aarch64-macos]
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Build and Test
run: sh ci/aarch64-macos-debug.sh
timeout-minutes: 180
aarch64-macos-release:
runs-on: [self-hosted, aarch64-macos]
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Build and Test
run: sh ci/aarch64-macos-release.sh
timeout-minutes: 120
loongarch64-linux-debug:
runs-on: [self-hosted, loongarch64-linux]
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Build and Test
run: sh ci/loongarch64-linux-debug.sh
timeout-minutes: 240
loongarch64-linux-release:
runs-on: [self-hosted, loongarch64-linux]
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Build and Test
run: sh ci/loongarch64-linux-release.sh
timeout-minutes: 180
riscv64-linux-debug:
if: github.event_name != 'pull_request'
runs-on: [self-hosted, riscv64-linux]
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Build and Test
run: sh ci/riscv64-linux-debug.sh
timeout-minutes: 600
riscv64-linux-release:
if: github.event_name != 'pull_request'
runs-on: [self-hosted, riscv64-linux]
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Build and Test
run: sh ci/riscv64-linux-release.sh
timeout-minutes: 480
s390x-linux-debug:
runs-on: [self-hosted, s390x-linux]
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Build and Test
run: sh ci/s390x-linux-debug.sh
timeout-minutes: 300
s390x-linux-release:
runs-on: [self-hosted, s390x-linux]
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Build and Test
run: sh ci/s390x-linux-release.sh
timeout-minutes: 240
x86_64-freebsd-debug:
runs-on: [self-hosted, x86_64-freebsd]
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Build and Test
run: sh ci/x86_64-freebsd-debug.sh
timeout-minutes: 120
x86_64-freebsd-release:
runs-on: [self-hosted, x86_64-freebsd]
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Build and Test
run: sh ci/x86_64-freebsd-release.sh
timeout-minutes: 120
x86_64-linux-debug:
runs-on: [self-hosted, x86_64-linux]
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Build and Test
run: sh ci/x86_64-linux-debug.sh
timeout-minutes: 240
x86_64-linux-debug-llvm:
runs-on: [self-hosted, x86_64-linux]
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Build and Test
run: sh ci/x86_64-linux-debug-llvm.sh
timeout-minutes: 480
x86_64-linux-release:
runs-on: [self-hosted, x86_64-linux]
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Build and Test
run: sh ci/x86_64-linux-release.sh
timeout-minutes: 480
x86_64-windows-debug:
runs-on: [self-hosted, x86_64-windows]
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Build and Test
run: ci/x86_64-windows-debug.ps1
timeout-minutes: 180
x86_64-windows-release:
runs-on: [self-hosted, x86_64-windows]
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Build and Test
run: ci/x86_64-windows-release.ps1
timeout-minutes: 180

16
.gitattributes vendored
View File

@ -2,24 +2,14 @@
*.zon text eol=lf
*.txt text eol=lf
langref.html.in text eol=lf
lib/libc/*/abilists binary
lib/std/compress/testdata/** binary
lib/std/compress/deflate/testdata/** binary
lib/std/compress/flate/testdata/** binary
lib/std/compress/lzma/testdata/** binary
lib/std/compress/xz/testdata/** binary
lib/std/crypto/codecs/asn1/der/testdata/** binary
lib/std/tar/testdata/** binary
src/Package/Fetch/testdata/** binary
src/Package/Fetch/git/testdata/** binary
lib/compiler/aro/** linguist-vendored
lib/compiler/resinator/** linguist-vendored
lib/compiler/translate-c/** linguist-vendored
lib/include/** linguist-vendored
lib/libc/** linguist-vendored
lib/libcxx/** linguist-vendored
lib/libcxxabi/** linguist-vendored
lib/libtsan/** linguist-vendored
lib/libunwind/** linguist-vendored
lib/tsan/** linguist-vendored
lib/compiler/aro/** linguist-vendored

75
.github/CODE_OF_CONDUCT.md vendored Normal file
View File

@ -0,0 +1,75 @@
# Code of Conduct
Hello, and welcome! 👋
The Zig community is decentralized. Anyone is free to start and maintain their
own space for people to gather, and edit
[the Community wiki page](https://github.com/ziglang/zig/wiki/Community) to add
a link. There is no concept of "official" or "unofficial", however, each
gathering place has its own moderators and rules.
This is Andrew Kelley speaking. At least for now, I'm the moderator of the
ziglang organization GitHub repositories and the #zig IRC channel on Libera.chat.
**This document contains the rules that govern these two spaces only**.
The rules here are strict. This space is for focused, on topic, technical work
on the Zig project only. It is everyone's responsibility to maintain a positive
environment, especially when disagreements occur.
## Our Standards
Examples of behavior that contribute to creating a positive environment include:
* Using welcoming and inclusive language.
* Being respectful of differing viewpoints and experiences.
* Gracefully accepting constructive criticism.
* Helping another person accomplish their own goals.
* Showing empathy towards others.
* Showing appreciation for others' work.
* Validating someone else's experience, skills, insight, and use cases.
Examples of unacceptable behavior by participants include:
* Unwelcome sexual attention or advances, or use of sexualized language or
imagery that causes discomfort.
* Trolling, insulting/derogatory comments, and personal attacks. Anything
antagonistic towards someone else.
* Off-topic discussion of any kind - especially offensive or sensitive issues.
* Publishing others' private information, such as a physical or electronic
address, without explicit permission.
* Discussing this Code of Conduct or publicly accusing someone of violating it.
* Making someone else feel like an outsider or implying a lack of technical
abilities.
* Destructive behavior. Anything that harms Zig or another open-source project.
## Enforcement
If you need to report an issue you can contact me or Loris Cro, who are both
paid by the Zig Software Foundation, and so moderation of this space is part of
our job. We will swiftly remove anyone who is antagonizing others or being
generally destructive.
This includes Private Harassment. If person A is directly harassed or
antagonized by person B, person B will be blocked from participating in this
space even if the harassment didn't take place on one of the mediums directly
under rule of this Code of Conduct.
As noted, discussing this Code of Conduct should not take place on GitHub or IRC
because these spaces are for directly working on code, not for meta-discussion.
If you have any issues with it, you can contact me directly, or you can join one
of the community spaces that has different rules.
* Andrew Kelley <andrew@ziglang.org>
* Loris Cro <loris@ziglang.org>
## Conclusion
Thanks for reading the rules. Together, we can make this space welcoming and
inclusive for everyone, regardless of age, body size, disability, ethnicity,
sex characteristics, gender identity and expression, level of experience,
education, socio-economic status, nationality, personal appearance, race,
religion, or sexual identity and orientation.
Sincerely,
Andrew ✌️

3
.github/CONTRIBUTING.md vendored Normal file
View File

@ -0,0 +1,3 @@
Please see the
[Contributing](https://github.com/ziglang/zig/wiki/Contributing)
page on the wiki.

1
.github/FUNDING.yml vendored Normal file
View File

@ -0,0 +1 @@
github: [ziglang]

View File

@ -1,6 +1,6 @@
name: Bug Report
description: File a bug report
labels: ["kind/bug"]
labels: ["bug"]
body:
- type: markdown
attributes:

7
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@ -0,0 +1,7 @@
contact_links:
- name: Language Proposal
about: Propose to improve the Zig language
url: https://github.com/ziglang/zig/wiki/Language-Proposals
- name: Question
about: Please use one of the community spaces for questions or general discussions.
url: https://github.com/ziglang/zig/wiki/Community

View File

@ -1,6 +1,6 @@
name: Error message improvement
description: Compiler produces an unhelpful or misleading error message.
labels: ["kind/error message"]
labels: ["error message"]
body:
- type: input
id: version

94
.github/workflows/ci.yaml vendored Normal file
View File

@ -0,0 +1,94 @@
name: ci
on:
pull_request:
push:
branches:
- master
- llvm19
concurrency:
# Cancels pending runs when a PR gets updated.
group: ${{ github.head_ref || github.run_id }}-${{ github.actor }}
cancel-in-progress: true
permissions:
# Sets permission policy for `GITHUB_TOKEN`
contents: read
jobs:
x86_64-linux-debug:
timeout-minutes: 420
runs-on: [self-hosted, Linux, x86_64]
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Build and Test
run: sh ci/x86_64-linux-debug.sh
x86_64-linux-release:
timeout-minutes: 420
runs-on: [self-hosted, Linux, x86_64]
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Build and Test
run: sh ci/x86_64-linux-release.sh
aarch64-linux-debug:
timeout-minutes: 480
runs-on: [self-hosted, Linux, aarch64]
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Build and Test
run: sh ci/aarch64-linux-debug.sh
aarch64-linux-release:
timeout-minutes: 480
runs-on: [self-hosted, Linux, aarch64]
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Build and Test
run: sh ci/aarch64-linux-release.sh
x86_64-macos-release:
runs-on: "macos-13"
env:
ARCH: "x86_64"
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Build and Test
run: ci/x86_64-macos-release.sh
aarch64-macos-debug:
runs-on: [self-hosted, macOS, aarch64]
env:
ARCH: "aarch64"
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Build and Test
run: ci/aarch64-macos-debug.sh
aarch64-macos-release:
runs-on: [self-hosted, macOS, aarch64]
env:
ARCH: "aarch64"
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Build and Test
run: ci/aarch64-macos-release.sh
x86_64-windows-debug:
timeout-minutes: 420
runs-on: [self-hosted, Windows, x86_64]
env:
ARCH: "x86_64"
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Build and Test
run: ci/x86_64-windows-debug.ps1
x86_64-windows-release:
timeout-minutes: 420
runs-on: [self-hosted, Windows, x86_64]
env:
ARCH: "x86_64"
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Build and Test
run: ci/x86_64-windows-release.ps1

4
.gitignore vendored
View File

@ -16,3 +16,7 @@ zig-out/
/build/
/build-*/
/docgen_tmp/
# Although this was renamed to .zig-cache, let's leave it here for a few
# releases to make it less annoying to work with multiple branches.
zig-cache/

View File

@ -4,13 +4,8 @@ Andrea Orru <andrea@orru.io> <andreaorru1991@gmail.com>
Andrew Kelley <andrew@ziglang.org> <superjoe30@gmail.com>
Bogdan Romanyuk <wrongnull@gmail.com> <65823030+wrongnull@users.noreply.github.com>
Casey Banner <kcbanner@gmail.com>
Dacheng Gao <successgdc@gmail.com>
Daniel Kongsgaard <dakongsgaard@gmail.com>
David Carlier <devnexen@gmail.com>
David Rubin <david@vortan.dev>
David Rubin <david@vortan.dev> <daviru007@icloud.com>
David Rubin <david@vortan.dev> <87927264+Rexicon226@users.noreply.github.com>
David Senoner <seda18@rolmail.net>
David Rubin <daviru007@icloud.com> <87927264+Rexicon226@users.noreply.github.com>
Dominic <4678790+dweiller@users.noreply.github.com>
Dominic <4678790+dweiller@users.noreply.github.com> <4678790+dweiller@users.noreplay.github.com>
Eric Eastwood <madlittlemods@gmail.com> <contact@ericeastwood.com>
@ -31,7 +26,6 @@ Igor Anić <igor.anic@gmail.com>
IntegratedQuantum <jahe788@gmail.com> <43880493+IntegratedQuantum@users.noreply.github.com>
Isaac Freund <mail@isaacfreund.com> <ifreund@ifreund.xyz>
Isaac Freund <mail@isaacfreund.com> <isaac.freund@coil.com>
Ivan Stepanov <ivanstepanovftw@gmail.com>
Jacob Young <amazingjacob@gmail.com>
Jacob Young <amazingjacob@gmail.com> <jacobly0@users.noreply.github.com>
Jacob Young <amazingjacob@gmail.com> <15544577+jacobly0@users.noreply.github.com>
@ -44,7 +38,6 @@ Jimmi Holst Christensen <jhc@dismail.de> <jimmiholstchristensen@gmail.com>
Jimmi Holst Christensen <jhc@dismail.de> <rainbowhejsil@gmail.com>
Joachim Schmidt <joachim.schmidt557@outlook.com>
Jonathan Marler <johnnymarler@gmail.com> <jonathan.j.marler@hp.com>
Kendall Condon <goon.pri.low@gmail.com> <149842806+gooncreeper@users.noreply.github.com>
Krzysztof Wolicki <der.teufel.mail@gmail.com>
Krzysztof Wolicki <der.teufel.mail@gmail.com> <46651553+der-teufel-programming@users.noreply.github.com>
LemonBoy <thatlemon@gmail.com> <LemonBoy@users.noreply.github.com>
@ -76,7 +69,6 @@ Travis Staloch <twostepted@gmail.com>
Travis Staloch <twostepted@gmail.com> <1562827+travisstaloch@users.noreply.github.com>
Veikka Tuominen <git@vexu.eu>
Veikka Tuominen <git@vexu.eu> <15308111+Vexu@users.noreply.github.com>
Veikka Tuominen <git@vexu.eu> <veikka@ziglang.org>
Will Lillis <will.lillis24@gmail.com>
Will Lillis <will.lillis24@gmail.com> <wlillis@umass.edu>
Wooster <r00ster91@proton.me>

View File

@ -38,7 +38,7 @@ project(zig
)
set(ZIG_VERSION_MAJOR 0)
set(ZIG_VERSION_MINOR 16)
set(ZIG_VERSION_MINOR 14)
set(ZIG_VERSION_PATCH 0)
set(ZIG_VERSION "" CACHE STRING "Override Zig version string. Default is to find out with git.")
@ -90,7 +90,6 @@ set(ZIG_STATIC_LLVM ${ZIG_STATIC} CACHE BOOL "Prefer linking against static LLVM
set(ZIG_STATIC_ZLIB ${ZIG_STATIC} CACHE BOOL "Prefer linking against static zlib")
set(ZIG_STATIC_ZSTD ${ZIG_STATIC} CACHE BOOL "Prefer linking against static zstd")
set(ZIG_STATIC_CURSES OFF CACHE BOOL "Enable static linking against curses")
set(ZIG_STATIC_LIBXML2 OFF CACHE BOOL "Enable static linking against libxml2")
if (ZIG_SHARED_LLVM AND ZIG_STATIC_LLVM)
message(SEND_ERROR "-DZIG_SHARED_LLVM and -DZIG_STATIC_LLVM cannot both be enabled simultaneously")
@ -133,9 +132,9 @@ else()
set(ZIG_SYSTEM_LIBCXX "stdc++" CACHE STRING "system libcxx name for build.zig")
endif()
find_package(llvm 21)
find_package(clang 21)
find_package(lld 21)
find_package(llvm 19)
find_package(clang 19)
find_package(lld 19)
if(ZIG_STATIC_ZLIB)
if (MSVC)
@ -159,16 +158,6 @@ if(ZIG_STATIC_ZSTD)
list(APPEND LLVM_LIBRARIES "${ZSTD}")
endif()
if (MSVC)
if(NOT DEFINED CMAKE_MSVC_RUNTIME_LIBRARY)
if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
# avoid linking to the debug versions of ucrt by default
# as they are not redistributable.
set(CMAKE_MSVC_RUNTIME_LIBRARY MultiThreadedDLL)
endif()
endif()
endif ()
if(ZIG_STATIC_CURSES)
list(REMOVE_ITEM LLVM_LIBRARIES "-lcurses")
find_library(CURSES NAMES libcurses.a libncurses.a NAMES_PER_DIR
@ -178,12 +167,6 @@ if(ZIG_STATIC_CURSES)
list(APPEND LLVM_LIBRARIES "${CURSES}")
endif()
if(ZIG_STATIC_LIBXML2)
list(REMOVE_ITEM LLVM_LIBRARIES "-lxml2")
find_library(LIBXML2 NAMES libxml2.a NAMES_PER_DIR)
list(APPEND LLVM_LIBRARIES "${LIBXML2}")
endif()
find_package(Threads)
set(ZIG_CONFIG_H_OUT "${PROJECT_BINARY_DIR}/config.h")
@ -197,6 +180,7 @@ set(ZIG_CPP_SOURCES
# These are planned to stay even when we are self-hosted.
src/zig_llvm.cpp
src/zig_llvm-ar.cpp
src/zig_clang.cpp
src/zig_clang_driver.cpp
src/zig_clang_cc1_main.cpp
src/zig_clang_cc1as_main.cpp
@ -211,10 +195,9 @@ set(ZIG_STAGE2_SOURCES
lib/compiler_rt/absvti2.zig
lib/compiler_rt/adddf3.zig
lib/compiler_rt/addf3.zig
lib/compiler_rt/addo.zig
lib/compiler_rt/addsf3.zig
lib/compiler_rt/addtf3.zig
lib/compiler_rt/addvsi3.zig
lib/compiler_rt/addvdi3.zig
lib/compiler_rt/addxf3.zig
lib/compiler_rt/arm.zig
lib/compiler_rt/atomics.zig
@ -333,7 +316,6 @@ set(ZIG_STAGE2_SOURCES
lib/compiler_rt/mulo.zig
lib/compiler_rt/mulsf3.zig
lib/compiler_rt/multf3.zig
lib/compiler_rt/mulvsi3.zig
lib/compiler_rt/mulxf3.zig
lib/compiler_rt/negXi2.zig
lib/compiler_rt/negdf2.zig
@ -354,10 +336,9 @@ set(ZIG_STAGE2_SOURCES
lib/compiler_rt/sqrt.zig
lib/compiler_rt/stack_probe.zig
lib/compiler_rt/subdf3.zig
lib/compiler_rt/subo.zig
lib/compiler_rt/subsf3.zig
lib/compiler_rt/subtf3.zig
lib/compiler_rt/subvdi3.zig
lib/compiler_rt/subvsi3.zig
lib/compiler_rt/subxf3.zig
lib/compiler_rt/tan.zig
lib/compiler_rt/trig.zig
@ -385,9 +366,6 @@ set(ZIG_STAGE2_SOURCES
lib/std/Build.zig
lib/std/Build/Cache.zig
lib/std/Build/Cache/DepTokenizer.zig
lib/std/Io.zig
lib/std/Io/Reader.zig
lib/std/Io/Writer.zig
lib/std/Progress.zig
lib/std/Random.zig
lib/std/Target.zig
@ -412,6 +390,7 @@ set(ZIG_STAGE2_SOURCES
lib/std/Thread/Futex.zig
lib/std/Thread/Mutex.zig
lib/std/Thread/Pool.zig
lib/std/Thread/ResetEvent.zig
lib/std/Thread/WaitGroup.zig
lib/std/array_hash_map.zig
lib/std/array_list.zig
@ -434,7 +413,9 @@ set(ZIG_STAGE2_SOURCES
lib/std/dwarf/OP.zig
lib/std/dwarf/TAG.zig
lib/std/elf.zig
lib/std/fifo.zig
lib/std/fmt.zig
lib/std/fmt/format_float.zig
lib/std/fmt/parse_float.zig
lib/std/fs.zig
lib/std/fs/AtomicFile.zig
@ -448,8 +429,22 @@ set(ZIG_STAGE2_SOURCES
lib/std/hash_map.zig
lib/std/heap.zig
lib/std/heap/arena_allocator.zig
lib/std/io.zig
lib/std/io/Reader.zig
lib/std/io/Writer.zig
lib/std/io/buffered_atomic_file.zig
lib/std/io/buffered_writer.zig
lib/std/io/change_detection_stream.zig
lib/std/io/counting_reader.zig
lib/std/io/counting_writer.zig
lib/std/io/find_byte_writer.zig
lib/std/io/fixed_buffer_stream.zig
lib/std/io/limited_reader.zig
lib/std/io/seekable_stream.zig
lib/std/json.zig
lib/std/json/stringify.zig
lib/std/leb128.zig
lib/std/linked_list.zig
lib/std/log.zig
lib/std/macho.zig
lib/std/math.zig
@ -491,7 +486,6 @@ set(ZIG_STAGE2_SOURCES
lib/std/unicode.zig
lib/std/zig.zig
lib/std/zig/Ast.zig
lib/std/zig/Ast/Render.zig
lib/std/zig/AstGen.zig
lib/std/zig/AstRlAnnotate.zig
lib/std/zig/LibCInstallation.zig
@ -499,6 +493,8 @@ set(ZIG_STAGE2_SOURCES
lib/std/zig/Server.zig
lib/std/zig/WindowsSdk.zig
lib/std/zig/Zir.zig
lib/std/zig/c_builtins.zig
lib/std/zig/render.zig
lib/std/zig/string_literal.zig
lib/std/zig/system.zig
lib/std/zig/system/NativePaths.zig
@ -510,16 +506,13 @@ set(ZIG_STAGE2_SOURCES
lib/std/zig/llvm/bitcode_writer.zig
lib/std/zig/llvm/ir.zig
src/Air.zig
src/Air/Legalize.zig
src/Air/Liveness.zig
src/Air/Liveness/Verify.zig
src/Air/print.zig
src/Air/types_resolved.zig
src/Builtin.zig
src/Compilation.zig
src/Compilation/Config.zig
src/DarwinPosixSpawn.zig
src/InternPool.zig
src/Liveness.zig
src/Liveness/Verify.zig
src/Package.zig
src/Package/Fetch.zig
src/Package/Fetch/git.zig
@ -529,34 +522,69 @@ set(ZIG_STAGE2_SOURCES
src/Sema.zig
src/Sema/bitcast.zig
src/Sema/comptime_ptr_access.zig
src/ThreadSafeQueue.zig
src/Type.zig
src/Value.zig
src/Zcu.zig
src/Zcu/PerThread.zig
src/arch/aarch64/CodeGen.zig
src/arch/aarch64/Emit.zig
src/arch/aarch64/Mir.zig
src/arch/aarch64/abi.zig
src/arch/aarch64/bits.zig
src/arch/arm/CodeGen.zig
src/arch/arm/Emit.zig
src/arch/arm/Mir.zig
src/arch/arm/abi.zig
src/arch/arm/bits.zig
src/arch/riscv64/abi.zig
src/arch/riscv64/bits.zig
src/arch/riscv64/CodeGen.zig
src/arch/riscv64/Emit.zig
src/arch/riscv64/encoding.zig
src/arch/riscv64/Lower.zig
src/arch/riscv64/Mir.zig
src/arch/riscv64/mnem.zig
src/arch/sparc64/CodeGen.zig
src/arch/sparc64/Emit.zig
src/arch/sparc64/Mir.zig
src/arch/sparc64/abi.zig
src/arch/sparc64/bits.zig
src/arch/wasm/CodeGen.zig
src/arch/wasm/Emit.zig
src/arch/wasm/Mir.zig
src/arch/wasm/abi.zig
src/arch/x86/bits.zig
src/arch/x86_64/CodeGen.zig
src/arch/x86_64/Disassembler.zig
src/arch/x86_64/Emit.zig
src/arch/x86_64/Encoding.zig
src/arch/x86_64/Lower.zig
src/arch/x86_64/Mir.zig
src/arch/x86_64/abi.zig
src/arch/x86_64/bits.zig
src/arch/x86_64/encoder.zig
src/arch/x86_64/encodings.zon
src/clang.zig
src/clang_options.zig
src/clang_options_data.zig
src/codegen.zig
src/codegen/aarch64.zig
src/codegen/aarch64/abi.zig
src/codegen/aarch64/Assemble.zig
src/codegen/aarch64/Disassemble.zig
src/codegen/aarch64/encoding.zig
src/codegen/aarch64/instructions.zon
src/codegen/aarch64/Mir.zig
src/codegen/aarch64/Select.zig
src/codegen/c.zig
src/codegen/c/Type.zig
src/codegen/llvm.zig
src/codegen/llvm/bindings.zig
src/codegen/spirv.zig
src/codegen/spirv/Assembler.zig
src/codegen/spirv/Module.zig
src/codegen/spirv/Section.zig
src/codegen/spirv/spec.zig
src/crash_report.zig
src/dev.zig
src/libs/freebsd.zig
src/libs/glibc.zig
src/libs/netbsd.zig
src/glibc.zig
src/introspect.zig
src/libs/libcxx.zig
src/libs/libtsan.zig
src/libs/libunwind.zig
src/libcxx.zig
src/libtsan.zig
src/libunwind.zig
src/link.zig
src/link/C.zig
src/link/Coff.zig
@ -578,9 +606,7 @@ set(ZIG_STAGE2_SOURCES
src/link/Elf/relocatable.zig
src/link/Elf/relocation.zig
src/link/Elf/synthetic_sections.zig
src/link/Elf2.zig
src/link/LdScript.zig
src/link/Lld.zig
src/link/MachO.zig
src/link/MachO/Archive.zig
src/link/MachO/Atom.zig
@ -607,8 +633,14 @@ set(ZIG_STAGE2_SOURCES
src/link/MachO/synthetic.zig
src/link/MachO/Thunk.zig
src/link/MachO/uuid.zig
src/link/MappedFile.zig
src/link/Queue.zig
src/link/NvPtx.zig
src/link/Plan9.zig
src/link/Plan9/aout.zig
src/link/SpirV.zig
src/link/SpirV/BinaryModule.zig
src/link/SpirV/deduplicate.zig
src/link/SpirV/lower_invocation_globals.zig
src/link/SpirV/prune_unused.zig
src/link/StringTable.zig
src/link/Wasm.zig
src/link/Wasm/Archive.zig
@ -624,9 +656,10 @@ set(ZIG_STAGE2_SOURCES
src/link/tapi/yaml.zig
src/link/tapi/yaml/test.zig
src/main.zig
src/libs/mingw.zig
src/libs/musl.zig
src/mingw.zig
src/musl.zig
src/mutable_value.zig
src/print_air.zig
src/print_env.zig
src/print_targets.zig
src/print_value.zig
@ -634,7 +667,8 @@ set(ZIG_STAGE2_SOURCES
src/register_manager.zig
src/target.zig
src/tracy.zig
src/libs/wasi_libc.zig
src/translate_c.zig
src/wasi_libc.zig
)
if(MSVC)
@ -643,12 +677,6 @@ if(MSVC)
set(ZIG_DIA_GUIDS_LIB "${MSVC_DIA_SDK_DIR}/lib/amd64/diaguids.lib")
string(REGEX REPLACE "\\\\" "\\\\\\\\" ZIG_DIA_GUIDS_LIB_ESCAPED "${ZIG_DIA_GUIDS_LIB}")
endif()
# The /RTC[c][s][u] flag enables extra runtime checks. ("/RTC1" == "/RTCsu")
# The "c" (PossibleDataLoss) and "u" (UninitializeVariable) flags trap on valid C code so we disable
# them. The "s" flag seems like it might be OK.
string(REPLACE "/RTC1" "/RTCs" CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}")
string(REPLACE "/RTC1" "/RTCs" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}")
endif()
configure_file (
@ -671,13 +699,6 @@ add_library(zigcpp STATIC ${ZIG_CPP_SOURCES})
target_compile_features(zigcpp PRIVATE cxx_std_17)
set_target_properties(zigcpp PROPERTIES POSITION_INDEPENDENT_CODE ${ZIG_PIE})
if(LLVM_LINK_MODE STREQUAL "static")
target_compile_definitions(zigcpp PRIVATE
LLVM_BUILD_STATIC
CLANG_BUILD_STATIC
)
endif()
if(NOT MSVC)
if(MINGW)
target_compile_options(zigcpp PRIVATE -Wno-format)
@ -731,22 +752,20 @@ endforeach()
include(CheckSymbolExists)
string(TOLOWER "${CMAKE_HOST_SYSTEM_NAME}" ZIG_HOST_TARGET_OS)
if(ZIG_HOST_TARGET_OS STREQUAL "android")
set(ZIG_HOST_TARGET_OS "linux")
set(ZIG_HOST_TARGET_IS_ANDROID TRUE)
elseif(ZIG_HOST_TARGET_OS STREQUAL "darwin")
if(ZIG_HOST_TARGET_OS STREQUAL "darwin")
set(ZIG_HOST_TARGET_OS "macos")
elseif(ZIG_HOST_TARGET_OS STREQUAL "gnu")
set(ZIG_HOST_TARGET_OS "hurd")
elseif(ZIG_HOST_TARGET_OS STREQUAL "serenityos")
set(ZIG_HOST_TARGET_OS "serenity")
elseif(ZIG_HOST_TARGET_OS STREQUAL "sunos")
check_symbol_exists(__illumos__ "" ZIG_HOST_TARGET_HAS_ILLUMOS_MACRO)
if (ZIG_HOST_TARGET_HAS_ILLUMOS_MACRO)
set(ZIG_HOST_TARGET_OS "illumos")
else()
set(ZIG_HOST_TARGET_OS "solaris")
endif()
endif()
string(TOLOWER "${CMAKE_HOST_SYSTEM_PROCESSOR}" ZIG_HOST_TARGET_ARCH)
if(ZIG_HOST_TARGET_ARCH MATCHES "^i[3-9]86$")
if (ZIG_HOST_TARGET_OS STREQUAL "illumos")
if (ZIG_HOST_TARGET_OS MATCHES "(solaris|illumos)")
set(ZIG_HOST_TARGET_ARCH "x86_64")
else()
set(ZIG_HOST_TARGET_ARCH "x86")
@ -755,12 +774,13 @@ elseif(ZIG_HOST_TARGET_ARCH STREQUAL "amd64")
set(ZIG_HOST_TARGET_ARCH "x86_64")
elseif(ZIG_HOST_TARGET_ARCH STREQUAL "arm64")
set(ZIG_HOST_TARGET_ARCH "aarch64")
elseif(ZIG_HOST_TARGET_ARCH MATCHES "^arm(el)?$" OR ZIG_HOST_TARGET_ARCH MATCHES "^armv[7-8]l$")
elseif(ZIG_HOST_TARGET_ARCH STREQUAL "armv7l")
set(ZIG_HOST_TARGET_ARCH "arm")
elseif(ZIG_HOST_TARGET_ARCH STREQUAL "armeb" OR ZIG_HOST_TARGET_ARCH MATCHES "^armv[7-8]b$")
elseif(ZIG_HOST_TARGET_ARCH STREQUAL "armv7b")
set(ZIG_HOST_TARGET_ARCH "armeb")
endif()
if(ZIG_HOST_TARGET_ARCH MATCHES "^arm(eb)?$")
string(REGEX REPLACE "^((arm|thumb)(hf?)?)el$" "\\1" ZIG_HOST_TARGET_ARCH "${ZIG_HOST_TARGET_ARCH}")
if(ZIG_HOST_TARGET_ARCH MATCHES "^arm(hf?)?(eb)?$")
check_symbol_exists(__thumb__ "" ZIG_HOST_TARGET_DEFAULTS_TO_THUMB)
if(ZIG_HOST_TARGET_DEFAULTS_TO_THUMB)
string(REGEX REPLACE "^arm" "thumb" ZIG_HOST_TARGET_ARCH "${ZIG_HOST_TARGET_ARCH}")
@ -768,17 +788,15 @@ if(ZIG_HOST_TARGET_ARCH MATCHES "^arm(eb)?$")
endif()
string(REGEX REPLACE "^ppc((64)?(le)?)$" "powerpc\\1" ZIG_HOST_TARGET_ARCH "${ZIG_HOST_TARGET_ARCH}")
set(ZIG_HOST_TARGET_ABI "")
if(MSVC)
set(ZIG_HOST_TARGET_ABI "-msvc")
elseif(MINGW)
set(ZIG_HOST_TARGET_ABI "-gnu")
elseif(ZIG_HOST_TARGET_IS_ANDROID)
if(ZIG_HOST_TARGET_ARCH STREQUAL "arm")
set(ZIG_HOST_TARGET_ABI "-androideabi")
else()
set(ZIG_HOST_TARGET_ABI "-android")
endif()
elseif(ZIG_HOST_TARGET_ARCH MATCHES "^(arm|thumb)hf?(eb)?$")
string(REGEX REPLACE "^(arm|thumb)hf?((eb)?)$" "\\1\\2" ZIG_HOST_TARGET_ARCH "${ZIG_HOST_TARGET_ARCH}")
set(ZIG_HOST_TARGET_ABI "-eabihf")
else()
set(ZIG_HOST_TARGET_ABI "")
endif()
set(ZIG_HOST_TARGET_TRIPLE "${ZIG_HOST_TARGET_ARCH}-${ZIG_HOST_TARGET_OS}${ZIG_HOST_TARGET_ABI}" CACHE STRING "Host zig target triple.")
@ -791,7 +809,7 @@ if(MSVC)
else()
set(ZIG_WASM2C_COMPILE_FLAGS "-std=c99 -O2")
set(ZIG1_COMPILE_FLAGS "-std=c99 -Os")
set(ZIG2_COMPILE_FLAGS "-std=c99 -O0 -fno-sanitize=undefined -fno-stack-protector")
set(ZIG2_COMPILE_FLAGS "-std=c99 -O0 -fno-stack-protector")
if(APPLE)
set(ZIG2_LINK_FLAGS "-Wl,-stack_size,0x10000000")
elseif(MINGW)
@ -920,24 +938,12 @@ if(ZIG_EXTRA_BUILD_ARGS)
list(APPEND ZIG_BUILD_ARGS ${ZIG_EXTRA_BUILD_ARGS})
endif()
set(ZIG_RELEASE_SAFE OFF CACHE BOOL "Build Zig as ReleaseSafe (with debug assertions on)")
if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
list(APPEND ZIG_BUILD_ARGS -Doptimize=Debug)
else()
if("${CMAKE_BUILD_TYPE}" STREQUAL "MinSizeRel")
list(APPEND ZIG_BUILD_ARGS -Doptimize=ReleaseSmall)
else()
# Release and RelWithDebInfo
if(ZIG_RELEASE_SAFE)
list(APPEND ZIG_BUILD_ARGS -Doptimize=ReleaseSafe)
else()
elseif("${CMAKE_BUILD_TYPE}" STREQUAL "RelWithDebInfo")
list(APPEND ZIG_BUILD_ARGS -Doptimize=ReleaseFast)
endif()
if(NOT "${CMAKE_BUILD_TYPE}" STREQUAL "RelWithDebInfo")
list(APPEND ZIG_BUILD_ARGS -Dstrip)
endif()
endif()
else()
list(APPEND ZIG_BUILD_ARGS -Doptimize=ReleaseFast -Dstrip)
endif()
if(ZIG_STATIC AND NOT MSVC)
@ -960,6 +966,10 @@ if(NOT "${ZIG_TARGET_DYNAMIC_LINKER}" STREQUAL "")
list(APPEND ZIG_BUILD_ARGS "-Ddynamic-linker=${ZIG_TARGET_DYNAMIC_LINKER}")
endif()
if(MINGW AND "${ZIG_HOST_TARGET_ARCH}" STREQUAL "x86")
list(APPEND ZIG_BUILD_ARGS --maxrss 7000000000)
endif()
add_custom_target(stage3 ALL
DEPENDS "${PROJECT_BINARY_DIR}/stage3/bin/zig"

148
README.md
View File

@ -1,3 +1,147 @@
[Moved to Codeberg](https://ziglang.org/news/migrating-from-github-to-codeberg/)
![ZIG](https://ziglang.org/img/zig-logo-dynamic.svg)
**This repository is not mirrored.**
A general-purpose programming language and toolchain for maintaining
**robust**, **optimal**, and **reusable** software.
https://ziglang.org/
## Documentation
If you are looking at this README file in a source tree, please refer to the
**Release Notes**, **Language Reference**, or **Standard Library
Documentation** corresponding to the version of Zig that you are using by
following the appropriate link on the
[download page](https://ziglang.org/download).
Otherwise, you're looking at a release of Zig, so you can find the language
reference at `doc/langref.html`, and the standard library documentation by
running `zig std`, which will open a browser tab.
## Installation
* [download a pre-built binary](https://ziglang.org/download/)
* [install from a package manager](https://github.com/ziglang/zig/wiki/Install-Zig-from-a-Package-Manager)
* [bootstrap zig for any target](https://github.com/ziglang/zig-bootstrap)
A Zig installation is composed of two things:
1. The Zig executable
2. The lib/ directory
At runtime, the executable searches up the file system for the lib/ directory,
relative to itself:
* lib/
* lib/zig/
* ../lib/
* ../lib/zig/
* (and so on)
In other words, you can **unpack a release of Zig anywhere**, and then begin
using it immediately. There is no need to install it globally, although this
mechanism supports that use case too (i.e. `/usr/bin/zig` and `/usr/lib/zig/`).
## Building from Source
Ensure you have the required dependencies:
* CMake >= 3.15
* System C/C++ Toolchain
* LLVM, Clang, LLD development libraries == 19.x
Then it is the standard CMake build process:
```
mkdir build
cd build
cmake ..
make install
```
For more options, tips, and troubleshooting, please see the
[Building Zig From Source](https://github.com/ziglang/zig/wiki/Building-Zig-From-Source)
page on the wiki.
## Building from Source without LLVM
In this case, the only system dependency is a C compiler.
```
cc -o bootstrap bootstrap.c
./bootstrap
```
This produces a `zig2` executable in the current working directory. This is a
"stage2" build of the compiler,
[without LLVM extensions](https://github.com/ziglang/zig/issues/16270), and is
therefore lacking these features:
- Release mode optimizations
- [aarch64 machine code backend](https://github.com/ziglang/zig/issues/21172)
- [@cImport](https://github.com/ziglang/zig/issues/20630)
- [zig translate-c](https://github.com/ziglang/zig/issues/20875)
- [Ability to compile assembly files](https://github.com/ziglang/zig/issues/21169)
- [Some ELF linking features](https://github.com/ziglang/zig/issues/17749)
- [Most COFF/PE linking features](https://github.com/ziglang/zig/issues/17751)
- [Some WebAssembly linking features](https://github.com/ziglang/zig/issues/17750)
- [Ability to create import libs from def files](https://github.com/ziglang/zig/issues/17807)
- [Ability to create static archives from object files](https://github.com/ziglang/zig/issues/9828)
- Ability to compile C, C++, Objective-C, and Objective-C++ files
However, a compiler built this way does provide a C backend, which may be
useful for creating system packages of Zig projects using the system C
toolchain. **In this case, LLVM is not needed!**
Furthermore, a compiler built this way provides an LLVM backend that produces
bitcode files, which may be compiled into object files via a system Clang
package. This can be used to produce system packages of Zig applications
without the Zig package dependency on LLVM.
## Contributing
[Donate monthly](https://ziglang.org/zsf/).
Zig is Free and Open Source Software. We welcome bug reports and patches from
everyone. However, keep in mind that Zig governance is BDFN (Benevolent
Dictator For Now) which means that Andrew Kelley has final say on the design
and implementation of everything.
One of the best ways you can contribute to Zig is to start using it for an
open-source personal project.
This leads to discovering bugs and helps flesh out use cases, which lead to
further design iterations of Zig. Importantly, each issue found this way comes
with real world motivations, making it straightforward to explain the reasoning
behind proposals and feature requests.
You will be taken much more seriously on the issue tracker if you have a
personal project that uses Zig.
The issue label
[Contributor Friendly](https://github.com/ziglang/zig/issues?q=is%3Aissue+is%3Aopen+label%3A%22contributor+friendly%22)
exists to help you find issues that are **limited in scope and/or knowledge of
Zig internals.**
Please note that issues labeled
[Proposal](https://github.com/ziglang/zig/issues?q=is%3Aissue+is%3Aopen+label%3Aproposal)
but do not also have the
[Accepted](https://github.com/ziglang/zig/issues?q=is%3Aissue+is%3Aopen+label%3Aaccepted)
label are still under consideration, and efforts to implement such a proposal
have a high risk of being wasted. If you are interested in a proposal which is
still under consideration, please express your interest in the issue tracker,
providing extra insights and considerations that others have not yet expressed.
The most highly regarded argument in such a discussion is a real world use case.
For more tips, please see the
[Contributing](https://github.com/ziglang/zig/wiki/Contributing) page on the
wiki.
## Community
The Zig community is decentralized. Anyone is free to start and maintain their
own space for Zig users to gather. There is no concept of "official" or
"unofficial". Each gathering place has its own moderators and rules. Users are
encouraged to be aware of the social structures of the spaces they inhabit, and
work purposefully to facilitate spaces that align with their values.
Please see the [Community](https://github.com/ziglang/zig/wiki/Community) wiki
page for a public listing of social spaces.

View File

@ -64,8 +64,6 @@ static const char *get_host_os(void) {
return "linux";
#elif defined(__FreeBSD__)
return "freebsd";
#elif defined(__DragonFly__)
return "dragonfly";
#elif defined(__HAIKU__)
return "haiku";
#else

331
build.zig
View File

@ -3,6 +3,7 @@ const builtin = std.builtin;
const tests = @import("test/tests.zig");
const BufMap = std.BufMap;
const mem = std.mem;
const ArrayList = std.ArrayList;
const io = std.io;
const fs = std.fs;
const InstallDirectoryOptions = std.Build.InstallDirectoryOptions;
@ -10,7 +11,7 @@ const assert = std.debug.assert;
const DevEnv = @import("src/dev.zig").Env;
const ValueInterpretMode = enum { direct, by_name };
const zig_version: std.SemanticVersion = .{ .major = 0, .minor = 16, .patch = 0 };
const zig_version: std.SemanticVersion = .{ .major = 0, .minor = 14, .patch = 0 };
const stack_size = 46 * 1024 * 1024;
pub fn build(b: *std.Build) !void {
@ -81,23 +82,16 @@ pub fn build(b: *std.Build) !void {
docs_step.dependOn(langref_step);
docs_step.dependOn(std_docs_step);
const no_matrix = b.option(bool, "no-matrix", "Limit test matrix to exactly one target configuration") orelse false;
const skip_debug = b.option(bool, "skip-debug", "Main test suite skips debug builds") orelse false;
const skip_release = b.option(bool, "skip-release", "Main test suite skips release builds") orelse no_matrix;
const skip_release = b.option(bool, "skip-release", "Main test suite skips release builds") orelse false;
const skip_release_small = b.option(bool, "skip-release-small", "Main test suite skips release-small builds") orelse skip_release;
const skip_release_fast = b.option(bool, "skip-release-fast", "Main test suite skips release-fast builds") orelse skip_release;
const skip_release_safe = b.option(bool, "skip-release-safe", "Main test suite skips release-safe builds") orelse skip_release;
const skip_non_native = b.option(bool, "skip-non-native", "Main test suite skips non-native builds") orelse no_matrix;
const skip_non_native = b.option(bool, "skip-non-native", "Main test suite skips non-native builds") orelse false;
const skip_libc = b.option(bool, "skip-libc", "Main test suite skips tests that link libc") orelse false;
const skip_single_threaded = b.option(bool, "skip-single-threaded", "Main test suite skips tests that are single-threaded") orelse false;
const skip_compile_errors = b.option(bool, "skip-compile-errors", "Main test suite skips compile error tests") orelse false;
const skip_freebsd = b.option(bool, "skip-freebsd", "Main test suite skips targets with freebsd OS") orelse false;
const skip_netbsd = b.option(bool, "skip-netbsd", "Main test suite skips targets with netbsd OS") orelse false;
const skip_windows = b.option(bool, "skip-windows", "Main test suite skips targets with windows OS") orelse false;
const skip_darwin = b.option(bool, "skip-darwin", "Main test suite skips targets with darwin OSs") orelse false;
const skip_linux = b.option(bool, "skip-linux", "Main test suite skips targets with linux OS") orelse false;
const skip_llvm = b.option(bool, "skip-llvm", "Main test suite skips targets that use LLVM backend") orelse false;
const skip_test_incremental = b.option(bool, "skip-test-incremental", "Main test step omits dependency on test-incremental step") orelse false;
const skip_translate_c = b.option(bool, "skip-translate-c", "Main test suite skips translate-c tests") orelse false;
const skip_run_translated_c = b.option(bool, "skip-run-translated-c", "Main test suite skips run-translated-c tests") orelse false;
const only_install_lib_files = b.option(bool, "lib-files-only", "Only install library files") orelse false;
@ -202,11 +196,12 @@ pub fn build(b: *std.Build) !void {
});
exe.pie = pie;
exe.entitlements = entitlements;
exe.use_new_linker = b.option(bool, "new-linker", "Use the new linker");
const use_llvm = b.option(bool, "use-llvm", "Use the llvm backend");
exe.use_llvm = use_llvm;
exe.use_lld = use_llvm;
exe.build_id = b.option(
std.zig.BuildId,
"build-id",
"Request creation of '.note.gnu.build-id' section",
);
if (no_bin) {
b.getInstallStep().dependOn(&exe.step);
@ -219,6 +214,15 @@ pub fn build(b: *std.Build) !void {
test_step.dependOn(&exe.step);
if (target.result.os.tag == .windows and target.result.abi == .gnu) {
// LTO is currently broken on mingw, this can be removed when it's fixed.
exe.want_lto = false;
}
const use_llvm = b.option(bool, "use-llvm", "Use the llvm backend");
exe.use_llvm = use_llvm;
exe.use_lld = use_llvm;
const exe_options = b.addOptions();
exe.root_module.addOptions("build_options", exe_options);
@ -253,16 +257,19 @@ pub fn build(b: *std.Build) !void {
var code: u8 = undefined;
const git_describe_untrimmed = b.runAllowFail(&[_][]const u8{
"git",
"-C", b.build_root.path orelse ".", // affects the --git-dir argument
"--git-dir", ".git", // affected by the -C argument
"describe", "--match", "*.*.*", //
"--tags", "--abbrev=9",
"-C",
b.build_root.path orelse ".",
"describe",
"--match",
"*.*.*",
"--tags",
"--abbrev=9",
}, &code, .Ignore) catch {
break :v version_string;
};
const git_describe = mem.trim(u8, git_describe_untrimmed, " \n\r");
switch (mem.countScalar(u8, git_describe, '-')) {
switch (mem.count(u8, git_describe, "-")) {
0 => {
// Tagged release version (e.g. 0.10.0).
if (!mem.eql(u8, git_describe, version_string)) {
@ -280,7 +287,7 @@ pub fn build(b: *std.Build) !void {
const ancestor_ver = try std.SemanticVersion.parse(tagged_ancestor);
if (zig_version.order(ancestor_ver) != .gt) {
std.debug.print("Zig version '{f}' must be greater than tagged ancestor '{f}'\n", .{ zig_version, ancestor_ver });
std.debug.print("Zig version '{}' must be greater than tagged ancestor '{}'\n", .{ zig_version, ancestor_ver });
std.process.exit(1);
}
@ -305,7 +312,7 @@ pub fn build(b: *std.Build) !void {
if (enable_llvm) {
const cmake_cfg = if (static_llvm) null else blk: {
if (findConfigH(b, config_h_path_option)) |config_h_path| {
const file_contents = fs.cwd().readFileAlloc(config_h_path, b.allocator, .limited(max_config_h_bytes)) catch unreachable;
const file_contents = fs.cwd().readFileAlloc(b.allocator, config_h_path, max_config_h_bytes) catch unreachable;
break :blk parseConfigH(b, file_contents);
} else {
std.log.warn("config.h could not be located automatically. Consider providing it explicitly via \"-Dconfig_h\"", .{});
@ -327,12 +334,7 @@ pub fn build(b: *std.Build) !void {
try addCmakeCfgOptionsToExe(b, cfg, exe, use_zig_libcxx);
} else {
// Here we are -Denable-llvm but no cmake integration.
try addStaticLlvmOptionsToModule(exe.root_module, .{
.llvm_has_m68k = llvm_has_m68k,
.llvm_has_csky = llvm_has_csky,
.llvm_has_arc = llvm_has_arc,
.llvm_has_xtensa = llvm_has_xtensa,
});
try addStaticLlvmOptionsToModule(exe.root_module);
}
if (target.result.os.tag == .windows) {
// LLVM depends on networking as of version 18.
@ -360,7 +362,11 @@ pub fn build(b: *std.Build) !void {
&[_][]const u8{ tracy_path, "public", "TracyClient.cpp" },
);
const tracy_c_flags: []const []const u8 = &.{ "-DTRACY_ENABLE=1", "-fno-sanitize=undefined" };
// On mingw, we need to opt into windows 7+ to get some features required by tracy.
const tracy_c_flags: []const []const u8 = if (target.result.os.tag == .windows and target.result.abi == .gnu)
&[_][]const u8{ "-DTRACY_ENABLE=1", "-fno-sanitize=undefined", "-D_WIN32_WINNT=0x601" }
else
&[_][]const u8{ "-DTRACY_ENABLE=1", "-fno-sanitize=undefined" };
exe.root_module.addIncludePath(.{ .cwd_relative = tracy_path });
exe.root_module.addCSourceFile(.{ .file = .{ .cwd_relative = client_cpp }, .flags = tracy_c_flags });
@ -377,7 +383,7 @@ pub fn build(b: *std.Build) !void {
const test_filters = b.option([]const []const u8, "test-filter", "Skip tests that do not match any filter") orelse &[0][]const u8{};
const test_target_filters = b.option([]const []const u8, "test-target-filter", "Skip tests whose target triple do not match any filter") orelse &[0][]const u8{};
const test_extra_targets = b.option(bool, "test-extra-targets", "Enable running module tests for additional targets") orelse false;
const test_slow_targets = b.option(bool, "test-slow-targets", "Enable running module tests for targets that have a slow compiler backend") orelse false;
var chosen_opt_modes_buf: [4]builtin.OptimizeMode = undefined;
var chosen_mode_index: usize = 0;
@ -416,18 +422,9 @@ pub fn build(b: *std.Build) !void {
test_step.dependOn(check_fmt);
const test_cases_step = b.step("test-cases", "Run the main compiler test cases");
try tests.addCases(b, test_cases_step, .{
.test_filters = test_filters,
.test_target_filters = test_target_filters,
.skip_compile_errors = skip_compile_errors,
.skip_non_native = skip_non_native,
.skip_freebsd = skip_freebsd,
.skip_netbsd = skip_netbsd,
.skip_windows = skip_windows,
.skip_darwin = skip_darwin,
.skip_linux = skip_linux,
.skip_llvm = skip_llvm,
.skip_libc = skip_libc,
try tests.addCases(b, test_cases_step, test_filters, test_target_filters, target, .{
.skip_translate_c = skip_translate_c,
.skip_run_translated_c = skip_run_translated_c,
}, .{
.enable_llvm = enable_llvm,
.llvm_has_m68k = llvm_has_m68k,
@ -443,7 +440,7 @@ pub fn build(b: *std.Build) !void {
test_modules_step.dependOn(tests.addModuleTests(b, .{
.test_filters = test_filters,
.test_target_filters = test_target_filters,
.test_extra_targets = test_extra_targets,
.test_slow_targets = test_slow_targets,
.root_src = "test/behavior.zig",
.name = "behavior",
.desc = "Run the behavior tests",
@ -451,22 +448,30 @@ pub fn build(b: *std.Build) !void {
.include_paths = &.{},
.skip_single_threaded = skip_single_threaded,
.skip_non_native = skip_non_native,
.test_default_only = no_matrix,
.skip_freebsd = skip_freebsd,
.skip_netbsd = skip_netbsd,
.skip_windows = skip_windows,
.skip_darwin = skip_darwin,
.skip_linux = skip_linux,
.skip_llvm = skip_llvm,
.skip_libc = skip_libc,
// 3888779264 was observed on an x86_64-linux-gnu host.
.max_rss = 4000000000,
.use_llvm = use_llvm,
.max_rss = 2 * 1024 * 1024 * 1024,
}));
test_modules_step.dependOn(tests.addModuleTests(b, .{
.test_filters = test_filters,
.test_target_filters = test_target_filters,
.test_extra_targets = test_extra_targets,
.test_slow_targets = test_slow_targets,
.root_src = "test/c_import.zig",
.name = "c-import",
.desc = "Run the @cImport tests",
.optimize_modes = optimization_modes,
.include_paths = &.{"test/c_import"},
.skip_single_threaded = true,
.skip_non_native = skip_non_native,
.skip_libc = skip_libc,
.use_llvm = use_llvm,
}));
test_modules_step.dependOn(tests.addModuleTests(b, .{
.test_filters = test_filters,
.test_target_filters = test_target_filters,
.test_slow_targets = test_slow_targets,
.root_src = "lib/compiler_rt.zig",
.name = "compiler-rt",
.desc = "Run the compiler_rt tests",
@ -474,43 +479,31 @@ pub fn build(b: *std.Build) !void {
.include_paths = &.{},
.skip_single_threaded = true,
.skip_non_native = skip_non_native,
.test_default_only = no_matrix,
.skip_freebsd = skip_freebsd,
.skip_netbsd = skip_netbsd,
.skip_windows = skip_windows,
.skip_darwin = skip_darwin,
.skip_linux = skip_linux,
.skip_llvm = skip_llvm,
.skip_libc = true,
.use_llvm = use_llvm,
.no_builtin = true,
}));
test_modules_step.dependOn(tests.addModuleTests(b, .{
.test_filters = test_filters,
.test_target_filters = test_target_filters,
.test_extra_targets = test_extra_targets,
.test_slow_targets = test_slow_targets,
.root_src = "lib/c.zig",
.name = "zigc",
.desc = "Run the zigc tests",
.name = "universal-libc",
.desc = "Run the universal libc tests",
.optimize_modes = optimization_modes,
.include_paths = &.{},
.skip_single_threaded = true,
.skip_non_native = skip_non_native,
.test_default_only = no_matrix,
.skip_freebsd = skip_freebsd,
.skip_netbsd = skip_netbsd,
.skip_windows = skip_windows,
.skip_darwin = skip_darwin,
.skip_linux = skip_linux,
.skip_llvm = skip_llvm,
.skip_libc = true,
.use_llvm = use_llvm,
.no_builtin = true,
}));
test_modules_step.dependOn(tests.addModuleTests(b, .{
.test_filters = test_filters,
.test_target_filters = test_target_filters,
.test_extra_targets = test_extra_targets,
.test_slow_targets = test_slow_targets,
.root_src = "lib/std/std.zig",
.name = "std",
.desc = "Run the standard library tests",
@ -518,25 +511,21 @@ pub fn build(b: *std.Build) !void {
.include_paths = &.{},
.skip_single_threaded = skip_single_threaded,
.skip_non_native = skip_non_native,
.test_default_only = no_matrix,
.skip_freebsd = skip_freebsd,
.skip_netbsd = skip_netbsd,
.skip_windows = skip_windows,
.skip_darwin = skip_darwin,
.skip_linux = skip_linux,
.skip_llvm = skip_llvm,
.skip_libc = skip_libc,
// I observed a value of 5605064704 on the M2 CI.
.max_rss = 6165571174,
.use_llvm = use_llvm,
// I observed a value of 5136793600 on the M2 CI.
.max_rss = 5368709120,
}));
const unit_tests_step = b.step("test-unit", "Run the compiler source unit tests");
test_step.dependOn(unit_tests_step);
const unit_tests = b.addTest(.{
.root_module = addCompilerMod(b, .{
.root_module = b.createModule(.{
.root_source_file = b.path("src/main.zig"),
.optimize = optimize,
.target = target,
.link_libc = link_libc,
.single_threaded = single_threaded,
}),
.filters = test_filters,
@ -544,12 +533,10 @@ pub fn build(b: *std.Build) !void {
.use_lld = use_llvm,
.zig_lib_dir = b.path("lib"),
});
if (link_libc) {
unit_tests.root_module.link_libc = true;
}
unit_tests.root_module.addOptions("build_options", exe_options);
unit_tests_step.dependOn(&b.addRunArtifact(unit_tests).step);
test_step.dependOn(tests.addCompareOutputTests(b, test_filters, optimization_modes));
test_step.dependOn(tests.addStandaloneTests(
b,
optimization_modes,
@ -560,18 +547,12 @@ pub fn build(b: *std.Build) !void {
test_step.dependOn(tests.addCAbiTests(b, .{
.test_target_filters = test_target_filters,
.skip_non_native = skip_non_native,
.skip_freebsd = skip_freebsd,
.skip_netbsd = skip_netbsd,
.skip_windows = skip_windows,
.skip_darwin = skip_darwin,
.skip_linux = skip_linux,
.skip_llvm = skip_llvm,
.skip_release = skip_release,
}));
test_step.dependOn(tests.addLinkTests(b, enable_macos_sdk, enable_ios_sdk, enable_symlinks_windows));
test_step.dependOn(tests.addStackTraceTests(b, test_filters, skip_non_native));
test_step.dependOn(tests.addErrorTraceTests(b, test_filters, optimization_modes, skip_non_native));
test_step.dependOn(tests.addStackTraceTests(b, test_filters, optimization_modes));
test_step.dependOn(tests.addCliTests(b));
test_step.dependOn(tests.addAssembleAndLinkTests(b, test_filters, optimization_modes));
if (tests.addDebuggerTests(b, .{
.test_filters = test_filters,
.test_target_filters = test_target_filters,
@ -579,13 +560,9 @@ pub fn build(b: *std.Build) !void {
.lldb = b.option([]const u8, "lldb", "path to lldb binary"),
.optimize_modes = optimization_modes,
.skip_single_threaded = skip_single_threaded,
.skip_non_native = skip_non_native,
.skip_libc = skip_libc,
})) |test_debugger_step| test_step.dependOn(test_debugger_step);
if (tests.addLlvmIrTests(b, .{
.enable_llvm = enable_llvm,
.test_filters = test_filters,
.test_target_filters = test_target_filters,
})) |test_llvm_ir_step| test_step.dependOn(test_llvm_ir_step);
try addWasiUpdateStep(b, version);
@ -610,15 +587,7 @@ pub fn build(b: *std.Build) !void {
const test_incremental_step = b.step("test-incremental", "Run the incremental compilation test cases");
try tests.addIncrementalTests(b, test_incremental_step);
if (!skip_test_incremental) test_step.dependOn(test_incremental_step);
if (tests.addLibcTests(b, .{
.optimize_modes = optimization_modes,
.test_filters = test_filters,
.test_target_filters = test_target_filters,
// Highest RSS observed in any test case was exactly 1802878976 on x86_64-linux.
.max_rss = 2253598720,
})) |test_libc_step| test_step.dependOn(test_libc_step);
test_step.dependOn(test_incremental_step);
}
fn addWasiUpdateStep(b: *std.Build, version: [:0]const u8) !void {
@ -679,17 +648,17 @@ fn addWasiUpdateStep(b: *std.Build, version: [:0]const u8) !void {
});
run_opt.addArtifactArg(exe);
run_opt.addArg("-o");
const optimized_wasm = run_opt.addOutputFileArg("zig1.wasm");
run_opt.addFileArg(b.path("stage1/zig1.wasm"));
const update_zig1 = b.addUpdateSourceFiles();
update_zig1.addCopyFileToSource(optimized_wasm, "stage1/zig1.wasm");
update_zig1.addCopyFileToSource(b.path("lib/zig.h"), "stage1/zig.h");
const copy_zig_h = b.addUpdateSourceFiles();
copy_zig_h.addCopyFileToSource(b.path("lib/zig.h"), "stage1/zig.h");
const update_zig1_step = b.step("update-zig1", "Update stage1/zig1.wasm");
update_zig1_step.dependOn(&update_zig1.step);
update_zig1_step.dependOn(&run_opt.step);
update_zig1_step.dependOn(&copy_zig_h.step);
}
const AddCompilerModOptions = struct {
const AddCompilerStepOptions = struct {
optimize: std.builtin.OptimizeMode,
target: std.Build.ResolvedTarget,
strip: ?bool = null,
@ -698,7 +667,7 @@ const AddCompilerModOptions = struct {
single_threaded: ?bool = null,
};
fn addCompilerMod(b: *std.Build, options: AddCompilerModOptions) *std.Build.Module {
fn addCompilerStep(b: *std.Build, options: AddCompilerStepOptions) *std.Build.Step.Compile {
const compiler_mod = b.createModule(.{
.root_source_file = b.path("src/main.zig"),
.target = options.target,
@ -706,6 +675,24 @@ fn addCompilerMod(b: *std.Build, options: AddCompilerModOptions) *std.Build.Modu
.strip = options.strip,
.sanitize_thread = options.sanitize_thread,
.single_threaded = options.single_threaded,
.code_model = switch (options.target.result.cpu.arch) {
// NB:
// For loongarch, LLVM supports only small, medium and large
// code model. If we don't explicitly specify the code model,
// the default value `small' will be used.
//
// Since zig binary itself is relatively large, using a `small'
// code model will cause
//
// relocation R_LARCH_B26 out of range
//
// error when linking a loongarch32/loongarch64 zig binary.
//
// Here we explicitly set code model to `medium' to avoid this
// error.
.loongarch32, .loongarch64 => .medium,
else => .default,
},
.valgrind = options.valgrind,
});
@ -713,16 +700,18 @@ fn addCompilerMod(b: *std.Build, options: AddCompilerModOptions) *std.Build.Modu
.root_source_file = b.path("lib/compiler/aro/aro.zig"),
});
const aro_translate_c_mod = b.createModule(.{
.root_source_file = b.path("lib/compiler/aro_translate_c.zig"),
});
aro_translate_c_mod.addImport("aro", aro_mod);
compiler_mod.addImport("aro", aro_mod);
compiler_mod.addImport("aro_translate_c", aro_translate_c_mod);
return compiler_mod;
}
fn addCompilerStep(b: *std.Build, options: AddCompilerModOptions) *std.Build.Step.Compile {
const exe = b.addExecutable(.{
.name = "zig",
.max_rss = 7_800_000_000,
.root_module = addCompilerMod(b, options),
.root_module = compiler_mod,
});
exe.stack_size = stack_size;
@ -742,9 +731,6 @@ const exe_cflags = [_][]const u8{
"-Wno-type-limits",
"-Wno-missing-braces",
"-Wno-comment",
// `exe_cflags` is only used for static linking.
"-DLLVM_BUILD_STATIC",
"-DCLANG_BUILD_STATIC",
};
fn addCmakeCfgOptionsToExe(
@ -754,7 +740,7 @@ fn addCmakeCfgOptionsToExe(
use_zig_libcxx: bool,
) !void {
const mod = exe.root_module;
const target = &mod.resolved_target.?.result;
const target = mod.resolved_target.?.result;
if (target.os.tag.isDarwin()) {
// useful for package maintainers
@ -819,7 +805,7 @@ fn addCmakeCfgOptionsToExe(
try addCxxKnownPath(b, cfg, exe, b.fmt("libstdc++.{s}", .{lib_suffix}), null, need_cpp_includes);
if (static) try addCxxKnownPath(b, cfg, exe, b.fmt("libgcc_eh.{s}", .{lib_suffix}), null, need_cpp_includes);
},
.illumos => {
.solaris, .illumos => {
try addCxxKnownPath(b, cfg, exe, b.fmt("libstdc++.{s}", .{lib_suffix}), null, need_cpp_includes);
try addCxxKnownPath(b, cfg, exe, b.fmt("libgcc_eh.{s}", .{lib_suffix}), null, need_cpp_includes);
},
@ -835,12 +821,7 @@ fn addCmakeCfgOptionsToExe(
}
}
fn addStaticLlvmOptionsToModule(mod: *std.Build.Module, options: struct {
llvm_has_m68k: bool,
llvm_has_csky: bool,
llvm_has_arc: bool,
llvm_has_xtensa: bool,
}) !void {
fn addStaticLlvmOptionsToModule(mod: *std.Build.Module) !void {
// Adds the Zig C++ sources which both stage1 and stage2 need.
//
// We need this because otherwise zig_clang_cc1_main.cpp ends up pulling
@ -864,22 +845,6 @@ fn addStaticLlvmOptionsToModule(mod: *std.Build.Module, options: struct {
mod.linkSystemLibrary(lib_name, .{});
}
if (options.llvm_has_m68k) for (llvm_libs_m68k) |lib_name| {
mod.linkSystemLibrary(lib_name, .{});
};
if (options.llvm_has_csky) for (llvm_libs_csky) |lib_name| {
mod.linkSystemLibrary(lib_name, .{});
};
if (options.llvm_has_arc) for (llvm_libs_arc) |lib_name| {
mod.linkSystemLibrary(lib_name, .{});
};
if (options.llvm_has_xtensa) for (llvm_libs_xtensa) |lib_name| {
mod.linkSystemLibrary(lib_name, .{});
};
mod.linkSystemLibrary("z", .{});
mod.linkSystemLibrary("zstd", .{});
@ -907,7 +872,7 @@ fn addCxxKnownPath(
return error.RequiredLibraryNotFound;
const path_padded = run: {
var args = std.array_list.Managed([]const u8).init(b.allocator);
var args = std.ArrayList([]const u8).init(b.allocator);
try args.append(ctx.cxx_compiler);
var it = std.mem.tokenizeAny(u8, ctx.cxx_compiler_arg1, &std.ascii.whitespace);
while (it.next()) |arg| try args.append(arg);
@ -1133,6 +1098,7 @@ fn toNativePathSep(b: *std.Build, s: []const u8) []u8 {
const zig_cpp_sources = [_][]const u8{
// These are planned to stay even when we are self-hosted.
"src/zig_llvm.cpp",
"src/zig_clang.cpp",
"src/zig_llvm-ar.cpp",
"src/zig_clang_driver.cpp",
"src/zig_clang_cc1_main.cpp",
@ -1158,6 +1124,7 @@ const clang_libs = [_][]const u8{
"clangBasic",
"clangEdit",
"clangLex",
"clangARCMigrate",
"clangRewriteFrontend",
"clangRewrite",
"clangCrossTU",
@ -1185,10 +1152,10 @@ const llvm_libs = [_][]const u8{
"LLVMXRay",
"LLVMLibDriver",
"LLVMDlltoolDriver",
"LLVMTelemetry",
"LLVMTextAPIBinaryReader",
"LLVMCoverage",
"LLVMLineEditor",
"LLVMSandboxIR",
"LLVMXCoreDisassembler",
"LLVMXCoreCodeGen",
"LLVMXCoreDesc",
@ -1215,10 +1182,6 @@ const llvm_libs = [_][]const u8{
"LLVMSystemZCodeGen",
"LLVMSystemZDesc",
"LLVMSystemZInfo",
"LLVMSPIRVCodeGen",
"LLVMSPIRVDesc",
"LLVMSPIRVInfo",
"LLVMSPIRVAnalysis",
"LLVMSparcDisassembler",
"LLVMSparcAsmParser",
"LLVMSparcCodeGen",
@ -1303,34 +1266,32 @@ const llvm_libs = [_][]const u8{
"LLVMOrcTargetProcess",
"LLVMOrcShared",
"LLVMDWP",
"LLVMDWARFCFIChecker",
"LLVMDebugInfoLogicalView",
"LLVMDebugInfoGSYM",
"LLVMOption",
"LLVMObjectYAML",
"LLVMObjCopy",
"LLVMMCA",
"LLVMMCDisassembler",
"LLVMLTO",
"LLVMPasses",
"LLVMHipStdPar",
"LLVMCFGuard",
"LLVMCoroutines",
"LLVMipo",
"LLVMVectorize",
"LLVMLinker",
"LLVMInstrumentation",
"LLVMFrontendOpenMP",
"LLVMFrontendOffloading",
"LLVMFrontendOpenACC",
"LLVMFrontendHLSL",
"LLVMFrontendDriver",
"LLVMExtensions",
"LLVMPasses",
"LLVMHipStdPar",
"LLVMCoroutines",
"LLVMCFGuard",
"LLVMipo",
"LLVMInstrumentation",
"LLVMVectorize",
"LLVMSandboxIR",
"LLVMLinker",
"LLVMFrontendOpenMP",
"LLVMFrontendDirective",
"LLVMFrontendAtomic",
"LLVMFrontendOffloading",
"LLVMObjectYAML",
"LLVMDWARFLinkerParallel",
"LLVMDWARFLinkerClassic",
"LLVMDWARFLinker",
"LLVMCodeGenData",
"LLVMGlobalISel",
"LLVMMIRParser",
"LLVMAsmPrinter",
@ -1339,7 +1300,6 @@ const llvm_libs = [_][]const u8{
"LLVMTarget",
"LLVMObjCARCOpts",
"LLVMCodeGenTypes",
"LLVMCGData",
"LLVMIRPrinter",
"LLVMInterfaceStub",
"LLVMFileCheck",
@ -1355,16 +1315,14 @@ const llvm_libs = [_][]const u8{
"LLVMDebugInfoBTF",
"LLVMDebugInfoPDB",
"LLVMDebugInfoMSF",
"LLVMDebugInfoCodeView",
"LLVMDebugInfoGSYM",
"LLVMDebugInfoDWARF",
"LLVMDebugInfoDWARFLowLevel",
"LLVMObject",
"LLVMTextAPI",
"LLVMMCParser",
"LLVMIRReader",
"LLVMAsmParser",
"LLVMMC",
"LLVMDebugInfoCodeView",
"LLVMBitReader",
"LLVMFuzzerCLI",
"LLVMCore",
@ -1375,33 +1333,6 @@ const llvm_libs = [_][]const u8{
"LLVMSupport",
"LLVMDemangle",
};
const llvm_libs_m68k = [_][]const u8{
"LLVMM68kDisassembler",
"LLVMM68kAsmParser",
"LLVMM68kCodeGen",
"LLVMM68kDesc",
"LLVMM68kInfo",
};
const llvm_libs_csky = [_][]const u8{
"LLVMCSKYDisassembler",
"LLVMCSKYAsmParser",
"LLVMCSKYCodeGen",
"LLVMCSKYDesc",
"LLVMCSKYInfo",
};
const llvm_libs_arc = [_][]const u8{
"LLVMARCDisassembler",
"LLVMARCCodeGen",
"LLVMARCDesc",
"LLVMARCInfo",
};
const llvm_libs_xtensa = [_][]const u8{
"LLVMXtensaDisassembler",
"LLVMXtensaAsmParser",
"LLVMXtensaCodeGen",
"LLVMXtensaDesc",
"LLVMXtensaInfo",
};
fn generateLangRef(b: *std.Build) std.Build.LazyPath {
const doctest_exe = b.addExecutable(.{
@ -1414,7 +1345,7 @@ fn generateLangRef(b: *std.Build) std.Build.LazyPath {
});
var dir = b.build_root.handle.openDir("doc/langref", .{ .iterate = true }) catch |err| {
std.debug.panic("unable to open '{f}doc/langref' directory: {s}", .{
std.debug.panic("unable to open '{}doc/langref' directory: {s}", .{
b.build_root, @errorName(err),
});
};
@ -1435,7 +1366,7 @@ fn generateLangRef(b: *std.Build) std.Build.LazyPath {
// in a temporary directory
"--cache-root", b.cache_root.path orelse ".",
});
cmd.addArgs(&.{ "--zig-lib-dir", b.fmt("{f}", .{b.graph.zig_lib_directory}) });
cmd.addArgs(&.{ "--zig-lib-dir", b.fmt("{}", .{b.graph.zig_lib_directory}) });
cmd.addArgs(&.{"-i"});
cmd.addFileArg(b.path(b.fmt("doc/langref/{s}", .{entry.name})));

59
ci/aarch64-linux-debug.sh Executable file → Normal file
View File

@ -5,14 +5,20 @@
set -x
set -e
TARGET="aarch64-linux-musl"
ARCH="$(uname -m)"
TARGET="$ARCH-linux-musl"
MCPU="baseline"
CACHE_BASENAME="zig+llvm+lld+clang-$TARGET-0.16.0-dev.104+689461e31"
CACHE_BASENAME="zig+llvm+lld+clang-$TARGET-0.14.0-dev.1622+2ac543388"
PREFIX="$HOME/deps/$CACHE_BASENAME"
ZIG="$PREFIX/bin/zig"
export PATH="$HOME/local/bin:$PATH"
# Make the `zig version` number consistent.
# This will affect the cmake command below.
git fetch --unshallow || true
git fetch --tags
# Override the cache directories because they won't actually help other CI runs
# which will be testing alternate versions of zig, and ultimately would just
# fill up space on the hard drive for no reason.
@ -42,23 +48,48 @@ unset CXX
ninja install
# simultaneously test building self-hosted without LLVM and with 32-bit arm
stage3-debug/bin/zig build \
-Dtarget=arm-linux-musleabihf \
-Dno-lib
# No -fqemu and -fwasmtime here as they're covered by the x86_64-linux scripts.
stage3-debug/bin/zig build test docs \
--maxrss 44918199637 \
--maxrss 24696061952 \
-Dstatic-llvm \
-Dskip-non-native \
-Dtarget=native-native-musl \
--search-prefix "$PREFIX" \
--zig-lib-dir "$PWD/../lib" \
-Denable-superhtml \
--test-timeout 3m
-Denable-superhtml
stage3-debug/bin/zig build \
--prefix stage4-debug \
-Denable-llvm \
# Ensure that updating the wasm binary from this commit will result in a viable build.
stage3-debug/bin/zig build update-zig1
mkdir ../build-new
cd ../build-new
export CC="$ZIG cc -target $TARGET -mcpu=$MCPU"
export CXX="$ZIG c++ -target $TARGET -mcpu=$MCPU"
cmake .. \
-DCMAKE_PREFIX_PATH="$PREFIX" \
-DCMAKE_BUILD_TYPE=Debug \
-DZIG_TARGET_TRIPLE="$TARGET" \
-DZIG_TARGET_MCPU="$MCPU" \
-DZIG_STATIC=ON \
-DZIG_NO_LIB=ON \
-GNinja
unset CC
unset CXX
ninja install
stage3/bin/zig test ../test/behavior.zig
stage3/bin/zig build -p stage4 \
-Dstatic-llvm \
-Dtarget=native-native-musl \
-Dno-lib \
-Dtarget=$TARGET \
-Duse-zig-libcxx \
-Dversion-string="$(stage3-debug/bin/zig version)"
stage4-debug/bin/zig test ../test/behavior.zig
--search-prefix "$PREFIX" \
--zig-lib-dir "$PWD/../lib"
stage4/bin/zig test ../test/behavior.zig

53
ci/aarch64-linux-release.sh Executable file → Normal file
View File

@ -5,14 +5,20 @@
set -x
set -e
TARGET="aarch64-linux-musl"
ARCH="$(uname -m)"
TARGET="$ARCH-linux-musl"
MCPU="baseline"
CACHE_BASENAME="zig+llvm+lld+clang-$TARGET-0.16.0-dev.104+689461e31"
CACHE_BASENAME="zig+llvm+lld+clang-$TARGET-0.14.0-dev.1622+2ac543388"
PREFIX="$HOME/deps/$CACHE_BASENAME"
ZIG="$PREFIX/bin/zig"
export PATH="$HOME/local/bin:$PATH"
# Make the `zig version` number consistent.
# This will affect the cmake command below.
git fetch --unshallow || true
git fetch --tags
# Override the cache directories because they won't actually help other CI runs
# which will be testing alternate versions of zig, and ultimately would just
# fill up space on the hard drive for no reason.
@ -42,16 +48,19 @@ unset CXX
ninja install
# simultaneously test building self-hosted without LLVM and with 32-bit arm
stage3-release/bin/zig build \
-Dtarget=arm-linux-musleabihf \
-Dno-lib
# No -fqemu and -fwasmtime here as they're covered by the x86_64-linux scripts.
stage3-release/bin/zig build test docs \
--maxrss 44918199637 \
--maxrss 24696061952 \
-Dstatic-llvm \
-Dskip-non-native \
-Dtarget=native-native-musl \
--search-prefix "$PREFIX" \
--zig-lib-dir "$PWD/../lib" \
-Denable-superhtml \
--test-timeout 3m
-Denable-superhtml
# Ensure that stage3 and stage4 are byte-for-byte identical.
stage3-release/bin/zig build \
@ -68,3 +77,35 @@ stage3-release/bin/zig build \
echo "If the following command fails, it means nondeterminism has been"
echo "introduced, making stage3 and stage4 no longer byte-for-byte identical."
diff stage3-release/bin/zig stage4-release/bin/zig
# Ensure that updating the wasm binary from this commit will result in a viable build.
stage3-release/bin/zig build update-zig1
mkdir ../build-new
cd ../build-new
export CC="$ZIG cc -target $TARGET -mcpu=$MCPU"
export CXX="$ZIG c++ -target $TARGET -mcpu=$MCPU"
cmake .. \
-DCMAKE_PREFIX_PATH="$PREFIX" \
-DCMAKE_BUILD_TYPE=Release \
-DZIG_TARGET_TRIPLE="$TARGET" \
-DZIG_TARGET_MCPU="$MCPU" \
-DZIG_STATIC=ON \
-DZIG_NO_LIB=ON \
-GNinja
unset CC
unset CXX
ninja install
stage3/bin/zig test ../test/behavior.zig
stage3/bin/zig build -p stage4 \
-Dstatic-llvm \
-Dtarget=native-native-musl \
-Dno-lib \
--search-prefix "$PREFIX" \
--zig-lib-dir "$PWD/../lib"
stage4/bin/zig test ../test/behavior.zig

View File

@ -3,10 +3,13 @@
set -x
set -e
# Script assumes the presence of the following:
# s3cmd
ZIGDIR="$PWD"
TARGET="aarch64-macos-none"
TARGET="$ARCH-macos-none"
MCPU="baseline"
CACHE_BASENAME="zig+llvm+lld+clang-$TARGET-0.16.0-dev.104+689461e31"
CACHE_BASENAME="zig+llvm+lld+clang-$TARGET-0.14.0-dev.1622+2ac543388"
PREFIX="$HOME/$CACHE_BASENAME"
ZIG="$PREFIX/bin/zig"
@ -18,6 +21,11 @@ fi
cd $ZIGDIR
# Make the `zig version` number consistent.
# This will affect the cmake command below.
git fetch --unshallow || true
git fetch --tags
# Override the cache directories because they won't actually help other CI runs
# which will be testing alternate versions of zig, and ultimately would just
# fill up space on the hard drive for no reason.
@ -27,7 +35,7 @@ export ZIG_LOCAL_CACHE_DIR="$PWD/zig-local-cache"
mkdir build-debug
cd build-debug
cmake .. \
PATH="$HOME/local/bin:$PATH" cmake .. \
-DCMAKE_INSTALL_PREFIX="stage3-debug" \
-DCMAKE_PREFIX_PATH="$PREFIX" \
-DCMAKE_BUILD_TYPE=Debug \
@ -39,12 +47,11 @@ cmake .. \
-DZIG_NO_LIB=ON \
-GNinja
ninja install
$HOME/local/bin/ninja install
stage3-debug/bin/zig build test docs \
--zig-lib-dir "$PWD/../lib" \
-Denable-macos-sdk \
-Dstatic-llvm \
-Dskip-non-native \
--search-prefix "$PREFIX" \
--test-timeout 2m
--search-prefix "$PREFIX"

View File

@ -3,10 +3,13 @@
set -x
set -e
# Script assumes the presence of the following:
# s3cmd
ZIGDIR="$PWD"
TARGET="aarch64-macos-none"
TARGET="$ARCH-macos-none"
MCPU="baseline"
CACHE_BASENAME="zig+llvm+lld+clang-$TARGET-0.16.0-dev.104+689461e31"
CACHE_BASENAME="zig+llvm+lld+clang-$TARGET-0.14.0-dev.1622+2ac543388"
PREFIX="$HOME/$CACHE_BASENAME"
ZIG="$PREFIX/bin/zig"
@ -18,6 +21,11 @@ fi
cd $ZIGDIR
# Make the `zig version` number consistent.
# This will affect the cmake command below.
git fetch --unshallow || true
git fetch --tags
# Override the cache directories because they won't actually help other CI runs
# which will be testing alternate versions of zig, and ultimately would just
# fill up space on the hard drive for no reason.
@ -27,7 +35,7 @@ export ZIG_LOCAL_CACHE_DIR="$PWD/zig-local-cache"
mkdir build-release
cd build-release
cmake .. \
PATH="$HOME/local/bin:$PATH" cmake .. \
-DCMAKE_INSTALL_PREFIX="stage3-release" \
-DCMAKE_PREFIX_PATH="$PREFIX" \
-DCMAKE_BUILD_TYPE=Release \
@ -39,15 +47,14 @@ cmake .. \
-DZIG_NO_LIB=ON \
-GNinja
ninja install
$HOME/local/bin/ninja install
stage3-release/bin/zig build test docs \
--zig-lib-dir "$PWD/../lib" \
-Denable-macos-sdk \
-Dstatic-llvm \
-Dskip-non-native \
--search-prefix "$PREFIX" \
--test-timeout 2m
--search-prefix "$PREFIX"
# Ensure that stage3 and stage4 are byte-for-byte identical.
stage3-release/bin/zig build \

View File

@ -1,5 +1,5 @@
$TARGET = "aarch64-windows-gnu"
$ZIG_LLVM_CLANG_LLD_NAME = "zig+llvm+lld+clang-$TARGET-0.16.0-dev.104+689461e31"
$TARGET = "$($Env:ARCH)-windows-gnu"
$ZIG_LLVM_CLANG_LLD_NAME = "zig+llvm+lld+clang-$TARGET-0.14.0-dev.1622+2ac543388"
$MCPU = "baseline"
$ZIG_LLVM_CLANG_LLD_URL = "https://ziglang.org/deps/$ZIG_LLVM_CLANG_LLD_NAME.zip"
$PREFIX_PATH = "$(Get-Location)\..\$ZIG_LLVM_CLANG_LLD_NAME"
@ -22,6 +22,14 @@ function CheckLastExitCode {
return 0
}
# Make the `zig version` number consistent.
# This will affect the `zig build` command below which uses `git describe`.
git fetch --tags
if ((git rev-parse --is-shallow-repository) -eq "true") {
git fetch --unshallow # `git describe` won't work on a shallow repo
}
# Override the cache directories because they won't actually help other CI runs
# which will be testing alternate versions of zig, and ultimately would just
# fill up space on the hard drive for no reason.
@ -58,8 +66,7 @@ Write-Output "Main test suite..."
--search-prefix "$PREFIX_PATH" `
-Dstatic-llvm `
-Dskip-non-native `
-Denable-symlinks-windows `
--test-timeout 30m
-Denable-symlinks-windows
CheckLastExitCode
# Ensure that stage3 and stage4 are byte-for-byte identical.

View File

@ -1,64 +0,0 @@
#!/bin/sh
# Requires cmake ninja-build
set -x
set -e
TARGET="loongarch64-linux-musl"
MCPU="baseline"
CACHE_BASENAME="zig+llvm+lld+clang-$TARGET-0.16.0-dev.157+7fdd60df1"
PREFIX="$HOME/deps/$CACHE_BASENAME"
ZIG="$PREFIX/bin/zig"
# Override the cache directories because they won't actually help other CI runs
# which will be testing alternate versions of zig, and ultimately would just
# fill up space on the hard drive for no reason.
export ZIG_GLOBAL_CACHE_DIR="$PWD/zig-global-cache"
export ZIG_LOCAL_CACHE_DIR="$PWD/zig-local-cache"
mkdir build-debug
cd build-debug
export CC="$ZIG cc -target $TARGET -mcpu=$MCPU"
export CXX="$ZIG c++ -target $TARGET -mcpu=$MCPU"
cmake .. \
-DCMAKE_INSTALL_PREFIX="stage3-debug" \
-DCMAKE_PREFIX_PATH="$PREFIX" \
-DCMAKE_BUILD_TYPE=Debug \
-DZIG_TARGET_TRIPLE="$TARGET" \
-DZIG_TARGET_MCPU="$MCPU" \
-DZIG_STATIC=ON \
-DZIG_NO_LIB=ON \
-GNinja \
-DCMAKE_C_LINKER_DEPFILE_SUPPORTED=FALSE \
-DCMAKE_CXX_LINKER_DEPFILE_SUPPORTED=FALSE
# https://github.com/ziglang/zig/issues/22213
# Now cmake will use zig as the C/C++ compiler. We reset the environment variables
# so that installation and testing do not get affected by them.
unset CC
unset CXX
ninja install
# No -fqemu and -fwasmtime here as they're covered by the x86_64-linux scripts.
stage3-debug/bin/zig build test docs \
--maxrss 60129542144 \
-Dstatic-llvm \
-Dskip-non-native \
-Dtarget=native-native-musl \
--search-prefix "$PREFIX" \
--zig-lib-dir "$PWD/../lib" \
--test-timeout 4m
stage3-debug/bin/zig build \
--prefix stage4-debug \
-Denable-llvm \
-Dno-lib \
-Dtarget=$TARGET \
-Duse-zig-libcxx \
-Dversion-string="$(stage3-debug/bin/zig version)"
stage4-debug/bin/zig test ../test/behavior.zig

View File

@ -1,70 +0,0 @@
#!/bin/sh
# Requires cmake ninja-build
set -x
set -e
TARGET="loongarch64-linux-musl"
MCPU="baseline"
CACHE_BASENAME="zig+llvm+lld+clang-$TARGET-0.16.0-dev.157+7fdd60df1"
PREFIX="$HOME/deps/$CACHE_BASENAME"
ZIG="$PREFIX/bin/zig"
# Override the cache directories because they won't actually help other CI runs
# which will be testing alternate versions of zig, and ultimately would just
# fill up space on the hard drive for no reason.
export ZIG_GLOBAL_CACHE_DIR="$PWD/zig-global-cache"
export ZIG_LOCAL_CACHE_DIR="$PWD/zig-local-cache"
mkdir build-release
cd build-release
export CC="$ZIG cc -target $TARGET -mcpu=$MCPU"
export CXX="$ZIG c++ -target $TARGET -mcpu=$MCPU"
cmake .. \
-DCMAKE_INSTALL_PREFIX="stage3-release" \
-DCMAKE_PREFIX_PATH="$PREFIX" \
-DCMAKE_BUILD_TYPE=Release \
-DZIG_TARGET_TRIPLE="$TARGET" \
-DZIG_TARGET_MCPU="$MCPU" \
-DZIG_STATIC=ON \
-DZIG_NO_LIB=ON \
-GNinja \
-DCMAKE_C_LINKER_DEPFILE_SUPPORTED=FALSE \
-DCMAKE_CXX_LINKER_DEPFILE_SUPPORTED=FALSE
# https://github.com/ziglang/zig/issues/22213
# Now cmake will use zig as the C/C++ compiler. We reset the environment variables
# so that installation and testing do not get affected by them.
unset CC
unset CXX
ninja install
# No -fqemu and -fwasmtime here as they're covered by the x86_64-linux scripts.
stage3-release/bin/zig build test docs \
--maxrss 60129542144 \
-Dstatic-llvm \
-Dskip-non-native \
-Dtarget=native-native-musl \
--search-prefix "$PREFIX" \
--zig-lib-dir "$PWD/../lib" \
--test-timeout 4m
# Ensure that stage3 and stage4 are byte-for-byte identical.
stage3-release/bin/zig build \
--prefix stage4-release \
-Denable-llvm \
-Dno-lib \
-Doptimize=ReleaseFast \
-Dstrip \
-Dtarget=$TARGET \
-Duse-zig-libcxx \
-Dversion-string="$(stage3-release/bin/zig version)"
# diff returns an error code if the files differ.
echo "If the following command fails, it means nondeterminism has been"
echo "introduced, making stage3 and stage4 no longer byte-for-byte identical."
diff stage3-release/bin/zig stage4-release/bin/zig

View File

@ -1,55 +0,0 @@
#!/bin/sh
# Requires cmake ninja-build
set -x
set -e
TARGET="riscv64-linux-musl"
MCPU="spacemit_x60"
CACHE_BASENAME="zig+llvm+lld+clang-riscv64-linux-musl-0.16.0-dev.104+689461e31"
PREFIX="$HOME/deps/$CACHE_BASENAME"
ZIG="$PREFIX/bin/zig"
export PATH="$HOME/local/bin:$PATH"
# Override the cache directories because they won't actually help other CI runs
# which will be testing alternate versions of zig, and ultimately would just
# fill up space on the hard drive for no reason.
export ZIG_GLOBAL_CACHE_DIR="$PWD/zig-global-cache"
export ZIG_LOCAL_CACHE_DIR="$PWD/zig-local-cache"
mkdir build-debug
cd build-debug
export CC="$ZIG cc -target $TARGET -mcpu=$MCPU"
export CXX="$ZIG c++ -target $TARGET -mcpu=$MCPU"
cmake .. \
-DCMAKE_INSTALL_PREFIX="stage3-debug" \
-DCMAKE_PREFIX_PATH="$PREFIX" \
-DCMAKE_BUILD_TYPE=Debug \
-DZIG_TARGET_TRIPLE="$TARGET" \
-DZIG_TARGET_MCPU="$MCPU" \
-DZIG_STATIC=ON \
-DZIG_NO_LIB=ON \
-GNinja
# Now cmake will use zig as the C/C++ compiler. We reset the environment variables
# so that installation and testing do not get affected by them.
unset CC
unset CXX
ninja install
# No -fqemu and -fwasmtime here as they're covered by the x86_64-linux scripts.
stage3-debug/bin/zig build test-cases test-modules test-unit test-c-abi test-stack-traces test-error-traces test-llvm-ir \
--maxrss 68719476736 \
-Dstatic-llvm \
-Dskip-non-native \
-Dskip-single-threaded \
-Dskip-compile-errors \
-Dtarget=native-native-musl \
--search-prefix "$PREFIX" \
--zig-lib-dir "$PWD/../lib" \
--test-timeout 4m

View File

@ -1,55 +0,0 @@
#!/bin/sh
# Requires cmake ninja-build
set -x
set -e
TARGET="riscv64-linux-musl"
MCPU="spacemit_x60"
CACHE_BASENAME="zig+llvm+lld+clang-riscv64-linux-musl-0.16.0-dev.104+689461e31"
PREFIX="$HOME/deps/$CACHE_BASENAME"
ZIG="$PREFIX/bin/zig"
export PATH="$HOME/local/bin:$PATH"
# Override the cache directories because they won't actually help other CI runs
# which will be testing alternate versions of zig, and ultimately would just
# fill up space on the hard drive for no reason.
export ZIG_GLOBAL_CACHE_DIR="$PWD/zig-global-cache"
export ZIG_LOCAL_CACHE_DIR="$PWD/zig-local-cache"
mkdir build-release
cd build-release
export CC="$ZIG cc -target $TARGET -mcpu=$MCPU"
export CXX="$ZIG c++ -target $TARGET -mcpu=$MCPU"
cmake .. \
-DCMAKE_INSTALL_PREFIX="stage3-release" \
-DCMAKE_PREFIX_PATH="$PREFIX" \
-DCMAKE_BUILD_TYPE=Release \
-DZIG_TARGET_TRIPLE="$TARGET" \
-DZIG_TARGET_MCPU="$MCPU" \
-DZIG_STATIC=ON \
-DZIG_NO_LIB=ON \
-GNinja
# Now cmake will use zig as the C/C++ compiler. We reset the environment variables
# so that installation and testing do not get affected by them.
unset CC
unset CXX
ninja install
# No -fqemu and -fwasmtime here as they're covered by the x86_64-linux scripts.
stage3-release/bin/zig build test-cases test-modules test-unit test-c-abi test-stack-traces test-error-traces test-llvm-ir \
--maxrss 68719476736 \
-Dstatic-llvm \
-Dskip-non-native \
-Dskip-single-threaded \
-Dskip-compile-errors \
-Dtarget=native-native-musl \
--search-prefix "$PREFIX" \
--zig-lib-dir "$PWD/../lib" \
--test-timeout 4m

View File

@ -1,65 +0,0 @@
#!/bin/sh
# Requires cmake ninja-build
set -x
set -e
TARGET="s390x-linux-musl"
MCPU="z15"
CACHE_BASENAME="zig+llvm+lld+clang-$TARGET-0.16.0-dev.1354+94e98bfe8"
PREFIX="$HOME/deps/$CACHE_BASENAME"
ZIG="$PREFIX/bin/zig"
# Override the cache directories because they won't actually help other CI runs
# which will be testing alternate versions of zig, and ultimately would just
# fill up space on the hard drive for no reason.
export ZIG_GLOBAL_CACHE_DIR="$PWD/zig-global-cache"
export ZIG_LOCAL_CACHE_DIR="$PWD/zig-local-cache"
mkdir build-debug
cd build-debug
export CC="$ZIG cc -target $TARGET -mcpu=$MCPU"
export CXX="$ZIG c++ -target $TARGET -mcpu=$MCPU"
cmake .. \
-DCMAKE_INSTALL_PREFIX="stage3-debug" \
-DCMAKE_PREFIX_PATH="$PREFIX" \
-DCMAKE_BUILD_TYPE=Debug \
-DZIG_TARGET_TRIPLE="$TARGET" \
-DZIG_TARGET_MCPU="$MCPU" \
-DZIG_STATIC=ON \
-DZIG_NO_LIB=ON \
-GNinja \
-DCMAKE_C_LINKER_DEPFILE_SUPPORTED=FALSE \
-DCMAKE_CXX_LINKER_DEPFILE_SUPPORTED=FALSE
# https://github.com/ziglang/zig/issues/22213
# Now cmake will use zig as the C/C++ compiler. We reset the environment variables
# so that installation and testing do not get affected by them.
unset CC
unset CXX
ninja install
# No -fqemu and -fwasmtime here as they're covered by the x86_64-linux scripts.
stage3-debug/bin/zig build test docs \
--maxrss 30064771072 \
-Dstatic-llvm \
-Dskip-non-native \
-Dtarget=native-native-musl \
--search-prefix "$PREFIX" \
--zig-lib-dir "$PWD/../lib" \
--test-timeout 4m
stage3-debug/bin/zig build \
--prefix stage4-debug \
-Denable-llvm \
-Dno-lib \
-Dtarget=$TARGET \
-Dcpu=$MCPU \
-Duse-zig-libcxx \
-Dversion-string="$(stage3-debug/bin/zig version)"
stage4-debug/bin/zig test ../test/behavior.zig

View File

@ -1,71 +0,0 @@
#!/bin/sh
# Requires cmake ninja-build
set -x
set -e
TARGET="s390x-linux-musl"
MCPU="z15"
CACHE_BASENAME="zig+llvm+lld+clang-$TARGET-0.16.0-dev.1354+94e98bfe8"
PREFIX="$HOME/deps/$CACHE_BASENAME"
ZIG="$PREFIX/bin/zig"
# Override the cache directories because they won't actually help other CI runs
# which will be testing alternate versions of zig, and ultimately would just
# fill up space on the hard drive for no reason.
export ZIG_GLOBAL_CACHE_DIR="$PWD/zig-global-cache"
export ZIG_LOCAL_CACHE_DIR="$PWD/zig-local-cache"
mkdir build-release
cd build-release
export CC="$ZIG cc -target $TARGET -mcpu=$MCPU"
export CXX="$ZIG c++ -target $TARGET -mcpu=$MCPU"
cmake .. \
-DCMAKE_INSTALL_PREFIX="stage3-release" \
-DCMAKE_PREFIX_PATH="$PREFIX" \
-DCMAKE_BUILD_TYPE=Release \
-DZIG_TARGET_TRIPLE="$TARGET" \
-DZIG_TARGET_MCPU="$MCPU" \
-DZIG_STATIC=ON \
-DZIG_NO_LIB=ON \
-GNinja \
-DCMAKE_C_LINKER_DEPFILE_SUPPORTED=FALSE \
-DCMAKE_CXX_LINKER_DEPFILE_SUPPORTED=FALSE
# https://github.com/ziglang/zig/issues/22213
# Now cmake will use zig as the C/C++ compiler. We reset the environment variables
# so that installation and testing do not get affected by them.
unset CC
unset CXX
ninja install
# No -fqemu and -fwasmtime here as they're covered by the x86_64-linux scripts.
stage3-release/bin/zig build test docs \
--maxrss 30064771072 \
-Dstatic-llvm \
-Dskip-non-native \
-Dtarget=native-native-musl \
--search-prefix "$PREFIX" \
--zig-lib-dir "$PWD/../lib" \
--test-timeout 4m
# Ensure that stage3 and stage4 are byte-for-byte identical.
stage3-release/bin/zig build \
--prefix stage4-release \
-Denable-llvm \
-Dno-lib \
-Doptimize=ReleaseFast \
-Dstrip \
-Dtarget=$TARGET \
-Dcpu=$MCPU \
-Duse-zig-libcxx \
-Dversion-string="$(stage3-release/bin/zig version)"
# diff returns an error code if the files differ.
echo "If the following command fails, it means nondeterminism has been"
echo "introduced, making stage3 and stage4 no longer byte-for-byte identical."
diff stage3-release/bin/zig stage4-release/bin/zig

View File

@ -1,65 +0,0 @@
#!/bin/sh
# Requires cmake ninja-build
set -x
set -e
TARGET="x86_64-freebsd-none"
MCPU="baseline"
CACHE_BASENAME="zig+llvm+lld+clang-$TARGET-0.16.0-dev.312+164c598cd"
PREFIX="$HOME/deps/$CACHE_BASENAME"
ZIG="$PREFIX/bin/zig"
# Override the cache directories because they won't actually help other CI runs
# which will be testing alternate versions of zig, and ultimately would just
# fill up space on the hard drive for no reason.
export ZIG_GLOBAL_CACHE_DIR="$PWD/zig-global-cache"
export ZIG_LOCAL_CACHE_DIR="$PWD/zig-local-cache"
mkdir build-debug
cd build-debug
export CC="$ZIG cc -target $TARGET -mcpu=$MCPU"
export CXX="$ZIG c++ -target $TARGET -mcpu=$MCPU"
cmake .. \
-DCMAKE_INSTALL_PREFIX="stage3-debug" \
-DCMAKE_PREFIX_PATH="$PREFIX" \
-DCMAKE_BUILD_TYPE=Debug \
-DZIG_TARGET_TRIPLE="$TARGET" \
-DZIG_TARGET_MCPU="$MCPU" \
-DZIG_STATIC=ON \
-DZIG_NO_LIB=ON \
-GNinja \
-DCMAKE_C_LINKER_DEPFILE_SUPPORTED=FALSE \
-DCMAKE_CXX_LINKER_DEPFILE_SUPPORTED=FALSE
# https://github.com/ziglang/zig/issues/22213
# Now cmake will use zig as the C/C++ compiler. We reset the environment variables
# so that installation and testing do not get affected by them.
unset CC
unset CXX
ninja install
stage3-debug/bin/zig build test docs \
--maxrss 42949672960 \
-Dstatic-llvm \
-Dskip-linux \
-Dskip-netbsd \
-Dskip-windows \
-Dskip-darwin \
--search-prefix "$PREFIX" \
--zig-lib-dir "$PWD/../lib" \
--test-timeout 2m
stage3-debug/bin/zig build \
--prefix stage4-debug \
-Denable-llvm \
-Dno-lib \
-Dtarget=$TARGET \
-Duse-zig-libcxx \
-Dversion-string="$(stage3-debug/bin/zig version)"
stage4-debug/bin/zig test ../test/behavior.zig

View File

@ -1,71 +0,0 @@
#!/bin/sh
# Requires cmake ninja-build
set -x
set -e
TARGET="x86_64-freebsd-none"
MCPU="baseline"
CACHE_BASENAME="zig+llvm+lld+clang-$TARGET-0.16.0-dev.312+164c598cd"
PREFIX="$HOME/deps/$CACHE_BASENAME"
ZIG="$PREFIX/bin/zig"
# Override the cache directories because they won't actually help other CI runs
# which will be testing alternate versions of zig, and ultimately would just
# fill up space on the hard drive for no reason.
export ZIG_GLOBAL_CACHE_DIR="$PWD/zig-global-cache"
export ZIG_LOCAL_CACHE_DIR="$PWD/zig-local-cache"
mkdir build-release
cd build-release
export CC="$ZIG cc -target $TARGET -mcpu=$MCPU"
export CXX="$ZIG c++ -target $TARGET -mcpu=$MCPU"
cmake .. \
-DCMAKE_INSTALL_PREFIX="stage3-release" \
-DCMAKE_PREFIX_PATH="$PREFIX" \
-DCMAKE_BUILD_TYPE=Release \
-DZIG_TARGET_TRIPLE="$TARGET" \
-DZIG_TARGET_MCPU="$MCPU" \
-DZIG_STATIC=ON \
-DZIG_NO_LIB=ON \
-GNinja \
-DCMAKE_C_LINKER_DEPFILE_SUPPORTED=FALSE \
-DCMAKE_CXX_LINKER_DEPFILE_SUPPORTED=FALSE
# https://github.com/ziglang/zig/issues/22213
# Now cmake will use zig as the C/C++ compiler. We reset the environment variables
# so that installation and testing do not get affected by them.
unset CC
unset CXX
ninja install
stage3-release/bin/zig build test docs \
--maxrss 42949672960 \
-Dstatic-llvm \
-Dskip-linux \
-Dskip-netbsd \
-Dskip-windows \
-Dskip-darwin \
--search-prefix "$PREFIX" \
--zig-lib-dir "$PWD/../lib" \
--test-timeout 2m
# Ensure that stage3 and stage4 are byte-for-byte identical.
stage3-release/bin/zig build \
--prefix stage4-release \
-Denable-llvm \
-Dno-lib \
-Doptimize=ReleaseFast \
-Dstrip \
-Dtarget=$TARGET \
-Duse-zig-libcxx \
-Dversion-string="$(stage3-release/bin/zig version)"
# diff returns an error code if the files differ.
echo "If the following command fails, it means nondeterminism has been"
echo "introduced, making stage3 and stage4 no longer byte-for-byte identical."
diff stage3-release/bin/zig stage4-release/bin/zig

View File

@ -1,65 +0,0 @@
#!/bin/sh
# Requires cmake ninja-build
set -x
set -e
TARGET="x86_64-linux-musl"
MCPU="baseline"
CACHE_BASENAME="zig+llvm+lld+clang-$TARGET-0.16.0-dev.104+689461e31"
PREFIX="$HOME/deps/$CACHE_BASENAME"
ZIG="$PREFIX/bin/zig"
export PATH="$HOME/deps/wasmtime-v38.0.3-x86_64-linux:$HOME/deps/qemu-linux-x86_64-10.1.1.1/bin:$HOME/local/bin:$PATH"
# Override the cache directories because they won't actually help other CI runs
# which will be testing alternate versions of zig, and ultimately would just
# fill up space on the hard drive for no reason.
export ZIG_GLOBAL_CACHE_DIR="$PWD/zig-global-cache"
export ZIG_LOCAL_CACHE_DIR="$PWD/zig-local-cache"
mkdir build-debug-llvm
cd build-debug-llvm
export CC="$ZIG cc -target $TARGET -mcpu=$MCPU"
export CXX="$ZIG c++ -target $TARGET -mcpu=$MCPU"
cmake .. \
-DCMAKE_INSTALL_PREFIX="stage3-debug" \
-DCMAKE_PREFIX_PATH="$PREFIX" \
-DCMAKE_BUILD_TYPE=Debug \
-DZIG_TARGET_TRIPLE="$TARGET" \
-DZIG_TARGET_MCPU="$MCPU" \
-DZIG_STATIC=ON \
-DZIG_NO_LIB=ON \
-DZIG_EXTRA_BUILD_ARGS="-Duse-llvm=true" \
-GNinja
# Now cmake will use zig as the C/C++ compiler. We reset the environment variables
# so that installation and testing do not get affected by them.
unset CC
unset CXX
ninja install
# simultaneously test building self-hosted without LLVM and with 32-bit arm
stage3-debug/bin/zig build \
-Dtarget=arm-linux-musleabihf \
-Dno-lib
stage3-debug/bin/zig build test docs \
--maxrss 21000000000 \
-Dlldb=$HOME/deps/lldb-zig/Debug-e0a42bb34/bin/lldb \
-fqemu \
-fwasmtime \
-Dstatic-llvm \
-Dskip-freebsd \
-Dskip-netbsd \
-Dskip-windows \
-Dskip-darwin \
-Dtarget=native-native-musl \
--search-prefix "$PREFIX" \
--zig-lib-dir "$PWD/../lib" \
-Denable-superhtml \
--test-timeout 12m

View File

@ -5,13 +5,19 @@
set -x
set -e
TARGET="x86_64-linux-musl"
ARCH="$(uname -m)"
TARGET="$ARCH-linux-musl"
MCPU="baseline"
CACHE_BASENAME="zig+llvm+lld+clang-$TARGET-0.16.0-dev.104+689461e31"
CACHE_BASENAME="zig+llvm+lld+clang-$TARGET-0.14.0-dev.1622+2ac543388"
PREFIX="$HOME/deps/$CACHE_BASENAME"
ZIG="$PREFIX/bin/zig"
export PATH="$HOME/deps/wasmtime-v38.0.3-x86_64-linux:$HOME/deps/qemu-linux-x86_64-10.1.1.1/bin:$HOME/local/bin:$PATH"
export PATH="$HOME/deps/wasmtime-v29.0.0-$ARCH-linux:$HOME/deps/qemu-linux-x86_64-9.2.0-rc1/bin:$HOME/local/bin:$PATH"
# Make the `zig version` number consistent.
# This will affect the cmake command below.
git fetch --unshallow || true
git fetch --tags
# Override the cache directories because they won't actually help other CI runs
# which will be testing alternate versions of zig, and ultimately would just
@ -19,6 +25,12 @@ export PATH="$HOME/deps/wasmtime-v38.0.3-x86_64-linux:$HOME/deps/qemu-linux-x86_
export ZIG_GLOBAL_CACHE_DIR="$PWD/zig-global-cache"
export ZIG_LOCAL_CACHE_DIR="$PWD/zig-local-cache"
# Test building from source without LLVM.
cc -o bootstrap bootstrap.c
./bootstrap
./zig2 build -Dno-lib
./zig-out/bin/zig test test/behavior.zig
mkdir build-debug
cd build-debug
@ -53,13 +65,39 @@ stage3-debug/bin/zig build test docs \
-fqemu \
-fwasmtime \
-Dstatic-llvm \
-Dskip-freebsd \
-Dskip-netbsd \
-Dskip-windows \
-Dskip-darwin \
-Dskip-llvm \
-Dtarget=native-native-musl \
--search-prefix "$PREFIX" \
--zig-lib-dir "$PWD/../lib" \
-Denable-superhtml \
--test-timeout 10m
-Denable-superhtml
# Ensure that updating the wasm binary from this commit will result in a viable build.
stage3-debug/bin/zig build update-zig1
mkdir ../build-new
cd ../build-new
export CC="$ZIG cc -target $TARGET -mcpu=$MCPU"
export CXX="$ZIG c++ -target $TARGET -mcpu=$MCPU"
cmake .. \
-DCMAKE_PREFIX_PATH="$PREFIX" \
-DCMAKE_BUILD_TYPE=Debug \
-DZIG_TARGET_TRIPLE="$TARGET" \
-DZIG_TARGET_MCPU="$MCPU" \
-DZIG_STATIC=ON \
-DZIG_NO_LIB=ON \
-GNinja
unset CC
unset CXX
ninja install
stage3/bin/zig test ../test/behavior.zig
stage3/bin/zig build -p stage4 \
-Dstatic-llvm \
-Dtarget=native-native-musl \
-Dno-lib \
--search-prefix "$PREFIX" \
--zig-lib-dir "$PWD/../lib"
stage4/bin/zig test ../test/behavior.zig

View File

@ -5,13 +5,19 @@
set -x
set -e
TARGET="x86_64-linux-musl"
ARCH="$(uname -m)"
TARGET="$ARCH-linux-musl"
MCPU="baseline"
CACHE_BASENAME="zig+llvm+lld+clang-$TARGET-0.16.0-dev.104+689461e31"
CACHE_BASENAME="zig+llvm+lld+clang-$TARGET-0.14.0-dev.1622+2ac543388"
PREFIX="$HOME/deps/$CACHE_BASENAME"
ZIG="$PREFIX/bin/zig"
export PATH="$HOME/deps/wasmtime-v38.0.3-x86_64-linux:$HOME/deps/qemu-linux-x86_64-10.1.1.1/bin:$HOME/local/bin:$PATH"
export PATH="$HOME/deps/wasmtime-v29.0.0-$ARCH-linux:$HOME/deps/qemu-linux-x86_64-9.2.0-rc1/bin:$HOME/local/bin:$PATH"
# Make the `zig version` number consistent.
# This will affect the cmake command below.
git fetch --unshallow || true
git fetch --tags
# Override the cache directories because they won't actually help other CI runs
# which will be testing alternate versions of zig, and ultimately would just
@ -62,8 +68,7 @@ stage3-release/bin/zig build test docs \
-Dtarget=native-native-musl \
--search-prefix "$PREFIX" \
--zig-lib-dir "$PWD/../lib" \
-Denable-superhtml \
--test-timeout 12m
-Denable-superhtml
# Ensure that stage3 and stage4 are byte-for-byte identical.
stage3-release/bin/zig build \

75
ci/x86_64-macos-release.sh Executable file
View File

@ -0,0 +1,75 @@
#!/bin/sh
set -x
set -e
ZIGDIR="$PWD"
TARGET="$ARCH-macos-none"
MCPU="baseline"
CACHE_BASENAME="zig+llvm+lld+clang-$TARGET-0.14.0-dev.1622+2ac543388"
PREFIX="$HOME/$CACHE_BASENAME"
JOBS="-j3"
ZIG="$PREFIX/bin/zig"
if [ ! -d "$PREFIX" ]; then
cd $HOME
curl -L -O "https://ziglang.org/deps/$CACHE_BASENAME.tar.xz"
tar xf "$CACHE_BASENAME.tar.xz"
fi
cd $ZIGDIR
# Make the `zig version` number consistent.
# This will affect the cmake command below.
git fetch --unshallow || true
git fetch --tags
# Override the cache directories because they won't actually help other CI runs
# which will be testing alternate versions of zig, and ultimately would just
# fill up space on the hard drive for no reason.
export ZIG_GLOBAL_CACHE_DIR="$PWD/zig-global-cache"
export ZIG_LOCAL_CACHE_DIR="$PWD/zig-local-cache"
# Test building from source without LLVM.
cc -o bootstrap bootstrap.c
./bootstrap
./zig2 build -Dno-lib
./zig-out/bin/zig test test/behavior.zig
mkdir build
cd build
cmake .. \
-DCMAKE_PREFIX_PATH="$PREFIX" \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_C_COMPILER="$ZIG;cc;-target;$TARGET;-mcpu=$MCPU" \
-DCMAKE_CXX_COMPILER="$ZIG;c++;-target;$TARGET;-mcpu=$MCPU" \
-DZIG_TARGET_TRIPLE="$TARGET" \
-DZIG_TARGET_MCPU="$MCPU" \
-DZIG_STATIC=ON \
-DZIG_NO_LIB=ON
make $JOBS install
stage3/bin/zig build test docs \
--zig-lib-dir "$PWD/../lib" \
-Denable-macos-sdk \
-Dstatic-llvm \
-Dskip-non-native \
--search-prefix "$PREFIX"
# Ensure that stage3 and stage4 are byte-for-byte identical.
stage3/bin/zig build \
--prefix stage4 \
-Denable-llvm \
-Dno-lib \
-Doptimize=ReleaseFast \
-Dstrip \
-Dtarget=$TARGET \
-Duse-zig-libcxx \
-Dversion-string="$(stage3/bin/zig version)"
# diff returns an error code if the files differ.
echo "If the following command fails, it means nondeterminism has been"
echo "introduced, making stage3 and stage4 no longer byte-for-byte identical."
diff stage3/bin/zig stage4/bin/zig

View File

@ -1,5 +1,5 @@
$TARGET = "x86_64-windows-gnu"
$ZIG_LLVM_CLANG_LLD_NAME = "zig+llvm+lld+clang-$TARGET-0.16.0-dev.104+689461e31"
$TARGET = "$($Env:ARCH)-windows-gnu"
$ZIG_LLVM_CLANG_LLD_NAME = "zig+llvm+lld+clang-$TARGET-0.14.0-dev.1622+2ac543388"
$MCPU = "baseline"
$ZIG_LLVM_CLANG_LLD_URL = "https://ziglang.org/deps/$ZIG_LLVM_CLANG_LLD_NAME.zip"
$PREFIX_PATH = "$($Env:USERPROFILE)\$ZIG_LLVM_CLANG_LLD_NAME"
@ -22,6 +22,14 @@ function CheckLastExitCode {
return 0
}
# Make the `zig version` number consistent.
# This will affect the `zig build` command below which uses `git describe`.
git fetch --tags
if ((git rev-parse --is-shallow-repository) -eq "true") {
git fetch --unshallow # `git describe` won't work on a shallow repo
}
# Override the cache directories because they won't actually help other CI runs
# which will be testing alternate versions of zig, and ultimately would just
# fill up space on the hard drive for no reason.
@ -59,9 +67,7 @@ Write-Output "Main test suite..."
-Dstatic-llvm `
-Dskip-non-native `
-Dskip-release `
-Dskip-test-incremental `
-Denable-symlinks-windows `
--test-timeout 30m
-Denable-symlinks-windows
CheckLastExitCode
Write-Output "Build x86_64-windows-msvc behavior tests using the C backend..."
@ -96,7 +102,7 @@ Enter-VsDevShell -VsInstallPath "C:\Program Files (x86)\Microsoft Visual Studio\
CheckLastExitCode
Write-Output "Build and run behavior tests with msvc..."
& cl.exe -I..\lib test-x86_64-windows-msvc.c compiler_rt-x86_64-windows-msvc.c /W3 /Z7 -link -nologo -debug -subsystem:console kernel32.lib ntdll.lib libcmt.lib ws2_32.lib
& cl.exe -I..\lib test-x86_64-windows-msvc.c compiler_rt-x86_64-windows-msvc.c /W3 /Z7 -link -nologo -debug -subsystem:console kernel32.lib ntdll.lib libcmt.lib
CheckLastExitCode
& .\test-x86_64-windows-msvc.exe

View File

@ -1,5 +1,5 @@
$TARGET = "x86_64-windows-gnu"
$ZIG_LLVM_CLANG_LLD_NAME = "zig+llvm+lld+clang-$TARGET-0.16.0-dev.104+689461e31"
$TARGET = "$($Env:ARCH)-windows-gnu"
$ZIG_LLVM_CLANG_LLD_NAME = "zig+llvm+lld+clang-$TARGET-0.14.0-dev.1622+2ac543388"
$MCPU = "baseline"
$ZIG_LLVM_CLANG_LLD_URL = "https://ziglang.org/deps/$ZIG_LLVM_CLANG_LLD_NAME.zip"
$PREFIX_PATH = "$($Env:USERPROFILE)\$ZIG_LLVM_CLANG_LLD_NAME"
@ -22,6 +22,14 @@ function CheckLastExitCode {
return 0
}
# Make the `zig version` number consistent.
# This will affect the `zig build` command below which uses `git describe`.
git fetch --tags
if ((git rev-parse --is-shallow-repository) -eq "true") {
git fetch --unshallow # `git describe` won't work on a shallow repo
}
# Override the cache directories because they won't actually help other CI runs
# which will be testing alternate versions of zig, and ultimately would just
# fill up space on the hard drive for no reason.
@ -58,9 +66,7 @@ Write-Output "Main test suite..."
--search-prefix "$PREFIX_PATH" `
-Dstatic-llvm `
-Dskip-non-native `
-Dskip-test-incremental `
-Denable-symlinks-windows `
--test-timeout 30m
-Denable-symlinks-windows
CheckLastExitCode
# Ensure that stage3 and stage4 are byte-for-byte identical.
@ -114,7 +120,7 @@ Enter-VsDevShell -VsInstallPath "C:\Program Files (x86)\Microsoft Visual Studio\
CheckLastExitCode
Write-Output "Build and run behavior tests with msvc..."
& cl.exe -I..\lib test-x86_64-windows-msvc.c compiler_rt-x86_64-windows-msvc.c /W3 /Z7 -link -nologo -debug -subsystem:console kernel32.lib ntdll.lib libcmt.lib ws2_32.lib
& cl.exe -I..\lib test-x86_64-windows-msvc.c compiler_rt-x86_64-windows-msvc.c /W3 /Z7 -link -nologo -debug -subsystem:console kernel32.lib ntdll.lib libcmt.lib
CheckLastExitCode
& .\test-x86_64-windows-msvc.exe

View File

@ -17,10 +17,10 @@ find_path(CLANG_INCLUDE_DIRS NAMES clang/Frontend/ASTUnit.h
if(${LLVM_LINK_MODE} STREQUAL "shared")
find_library(CLANG_LIBRARIES
NAMES
libclang-cpp.so.21
libclang-cpp.so.21.1
clang-cpp-21.0
clang-cpp210
libclang-cpp.so.19
libclang-cpp.so.19.1
clang-cpp-19.0
clang-cpp190
clang-cpp
NAMES_PER_DIR
HINTS "${LLVM_LIBDIRS}"
@ -60,6 +60,7 @@ else()
FIND_AND_ADD_CLANG_LIB(clangBasic)
FIND_AND_ADD_CLANG_LIB(clangEdit)
FIND_AND_ADD_CLANG_LIB(clangLex)
FIND_AND_ADD_CLANG_LIB(clangARCMigrate)
FIND_AND_ADD_CLANG_LIB(clangRewriteFrontend)
FIND_AND_ADD_CLANG_LIB(clangRewrite)
FIND_AND_ADD_CLANG_LIB(clangCrossTU)

View File

@ -9,23 +9,21 @@
find_path(LLD_INCLUDE_DIRS NAMES lld/Common/Driver.h
HINTS ${LLVM_INCLUDE_DIRS}
PATHS
/usr/lib/llvm-21/include
/usr/local/llvm210/include
/usr/local/llvm21/include
/usr/local/opt/lld@21/include
/opt/homebrew/opt/lld@21/include
/home/linuxbrew/.linuxbrew/opt/lld@21/include
/usr/lib/llvm-19/include
/usr/local/llvm190/include
/usr/local/llvm19/include
/usr/local/opt/llvm@19/include
/opt/homebrew/opt/llvm@19/include
/mingw64/include)
find_library(LLD_LIBRARY NAMES lld-21.0 lld210 lld NAMES_PER_DIR
find_library(LLD_LIBRARY NAMES lld-19.0 lld190 lld NAMES_PER_DIR
HINTS ${LLVM_LIBDIRS}
PATHS
/usr/lib/llvm-21/lib
/usr/local/llvm210/lib
/usr/local/llvm21/lib
/usr/local/opt/lld@21/lib
/opt/homebrew/opt/lld@21/lib
/home/linuxbrew/.linuxbrew/opt/lld@21/lib
/usr/lib/llvm-19/lib
/usr/local/llvm190/lib
/usr/local/llvm19/lib
/usr/local/opt/llvm@19/lib
/opt/homebrew/opt/llvm@19/lib
)
if(EXISTS ${LLD_LIBRARY})
set(LLD_LIBRARIES ${LLD_LIBRARY})
@ -36,12 +34,11 @@ else()
HINTS ${LLVM_LIBDIRS}
PATHS
${LLD_LIBDIRS}
/usr/lib/llvm-21/lib
/usr/local/llvm210/lib
/usr/local/llvm21/lib
/usr/local/opt/lld@21/lib
/opt/homebrew/opt/lld@21/lib
/home/linuxbrew/.linuxbrew/opt/lld@21/lib
/usr/lib/llvm-19/lib
/usr/local/llvm190/lib
/usr/local/llvm19/lib
/usr/local/opt/llvm@19/lib
/opt/homebrew/opt/llvm@19/lib
/mingw64/lib
/c/msys64/mingw64/lib
c:/msys64/mingw64/lib)

View File

@ -17,12 +17,12 @@ if(ZIG_USE_LLVM_CONFIG)
# terminate when the right LLVM version is not found.
unset(LLVM_CONFIG_EXE CACHE)
find_program(LLVM_CONFIG_EXE
NAMES llvm-config-21 llvm-config-21.0 llvm-config210 llvm-config21 llvm-config NAMES_PER_DIR
NAMES llvm-config-19 llvm-config-19.0 llvm-config190 llvm-config19 llvm-config NAMES_PER_DIR
PATHS
"/mingw64/bin"
"/c/msys64/mingw64/bin"
"c:/msys64/mingw64/bin"
"C:/Libraries/llvm-21.0.0/bin")
"C:/Libraries/llvm-19.0.0/bin")
if ("${LLVM_CONFIG_EXE}" STREQUAL "LLVM_CONFIG_EXE-NOTFOUND")
if (NOT LLVM_CONFIG_ERROR_MESSAGES STREQUAL "")
@ -40,9 +40,9 @@ if(ZIG_USE_LLVM_CONFIG)
OUTPUT_STRIP_TRAILING_WHITESPACE)
get_filename_component(LLVM_CONFIG_DIR "${LLVM_CONFIG_EXE}" DIRECTORY)
if("${LLVM_CONFIG_VERSION}" VERSION_LESS 21 OR "${LLVM_CONFIG_VERSION}" VERSION_EQUAL 22 OR "${LLVM_CONFIG_VERSION}" VERSION_GREATER 22)
if("${LLVM_CONFIG_VERSION}" VERSION_LESS 19 OR "${LLVM_CONFIG_VERSION}" VERSION_EQUAL 20 OR "${LLVM_CONFIG_VERSION}" VERSION_GREATER 20)
# Save the error message, in case this is the last llvm-config we find
list(APPEND LLVM_CONFIG_ERROR_MESSAGES "expected LLVM 21.x but found ${LLVM_CONFIG_VERSION} using ${LLVM_CONFIG_EXE}")
list(APPEND LLVM_CONFIG_ERROR_MESSAGES "expected LLVM 19.x but found ${LLVM_CONFIG_VERSION} using ${LLVM_CONFIG_EXE}")
# Ignore this directory and try the search again
list(APPEND CMAKE_IGNORE_PATH "${LLVM_CONFIG_DIR}")
@ -66,9 +66,9 @@ if(ZIG_USE_LLVM_CONFIG)
if (LLVM_CONFIG_ERROR)
# Save the error message, in case this is the last llvm-config we find
if (ZIG_SHARED_LLVM)
list(APPEND LLVM_CONFIG_ERROR_MESSAGES "LLVM 21.x found at ${LLVM_CONFIG_EXE} does not support linking as a shared library")
list(APPEND LLVM_CONFIG_ERROR_MESSAGES "LLVM 19.x found at ${LLVM_CONFIG_EXE} does not support linking as a shared library")
else()
list(APPEND LLVM_CONFIG_ERROR_MESSAGES "LLVM 21.x found at ${LLVM_CONFIG_EXE} does not support linking as a static library")
list(APPEND LLVM_CONFIG_ERROR_MESSAGES "LLVM 19.x found at ${LLVM_CONFIG_EXE} does not support linking as a static library")
endif()
# Ignore this directory and try the search again
@ -83,7 +83,7 @@ if(ZIG_USE_LLVM_CONFIG)
OUTPUT_STRIP_TRAILING_WHITESPACE)
string(REPLACE " " ";" LLVM_TARGETS_BUILT "${LLVM_TARGETS_BUILT_SPACES}")
set(ZIG_LLVM_REQUIRED_TARGETS "AArch64;AMDGPU;ARM;AVR;BPF;Hexagon;Lanai;LoongArch;Mips;MSP430;NVPTX;PowerPC;RISCV;SPIRV;Sparc;SystemZ;VE;WebAssembly;X86;XCore")
set(ZIG_LLVM_REQUIRED_TARGETS "AArch64;AMDGPU;ARM;AVR;BPF;Hexagon;Lanai;Mips;MSP430;NVPTX;PowerPC;RISCV;Sparc;SystemZ;VE;WebAssembly;X86;XCore")
set(ZIG_LLVM_REQUIRED_TARGETS_ENABLED TRUE)
foreach(TARGET_NAME IN LISTS ZIG_LLVM_REQUIRED_TARGETS)
@ -197,10 +197,10 @@ else()
FIND_AND_ADD_LLVM_LIB(LLVMXRay)
FIND_AND_ADD_LLVM_LIB(LLVMLibDriver)
FIND_AND_ADD_LLVM_LIB(LLVMDlltoolDriver)
FIND_AND_ADD_LLVM_LIB(LLVMTelemetry)
FIND_AND_ADD_LLVM_LIB(LLVMTextAPIBinaryReader)
FIND_AND_ADD_LLVM_LIB(LLVMCoverage)
FIND_AND_ADD_LLVM_LIB(LLVMLineEditor)
FIND_AND_ADD_LLVM_LIB(LLVMSandboxIR)
FIND_AND_ADD_LLVM_LIB(LLVMXCoreDisassembler)
FIND_AND_ADD_LLVM_LIB(LLVMXCoreCodeGen)
FIND_AND_ADD_LLVM_LIB(LLVMXCoreDesc)
@ -227,10 +227,6 @@ else()
FIND_AND_ADD_LLVM_LIB(LLVMSystemZCodeGen)
FIND_AND_ADD_LLVM_LIB(LLVMSystemZDesc)
FIND_AND_ADD_LLVM_LIB(LLVMSystemZInfo)
FIND_AND_ADD_LLVM_LIB(LLVMSPIRVCodeGen)
FIND_AND_ADD_LLVM_LIB(LLVMSPIRVDesc)
FIND_AND_ADD_LLVM_LIB(LLVMSPIRVInfo)
FIND_AND_ADD_LLVM_LIB(LLVMSPIRVAnalysis)
FIND_AND_ADD_LLVM_LIB(LLVMSparcDisassembler)
FIND_AND_ADD_LLVM_LIB(LLVMSparcAsmParser)
FIND_AND_ADD_LLVM_LIB(LLVMSparcCodeGen)
@ -315,34 +311,32 @@ else()
FIND_AND_ADD_LLVM_LIB(LLVMOrcTargetProcess)
FIND_AND_ADD_LLVM_LIB(LLVMOrcShared)
FIND_AND_ADD_LLVM_LIB(LLVMDWP)
FIND_AND_ADD_LLVM_LIB(LLVMDWARFCFIChecker)
FIND_AND_ADD_LLVM_LIB(LLVMDebugInfoLogicalView)
FIND_AND_ADD_LLVM_LIB(LLVMDebugInfoGSYM)
FIND_AND_ADD_LLVM_LIB(LLVMOption)
FIND_AND_ADD_LLVM_LIB(LLVMObjectYAML)
FIND_AND_ADD_LLVM_LIB(LLVMObjCopy)
FIND_AND_ADD_LLVM_LIB(LLVMMCA)
FIND_AND_ADD_LLVM_LIB(LLVMMCDisassembler)
FIND_AND_ADD_LLVM_LIB(LLVMLTO)
FIND_AND_ADD_LLVM_LIB(LLVMPasses)
FIND_AND_ADD_LLVM_LIB(LLVMHipStdPar)
FIND_AND_ADD_LLVM_LIB(LLVMCFGuard)
FIND_AND_ADD_LLVM_LIB(LLVMCoroutines)
FIND_AND_ADD_LLVM_LIB(LLVMipo)
FIND_AND_ADD_LLVM_LIB(LLVMVectorize)
FIND_AND_ADD_LLVM_LIB(LLVMLinker)
FIND_AND_ADD_LLVM_LIB(LLVMInstrumentation)
FIND_AND_ADD_LLVM_LIB(LLVMFrontendOpenMP)
FIND_AND_ADD_LLVM_LIB(LLVMFrontendOffloading)
FIND_AND_ADD_LLVM_LIB(LLVMFrontendOpenACC)
FIND_AND_ADD_LLVM_LIB(LLVMFrontendHLSL)
FIND_AND_ADD_LLVM_LIB(LLVMFrontendDriver)
FIND_AND_ADD_LLVM_LIB(LLVMExtensions)
FIND_AND_ADD_LLVM_LIB(LLVMPasses)
FIND_AND_ADD_LLVM_LIB(LLVMHipStdPar)
FIND_AND_ADD_LLVM_LIB(LLVMCoroutines)
FIND_AND_ADD_LLVM_LIB(LLVMCFGuard)
FIND_AND_ADD_LLVM_LIB(LLVMipo)
FIND_AND_ADD_LLVM_LIB(LLVMInstrumentation)
FIND_AND_ADD_LLVM_LIB(LLVMVectorize)
FIND_AND_ADD_LLVM_LIB(LLVMSandboxIR)
FIND_AND_ADD_LLVM_LIB(LLVMLinker)
FIND_AND_ADD_LLVM_LIB(LLVMFrontendOpenMP)
FIND_AND_ADD_LLVM_LIB(LLVMFrontendDirective)
FIND_AND_ADD_LLVM_LIB(LLVMFrontendAtomic)
FIND_AND_ADD_LLVM_LIB(LLVMFrontendOffloading)
FIND_AND_ADD_LLVM_LIB(LLVMObjectYAML)
FIND_AND_ADD_LLVM_LIB(LLVMDWARFLinkerParallel)
FIND_AND_ADD_LLVM_LIB(LLVMDWARFLinkerClassic)
FIND_AND_ADD_LLVM_LIB(LLVMDWARFLinker)
FIND_AND_ADD_LLVM_LIB(LLVMCodeGenData)
FIND_AND_ADD_LLVM_LIB(LLVMGlobalISel)
FIND_AND_ADD_LLVM_LIB(LLVMMIRParser)
FIND_AND_ADD_LLVM_LIB(LLVMAsmPrinter)
@ -351,7 +345,6 @@ else()
FIND_AND_ADD_LLVM_LIB(LLVMTarget)
FIND_AND_ADD_LLVM_LIB(LLVMObjCARCOpts)
FIND_AND_ADD_LLVM_LIB(LLVMCodeGenTypes)
FIND_AND_ADD_LLVM_LIB(LLVMCGData)
FIND_AND_ADD_LLVM_LIB(LLVMIRPrinter)
FIND_AND_ADD_LLVM_LIB(LLVMInterfaceStub)
FIND_AND_ADD_LLVM_LIB(LLVMFileCheck)
@ -367,16 +360,14 @@ else()
FIND_AND_ADD_LLVM_LIB(LLVMDebugInfoBTF)
FIND_AND_ADD_LLVM_LIB(LLVMDebugInfoPDB)
FIND_AND_ADD_LLVM_LIB(LLVMDebugInfoMSF)
FIND_AND_ADD_LLVM_LIB(LLVMDebugInfoCodeView)
FIND_AND_ADD_LLVM_LIB(LLVMDebugInfoGSYM)
FIND_AND_ADD_LLVM_LIB(LLVMDebugInfoDWARF)
FIND_AND_ADD_LLVM_LIB(LLVMDebugInfoDWARFLowLevel)
FIND_AND_ADD_LLVM_LIB(LLVMObject)
FIND_AND_ADD_LLVM_LIB(LLVMTextAPI)
FIND_AND_ADD_LLVM_LIB(LLVMMCParser)
FIND_AND_ADD_LLVM_LIB(LLVMIRReader)
FIND_AND_ADD_LLVM_LIB(LLVMAsmParser)
FIND_AND_ADD_LLVM_LIB(LLVMMC)
FIND_AND_ADD_LLVM_LIB(LLVMDebugInfoCodeView)
FIND_AND_ADD_LLVM_LIB(LLVMBitReader)
FIND_AND_ADD_LLVM_LIB(LLVMFuzzerCLI)
FIND_AND_ADD_LLVM_LIB(LLVMCore)

View File

@ -316,8 +316,7 @@
<a href="https://ziglang.org/documentation/0.11.0/">0.11.0</a> |
<a href="https://ziglang.org/documentation/0.12.0/">0.12.0</a> |
<a href="https://ziglang.org/documentation/0.13.0/">0.13.0</a> |
<a href="https://ziglang.org/documentation/0.14.1/">0.14.1</a> |
<a href="https://ziglang.org/documentation/0.15.2/">0.15.2</a> |
<a href="https://ziglang.org/documentation/0.14.0/">0.14.0</a> |
master
</nav>
<nav aria-labelledby="table-of-contents">
@ -375,8 +374,7 @@
<p>
Most of the time, it is more appropriate to write to stderr rather than stdout, and
whether or not the message is successfully written to the stream is irrelevant.
Also, formatted printing often comes in handy. For this common case,
there is a simpler API:
For this common case, there is a simpler API:
</p>
{#code|hello_again.zig#}
@ -421,7 +419,8 @@
{#code|unattached_doc-comment.zig#}
<p>
Doc comments can be interleaved with normal comments, which are ignored.
Doc comments can be interleaved with normal comments. Currently, when producing
the package documentation, normal comments are merged with doc comments.
</p>
{#header_close#}
{#header_open|Top-Level Doc Comments#}
@ -638,7 +637,7 @@
{#syntax#}i7{#endsyntax#} refers to a signed 7-bit integer. The maximum allowed bit-width of an
integer type is {#syntax#}65535{#endsyntax#}.
</p>
{#see_also|Integers|Floats|void|Errors|@Int#}
{#see_also|Integers|Floats|void|Errors|@Type#}
{#header_close#}
{#header_open|Primitive Values#}
<div class="table-wrapper">
@ -778,7 +777,7 @@
value. Using this value would be a bug. The value will be unused, or overwritten before being used."
</p>
<p>
In {#link|Debug#} and {#link|ReleaseSafe#} mode, Zig writes {#syntax#}0xaa{#endsyntax#} bytes to undefined memory. This is to catch
In {#link|Debug#} mode, Zig writes {#syntax#}0xaa{#endsyntax#} bytes to undefined memory. This is to catch
bugs early, and to help detect use of undefined memory in a debugger. However, this behavior is only an
implementation feature, not a language semantic, so it is not guaranteed to be observable to code.
</p>
@ -1650,7 +1649,6 @@ unwrapped == 1234{#endsyntax#}</pre>
<li>{#link|Floats#}</li>
<li>{#link|bool|Primitive Types#}</li>
<li>{#link|type|Primitive Types#}</li>
<li>{#link|packed struct#}</li>
</ul>
</td>
<td>
@ -1927,10 +1925,8 @@ or
Vector types are created with the builtin function {#link|@Vector#}.
</p>
<p>
Vectors generally support the same builtin operators as their underlying base types.
The only exception to this is the keywords `and` and `or` on vectors of bools, since
these operators affect control flow, which is not allowed for vectors.
All other operations are performed element-wise, and return a vector of the same length
Vectors support the same builtin operators as their underlying base types.
These operations are performed element-wise, and return a vector of the same length
as the input vectors. This includes:
</p>
<ul>
@ -1940,7 +1936,6 @@ or
<li>Bitwise operators ({#syntax#}>>{#endsyntax#}, {#syntax#}<<{#endsyntax#}, {#syntax#}&{#endsyntax#},
{#syntax#}|{#endsyntax#}, {#syntax#}~{#endsyntax#}, etc.)</li>
<li>Comparison operators ({#syntax#}<{#endsyntax#}, {#syntax#}>{#endsyntax#}, {#syntax#}=={#endsyntax#}, etc.)</li>
<li>Boolean not ({#syntax#}!{#endsyntax#})</li>
</ul>
<p>
It is prohibited to use a math operator on a mixture of scalars (individual numbers)
@ -1968,14 +1963,6 @@ or
</p>
{#see_also|@splat|@shuffle|@select|@reduce#}
{#header_open|Relationship with Arrays#}
<p>Vectors and {#link|Arrays#} each have a well-defined <strong>bit layout</strong>
and therefore support {#link|@bitCast#} between each other. {#link|Type Coercion#} implicitly peforms
{#syntax#}@bitCast{#endsyntax#}.</p>
<p>Arrays have well-defined byte layout, but vectors do not, making {#link|@ptrCast#} between
them {#link|Illegal Behavior#}.</p>
{#header_close#}
{#header_open|Destructuring Vectors#}
<p>
Vectors can be destructured:
@ -2237,24 +2224,20 @@ or
{#header_open|packed struct#}
<p>
{#syntax#}packed{#endsyntax#} structs, like {#syntax#}enum{#endsyntax#}, are based on the concept
of interpreting integers differently. All packed structs have a <strong>backing integer</strong>,
which is implicitly determined by the total bit count of fields, or explicitly specified.
Packed structs have well-defined memory layout - exactly the same ABI as their backing integer.
</p>
<p>
Each field of a packed struct is interpreted as a logical sequence of bits, arranged from
least to most significant. Allowed field types:
Unlike normal structs, {#syntax#}packed{#endsyntax#} structs have guaranteed in-memory layout:
</p>
<ul>
<li>An {#link|integer|Integers#} field uses exactly as many bits as its
bit width. For example, a {#syntax#}u5{#endsyntax#} will use 5 bits of
the backing integer.</li>
<li>A {#link|bool|Primitive Types#} field uses exactly 1 bit.</li>
<li>Fields remain in the order declared, least to most significant.</li>
<li>There is no padding between fields.</li>
<li>Zig supports arbitrary width {#link|Integers#} and although normally, integers with fewer
than 8 bits will still use 1 byte of memory, in packed structs, they use
exactly their bit width.
</li>
<li>{#syntax#}bool{#endsyntax#} fields use exactly 1 bit.</li>
<li>An {#link|enum#} field uses exactly the bit width of its integer tag type.</li>
<li>A {#link|packed union#} field uses exactly the bit width of the union field with
the largest bit width.</li>
<li>A {#syntax#}packed struct{#endsyntax#} field uses the bits of its backing integer.</li>
<li>Packed structs support equality operators.</li>
</ul>
<p>
This means that a {#syntax#}packed struct{#endsyntax#} can participate
@ -2262,11 +2245,10 @@ or
This even works at {#link|comptime#}:
</p>
{#code|test_packed_structs.zig#}
<p>
The backing integer can be inferred or explicitly provided. When
inferred, it will be unsigned. When explicitly provided, its bit width
will be enforced at compile time to exactly match the total bit width of
the fields:
The backing integer is inferred from the fields' total bit width.
Optionally, it can be explicitly provided and enforced at compile time:
</p>
{#code|test_missized_packed_struct.zig#}
@ -2308,18 +2290,18 @@ or
<p>
Equating packed structs results in a comparison of the backing integer,
and only works for the {#syntax#}=={#endsyntax#} and {#syntax#}!={#endsyntax#} {#link|Operators#}.
and only works for the `==` and `!=` operators.
</p>
{#code|test_packed_struct_equality.zig#}
<p>
Field access and assignment can be understood as shorthand for bitshifts
on the backing integer. These operations are not {#link|atomic|Atomics#},
so beware using field access syntax when combined with memory-mapped
input-output (MMIO). Instead of field access on {#link|volatile#} {#link|Pointers#},
construct a fully-formed new value first, then write that value to the volatile pointer.
Using packed structs with {#link|volatile#} is problematic, and may be a compile error in the future.
For details on this subscribe to
<a href="https://github.com/ziglang/zig/issues/1761">this issue</a>.
TODO update these docs with a recommendation on how to use packed structs with MMIO
(the use case for volatile packed structs) once this issue is resolved.
Don't worry, there will be a good solution for this use case in zig.
</p>
{#code|packed_struct_mmio.zig#}
{#header_close#}
{#header_open|Struct Naming#}
@ -2477,13 +2459,6 @@ or
</p>
{#code|test_union_method.zig#}
<p>
Unions with inferred enum tag types can also assign ordinal values to their inferred tag.
This requires the tag to specify an explicit integer type.
{#link|@intFromEnum#} can be used to access the ordinal value corresponding to the active field.
</p>
{#code|test_tagged_union_with_tag_values.zig#}
<p>
{#link|@tagName#} can be used to return a {#link|comptime#}
{#syntax#}[:0]const u8{#endsyntax#} value representing the field name:
@ -2503,7 +2478,6 @@ or
{#header_open|packed union#}
<p>A {#syntax#}packed union{#endsyntax#} has well-defined in-memory layout and is eligible
to be in a {#link|packed struct#}.</p>
<p>All fields in a packed union must have the same {#link|@bitSizeOf#}.</p>
{#header_close#}
{#header_open|Anonymous Union Literals#}
@ -3024,7 +2998,7 @@ or
{#syntax#}catch{#endsyntax#} after performing some logic, you
can combine {#syntax#}catch{#endsyntax#} with named {#link|Blocks#}:
</p>
{#code|handle_error_with_catch_block.zig#}
{#code|handle_error_with_catch_block.zig.zig#}
{#header_close#}
{#header_open|try#}
@ -3231,7 +3205,7 @@ fn createFoo(param: i32) !Foo {
to increase their development pace.
</p>
<p>
Error Return Traces are enabled by default in {#link|Debug#} builds and disabled by default in {#link|ReleaseFast#}, {#link|ReleaseSafe#} and {#link|ReleaseSmall#} builds.
Error Return Traces are enabled by default in {#link|Debug#} and {#link|ReleaseSafe#} builds and disabled by default in {#link|ReleaseFast#} and {#link|ReleaseSmall#} builds.
</p>
<p>
There are a few ways to activate this error return tracing feature:
@ -3705,27 +3679,27 @@ void do_a_thing(struct Foo *foo) {
<tr>
<th scope="row">{#syntax#}.{x}{#endsyntax#}</th>
<td>{#syntax#}T{#endsyntax#}</td>
<td>{#syntax#}x{#endsyntax#} is a {#syntax#}@FieldType(T, "0"){#endsyntax#}</td>
<td>{#syntax#}x{#endsyntax#} is a {#syntax#}std.meta.FieldType(T, .@"0"){#endsyntax#}</td>
</tr>
<tr>
<th scope="row">{#syntax#}.{ .a = x }{#endsyntax#}</th>
<td>{#syntax#}T{#endsyntax#}</td>
<td>{#syntax#}x{#endsyntax#} is a {#syntax#}@FieldType(T, "a"){#endsyntax#}</td>
<td>{#syntax#}x{#endsyntax#} is a {#syntax#}std.meta.FieldType(T, .a){#endsyntax#}</td>
</tr>
<tr>
<th scope="row">{#syntax#}T{x}{#endsyntax#}</th>
<td>-</td>
<td>{#syntax#}x{#endsyntax#} is a {#syntax#}@FieldType(T, "0"){#endsyntax#}</td>
<td>{#syntax#}x{#endsyntax#} is a {#syntax#}std.meta.FieldType(T, .@"0"){#endsyntax#}</td>
</tr>
<tr>
<th scope="row">{#syntax#}T{ .a = x }{#endsyntax#}</th>
<td>-</td>
<td>{#syntax#}x{#endsyntax#} is a {#syntax#}@FieldType(T, "a"){#endsyntax#}</td>
<td>{#syntax#}x{#endsyntax#} is a {#syntax#}std.meta.FieldType(T, .a){#endsyntax#}</td>
</tr>
<tr>
<th scope="row">{#syntax#}@Int(x, y){#endsyntax#}</th>
<th scope="row">{#syntax#}@Type(x){#endsyntax#}</th>
<td>-</td>
<td>{#syntax#}x{#endsyntax#} is a {#syntax#}std.builtin.Signedness{#endsyntax#}, {#syntax#}y{#endsyntax#} is a {#syntax#}u16{#endsyntax#}</td>
<td>{#syntax#}x{#endsyntax#} is a {#syntax#}std.builtin.Type{#endsyntax#}</td>
</tr>
<tr>
<th scope="row">{#syntax#}@typeInfo(x){#endsyntax#}</th>
@ -3839,9 +3813,9 @@ void do_a_thing(struct Foo *foo) {
<td>{#syntax#}x{#endsyntax#} has no result location (typed initializers do not propagate result locations)</td>
</tr>
<tr>
<th scope="row">{#syntax#}@Int(x, y){#endsyntax#}</th>
<td>-</td>
<td>{#syntax#}x{#endsyntax#} and {#syntax#}y{#endsyntax#} do not have result locations</td>
<th scope="row">{#syntax#}@Type(x){#endsyntax#}</th>
<td>{#syntax#}ptr{#endsyntax#}</td>
<td>{#syntax#}x{#endsyntax#} has no result location</td>
</tr>
<tr>
<th scope="row">{#syntax#}@typeInfo(x){#endsyntax#}</th>
@ -3859,6 +3833,37 @@ void do_a_thing(struct Foo *foo) {
{#header_close#}
{#header_close#}
{#header_open|usingnamespace#}
<p>
{#syntax#}usingnamespace{#endsyntax#} is a declaration that mixes all the public
declarations of the operand, which must be a {#link|struct#}, {#link|union#}, {#link|enum#},
or {#link|opaque#}, into the namespace:
</p>
{#code|test_usingnamespace.zig#}
<p>
{#syntax#}usingnamespace{#endsyntax#} has an important use case when organizing the public
API of a file or package. For example, one might have <code class="file">c.zig</code> with all of the
{#link|C imports|Import from C Header File#}:
</p>
{#syntax_block|zig|c.zig#}
pub usingnamespace @cImport({
@cInclude("epoxy/gl.h");
@cInclude("GLFW/glfw3.h");
@cDefine("STBI_ONLY_PNG", "");
@cDefine("STBI_NO_STDIO", "");
@cInclude("stb_image.h");
});
{#end_syntax_block#}
<p>
The above example demonstrates using {#syntax#}pub{#endsyntax#} to qualify the
{#syntax#}usingnamespace{#endsyntax#} additionally makes the imported declarations
{#syntax#}pub{#endsyntax#}. This can be used to forward declarations, giving precise control
over what declarations a given file exposes.
</p>
{#header_close#}
{#header_open|comptime#}
<p>
Zig places importance on the concept of whether an expression is known at compile-time.
@ -4265,9 +4270,16 @@ pub fn print(self: *Writer, arg0: []const u8, arg1: i32) !void {
{#header_close#}
{#header_open|Async Functions#}
<p>Async functions regressed with the release of 0.11.0. The current plan is to
reintroduce them as a lower level primitive that powers I/O implementations.</p>
<p>Tracking issue: <a href="https://github.com/ziglang/zig/issues/23446">Proposal: stackless coroutines as low-level primitives</a></p>
<p>Async functions regressed with the release of 0.11.0. Their future in
the Zig language is unclear due to multiple unsolved problems:</p>
<ul>
<li>LLVM's lack of ability to optimize them.</li>
<li>Third-party debuggers' lack of ability to debug them.</li>
<li><a href="https://github.com/ziglang/zig/issues/5913">The cancellation problem</a>.</li>
<li>Async function pointers preventing the stack size from being known.</li>
</ul>
<p>These problems are surmountable, but it will take time. The Zig team
is currently focused on other priorities.</p>
{#header_close#}
{#header_open|Builtin Functions|2col#}
@ -4335,7 +4347,7 @@ comptime {
</p>
<p>
{#syntax#}T{#endsyntax#} must be a pointer, a {#syntax#}bool{#endsyntax#}, a float,
an integer, an enum, or a packed struct.
an integer or an enum.
</p>
<p>{#syntax#}AtomicOrder{#endsyntax#} can be found with {#syntax#}@import("std").builtin.AtomicOrder{#endsyntax#}.</p>
{#see_also|@atomicStore|@atomicRmw||@cmpxchgWeak|@cmpxchgStrong#}
@ -4349,7 +4361,7 @@ comptime {
</p>
<p>
{#syntax#}T{#endsyntax#} must be a pointer, a {#syntax#}bool{#endsyntax#}, a float,
an integer, an enum, or a packed struct.
an integer or an enum.
</p>
<p>{#syntax#}AtomicOrder{#endsyntax#} can be found with {#syntax#}@import("std").builtin.AtomicOrder{#endsyntax#}.</p>
<p>{#syntax#}AtomicRmwOp{#endsyntax#} can be found with {#syntax#}@import("std").builtin.AtomicRmwOp{#endsyntax#}.</p>
@ -4363,7 +4375,7 @@ comptime {
</p>
<p>
{#syntax#}T{#endsyntax#} must be a pointer, a {#syntax#}bool{#endsyntax#}, a float,
an integer, an enum, or a packed struct.
an integer or an enum.
</p>
<p>{#syntax#}AtomicOrder{#endsyntax#} can be found with {#syntax#}@import("std").builtin.AtomicOrder{#endsyntax#}.</p>
{#see_also|@atomicLoad|@atomicRmw|@cmpxchgWeak|@cmpxchgStrong#}
@ -4592,8 +4604,8 @@ comptime {
more efficiently in machine instructions.
</p>
<p>
{#syntax#}T{#endsyntax#} must be a pointer, a {#syntax#}bool{#endsyntax#},
an integer, an enum, or a packed struct.
{#syntax#}T{#endsyntax#} must be a pointer, a {#syntax#}bool{#endsyntax#}, a float,
an integer or an enum.
</p>
<p>{#syntax#}@typeInfo(@TypeOf(ptr)).pointer.alignment{#endsyntax#} must be {#syntax#}>= @sizeOf(T).{#endsyntax#}</p>
<p>{#syntax#}AtomicOrder{#endsyntax#} can be found with {#syntax#}@import("std").builtin.AtomicOrder{#endsyntax#}.</p>
@ -4624,8 +4636,8 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
However if you need a stronger guarantee, use {#link|@cmpxchgStrong#}.
</p>
<p>
{#syntax#}T{#endsyntax#} must be a pointer, a {#syntax#}bool{#endsyntax#},
an integer, an enum, or a packed struct.
{#syntax#}T{#endsyntax#} must be a pointer, a {#syntax#}bool{#endsyntax#}, a float,
an integer or an enum.
</p>
<p>{#syntax#}@typeInfo(@TypeOf(ptr)).pointer.alignment{#endsyntax#} must be {#syntax#}>= @sizeOf(T).{#endsyntax#}</p>
<p>{#syntax#}AtomicOrder{#endsyntax#} can be found with {#syntax#}@import("std").builtin.AtomicOrder{#endsyntax#}.</p>
@ -4856,7 +4868,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
<p>
This builtin can be called from a {#link|comptime#} block to conditionally export symbols.
When <code>ptr</code> points to a function with the C calling convention and
{#syntax#}options.linkage{#endsyntax#} is {#syntax#}.strong{#endsyntax#}, this is equivalent to
{#syntax#}options.linkage{#endsyntax#} is {#syntax#}.Strong{#endsyntax#}, this is equivalent to
the {#syntax#}export{#endsyntax#} keyword used on a function:
</p>
{#code|export_builtin.zig#}
@ -4896,8 +4908,8 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
{#header_open|@fieldParentPtr#}
<pre>{#syntax#}@fieldParentPtr(comptime field_name: []const u8, field_ptr: *T) anytype{#endsyntax#}</pre>
<p>
Given a pointer to a struct or union field, returns a pointer to the struct or union containing that field.
The return type (pointer to the parent struct or union in question) is the inferred result type.
Given a pointer to a struct field, returns a pointer to the struct containing that field.
The return type (and struct in question) is the inferred result type.
</p>
<p>
If {#syntax#}field_ptr{#endsyntax#} does not point to the {#syntax#}field_name{#endsyntax#} field of an instance of
@ -4968,25 +4980,34 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
{#header_close#}
{#header_open|@import#}
<pre>{#syntax#}@import(comptime target: []const u8) anytype{#endsyntax#}</pre>
<p>Imports the file at {#syntax#}target{#endsyntax#}, adding it to the compilation if it is not already
added. {#syntax#}target{#endsyntax#} is either a relative path to another file from the file containing
the {#syntax#}@import{#endsyntax#} call, or it is the name of a {#link|module|Compilation Model#}, with
the import referring to the root source file of that module. Either way, the file path must end in
either <code>.zig</code> (for a Zig source file) or <code>.zon</code> (for a ZON data file).</p>
<p>If {#syntax#}target{#endsyntax#} refers to a Zig source file, then {#syntax#}@import{#endsyntax#} returns
that file's {#link|corresponding struct type|Source File Structs#}, essentially as if the builtin call was
replaced by {#syntax#}struct { FILE_CONTENTS }{#endsyntax#}. The return type is {#syntax#}type{#endsyntax#}.</p>
<p>If {#syntax#}target{#endsyntax#} refers to a ZON file, then {#syntax#}@import{#endsyntax#} returns the value
of the literal in the file. If there is an inferred {#link|result type|Result Types#}, then the return type
is that type, and the ZON literal is interpreted as that type ({#link|Result Types#} are propagated through
the ZON expression). Otherwise, the return type is the type of the equivalent Zig expression, essentially as
if the builtin call was replaced by the ZON file contents.</p>
<p>The following modules are always available for import:</p>
<pre>{#syntax#}@import(comptime path: []const u8) type{#endsyntax#}</pre>
<p>
This function finds a zig file corresponding to {#syntax#}path{#endsyntax#} and adds it to the build,
if it is not already added.
</p>
<p>
Zig source files are implicitly structs, with a name equal to the file's basename with the extension
truncated. {#syntax#}@import{#endsyntax#} returns the struct type corresponding to the file.
</p>
<p>
Declarations which have the {#syntax#}pub{#endsyntax#} keyword may be referenced from a different
source file than the one they are declared in.
</p>
<p>
{#syntax#}path{#endsyntax#} can be a relative path or it can be the name of a package.
If it is a relative path, it is relative to the file that contains the {#syntax#}@import{#endsyntax#}
function call.
</p>
<p>
The following packages are always available:
</p>
<ul>
<li>{#syntax#}@import("std"){#endsyntax#} - Zig Standard Library</li>
<li>{#syntax#}@import("builtin"){#endsyntax#} - Target-specific information. The command <code>zig build-exe --show-builtin</code> outputs the source to stdout for reference.</li>
<li>{#syntax#}@import("root"){#endsyntax#} - Alias for the root module. In typical project structures, this means it refers back to <code>src/main.zig</code>.
<li>{#syntax#}@import("builtin"){#endsyntax#} - Target-specific information
The command <code>zig build-exe --show-builtin</code> outputs the source to stdout for reference.
</li>
<li>{#syntax#}@import("root"){#endsyntax#} - Root source file
This is usually <code>src/main.zig</code> but depends on what file is built.
</li>
</ul>
{#see_also|Compile Variables|@embedFile#}
@ -5122,23 +5143,6 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
{#syntax#}std.crypto.secureZero{#endsyntax#}</p>
{#header_close#}
{#header_open|@memmove#}
<pre>{#syntax#}@memmove(dest, source) void{#endsyntax#}</pre>
<p>This function copies bytes from one region of memory to another, but unlike
{#link|@memcpy#} the regions may overlap.</p>
<p>{#syntax#}dest{#endsyntax#} must be a mutable slice, a mutable pointer to an array, or
a mutable many-item {#link|pointer|Pointers#}. It may have any
alignment, and it may have any element type.</p>
<p>{#syntax#}source{#endsyntax#} must be a slice, a pointer to
an array, or a many-item {#link|pointer|Pointers#}. It may
have any alignment, and it may have any element type.</p>
<p>The {#syntax#}source{#endsyntax#} element type must have the same in-memory
representation as the {#syntax#}dest{#endsyntax#} element type.</p>
<p>Similar to {#link|for#} loops, at least one of {#syntax#}source{#endsyntax#} and
{#syntax#}dest{#endsyntax#} must provide a length, and if two lengths are provided,
they must be equal.</p>
{#header_close#}
{#header_open|@min#}
<pre>{#syntax#}@min(...) T{#endsyntax#}</pre>
<p>
@ -5186,7 +5190,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
<pre>{#syntax#}@mod(numerator: T, denominator: T) T{#endsyntax#}</pre>
<p>
Modulus division. For unsigned integers this is the same as
{#syntax#}numerator % denominator{#endsyntax#}. Caller guarantees {#syntax#}denominator != 0{#endsyntax#}, otherwise the
{#syntax#}numerator % denominator{#endsyntax#}. Caller guarantees {#syntax#}denominator > 0{#endsyntax#}, otherwise the
operation will result in a {#link|Remainder Division by Zero#} when runtime safety checks are enabled.
</p>
<ul>
@ -5291,7 +5295,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
<pre>{#syntax#}@rem(numerator: T, denominator: T) T{#endsyntax#}</pre>
<p>
Remainder division. For unsigned integers this is the same as
{#syntax#}numerator % denominator{#endsyntax#}. Caller guarantees {#syntax#}denominator != 0{#endsyntax#}, otherwise the
{#syntax#}numerator % denominator{#endsyntax#}. Caller guarantees {#syntax#}denominator > 0{#endsyntax#}, otherwise the
operation will result in a {#link|Remainder Division by Zero#} when runtime safety checks are enabled.
</p>
<ul>
@ -5494,9 +5498,8 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
{#header_open|@splat#}
<pre>{#syntax#}@splat(scalar: anytype) anytype{#endsyntax#}</pre>
<p>
Produces an array or vector where each element is the value
{#syntax#}scalar{#endsyntax#}. The return type and thus the length of the
vector is inferred.
Produces a vector where each element is the value {#syntax#}scalar{#endsyntax#}.
The return type and thus the length of the vector is inferred.
</p>
{#code|test_splat_builtin.zig#}
@ -5755,75 +5758,41 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
</p>
{#header_close#}
{#header_open|@EnumLiteral#}
<pre>{#syntax#}@EnumLiteral() type{#endsyntax#}</pre>
<p>Returns the comptime-only "enum literal" type. This is the type of uncoerced {#link|Enum Literals#}. Values of this type can coerce to any {#link|enum#} with a matching field.</p>
{#header_open|@Type#}
<pre>{#syntax#}@Type(comptime info: std.builtin.Type) type{#endsyntax#}</pre>
<p>
This function is the inverse of {#link|@typeInfo#}. It reifies type information
into a {#syntax#}type{#endsyntax#}.
</p>
<p>
It is available for the following types:
</p>
<ul>
<li>{#syntax#}type{#endsyntax#}</li>
<li>{#syntax#}noreturn{#endsyntax#}</li>
<li>{#syntax#}void{#endsyntax#}</li>
<li>{#syntax#}bool{#endsyntax#}</li>
<li>{#link|Integers#} - The maximum bit count for an integer type is {#syntax#}65535{#endsyntax#}.</li>
<li>{#link|Floats#}</li>
<li>{#link|Pointers#}</li>
<li>{#syntax#}comptime_int{#endsyntax#}</li>
<li>{#syntax#}comptime_float{#endsyntax#}</li>
<li>{#syntax#}@TypeOf(undefined){#endsyntax#}</li>
<li>{#syntax#}@TypeOf(null){#endsyntax#}</li>
<li>{#link|Arrays#}</li>
<li>{#link|Optionals#}</li>
<li>{#link|Error Set Type#}</li>
<li>{#link|Error Union Type#}</li>
<li>{#link|Vectors#}</li>
<li>{#link|opaque#}</li>
<li>{#syntax#}anyframe{#endsyntax#}</li>
<li>{#link|struct#}</li>
<li>{#link|enum#}</li>
<li>{#link|Enum Literals#}</li>
<li>{#link|union#}</li>
<li>{#link|Functions#}</li>
</ul>
{#header_close#}
{#header_open|@Int#}
<pre>{#syntax#}@Int(comptime signedness: std.builtin.Signedness, comptime bits: u16) type{#endsyntax#}</pre>
<p>Returns an integer type with the given signedness and bit width.</p>
<p>For instance, {#syntax#}@Int(.unsigned, 18){#endsyntax#} returns the type {#syntax#}u18{#endsyntax#}.</p>
{#header_close#}
{#header_open|@Tuple#}
<pre>{#syntax#}@Tuple(comptime field_types: []const type) type{#endsyntax#}</pre>
<p>Returns a {#link|tuple|Tuples#} type with the given field types.</p>
{#header_close#}
{#header_open|@Pointer#}
<pre>{#syntax#}@Pointer(
comptime size: std.builtin.Type.Pointer.Size,
comptime attrs: std.builtin.Type.Pointer.Attributes,
comptime Element: type,
comptime sentinel: ?Element,
) type{#endsyntax#}</pre>
<p>Returns a {#link|pointer|Pointers#} type with the properties specified by the arguments.</p>
{#header_close#}
{#header_open|@Fn#}
<pre>{#syntax#}@Fn(
comptime param_types: []const type,
comptime param_attrs: *const [param_types.len]std.builtin.Type.Fn.Param.Attributes,
comptime ReturnType: type,
comptime attrs: std.builtin.Type.Fn.Attributes,
) type{#endsyntax#}</pre>
<p>Returns a {#link|function|Functions#} type with the properties specified by the arguments.</p>
{#header_close#}
{#header_open|@Struct#}
<pre>{#syntax#}@Struct(
comptime layout: std.builtin.Type.ContainerLayout,
comptime BackingInt: ?type,
comptime field_names: []const []const u8,
comptime field_types: *const [field_names.len]type,
comptime field_attrs: *const [field_names.len]std.builtin.Type.StructField.Attributes,
) type{#endsyntax#}</pre>
<p>Returns a {#link|struct#} type with the properties specified by the arguments.</p>
{#header_close#}
{#header_open|@Union#}
<pre>{#syntax#}@Union(
comptime layout: std.builtin.Type.ContainerLayout,
/// Either the integer tag type, or the integer backing type, depending on `layout`.
comptime ArgType: ?type,
comptime field_names: []const []const u8,
comptime field_types: *const [field_names.len]type,
comptime field_attrs: *const [field_names.len]std.builtin.Type.UnionField.Attributes,
) type{#endsyntax#}</pre>
<p>Returns a {#link|union#} type with the properties specified by the arguments.</p>
{#header_close#}
{#header_open|@Enum#}
<pre>{#syntax#}@Enum(
comptime TagInt: type,
comptime mode: std.builtin.Type.Enum.Mode,
comptime field_names: []const []const u8,
comptime field_values: *const [field_names.len]TagInt,
) type{#endsyntax#}</pre>
<p>Returns an {#link|enum#} type with the properties specified by the arguments.</p>
{#header_close#}
{#header_open|@typeInfo#}
<pre>{#syntax#}@typeInfo(comptime T: type) std.builtin.Type{#endsyntax#}</pre>
<p>
@ -6127,7 +6096,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
{#header_close#}
{#header_open|Exact Left Shift Overflow#}
<p>At compile-time:</p>
{#code|test_comptime_shlExact_overflow.zig#}
{#code|test_comptime_shlExact_overwlow.zig#}
<p>At runtime:</p>
{#code|runtime_shlExact_overflow.zig#}
@ -6291,8 +6260,9 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
C has a default allocator - <code>malloc</code>, <code>realloc</code>, and <code>free</code>.
When linking against libc, Zig exposes this allocator with {#syntax#}std.heap.c_allocator{#endsyntax#}.
However, by convention, there is no default allocator in Zig. Instead, functions which need to
allocate accept an {#syntax#}Allocator{#endsyntax#} parameter. Likewise, some data structures
accept an {#syntax#}Allocator{#endsyntax#} parameter in their initialization functions:
allocate accept an {#syntax#}Allocator{#endsyntax#} parameter. Likewise, data structures such as
{#syntax#}std.ArrayList{#endsyntax#} accept an {#syntax#}Allocator{#endsyntax#} parameter in
their initialization functions:
</p>
{#code|test_allocator.zig#}
@ -6319,6 +6289,10 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
</li>
<li>Are you linking libc? In this case, {#syntax#}std.heap.c_allocator{#endsyntax#} is likely
the right choice, at least for your main allocator.</li>
<li>
Need to use the same allocator in multiple threads? Use one of your choice
wrapped around {#syntax#}std.heap.ThreadSafeAllocator{#endsyntax#}
</li>
<li>
Is the maximum number of bytes that you will need bounded by a number known at
{#link|comptime#}? In this case, use {#syntax#}std.heap.FixedBufferAllocator{#endsyntax#}.
@ -6351,18 +6325,14 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
</li>
<li>
Finally, if none of the above apply, you need a general purpose allocator.
If you are in Debug mode, {#syntax#}std.heap.DebugAllocator{#endsyntax#} is available as a
function that takes a {#link|comptime#} {#link|struct#} of configuration options and returns a type.
Generally, you will set up exactly one in your main function, and
then pass it or sub-allocators around to various parts of your
Zig's general purpose allocator is available as a function that takes a {#link|comptime#}
{#link|struct#} of configuration options and returns a type.
Generally, you will set up one {#syntax#}std.heap.GeneralPurposeAllocator{#endsyntax#} in
your main function, and then pass it or sub-allocators around to various parts of your
application.
</li>
<li>
If you are compiling in ReleaseFast mode, {#syntax#}std.heap.smp_allocator{#endsyntax#} is
a solid choice for a general purpose allocator.
</li>
<li>
You can also consider implementing an allocator.
You can also consider {#link|Implementing an Allocator#}.
</li>
</ol>
{#header_close#}
@ -6397,6 +6367,17 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
<p>TODO: thread local variables</p>
{#header_close#}
{#header_open|Implementing an Allocator#}
<p>Zig programmers can implement their own allocators by fulfilling the Allocator interface.
In order to do this one must read carefully the documentation comments in std/mem.zig and
then supply a {#syntax#}allocFn{#endsyntax#} and a {#syntax#}resizeFn{#endsyntax#}.
</p>
<p>
There are many example allocators to look at for inspiration. Look at std/heap.zig and
{#syntax#}std.heap.GeneralPurposeAllocator{#endsyntax#}.
</p>
{#header_close#}
{#header_open|Heap Allocation Failure#}
<p>
Many programming languages choose to handle the possibility of heap allocation failure by
@ -6544,7 +6525,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
</p>
<ul>
<li>If a call to {#syntax#}@import{#endsyntax#} is analyzed, the file being imported is analyzed.</li>
<li>If a type (including a file) is analyzed, all {#syntax#}comptime{#endsyntax#} and {#syntax#}export{#endsyntax#} declarations within it are analyzed.</li>
<li>If a type (including a file) is analyzed, all {#syntax#}comptime{#endsyntax#}, {#syntax#}usingnamespace{#endsyntax#}, and {#syntax#}export{#endsyntax#} declarations within it are analyzed.</li>
<li>If a type (including a file) is analyzed, and the compilation is for a {#link|test|Zig Test#}, and the module the type is within is the root module of the compilation, then all {#syntax#}test{#endsyntax#} declarations within it are also analyzed.</li>
<li>If a reference to a named declaration (i.e. a usage of it) is analyzed, the declaration being referenced is analyzed. Declarations are order-independent, so this reference may be above or below the declaration being referenced, or even in another file entirely.</li>
</ul>
@ -7138,12 +7119,10 @@ coding style.
</p>
<ul>
<li>
If {#syntax#}x{#endsyntax#} is a {#syntax#}struct{#endsyntax#} with 0 fields and is never meant to be instantiated
then {#syntax#}x{#endsyntax#} is considered to be a "namespace" and should be {#syntax#}snake_case{#endsyntax#}.
</li>
<li>
If {#syntax#}x{#endsyntax#} is a {#syntax#}type{#endsyntax#} or {#syntax#}type{#endsyntax#} alias
then {#syntax#}x{#endsyntax#} should be {#syntax#}TitleCase{#endsyntax#}.
If {#syntax#}x{#endsyntax#} is a {#syntax#}type{#endsyntax#}
then {#syntax#}x{#endsyntax#} should be {#syntax#}TitleCase{#endsyntax#}, unless it
is a {#syntax#}struct{#endsyntax#} with 0 fields and is never meant to be instantiated,
in which case it is considered to be a "namespace" and uses {#syntax#}snake_case{#endsyntax#}.
</li>
<li>
If {#syntax#}x{#endsyntax#} is callable, and {#syntax#}x{#endsyntax#}'s return type is
@ -7182,7 +7161,8 @@ const namespace_name = @import("dir_name/file_name.zig");
const TypeName = @import("dir_name/TypeName.zig");
var global_var: i32 = undefined;
const const_name = 42;
const PrimitiveTypeAlias = f32;
const primitive_type_alias = f32;
const string_alias = []u8;
const StructName = struct {
field: i32,
@ -7365,6 +7345,29 @@ fn readU32Be() u32 {}
</ul>
</td>
</tr>
<tr>
<th scope="row">
<pre>{#syntax#}async{#endsyntax#}</pre>
</th>
<td>
{#syntax#}async{#endsyntax#} can be used before a function call to get a pointer to the function's frame when it suspends.
<ul>
<li>See also {#link|Async Functions#}</li>
</ul>
</td>
</tr>
<tr>
<th scope="row">
<pre>{#syntax#}await{#endsyntax#}</pre>
</th>
<td>
{#syntax#}await{#endsyntax#} can be used to suspend the current function until the frame provided after the {#syntax#}await{#endsyntax#} completes.
{#syntax#}await{#endsyntax#} copies the value returned from the target function's frame to the caller.
<ul>
<li>See also {#link|Async Functions#}</li>
</ul>
</td>
</tr>
<tr>
<th scope="row">
<pre>{#syntax#}break{#endsyntax#}</pre>
@ -7782,6 +7785,18 @@ fn readU32Be() u32 {}
</ul>
</td>
</tr>
<tr>
<th scope="row">
<pre>{#syntax#}usingnamespace{#endsyntax#}</pre>
</th>
<td>
{#syntax#}usingnamespace{#endsyntax#} is a top-level declaration that imports all the public declarations of the operand,
which must be a struct, union, or enum, into the current scope.
<ul>
<li>See also {#link|usingnamespace#}</li>
</ul>
</td>
</tr>
<tr>
<th scope="row">
<pre>{#syntax#}var{#endsyntax#}</pre>
@ -7836,11 +7851,11 @@ fn readU32Be() u32 {}
{#header_close#}
{#header_open|Grammar#}
{#syntax_block|peg|grammar.peg#}
Root <- skip ContainerMembers eof
{#syntax_block|peg|grammar.y#}
Root <- skip container_doc_comment? ContainerMembers eof
# *** Top level ***
ContainerMembers <- container_doc_comment? ContainerDeclaration* (ContainerField COMMA)* (ContainerField / ContainerDeclaration*)
ContainerMembers <- ContainerDeclaration* (ContainerField COMMA)* (ContainerField / ContainerDeclaration*)
ContainerDeclaration <- TestDecl / ComptimeDecl / doc_comment? KEYWORD_pub? Decl
@ -7851,6 +7866,7 @@ ComptimeDecl <- KEYWORD_comptime Block
Decl
<- (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE? / KEYWORD_inline / KEYWORD_noinline)? FnProto (SEMICOLON / Block)
/ (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE?)? KEYWORD_threadlocal? GlobalVarDecl
/ KEYWORD_usingnamespace Expr SEMICOLON
FnProto <- KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? AddrSpace? LinkSection? CallConv? EXCLAMATIONMARK? TypeExpr
@ -7869,6 +7885,7 @@ Statement
/ KEYWORD_errdefer Payload? BlockExprStatement
/ IfStatement
/ LabeledStatement
/ SwitchExpr
/ VarDeclExprStatement
ComptimeStatement
@ -7879,7 +7896,7 @@ IfStatement
<- IfPrefix BlockExpr ( KEYWORD_else Payload? Statement )?
/ IfPrefix AssignExpr ( SEMICOLON / KEYWORD_else Payload? Statement )
LabeledStatement <- BlockLabel? (Block / LoopStatement / SwitchExpr)
LabeledStatement <- BlockLabel? (Block / LoopStatement)
LoopStatement <- KEYWORD_inline? (ForStatement / WhileStatement)
@ -7933,7 +7950,7 @@ PrimaryExpr
/ KEYWORD_break BreakLabel? Expr?
/ KEYWORD_comptime Expr
/ KEYWORD_nosuspend Expr
/ KEYWORD_continue BreakLabel? Expr?
/ KEYWORD_continue BreakLabel?
/ KEYWORD_resume Expr
/ KEYWORD_return Expr?
/ BlockLabel? LoopExpr
@ -7962,7 +7979,8 @@ TypeExpr <- PrefixTypeOp* ErrorUnionExpr
ErrorUnionExpr <- SuffixExpr (EXCLAMATIONMARK TypeExpr)?
SuffixExpr
<- PrimaryTypeExpr (SuffixOp / FnCallArguments)*
<- KEYWORD_async PrimaryTypeExpr SuffixOp* FnCallArguments
/ PrimaryTypeExpr (SuffixOp / FnCallArguments)*
PrimaryTypeExpr
<- BUILTINIDENTIFIER FnCallArguments
@ -7983,6 +8001,7 @@ PrimaryTypeExpr
/ KEYWORD_anyframe
/ KEYWORD_unreachable
/ STRINGLITERAL
/ SwitchExpr
ContainerDecl <- (KEYWORD_extern / KEYWORD_packed)? ContainerDeclAuto
@ -7995,7 +8014,6 @@ IfTypeExpr <- IfPrefix TypeExpr (KEYWORD_else Payload? TypeExpr)?
LabeledTypeExpr
<- BlockLabel Block
/ BlockLabel? LoopTypeExpr
/ BlockLabel? SwitchExpr
LoopTypeExpr <- KEYWORD_inline? (ForTypeExpr / WhileTypeExpr)
@ -8016,7 +8034,7 @@ AsmInput <- COLON AsmInputList AsmClobbers?
AsmInputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN Expr RPAREN
AsmClobbers <- COLON Expr
AsmClobbers <- COLON StringList
# *** Helper grammar ***
BreakLabel <- COLON IDENTIFIER
@ -8138,6 +8156,7 @@ PrefixOp
/ MINUSPERCENT
/ AMPERSAND
/ KEYWORD_try
/ KEYWORD_await
PrefixTypeOp
<- QUESTIONMARK
@ -8165,7 +8184,7 @@ PtrTypeStart
ArrayTypeStart <- LBRACKET Expr (COLON Expr)? RBRACKET
# ContainerDecl specific
ContainerDeclAuto <- ContainerDeclType LBRACE ContainerMembers RBRACE
ContainerDeclAuto <- ContainerDeclType LBRACE container_doc_comment? ContainerMembers RBRACE
ContainerDeclType
<- KEYWORD_struct (LPAREN Expr RPAREN)?
@ -8185,6 +8204,8 @@ AsmOutputList <- (AsmOutputItem COMMA)* AsmOutputItem?
AsmInputList <- (AsmInputItem COMMA)* AsmInputItem?
StringList <- (STRINGLITERAL COMMA)* STRINGLITERAL?
ParamDeclList <- (ParamDecl COMMA)* ParamDecl?
ExprList <- (Expr COMMA)* Expr?
@ -8231,7 +8252,7 @@ oxC2_oxDF <- [\302-\337]
# [0xF1,0xF3] [0x80,0xBF] [0x80,0xBF] [0x80,0xBF]
# 0xF4 [0x80,0x8F] [0x80,0xBF] [0x80,0xBF]
multibyte_utf8 <-
mb_utf8_literal <-
oxF4 ox80_ox8F ox80_oxBF ox80_oxBF
/ oxF1_oxF3 ox80_oxBF ox80_oxBF ox80_oxBF
/ oxF0 ox90_0xBF ox80_oxBF ox80_oxBF
@ -8241,47 +8262,46 @@ multibyte_utf8 <-
/ oxE0 oxA0_oxBF ox80_oxBF
/ oxC2_oxDF ox80_oxBF
non_control_ascii <- [\040-\176]
ascii_char_not_nl_slash_squote <- [\000-\011\013-\046\050-\133\135-\177]
char_escape
<- "\\x" hex hex
/ "\\u{" hex+ "}"
/ "\\" [nr\\t'"]
char_char
<- multibyte_utf8
<- mb_utf8_literal
/ char_escape
/ ![\\'\n] non_control_ascii
/ ascii_char_not_nl_slash_squote
string_char
<- multibyte_utf8
/ char_escape
/ ![\\"\n] non_control_ascii
<- char_escape
/ [^\\"\n]
container_doc_comment <- ('//!' [^\n]* [ \n]* skip)+
doc_comment <- ('///' [^\n]* [ \n]* skip)+
line_comment <- '//' ![!/][^\n]* / '////' [^\n]*
line_string <- ('\\\\' [^\n]* [ \n]*)+
line_string <- ("\\\\" [^\n]* [ \n]*)+
skip <- ([ \n] / line_comment)*
CHAR_LITERAL <- ['] char_char ['] skip
CHAR_LITERAL <- "'" char_char "'" skip
FLOAT
<- '0x' hex_int '.' hex_int ([pP] [-+]? dec_int)? skip
/ dec_int '.' dec_int ([eE] [-+]? dec_int)? skip
/ '0x' hex_int [pP] [-+]? dec_int skip
<- "0x" hex_int "." hex_int ([pP] [-+]? dec_int)? skip
/ dec_int "." dec_int ([eE] [-+]? dec_int)? skip
/ "0x" hex_int [pP] [-+]? dec_int skip
/ dec_int [eE] [-+]? dec_int skip
INTEGER
<- '0b' bin_int skip
/ '0o' oct_int skip
/ '0x' hex_int skip
<- "0b" bin_int skip
/ "0o" oct_int skip
/ "0x" hex_int skip
/ dec_int skip
STRINGLITERALSINGLE <- ["] string_char* ["] skip
STRINGLITERALSINGLE <- "\"" string_char* "\"" skip
STRINGLITERAL
<- STRINGLITERALSINGLE
/ (line_string skip)+
IDENTIFIER
<- !keyword [A-Za-z_] [A-Za-z0-9_]* skip
/ '@' STRINGLITERALSINGLE
BUILTINIDENTIFIER <- '@'[A-Za-z_][A-Za-z0-9_]* skip
/ "@" STRINGLITERALSINGLE
BUILTINIDENTIFIER <- "@"[A-Za-z_][A-Za-z0-9_]* skip
AMPERSAND <- '&' ![=] skip
@ -8357,6 +8377,8 @@ KEYWORD_and <- 'and' end_of_word
KEYWORD_anyframe <- 'anyframe' end_of_word
KEYWORD_anytype <- 'anytype' end_of_word
KEYWORD_asm <- 'asm' end_of_word
KEYWORD_async <- 'async' end_of_word
KEYWORD_await <- 'await' end_of_word
KEYWORD_break <- 'break' end_of_word
KEYWORD_callconv <- 'callconv' end_of_word
KEYWORD_catch <- 'catch' end_of_word
@ -8393,13 +8415,14 @@ KEYWORD_threadlocal <- 'threadlocal' end_of_word
KEYWORD_try <- 'try' end_of_word
KEYWORD_union <- 'union' end_of_word
KEYWORD_unreachable <- 'unreachable' end_of_word
KEYWORD_usingnamespace <- 'usingnamespace' end_of_word
KEYWORD_var <- 'var' end_of_word
KEYWORD_volatile <- 'volatile' end_of_word
KEYWORD_while <- 'while' end_of_word
keyword <- KEYWORD_addrspace / KEYWORD_align / KEYWORD_allowzero / KEYWORD_and
/ KEYWORD_anyframe / KEYWORD_anytype / KEYWORD_asm
/ KEYWORD_break / KEYWORD_callconv / KEYWORD_catch
/ KEYWORD_anyframe / KEYWORD_anytype / KEYWORD_asm / KEYWORD_async
/ KEYWORD_await / KEYWORD_break / KEYWORD_callconv / KEYWORD_catch
/ KEYWORD_comptime / KEYWORD_const / KEYWORD_continue / KEYWORD_defer
/ KEYWORD_else / KEYWORD_enum / KEYWORD_errdefer / KEYWORD_error / KEYWORD_export
/ KEYWORD_extern / KEYWORD_fn / KEYWORD_for / KEYWORD_if
@ -8408,7 +8431,7 @@ keyword <- KEYWORD_addrspace / KEYWORD_align / KEYWORD_allowzero / KEYWORD_and
/ KEYWORD_pub / KEYWORD_resume / KEYWORD_return / KEYWORD_linksection
/ KEYWORD_struct / KEYWORD_suspend / KEYWORD_switch / KEYWORD_test
/ KEYWORD_threadlocal / KEYWORD_try / KEYWORD_union / KEYWORD_unreachable
/ KEYWORD_var / KEYWORD_volatile / KEYWORD_while
/ KEYWORD_usingnamespace / KEYWORD_var / KEYWORD_volatile / KEYWORD_while
{#end_syntax_block#}
{#header_close#}
{#header_open|Zen#}

View File

@ -53,7 +53,8 @@ pub fn syscall1(number: usize, arg1: usize) usize {
// memory locations - not only the memory pointed to by a declared indirect
// output. In this example we list $rcx and $r11 because it is known the
// kernel syscall does not preserve these registers.
: .{ .rcx = true, .r11 = true });
: "rcx", "r11"
);
}
// syntax

View File

@ -17,7 +17,7 @@ pub fn main() !void {
.maximum = 0.20,
};
const category = threshold.categorize(0.90);
try std.fs.File.stdout().writeAll(@tagName(category));
try std.io.getStdOut().writeAll(@tagName(category));
}
const std = @import("std");

View File

@ -4,10 +4,8 @@ pub fn build(b: *std.Build) void {
const optimize = b.standardOptimizeOption(.{});
const exe = b.addExecutable(.{
.name = "example",
.root_module = b.createModule(.{
.root_source_file = b.path("example.zig"),
.optimize = optimize,
}),
});
b.default_step.dependOn(&exe.step);
}

View File

@ -1,22 +1,17 @@
const std = @import("std");
pub fn build(b: *std.Build) void {
const lib = b.addLibrary(.{
.linkage = .dynamic,
const lib = b.addSharedLibrary(.{
.name = "mathtest",
.root_module = b.createModule(.{
.root_source_file = b.path("mathtest.zig"),
}),
.version = .{ .major = 1, .minor = 0, .patch = 0 },
});
const exe = b.addExecutable(.{
.name = "test",
.root_module = b.createModule(.{
.link_libc = true,
}),
});
exe.root_module.addCSourceFile(.{ .file = b.path("test.c"), .flags = &.{"-std=c99"} });
exe.root_module.linkLibrary(lib);
exe.addCSourceFile(.{ .file = b.path("test.c"), .flags = &.{"-std=c99"} });
exe.linkLibrary(lib);
exe.linkSystemLibrary("c");
b.default_step.dependOn(&exe.step);

View File

@ -3,19 +3,15 @@ const std = @import("std");
pub fn build(b: *std.Build) void {
const obj = b.addObject(.{
.name = "base64",
.root_module = b.createModule(.{
.root_source_file = b.path("base64.zig"),
}),
});
const exe = b.addExecutable(.{
.name = "test",
.root_module = b.createModule(.{
.link_libc = true,
}),
});
exe.root_module.addCSourceFile(.{ .file = b.path("test.c"), .flags = &.{"-std=c99"} });
exe.root_module.addObject(obj);
exe.addCSourceFile(.{ .file = b.path("test.c"), .flags = &.{"-std=c99"} });
exe.addObject(obj);
exe.linkSystemLibrary("c");
b.installArtifact(exe);
}

View File

@ -1,7 +1,8 @@
const std = @import("std");
const expect = std.testing.expect;
const print = std.debug.print;
pub fn main() void {
test "defer unwinding" {
print("\n", .{});
defer {
@ -18,4 +19,4 @@ pub fn main() void {
}
}
// exe=succeed
// test

View File

@ -15,8 +15,8 @@ pub fn main() void {
break :blk .{ min, max };
};
print("min = {}\n", .{ min });
print("max = {}\n", .{ max });
print("min = {}", .{ min });
print("max = {}", .{ max });
}
// exe=succeed

View File

@ -2,6 +2,6 @@ comptime {
@export(&internalName, .{ .name = "foo", .linkage = .strong });
}
fn internalName() callconv(.c) void {}
fn internalName() callconv(.C) void {}
// obj

View File

@ -1,7 +1,8 @@
const std = @import("std");
pub fn main() !void {
try std.fs.File.stdout().writeAll("Hello, World!\n");
const stdout = std.io.getStdOut().writer();
try stdout.print("Hello, {s}!\n", .{"world"});
}
// exe=succeed

View File

@ -1,7 +1,7 @@
const std = @import("std");
pub fn main() void {
std.debug.print("Hello, {s}!\n", .{"World"});
std.debug.print("Hello, world!\n", .{});
}
// exe=succeed

View File

@ -15,7 +15,8 @@ pub fn syscall1(number: usize, arg1: usize) usize {
: [ret] "={rax}" (-> usize),
: [number] "{rax}" (number),
[arg1] "{rdi}" (arg1),
: .{ .rcx = true, .r11 = true });
: "rcx", "r11"
);
}
pub fn syscall3(number: usize, arg1: usize, arg2: usize, arg3: usize) usize {
@ -25,7 +26,8 @@ pub fn syscall3(number: usize, arg1: usize, arg2: usize, arg3: usize) usize {
[arg1] "{rdi}" (arg1),
[arg2] "{rsi}" (arg2),
[arg3] "{rdx}" (arg3),
: .{ .rcx = true, .r11 = true });
: "rcx", "r11"
);
}
// exe=succeed

View File

@ -1,14 +1,11 @@
const std = @import("std");
pub fn main() void {
test "inline function call" {
if (foo(1200, 34) != 1234) {
@compileError("bad");
}
}
inline fn foo(a: i32, b: i32) i32 {
std.debug.print("runtime a = {} b = {}", .{ a, b });
return a + b;
}
// exe=succeed
// test

View File

@ -1,19 +0,0 @@
pub const GpioRegister = packed struct(u8) {
GPIO0: bool,
GPIO1: bool,
GPIO2: bool,
GPIO3: bool,
reserved: u4 = 0,
};
const gpio: *volatile GpioRegister = @ptrFromInt(0x0123);
pub fn writeToGpio(new_states: GpioRegister) void {
// Example of what not to do:
// BAD! gpio.GPIO0 = true; BAD!
// Instead, do this:
gpio.* = new_states;
}
// syntax

View File

@ -1,4 +1,3 @@
const builtin = @import("builtin");
const std = @import("std");
pub fn main() void {
@ -6,8 +5,6 @@ pub fn main() void {
_ = &x;
const y = @shrExact(x, 2);
std.debug.print("value: {}\n", .{y});
if ((builtin.cpu.arch.isRISCV() or builtin.cpu.arch.isLoongArch() or builtin.cpu.arch == .s390x) and builtin.zig_backend == .stage2_llvm) @panic("https://github.com/ziglang/zig/issues/24304");
}
// exe=fail

View File

@ -11,7 +11,7 @@ pub const std_options: std.Options = .{
fn myLogFn(
comptime level: std.log.Level,
comptime scope: @EnumLiteral(),
comptime scope: @Type(.enum_literal),
comptime format: []const u8,
args: anytype,
) void {

View File

@ -67,11 +67,4 @@ test "*T to *[1]T" {
try expect(z[0] == 1234);
}
// Sentinel-terminated slices can be coerced into sentinel-terminated pointers
test "[:x]T to [*:x]T" {
const buf: [:0]const u8 = "hello";
const buf2: [*:0]const u8 = buf;
try expect(buf2[4] == 'o');
}
// test

View File

@ -41,7 +41,7 @@ test "coercion between unions and enums" {
try expect(u_4.tag() == 1);
// The following example is invalid.
// error: coercion from enum '@EnumLiteral()' to union 'test_coerce_unions_enum.U2' must initialize 'f32' field 'b'
// error: coercion from enum '@TypeOf(.enum_literal)' to union 'test_coerce_unions_enum.U2' must initialize 'f32' field 'b'
//var u_5: U2 = .b;
//try expect(u_5.tag() == 2);
}

View File

@ -1,6 +0,0 @@
comptime {
const x = @shlExact(@as(u8, 0b01010101), 2);
_ = x;
}
// test_error=overflow of integer type 'u8' with value '340'

View File

@ -0,0 +1,6 @@
comptime {
const x = @shlExact(@as(u8, 0b01010101), 2);
_ = x;
}
// test_error=operation caused overflow

View File

@ -2,7 +2,7 @@ const std = @import("std");
const testing = std.testing;
const builtin = @import("builtin");
fn add(count: c_int, ...) callconv(.c) c_int {
fn add(count: c_int, ...) callconv(.C) c_int {
var ap = @cVaStart();
defer @cVaEnd(&ap);
var i: usize = 0;
@ -22,10 +22,6 @@ test "defining a variadic function" {
// https://github.com/ziglang/zig/issues/16961
return error.SkipZigTest;
}
if (builtin.cpu.arch == .s390x) {
// https://github.com/ziglang/zig/issues/21350#issuecomment-3543006475
return error.SkipZigTest;
}
try std.testing.expectEqual(@as(c_int, 0), add(0));
try std.testing.expectEqual(@as(c_int, 1), add(1, @as(c_int, 1)));

View File

@ -23,7 +23,8 @@ export fn sub(a: i8, b: i8) i8 {
// dynamically. The quoted identifier after the extern keyword specifies
// the library that has the function. (e.g. "c" -> libc.so)
// The callconv specifier changes the calling convention of the function.
extern "kernel32" fn ExitProcess(exit_code: u32) callconv(.winapi) noreturn;
const WINAPI: std.builtin.CallingConvention = if (native_arch == .x86) .Stdcall else .C;
extern "kernel32" fn ExitProcess(exit_code: u32) callconv(WINAPI) noreturn;
extern "c" fn atan2(a: f64, b: f64) f64;
// The @branchHint builtin can be used to tell the optimizer that a function is rarely called ("cold").
@ -34,7 +35,7 @@ fn abort() noreturn {
// The naked calling convention makes a function not have any function prologue or epilogue.
// This can be useful when integrating with assembly.
fn _start() callconv(.naked) noreturn {
fn _start() callconv(.Naked) noreturn {
abort();
}

View File

@ -19,4 +19,3 @@ test "global assembly" {
// test
// target=x86_64-linux
// llvm=true

View File

@ -5,4 +5,4 @@ test "integer cast panic" {
_ = b;
}
// test_error=integer does not fit in destination type
// test_error=cast truncated bits

View File

@ -1,22 +1,18 @@
const std = @import("std");
const expect = std.testing.expect;
const expectEqual = std.testing.expectEqual;
const mat4x5 = [4][5]f32{
[_]f32{ 1.0, 0.0, 0.0, 0.0, 0.0 },
[_]f32{ 0.0, 1.0, 0.0, 1.0, 0.0 },
[_]f32{ 0.0, 0.0, 1.0, 0.0, 0.0 },
[_]f32{ 0.0, 0.0, 0.0, 1.0, 9.9 },
const mat4x4 = [4][4]f32{
[_]f32{ 1.0, 0.0, 0.0, 0.0 },
[_]f32{ 0.0, 1.0, 0.0, 1.0 },
[_]f32{ 0.0, 0.0, 1.0, 0.0 },
[_]f32{ 0.0, 0.0, 0.0, 1.0 },
};
test "multidimensional arrays" {
// mat4x5 itself is a one-dimensional array of arrays.
try expectEqual(mat4x5[1], [_]f32{ 0.0, 1.0, 0.0, 1.0, 0.0 });
// Access the 2D array by indexing the outer array, and then the inner array.
try expect(mat4x5[3][4] == 9.9);
try expect(mat4x4[1][1] == 1.0);
// Here we iterate with for loops.
for (mat4x5, 0..) |row, row_index| {
for (mat4x4, 0..) |row, row_index| {
for (row, 0..) |cell, column_index| {
if (row_index == column_index) {
try expect(cell == 1.0);
@ -24,8 +20,8 @@ test "multidimensional arrays" {
}
}
// Initialize a multidimensional array to zeros.
const all_zero: [4][5]f32 = .{.{0} ** 5} ** 4;
// initialize a multidimensional array to zeros
const all_zero: [4][4]f32 = .{.{0} ** 4} ** 4;
try expect(all_zero[0][0] == 0);
}

View File

@ -3,7 +3,7 @@ const builtin = @import("builtin");
const native_arch = builtin.cpu.arch;
const expect = std.testing.expect;
const WINAPI: std.builtin.CallingConvention = if (native_arch == .x86) .{ .x86_stdcall = .{} } else .c;
const WINAPI: std.builtin.CallingConvention = if (native_arch == .x86) .Stdcall else .C;
extern "kernel32" fn ExitProcess(exit_code: c_uint) callconv(WINAPI) noreturn;
test "foo" {

View File

@ -2,7 +2,7 @@ const Derp = opaque {};
const Wat = opaque {};
extern fn bar(d: *Derp) void;
fn foo(w: *Wat) callconv(.c) void {
fn foo(w: *Wat) callconv(.C) void {
bar(w);
}

View File

@ -8,7 +8,7 @@ const S = packed struct {
test "overaligned pointer to packed struct" {
var foo: S align(4) = .{ .a = 1, .b = 2 };
const ptr: *align(4) S = &foo;
const ptr_to_b = &ptr.b;
const ptr_to_b: *u32 = &ptr.b;
try expect(ptr_to_b.* == 2);
}

View File

@ -7,10 +7,4 @@ test "vector @splat" {
try expect(std.mem.eql(u32, &@as([4]u32, result), &[_]u32{ 5, 5, 5, 5 }));
}
test "array @splat" {
const scalar: u32 = 5;
const result: [4]u32 = @splat(scalar);
try expect(std.mem.eql(u32, &@as([4]u32, result), &[_]u32{ 5, 5, 5, 5 }));
}
// test

View File

@ -8,22 +8,20 @@ const Instruction = enum {
};
fn evaluate(initial_stack: []const i32, code: []const Instruction) !i32 {
var buffer: [8]i32 = undefined;
var stack = std.ArrayList(i32).initBuffer(&buffer);
try stack.appendSliceBounded(initial_stack);
var stack = try std.BoundedArray(i32, 8).fromSlice(initial_stack);
var ip: usize = 0;
return vm: switch (code[ip]) {
// Because all code after `continue` is unreachable, this branch does
// not provide a result.
.add => {
try stack.appendBounded(stack.pop().? + stack.pop().?);
try stack.append(stack.pop().? + stack.pop().?);
ip += 1;
continue :vm code[ip];
},
.mul => {
try stack.appendBounded(stack.pop().? * stack.pop().?);
try stack.append(stack.pop().? * stack.pop().?);
ip += 1;
continue :vm code[ip];

View File

@ -1,17 +0,0 @@
const std = @import("std");
const expect = std.testing.expect;
const Tagged = union(enum(u32)) {
int: i64 = 123,
boolean: bool = 67,
};
test "tag values" {
const int: Tagged = .{ .int = -40 };
try expect(@intFromEnum(int) == 123);
const boolean: Tagged = .{ .boolean = false };
try expect(@intFromEnum(boolean) == 67);
}
// test

View File

@ -0,0 +1,8 @@
test "using std namespace" {
const S = struct {
usingnamespace @import("std");
};
try S.testing.expect(true);
}
// test

View File

@ -17,7 +17,7 @@ test "Basic vector usage" {
}
test "Conversion between vectors, arrays, and slices" {
// Vectors can be coerced to arrays, and vice versa.
// Vectors and fixed-length arrays can be automatically assigned back and forth
const arr1: [4]f32 = [_]f32{ 1.1, 3.2, 4.5, 5.6 };
const vec: @Vector(4, f32) = arr1;
const arr2: [4]f32 = vec;

View File

@ -1,10 +1,9 @@
const std = @import("std");
test "detect leak" {
const gpa = std.testing.allocator;
var list: std.ArrayList(u21) = .empty;
// missing `defer list.deinit(gpa);`
try list.append(gpa, '☔');
var list = std.ArrayList(u21).init(std.testing.allocator);
// missing `defer list.deinit();`
try list.append('☔');
try std.testing.expect(list.items.len == 1);
}

View File

@ -4,11 +4,6 @@ const std = @import("std");
const os = std.os;
const assert = std.debug.assert;
// Custom error set definition:
const ExampleErrorSet = error{
ExampleErrorVariant,
};
pub fn main() void {
// integers
const one_plus_one: i32 = 1 + 1;
@ -41,7 +36,7 @@ pub fn main() void {
});
// error union
var number_or_error: ExampleErrorSet!i32 = ExampleErrorSet.ExampleErrorVariant;
var number_or_error: anyerror!i32 = error.ArgNotFound;
print("\nerror union 1\ntype: {}\nvalue: {!}\n", .{
@TypeOf(number_or_error),

View File

@ -1,378 +0,0 @@
// Server timestamp.
var start_fuzzing_timestamp: i64 = undefined;
const js = struct {
extern "fuzz" fn requestSources() void;
extern "fuzz" fn ready() void;
extern "fuzz" fn updateStats(html_ptr: [*]const u8, html_len: usize) void;
extern "fuzz" fn updateEntryPoints(html_ptr: [*]const u8, html_len: usize) void;
extern "fuzz" fn updateSource(html_ptr: [*]const u8, html_len: usize) void;
extern "fuzz" fn updateCoverage(covered_ptr: [*]const SourceLocationIndex, covered_len: u32) void;
};
pub fn sourceIndexMessage(msg_bytes: []u8) error{OutOfMemory}!void {
Walk.files.clearRetainingCapacity();
Walk.decls.clearRetainingCapacity();
Walk.modules.clearRetainingCapacity();
recent_coverage_update.clearRetainingCapacity();
selected_source_location = null;
js.requestSources();
const Header = abi.fuzz.SourceIndexHeader;
const header: Header = @bitCast(msg_bytes[0..@sizeOf(Header)].*);
const directories_start = @sizeOf(Header);
const directories_end = directories_start + header.directories_len * @sizeOf(Coverage.String);
const files_start = directories_end;
const files_end = files_start + header.files_len * @sizeOf(Coverage.File);
const source_locations_start = files_end;
const source_locations_end = source_locations_start + header.source_locations_len * @sizeOf(Coverage.SourceLocation);
const string_bytes = msg_bytes[source_locations_end..][0..header.string_bytes_len];
const directories: []const Coverage.String = @alignCast(std.mem.bytesAsSlice(Coverage.String, msg_bytes[directories_start..directories_end]));
const files: []const Coverage.File = @alignCast(std.mem.bytesAsSlice(Coverage.File, msg_bytes[files_start..files_end]));
const source_locations: []const Coverage.SourceLocation = @alignCast(std.mem.bytesAsSlice(Coverage.SourceLocation, msg_bytes[source_locations_start..source_locations_end]));
start_fuzzing_timestamp = header.start_timestamp;
try updateCoverageSources(directories, files, source_locations, string_bytes);
js.ready();
}
var coverage = Coverage.init;
/// Index of type `SourceLocationIndex`.
var coverage_source_locations: std.ArrayList(Coverage.SourceLocation) = .empty;
/// Contains the most recent coverage update message, unmodified.
var recent_coverage_update: std.ArrayListAlignedUnmanaged(u8, .of(u64)) = .empty;
fn updateCoverageSources(
directories: []const Coverage.String,
files: []const Coverage.File,
source_locations: []const Coverage.SourceLocation,
string_bytes: []const u8,
) !void {
coverage.directories.clearRetainingCapacity();
coverage.files.clearRetainingCapacity();
coverage.string_bytes.clearRetainingCapacity();
coverage_source_locations.clearRetainingCapacity();
try coverage_source_locations.appendSlice(gpa, source_locations);
try coverage.string_bytes.appendSlice(gpa, string_bytes);
try coverage.files.entries.resize(gpa, files.len);
@memcpy(coverage.files.entries.items(.key), files);
try coverage.files.reIndexContext(gpa, .{ .string_bytes = coverage.string_bytes.items });
try coverage.directories.entries.resize(gpa, directories.len);
@memcpy(coverage.directories.entries.items(.key), directories);
try coverage.directories.reIndexContext(gpa, .{ .string_bytes = coverage.string_bytes.items });
}
pub fn coverageUpdateMessage(msg_bytes: []u8) error{OutOfMemory}!void {
recent_coverage_update.clearRetainingCapacity();
recent_coverage_update.appendSlice(gpa, msg_bytes) catch @panic("OOM");
try updateStats();
try updateCoverage();
}
var entry_points: std.ArrayList(SourceLocationIndex) = .empty;
pub fn entryPointsMessage(msg_bytes: []u8) error{OutOfMemory}!void {
const header: abi.fuzz.EntryPointHeader = @bitCast(msg_bytes[0..@sizeOf(abi.fuzz.EntryPointHeader)].*);
const slis: []align(1) const SourceLocationIndex = @ptrCast(msg_bytes[@sizeOf(abi.fuzz.EntryPointHeader)..]);
assert(slis.len == header.locsLen());
try entry_points.resize(gpa, slis.len);
@memcpy(entry_points.items, slis);
try updateEntryPoints();
}
/// Index into `coverage_source_locations`.
const SourceLocationIndex = enum(u32) {
_,
fn haveCoverage(sli: SourceLocationIndex) bool {
return @intFromEnum(sli) < coverage_source_locations.items.len;
}
fn ptr(sli: SourceLocationIndex) *Coverage.SourceLocation {
return &coverage_source_locations.items[@intFromEnum(sli)];
}
fn sourceLocationLinkHtml(
sli: SourceLocationIndex,
out: *std.ArrayList(u8),
focused: bool,
) error{OutOfMemory}!void {
const sl = sli.ptr();
try out.print(gpa, "<code{s}>", .{
@as([]const u8, if (focused) " class=\"status-running\"" else ""),
});
try sli.appendPath(out);
try out.print(gpa, ":{d}:{d} </code><button class=\"linkish\" onclick=\"wasm_exports.fuzzSelectSli({d});\">View</button>", .{
sl.line,
sl.column,
@intFromEnum(sli),
});
}
fn appendPath(sli: SourceLocationIndex, out: *std.ArrayList(u8)) error{OutOfMemory}!void {
const sl = sli.ptr();
const file = coverage.fileAt(sl.file);
const file_name = coverage.stringAt(file.basename);
const dir_name = coverage.stringAt(coverage.directories.keys()[file.directory_index]);
try html_render.appendEscaped(out, dir_name);
try out.appendSlice(gpa, "/");
try html_render.appendEscaped(out, file_name);
}
fn toWalkFile(sli: SourceLocationIndex) ?Walk.File.Index {
var buf: std.ArrayList(u8) = .empty;
defer buf.deinit(gpa);
sli.appendPath(&buf) catch @panic("OOM");
return @enumFromInt(Walk.files.getIndex(buf.items) orelse return null);
}
fn fileHtml(
sli: SourceLocationIndex,
out: *std.ArrayList(u8),
) error{ OutOfMemory, SourceUnavailable }!void {
const walk_file_index = sli.toWalkFile() orelse return error.SourceUnavailable;
const root_node = walk_file_index.findRootDecl().get().ast_node;
var annotations: std.ArrayList(html_render.Annotation) = .empty;
defer annotations.deinit(gpa);
try computeSourceAnnotations(sli.ptr().file, walk_file_index, &annotations, coverage_source_locations.items);
html_render.fileSourceHtml(walk_file_index, out, root_node, .{
.source_location_annotations = annotations.items,
}) catch |err| {
fatal("unable to render source: {s}", .{@errorName(err)});
};
}
};
fn computeSourceAnnotations(
cov_file_index: Coverage.File.Index,
walk_file_index: Walk.File.Index,
annotations: *std.ArrayList(html_render.Annotation),
source_locations: []const Coverage.SourceLocation,
) !void {
// Collect all the source locations from only this file into this array
// first, then sort by line, col, so that we can collect annotations with
// O(N) time complexity.
var locs: std.ArrayList(SourceLocationIndex) = .empty;
defer locs.deinit(gpa);
for (source_locations, 0..) |sl, sli_usize| {
if (sl.file != cov_file_index) continue;
const sli: SourceLocationIndex = @enumFromInt(sli_usize);
try locs.append(gpa, sli);
}
std.mem.sortUnstable(SourceLocationIndex, locs.items, {}, struct {
pub fn lessThan(context: void, lhs: SourceLocationIndex, rhs: SourceLocationIndex) bool {
_ = context;
const lhs_ptr = lhs.ptr();
const rhs_ptr = rhs.ptr();
if (lhs_ptr.line < rhs_ptr.line) return true;
if (lhs_ptr.line > rhs_ptr.line) return false;
return lhs_ptr.column < rhs_ptr.column;
}
}.lessThan);
const source = walk_file_index.get_ast().source;
var line: usize = 1;
var column: usize = 1;
var next_loc_index: usize = 0;
for (source, 0..) |byte, offset| {
if (byte == '\n') {
line += 1;
column = 1;
} else {
column += 1;
}
while (true) {
if (next_loc_index >= locs.items.len) return;
const next_sli = locs.items[next_loc_index];
const next_sl = next_sli.ptr();
if (next_sl.line > line or (next_sl.line == line and next_sl.column >= column)) break;
try annotations.append(gpa, .{
.file_byte_offset = offset,
.dom_id = @intFromEnum(next_sli),
});
next_loc_index += 1;
}
}
}
export fn fuzzUnpackSources(tar_ptr: [*]u8, tar_len: usize) void {
const tar_bytes = tar_ptr[0..tar_len];
log.debug("received {d} bytes of sources.tar", .{tar_bytes.len});
unpackSourcesInner(tar_bytes) catch |err| {
fatal("unable to unpack sources.tar: {s}", .{@errorName(err)});
};
}
fn unpackSourcesInner(tar_bytes: []u8) !void {
var tar_reader: std.Io.Reader = .fixed(tar_bytes);
var file_name_buffer: [1024]u8 = undefined;
var link_name_buffer: [1024]u8 = undefined;
var it: std.tar.Iterator = .init(&tar_reader, .{
.file_name_buffer = &file_name_buffer,
.link_name_buffer = &link_name_buffer,
});
while (try it.next()) |tar_file| {
switch (tar_file.kind) {
.file => {
if (tar_file.size == 0 and tar_file.name.len == 0) break;
if (std.mem.endsWith(u8, tar_file.name, ".zig")) {
log.debug("found file: '{s}'", .{tar_file.name});
const file_name = try gpa.dupe(u8, tar_file.name);
// This is a hack to guess modules from the tar file contents. To handle modules
// properly, the build system will need to change the structure here to have one
// directory per module. This in turn requires compiler enhancements to allow
// the build system to actually discover the required information.
const mod_name, const is_module_root = p: {
if (std.mem.find(u8, file_name, "std/")) |i| break :p .{ "std", std.mem.eql(u8, file_name[i + 4 ..], "std.zig") };
if (std.mem.endsWith(u8, file_name, "/builtin.zig")) break :p .{ "builtin", true };
break :p .{ "root", std.mem.endsWith(u8, file_name, "/root.zig") };
};
const gop = try Walk.modules.getOrPut(gpa, mod_name);
const file: Walk.File.Index = @enumFromInt(Walk.files.entries.len);
if (!gop.found_existing or is_module_root) gop.value_ptr.* = file;
const file_bytes = tar_reader.take(@intCast(tar_file.size)) catch unreachable;
it.unread_file_bytes = 0; // we have read the whole thing
assert(file == try Walk.add_file(file_name, file_bytes));
} else {
log.warn("skipping: '{s}' - the tar creation should have done that", .{tar_file.name});
}
},
else => continue,
}
}
}
fn updateStats() error{OutOfMemory}!void {
@setFloatMode(.optimized);
if (recent_coverage_update.items.len == 0) return;
const hdr: *abi.fuzz.CoverageUpdateHeader = @ptrCast(@alignCast(
recent_coverage_update.items[0..@sizeOf(abi.fuzz.CoverageUpdateHeader)],
));
const covered_src_locs: usize = n: {
var n: usize = 0;
const covered_bits = recent_coverage_update.items[@sizeOf(abi.fuzz.CoverageUpdateHeader)..];
for (covered_bits) |byte| n += @popCount(byte);
break :n n;
};
const total_src_locs = coverage_source_locations.items.len;
const avg_speed: f64 = speed: {
const ns_elapsed: f64 = @floatFromInt(nsSince(start_fuzzing_timestamp));
const n_runs: f64 = @floatFromInt(hdr.n_runs);
break :speed n_runs / (ns_elapsed / std.time.ns_per_s);
};
const html = try std.fmt.allocPrint(gpa,
\\<span slot="stat-total-runs">{d}</span>
\\<span slot="stat-unique-runs">{d} ({d:.1}%)</span>
\\<span slot="stat-coverage">{d} / {d} ({d:.1}%)</span>
\\<span slot="stat-speed">{d:.0}</span>
, .{
hdr.n_runs,
hdr.unique_runs,
@as(f64, @floatFromInt(hdr.unique_runs)) / @as(f64, @floatFromInt(hdr.n_runs)),
covered_src_locs,
total_src_locs,
@as(f64, @floatFromInt(covered_src_locs)) / @as(f64, @floatFromInt(total_src_locs)),
avg_speed,
});
defer gpa.free(html);
js.updateStats(html.ptr, html.len);
}
fn updateEntryPoints() error{OutOfMemory}!void {
var html: std.ArrayList(u8) = .empty;
defer html.deinit(gpa);
for (entry_points.items) |sli| {
try html.appendSlice(gpa, "<li>");
try sli.sourceLocationLinkHtml(&html, selected_source_location == sli);
try html.appendSlice(gpa, "</li>\n");
}
js.updateEntryPoints(html.items.ptr, html.items.len);
}
fn updateCoverage() error{OutOfMemory}!void {
if (recent_coverage_update.items.len == 0) return;
const want_file = (selected_source_location orelse return).ptr().file;
var covered: std.ArrayList(SourceLocationIndex) = .empty;
defer covered.deinit(gpa);
// This code assumes 64-bit elements, which is incorrect if the executable
// being fuzzed is not a 64-bit CPU. It also assumes little-endian which
// can also be incorrect.
comptime assert(abi.fuzz.CoverageUpdateHeader.trailing[0] == .pc_bits_usize);
const n_bitset_elems = (coverage_source_locations.items.len + @bitSizeOf(u64) - 1) / @bitSizeOf(u64);
const covered_bits = std.mem.bytesAsSlice(
u64,
recent_coverage_update.items[@sizeOf(abi.fuzz.CoverageUpdateHeader)..][0 .. n_bitset_elems * @sizeOf(u64)],
);
var sli: SourceLocationIndex = @enumFromInt(0);
for (covered_bits) |elem| {
try covered.ensureUnusedCapacity(gpa, 64);
for (0..@bitSizeOf(u64)) |i| {
if ((elem & (@as(u64, 1) << @intCast(i))) != 0) {
if (sli.ptr().file == want_file) {
covered.appendAssumeCapacity(sli);
}
}
sli = @enumFromInt(@intFromEnum(sli) + 1);
}
}
js.updateCoverage(covered.items.ptr, covered.items.len);
}
fn updateSource() error{OutOfMemory}!void {
if (recent_coverage_update.items.len == 0) return;
const file_sli = selected_source_location.?;
var html: std.ArrayList(u8) = .empty;
defer html.deinit(gpa);
file_sli.fileHtml(&html) catch |err| switch (err) {
error.OutOfMemory => |e| return e,
error.SourceUnavailable => {},
};
js.updateSource(html.items.ptr, html.items.len);
}
var selected_source_location: ?SourceLocationIndex = null;
/// This function is not used directly by `main.js`, but a reference to it is
/// emitted by `SourceLocationIndex.sourceLocationLinkHtml`.
export fn fuzzSelectSli(sli: SourceLocationIndex) void {
if (!sli.haveCoverage()) return;
selected_source_location = sli;
updateEntryPoints() catch @panic("out of memory"); // highlights the selected one green
updateSource() catch @panic("out of memory");
updateCoverage() catch @panic("out of memory");
}
const std = @import("std");
const Allocator = std.mem.Allocator;
const Coverage = std.debug.Coverage;
const abi = std.Build.abi;
const assert = std.debug.assert;
const gpa = std.heap.wasm_allocator;
const Walk = @import("Walk");
const html_render = @import("html_render");
const nsSince = @import("main.zig").nsSince;
const Slice = @import("main.zig").Slice;
const fatal = @import("main.zig").fatal;
const log = std.log;
const String = Slice(u8);

View File

@ -1,217 +0,0 @@
<!doctype html>
<meta charset="utf-8">
<title>Zig Build System</title>
<link rel="stylesheet" href="style.css">
<!-- Highly compressed 32x32 Zig logo -->
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABSklEQVRYw8WWXbLDIAiFP5xuURYpi+Q+VDvJTYxaY8pLJ52EA5zDj/AD8wRABCw8DeyJBDiAKMiDGaecNYCKYgCvh4EBjPgGh0UVqAB/MEU3D57efDRMiRhWddprCljRAECPCE0Uw4iz4Jn3tP2zFYAB6on4/8NBM1Es+9kl0aKgaMRnwHPpT5MIDb6YzLzp57wNIyIC7iCCdijeL3gv78jZe6cVENn/drRbXbxl4lXSmB3FtbY0iNrjIEwMm6u2VFFjWQCN0qtov6+wANxG/IV7eR8DHw6gzft4NuEXvA8HcDfv31SgyvsMeDUA90/WTd47bsCdv8PUrWzDyw02uIYv13ktgOVr+IqCouila7gWgNYuly/BfVSEdsP5Vdqyiz7pPC40C+p2e21bL5/dByGtAD6eZPuzeznwjoIN748BfyqwmVDyJHCxPwLSkjUkraEXAAAAAElFTkSuQmCC">
<!-- Templates, to be cloned into shadow DOMs by JavaScript -->
<template id="timeReportEntryTemplate">
<link rel="stylesheet" href="style.css">
<link rel="stylesheet" href="time_report.css">
<details>
<summary><slot name="step-name"></slot></summary>
<div id="genericReport">
<div class="stats">
Time: <slot name="stat-total-time"></slot><br>
</div>
</div>
<div id="compileReport">
<div class="stats">
Files Discovered: <slot name="stat-reachable-files"></slot><br>
Files Analyzed: <slot name="stat-imported-files"></slot><br>
Generic Instances Analyzed: <slot name="stat-generic-instances"></slot><br>
Inline Calls Analyzed: <slot name="stat-inline-calls"></slot><br>
Compilation Time: <slot name="stat-compilation-time"></slot><br>
</div>
<table class="time-stats">
<thead>
<tr>
<th scope="col">Pipeline Component</th>
<th scope="col" class="tooltip">CPU Time
<span class="tooltip-content">Sum across all threads of the time spent in this pipeline component</span>
</th>
<th scope="col" class="tooltip">Real Time
<span class="tooltip-content">Wall-clock time elapsed between the start and end of this compilation phase</span>
</th>
<th scope="col">Compilation Phase</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row" class="tooltip">Parsing
<span class="tooltip-content"><code>tokenize</code> converts a file of Zig source code into a sequence of tokens, which are then processed by <code>Parse</code> into an Abstract Syntax Tree (AST).</span>
</th>
<td><slot name="cpu-time-parse"></slot></td>
<td rowspan="2"><slot name="real-time-files"></slot></td>
<th scope="row" rowspan="2" class="tooltip">File Lower
<span class="tooltip-content">Tokenization, parsing, and lowering of Zig source files to a high-level IR.<br><br>Starting from module roots, every file theoretically accessible through a chain of <code>@import</code> calls is processed. Individual source files are processed serially, but different files are processed in parallel by a thread pool.<br><br>The results of this phase of compilation are cached on disk per source file, meaning the time spent here is typically only relevant to "clean" builds.</span>
</th>
</tr>
<tr>
<th scope="row" class="tooltip">AST Lowering
<span class="tooltip-content"><code>AstGen</code> converts a file's AST into a high-level SSA IR named Zig Intermediate Representation (ZIR). The resulting ZIR code is cached on disk to avoid, for instance, re-lowering all source files in the Zig standard library each time the compiler is invoked.</span>
</th>
<td><slot name="cpu-time-astgen"></slot></td>
</tr>
<tr>
<th scope="row" class="tooltip">Semantic Analysis
<span class="tooltip-content"><code>Sema</code> interprets ZIR to perform type checking, compile-time code execution, and type resolution, collectively termed "semantic analysis". When a runtime function body is analyzed, it emits Analyzed Intermediate Representation (AIR) code to be sent to the next pipeline component. Semantic analysis is currently entirely single-threaded.</span>
</th>
<td><slot name="cpu-time-sema"></slot></td>
<td rowspan="3"><slot name="real-time-decls"></slot></td>
<th scope="row" rowspan="3" class="tooltip">Declaration Lower
<span class="tooltip-content">Semantic analysis, code generation, and linking, at the granularity of individual declarations (as opposed to whole source files).<br><br>These components are run in parallel with one another. Semantic analysis is almost always the bottleneck, as it is complex and currently can only run single-threaded.<br><br>This phase completes when a work queue empties, but semantic analysis may add work by one declaration referencing another.<br><br>This is the main phase of compilation, typically taking significantly longer than File Lower (even in a clean build).</span>
</th>
</tr>
<tr>
<th scope="row" class="tooltip">Code Generation
<span class="tooltip-content"><code>CodeGen</code> converts AIR from <code>Sema</code> into machine instructions in the form of Machine Intermediate Representation (MIR). This work is usually highly parallel, since in most cases, arbitrarily many functions can be run through <code>CodeGen</code> simultaneously.</span>
</th>
<td><slot name="cpu-time-codegen"></slot></td>
</tr>
<tr>
<th scope="row" class="tooltip">Linking
<span class="tooltip-content"><code>link</code> converts MIR from <code>CodeGen</code>, as well as global constants and variables from <code>Sema</code>, and places them in the output binary. MIR is converted to a finished sequence of real instruction bytes.<br><br>When using the LLVM backend, most of this work is instead deferred to the "LLVM Emit" phase.</span>
</th>
<td><slot name="cpu-time-link"></slot></td>
</tr>
<tr class="llvm-only">
<th class="empty-cell"></th>
<td class="empty-cell"></td>
<td><slot name="real-time-llvm-emit"></slot></td>
<th scope="row" class="tooltip">LLVM Emit
<span class="tooltip-content"><b>Only applicable when using the LLVM backend.</b><br><br>Conversion of generated LLVM bitcode to an object file, including any optimization passes.<br><br>When using LLVM, this phase of compilation is typically the slowest by a significant margin. Unfortunately, the Zig compiler implementation has essentially no control over it.</span>
</th>
</tr>
<tr>
<th class="empty-cell"></th>
<td class="empty-cell"></td>
<td><slot name="real-time-link-flush"></slot></td>
<th scope="row" class="tooltip">Linker Flush
<span class="tooltip-content">Finalizing the emitted binary, and ensuring it is fully written to disk.<br><br>When using LLD, this phase represents the entire linker invocation. Otherwise, the amount of work performed here is dependent on details of Zig's linker implementation for the particular output format, but typically aims to be fairly minimal.</span>
</th>
</tr>
</tbody>
</table>
<details class="section">
<summary>Files</summary>
<table class="time-stats">
<thead>
<tr>
<th scope="col">File</th>
<th scope="col">Semantic Analysis</th>
<th scope="col">Code Generation</th>
<th scope="col">Linking</th>
<th scope="col">Total</th>
</tr>
</thead>
<!-- HTML does not allow placing a 'slot' inside of a 'tbody' for backwards-compatibility
reasons, so we unfortunately must template on the `id` here. -->
<tbody id="fileTableBody"></tbody>
</table>
</details>
<details class="section">
<summary>Declarations</summary>
<table class="time-stats">
<thead>
<tr>
<th scope="col">File</th>
<th scope="col">Declaration</th>
<th scope="col" class="tooltip">Analysis Count
<span class="tooltip-content">The number of times the compiler analyzed some part of this declaration. If this is a function, <code>inline</code> and <code>comptime</code> calls to it are <i>not</i> included here. Typically, this value is approximately equal to the number of instances of a generic declaration.</span>
</th>
<th scope="col">Semantic Analysis</th>
<th scope="col">Code Generation</th>
<th scope="col">Linking</th>
<th scope="col">Total</th>
</tr>
</thead>
<!-- HTML does not allow placing a 'slot' inside of a 'tbody' for backwards-compatibility
reasons, so we unfortunately must template on the `id` here. -->
<tbody id="declTableBody"></tbody>
</table>
</details>
<details class="section llvm-only">
<summary>LLVM Pass Timings</summary>
<div><slot name="llvm-pass-timings"></slot></div>
</details>
</div>
<div id="runTestReport">
<table class="time-stats">
<thead>
<tr>
<th scope="col">Test Name</th>
<th scope="col">Duration</th>
</tr>
</thead>
<!-- HTML does not allow placing a 'slot' inside of a 'tbody' for backwards-compatibility
reasons, so we unfortunately must template on the `id` here. -->
<tbody id="runTestTableBody"></tbody>
</div>
</div>
</details>
</template>
<template id="fuzzEntryTemplate">
<link rel="stylesheet" href="style.css">
<ul>
<li>Total Runs: <slot name="stat-total-runs"></slot></li>
<li>Unique Runs: <slot name="stat-unique-runs"></slot></li>
<li>Speed: <slot name="stat-speed"></slot> runs/sec</li>
<li>Coverage: <slot name="stat-coverage"></slot></li>
</ul>
<!-- I have observed issues in Firefox clicking frequently-updating slotted links, so the entry
point list is handled separately since it rarely changes. -->
<ul id="entryPointList" class="no-marker"></ul>
<div id="source" class="hidden">
<h2>Source Code</h2>
<pre><code id="sourceText"></code></pre>
</div>
</template>
<!-- The actual body: fairly minimal, content populated by JavaScript -->
<p id="connectionStatus">Loading JavaScript...</p>
<p class="hidden" id="firefoxWebSocketBullshitExplainer">
If you are using Firefox and <code>zig build --listen</code> is definitely running, you may be experiencing an unreasonably aggressive exponential
backoff for WebSocket connection attempts, which is enabled by default and can block connection attempts for up to a minute. To disable this limit,
open <code>about:config</code> and set the <code>network.websocket.delay-failed-reconnects</code> option to <code>false</code>.
</p>
<main class="hidden">
<h1>Zig Build System</h1>
<p><span id="summaryStatus"></span> | <span id="summaryStepCount"></span> steps</p>
<button class="big-btn" id="buttonRebuild" disabled>Rebuild</button>
<ul class="no-marker" id="stepList"></ul>
<hr>
<div id="timeReport" class="hidden">
<h1>Time Report</h1>
<div id="timeReportList"></div>
<hr>
</div>
<div id="fuzz" class="hidden">
<h1>Fuzzer</h1>
<p id="fuzzStatus"></p>
<div id="fuzzEntries"></div>
<hr>
</div>
<h1>Help</h1>
<p>This is the Zig Build System web interface. It allows live interaction with the build system.</p>
<p>The following <code>zig build</code> flags can expose extra features of this interface:</p>
<ul>
<li><code>--time-report</code>: collect and show statistics about the time taken to evaluate a build graph</li>
<li><code>--fuzz</code>: enable the fuzzer for any Zig test binaries in the build graph (experimental)</li>
</ul>
</main>
<!-- JavaScript at the very end -->
<script src="main.js"></script>

View File

@ -1,366 +0,0 @@
const domConnectionStatus = document.getElementById("connectionStatus");
const domFirefoxWebSocketBullshitExplainer = document.getElementById("firefoxWebSocketBullshitExplainer");
const domMain = document.getElementsByTagName("main")[0];
const domSummary = {
stepCount: document.getElementById("summaryStepCount"),
status: document.getElementById("summaryStatus"),
};
const domButtonRebuild = document.getElementById("buttonRebuild");
const domStepList = document.getElementById("stepList");
let domSteps = [];
let wasm_promise = fetch("main.wasm");
let wasm_exports = null;
const text_decoder = new TextDecoder();
const text_encoder = new TextEncoder();
domButtonRebuild.addEventListener("click", () => wasm_exports.rebuild());
setConnectionStatus("Loading WebAssembly...", false);
WebAssembly.instantiateStreaming(wasm_promise, {
core: {
log: function(ptr, len) {
const msg = decodeString(ptr, len);
console.log(msg);
},
panic: function (ptr, len) {
const msg = decodeString(ptr, len);
throw new Error("panic: " + msg);
},
timestamp: function () {
return BigInt(new Date());
},
hello: hello,
updateBuildStatus: updateBuildStatus,
updateStepStatus: updateStepStatus,
sendWsMessage: (ptr, len) => ws.send(new Uint8Array(wasm_exports.memory.buffer, ptr, len)),
},
fuzz: {
requestSources: fuzzRequestSources,
ready: fuzzReady,
updateStats: fuzzUpdateStats,
updateEntryPoints: fuzzUpdateEntryPoints,
updateSource: fuzzUpdateSource,
updateCoverage: fuzzUpdateCoverage,
},
time_report: {
updateGeneric: timeReportUpdateGeneric,
updateCompile: timeReportUpdateCompile,
updateRunTest: timeReportUpdateRunTest,
},
}).then(function(obj) {
setConnectionStatus("Connecting to WebSocket...", true);
connectWebSocket();
wasm_exports = obj.instance.exports;
window.wasm = obj; // for debugging
});
function connectWebSocket() {
const host = document.location.host;
const pathname = document.location.pathname;
const isHttps = document.location.protocol === 'https:';
const match = host.match(/^(.+):(\d+)$/);
const defaultPort = isHttps ? 443 : 80;
const port = match ? parseInt(match[2], 10) : defaultPort;
const hostName = match ? match[1] : host;
const wsProto = isHttps ? "wss:" : "ws:";
const wsUrl = wsProto + '//' + hostName + ':' + port + pathname;
ws = new WebSocket(wsUrl);
ws.binaryType = "arraybuffer";
ws.addEventListener('message', onWebSocketMessage, false);
ws.addEventListener('error', onWebSocketClose, false);
ws.addEventListener('close', onWebSocketClose, false);
ws.addEventListener('open', onWebSocketOpen, false);
}
function onWebSocketOpen() {
setConnectionStatus("Waiting for data...", false);
}
function onWebSocketMessage(ev) {
const jsArray = new Uint8Array(ev.data);
const ptr = wasm_exports.message_begin(jsArray.length);
const wasmArray = new Uint8Array(wasm_exports.memory.buffer, ptr, jsArray.length);
wasmArray.set(jsArray);
wasm_exports.message_end();
}
function onWebSocketClose() {
setConnectionStatus("WebSocket connection closed. Re-connecting...", true);
ws.removeEventListener('message', onWebSocketMessage, false);
ws.removeEventListener('error', onWebSocketClose, false);
ws.removeEventListener('close', onWebSocketClose, false);
ws.removeEventListener('open', onWebSocketOpen, false);
ws = null;
setTimeout(connectWebSocket, 1000);
}
function setConnectionStatus(msg, is_websocket_connect) {
domConnectionStatus.textContent = msg;
if (msg.length > 0) {
domConnectionStatus.classList.remove("hidden");
domMain.classList.add("hidden");
} else {
domConnectionStatus.classList.add("hidden");
domMain.classList.remove("hidden");
}
if (is_websocket_connect) {
domFirefoxWebSocketBullshitExplainer.classList.remove("hidden");
} else {
domFirefoxWebSocketBullshitExplainer.classList.add("hidden");
}
}
function hello(
steps_len,
build_status,
time_report,
) {
domSummary.stepCount.textContent = steps_len;
updateBuildStatus(build_status);
setConnectionStatus("", false);
{
let entries = [];
for (let i = 0; i < steps_len; i += 1) {
const step_name = unwrapString(wasm_exports.stepName(i));
const code = document.createElement("code");
code.textContent = step_name;
const li = document.createElement("li");
li.appendChild(code);
entries.push(li);
}
domStepList.replaceChildren(...entries);
for (let i = 0; i < steps_len; i += 1) {
updateStepStatus(i);
}
}
if (time_report) timeReportReset(steps_len);
fuzzReset();
}
function updateBuildStatus(s) {
let text;
let active = false;
let reset_time_reports = false;
if (s == 0) {
text = "Idle";
} else if (s == 1) {
text = "Watching for changes...";
} else if (s == 2) {
text = "Running...";
active = true;
reset_time_reports = true;
} else if (s == 3) {
text = "Starting fuzzer...";
active = true;
} else {
console.log(`bad build status: ${s}`);
}
domSummary.status.textContent = text;
if (active) {
domSummary.status.classList.add("status-running");
domSummary.status.classList.remove("status-idle");
domButtonRebuild.disabled = true;
} else {
domSummary.status.classList.remove("status-running");
domSummary.status.classList.add("status-idle");
domButtonRebuild.disabled = false;
}
if (reset_time_reports) {
// Grey out and collapse all the time reports
for (const time_report_host of domTimeReportList.children) {
const details = time_report_host.shadowRoot.querySelector(":host > details");
details.classList.add("pending");
details.open = false;
}
}
}
function updateStepStatus(step_idx) {
const li = domStepList.children[step_idx];
const step_status = wasm_exports.stepStatus(step_idx);
li.classList.remove("step-wip", "step-success", "step-failure");
if (step_status == 0) {
// pending
} else if (step_status == 1) {
li.classList.add("step-wip");
} else if (step_status == 2) {
li.classList.add("step-success");
} else if (step_status == 3) {
li.classList.add("step-failure");
} else {
console.log(`bad step status: ${step_status}`);
}
}
function decodeString(ptr, len) {
if (len === 0) return "";
return text_decoder.decode(new Uint8Array(wasm_exports.memory.buffer, ptr, len));
}
function getU32Array(ptr, len) {
if (len === 0) return new Uint32Array();
return new Uint32Array(wasm_exports.memory.buffer, ptr, len);
}
function unwrapString(bigint) {
const ptr = Number(bigint & 0xffffffffn);
const len = Number(bigint >> 32n);
return decodeString(ptr, len);
}
const time_report_entry_template = document.getElementById("timeReportEntryTemplate").content;
const domTimeReport = document.getElementById("timeReport");
const domTimeReportList = document.getElementById("timeReportList");
function timeReportReset(steps_len) {
let entries = [];
for (let i = 0; i < steps_len; i += 1) {
const step_name = unwrapString(wasm_exports.stepName(i));
const host = document.createElement("div");
const shadow = host.attachShadow({ mode: "open" });
shadow.appendChild(time_report_entry_template.cloneNode(true));
shadow.querySelector(":host > details").classList.add("pending");
const slotted_name = document.createElement("code");
slotted_name.setAttribute("slot", "step-name");
slotted_name.textContent = step_name;
host.appendChild(slotted_name);
entries.push(host);
}
domTimeReportList.replaceChildren(...entries);
domTimeReport.classList.remove("hidden");
}
function timeReportUpdateCompile(
step_idx,
inner_html_ptr,
inner_html_len,
file_table_html_ptr,
file_table_html_len,
decl_table_html_ptr,
decl_table_html_len,
use_llvm,
) {
const inner_html = decodeString(inner_html_ptr, inner_html_len);
const file_table_html = decodeString(file_table_html_ptr, file_table_html_len);
const decl_table_html = decodeString(decl_table_html_ptr, decl_table_html_len);
const host = domTimeReportList.children.item(step_idx);
const shadow = host.shadowRoot;
shadow.querySelector(":host > details").classList.remove("pending", "no-llvm");
shadow.getElementById("genericReport").classList.add("hidden");
shadow.getElementById("compileReport").classList.remove("hidden");
shadow.getElementById("runTestReport").classList.add("hidden");
if (!use_llvm) shadow.querySelector(":host > details").classList.add("no-llvm");
host.innerHTML = inner_html;
shadow.getElementById("fileTableBody").innerHTML = file_table_html;
shadow.getElementById("declTableBody").innerHTML = decl_table_html;
}
function timeReportUpdateGeneric(
step_idx,
inner_html_ptr,
inner_html_len,
) {
const inner_html = decodeString(inner_html_ptr, inner_html_len);
const host = domTimeReportList.children.item(step_idx);
const shadow = host.shadowRoot;
shadow.querySelector(":host > details").classList.remove("pending", "no-llvm");
shadow.getElementById("genericReport").classList.remove("hidden");
shadow.getElementById("compileReport").classList.add("hidden");
shadow.getElementById("runTestReport").classList.add("hidden");
host.innerHTML = inner_html;
}
function timeReportUpdateRunTest(
step_idx,
table_html_ptr,
table_html_len,
) {
const table_html = decodeString(table_html_ptr, table_html_len);
const host = domTimeReportList.children.item(step_idx);
const shadow = host.shadowRoot;
shadow.querySelector(":host > details").classList.remove("pending", "no-llvm");
shadow.getElementById("genericReport").classList.add("hidden");
shadow.getElementById("compileReport").classList.add("hidden");
shadow.getElementById("runTestReport").classList.remove("hidden");
shadow.getElementById("runTestTableBody").innerHTML = table_html;
}
const fuzz_entry_template = document.getElementById("fuzzEntryTemplate").content;
const domFuzz = document.getElementById("fuzz");
const domFuzzStatus = document.getElementById("fuzzStatus");
const domFuzzEntries = document.getElementById("fuzzEntries");
let domFuzzInstance = null;
function fuzzRequestSources() {
domFuzzStatus.classList.remove("hidden");
domFuzzStatus.textContent = "Loading sources tarball...";
fetch("sources.tar").then(function(response) {
if (!response.ok) throw new Error("unable to download sources");
domFuzzStatus.textContent = "Parsing fuzz test sources...";
return response.arrayBuffer();
}).then(function(buffer) {
if (buffer.length === 0) throw new Error("sources.tar was empty");
const js_array = new Uint8Array(buffer);
const ptr = wasm_exports.alloc(js_array.length);
const wasm_array = new Uint8Array(wasm_exports.memory.buffer, ptr, js_array.length);
wasm_array.set(js_array);
wasm_exports.fuzzUnpackSources(ptr, js_array.length);
domFuzzStatus.textContent = "";
domFuzzStatus.classList.add("hidden");
});
}
function fuzzReady() {
domFuzz.classList.remove("hidden");
// TODO: multiple fuzzer instances
if (domFuzzInstance !== null) return;
const host = document.createElement("div");
const shadow = host.attachShadow({ mode: "open" });
shadow.appendChild(fuzz_entry_template.cloneNode(true));
domFuzzInstance = host;
domFuzzEntries.appendChild(host);
}
function fuzzReset() {
domFuzz.classList.add("hidden");
domFuzzEntries.replaceChildren();
domFuzzInstance = null;
}
function fuzzUpdateStats(stats_html_ptr, stats_html_len) {
if (domFuzzInstance === null) throw new Error("fuzzUpdateStats called when fuzzer inactive");
const stats_html = decodeString(stats_html_ptr, stats_html_len);
const host = domFuzzInstance;
host.innerHTML = stats_html;
}
function fuzzUpdateEntryPoints(entry_points_html_ptr, entry_points_html_len) {
if (domFuzzInstance === null) throw new Error("fuzzUpdateEntryPoints called when fuzzer inactive");
const entry_points_html = decodeString(entry_points_html_ptr, entry_points_html_len);
const domEntryPointList = domFuzzInstance.shadowRoot.getElementById("entryPointList");
domEntryPointList.innerHTML = entry_points_html;
}
function fuzzUpdateSource(source_html_ptr, source_html_len) {
if (domFuzzInstance === null) throw new Error("fuzzUpdateSource called when fuzzer inactive");
const source_html = decodeString(source_html_ptr, source_html_len);
const domSourceText = domFuzzInstance.shadowRoot.getElementById("sourceText");
domSourceText.innerHTML = source_html;
domFuzzInstance.shadowRoot.getElementById("source").classList.remove("hidden");
}
function fuzzUpdateCoverage(covered_ptr, covered_len) {
if (domFuzzInstance === null) throw new Error("fuzzUpdateCoverage called when fuzzer inactive");
const shadow = domFuzzInstance.shadowRoot;
const domSourceText = shadow.getElementById("sourceText");
const covered = getU32Array(covered_ptr, covered_len);
for (let i = 0; i < domSourceText.children.length; i += 1) {
const childDom = domSourceText.children[i];
if (childDom.id != null && childDom.id[0] == "l") {
childDom.classList.add("l");
childDom.classList.remove("c");
}
}
for (const sli of covered) {
shadow.getElementById(`l${sli}`).classList.add("c");
}
}

View File

@ -1,214 +0,0 @@
const std = @import("std");
const assert = std.debug.assert;
const abi = std.Build.abi;
const gpa = std.heap.wasm_allocator;
const log = std.log;
const Allocator = std.mem.Allocator;
const fuzz = @import("fuzz.zig");
const time_report = @import("time_report.zig");
/// Nanoseconds.
var server_base_timestamp: i64 = 0;
/// Milliseconds.
var client_base_timestamp: i64 = 0;
pub var step_list: []Step = &.{};
/// Not accessed after initialization, but must be freed alongside `step_list`.
pub var step_list_data: []u8 = &.{};
const Step = struct {
name: []const u8,
status: abi.StepUpdate.Status,
};
const js = struct {
extern "core" fn log(ptr: [*]const u8, len: usize) void;
extern "core" fn panic(ptr: [*]const u8, len: usize) noreturn;
extern "core" fn timestamp() i64;
extern "core" fn hello(
steps_len: u32,
status: abi.BuildStatus,
time_report: bool,
) void;
extern "core" fn updateBuildStatus(status: abi.BuildStatus) void;
extern "core" fn updateStepStatus(step_idx: u32) void;
extern "core" fn sendWsMessage(ptr: [*]const u8, len: usize) void;
};
pub const std_options: std.Options = .{
.logFn = logFn,
};
pub fn panic(msg: []const u8, st: ?*std.builtin.StackTrace, addr: ?usize) noreturn {
_ = st;
_ = addr;
log.err("panic: {s}", .{msg});
@trap();
}
fn logFn(
comptime message_level: log.Level,
comptime scope: @EnumLiteral(),
comptime format: []const u8,
args: anytype,
) void {
const level_txt = comptime message_level.asText();
const prefix2 = if (scope == .default) ": " else "(" ++ @tagName(scope) ++ "): ";
var buf: [500]u8 = undefined;
const line = std.fmt.bufPrint(&buf, level_txt ++ prefix2 ++ format, args) catch l: {
buf[buf.len - 3 ..][0..3].* = "...".*;
break :l &buf;
};
js.log(line.ptr, line.len);
}
export fn alloc(n: usize) [*]u8 {
const slice = gpa.alloc(u8, n) catch @panic("OOM");
return slice.ptr;
}
var message_buffer: std.ArrayListAlignedUnmanaged(u8, .of(u64)) = .empty;
/// Resizes the message buffer to be the correct length; returns the pointer to
/// the query string.
export fn message_begin(len: usize) [*]u8 {
message_buffer.resize(gpa, len) catch @panic("OOM");
return message_buffer.items.ptr;
}
export fn message_end() void {
const msg_bytes = message_buffer.items;
const tag: abi.ToClientTag = @enumFromInt(msg_bytes[0]);
switch (tag) {
_ => @panic("malformed message"),
.hello => return helloMessage(msg_bytes) catch @panic("OOM"),
.status_update => return statusUpdateMessage(msg_bytes) catch @panic("OOM"),
.step_update => return stepUpdateMessage(msg_bytes) catch @panic("OOM"),
.fuzz_source_index => return fuzz.sourceIndexMessage(msg_bytes) catch @panic("OOM"),
.fuzz_coverage_update => return fuzz.coverageUpdateMessage(msg_bytes) catch @panic("OOM"),
.fuzz_entry_points => return fuzz.entryPointsMessage(msg_bytes) catch @panic("OOM"),
.time_report_generic_result => return time_report.genericResultMessage(msg_bytes) catch @panic("OOM"),
.time_report_compile_result => return time_report.compileResultMessage(msg_bytes) catch @panic("OOM"),
.time_report_run_test_result => return time_report.runTestResultMessage(msg_bytes) catch @panic("OOM"),
}
}
const String = Slice(u8);
pub fn Slice(T: type) type {
return packed struct(u64) {
ptr: u32,
len: u32,
pub fn init(s: []const T) @This() {
return .{
.ptr = @intFromPtr(s.ptr),
.len = s.len,
};
}
};
}
pub fn fatal(comptime format: []const u8, args: anytype) noreturn {
var buf: [500]u8 = undefined;
const line = std.fmt.bufPrint(&buf, format, args) catch l: {
buf[buf.len - 3 ..][0..3].* = "...".*;
break :l &buf;
};
js.panic(line.ptr, line.len);
}
fn helloMessage(msg_bytes: []align(4) u8) Allocator.Error!void {
if (msg_bytes.len < @sizeOf(abi.Hello)) @panic("malformed Hello message");
const hdr: *const abi.Hello = @ptrCast(msg_bytes[0..@sizeOf(abi.Hello)]);
const trailing = msg_bytes[@sizeOf(abi.Hello)..];
client_base_timestamp = js.timestamp();
server_base_timestamp = hdr.timestamp;
const steps = try gpa.alloc(Step, hdr.steps_len);
errdefer gpa.free(steps);
const step_name_lens: []align(1) const u32 = @ptrCast(trailing[0 .. steps.len * 4]);
const step_name_data_len: usize = len: {
var sum: usize = 0;
for (step_name_lens) |n| sum += n;
break :len sum;
};
const step_name_data: []const u8 = trailing[steps.len * 4 ..][0..step_name_data_len];
const step_status_bits: []const u8 = trailing[steps.len * 4 + step_name_data_len ..];
const duped_step_name_data = try gpa.dupe(u8, step_name_data);
errdefer gpa.free(duped_step_name_data);
var name_off: usize = 0;
for (steps, step_name_lens, 0..) |*step_out, name_len, step_idx| {
step_out.* = .{
.name = duped_step_name_data[name_off..][0..name_len],
.status = @enumFromInt(@as(u2, @truncate(step_status_bits[step_idx / 4] >> @intCast((step_idx % 4) * 2)))),
};
name_off += name_len;
}
gpa.free(step_list);
gpa.free(step_list_data);
step_list = steps;
step_list_data = duped_step_name_data;
js.hello(step_list.len, hdr.status, hdr.flags.time_report);
}
fn statusUpdateMessage(msg_bytes: []u8) Allocator.Error!void {
if (msg_bytes.len < @sizeOf(abi.StatusUpdate)) @panic("malformed StatusUpdate message");
const msg: *const abi.StatusUpdate = @ptrCast(msg_bytes[0..@sizeOf(abi.StatusUpdate)]);
js.updateBuildStatus(msg.new);
}
fn stepUpdateMessage(msg_bytes: []u8) Allocator.Error!void {
if (msg_bytes.len < @sizeOf(abi.StepUpdate)) @panic("malformed StepUpdate message");
const msg: *const abi.StepUpdate = @ptrCast(msg_bytes[0..@sizeOf(abi.StepUpdate)]);
if (msg.step_idx >= step_list.len) @panic("malformed StepUpdate message");
step_list[msg.step_idx].status = msg.bits.status;
js.updateStepStatus(msg.step_idx);
}
export fn stepName(idx: usize) String {
return .init(step_list[idx].name);
}
export fn stepStatus(idx: usize) u8 {
return @intFromEnum(step_list[idx].status);
}
export fn rebuild() void {
const msg: abi.Rebuild = .{};
const raw: []const u8 = @ptrCast(&msg);
js.sendWsMessage(raw.ptr, raw.len);
}
/// Nanoseconds passed since a server timestamp.
pub fn nsSince(server_timestamp: i64) i64 {
const ms_passed = js.timestamp() - client_base_timestamp;
const ns_passed = server_base_timestamp - server_timestamp;
return ns_passed + ms_passed * std.time.ns_per_ms;
}
pub fn fmtEscapeHtml(unescaped: []const u8) HtmlEscaper {
return .{ .unescaped = unescaped };
}
const HtmlEscaper = struct {
unescaped: []const u8,
pub fn format(he: HtmlEscaper, w: *std.Io.Writer) !void {
for (he.unescaped) |c| switch (c) {
'&' => try w.writeAll("&amp;"),
'<' => try w.writeAll("&lt;"),
'>' => try w.writeAll("&gt;"),
'"' => try w.writeAll("&quot;"),
'\'' => try w.writeAll("&#39;"),
else => try w.writeByte(c),
};
}
};

View File

@ -1,240 +0,0 @@
body {
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
color: #000000;
padding: 1em 10%;
}
ul.no-marker {
list-style-type: none;
padding-left: 0;
}
hr {
margin: 2em 0;
}
.hidden {
display: none;
}
.empty-cell {
background: #ccc;
}
table.time-stats > tbody > tr > th {
text-align: left;
}
table.time-stats > tbody > tr > td {
text-align: right;
}
details > summary {
cursor: pointer;
font-size: 1.5em;
}
.tooltip {
text-decoration: underline;
cursor: help;
}
.tooltip-content {
border-radius: 6px;
display: none;
position: absolute;
background: #fff;
border: 1px solid black;
max-width: 500px;
padding: 1em;
text-align: left;
font-weight: normal;
pointer-events: none;
}
.tooltip:hover > .tooltip-content {
display: block;
}
table {
margin: 1.0em auto 1.5em 0;
border-collapse: collapse;
}
th, td {
padding: 0.5em 1em 0.5em 1em;
border: 1px solid;
border-color: black;
}
a, button {
color: #2A6286;
}
button {
background: #eee;
cursor: pointer;
border: none;
border-radius: 3px;
padding: 0.2em 0.5em;
}
button.big-btn {
font-size: 1.3em;
}
button.linkish {
background: none;
text-decoration: underline;
padding: 0;
}
button:disabled {
color: #888;
cursor: not-allowed;
}
pre {
font-family: "Source Code Pro", monospace;
font-size: 1em;
background-color: #F5F5F5;
padding: 1em;
margin: 0;
overflow-x: auto;
}
:not(pre) > code {
white-space: break-spaces;
}
code {
font-family: "Source Code Pro", monospace;
font-size: 0.9em;
}
code a {
color: #000000;
}
kbd {
color: #000;
background-color: #fafbfc;
border-color: #d1d5da;
border-bottom-color: #c6cbd1;
box-shadow-color: #c6cbd1;
display: inline-block;
padding: 0.3em 0.2em;
font: 1.2em monospace;
line-height: 0.8em;
vertical-align: middle;
border: solid 1px;
border-radius: 3px;
box-shadow: inset 0 -1px 0;
cursor: default;
}
.status-running { color: #181; }
.status-idle { color: #444; }
.step-success { color: #181; }
.step-failure { color: #d11; }
.step-wip::before {
content: '';
position: absolute;
margin-left: -1.5em;
width: 1em;
text-align: center;
animation-name: spinner;
animation-duration: 0.5s;
animation-iteration-count: infinite;
animation-timing-function: step-start;
}
@keyframes spinner {
0% { content: '|'; }
25% { content: '/'; }
50% { content: '-'; }
75% { content: '\\'; }
100% { content: '|'; }
}
.l {
display: inline-block;
background: red;
width: 1em;
height: 1em;
border-radius: 1em;
}
.c {
background-color: green;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #0086b3;
}
.tok-comment {
color: #777;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #008080;
}
.tok-number {
color: #008080;
}
.tok-type {
color: #458;
font-weight: bold;
}
@media (prefers-color-scheme: dark) {
body {
background-color: #111;
color: #ddd;
}
pre {
background-color: #222;
}
a, button {
color: #88f;
}
button {
background: #333;
}
button:disabled {
color: #555;
}
code a {
color: #eee;
}
th, td {
border-color: white;
}
.empty-cell {
background: #000;
}
.tooltip-content {
background: #060606;
border-color: white;
}
.status-running { color: #90ee90; }
.status-idle { color: #bbb; }
.step-success { color: #90ee90; }
.step-failure { color: #f66; }
.l {
background-color: red;
}
.c {
background-color: green;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}

View File

@ -1,43 +0,0 @@
:host > details {
padding: 0.5em 1em;
background: #f2f2f2;
margin-bottom: 1.0em;
overflow-x: scroll;
}
:host > details.pending {
pointer-events: none;
background: #fafafa;
color: #666;
}
:host > details > div {
margin: 1em 2em;
overflow: scroll; /* we'll try to avoid overflow, but if it does happen, this makes sense */
}
.stats {
font-size: 1.2em;
}
details.section {
margin: 1.0em 0 0 0;
}
details.section > summary {
font-weight: bold;
}
details.section > :not(summary) {
margin-left: 2em;
}
:host > details.no-llvm .llvm-only {
display: none;
}
@media (prefers-color-scheme: dark) {
:host > details {
background: #222;
}
:host > details.pending {
background: #181818;
color: #888;
}
}
th {
max-width: 20em; /* don't let the 'file' column get crazy long */
overflow-wrap: anywhere; /* avoid overflow where possible */
}

View File

@ -1,280 +0,0 @@
const std = @import("std");
const gpa = std.heap.wasm_allocator;
const abi = std.Build.abi.time_report;
const fmtEscapeHtml = @import("root").fmtEscapeHtml;
const step_list = &@import("root").step_list;
const js = struct {
extern "time_report" fn updateGeneric(
/// The index of the step.
step_idx: u32,
// The HTML which will be used to populate the template slots.
inner_html_ptr: [*]const u8,
inner_html_len: usize,
) void;
extern "time_report" fn updateCompile(
/// The index of the step.
step_idx: u32,
// The HTML which will be used to populate the template slots.
inner_html_ptr: [*]const u8,
inner_html_len: usize,
// The HTML which will populate the <tbody> of the file table.
file_table_html_ptr: [*]const u8,
file_table_html_len: usize,
// The HTML which will populate the <tbody> of the decl table.
decl_table_html_ptr: [*]const u8,
decl_table_html_len: usize,
/// Whether the LLVM backend was used. If not, LLVM-specific statistics are hidden.
use_llvm: bool,
) void;
extern "time_report" fn updateRunTest(
/// The index of the step.
step_idx: u32,
// The HTML which will populate the <tbody> of the test table.
table_html_ptr: [*]const u8,
table_html_len: usize,
) void;
};
pub fn genericResultMessage(msg_bytes: []u8) error{OutOfMemory}!void {
if (msg_bytes.len != @sizeOf(abi.GenericResult)) @panic("malformed GenericResult message");
const msg: *const abi.GenericResult = @ptrCast(msg_bytes);
if (msg.step_idx >= step_list.*.len) @panic("malformed GenericResult message");
const inner_html = try std.fmt.allocPrint(gpa,
\\<code slot="step-name">{[step_name]f}</code>
\\<span slot="stat-total-time">{[stat_total_time]D}</span>
, .{
.step_name = fmtEscapeHtml(step_list.*[msg.step_idx].name),
.stat_total_time = msg.ns_total,
});
defer gpa.free(inner_html);
js.updateGeneric(msg.step_idx, inner_html.ptr, inner_html.len);
}
pub fn compileResultMessage(msg_bytes: []u8) error{ OutOfMemory, WriteFailed }!void {
const max_table_rows = 500;
if (msg_bytes.len < @sizeOf(abi.CompileResult)) @panic("malformed CompileResult message");
const hdr: *const abi.CompileResult = @ptrCast(msg_bytes[0..@sizeOf(abi.CompileResult)]);
if (hdr.step_idx >= step_list.*.len) @panic("malformed CompileResult message");
var trailing = msg_bytes[@sizeOf(abi.CompileResult)..];
const llvm_pass_timings = trailing[0..hdr.llvm_pass_timings_len];
trailing = trailing[hdr.llvm_pass_timings_len..];
const FileTimeReport = struct {
name: []const u8,
ns_sema: u64,
ns_codegen: u64,
ns_link: u64,
};
const DeclTimeReport = struct {
file_name: []const u8,
name: []const u8,
sema_count: u32,
ns_sema: u64,
ns_codegen: u64,
ns_link: u64,
};
const slowest_files = try gpa.alloc(FileTimeReport, hdr.files_len);
defer gpa.free(slowest_files);
const slowest_decls = try gpa.alloc(DeclTimeReport, hdr.decls_len);
defer gpa.free(slowest_decls);
for (slowest_files) |*file_out| {
const i = std.mem.indexOfScalar(u8, trailing, 0) orelse @panic("malformed CompileResult message");
file_out.* = .{
.name = trailing[0..i],
.ns_sema = 0,
.ns_codegen = 0,
.ns_link = 0,
};
trailing = trailing[i + 1 ..];
}
for (slowest_decls) |*decl_out| {
const i = std.mem.indexOfScalar(u8, trailing, 0) orelse @panic("malformed CompileResult message");
const file_idx = std.mem.readInt(u32, trailing[i..][1..5], .little);
const sema_count = std.mem.readInt(u32, trailing[i..][5..9], .little);
const sema_ns = std.mem.readInt(u64, trailing[i..][9..17], .little);
const codegen_ns = std.mem.readInt(u64, trailing[i..][17..25], .little);
const link_ns = std.mem.readInt(u64, trailing[i..][25..33], .little);
const file = &slowest_files[file_idx];
decl_out.* = .{
.file_name = file.name,
.name = trailing[0..i],
.sema_count = sema_count,
.ns_sema = sema_ns,
.ns_codegen = codegen_ns,
.ns_link = link_ns,
};
trailing = trailing[i + 33 ..];
file.ns_sema += sema_ns;
file.ns_codegen += codegen_ns;
file.ns_link += link_ns;
}
const S = struct {
fn fileLessThan(_: void, lhs: FileTimeReport, rhs: FileTimeReport) bool {
const lhs_ns = lhs.ns_sema + lhs.ns_codegen + lhs.ns_link;
const rhs_ns = rhs.ns_sema + rhs.ns_codegen + rhs.ns_link;
return lhs_ns > rhs_ns; // flipped to sort in reverse order
}
fn declLessThan(_: void, lhs: DeclTimeReport, rhs: DeclTimeReport) bool {
//if (true) return lhs.sema_count > rhs.sema_count;
const lhs_ns = lhs.ns_sema + lhs.ns_codegen + lhs.ns_link;
const rhs_ns = rhs.ns_sema + rhs.ns_codegen + rhs.ns_link;
return lhs_ns > rhs_ns; // flipped to sort in reverse order
}
};
std.mem.sort(FileTimeReport, slowest_files, {}, S.fileLessThan);
std.mem.sort(DeclTimeReport, slowest_decls, {}, S.declLessThan);
const stats = hdr.stats;
const inner_html = try std.fmt.allocPrint(gpa,
\\<code slot="step-name">{[step_name]f}</code>
\\<span slot="stat-reachable-files">{[stat_reachable_files]d}</span>
\\<span slot="stat-imported-files">{[stat_imported_files]d}</span>
\\<span slot="stat-generic-instances">{[stat_generic_instances]d}</span>
\\<span slot="stat-inline-calls">{[stat_inline_calls]d}</span>
\\<span slot="stat-compilation-time">{[stat_compilation_time]D}</span>
\\<span slot="cpu-time-parse">{[cpu_time_parse]D}</span>
\\<span slot="cpu-time-astgen">{[cpu_time_astgen]D}</span>
\\<span slot="cpu-time-sema">{[cpu_time_sema]D}</span>
\\<span slot="cpu-time-codegen">{[cpu_time_codegen]D}</span>
\\<span slot="cpu-time-link">{[cpu_time_link]D}</span>
\\<span slot="real-time-files">{[real_time_files]D}</span>
\\<span slot="real-time-decls">{[real_time_decls]D}</span>
\\<span slot="real-time-llvm-emit">{[real_time_llvm_emit]D}</span>
\\<span slot="real-time-link-flush">{[real_time_link_flush]D}</span>
\\<pre slot="llvm-pass-timings"><code>{[llvm_pass_timings]f}</code></pre>
\\
, .{
.step_name = fmtEscapeHtml(step_list.*[hdr.step_idx].name),
.stat_reachable_files = stats.n_reachable_files,
.stat_imported_files = stats.n_imported_files,
.stat_generic_instances = stats.n_generic_instances,
.stat_inline_calls = stats.n_inline_calls,
.stat_compilation_time = hdr.ns_total,
.cpu_time_parse = stats.cpu_ns_parse,
.cpu_time_astgen = stats.cpu_ns_astgen,
.cpu_time_sema = stats.cpu_ns_sema,
.cpu_time_codegen = stats.cpu_ns_codegen,
.cpu_time_link = stats.cpu_ns_link,
.real_time_files = stats.real_ns_files,
.real_time_decls = stats.real_ns_decls,
.real_time_llvm_emit = stats.real_ns_llvm_emit,
.real_time_link_flush = stats.real_ns_link_flush,
.llvm_pass_timings = fmtEscapeHtml(llvm_pass_timings),
});
defer gpa.free(inner_html);
var file_table_html: std.Io.Writer.Allocating = .init(gpa);
defer file_table_html.deinit();
for (slowest_files[0..@min(max_table_rows, slowest_files.len)]) |file| {
try file_table_html.writer.print(
\\<tr>
\\ <th scope="row"><code>{f}</code></th>
\\ <td>{D}</td>
\\ <td>{D}</td>
\\ <td>{D}</td>
\\ <td>{D}</td>
\\</tr>
\\
, .{
fmtEscapeHtml(file.name),
file.ns_sema,
file.ns_codegen,
file.ns_link,
file.ns_sema + file.ns_codegen + file.ns_link,
});
}
if (slowest_files.len > max_table_rows) {
try file_table_html.writer.print(
\\<tr><td colspan="4">{d} more rows omitted</td></tr>
\\
, .{slowest_files.len - max_table_rows});
}
var decl_table_html: std.Io.Writer.Allocating = .init(gpa);
defer decl_table_html.deinit();
for (slowest_decls[0..@min(max_table_rows, slowest_decls.len)]) |decl| {
try decl_table_html.writer.print(
\\<tr>
\\ <th scope="row"><code>{f}</code></th>
\\ <th scope="row"><code>{f}</code></th>
\\ <td>{d}</td>
\\ <td>{D}</td>
\\ <td>{D}</td>
\\ <td>{D}</td>
\\ <td>{D}</td>
\\</tr>
\\
, .{
fmtEscapeHtml(decl.file_name),
fmtEscapeHtml(decl.name),
decl.sema_count,
decl.ns_sema,
decl.ns_codegen,
decl.ns_link,
decl.ns_sema + decl.ns_codegen + decl.ns_link,
});
}
if (slowest_decls.len > max_table_rows) {
try decl_table_html.writer.print(
\\<tr><td colspan="6">{d} more rows omitted</td></tr>
\\
, .{slowest_decls.len - max_table_rows});
}
js.updateCompile(
hdr.step_idx,
inner_html.ptr,
inner_html.len,
file_table_html.written().ptr,
file_table_html.written().len,
decl_table_html.written().ptr,
decl_table_html.written().len,
hdr.flags.use_llvm,
);
}
pub fn runTestResultMessage(msg_bytes: []u8) error{OutOfMemory}!void {
if (msg_bytes.len < @sizeOf(abi.RunTestResult)) @panic("malformed RunTestResult message");
const hdr: *const abi.RunTestResult = @ptrCast(msg_bytes[0..@sizeOf(abi.RunTestResult)]);
if (hdr.step_idx >= step_list.*.len) @panic("malformed RunTestResult message");
const trailing = msg_bytes[@sizeOf(abi.RunTestResult)..];
const durations: []align(1) const u64 = @ptrCast(trailing[0 .. hdr.tests_len * 8]);
var offset: usize = hdr.tests_len * 8;
var table_html: std.ArrayList(u8) = .empty;
defer table_html.deinit(gpa);
for (durations) |test_ns| {
const test_name_len = std.mem.indexOfScalar(u8, trailing[offset..], 0) orelse @panic("malformed RunTestResult message");
const test_name = trailing[offset..][0..test_name_len];
offset += test_name_len + 1;
try table_html.print(gpa, "<tr><th scope=\"row\"><code>{f}</code></th>", .{fmtEscapeHtml(test_name)});
if (test_ns == std.math.maxInt(u64)) {
try table_html.appendSlice(gpa, "<td class=\"empty-cell\"></td>"); // didn't run
} else {
try table_html.print(gpa, "<td>{D}</td>", .{test_ns});
}
try table_html.appendSlice(gpa, "</tr>\n");
}
if (offset != trailing.len) @panic("malformed RunTestResult message");
js.updateRunTest(
hdr.step_idx,
table_html.items.ptr,
table_html.items.len,
);
}

198
lib/c.zig
View File

@ -1,38 +1,180 @@
//! This is Zig's multi-target implementation of libc.
//!
//! When `builtin.link_libc` is true, we need to export all the functions and
//! provide a libc API compatible with the target (e.g. musl, wasi-libc, ...).
//! When builtin.link_libc is true, we need to export all the functions and
//! provide an entire C API.
const builtin = @import("builtin");
const std = @import("std");
const builtin = @import("builtin");
const math = std.math;
const isNan = std.math.isNan;
const maxInt = std.math.maxInt;
const native_os = builtin.os.tag;
const native_arch = builtin.cpu.arch;
const native_abi = builtin.abi;
// Avoid dragging in the runtime safety mechanisms into this .o file, unless
// we're trying to test zigc.
pub const panic = if (builtin.is_test)
std.debug.FullPanic(std.debug.defaultPanic)
else
std.debug.no_panic;
const linkage: std.builtin.GlobalLinkage = if (builtin.is_test) .internal else .strong;
const is_wasm = switch (native_arch) {
.wasm32, .wasm64 => true,
else => false,
};
const is_freestanding = switch (native_os) {
.freestanding, .other => true,
else => false,
};
comptime {
_ = @import("c/inttypes.zig");
_ = @import("c/stdlib.zig");
_ = @import("c/math.zig");
if (builtin.target.isMuslLibC() or builtin.target.isWasiLibC()) {
// Files specific to musl and wasi-libc.
_ = @import("c/string.zig");
_ = @import("c/strings.zig");
if (is_freestanding and is_wasm and builtin.link_libc) {
@export(&wasm_start, .{ .name = "_start", .linkage = .strong });
}
if (builtin.target.isMuslLibC()) {
// Files specific to musl.
}
if (builtin.target.isWasiLibC()) {
// Files specific to wasi-libc.
}
if (builtin.target.isMinGW()) {
// Files specific to MinGW-w64.
if (builtin.link_libc) {
@export(&strcmp, .{ .name = "strcmp", .linkage = linkage });
@export(&strncmp, .{ .name = "strncmp", .linkage = linkage });
@export(&strerror, .{ .name = "strerror", .linkage = linkage });
@export(&strlen, .{ .name = "strlen", .linkage = linkage });
@export(&strcpy, .{ .name = "strcpy", .linkage = linkage });
@export(&strncpy, .{ .name = "strncpy", .linkage = linkage });
@export(&strcat, .{ .name = "strcat", .linkage = linkage });
@export(&strncat, .{ .name = "strncat", .linkage = linkage });
}
}
// Avoid dragging in the runtime safety mechanisms into this .o file,
// unless we're trying to test this file.
pub fn panic(msg: []const u8, error_return_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn {
@branchHint(.cold);
_ = error_return_trace;
if (builtin.is_test) {
std.debug.panic("{s}", .{msg});
}
switch (native_os) {
.freestanding, .other, .amdhsa, .amdpal => while (true) {},
else => std.os.abort(),
}
}
extern fn main(argc: c_int, argv: [*:null]?[*:0]u8) c_int;
fn wasm_start() callconv(.C) void {
_ = main(0, undefined);
}
fn strcpy(dest: [*:0]u8, src: [*:0]const u8) callconv(.C) [*:0]u8 {
var i: usize = 0;
while (src[i] != 0) : (i += 1) {
dest[i] = src[i];
}
dest[i] = 0;
return dest;
}
test "strcpy" {
var s1: [9:0]u8 = undefined;
s1[0] = 0;
_ = strcpy(&s1, "foobarbaz");
try std.testing.expectEqualSlices(u8, "foobarbaz", std.mem.sliceTo(&s1, 0));
}
fn strncpy(dest: [*:0]u8, src: [*:0]const u8, n: usize) callconv(.C) [*:0]u8 {
var i: usize = 0;
while (i < n and src[i] != 0) : (i += 1) {
dest[i] = src[i];
}
while (i < n) : (i += 1) {
dest[i] = 0;
}
return dest;
}
test "strncpy" {
var s1: [9:0]u8 = undefined;
s1[0] = 0;
_ = strncpy(&s1, "foobarbaz", @sizeOf(@TypeOf(s1)));
try std.testing.expectEqualSlices(u8, "foobarbaz", std.mem.sliceTo(&s1, 0));
}
fn strcat(dest: [*:0]u8, src: [*:0]const u8) callconv(.C) [*:0]u8 {
var dest_end: usize = 0;
while (dest[dest_end] != 0) : (dest_end += 1) {}
var i: usize = 0;
while (src[i] != 0) : (i += 1) {
dest[dest_end + i] = src[i];
}
dest[dest_end + i] = 0;
return dest;
}
test "strcat" {
var s1: [9:0]u8 = undefined;
s1[0] = 0;
_ = strcat(&s1, "foo");
_ = strcat(&s1, "bar");
_ = strcat(&s1, "baz");
try std.testing.expectEqualSlices(u8, "foobarbaz", std.mem.sliceTo(&s1, 0));
}
fn strncat(dest: [*:0]u8, src: [*:0]const u8, avail: usize) callconv(.C) [*:0]u8 {
var dest_end: usize = 0;
while (dest[dest_end] != 0) : (dest_end += 1) {}
var i: usize = 0;
while (i < avail and src[i] != 0) : (i += 1) {
dest[dest_end + i] = src[i];
}
dest[dest_end + i] = 0;
return dest;
}
test "strncat" {
var s1: [9:0]u8 = undefined;
s1[0] = 0;
_ = strncat(&s1, "foo1111", 3);
_ = strncat(&s1, "bar1111", 3);
_ = strncat(&s1, "baz1111", 3);
try std.testing.expectEqualSlices(u8, "foobarbaz", std.mem.sliceTo(&s1, 0));
}
fn strcmp(s1: [*:0]const u8, s2: [*:0]const u8) callconv(.C) c_int {
return switch (std.mem.orderZ(u8, s1, s2)) {
.lt => -1,
.eq => 0,
.gt => 1,
};
}
fn strlen(s: [*:0]const u8) callconv(.C) usize {
return std.mem.len(s);
}
fn strncmp(_l: [*:0]const u8, _r: [*:0]const u8, _n: usize) callconv(.C) c_int {
if (_n == 0) return 0;
var l = _l;
var r = _r;
var n = _n - 1;
while (l[0] != 0 and r[0] != 0 and n != 0 and l[0] == r[0]) {
l += 1;
r += 1;
n -= 1;
}
return @as(c_int, l[0]) - @as(c_int, r[0]);
}
fn strerror(errnum: c_int) callconv(.C) [*:0]const u8 {
_ = errnum;
return "TODO strerror implementation";
}
test "strncmp" {
try std.testing.expect(strncmp("a", "b", 1) < 0);
try std.testing.expect(strncmp("a", "c", 1) < 0);
try std.testing.expect(strncmp("b", "a", 1) > 0);
try std.testing.expect(strncmp("\xff", "\x02", 1) > 0);
}

View File

@ -1,15 +0,0 @@
const builtin = @import("builtin");
const std = @import("std");
pub const linkage: std.builtin.GlobalLinkage = if (builtin.is_test)
.internal
else
.strong;
/// Determines the symbol's visibility to other objects.
/// For WebAssembly this allows the symbol to be resolved to other modules, but will not
/// export it to the host runtime.
pub const visibility: std.builtin.SymbolVisibility = if (linkage != .internal)
.hidden
else
.default;

View File

@ -1,20 +0,0 @@
const std = @import("std");
const common = @import("common.zig");
const builtin = @import("builtin");
const intmax_t = std.c.intmax_t;
comptime {
if (builtin.target.isMuslLibC() or builtin.target.isWasiLibC()) {
// Functions specific to musl and wasi-libc.
@export(&imaxabs, .{ .name = "imaxabs", .linkage = common.linkage, .visibility = common.visibility });
}
}
fn imaxabs(a: intmax_t) callconv(.c) intmax_t {
return @intCast(@abs(a));
}
test imaxabs {
const val: intmax_t = -10;
try std.testing.expectEqual(10, imaxabs(val));
}

View File

@ -1,26 +0,0 @@
const std = @import("std");
const common = @import("common.zig");
const builtin = @import("builtin");
comptime {
if (builtin.target.isMinGW()) {
@export(&isnan, .{ .name = "isnan", .linkage = common.linkage, .visibility = common.visibility });
@export(&isnan, .{ .name = "__isnan", .linkage = common.linkage, .visibility = common.visibility });
@export(&isnanf, .{ .name = "isnanf", .linkage = common.linkage, .visibility = common.visibility });
@export(&isnanf, .{ .name = "__isnanf", .linkage = common.linkage, .visibility = common.visibility });
@export(&isnanl, .{ .name = "isnanl", .linkage = common.linkage, .visibility = common.visibility });
@export(&isnanl, .{ .name = "__isnanl", .linkage = common.linkage, .visibility = common.visibility });
}
}
fn isnan(x: f64) callconv(.c) c_int {
return if (std.math.isNan(x)) 1 else 0;
}
fn isnanf(x: f32) callconv(.c) c_int {
return if (std.math.isNan(x)) 1 else 0;
}
fn isnanl(x: c_longdouble) callconv(.c) c_int {
return if (std.math.isNan(x)) 1 else 0;
}

View File

@ -1,39 +0,0 @@
const std = @import("std");
const common = @import("common.zig");
const builtin = @import("builtin");
comptime {
if (builtin.target.isMuslLibC() or builtin.target.isWasiLibC()) {
// Functions specific to musl and wasi-libc.
@export(&abs, .{ .name = "abs", .linkage = common.linkage, .visibility = common.visibility });
@export(&labs, .{ .name = "labs", .linkage = common.linkage, .visibility = common.visibility });
@export(&llabs, .{ .name = "llabs", .linkage = common.linkage, .visibility = common.visibility });
}
}
fn abs(a: c_int) callconv(.c) c_int {
return @intCast(@abs(a));
}
fn labs(a: c_long) callconv(.c) c_long {
return @intCast(@abs(a));
}
fn llabs(a: c_longlong) callconv(.c) c_longlong {
return @intCast(@abs(a));
}
test abs {
const val: c_int = -10;
try std.testing.expectEqual(10, abs(val));
}
test labs {
const val: c_long = -10;
try std.testing.expectEqual(10, labs(val));
}
test llabs {
const val: c_longlong = -10;
try std.testing.expectEqual(10, llabs(val));
}

View File

@ -1,104 +0,0 @@
const builtin = @import("builtin");
const std = @import("std");
const common = @import("common.zig");
comptime {
@export(&strcmp, .{ .name = "strcmp", .linkage = common.linkage, .visibility = common.visibility });
@export(&strncmp, .{ .name = "strncmp", .linkage = common.linkage, .visibility = common.visibility });
@export(&strcasecmp, .{ .name = "strcasecmp", .linkage = common.linkage, .visibility = common.visibility });
@export(&strncasecmp, .{ .name = "strncasecmp", .linkage = common.linkage, .visibility = common.visibility });
@export(&__strcasecmp_l, .{ .name = "__strcasecmp_l", .linkage = common.linkage, .visibility = common.visibility });
@export(&__strncasecmp_l, .{ .name = "__strncasecmp_l", .linkage = common.linkage, .visibility = common.visibility });
@export(&__strcasecmp_l, .{ .name = "strcasecmp_l", .linkage = .weak, .visibility = common.visibility });
@export(&__strncasecmp_l, .{ .name = "strncasecmp_l", .linkage = .weak, .visibility = common.visibility });
}
fn strcmp(s1: [*:0]const c_char, s2: [*:0]const c_char) callconv(.c) c_int {
// We need to perform unsigned comparisons.
return switch (std.mem.orderZ(u8, @ptrCast(s1), @ptrCast(s2))) {
.lt => -1,
.eq => 0,
.gt => 1,
};
}
fn strncmp(s1: [*:0]const c_char, s2: [*:0]const c_char, n: usize) callconv(.c) c_int {
if (n == 0) return 0;
var l: [*:0]const u8 = @ptrCast(s1);
var r: [*:0]const u8 = @ptrCast(s2);
var i = n - 1;
while (l[0] != 0 and r[0] != 0 and i != 0 and l[0] == r[0]) {
l += 1;
r += 1;
i -= 1;
}
return @as(c_int, l[0]) - @as(c_int, r[0]);
}
fn strcasecmp(s1: [*:0]const c_char, s2: [*:0]const c_char) callconv(.c) c_int {
const toLower = std.ascii.toLower;
var l: [*:0]const u8 = @ptrCast(s1);
var r: [*:0]const u8 = @ptrCast(s2);
while (l[0] != 0 and r[0] != 0 and (l[0] == r[0] or toLower(l[0]) == toLower(r[0]))) {
l += 1;
r += 1;
}
return @as(c_int, toLower(l[0])) - @as(c_int, toLower(r[0]));
}
fn __strcasecmp_l(s1: [*:0]const c_char, s2: [*:0]const c_char, locale: *anyopaque) callconv(.c) c_int {
_ = locale;
return strcasecmp(s1, s2);
}
fn strncasecmp(s1: [*:0]const c_char, s2: [*:0]const c_char, n: usize) callconv(.c) c_int {
const toLower = std.ascii.toLower;
var l: [*:0]const u8 = @ptrCast(s1);
var r: [*:0]const u8 = @ptrCast(s2);
var i = n - 1;
while (l[0] != 0 and r[0] != 0 and i != 0 and (l[0] == r[0] or toLower(l[0]) == toLower(r[0]))) {
l += 1;
r += 1;
i -= 1;
}
return @as(c_int, toLower(l[0])) - @as(c_int, toLower(r[0]));
}
fn __strncasecmp_l(s1: [*:0]const c_char, s2: [*:0]const c_char, n: usize, locale: *anyopaque) callconv(.c) c_int {
_ = locale;
return strncasecmp(s1, s2, n);
}
test strcasecmp {
try std.testing.expect(strcasecmp(@ptrCast("a"), @ptrCast("b")) < 0);
try std.testing.expect(strcasecmp(@ptrCast("b"), @ptrCast("a")) > 0);
try std.testing.expect(strcasecmp(@ptrCast("A"), @ptrCast("b")) < 0);
try std.testing.expect(strcasecmp(@ptrCast("b"), @ptrCast("A")) > 0);
try std.testing.expect(strcasecmp(@ptrCast("A"), @ptrCast("A")) == 0);
try std.testing.expect(strcasecmp(@ptrCast("B"), @ptrCast("b")) == 0);
try std.testing.expect(strcasecmp(@ptrCast("bb"), @ptrCast("AA")) > 0);
}
test strncasecmp {
try std.testing.expect(strncasecmp(@ptrCast("a"), @ptrCast("b"), 1) < 0);
try std.testing.expect(strncasecmp(@ptrCast("b"), @ptrCast("a"), 1) > 0);
try std.testing.expect(strncasecmp(@ptrCast("A"), @ptrCast("b"), 1) < 0);
try std.testing.expect(strncasecmp(@ptrCast("b"), @ptrCast("A"), 1) > 0);
try std.testing.expect(strncasecmp(@ptrCast("A"), @ptrCast("A"), 1) == 0);
try std.testing.expect(strncasecmp(@ptrCast("B"), @ptrCast("b"), 1) == 0);
try std.testing.expect(strncasecmp(@ptrCast("bb"), @ptrCast("AA"), 2) > 0);
}
test strncmp {
try std.testing.expect(strncmp(@ptrCast("a"), @ptrCast("b"), 1) < 0);
try std.testing.expect(strncmp(@ptrCast("a"), @ptrCast("c"), 1) < 0);
try std.testing.expect(strncmp(@ptrCast("b"), @ptrCast("a"), 1) > 0);
try std.testing.expect(strncmp(@ptrCast("\xff"), @ptrCast("\x02"), 1) > 0);
}

View File

@ -1,19 +0,0 @@
const std = @import("std");
const common = @import("common.zig");
comptime {
@export(&bzero, .{ .name = "bzero", .linkage = common.linkage, .visibility = common.visibility });
}
fn bzero(s: *anyopaque, n: usize) callconv(.c) void {
const s_cast: [*]u8 = @ptrCast(s);
@memset(s_cast[0..n], 0);
}
test bzero {
var array: [10]u8 = [_]u8{ '1', '2', '3', '4', '5', '6', '7', '8', '9', '0' };
var a = std.mem.zeroes([array.len]u8);
a[9] = '0';
bzero(&array[0], 9);
try std.testing.expect(std.mem.eql(u8, &array, &a));
}

26
lib/compiler/aro/README.md vendored Normal file
View File

@ -0,0 +1,26 @@
<img src="https://aro.vexu.eu/aro-logo.svg" alt="Aro" width="120px"/>
# Aro
A C compiler with the goal of providing fast compilation and low memory usage with good diagnostics.
Aro is included as an alternative C frontend in the [Zig compiler](https://github.com/ziglang/zig)
for `translate-c` and eventually compiling C files by translating them to Zig first.
Aro is developed in https://github.com/Vexu/arocc and the Zig dependency is
updated from there when needed.
Currently most of standard C is supported up to C23 and as are many of the common
extensions from GNU, MSVC, and Clang
Basic code generation is supported for x86-64 linux and can produce a valid hello world:
```sh-session
$ cat hello.c
extern int printf(const char *restrict fmt, ...);
int main(void) {
printf("Hello, world!\n");
return 0;
}
$ zig build && ./zig-out/bin/arocc hello.c -o hello
$ ./hello
Hello, world!
```

View File

@ -5,14 +5,12 @@ pub const Driver = @import("aro/Driver.zig");
pub const Parser = @import("aro/Parser.zig");
pub const Preprocessor = @import("aro/Preprocessor.zig");
pub const Source = @import("aro/Source.zig");
pub const StringInterner = @import("aro/StringInterner.zig");
pub const Target = @import("aro/Target.zig");
pub const Tokenizer = @import("aro/Tokenizer.zig");
pub const Toolchain = @import("aro/Toolchain.zig");
pub const Tree = @import("aro/Tree.zig");
pub const TypeStore = @import("aro/TypeStore.zig");
pub const QualType = TypeStore.QualType;
pub const Type = TypeStore.Type;
pub const Type = @import("aro/Type.zig");
pub const TypeMapper = @import("aro/StringInterner.zig").TypeMapper;
pub const target_util = @import("aro/target.zig");
pub const Value = @import("aro/Value.zig");
const backend = @import("backend.zig");
@ -20,7 +18,6 @@ pub const Interner = backend.Interner;
pub const Ir = backend.Ir;
pub const Object = backend.Object;
pub const CallingConvention = backend.CallingConvention;
pub const Assembly = backend.Assembly;
pub const version_str = backend.version_str;
pub const version = backend.version;
@ -31,11 +28,12 @@ test {
_ = @import("aro/char_info.zig");
_ = @import("aro/Compilation.zig");
_ = @import("aro/Driver/Distro.zig");
_ = @import("aro/Driver/Filesystem.zig");
_ = @import("aro/Driver/GCCVersion.zig");
_ = @import("aro/InitList.zig");
_ = @import("aro/LangOpts.zig");
_ = @import("aro/Preprocessor.zig");
_ = @import("aro/Target.zig");
_ = @import("aro/target.zig");
_ = @import("aro/Tokenizer.zig");
_ = @import("aro/toolchains/Linux.zig");
_ = @import("aro/Value.zig");
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,115 +1,62 @@
const std = @import("std");
const Compilation = @import("Compilation.zig");
const Type = @import("Type.zig");
const TypeDescription = @import("Builtins/TypeDescription.zig");
const target_util = @import("target.zig");
const StringId = @import("StringInterner.zig").StringId;
const LangOpts = @import("LangOpts.zig");
const Parser = @import("Parser.zig");
const Target = @import("Target.zig");
const TypeStore = @import("TypeStore.zig");
const QualType = TypeStore.QualType;
const Builder = TypeStore.Builder;
const TypeDescription = @import("Builtins/TypeDescription.zig");
const properties = @import("Builtins/properties.zig");
const BuiltinBase = struct {
param_str: [*:0]const u8,
language: properties.Language = .all_languages,
attributes: properties.Attributes = .{},
header: properties.Header = .none,
const Properties = @import("Builtins/Properties.zig");
pub const Builtin = @import("Builtins/Builtin.zig").with(Properties);
const Expanded = struct {
ty: Type,
builtin: Builtin,
};
const BuiltinTarget = struct {
param_str: [*:0]const u8,
language: properties.Language = .all_languages,
attributes: properties.Attributes = .{},
header: properties.Header = .none,
features: ?[*:0]const u8 = null,
};
const aarch64 = @import("Builtins/aarch64.zig").with(BuiltinTarget);
const amdgcn = @import("Builtins/amdgcn.zig").with(BuiltinTarget);
const arm = @import("Builtins/arm.zig").with(BuiltinTarget);
const bpf = @import("Builtins/bpf.zig").with(BuiltinTarget);
const common = @import("Builtins/common.zig").with(BuiltinBase);
const hexagon = @import("Builtins/hexagon.zig").with(BuiltinTarget);
const loongarch = @import("Builtins/loongarch.zig").with(BuiltinTarget);
const mips = @import("Builtins/mips.zig").with(BuiltinBase);
const nvptx = @import("Builtins/nvptx.zig").with(BuiltinTarget);
const powerpc = @import("Builtins/powerpc.zig").with(BuiltinTarget);
const riscv = @import("Builtins/riscv.zig").with(BuiltinTarget);
const s390x = @import("Builtins/s390x.zig").with(BuiltinTarget);
const ve = @import("Builtins/ve.zig").with(BuiltinBase);
const x86_64 = @import("Builtins/x86_64.zig").with(BuiltinTarget);
const x86 = @import("Builtins/x86.zig").with(BuiltinTarget);
const xcore = @import("Builtins/xcore.zig").with(BuiltinBase);
pub const Tag = union(enum) {
aarch64: aarch64.Tag,
amdgcn: amdgcn.Tag,
arm: arm.Tag,
bpf: bpf.Tag,
common: common.Tag,
hexagon: hexagon.Tag,
loongarch: loongarch.Tag,
mips: mips.Tag,
nvptx: nvptx.Tag,
powerpc: powerpc.Tag,
riscv: riscv.Tag,
s390x: s390x.Tag,
ve: ve.Tag,
x86_64: x86_64.Tag,
x86: x86.Tag,
xcore: xcore.Tag,
};
pub const Expanded = struct {
tag: Tag,
qt: QualType,
language: properties.Language = .all_languages,
attributes: properties.Attributes = .{},
header: properties.Header = .none,
};
const NameToTypeMap = std.StringHashMapUnmanaged(Type);
const Builtins = @This();
_name_to_type_map: std.StringHashMapUnmanaged(Expanded) = .{},
_name_to_type_map: NameToTypeMap = .{},
pub fn deinit(b: *Builtins, gpa: std.mem.Allocator) void {
b._name_to_type_map.deinit(gpa);
}
fn specForSize(comp: *const Compilation, size_bits: u32) TypeStore.Builder.Specifier {
var qt: QualType = .short;
if (qt.bitSizeof(comp) == size_bits) return .short;
fn specForSize(comp: *const Compilation, size_bits: u32) Type.Builder.Specifier {
var ty = Type{ .specifier = .short };
if (ty.sizeof(comp).? * 8 == size_bits) return .short;
qt = .int;
if (qt.bitSizeof(comp) == size_bits) return .int;
ty.specifier = .int;
if (ty.sizeof(comp).? * 8 == size_bits) return .int;
qt = .long;
if (qt.bitSizeof(comp) == size_bits) return .long;
ty.specifier = .long;
if (ty.sizeof(comp).? * 8 == size_bits) return .long;
qt = .long_long;
if (qt.bitSizeof(comp) == size_bits) return .long_long;
ty.specifier = .long_long;
if (ty.sizeof(comp).? * 8 == size_bits) return .long_long;
unreachable;
}
fn createType(desc: TypeDescription, it: *TypeDescription.TypeIterator, comp: *Compilation) !QualType {
var parser: Parser = undefined;
parser.comp = comp;
var builder: TypeStore.Builder = .{ .parser = &parser, .error_on_invalid = true };
var actual_suffix = desc.suffix;
fn createType(desc: TypeDescription, it: *TypeDescription.TypeIterator, comp: *const Compilation, allocator: std.mem.Allocator) !Type {
var builder: Type.Builder = .{ .error_on_invalid = true };
var require_native_int32 = false;
var require_native_int64 = false;
for (desc.prefix) |prefix| {
switch (prefix) {
.L => builder.combine(.long, 0) catch unreachable,
.LL => builder.combine(.long_long, 0) catch unreachable,
.L => builder.combine(undefined, .long, 0) catch unreachable,
.LL => {
builder.combine(undefined, .long, 0) catch unreachable;
builder.combine(undefined, .long, 0) catch unreachable;
},
.LLL => {
switch (builder.type) {
.none => builder.type = .int128,
.signed => builder.type = .sint128,
.unsigned => builder.type = .uint128,
switch (builder.specifier) {
.none => builder.specifier = .int128,
.signed => builder.specifier = .sint128,
.unsigned => builder.specifier = .uint128,
else => unreachable,
}
},
@ -117,285 +64,331 @@ fn createType(desc: TypeDescription, it: *TypeDescription.TypeIterator, comp: *C
.W => require_native_int64 = true,
.N => {
std.debug.assert(desc.spec == .i);
if (!comp.target.isLP64()) {
builder.combine(.long, 0) catch unreachable;
if (!target_util.isLP64(comp.target)) {
builder.combine(undefined, .long, 0) catch unreachable;
}
},
.O => {
builder.combine(.long, 0) catch unreachable;
builder.combine(undefined, .long, 0) catch unreachable;
if (comp.target.os.tag != .opencl) {
builder.combine(.long, 0) catch unreachable;
builder.combine(undefined, .long, 0) catch unreachable;
}
},
.S => builder.combine(.signed, 0) catch unreachable,
.U => builder.combine(.unsigned, 0) catch unreachable,
.S => builder.combine(undefined, .signed, 0) catch unreachable,
.U => builder.combine(undefined, .unsigned, 0) catch unreachable,
.I => {
// Todo: compile-time constant integer
},
}
}
switch (desc.spec) {
.v => builder.combine(.void, 0) catch unreachable,
.b => builder.combine(.bool, 0) catch unreachable,
.c => builder.combine(.char, 0) catch unreachable,
.s => builder.combine(.short, 0) catch unreachable,
.v => builder.combine(undefined, .void, 0) catch unreachable,
.b => builder.combine(undefined, .bool, 0) catch unreachable,
.c => builder.combine(undefined, .char, 0) catch unreachable,
.s => builder.combine(undefined, .short, 0) catch unreachable,
.i => {
if (require_native_int32) {
builder.type = specForSize(comp, 32);
builder.specifier = specForSize(comp, 32);
} else if (require_native_int64) {
builder.type = specForSize(comp, 64);
builder.specifier = specForSize(comp, 64);
} else {
switch (builder.type) {
switch (builder.specifier) {
.int128, .sint128, .uint128 => {},
else => builder.combine(.int, 0) catch unreachable,
else => builder.combine(undefined, .int, 0) catch unreachable,
}
}
},
.h => builder.combine(.fp16, 0) catch unreachable,
.x => builder.combine(.float16, 0) catch unreachable,
.y => builder.combine(.bf16, 0) catch unreachable,
.f => builder.combine(.float, 0) catch unreachable,
.h => builder.combine(undefined, .fp16, 0) catch unreachable,
.x => builder.combine(undefined, .float16, 0) catch unreachable,
.y => {
// Todo: __bf16
return .{ .specifier = .invalid };
},
.f => builder.combine(undefined, .float, 0) catch unreachable,
.d => {
if (builder.type == .long_long) {
builder.type = .float128;
if (builder.specifier == .long_long) {
builder.specifier = .float128;
} else {
builder.combine(.double, 0) catch unreachable;
builder.combine(undefined, .double, 0) catch unreachable;
}
},
.z => {
std.debug.assert(builder.type == .none);
builder.type = Builder.fromType(comp, comp.type_store.size);
std.debug.assert(builder.specifier == .none);
builder.specifier = Type.Builder.fromType(comp.types.size);
},
.w => {
std.debug.assert(builder.type == .none);
builder.type = Builder.fromType(comp, comp.type_store.wchar);
std.debug.assert(builder.specifier == .none);
builder.specifier = Type.Builder.fromType(comp.types.wchar);
},
.F => {
std.debug.assert(builder.type == .none);
builder.type = Builder.fromType(comp, comp.type_store.ns_constant_string);
std.debug.assert(builder.specifier == .none);
builder.specifier = Type.Builder.fromType(comp.types.ns_constant_string.ty);
},
.G => {
// Todo: id
return .{ .specifier = .invalid };
},
.H => {
// Todo: SEL
return .{ .specifier = .invalid };
},
.M => {
// Todo: struct objc_super
return .{ .specifier = .invalid };
},
.a => {
std.debug.assert(builder.type == .none);
std.debug.assert(builder.specifier == .none);
std.debug.assert(desc.suffix.len == 0);
builder.type = Builder.fromType(comp, comp.type_store.va_list);
builder.specifier = Type.Builder.fromType(comp.types.va_list);
},
.A => {
std.debug.assert(builder.type == .none);
std.debug.assert(builder.specifier == .none);
std.debug.assert(desc.suffix.len == 0);
var va_list = comp.type_store.va_list;
std.debug.assert(!va_list.is(comp, .array));
builder.type = Builder.fromType(comp, va_list);
var va_list = comp.types.va_list;
if (va_list.isArray()) va_list.decayArray();
builder.specifier = Type.Builder.fromType(va_list);
},
.V => |element_count| {
std.debug.assert(desc.suffix.len == 0);
var child_desc = it.next().?;
actual_suffix = child_desc.suffix;
child_desc.suffix = &.{};
const elem_qt = try createType(child_desc, undefined, comp);
const vector_qt = try comp.type_store.put(comp.gpa, .{ .vector = .{
.elem = elem_qt,
const child_desc = it.next().?;
const child_ty = try createType(child_desc, undefined, comp, allocator);
const arr_ty = try allocator.create(Type.Array);
arr_ty.* = .{
.len = element_count,
} });
builder.type = .{ .other = vector_qt };
.elem = child_ty,
};
const vector_ty: Type = .{ .specifier = .vector, .data = .{ .array = arr_ty } };
builder.specifier = Type.Builder.fromType(vector_ty);
},
.Q => {
// Todo: target builtin type
return .invalid;
.q => {
// Todo: scalable vector
return .{ .specifier = .invalid };
},
.E => {
// Todo: ext_vector (OpenCL vector)
return .invalid;
return .{ .specifier = .invalid };
},
.X => |child| {
builder.combine(.complex, 0) catch unreachable;
builder.combine(undefined, .complex, 0) catch unreachable;
switch (child) {
.float => builder.combine(.float, 0) catch unreachable,
.double => builder.combine(.double, 0) catch unreachable,
.float => builder.combine(undefined, .float, 0) catch unreachable,
.double => builder.combine(undefined, .double, 0) catch unreachable,
.longdouble => {
builder.combine(.long, 0) catch unreachable;
builder.combine(.double, 0) catch unreachable;
builder.combine(undefined, .long, 0) catch unreachable;
builder.combine(undefined, .double, 0) catch unreachable;
},
}
},
.Y => {
std.debug.assert(builder.type == .none);
std.debug.assert(builder.specifier == .none);
std.debug.assert(desc.suffix.len == 0);
builder.type = Builder.fromType(comp, comp.type_store.ptrdiff);
builder.specifier = Type.Builder.fromType(comp.types.ptrdiff);
},
.P => {
std.debug.assert(builder.type == .none);
if (comp.type_store.file.isInvalid()) {
return comp.type_store.file;
std.debug.assert(builder.specifier == .none);
if (comp.types.file.specifier == .invalid) {
return comp.types.file;
}
builder.type = Builder.fromType(comp, comp.type_store.file);
builder.specifier = Type.Builder.fromType(comp.types.file);
},
.J => {
std.debug.assert(builder.type == .none);
std.debug.assert(builder.specifier == .none);
std.debug.assert(desc.suffix.len == 0);
if (comp.type_store.jmp_buf.isInvalid()) {
return comp.type_store.jmp_buf;
if (comp.types.jmp_buf.specifier == .invalid) {
return comp.types.jmp_buf;
}
builder.type = Builder.fromType(comp, comp.type_store.jmp_buf);
builder.specifier = Type.Builder.fromType(comp.types.jmp_buf);
},
.SJ => {
std.debug.assert(builder.type == .none);
std.debug.assert(builder.specifier == .none);
std.debug.assert(desc.suffix.len == 0);
if (comp.type_store.sigjmp_buf.isInvalid()) {
return comp.type_store.sigjmp_buf;
if (comp.types.sigjmp_buf.specifier == .invalid) {
return comp.types.sigjmp_buf;
}
builder.type = Builder.fromType(comp, comp.type_store.sigjmp_buf);
builder.specifier = Type.Builder.fromType(comp.types.sigjmp_buf);
},
.K => {
std.debug.assert(builder.type == .none);
if (comp.type_store.ucontext_t.isInvalid()) {
return comp.type_store.ucontext_t;
std.debug.assert(builder.specifier == .none);
if (comp.types.ucontext_t.specifier == .invalid) {
return comp.types.ucontext_t;
}
builder.type = Builder.fromType(comp, comp.type_store.ucontext_t);
builder.specifier = Type.Builder.fromType(comp.types.ucontext_t);
},
.p => {
std.debug.assert(builder.type == .none);
std.debug.assert(builder.specifier == .none);
std.debug.assert(desc.suffix.len == 0);
builder.type = Builder.fromType(comp, comp.type_store.pid_t);
builder.specifier = Type.Builder.fromType(comp.types.pid_t);
},
.@"!" => return .{ .specifier = .invalid },
}
for (actual_suffix) |suffix| {
for (desc.suffix) |suffix| {
switch (suffix) {
.@"*" => |address_space| {
_ = address_space; // TODO: handle address space
const pointer_qt = try comp.type_store.put(comp.gpa, .{ .pointer = .{
.child = builder.finish() catch unreachable,
.decayed = null,
} });
builder.@"const" = null;
builder.@"volatile" = null;
builder.restrict = null;
builder.type = .{ .other = pointer_qt };
const elem_ty = try allocator.create(Type);
elem_ty.* = builder.finish(undefined) catch unreachable;
const ty = Type{
.specifier = .pointer,
.data = .{ .sub_type = elem_ty },
};
builder.qual = .{};
builder.specifier = Type.Builder.fromType(ty);
},
.C => builder.@"const" = 0,
.D => builder.@"volatile" = 0,
.R => builder.restrict = 0,
.C => builder.qual.@"const" = 0,
.D => builder.qual.@"volatile" = 0,
.R => builder.qual.restrict = 0,
}
}
return builder.finish() catch unreachable;
return builder.finish(undefined) catch unreachable;
}
fn createBuiltin(comp: *Compilation, param_str: [*:0]const u8) !QualType {
var it = TypeDescription.TypeIterator.init(param_str);
fn createBuiltin(comp: *const Compilation, builtin: Builtin, type_arena: std.mem.Allocator) !Type {
var it = TypeDescription.TypeIterator.init(builtin.properties.param_str);
const ret_ty_desc = it.next().?;
const ret_ty = try createType(ret_ty_desc, &it, comp);
if (ret_ty_desc.spec == .@"!") {
// Todo: handle target-dependent definition
}
const ret_ty = try createType(ret_ty_desc, &it, comp, type_arena);
var param_count: usize = 0;
var params: [32]TypeStore.Type.Func.Param = undefined;
var params: [Builtin.max_param_count]Type.Func.Param = undefined;
while (it.next()) |desc| : (param_count += 1) {
params[param_count] = .{ .name_tok = 0, .qt = try createType(desc, &it, comp), .name = .empty, .node = .null };
params[param_count] = .{ .name_tok = 0, .ty = try createType(desc, &it, comp, type_arena), .name = .empty };
}
return comp.type_store.put(comp.gpa, .{ .func = .{
const duped_params = try type_arena.dupe(Type.Func.Param, params[0..param_count]);
const func = try type_arena.create(Type.Func);
func.* = .{
.return_type = ret_ty,
.kind = if (properties.isVarArgs(param_str)) .variadic else .normal,
.params = params[0..param_count],
} });
.params = duped_params,
};
return .{
.specifier = if (builtin.properties.isVarArgs()) .var_args_func else .func,
.data = .{ .func = func },
};
}
/// Asserts that the builtin has already been created
pub fn lookup(b: *const Builtins, name: []const u8) Expanded {
return b._name_to_type_map.get(name).?;
const builtin = Builtin.fromName(name).?;
const ty = b._name_to_type_map.get(name).?;
return .{
.builtin = builtin,
.ty = ty,
};
}
pub fn getOrCreate(b: *Builtins, comp: *Compilation, name: []const u8) !?Expanded {
if (b._name_to_type_map.get(name)) |expanded| return expanded;
const builtin = fromName(comp, name) orelse return null;
if (builtin.features) |_| {
// TODO check features
}
pub fn getOrCreate(b: *Builtins, comp: *Compilation, name: []const u8, type_arena: std.mem.Allocator) !?Expanded {
const ty = b._name_to_type_map.get(name) orelse {
const builtin = Builtin.fromName(name) orelse return null;
if (!comp.hasBuiltinFunction(builtin)) return null;
try b._name_to_type_map.ensureUnusedCapacity(comp.gpa, 1);
const expanded: Expanded = .{
.tag = builtin.tag,
.qt = try createBuiltin(comp, builtin.param_str),
.attributes = builtin.attributes,
.header = builtin.header,
.language = builtin.language,
};
b._name_to_type_map.putAssumeCapacity(name, expanded);
return expanded;
}
pub const FromName = struct {
tag: Tag,
param_str: [*:0]const u8,
language: properties.Language = .all_languages,
attributes: properties.Attributes = .{},
header: properties.Header = .none,
features: ?[*:0]const u8 = null,
};
pub fn fromName(comp: *Compilation, name: []const u8) ?FromName {
if (fromNameExtra(name, .common)) |found| return found;
switch (comp.target.cpu.arch) {
.aarch64, .aarch64_be => if (fromNameExtra(name, .aarch64)) |found| return found,
.amdgcn => if (fromNameExtra(name, .amdgcn)) |found| return found,
.arm, .armeb, .thumb, .thumbeb => if (fromNameExtra(name, .arm)) |found| return found,
.bpfeb, .bpfel => if (fromNameExtra(name, .bpf)) |found| return found,
.hexagon => if (fromNameExtra(name, .hexagon)) |found| return found,
.loongarch32, .loongarch64 => if (fromNameExtra(name, .loongarch)) |found| return found,
.mips64, .mips64el, .mips, .mipsel => if (fromNameExtra(name, .mips)) |found| return found,
.nvptx, .nvptx64 => if (fromNameExtra(name, .nvptx)) |found| return found,
.powerpc64, .powerpc64le, .powerpc, .powerpcle => if (fromNameExtra(name, .powerpc)) |found| return found,
.riscv32, .riscv32be, .riscv64, .riscv64be => if (fromNameExtra(name, .riscv)) |found| return found,
.s390x => if (fromNameExtra(name, .s390x)) |found| return found,
.ve => if (fromNameExtra(name, .ve)) |found| return found,
.xcore => if (fromNameExtra(name, .xcore)) |found| return found,
.x86_64 => {
if (fromNameExtra(name, .x86_64)) |found| return found;
if (fromNameExtra(name, .x86)) |found| return found;
},
.x86 => if (fromNameExtra(name, .x86)) |found| return found,
else => {},
}
return null;
}
fn fromNameExtra(name: []const u8, comptime arch: std.meta.Tag(Tag)) ?FromName {
const list = @field(@This(), @tagName(arch));
const tag = list.tagFromName(name) orelse return null;
const builtin = list.data[@intFromEnum(tag)];
const ty = try createBuiltin(comp, builtin, type_arena);
b._name_to_type_map.putAssumeCapacity(name, ty);
return .{
.tag = @unionInit(Tag, @tagName(arch), tag),
.param_str = builtin.param_str,
.header = builtin.header,
.language = builtin.language,
.attributes = builtin.attributes,
.features = if (@hasField(@TypeOf(builtin), "features")) builtin.features else null,
.builtin = builtin,
.ty = ty,
};
};
const builtin = Builtin.fromName(name).?;
return .{
.builtin = builtin,
.ty = ty,
};
}
test "all builtins" {
const list_names = comptime std.meta.fieldNames(Tag);
inline for (list_names) |list_name| {
const list = @field(Builtins, list_name);
for (list.data, 0..) |builtin, index| {
{
var it = TypeDescription.TypeIterator.init(builtin.param_str);
while (it.next()) |_| {}
}
if (@hasField(@TypeOf(builtin), "features")) {
const corrected_name = comptime if (std.mem.eql(u8, list_name, "x86_64")) "x86" else list_name;
const features = &@field(std.Target, corrected_name).all_features;
pub const Iterator = struct {
index: u16 = 1,
name_buf: [Builtin.longest_name]u8 = undefined,
const feature_string = builtin.features orelse continue;
var it = std.mem.tokenizeAny(u8, std.mem.span(feature_string), "()|,");
pub const Entry = struct {
/// Memory of this slice is overwritten on every call to `next`
name: []const u8,
builtin: Builtin,
};
outer: while (it.next()) |feature| {
for (features) |valid_feature| {
if (std.mem.eql(u8, feature, valid_feature.name)) continue :outer;
pub fn next(self: *Iterator) ?Entry {
if (self.index > Builtin.data.len) return null;
const index = self.index;
const data_index = index - 1;
self.index += 1;
return .{
.name = Builtin.nameFromUniqueIndex(index, &self.name_buf),
.builtin = Builtin.data[data_index],
};
}
std.debug.panic("unknown feature {s} on {t}\n", .{ feature, @as(list.Tag, @enumFromInt(index)) });
};
test Iterator {
var it = Iterator{};
var seen = std.StringHashMap(Builtin).init(std.testing.allocator);
defer seen.deinit();
var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator);
defer arena_state.deinit();
const arena = arena_state.allocator();
while (it.next()) |entry| {
const index = Builtin.uniqueIndex(entry.name).?;
var buf: [Builtin.longest_name]u8 = undefined;
const name_from_index = Builtin.nameFromUniqueIndex(index, &buf);
try std.testing.expectEqualStrings(entry.name, name_from_index);
if (seen.contains(entry.name)) {
std.debug.print("iterated over {s} twice\n", .{entry.name});
std.debug.print("current data: {}\n", .{entry.builtin});
std.debug.print("previous data: {}\n", .{seen.get(entry.name).?});
return error.TestExpectedUniqueEntries;
}
try seen.put(try arena.dupe(u8, entry.name), entry.builtin);
}
try std.testing.expectEqual(@as(usize, Builtin.data.len), seen.count());
}
test "All builtins" {
var comp = Compilation.init(std.testing.allocator, std.fs.cwd());
defer comp.deinit();
_ = try comp.generateBuiltinMacros(.include_system_defines);
var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
defer arena.deinit();
const type_arena = arena.allocator();
var builtin_it = Iterator{};
while (builtin_it.next()) |entry| {
const name = try type_arena.dupe(u8, entry.name);
if (try comp.builtins.getOrCreate(&comp, name, type_arena)) |func_ty| {
const get_again = (try comp.builtins.getOrCreate(&comp, name, std.testing.failing_allocator)).?;
const found_by_lookup = comp.builtins.lookup(name);
try std.testing.expectEqual(func_ty.builtin.tag, get_again.builtin.tag);
try std.testing.expectEqual(func_ty.builtin.tag, found_by_lookup.builtin.tag);
}
}
}
test "Allocation failures" {
const Test = struct {
fn testOne(allocator: std.mem.Allocator) !void {
var comp = Compilation.init(allocator, std.fs.cwd());
defer comp.deinit();
_ = try comp.generateBuiltinMacros(.include_system_defines);
var arena = std.heap.ArenaAllocator.init(comp.gpa);
defer arena.deinit();
const type_arena = arena.allocator();
const num_builtins = 40;
var builtin_it = Iterator{};
for (0..num_builtins) |_| {
const entry = builtin_it.next().?;
_ = try comp.builtins.getOrCreate(&comp, entry.name, type_arena);
}
}
};
try std.testing.checkAllAllocationFailures(std.testing.allocator, Test.testOne, .{});
}

13146
lib/compiler/aro/aro/Builtins/Builtin.zig vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,143 @@
const std = @import("std");
const Properties = @This();
param_str: []const u8,
language: Language = .all_languages,
attributes: Attributes = Attributes{},
header: Header = .none,
target_set: TargetSet = TargetSet.initOne(.basic),
/// Header which must be included for a builtin to be available
pub const Header = enum {
none,
/// stdio.h
stdio,
/// stdlib.h
stdlib,
/// setjmpex.h
setjmpex,
/// stdarg.h
stdarg,
/// string.h
string,
/// ctype.h
ctype,
/// wchar.h
wchar,
/// setjmp.h
setjmp,
/// malloc.h
malloc,
/// strings.h
strings,
/// unistd.h
unistd,
/// pthread.h
pthread,
/// math.h
math,
/// complex.h
complex,
/// Blocks.h
blocks,
};
/// Languages in which a builtin is available
pub const Language = enum {
all_languages,
all_ms_languages,
all_gnu_languages,
gnu_lang,
};
pub const Attributes = packed struct {
/// Function does not return
noreturn: bool = false,
/// Function has no side effects
pure: bool = false,
/// Function has no side effects and does not read memory
@"const": bool = false,
/// Signature is meaningless; use custom typecheck
custom_typecheck: bool = false,
/// A declaration of this builtin should be recognized even if the type doesn't match the specified signature.
allow_type_mismatch: bool = false,
/// this is a libc/libm function with a '__builtin_' prefix added.
lib_function_with_builtin_prefix: bool = false,
/// this is a libc/libm function without a '__builtin_' prefix. This builtin is disableable by '-fno-builtin-foo'
lib_function_without_prefix: bool = false,
/// Function returns twice (e.g. setjmp)
returns_twice: bool = false,
/// Nature of the format string passed to this function
format_kind: enum(u3) {
/// Does not take a format string
none,
/// this is a printf-like function whose Nth argument is the format string
printf,
/// function is like vprintf in that it accepts its arguments as a va_list rather than through an ellipsis
vprintf,
/// this is a scanf-like function whose Nth argument is the format string
scanf,
/// the function is like vscanf in that it accepts its arguments as a va_list rather than through an ellipsis
vscanf,
} = .none,
/// Position of format string argument. Only meaningful if format_kind is not .none
format_string_position: u5 = 0,
/// if false, arguments are not evaluated
eval_args: bool = true,
/// no side effects and does not read memory, but only when -fno-math-errno and FP exceptions are ignored
const_without_errno_and_fp_exceptions: bool = false,
/// no side effects and does not read memory, but only when FP exceptions are ignored
const_without_fp_exceptions: bool = false,
/// this function can be constant evaluated by the frontend
const_evaluable: bool = false,
};
pub const Target = enum {
/// Supported on all targets
basic,
aarch64,
aarch64_neon_sve_bridge,
aarch64_neon_sve_bridge_cg,
amdgpu,
arm,
bpf,
hexagon,
hexagon_dep,
hexagon_map_custom_dep,
loong_arch,
mips,
neon,
nvptx,
ppc,
riscv,
riscv_vector,
sve,
systemz,
ve,
vevl_gen,
webassembly,
x86,
x86_64,
xcore,
};
/// Targets for which a builtin is enabled
pub const TargetSet = std.enums.EnumSet(Target);
pub fn isVarArgs(properties: Properties) bool {
return properties.param_str[properties.param_str.len - 1] == '.';
}

View File

@ -13,10 +13,10 @@ pub const Component = union(enum) {
};
pub const ComponentIterator = struct {
str: [*:0]const u8,
str: []const u8,
idx: usize,
pub fn init(str: [*:0]const u8) ComponentIterator {
pub fn init(str: []const u8) ComponentIterator {
return .{
.str = str,
.idx = 0,
@ -30,8 +30,8 @@ pub const ComponentIterator = struct {
}
pub fn next(self: *ComponentIterator) ?Component {
if (self.idx == self.str.len) return null;
const c = self.str[self.idx];
if (c == 0) return null;
self.idx += 1;
switch (c) {
'L' => {
@ -68,14 +68,18 @@ pub const ComponentIterator = struct {
'z' => return .{ .spec = .z },
'w' => return .{ .spec = .w },
'F' => return .{ .spec = .F },
'G' => return .{ .spec = .G },
'H' => return .{ .spec = .H },
'M' => return .{ .spec = .M },
'a' => return .{ .spec = .a },
'A' => return .{ .spec = .A },
'V', 'E' => {
'V', 'q', 'E' => {
const start = self.idx;
while (std.ascii.isDigit(self.str[self.idx])) : (self.idx += 1) {}
const count = std.fmt.parseUnsigned(u32, self.str[start..self.idx], 10) catch unreachable;
return switch (c) {
'V' => .{ .spec = .{ .V = count } },
'q' => .{ .spec = .{ .q = count } },
'E' => .{ .spec = .{ .E = count } },
else => unreachable,
};
@ -99,12 +103,16 @@ pub const ComponentIterator = struct {
'p' => return .{ .spec = .p },
'.' => {
// can only appear at end of param string; indicates varargs function
std.debug.assert(self.str[self.idx] == 0);
std.debug.assert(self.idx == self.str.len);
return null;
},
'!' => {
std.debug.assert(self.str.len == 1);
return .{ .spec = .@"!" };
},
'*' => {
if (std.ascii.isDigit(self.str[self.idx])) {
if (self.idx < self.str.len and std.ascii.isDigit(self.str[self.idx])) {
defer self.idx += 1;
const addr_space = self.str[self.idx] - '0';
return .{ .suffix = .{ .@"*" = addr_space } };
@ -115,14 +123,6 @@ pub const ComponentIterator = struct {
'C' => return .{ .suffix = .C },
'D' => return .{ .suffix = .D },
'R' => return .{ .suffix = .R },
'Q' => {
defer self.idx += 1;
switch (self.str[self.idx]) {
'a' => return .{ .spec = .{ .Q = .aarch64_svcount_t } },
'b' => return .{ .spec = .{ .Q = .amdgpu_buffer_rsrc_t } },
else => unreachable,
}
},
else => unreachable,
}
return null;
@ -130,13 +130,13 @@ pub const ComponentIterator = struct {
};
pub const TypeIterator = struct {
param_str: [*:0]const u8,
param_str: []const u8,
prefix: [4]Prefix,
spec: Spec,
suffix: [4]Suffix,
idx: usize,
pub fn init(param_str: [*:0]const u8) TypeIterator {
pub fn init(param_str: []const u8) TypeIterator {
return .{
.param_str = param_str,
.prefix = undefined,
@ -176,7 +176,7 @@ pub const TypeIterator = struct {
_ = it.next();
}
if (maybe_spec) |spec| {
return .{
return TypeDescription{
.prefix = self.prefix[0..prefix_count],
.spec = spec,
.suffix = self.suffix[0..suffix_count],
@ -236,17 +236,20 @@ const Spec = union(enum) {
w,
/// constant CFString
F,
/// id
G,
/// SEL
H,
/// struct objc_super
M,
/// __builtin_va_list
a,
/// "reference" to __builtin_va_list
A,
/// Vector, followed by the number of elements and the base type.
V: u32,
/// target builtin type, followed by a character to distinguish the builtin type
Q: enum {
aarch64_svcount_t,
amdgpu_buffer_rsrc_t,
},
/// Scalable vector, followed by the number of elements and the base type.
q: u32,
/// ext_vector, followed by the number of elements and the base type.
E: u32,
/// _Complex, followed by the base type.
@ -267,6 +270,8 @@ const Spec = union(enum) {
K,
/// pid_t
p,
/// Used to indicate a builtin with target-dependent param types. Must appear by itself
@"!",
};
const Suffix = union(enum) {

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,231 +0,0 @@
//! Autogenerated by GenerateDef from src/aro/Builtins/bpf.def, do not edit
// zig fmt: off
const std = @import("std");
pub fn with(comptime Properties: type) type {
return struct {
/// Integer starting at 0 derived from the unique index,
/// corresponds with the data array index.
pub const Tag = enum(u16) { __builtin_btf_type_id,
__builtin_preserve_enum_value,
__builtin_preserve_field_info,
__builtin_preserve_type_info,
};
pub fn fromName(name: []const u8) ?Properties {
const data_index = tagFromName(name) orelse return null;
return data[@intFromEnum(data_index)];
}
pub fn tagFromName(name: []const u8) ?Tag {
const unique_index = uniqueIndex(name) orelse return null;
return @enumFromInt(unique_index - 1);
}
pub fn fromTag(tag: Tag) Properties {
return data[@intFromEnum(tag)];
}
pub fn nameFromTagIntoBuf(tag: Tag, name_buf: []u8) []u8 {
std.debug.assert(name_buf.len >= longest_name);
const unique_index = @intFromEnum(tag) + 1;
return nameFromUniqueIndex(unique_index, name_buf);
}
pub fn nameFromTag(tag: Tag) NameBuf {
var name_buf: NameBuf = undefined;
const unique_index = @intFromEnum(tag) + 1;
const name = nameFromUniqueIndex(unique_index, &name_buf.buf);
name_buf.len = @intCast(name.len);
return name_buf;
}
pub const NameBuf = struct {
buf: [longest_name]u8 = undefined,
len: std.math.IntFittingRange(0, longest_name),
pub fn span(self: *const NameBuf) []const u8 {
return self.buf[0..self.len];
}
};
pub fn exists(name: []const u8) bool {
if (name.len < shortest_name or name.len > longest_name) return false;
var index: u16 = 0;
for (name) |c| {
index = findInList(dafsa[index].child_index, c) orelse return false;
}
return dafsa[index].end_of_word;
}
pub const shortest_name = 21;
pub const longest_name = 29;
/// Search siblings of `first_child_index` for the `char`
/// If found, returns the index of the node within the `dafsa` array.
/// Otherwise, returns `null`.
pub fn findInList(first_child_index: u16, char: u8) ?u16 {
@setEvalBranchQuota(8);
var index = first_child_index;
while (true) {
if (dafsa[index].char == char) return index;
if (dafsa[index].end_of_list) return null;
index += 1;
}
unreachable;
}
/// Returns a unique (minimal perfect hash) index (starting at 1) for the `name`,
/// or null if the name was not found.
pub fn uniqueIndex(name: []const u8) ?u16 {
if (name.len < shortest_name or name.len > longest_name) return null;
var index: u16 = 0;
var node_index: u16 = 0;
for (name) |c| {
const child_index = findInList(dafsa[node_index].child_index, c) orelse return null;
var sibling_index = dafsa[node_index].child_index;
while (true) {
const sibling_c = dafsa[sibling_index].char;
std.debug.assert(sibling_c != 0);
if (sibling_c < c) {
index += dafsa[sibling_index].number;
}
if (dafsa[sibling_index].end_of_list) break;
sibling_index += 1;
}
node_index = child_index;
if (dafsa[node_index].end_of_word) index += 1;
}
if (!dafsa[node_index].end_of_word) return null;
return index;
}
/// Returns a slice of `buf` with the name associated with the given `index`.
/// This function should only be called with an `index` that
/// is already known to exist within the `dafsa`, e.g. an index
/// returned from `uniqueIndex`.
pub fn nameFromUniqueIndex(index: u16, buf: []u8) []u8 {
std.debug.assert(index >= 1 and index <= data.len);
var node_index: u16 = 0;
var count: u16 = index;
var w = std.Io.Writer.fixed(buf);
while (true) {
var sibling_index = dafsa[node_index].child_index;
while (true) {
if (dafsa[sibling_index].number > 0 and dafsa[sibling_index].number < count) {
count -= dafsa[sibling_index].number;
} else {
w.writeByte(dafsa[sibling_index].char) catch unreachable;
node_index = sibling_index;
if (dafsa[node_index].end_of_word) {
count -= 1;
}
break;
}
if (dafsa[sibling_index].end_of_list) break;
sibling_index += 1;
}
if (count == 0) break;
}
return w.buffered();
}
const Node = packed struct {
char: u8,
/// Nodes are numbered with "an integer which gives the number of words that
/// would be accepted by the automaton starting from that state." This numbering
/// allows calculating "a one-to-one correspondence between the integers 1 to L
/// (L is the number of words accepted by the automaton) and the words themselves."
///
/// Essentially, this allows us to have a minimal perfect hashing scheme such that
/// it's possible to store & lookup the properties of each builtin using a separate array.
number: std.math.IntFittingRange(0, data.len),
/// If true, this node is the end of a valid builtin.
/// Note: This does not necessarily mean that this node does not have child nodes.
end_of_word: bool,
/// If true, this node is the end of a sibling list.
/// If false, then (index + 1) will contain the next sibling.
end_of_list: bool,
/// Index of the first child of this node.
child_index: u16,
};
const dafsa = [_]Node{
.{ .char = 0, .end_of_word = false, .end_of_list = true, .number = 0, .child_index = 1 },
.{ .char = '_', .end_of_word = false, .end_of_list = true, .number = 4, .child_index = 2 },
.{ .char = '_', .end_of_word = false, .end_of_list = true, .number = 4, .child_index = 3 },
.{ .char = 'b', .end_of_word = false, .end_of_list = true, .number = 4, .child_index = 4 },
.{ .char = 'u', .end_of_word = false, .end_of_list = true, .number = 4, .child_index = 5 },
.{ .char = 'i', .end_of_word = false, .end_of_list = true, .number = 4, .child_index = 6 },
.{ .char = 'l', .end_of_word = false, .end_of_list = true, .number = 4, .child_index = 7 },
.{ .char = 't', .end_of_word = false, .end_of_list = true, .number = 4, .child_index = 8 },
.{ .char = 'i', .end_of_word = false, .end_of_list = true, .number = 4, .child_index = 9 },
.{ .char = 'n', .end_of_word = false, .end_of_list = true, .number = 4, .child_index = 10 },
.{ .char = '_', .end_of_word = false, .end_of_list = true, .number = 4, .child_index = 11 },
.{ .char = 'b', .end_of_word = false, .end_of_list = false, .number = 1, .child_index = 13 },
.{ .char = 'p', .end_of_word = false, .end_of_list = true, .number = 3, .child_index = 14 },
.{ .char = 't', .end_of_word = false, .end_of_list = true, .number = 1, .child_index = 15 },
.{ .char = 'r', .end_of_word = false, .end_of_list = true, .number = 3, .child_index = 16 },
.{ .char = 'f', .end_of_word = false, .end_of_list = true, .number = 1, .child_index = 17 },
.{ .char = 'e', .end_of_word = false, .end_of_list = true, .number = 3, .child_index = 18 },
.{ .char = '_', .end_of_word = false, .end_of_list = true, .number = 1, .child_index = 19 },
.{ .char = 's', .end_of_word = false, .end_of_list = true, .number = 3, .child_index = 20 },
.{ .char = 't', .end_of_word = false, .end_of_list = true, .number = 1, .child_index = 21 },
.{ .char = 'e', .end_of_word = false, .end_of_list = true, .number = 3, .child_index = 22 },
.{ .char = 'y', .end_of_word = false, .end_of_list = true, .number = 1, .child_index = 23 },
.{ .char = 'r', .end_of_word = false, .end_of_list = true, .number = 3, .child_index = 24 },
.{ .char = 'p', .end_of_word = false, .end_of_list = true, .number = 1, .child_index = 25 },
.{ .char = 'v', .end_of_word = false, .end_of_list = true, .number = 3, .child_index = 26 },
.{ .char = 'e', .end_of_word = false, .end_of_list = true, .number = 1, .child_index = 27 },
.{ .char = 'e', .end_of_word = false, .end_of_list = true, .number = 3, .child_index = 28 },
.{ .char = '_', .end_of_word = false, .end_of_list = true, .number = 1, .child_index = 29 },
.{ .char = '_', .end_of_word = false, .end_of_list = true, .number = 3, .child_index = 30 },
.{ .char = 'i', .end_of_word = false, .end_of_list = true, .number = 1, .child_index = 33 },
.{ .char = 'e', .end_of_word = false, .end_of_list = false, .number = 1, .child_index = 34 },
.{ .char = 'f', .end_of_word = false, .end_of_list = false, .number = 1, .child_index = 35 },
.{ .char = 't', .end_of_word = false, .end_of_list = true, .number = 1, .child_index = 36 },
.{ .char = 'd', .end_of_word = true, .end_of_list = true, .number = 1, .child_index = 0 },
.{ .char = 'n', .end_of_word = false, .end_of_list = true, .number = 1, .child_index = 37 },
.{ .char = 'i', .end_of_word = false, .end_of_list = true, .number = 1, .child_index = 38 },
.{ .char = 'y', .end_of_word = false, .end_of_list = true, .number = 1, .child_index = 39 },
.{ .char = 'u', .end_of_word = false, .end_of_list = true, .number = 1, .child_index = 40 },
.{ .char = 'e', .end_of_word = false, .end_of_list = true, .number = 1, .child_index = 41 },
.{ .char = 'p', .end_of_word = false, .end_of_list = true, .number = 1, .child_index = 42 },
.{ .char = 'm', .end_of_word = false, .end_of_list = true, .number = 1, .child_index = 43 },
.{ .char = 'l', .end_of_word = false, .end_of_list = true, .number = 1, .child_index = 44 },
.{ .char = 'e', .end_of_word = false, .end_of_list = true, .number = 1, .child_index = 45 },
.{ .char = '_', .end_of_word = false, .end_of_list = true, .number = 1, .child_index = 46 },
.{ .char = 'd', .end_of_word = false, .end_of_list = true, .number = 1, .child_index = 45 },
.{ .char = '_', .end_of_word = false, .end_of_list = true, .number = 1, .child_index = 47 },
.{ .char = 'v', .end_of_word = false, .end_of_list = true, .number = 1, .child_index = 48 },
.{ .char = 'i', .end_of_word = false, .end_of_list = true, .number = 1, .child_index = 49 },
.{ .char = 'a', .end_of_word = false, .end_of_list = true, .number = 1, .child_index = 50 },
.{ .char = 'n', .end_of_word = false, .end_of_list = true, .number = 1, .child_index = 51 },
.{ .char = 'l', .end_of_word = false, .end_of_list = true, .number = 1, .child_index = 52 },
.{ .char = 'f', .end_of_word = false, .end_of_list = true, .number = 1, .child_index = 53 },
.{ .char = 'u', .end_of_word = false, .end_of_list = true, .number = 1, .child_index = 54 },
.{ .char = 'o', .end_of_word = true, .end_of_list = true, .number = 1, .child_index = 0 },
.{ .char = 'e', .end_of_word = true, .end_of_list = true, .number = 1, .child_index = 0 },
};
pub const data = blk: {
@setEvalBranchQuota(36);
break :blk [_]Properties{
.{ .param_str = "LUi.", .attributes = .{ .custom_typecheck = true } },
.{ .param_str = "Li.", .attributes = .{ .custom_typecheck = true } },
.{ .param_str = "Ui.", .attributes = .{ .custom_typecheck = true } },
.{ .param_str = "LUi.", .attributes = .{ .custom_typecheck = true } },
};
};
};
}

Some files were not shown because too many files have changed in this diff Show More