컴파일 변수

컴파일 변수 (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 등의 컴파일 변수에 어떻게 반영되는지.