Bazel Cross Compile

3 minute read

Basics of Bazel

  • Target:
    • Bazel ๋นŒ๋“œ ํ”„๋กœ์„ธ์Šค์˜ ๊ธฐ๋ณธ ๋‹จ์œ„๋กœ, ๋นŒ๋“œํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐœ๋ณ„ ํ•ญ๋ชฉ.
  • Label:
    • ํŠน์ • Target์„ ์ฐธ์กฐํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•˜๋Š” ๊ณ ์œ  ์‹๋ณ„์ž.
  • Rule:
    • ์–ด๋–ค ์•ก์…˜์„ ์„œ์ˆ ํ•˜๋Š” ๊ทœ์น™.
  • Package:
    • ๋นŒ๋“œ ํŒŒ์ผ(BUILD)์ด ์œ„์น˜ํ•œ ๋””๋ ‰ํ„ฐ๋ฆฌ. ์†Œ์Šค ์ฝ”๋“œ์™€ ๋นŒ๋“œ ๊ทœ์น™(rule)์„ ๋ชจ์•„ ๋†“์€ ๋…ผ๋ฆฌ์  ๋‹จ์œ„.
  • Workspace:
    • Bazel ๋นŒ๋“œ์˜ ์ตœ์ƒ์œ„ ๋””๋ ‰ํ„ฐ๋ฆฌ๋กœ, ํ”„๋กœ์ ํŠธ์˜ ์‹œ์ž‘ ์ง€์ .
  • Starlark:
    • Bazel์˜ ๋นŒ๋“œ ๋ฐ ์„ค์ • ํŒŒ์ผ์„ ์ž‘์„ฑํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•˜๋Š” ๋‚ด์žฅํ˜• ์Šคํฌ๋ฆฝํŒ… ์–ธ์–ด.
    • Python๊ณผ ์œ ์‚ฌํ•œ ๋ฌธ๋ฒ•์„ ๊ฐ€์ง€๊ณ  ์žˆ์ง€๋งŒ, ๋นŒ๋“œ ์‹œ์Šคํ…œ์— ์ตœ์ ํ™”๋˜์–ด ์žˆ๊ณ , ๊ฒฐ์ •์ (deterministic)์œผ๋กœ ๋™์ž‘ํ•˜๋„๋ก ์„ค๊ณ„.

Getting Started with Cross Compilation in Bazel

ํฌ๋กœ์Šค ์ปดํŒŒ์ผ๋Ÿฌ ์ค€๋น„

ํƒ€๊ฒŸ ํ”Œ๋žซํผ์„ ์œ„ํ•œ ์•Œ๋งž์€ ํˆด์ฒด์ธ ์ค€๋น„

  • ํˆด์ฒด์ธ(Toolchain)์ด๋ž€?
    • ํƒ€๊ฒŸ ํ”Œ๋žซํผ(์˜ˆ: CPU ์•„ํ‚คํ…์ฒ˜๋‚˜ ์šด์˜์ฒด์ œ)์ด ํ˜„์žฌ ๊ฐœ๋ฐœ ์ค‘์ธ ํ˜ธ์ŠคํŠธ ํ”Œ๋žซํผ๊ณผ ๋‹ค๋ฅผ ๋•Œ, ํƒ€๊ฒŸ ํ™˜๊ฒฝ์— ๋งž๋Š” ์‹คํ–‰ ํŒŒ์ผ์„ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•œ ๋„๊ตฌ๋“ค์˜ ๋ชจ์Œ์„ ์˜๋ฏธ.

Platform

Bazel์—์„œ Platform์€ ํŠน์ • ๋นŒ๋“œ ํ™˜๊ฒฝ์— ๋งž๋Š” ํ•˜๋“œ์›จ์–ด ๋ฐ ์†Œํ”„ํŠธ์›จ์–ด ์š”๊ตฌ ์‚ฌํ•ญ์„ ์ •์˜ํ•˜๋Š” ๊ฐœ๋…์ž…๋‹ˆ๋‹ค. ํ”Œ๋žซํผ์„ ์ •์˜ํ•จ์œผ๋กœ์จ Bazel์€ ์—ฌ๋Ÿฌ ํ™˜๊ฒฝ์—์„œ ๋นŒ๋“œ ์ž‘์—…์„ ๋” ํšจ์œจ์ ์œผ๋กœ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๊ฐ ํ”Œ๋žซํผ์— ๋งž๋Š” ํˆด์ฒด์ธ์„ ์ž๋™์œผ๋กœ ์„ ํƒํ•˜์—ฌ ๋นŒ๋“œ๋ฅผ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Bazel์—์„œ Platform์€ ๋‹ค์Œ ๋‘ ๊ฐ€์ง€ ๊ธฐ๋ณธ ์š”์†Œ๋ฅผ ์‚ฌ์šฉํ•ด ์ •์˜ํ•ฉ๋‹ˆ๋‹ค.

  • ์ œ์•ฝ ์กฐ๊ฑด ์„ค์ • (constraint_setting)
    • Platform์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์ œ์•ฝ ์กฐ๊ฑด์˜ ์œ ํ˜•์„ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค.
    • ์˜ˆ๋ฅผ ๋“ค์–ด, ์šด์˜์ฒด์ œ ์œ ํ˜•, CPU ์•„ํ‚คํ…์ฒ˜, C++ ABI ๋“ฑ์ด ํฌํ•จ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์ œ์•ฝ ์กฐ๊ฑด ๊ฐ’ (constraint_value)
    • ๊ฐ ์ œ์•ฝ ์กฐ๊ฑด์— ๋Œ€ํ•ด ๊ตฌ์ฒด์ ์ธ ๊ฐ’์„ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค.
    • ์˜ˆ๋ฅผ ๋“ค์–ด, ์šด์˜์ฒด์ œ ์œ ํ˜•์— ๋Œ€ํ•œ ์ œ์•ฝ ์กฐ๊ฑด์œผ๋กœ linux, windows, macos ๋“ฑ์˜ ๊ฐ’์„ ์ •์˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
constraint_value(
    name = "bare_metal",
    constraint_setting = "@platforms//os",
    visibility = ["//visibility:public"],
)

platform(
    name = "riscv64_bare_metal",
    constraint_values = [
        ":bare_metal",
        "@platforms//cpu:riscv64",
    ],
)

Toolchain

Bazel์—์„œ ํฌ๋กœ์Šค ์ปดํŒŒ์ผ์„ ์ˆ˜ํ–‰ํ•˜๋ ค๋ฉด ์ปดํŒŒ์ผ ํƒ€๊ฒŸ์— ๋งž๋Š” ๋„๊ตฌ ์ฒด์ธ(toolchain)์„ ์„ค์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” CPU ์•„ํ‚คํ…์ฒ˜๋‚˜ ์šด์˜์ฒด์ œ์— ๋”ฐ๋ผ ๋‹ฌ๋ผ์ง€๋ฏ€๋กœ, ๋ณดํ†ต CROSSTOOL ํŒŒ์ผ์ด๋‚˜ .bazelrc ํŒŒ์ผ์„ ์‚ฌ์šฉํ•˜์—ฌ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. Bazel์˜ ๊ธฐ๋ณธ ํˆด์ฒด์ธ์„ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜, ์ƒˆ๋กœ์šด ํˆด์ฒด์ธ์„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ์ปค์Šคํ…€ ๋ฃฐ์„ ์ƒˆ๋กœ ์ž‘์„ฑํ•˜๋ฉด์„œ ํˆด์ฒด์ธ์„ ์ •์˜ํ•˜๋Š” ๋ฐฉ๋ฒ•
  • ๊ธฐ์กด์˜ ๋ฃฐ์„ ์žฌ์‚ฌ์šฉํ•˜์—ฌ ํˆด์ฒด์ธ์„ ์ •์˜ํ•˜๋Š” ๋ฐฉ๋ฒ•

์—ฌ๊ธฐ์„œ๋Š” ๊ธฐ์กด์˜ ๋ฃฐ์„ ์žฌ์‚ฌ์šฉํ•˜์—ฌ ํˆด์ฒด์ธ์„ ์ •์˜ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค.

Toolchain config ์ •์˜ํ•˜๊ธฐ

toolchain_config๋Š” Bazel์—์„œ ํŠน์ • ํˆด์ฒด์ธ(toolchain)์˜ ๋™์ž‘์„ ๊ตฌ์„ฑํ•˜๊ณ  ์„ค์ •ํ•˜๋Š” ์—ญํ• ์„ ํ•˜๋Š” ๊ตฌ์„ฑ ํŒŒ์ผ. ์ด ์„ค์ •์€ ์ปดํŒŒ์ผ๋Ÿฌ์™€ ๋ง์ปค๊ฐ€ ํŠน์ • ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ๋•Œ ์–ด๋–ค ํ”Œ๋ž˜๊ทธ๋ฅผ ์‚ฌ์šฉํ• ์ง€, ์–ด๋–ค ๊ฒฝ๋กœ์—์„œ ์‹คํ–‰ ํŒŒ์ผ์„ ์ฐพ์„์ง€ ๋“ฑ ์„ธ๋ถ€ ์‚ฌํ•ญ์„ ๋‹ค๋ฃน๋‹ˆ๋‹ค.

load("@bazel_tools//tools/cpp:cc_toolchain_config_lib.bzl", "feature", "tool_path", ... )

toolchain_tools = ["gcc", "ld", "ar", "cpp", "gcov", "nm", "objdump", "strip"]
tool_paths = [tool_path(name = tool, path = "/usr/bin/riscv64-linux-gnu-{}".format(tool)) for tool in toolchain_tools]

feature๋ž€?

  • Bazel์—์„œ feature ๊ทœ์น™์€ ํŠน์ • ์ปดํŒŒ์ผ/๋นŒ๋“œ ์„ค์ •์„ ์ •์˜ํ•˜์—ฌ ๋นŒ๋“œ ํ”„๋กœ์„ธ์Šค ์ค‘์— ํ•„์š”ํ•œ ํ”Œ๋ž˜๊ทธ๋‚˜ ๋™์ž‘์„ ์ œ์–ดํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.
# rv64_bare_metal_toolchain.bzl
load("@bazel_tools//tools/build_defs/cc:action_names.bzl", "ACTION_NAMES")

ASSEMBLE_ACTIONS = [
      ACTION_NAMES.assemble,
      ACTION_NAMES.preprocess_assemble,
  ]

COMPILE_ACTIONS = [
    ACTION_NAMES.cpp_compile,
    ACTION_NAMES.c_compile
]

ASSEMBLE_AND_COMPILE_ACTIONS = ASSEMBLE_ACTIONS + COMPILE_ACTIONS

arch_abi = feature(
    name = "arch_and_abi",
    enabled = True,
    flag_sets = [
        flag_set(
            actions = ASSEMBLE_AND_COMPILE_ACTIONS,
            flag_groups = [
                flag_group(
                    flags = ["-march=rv64i", "-mabi=lp64"],
                ),
            ],
        )
    ],
)

...

features = [arch_abi, link_static_no_stdlib, no_build_id]

...

return cc_common.create_cc_toolchain_config_info(
    ctx = ctx,
    toolchain_identifier = "local",
    host_system_name = "local",
    target_system_name = "local",
    target_cpu = "riscv64",
    target_libc = "unknown",
    compiler = "clang",
    abi_version = "unknown",
    abi_libc_version = "unknown",
    tool_paths = tool_paths,
    cxx_builtin_include_directories = [
        "/usr/riscv64-linux-gnu/include/",
        "/usr/lib/gcc-cross/riscv64-linux-gnu/10/include/",
    ],
    features = features,
)

CcToolchainConfigInfo?

  • CcToolchainConfigInfo๋Š” Bazel์˜ C/C++ ๋นŒ๋“œ์—์„œ ํˆด์ฒด์ธ์˜ ๊ตฌ์„ฑ์„ ๋‚˜ํƒ€๋‚ด๋Š” ์ œ๊ณต์ž(Provider).
  • ์ด ์ œ๊ณต์ž๋Š” Bazel์ด C/C++ ๋นŒ๋“œ์˜ ํŠน์ • ์š”๊ตฌ ์‚ฌํ•ญ์„ ์ถฉ์กฑํ•˜๊ธฐ ์œ„ํ•ด ํˆด์ฒด์ธ์— ๋Œ€ํ•œ ์„ธ๋ถ€ ์„ค์ • ์ •๋ณด๋ฅผ ์ „๋‹ฌํ•˜๊ณ  ๊ด€๋ฆฌํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ.
rv64_bare_metal_toolchain_config = rule(
  implementation = _impl,
  attrs = {},
  provides = [CcToolchainConfigInfo],
)
load(":rv64_bare_metal_toolchain.bzl", "rv64_bare_metal_toolchain_config")

rv64_bare_metal_toolchain_config(
  name = "rv64_bare_metal_config"
);

Toolchain ์ •์˜ํ•˜๊ธฐ

load(":rv64_bare_metal_toolchain.bzl", "rv64_bare_metal_toolchain_config")

rv64_bare_metal_toolchain_config(
  name = "rv64_bare_metal_config"
);

cc_toolchain(
  name = "rv64_bare_metal_toolchain",
  toolchain_identifier = "local",
  toolchain_config = ":rv64_bare_metal_config",
  ...
)

toolchain(
  name = "riscv64_bare_metal_toolchain_from_linux_x86_64",
  exec_compatible_with = [
    "@platforms//os:linux",
    "@platforms//cpu:x86_64",
  ],
  target_compatible_with = [
    "//platform:bare_metal",
    "@platforms//cpu:riscv64",
  ],
  toolchain = ":rv64_bare_metal_toolchain",
  toolchain_type = "@bazel_tools//tools/cpp:toolchain_type",
)

Toolchain ์‚ฌ์šฉํ•˜๊ธฐ

์ด์ œ ์ผ๋ฐ˜์ ์ธ cc_library์™€ cc_binary ํƒ€๊ฒŸ์„ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค!

BARE_METAL_RISCV64_CONSTRAINTS = [
  "//platform:bare_metal",
  "@platforms//cpu:riscv64",
]

cc_binary(
  name = "program",
  srcs = [
    "program.c",
    "boot.S",
  ],
  additional_linker_inputs = [
    "link_script.ld",
  ],
  linkopts = ["-Wl,-T $(location :link_script.ld)"],
  target_compatible_with = BARE_METAL_RISCV64_CONSTRAINTS,
)

๋นŒ๋“œ ๋ช…๋ น์–ด

ํฌ๋กœ์Šค ์ปดํŒŒ์ผ์„ ์‹คํ–‰ํ•  ๋•Œ๋Š” โ€“platforms ํ”Œ๋ž˜๊ทธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํƒ€๊ฒŸ ํ”Œ๋žซํผ์„ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด: bazel build -s โ€“platforms=//platform:riscv64_bare_metal //program

์ฐธ์กฐ

Cross compiling C and C++ with Bazel, Uros Popovic

Tags:

Categories:

Updated:

Leave a comment