C Translation CLI

C Translation CLI

Zig의 C 번역(C translation) 기능은 명령줄에서도 쓸 수 있는데요, 바로 zig translate-c라는 도구예요. 번역 대상이 되는 C 파일 이름을 인자로 딱 하나 받고, 선택적으로 clang에 전달할 플래그들을 함께 받아요. 그리고 번역이 끝난 파일은 표준 출력(stdout)으로 내보내죠.

출처: Zig Documentation

본문

zig translate-c는 C 소스를 Zig로 번역하는 CLI 도구예요. 자세한 사용 방법은 명령줄 플래그부터 하나씩 볼게요.

명령줄 플래그

  • -I: include 파일을 찾을 검색 디렉터리를 지정해요. 여러 번 사용할 수 있고, clang의 -I 플래그와 동일해요. 기본적으로 현재 디렉터리는 포함되지 않으니, 포함하고 싶다면 -I.을 써야 해요.
  • -D: 전처리기 매크로를 정의해요. clang의 -D 플래그와 동일해요.
  • -cflags [flags] --: clang에 임의의 추가 명령줄 플래그를 전달해요. 주의할 점은 플래그 목록이 반드시 --로 끝나야 한다는 거예요.
  • -target: 번역될 Zig 코드의 target triple을 지정해요. 지정하지 않으면 현재 호스트 타깃이 사용돼요.

-target-cflags 사용하기

중요합니다! zig translate-c로 C 코드를 번역할 때는, 나중에 번역된 코드를 컴파일할 때 쓸 것과 똑같은 -target triple을 반드시 사용해야 해요. 게다가 -cflags를 쓴다면, 그 플래그들이 타깃 시스템의 코드가 쓰는 cflags와 일치하는지도 꼭 확인해야 하고요. 잘못된 -target이나 -cflags를 쓰면 clang이나 Zig가 파싱에 실패하거나, C 코드와 링크할 때 미묘한 ABI 불일치(ABI incompatibility)가 생길 수 있어요.

target triple에 따라 번역 결과가 어떻게 달라지는지 바로 확인해 볼게요. 다음 C 파일을 두 가지 타깃으로 번역하면 c_long의 크기가 달라져요.

varytarget.h:

long FOO = __LONG_MAX__;
$ zig translate-c -target thumb-freestanding-gnueabihf varytarget.h|grep FOO
pub export var FOO: c_long = 2147483647;
$ zig translate-c -target x86_64-macos-gnu varytarget.h|grep FOO
pub export var FOO: c_long = 9223372036854775807;

같은 파일이라도 타깃이 thumb-freestanding-gnueabihfc_long이 32비트라 2147483647로 나오고, x86_64-macos-gnu면 64비트라 9223372036854775807이 되는 걸 볼 수 있어요.

cflags가 번역에 미치는 영향도 살펴볼게요. 다음 C 파일을 번역해 보면 enum의 기본 표현 방식이 어떻게 바뀌는지 보여요.

varycflags.h:

enum FOO { BAR };
int do_something(enum FOO foo);
$ zig translate-c varycflags.h|grep -B1 do_something
pub const enum_FOO = c_uint;
pub extern fn do_something(foo: enum_FOO) c_int;
$ zig translate-c -cflags -fshort-enums -- varycflags.h|grep -B1 do_something
pub const enum_FOO = u8;
pub extern fn do_something(foo: enum_FOO) c_int;

cflags를 주지 않으면 enum_FOOc_uint로 번역되는데, -fshort-enums를 넘기면 더 작은 u8로 바뀌죠. 이렇게 -target-cflags는 번역 결과 자체를 바꿀 수 있으니, 실제 컴파일에 쓰는 값과 항상 맞춰줘야 해요.

더 알아보기