컴파일 변수
컴파일 변수 (Compile Variables)
컴파일 변수는
builtin패키지를 임포트해서 접근할 수 있어요. 이 패키지는 컴파일러가 모든 Zig 소스 파일에 기본으로 제공하는데, 현재 타깃, 엔디언(endianness), 릴리즈 모드 같은 컴파일 타임 상수들이 담겨 있어요. 출처: Zig Documentation
본문
컴파일 변수라는 이름답게, 이 값들은 컴파일 타임에 이미 결정돼 있어요. 그래서 빌드 타깃이나 최적화 설정에 따라 코드가 달라지는 상황이 필요할 때 아주 유용하죠.
예를 들어 경로 구분자를 타깃 OS에 맞게 골라야 한다면, 이렇게 쓸 수 있어요.
// compile_variables.zig
const builtin = @import("builtin");
const separator = if (builtin.os.tag == .windows) '\\' else '/';
builtin.os.tag를 보면 지금 컴파일되고 있는 OS가 Windows인지 아닌지가 컴파일 타임에 확정돼요. 그래서 이 if는 두 분기 중 하나만 남기고 다른 쪽은 아예 제거된 채로 컴파일돼요.
그럼 실제로 @import("builtin")이 내부에 어떤 값들을 들고 있는지, 그 예시를 한번 볼게요. 각 줄이 바로 pub const로 공개된 컴파일 타임 상수예요.
const std = @import("std");
pub const zig_version = std.SemanticVersion.parse(zig_version_string) catch unreachable;
pub const zig_version_string = "0.17.0-dev.2131+d08989840";
pub const zig_backend = std.lang.CompilerBackend.stage2_x86_64;
pub const output_mode: std.lang.OutputMode = .Exe;
pub const link_mode: std.lang.LinkMode = .static;
pub const unwind_tables: std.lang.UnwindTables = .async;
pub const is_test = false;
pub const single_threaded = false;
/// Deprecated; to be removed in 0.18.0. Use `target.abi` instead.
pub const abi: std.Target.Abi = .gnu;
/// Deprecated; to be removed in 0.18.0. Use `target.cpu` instead.
pub const cpu: std.Target.Cpu = .{
.arch = .x86_64,
.model = &std.Target.x86.cpu.znver2,
.features = std.Target.x86.featureSet(&.{
.@"64bit",
.adx,
.aes,
.allow_light_256_bit,
.avx,
.avx2,
.bmi,
.bmi2,
.branchfusion,
.clflushopt,
.clwb,
.clzero,
.cmov,
.crc32,
.cx16,
.cx8,
.f16c,
.fast_15bytenop,
.fast_bextr,
.fast_imm16,
.fast_lzcnt,
.fast_movbe,
.fast_scalar_fsqrt,
.fast_scalar_shift_masks,
.fast_variable_perlane_shuffle,
.fast_vector_fsqrt,
.fma,
.fsgsbase,
.fxsr,
.idivq_to_divl,
.lzcnt,
.mmx,
.movbe,
.mwaitx,
.nopl,
.pclmul,
.popcnt,
.prfchw,
.rdpid,
.rdpru,
.rdrnd,
.rdseed,
.sahf,
.sbb_dep_breaking,
.sha,
.slow_shld,
.smap,
.smep,
.sse,
.sse2,
.sse3,
.sse4_1,
.sse4_2,
.sse4a,
.ssse3,
.vzeroupper,
.wbnoinvd,
.x87,
.xsave,
.xsavec,
.xsaveopt,
.xsaves,
}),
};
/// Deprecated; to be removed in 0.18.0. Use `target.os` instead.
pub const os: std.Target.Os = .{
.tag = .linux,
.version_range = .{ .linux = .{
.range = .{
.min = .{
.major = 6,
.minor = 1,
.patch = 0,
},
.max = .{
.major = 6,
.minor = 1,
.patch = 0,
},
},
.glibc = .{
.major = 2,
.minor = 36,
.patch = 0,
},
.android = 29,
}},
};
pub const target: std.Target = .{
.cpu = cpu,
.os = os,
.abi = abi,
.ofmt = object_format,
.dynamic_linker = .init("/lib64/ld-linux-x86-64.so.2"),
};
/// Deprecated; to be removed in 0.18.0. Use `target.ofmt` instead.
pub const object_format: std.Target.ObjectFormat = .elf;
/// Deprecated, to be removed after 0.18.0
pub const mode = optimize;
pub const optimize: std.lang.Optimize = .debug;
pub const link_libc = false;
pub const link_libcpp = false;
pub const have_error_return_tracing = true;
pub const valgrind_support = true;
pub const sanitize_thread = false;
pub const fuzz = false;
pub const position_independent_code = false;
pub const position_independent_executable = false;
pub const strip_debug_info = false;
pub const code_model: std.lang.CodeModel = .default;
pub const omit_frame_pointer = false;
이건 보통 지정하지 않은 값들로 채워진 기본 세팅 모습이에요. 여기서 몇 가지 눈여겨볼 점을 짚어볼게요.
zig_version_string은 컴파일러 자신의 버전 문자열이에요.zig_version은 그것을std.SemanticVersion으로 파싱해 둔 값이고요. 코드에서 버전 분기가 필요할 때 이걸 그대로 쓰면 돼요.cpu,os,abi,ofmt같은 값들은 원래target필드에 합쳐져 있는데, 예전 이름으로 직접 접근할 수 있게 유지돼 있어요. 다만 주석에서 보시다시피target.cpu,target.os처럼target아래로 쓰는 게 새 권장 방식이라, 이 별칭들은 0.18.0에서 제거될 예정이에요.optimize는 현재 빌드 모드(여기선.debug)를 나타내요.mode는 그걸 가리키는 예전 이름이고요.
정리하면, 컴파일 변수는 "이 코드가 지금 어떤 환경에서, 어떤 설정으로 컴파일되고 있나"를 프로그램 안에서 물어볼 수 있게 해 주는 창구예요. 그래서 플랫폼·모드에 따라 행동을 바꿔야 하는 라이브러리나 스크립트에서 특히 자주 쓰여요.
더 알아보기
- Build Mode — 최적화 수준과 릴리즈 모드가
optimize등의 컴파일 변수에 어떻게 반영되는지.