Zig v0.17.0
요약
Zig v0.17.0은 빌드 시스템을 재설계하여 구성(configurer)과 실행(maker) 프로세스를 분리하고, 외부 도구 연동을 위한 Build Server Protocol을 도입했습니다. 이로써 증분 컴파일 기능이 개선되고 캐시 관리 메타데이터 지원 등 전반적인 안정성과 성능이 향상되었습니다. 또한, `@bitCast`의 의미 변경 및 `SafeAllocator`를 통한 메모리 안전성 강화 등의 언어 레벨 변화도 포함됩니다.
핵심 포인트
- 빌드 프로세스 분리로 구성(configurer)과 실행(maker)을 분리하여 안정성을 높임.
- Build Server Protocol 도입으로 외부 IDE/도구와의 연동성이 향상됨.
- 캐시 시스템이 메타데이터 추적 및 다양한 모드를 지원하며 성능 개선 효과가 있음.
- 증분 컴파일 기능이 강화되었고, 메모리 안전성 강화를 위해 SafeAllocator를 사용함.
빌드 시스템을 재설계 해 빌드 구성과 실행을 별도 프로세스로 분리하고, IDE 등 외부 도구가 빌드 그래프를 조회하고 제어하는 Build Server Protocol 을 도입함
증분 컴파일 과 새 ELF 링커 개선으로 대부분의 x86_64-linux
프로젝트에서 zig build -fincremental --watch
를 이용한 증분 재빌드가 가능해짐
@bitCast
의 배열/벡터 변환 의미가 변경 되어 컴파일 오류 없이 기존 코드의 동작이 달라질 수 있으며, @cImport
제거 등 언어와 표준 라이브러리의 호환성 변경도 포함됨
SafeAllocator 가 DebugAllocator를 대체하며 누수, 이중 해제, 잘못된 할당 연산 탐지를 강화함
빌드 프로세스 분리로 ZLS가 0.17.0에서 동작하지 않는 호환성 문제 가 있으며, Zig와 ZLS 팀은 Build Server Protocol을 확장해 기능을 복구하는 작업을 진행 중임
빌드 구성과 실행 분리
Zig 0.17.0 에는 5개월간 206명이 기여한 925개 커밋이 반영됨
zig build
는 build.zig
를 실행하는 구성 프로세스(configurer) 와 패키지 관리 및 빌드 그래프 실행을 담당하는 실행 프로세스(maker) 를 별도 실행 파일로 분리함
maker는 build.zig
수정의 영향을 받지 않아 Zig 설치 후 최초 한 번만 빌드하면 됨
maker에 최적화를 적용하고, 명령행 옵션에 따라 구성 로직 실행을 생략할 수 있음
구성 정보는 외부 도구도 읽을 수 있는 바이너리 형식으로 직렬화하며, --print-configuration
으로 ZON 출력을 얻을 수 있음
빌드 러너 교체 기능은 제거 되고, 외부 도구 연동은 Build Server Protocol 이 담당함
--listen=-
으로 빌드 그래프의 구성 정보, 옵션과 의존성 조회, 단계 시작/종료 및 오류/생성 파일 알림, 특정 단계 실행 요청을 지원함
노출된 모듈 이름 등 일부 정보는 아직 제공하지 않으며, 이 변경으로 ZLS 와의 호환성이 깨짐
향후 Zig 자체 도구도 프로토콜 클라이언트로 전환하고, 컴파일러 서버 프로토콜을 연결해 타입 정보와 리팩터링 기능을 제공할 계획임
캐시와 패키지 관리 변경
캐시 시스템 은 디렉터리 항목 추가/삭제/이름 변경을 추적하고, 내용 외에 크기/inode/수정 시각 변화도 캐시 무효화 조건으로 삼는 메타데이터 모드를 지원함
바이너리 형식으로 바꿔 캐시 파일 크기가 약 25% 감소 했고, 캐시 적중 처리 속도는 5~10% 개선된 사례가 있음
캐시 미스 원인 추적과 zig cache-cat
명령을 추가했으며, std.Build.Cache
API에는 다수의 호환성 변경이 있음
구성 캐시 오염 은 build.zig
의 구성 로직이 부수 효과를 내거나 캐시가 추적할 수 없는 작업을 수행했음을 뜻함
오염된 구성은 재사용하지 않으며, 실행 단계의 부수 효과와는 구분됨
dependOnFileContents
, dependOnFileMetadata
, dependOnDirectoryContents
, dependOnDirectoryMetadata
로 구성 의존성을 명시할 수 있음
--cache-poison
은 기본값 pure
외에 poisoned
, disallowed
, ignored
모드를 제공함
findProgramLazy
는 실제로 의존 단계가 실행 파일을 사용할 때만 검색하며 구성 캐시를 오염시키지 않음
기존 findProgram
은 구성 단계에서 즉시 검색하므로 캐시를 오염시킴
지연 검색 결과는 LazyPath
이므로 구성 단계에서 사용할 수 없음
실행 인자 전달 은 b.args
를 읽는 방식에서 run_cmd.addPassthruArgs()
로 변경됨
빌드 스크립트는 전달 인자를 관찰할 수 없지만, 인자를 바꿀 때 스크립트를 다시 빌드할 필요가 없어짐
Fmt
의 paths
와 exclude_paths
는 LazyPath
목록으로 변경됨
경로 옵션은 addOptionPath
, addOptionPathDirectory
, addOptionPathUntracked
로 파일/디렉터리/추적 제외를 명시해야 함
지연 의존성 처리 에 다운로드 로그, std.Build.dependency
의 지연 의존성 지원, dependencyLazy
를 통한 error.LazyDependencyNeeded
반환을 추가함
사용자 build
함수가 이 오류를 반환하면 구성 실패 대신 필요한 의존성을 가져옴
패키지 관리 기능 은 컴파일러에서 빌드 시스템으로 이동함
네트워크, TLS, Git, 압축 처리, build.zig.zon
파싱 등의 코드를 소스로 배포하며, 기존 -Ofast
대신 -Osafe
로 컴파일함
부모 패키지 루트를 벗어나는 경로 의존성은 거부함
--pkg-path
와 ZIG_LOCAL_PKG_DIR
은 fetch
와 build
모두에 적용됨
zig fetch
는 기본적으로 전역 캐시에만 저장하고, --save
계열 옵션을 쓰면 로컬 패키지 경로에도 저장함
전역 다운로드에는 build.zig
가 필요하지 않으며, zig fetch .
의 회귀 문제가 수정됨
zig build
는 전역과 로컬에 모두 가져옴
경로로 가져올 때는 항상 해시와 재압축 tar 아카이브를 생성하고 기존 전역 캐시 항목을 덮어씀
Windows/Wine의 Run 단계 는 DLL 의존성 디렉터리를 통한 PATH
조정을 이제 argv[0]
에만 적용함
증분 컴파일과 링커
증분 컴파일 은 다수의 버그 수정과 새 ELF 링커 개선으로 대부분의 x86_64-linux
프로젝트에서 사용할 수 있음
zig build -fincremental --watch
로 소스 변경을 감지하고 증분 재빌드를 수행함
내부 동작과 사용법은 증분 컴파일 해설 에서 확인할 수 있음
향후 Mach-O 링커와 자체 aarch64 백엔드 개선, --watch
없는 증분 컴파일 지원을 추진함
새 ELF 링커 는 x86_64와 SPARC64를 완전히 지원하고 LoongArch를 부분 지원함
정적/공유 라이브러리 생성, GOT, 복사 재배치, GNU 심볼 버전 관리, DWARF 디버그 정보, 심볼 해시 테이블, 임의 섹션 정렬 등을 추가함
대부분의 x86_64-linux
프로젝트를 빌드할 수 있지만 구형 링커와 기능이 완전히 같지는 않아 일반적인 기본값은 아님
증분 컴파일에서는 기본 활성화되며, 다음 릴리스에서 구형 ELF 링커를 완전히 대체하는 것이 목표임
COFF 링커 는 .obj
/.lib
출력, 임포트 라이브러리 생성과 입력 처리, TLS, __dllimport
, GNU/MSVC libc 링크를 지원하도록 확장됨
아카이브에서 필요한 오브젝트만 링크하고, 내보낸 심볼에 따라 진입점을 선택함
GNU 생성자/소멸자 및 /INCLUDE
, /ALTERNATENAME
, /MERGE
, /DEFAULTLIB
지시문을 지원함
COMDAT는 compiler_rt와 libc 링크에 충분한 수준이지만 일부 유형은 아직 지원하지 않음
SPIR-V 링커 는 재작성되어 증분 컴파일과 외부 .spv
오브젝트 링크를 지원함
링커 테스트 는 objdump 스냅샷 비교, 산출물 실행, 오류 검증을 결합하는 방식으로 전환 중임
zig objdump
는 헤더, 심볼, 임포트/익스포트, 재배치, TLS 등을 출력함
--redact
와 --elements
로 테스트와 무관한 주소나 출력 요소를 제외해 불필요한 스냅샷 실패를 줄일 수 있음
언어 변경과 마이그레이션
언어 안정화 를 위해 지난 릴리스 이후 제안 약 25개를 수용하고 약 125개를 거절함
미결정 제안은 Codeberg에 23개, 기존 GitHub에 61개가 남아 있으며 주요 설계 결정도 아직 남아 있음
@bitCast
는 메모리 배치가 아닌 값의 논리적 비트 표현 을 재해석하도록 정의가 변경됨
정수/부동소수점은 최하위 비트부터, 배열/벡터는 첫 원소부터 각 원소의 비트 표현을 이어 붙임
대상의 엔디언과 무관하게 동일하게 동작하며, 기존 리틀 엔디언 동작과는 대체로 일치함
배열/벡터를 포함한 변환은 컴파일 오류 없이 의미가 달라질 수 있어 업그레이드 시 점검이 필요함
extern struct
와 extern union
변환은 금지되며, 메모리 표현을 재해석하려면 @ptrCast
나 extern union
을 사용해야 함
@cImport
가 제거 되고 std.Build.Step.TranslateC
는 사용 중단 예정으로 전환됨
@backingInt
와 @fromBackingInt
가 사용 중단 예정인 @intFromEnum
과 @enumFromInt
를 대체함
enum과 명시적 기반 정수 타입을 가진 비트팩을 지원하며, @backingInt
는 태그된 union의 활성 태그에도 사용할 수 있음
@fromBackingInt
는 정확히 기반 정수 타입인 인자를 요구하고, enum의 잘못된 태그나 undefined
입력은 안전성 검사 대상임
enum을 결과로 하는 @bitCast
도 잘못된 태그를 검사하며, 빈 enum의 기반 타입은 noreturn
이어야 함
std.meta.BackingInt
가 추가되고 zig fmt
가 기존 변환 코드의 마이그레이션을 수행함
제거된 문법과 타입 은 다음과 같이 수정해야 함
배열 반복 a ** b
는 @splat
으로, void{}
는 {}
로 대체함
errdefer |err|
의 캡처는 제거되어, 필요하면 함수를 나누고 바깥 함수의 catch
에서 오류를 처리함
i0
는 제거되며 대부분의 사용처에서 u0
로 대체할 수 있음
std.lang.GlobalLinkage
의 internal
과 link_once
는 제거되며, 각각 심볼을 @export
하지 않는 방식과 weak
가 대안이 될 수 있음
내장 함수 동작 도 변경됨
@hasDecl
은 같은 파일 안에서도 공개 선언에만 true
를 반환함
새 @divCeil
은 정수 나눗셈 결과를 양의 무한대 방향으로 올림하며, 호출자가 0이 아닌 분모와 오버플로 없는 결과를 보장해야 함
길이를 컴파일 시점에 아는 슬라이스는 역참조해 배열로 얻거나 배열 포인터로 강제 변환할 수 있음
형식 문법과 실제 파서의 불일치 를 수정함
grammar.peg
로 생성한 재귀 하강 파서를 기준으로 수작업 파서 std.zig.Ast.parse()
를 퍼즈 테스트하는 검증 체계 를 구축함
메모리 안전성과 표준 라이브러리
SafeAllocator 는 스레드 안전 할당자로 DebugAllocator
를 대체하며, DebugAllocator
와 std.heap.Check
는 사용 중단 예정임
deinit
에서 모든 누수를 보고하고 기반 메모리를 해제함
할당 정보 불일치, 이중 해제, resize/remap/free 연산 경쟁은 패닉 또는 세그멘테이션 오류로 이어짐
서로 다른 인스턴스의 할당은 Options.canary
가 다르면 패닉을 발생시킴
기반 할당자가 메모리를 재사용하지 않으면 SafeAllocator도 재사용하지 않으며, 대부분의 해제 후 쓰기는 오류를 내거나 나중에 탐지됨
생산자/소비자 간 acquire/release 순서는 외부에서 보장해야 함
할당 메타데이터와 스택 추적 은 체크섬으로 보호한 AllocFooter
에 저장함
작은 할당은 버킷에, 나머지는 기반 할당자에서 직접 확보하며 스레드별 테이블로 추적함
단일/다중 스레드 퍼즈 테스트를 추가하고 TSAN으로 광범위하게 테스트함
-Osafe
컴파일러와 -Ddebug-allocator
를 사용한 표준 라이브러리 테스트 빌드 시간은 29.4초→22.1초로 24.7% , 최대 RSS는 2.24GB→1.11GB로 50.3% 감소함
StackFallbackAllocator 는 크기를 타입 매개변수로 받는 대신 외부 버퍼를 인자로 받도록 재설계됨
버퍼 정렬을 직접 지정할 수 있고, 기존 할당자 접근 방식에 필요했던 런타임 안전성 검사를 피할 수 있음
컬렉션과 잠금 API 가 정리됨
ArrayList.getLastOrNull
은 last
, getLast
는 last().?
로 대체하며 lastPtr
를 추가함
ArrayList 포인터 안정성 개선 으로 사용 오류를 더 빨리 추적할 수 있음
debug.SafetyLock
에 읽기 전용 공유 잠금용 lockShared
/unlockShared
를 추가함
bit_set
타입 이름은 Integer
, Array
, Static
, Dynamic
으로 정리하고 관리형 DynamicManaged
는 사용 중단 예정임
출력과 ZON 파싱 도 마이그레이션이 필요함
std.fmt.allocPrint
는 mem.Allocator.print
로 이동함
"{q}"
는 UTF-8 데이터를 불필요하게 이스케이프하지 않으며, format()
결과를 큰따옴표 문자열용으로 이스케이프하는 "{qf}"
를 추가함
std.zon.parse
는 구조체 인자를 받고 결과를 아레나에 할당함
fromSliceAlloc
은 fromSlice
, 기존 fromSlice
는 fromSliceNoAlloc
으로 변경됨
updateFromSlice
등은 ZON에 지정된 필드만 덮어써 전역/프로젝트 설정처럼 우선순위가 다른 설정을 합칠 수 있음
타입 리플렉션과 최적화 모드 의 이름 및 구조가 변경됨
std.builtin
대신 std.lang
, std.meta.fieldInfo
/fieldNames
/fieldTypes
대신 @typeInfo
를 사용함
구조체와 union의 타입 정보는 field_names
, field_types
같은 배열별 구조 방식으로 반환됨
lang.OptimizeMode
는 lang.Optimize
, 태그는 debug
/safe
/fast
/small
로 바뀌며, ==
/!=
비교에는 기존 이름을 사용할 수 없음
모듈 자체의 안전성 설정을 반영하는 lang.Optimize.runtimeSafety
가 std.debug.runtime_safety
보다 권장됨
@import("builtin")
의 cpu
, os
, abi
, object_format
은 target
의 대응 필드로 옮겨야 하며 0.18.0에서 제거될 예정임
비교와 URI 검증 오류 를 수정함
mem.eql
과 mem.findDiff
는 부동소수점 슬라이스에 대해 같은 메모리라는 이유로 비교를 생략하지 않아 NaN을 올바르게 처리함
URI와 호스트명은 각각 RFC3986과 RFC1123의 다른 규칙을 따르므로 검증을 분리 함
Uri.getHost
는 검증과 오류 집합이 달라지는 HostName.fromUri
로 이동하고, Uri.getHostAlloc
은 제거됨
GPU와 자체 백엔드
@SpirvType
는 샘플러, 이미지, 샘플링된 이미지, 런타임 배열을 생성해 텍스처와 스토리지 버퍼를 일반 전역 변수로 선언할 수 있게 함
SPIR-V가 아닌 대상에서는 컴파일 오류가 발생하며, 옵션은 대상 OS에 맞춰 검증함
std.gpu
는 std.spirv
로 이름이 바뀌고 이미지 샘플링/조회/쓰기 도우미가 추가됨
SPIR-V 백엔드 는 다중 스레드화되고 태스크/메시 셰이더 호출 규약을 지원함
실행 모드는 인라인 어셈블리 대신 함수 호출 규약에서 결정함
OpCapability
와 OpExtension
선언은 금지되며 -mcpu
의 CPU 기능으로 활성화해야 함
자체 loongarch64 백엔드 의 초기 구현 이 추가됐지만 아직 실험적이며 사용할 수 있는 수준은 아님
aarch64 백엔드는 링커 개선에 의존하며, 필요한 작업 상당수가 이번 주기에 완료됨
WebAssembly 백엔드 는 LLVM 대비 동작 테스트에서 100%를 통과하지만, 디버그 정보 미지원 때문에 디버그 모드의 기본 백엔드는 아직 아님
플랫폼 지원과 실행 환경
AArch64 지원 은 OpenBSD 네이티브 CI와 필수 코드 강화 적용, FreeBSD/NetBSD 풀 리퀘스트 CI, Windows 바이너리를 깨뜨리던 LLVM 버그 우회 를 포함함
AArch64 스택 되감기는 포인터 인증 명령을 처리함
32비트 ARM과 SPARC도 크래시/단언 실패 시 스택 추적을 제공하며, Thumb 전용 대상에는 남은 작업 이 있음
지원 대상이 확대 되어 loongarch32-linux-gnu[sf]
가 추가되고, 새 ELF 링커 덕분에 특히 sparc64-linux
의 실용성이 높아짐
x86-64의 x32 ABI와 64비트 MIPS의 N32 ABI에 표준 라이브러리를 이식함
aarch64-switch
, arm-gba
, mipsel-psx
, powerpc-wiiu
의 대상 정보를 추가함
초기 xtensa-linux
지원은 C 백엔드 또는 실험적 LLVM 백엔드로만 사용할 수 있음
C 백엔드의 arc[eb]-linux
, csky-linux
, m88k-openbsd
및 libc 없는 microblaze[el]-linux
, sh[eb]-linux
, sparc-linux
지원을 추가함
일부 PowerPC GNU 대상은 지원 종료 됨
모든 PowerPC 대상에서 -mabi=ieeelongdouble
을 강제하며, glibc가 IBM double-double만 지원하는 powerpc-linux-gnueabi[hf]
를 제거함
powerpc-linux-musleabi[hf]
는 유지됨
빅 엔디언 glibc의 ELFv2 및 IEEE long double
지원 제약으로 powerpc64-linux-gnu
도 제거됨
CPU 탐지 는 거의 모든 지원 아키텍처/OS에서 개선됐으며 여러 대상의 기준 CPU 모델도 변경됨
대상 질의의 네이티브 libc 버전 탐지는 ABI 구성 요소를 생략해 실제로 네이티브 libc를 사용하는 경우에만 수행함
지원 등급 은 Tier 1~4로 구분되며, 현재 지원표의 Tier 1은 x86_64-linux
임
Tier 1은 LLVM 없는 기계어 생성과 비실험적 언어 기능, 해당 대상의 퍼저 동작을 요구함
Tier 2는 표준 라이브러리 추상화, 스택 추적, 해당 대상의 libc와 CI를 기준으로 함
Tier 3은 외부 백엔드 기반 기계어 생성과 링크, Tier 4는 어셈블리 또는 C 소스 생성을 기준으로 함
퇴역 예정 표시는 최선의 지원을 유지하지만 향후 제거할 수 있음을 뜻함
표준 라이브러리 최소 OS 요구사항 은 Darwin 15.0+, DragonFly BSD 6.4+, FreeBSD 14.0+, Linux 5.10+, NetBSD 10.1+, OpenBSD 7.8+, Windows 10+이며 컴파일러에도 영향을 줌
툴체인과 남은 제약
LLVM/Clang 22.1.8 로 업데이트하며 libc++, libc++abi, libunwind, libtsan도 함께 갱신함
잘못된 코드 생성 문제 의 수정이 LLVM 22에는 없어 루프 벡터화 비활성화 우회책 을 유지함
Zig 0.18.0의 LLVM 23 전환에서 다시 활성화할 예정임
교차 컴파일 환경 에 glibc 2.44, NetBSD libc 11.0, OpenBSD libc 7.9를 제공하고 Linux 7.2 및 macOS 27.0 헤더를 포함함
musl은 보안/이식성 수정이 백포트된 1.2.5를 유지하며 0.18.0에서 1.2.6으로 올릴 예정임
musl 정적 링크, MinGW-w64, WASI libc의 여러 함수는 Zig 자체 구현으로 대체되며, Zig가 제공하는 musl/MinGW-w64 관련 버그는 해당 업스트림 대신 Zig에 보고해야 함
0.18.0부터 WASI libc는 Zig 자체 구현으로 전환 할 계획임
libc.txt
의 gcc_dir
은 cc_dir
로 변경 되며 Linux에서는 필수임
기존 이름도 당분간 허용함
Android/OpenHarmony는 오브젝트 파일 위치 때문에 cc_dir
을 crt_dir
과 같은 경로로 설정하는 것이 적절할 수 있음
Windows 리소스 컴파일 은 다음 릴리스에서 공식 외부 패키지 로 이동할 예정이며 관련 std.Build
API는 사용 중단 예정임
다른 빌드 시스템과의 연동을 위한 zig rc
명령은 유지함
zig fmt --complexity
는 토큰과 AST 노드 수를 세어 줄 수보다 상세한 소스 복잡도 비교를 제공함
이번 주기에는 329개 버그 보고가 종료 됐지만, 알려진 버그와 잘못된 코드 생성, 회귀 문제가 여전히 있음
1.0을 향한 로드맵 은 ZLS 연동 복구, x86_64 백엔드의 Windows 지원 완성, 언어 안정화, aarch64 디버그 기본 백엔드 전환, LLD 의존성 제거와 증분 컴파일 개선을 포함함
이번에 변경하지 않은 통합 퍼저를 AFL 등과 경쟁할 수준으로 개선하고, LLVM 라이브러리 의존성을 Clang 프로세스 의존성으로 전환할 계획임
빌드 시스템과 패키지 관리 완성, 표준 라이브러리 감사도 남아 있음
댓글과 토론
AI 자동 생성 콘텐츠
본 콘텐츠는 RSS: GeekNews (한국어)의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기