---
title: "Zig 개발일지 총정리: kernel32 우회부터 io_uring, 컴파일러 대수술까지"
published: 2026-02-03T23:25:18.000Z
canonical: https://jeff.news/article/357
---
# Zig 개발일지 총정리: kernel32 우회부터 io_uring, 컴파일러 대수술까지

Zig 언어 2026년 1~3월 devlog 5건이 공개됨. 3만 줄 규모 타입 해석 재설계, io_uring/GCD 기반 비동기 I/O 통합, 패키지 매니저의 로컬 저장 및 --fork 플래그, kernel32 대신 ntdll 직접 호출 정책, C 소스를 Zig로 점진 교체하는 zig libc 프로젝트 등 컴파일러와 표준 라이브러리 전반에 걸친 대규모 변화가 포함됨.

Zig 언어 공식 devlog에 2026년 1월~3월 업데이트 5건이 한꺼번에 올라왔음. 컴파일러 내부 대수술부터 Windows 저수준 API 직접 호출, io_uring 통합까지 굵직한 변화들이 쏟아짐.

## 타입 해석 재설계 (3월 10일, Matthew Lugg)

- 3만 줄짜리 PR이 2~3개월 작업 끝에 머지됨. Zig 컴파일러의 타입 해석(type resolution) 로직을 전면 재설계한 것
- 핵심은 **lazy 분석**: 타입이 실제로 초기화되지 않으면 필드를 분석하지 않음. `std.Io.Writer` 쓴다고 `std.Io` 전체를 끌어오던 문제가 해결됨
- `@compileError`가 들어있는 필드라도 그 타입을 namespace로만 쓰면 컴파일 에러 안 남. 이전에는 무조건 터졌음
- 의존성 루프(dependency loop) 에러 메시지가 드디어 쓸모있어짐. 루프 경로를 정확히 보여줘서 어디를 끊어야 하는지 바로 알 수 있음
- 증분 컴파일(incremental compilation)도 크게 개선됨. "over-analysis" 문제가 사실상 제거되어 증분 빌드가 훨씬 빨라졌음

## io_uring & Grand Central Dispatch 통합 (2월 13일, Andrew Kelley)

- `std.Io.Evented`가 **io_uring**(Linux)과 **GCD**(macOS) 양쪽 모두 지원하게 됨. 유저스페이스 스택 스위칭(fibers/green threads) 기반
- 핵심 포인트: `app` 함수 코드가 완전히 동일한 채로 `Threaded`와 `Evented` I/O를 그냥 바꿔 끼울 수 있음. strace로 확인하면 threaded는 writev, evented는 io_uring_enter를 호출하는 차이만 있음
- Zig 컴파일러 자체도 `std.Io.Evented`로 동작함. 다만 아직 성능 저하가 있어서 원인 진단 중
- 아직 실험적 단계임. 에러 핸들링, 미구현 함수, 테스트 커버리지 등 남은 과제가 있음
- 오버커밋 꺼진 환경을 위해 함수의 최대 스택 사이즈를 알려주는 빌트인 함수도 계획 중

## 패키지 관리 워크플로우 개선 (2월 6일, Andrew Kelley)

- 의존성 패키지가 이제 `.zig-cache`가 아닌 프로젝트 루트의 `zig-pkg` 디렉토리에 저장됨. 오프라인 빌드용 자체 포함(self-contained) 소스 tarball 배포가 가능해짐
- 글로벌 캐시에는 미사용 파일 필터링 후 재압축된 `.tar.gz`가 저장됨. 향후 **P2P 토렌팅**으로 의존성 트리를 공유하는 것도 계획 중 -- 시더 수로 패키지 인기도까지 알 수 있게 된다는 구상
- `zig-pkg` 디렉토리를 직접 수정하거나, git clone으로 교체하거나, IDE 자동완성 소스로 잡는 것도 가능함
- **`--fork` 플래그** 신설: `zig build --fork=[path]`로 의존성 트리 전체에서 특정 패키지를 로컬 소스 체크아웃으로 오버라이드할 수 있음
- CLI 플래그라서 일시적(ephemeral)임. 플래그 빼면 원래 의존성 트리로 즉시 복귀. 에코시스템 깨졌을 때 포크 만들어서 작업하고, 패치 올리는 워크플로우가 깔끔해짐
- 매칭 안 되면 에러, 매칭 되면 info 메시지로 포크 사용 중임을 알려줘서 혼동 방지

## kernel32.dll 우회하기 (2월 3일, Andrew Kelley)

- Zig 표준 라이브러리 정책: **kernel32.dll(Win32) 대신 ntdll.dll(Native API)을 우선 사용**. ntdll API는 잘 설계되어 있는 반면 kernel32 래퍼는 불필요한 힙 할당, 추가 실패 모드, CPU 낭비를 유발함
- **엔트로피 예시**: Windows에서 랜덤 바이트 얻으려면 보통 advapi32의 `SystemFunction036`을 호출하는데, Win8부터 이게 내부적으로 bcryptprimitives.dll을 동적 로딩함. DLL 로드 실패 시 "절대 실패 안 한다"고 문서화된 함수가 에러 38을 뱉음. Zig CI에서 실제로 관측된 문제임
- 실제로는 `NtOpenFile`로 `\\Device\\CNG` 열고 48바이트 읽어서 AES 기반 CSPRNG 시드를 초기화하는 게 전부임. advapi32, bcryptprimitives 의존성과 비결정적 실패를 모두 제거함
- **NtReadFile vs ReadFile 예시**: kernel32의 `ReadFile`는 BOOL 반환 + `GetLastError` 패턴이고, ntdll의 `NtReadFile`은 NTSTATUS를 직접 반환함. `OVERLAPPED`는 커널이 모르는 가짜 타입임
- kernel32는 비동기 I/O에 Event 객체를 불필요하게 할당하지만, Zig는 APC 루틴 + `NtDelayExecution`을 사용해서 취소(cancellation)와도 자연스럽게 통합됨

## zig libc: C 소스 파일을 Zig로 교체 중 (1월 31일, Andrew Kelley)

- libc 함수를 C 소스 대신 Zig 표준 라이브러리 래퍼로 점진적 교체 중. 현재까지 약 **250개 C 파일 삭제**, 2,032개 남음
- `memcpy`, `atan2`, `strnlen` 같은 함수들이 Zig 코드로 1:1 대체됨. C 언어 및 서드파티 프로젝트 의존성이 줄어들고, 컴파일 속도 향상, 설치 크기 감소, 바이너리 크기 감소 효과
- 새로운 개선: zig libc가 별도 정적 아카이브가 아닌 **Zig Compilation Unit(ZCU)을 공유**함. LTO를 링커가 아닌 프론트엔드에서 제대로 하는 셈이라 중복 코드가 최적화 단계에서 제거됨
- 장기적으로 `std.Io` 변경과 결합하면, libc의 read/write 호출을 io_uring 이벤트 루프에 강제 참여시키거나 서드파티 C 코드의 리소스 누수 감지도 가능해질 수 있음 (아직 구상 단계)

## 핵심 포인트

- 3만 줄 PR로 타입 해석 재설계 완료, 증분 컴파일 성능 대폭 개선
- std.Io.Evented가 io_uring과 GCD 양쪽 지원, 동일 코드로 I/O 구현체 교체 가능
- 패키지를 zig-pkg에 로컬 저장하고 --fork 플래그로 의존성 오버라이드 지원
- kernel32 대신 ntdll 직접 호출로 불필요한 힙 할당과 실패 모드 제거
- zig libc로 250개 C 파일 삭제, ZCU 공유로 LTO급 최적화 달성

## 인사이트

Zig가 단순히 언어 스펙만 다듬는 게 아니라, OS 커널 인터페이스부터 libc 구현, 패키지 매니저 워크플로우까지 소프트웨어 스택 전체를 자기 방식으로 재정의하고 있음. 특히 kernel32 우회와 zig libc는 '왜 기존 추상화 레이어를 그대로 쓰면 안 되는가'에 대한 설득력 있는 사례임.
