1P by GN⁺ | ★ favorite | 댓글 1개
  • Zig는 build.zig와 빌드 시스템을 별도 프로세스로 분리한 흐름에 맞춰, 패키지 관리 로직을 컴파일러 실행 파일 밖의 maker 프로세스로 옮김
  • zig build, zig fetch, zig init, zig libc가 maker 쪽으로 이동하면서 HTTP, TLS, Git, 압축, build.zig.zon 처리 코드가 소스 형태로 배포됨
  • 이 구조에서는 컴파일러 재빌드 없이 패키지 관리 기능을 고칠 수 있고, maker가 ReleaseSafe로 컴파일되어 네트워킹 작업의 안전성 검사도 활성화됨
  • 원래 목적은 build server protocol을 노출해 ZLS를 막고 있던 --build-runner 변경 문제를 푸는 것이며, 새 프로세스 트리에서는 maker가 configurer의 부모로 남아 설정 재실행을 더 안정적으로 처리할 수 있음
  • 사용자 영향은 크지 않지만 Zig 실행 파일은 14.1MiB에서 13.5MiB로 4% 줄고, --maker-opt--zig-lib-dir는 각각 ZIG_DEBUG_MAKER, ZIG_LIB_DIR 환경 변수로 대체됨

패키지 관리 로직의 이동

  • Zig는 사용자 build.zig 스크립트와 빌드 시스템 자체가 별도 프로세스로 분리된 뒤, 패키지 관리 로직도 빌드 시스템 쪽에 두는 구조로 바꿈
  • maker 프로세스로 이동한 하위 명령은 다음과 같음
    • zig build
    • zig fetch
    • zig init
    • zig libc

컴파일러 실행 파일에서 빠진 코드

  • 이전에는 컴파일러 실행 파일 안에 있던 큰 코드 영역들이 이제 소스 형태로 배포됨
    • 패키지 가져오기 로직
    • HTTP 클라이언트와 네트워킹
    • TLS와 관련 암호화
    • Git 프로토콜
    • xz, gzip, zstd, flate, zip
    • build.zig.zon 파일의 파싱, 검증, 기타 처리
  • 이 기능들은 컴파일러를 다시 빌드하지 않고도 패치할 수 있어 사용자와 기여자가 더 쉽게 실험할 수 있음
  • maker 실행 파일은 ReleaseSafe 모드로 컴파일되므로, 패키지 관리의 네트워킹 작업에서 안전성 검사가 켜짐
  • 네트워킹과 파일 해싱에 쓰이는 암호화 코드는 호스트에서 사용 가능한 특수 CPU 명령을 활용할 수 있음

프로세스 구조와 build server

  • 원래 동기는 build server protocol을 노출해 ZLS를 막고 있던 문제를 해소하는 것이었음
  • 이전 구조에서는 zig build가 컴파일러와 패키지 관리자를 함께 담당하고, 그 아래 builder가 사용자 build.zig 로직과 빌드 시스템 구현을 담았음
  • maker/configurer 분리 이후 구조는 다음과 같았음
    • zig build: 컴파일러 + 패키지 관리자
    • configurer: 사용자 build.zig 로직
    • maker: 빌드 시스템
  • 이 구조에서 오래 실행되는 zig build --watchbuild.zig나 관련 파일 변경을 감지하면 configurer를 다시 실행해야 했고, 이를 위해 maker가 종료되어 zig build가 패키지 관리 로직을 반복할 기회를 줘야 했음
  • 새 구조에서는 zig build가 컴파일러만 맡고, 그 아래 maker가 빌드 시스템과 패키지 관리자를 담당하며, configurer는 maker의 자식 프로세스가 됨
  • 설정을 다시 실행해야 할 때도 maker가 부모 프로세스로 계속 살아 있을 수 있음
  • 예정된 build server에서는 서버 종료 후 클라이언트가 다시 연결하는 대신, 클라이언트에 설정 변경을 알리는 구조가 가능해짐

관찰 가능한 변경점

  • 대부분 비호환 변경은 아니지만, 사용자가 볼 수 있는 차이가 있음
    • Zig 실행 파일 바이너리 크기: LLVM 없는 ReleaseSmall 기준 14.1MiB에서 13.5MiB로 줄어 4% 감소
    • --maker-opt 플래그는 ZIG_DEBUG_MAKER 환경 변수로 대체됨
    • --zig-lib-dir 플래그는 ZIG_LIB_DIR 환경 변수로 대체됨

Zig 0.17.0 전 남은 차단 이슈

댓글과 토론

Hacker News 의견들
  • Zig, Go, Python 개발자들은 가끔 연료 탱크에서 냉각수를 제거했다고 발표하고, 지지자들은 언어에 좋고 성능도 크게 좋아질 거라며 환호함
    그런데 애초에 왜 냉각수를 연료 탱크에 넣었는지가 더 궁금함

    • 이런 프로젝트 초기에는 설계 결과를 깊이 생각하기보다 개별 개발자의 편의가 우선되기 쉬움
      패키지 관리를 컴파일러 안에 넣는 건 편했지만, 언어와 도구가 널리 쓰이기 시작하면 개인에게 유리했던 기능이 도입을 막는 부채가 됨
      많은 프로젝트에서 개발자들이 “제대로 하려면 필요한 어려운 작업”을 피하려고 편한 방식을 택하고, 다른 사람들도 그 어려운 일을 하기 싫어하니 그게 관례가 되어버림
    • 여기에는 옹호할 만한 논리도 있음
      빌드 시스템 안에 패키지 관리자를 구현하면서 컴파일러에도 남기고 싶다면, 컴파일러와 빌드 시스템 사이에 어떤 추상화를 둘지 먼저 정해야 함
      이는 import 시스템과 언어의 근본적인 부분에도 영향을 주고, 이런 부분은 제대로 설계해야 하며 나중에 바꾸기도 어려움
      처음에는 패키지 관리와 컴파일러를 강하게 결합해 원하는 프로그래머 경험에서 거꾸로 설계한 뒤, 나중에 구현을 바꾸면 사용자 영향이 더 적을 수 있음
      특히 Python의 import 시스템은 패키지 관리가 여러 방식으로 이뤄진 걸 수용하느라 매우 복잡하고 흠이 많아졌다고 봄
      반면 Go는 처음부터 패키지 관리를 염두에 두고 설계해서 import 관련 문법이 비교적 작고 깔끔함. 물론 모든 설계 결정에 동의하는 건 아님
    • 뭔가를 만들어본 적이 없어서 그렇게 들리는 것 같음
      작은 제품도 각 구성 요소가 어떻게 상호작용할지 예측하기 어려워 계속 고쳐야 함
      이제 자가 호스팅 C 대체 언어를 만든다고 생각해보면 됨
    • 성능에 대해서도 정확히 같은 느낌을 받음. 특정 프로그래밍 언어나 내 최적화와도 무관함
      속도 향상이 클수록 환호하지만, 대부분의 최적화는 영리한 기법이 아니라 프로파일러로 “어, 냉각수가 연료 탱크에 들어가면 안 되는데”를 찾는 일임
      대부분의 성능 병목은 하드웨어나 문제 자체의 본질적 한계가 아님
      결과를 얻는 데 필요한 최소한의 작업량은 있지만, 애플리케이션이 느린 이유는 거의 항상 그 위에 덧붙인 잡동사니 때문임
    • Zig나 Python은 잘 몰라 판단하기 어렵지만, Go에서는 전혀 그런 느낌을 못 받음. 언제 그런 일이 있었는지 모르겠음
  • Zig 개발은 정말 건강한 분위기로 느껴짐

    • 요즘 Zig를 보면 소프트웨어 개발이라는 craft가 죽었거나 LLM으로 대체된 게 아니라는 걸 증명해줌
      LLM을 매일 쓰고 있고 여러 문제 유형에서 놀랄 만큼 잘한다는 건 인정하지만, LLM이 만든 프로그래밍 언어는 원하지 않음
      프로그래밍 언어의 모든 코드 줄, 결정, 절충이 중요함
      분위기만으로 설계하고 코딩한 언어는 재앙이 될 것임
      어떤 모델도 그 반대로 확신할 만한 코드를 보여준 적이 없음. Fable조차 이전 최고 모델보다 분명히 나아졌지만 마찬가지임
      모델은 원하는 게 없고, 의미 있는 견해도 없으며, 언어에서 편안함과 불편함이 무엇인지 모름. 충분히 복잡한 GUI나 CLI 인터페이스에서도 마찬가지임
      Zig 같은 언어는 단순히 Zig를 베끼지 않는 한 LLM에서 나올 수 없고, 베끼더라도 더 나쁜 복사본일 것임
      여기서 LLM으로 베낀다는 건 소스 트리를 문자 그대로 cp하는 게 아니라, LLM이 명세를 쓰고 다른 LLM이 그 명세대로 언어를 구현하는 식을 뜻함
    • Zig로 만드는 것도 꽤 재미있음
      부트로더를 만들고 UEFI 작업을 해봤는데, 개인적으로는 C로 할 때보다 훨씬 쉬웠음
      다만 새롭고 반짝이는 걸 배우는 재미가 있어서 편향이 커진 것도 있음
  • 이 변경이 Zig에서 @cImport를 제거하고 빌드 시스템으로 옮기게 만든 그 변경이 맞는지 궁금함
    순전히 사용자 경험 문제이고, 빌드 시스템과 컴파일러를 분리하는 변경이 유지보수자에게 중요하다는 건 알지만, 그래도 개발 안정성이 사용자 경험보다 먼저 온다는 게 조금 아쉬움
    올바른 판단이긴 하지만 슬프고, @cImport는 이 언어의 강력한 킬러 기능이었다고 봄

    • 꼭 그렇지는 않음
      이 변경은 서드파티 패키지를 다운로드하고 압축 해제하는 코드에 관한 것임
      @cImport 변경은 Zig의 LLVM/libclang 의존성을 언젠가 선택 사항으로 만들고, 나중에는 서드파티 패키지로 뺄 수 있게 하려는 작업의 일부였지만 직접 관련 있어 보이지는 않음
  • 장기 목표가 빌드 시스템을 WebAssembly VM 안으로 옮기는 것이라고 어디선가 읽었음
    그렇다면 대단한 일임

    • 빌드에서 그게 어떤 장점이 있는지 궁금함
  • Zig에 좋은 변화임
    Go에서 Zig로 넘어가고 싶은 마음이 꽤 크지만, 일단은 옆에서 지켜보는 것도 즐기고 있음

    • 사용 사례에 따라 둘 다 쓸 수 있고, 어쩌면 그래야 함
  • 언어가 자기만의 패키지 시스템을 만들 때마다 우리가 뭔가 큰 기회를 놓쳤다는 생각만 듦
    유일한 예외는 C/C++인데, 좋든 나쁘든 충분히 자리 잡은 게 없음
    이런 선택은 나중에 여러 언어를 섞어 써야 할 때 매우 복잡한 절차를 만들 수 있음
    패키징 시스템은 일을 쉽게 만들지만, 다른 언어를 써야 하는 순간 이후 과정을 더 복잡하게 함

    • 무엇을 놓쳤다고 보는지 궁금함
      모든 언어를 위한 하나의 빌드 시스템을 원하는 건가? Bazel 같은 시스템은 있고 다중 언어 프로젝트에도 자주 쓰이지만, 현실적으로는 언어별 지식을 가진 빌드 시스템이 훨씬 다루기 쉽다는 게 증명된 듯함
    • C++에 표준화된 패키징 시스템이 없는 건 오히려 좋다고 봄
      의존성을 추가하기 전에 신중히 생각하게 만들기 때문임
      이런 의존성에는 보안 취약점 같은 숨은 비용이 있는 경우가 많음
      중요한 시스템 상당수가 C++로 작성되어 있으니, 쉽게 접근 가능한 서드파티 패키지 수십 개에 각 패키지를 제대로 감사하지 않고 의존하는 건 위험이 너무 큼
    • C는 여러 문제를 고치고 패키지 관리자를 추가하거나 하나를 공식적으로 인정했어야 함
      Zig가 그 빈자리를 채우고 있음
    • 세계는 아직 좋은 크로스플랫폼 다중 언어 빌드 시스템으로 표준화하지 못했음
      사실상 그런 빌드 시스템은 Buck과 Bazel뿐인데, 둘 다 배후의 거대 조직에서 온 짐이 너무 많음
      아쉬운 일임
    • Conan과 vcpkg는 충분히 자리 잡았음
  • 관심사의 분리가 아주 잘 납득되게 이뤄졌음