Zig 패키지 관리 및 빌드 시스템 재구성

Zig 패키지 관리 및 빌드 시스템 재구성

Zig는 패키지 관리 로직을 컴파일러 실행 파일에서 분리하여 빌드 시스템(“maker” 프로세스)으로 옮겼습니다. 이 구조적 변화로 패키지 관리 작업을 컴파일러를 다시 빌드하지 않고도 패치할 수 있게 되었으며, 네트워킹 작업에 ReleaseSafe 모드를 사용할 수 있어 전반적인 보안성과 성능이 향상되었습니다.

패키지 관리가 빌드 시스템으로 이동

Zig는 패키지 관리 책임을 컴파일러에서 빌드 시스템으로 옮겼습니다. 이제 zig build, zig fetch, zig init, zig libc와 같은 하위 명령은 컴파일러 실행 파일이 아니라 maker 프로세스에 의해 처리됩니다.

그 결과, 이전에 컴파일러에 포함되어 있던 여러 구성 요소가 이제 소스 형태로 제공됩니다:

  • 패키지 가져오기 로직
  • HTTP 클라이언트 및 네트워킹 스택
  • TLS(전송 계층 보안) 및 관련 암호화
  • Git 프로토콜 구현
  • 압축 라이브러리(xz, gzip, zstd, flate, zip)
  • build.zig.zon 파싱 및 검증

이 분리를 통해 빌드 시스템은 일반 컴파일러 배포판에 포함하기엔 너무 드문 호스트‑특정 CPU 명령을 암호화와 파일 해싱에 활용할 수 있게 됩니다. 또한 Zig 실행 파일의 크기가 약 4% 감소했습니다(LLVM 없이 ReleaseSmall 설정 기준 14.1 MiB → 13.5 MiB).

프로세스 아키텍처 진화

이 변화를 지원하기 위해 Zig는 구성 재실행 시 빌드 시스템이 부모 프로세스로 남도록 프로세스 트리를 진화시켰습니다.

이전 아키텍처:

zig build (the zig compiler + package manager)
└─ builder (the user's build.zig logic + build system implementation)

중간 아키텍처:

zig build (the zig compiler + package manager)
├─ configurer (the user's build.zig logic)
└─ maker (build system)

현재 아키텍처:

zig build (the zig compiler)
└─ maker (build system + package manager)
   └─ configurer (the user's build.zig logic)

makerconfigurer의 부모가 되면 configurer를 다시 실행해야 할 때(zig build --watch 세션 등) maker 프로세스가 계속 살아 있어 서버가 종료되고 클라이언트가 재연결되는 상황을 피할 수 있습니다. 이는 ZLS(Zig Language Server)의 차단을 해제하기 위한 빌드 서버 프로토콜을 공개하는 중요한 단계입니다.

빌드 시스템 성능 및 재구성

Zig는 "configurer"(사용자 build.zig 로직을 실행)와 "maker"(빌드 그래프를 실행) 사이에 명확한 구분을 도입했습니다. configurer는 디버그 모드로 컴파일되고, maker는 릴리즈 모드로 컴파일됩니다.

이 재구성은 세 가지 주요 성능 이점을 제공합니다:

  1. 컴파일 시간 감소: 변경이 있을 때 전체 빌드 시스템이 아니라 사용자 build.zig 로직만 컴파일됩니다.
  2. 구성 캐시: 변경이 감지되지 않으면 직렬화된 바이너리 구성 파일을 사용해 build.zig 로직을 완전히 건너뛸 수 있습니다.
  3. 실행 최적화: 빌드 그래프를 실행하는 프로세스가 이제 최적화된 코드로 컴파일됩니다.

벤치마크 결과는 간단한 명령의 실제 실행 시간이 크게 감소했음을 보여줍니다. 예를 들어 zig build -h는 150 ms에서 14.3 ms로 감소했으며(~90% 개선)였습니다.

LLVM 백엔드와 @bitCast 의미론

Zig는 비‑ABI 정수 타입이 낮아지는 방식을 개선하기 위해 LLVM 백엔드를 업데이트했습니다. 이전에는 임의 비트 폭 정수가 직접 LLVM IR bit-int 타입으로 낮아져 최적화가 누락되거나 잘못 컴파일되는 경우가 있었습니다. 이제 Zig는 이러한 값을 메모리에 저장할 때 ABI 크기의 타입으로 제로‑또는 부호‑확장하여 Clang의 _BitInt(N) 동작과 일치시킵니다.

@bitCast 재정의

메모리 변화에 맞추어 Zig는 @bitCast바이트 재해석이 아니라 타입의 논리적 비트 레이아웃을 기반으로 재정의했습니다.

  • 논리적 비트 레이아웃: 타입은 이제 가장 낮은 비트부터 가장 높은 비트까지 순서대로 배열된 비트 시퀀스로 표현됩니다. 예를 들어 u5는 5개의 논리 비트이며, [2]u5는 10개의 논리 비트입니다.
  • 엔디안 무관성: 연산이 논리적이므로 @bitCast는 모든 타깃에서 동일하게 동작합니다. [2]u8u16으로 비트캐스팅하면 첫 번째 배열 요소가 항상 8개의 최소 비트를 차지하게 되며, 타깃이 빅‑엔디안이든 리틀‑엔디언이든 결과는 같습니다.

이 변경으로 컴파일러의 Legalize 패스를 활용해 복잡한 @bitCast 연산을 LLVM 및 C 백엔드 모두에서 더 단순한 형태로 변환할 수 있게 되었습니다.

ELF 링커와 증분 컴파일

Zig는 -fnew-linker 플래그로 활성화되는 새로운 ELF 링커를 도입했으며, x86_64 Linux에서 빠른 증분 컴파일을 지원합니다. 이 링커는 외부 라이브러리와 C 소스를 링크하면서도 추가적인 성능 오버헤드 없이 증분 재빌드를 가능하게 하여, 일부 재빌드가 30 ms 안에 완료될 수 있습니다.

SPIR‑V 백엔드 진행 상황

SPIR‑V 백엔드에 대한 중요한 업데이트가 포함되었습니다:

  • @SpirvType: Zig 표준 타입 시스템으로 표현할 수 없는 SPIR‑V 타입(예: 샘플러와 이미지)을 나타내는 새로운 내장 함수.
  • 호출 규약: 실행 모드 정보(워크그룹 크기 등)가 이제 인라인 어셈블리가 아니라 호출 규약(callconv(.spirv_kernel))에 포함됩니다.
  • 멀티스레드 코드젠: 코드젠이 이제 Mir 값을 생성하고 컴파일러 스레드 풀에서 스케줄되어 단일 스레드 실행에서 벗어났습니다.
  • 오브젝트 파일 링크: .spv 파일이 오브젝트 파일로 인식되어 여러 .zig 파일이나 외부 .spv 오브젝트를 하나의 모듈로 링크할 수 있게 되었습니다.

표준 라이브러리와 OS 통합

Windows 네이티브 API 선호

Zig는 Win32(kernel32.dll) 래퍼보다 네이티브 NT API 사용을 선호하도록 이동하고 있습니다. 이는 불필요한 힙 할당을 줄이고 중복 오류 모드를 없애며 바이너리 부피를 감소시키기 위함입니다. 예를 들어 이제 Zig는 엔트로피(무작위 바이트)와 파일 I/O(NtReadFile/NtWriteFile)에 대해 kernel32.dll을 우회하여 취소와 더 나은 자원 관리를 지원합니다.

zig libc

Zig는 libc 구현에 포함된 벤더드 C 소스 파일을 점진적으로 Zig 표준 라이브러리 래퍼로 교체하고 있습니다. 이는 C 언어에 대한 의존성을 낮추고 컴파일 속도와 바이너리 크기를 개선합니다. 이러한 libc 함수들은 이제 Zig Compilation Unit(ZCU)을 공유하여 LTO와 유사한 경계 간 최적화를 가능하게 합니다.

이벤트 기반 I/O

실험적인 io_uring(Linux) 및 Grand Central Dispatch(GCD, macOS) 구현이 std.Io.Evented에 추가되었습니다. 이 구현은 사용자 공간 스택 스위칭(섬유/그린 스레드)을 사용해 I/O 구현을 애플리케이션 로직을 변경하지 않고도 손쉽게 교체할 수 있게 합니다.

커뮤니티 인사이트

아키텍처 변화가 기술적인 이유로 전반적으로 호평을 받는 반면, 일부 사용자는 사용자 경험(UX)에 대한 우려를 표명했습니다. 한 기여자는 컴파일러에서 @cImport를 제거하고 빌드 시스템으로 옮긴 것이 "개발자의 정신 건강은 UX보다 먼저다"는 트레이드오프라고 언급했습니다.

"Zig, Go, 그리고 Python 개발자들은 '우리는 라디에이터 액을 연료 탱크에서 뺐다'고 발표하고, 그들의 지지자들은 이것이 언어에 좋다고 환호한다. 나는 여기서 왜 처음에 라디에이터 액을 연료 탱크에 넣었는지 궁금해한다."


요약: Zig는 모든 패키지 관리 기능을 컴파일러에서 빌드 시스템으로 옮겨 빌드 속도를 높이고 안전성을 강화했으며, 도구 통합을 위한 보다 유연한 아키텍처를 제공했습니다.

제목: Zig 패키지 관리 및 빌드 시스템 재구성

Sources