Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

MoonBit

MoonBit은 WebAssembly 컴포넌트를 포함한 최신 WebAssembly를 일급으로 지원하는 프로그래밍 언어입니다.

이 가이드에서는 MoonBit을 사용하여 WebAssembly 컴포넌트를 빌드하는 방법을 설명합니다. 인터페이스 정의에는 WIT(WebAssembly 인터페이스 타입)를, 코드 생성에는 wit-bindgen 툴체인을 활용합니다.

이 튜토리얼에서는 docs:adder 패키지에 정의된 adder 월드를 구현하는 컴포넌트를 빌드하는 과정을 단계별로 안내합니다. 이 컴포넌트는 두 수를 더하는 add 함수가 포함된 add 인터페이스를 익스포트합니다.

1. 도구 설치

MoonBit 설치하기

먼저 MoonBit 컴파일러와 툴체인을 설치하십시오. MoonBit 다운로드 페이지의 설치 안내를 따르십시오.

MoonBit 설치를 확인하십시오(아래는 작성 시점의 버전입니다):

$ moon version --all
moon 0.1.20250826 (8ab6c9e 2025-08-26) ~/.moon/bin/moon
moonc v0.6.25+d6913262c (2025-08-27) ~/.moon/bin/moonc
moonrun 0.1.20250826 (8ab6c9e 2025-08-26) ~/.moon/bin/moonrun
moon-pilot 0.0.1-95f12db ~/.moon/bin/moon-pilot

Wasm 툴체인 설치하기

다음 도구가 필요합니다:

  • WIT에서 MoonBit 바인딩을 생성하기 위한 wit-bindgen
  • 컴포넌트 변환을 위한 wasm-tools
  • (선택 사항) Wasm 런타임으로 사용할 wasmtime

각 GitHub 릴리스에서 실행 파일을 다운로드하거나, Rust 툴체인이 설치되어 있다면 다음과 같이 설치할 수 있습니다:

cargo install wit-bindgen-cli
cargo install wasm-tools
cargo install wasmtime-cli

설치를 확인하십시오(아래는 작성 시점의 버전입니다):

$ wit-bindgen --version
wit-bindgen-cli 0.45.0
$ wasm-tools --version
wasm-tools 1.238.0
$ wasmtime --version
wasmtime 36.0.2

2. 인터페이스 정의하기(WIT)

MoonBit 프로젝트를 생성하기 전에 WIT를 사용하여 컴포넌트 인터페이스를 정의해야 합니다.

프로젝트용 디렉터리를 만들고 WIT 파일을 정의하십시오:

mkdir moonbit-adder && cd moonbit-adder
mkdir wit

다음 내용으로 wit/world.wit를 만드십시오:

package docs:adder@0.1.0;

interface add {
    add: func(x: u32, y: u32) -> u32;
}

world adder {
    export add;
}

이 WIT 정의는 다음을 수행합니다:

  • 버전이 0.1.0인 docs:adder 패키지를 선언합니다
  • u32 매개변수 두 개를 받아 u32를 반환하는 단일 함수가 있는 add 인터페이스를 정의합니다
  • add 인터페이스를 익스포트하는 adder 월드를 생성합니다

3. MoonBit 프로젝트 구조 생성하기

wit-bindgen을 사용하여 MoonBit 프로젝트 구조와 바인딩을 생성하십시오:

wit-bindgen moonbit wit/world.wit --out-dir . \
    --derive-eq \
    --derive-show \
    --derive-error

이 명령은 다음과 같은 디렉터리 구조를 생성합니다:

.
├── ffi
│   ├── moon.pkg.json
│   └── top.mbt
├── gen
│   ├── ffi.mbt
│   ├── gen_interface_docs_adder_add_export.mbt
│   ├── interface
│   │   └── docs
│   │       └── adder
│   │           └── add
│   │               ├── moon.pkg.json
│   │               ├── stub.mbt
│   │               └── top.mbt
│   ├── moon.pkg.json
│   ├── world
│   │   └── adder
│   │       ├── moon.pkg.json
│   │       └── stub.mbt
│   └── world_adder_export.mbt
├── moon.mod.json
├── wit
│   └── world.wit
└── world
    └── adder
        ├── ffi_import.mbt
        ├── import.mbt
        ├── moon.pkg.json
        └── top.mbt

생성된 파일은 다음과 같습니다:

  • moon.mod.json: MoonBit 모듈 구성
  • gen/: 생성된 익스포트 바인딩
    • interface/: 생성된 익스포트 인터페이스 바인딩
    • world/: 생성된 익스포트 월드 바인딩
    • stub.mbt: 주요 구현 파일
  • interface/: 생성된 임포트 인터페이스 바인딩
  • world/: 생성된 임포트 월드 바인딩

wit-bindgen 도구는 WebAssembly 컴포넌트 인터페이스를 처리하는 MoonBit 바인딩을 생성합니다.

moon check를 실행하면 gen/interface/docs/adder/add/stub.mbt 파일에 미완성 코드가 있다는 경고가 표시되며, 이 코드가 우리가 완성해야 할 부분입니다.

4. 컴포넌트 로직 구현하기

gen/interface/docs/adder/add/stub.mbt에 add 함수를 구현하십시오:

#![allow(unused)]
fn main() {
// Generated by `wit-bindgen` 0.45.0.

///|
pub fn add(x : UInt, y : UInt) -> UInt {
  x + y
}
}

5. 빌드 구성하기

gen/moon.pkg.json이 WebAssembly 대상에 맞게 올바르게 구성되어 있는지 확인하십시오:

{
    // link configuration for Wasm backend
    "link": {
        "wasm": {
            "exports": [
                // Export for cabi_realloc
                "cabi_realloc:cabi_realloc",
                // Export per the interface definition
                "wasmExportAdd:docs:adder/add@0.1.0#add"
            ],
            "export-memory-name": "memory",
            "heap-start-address": 16
        }
    },
    "import": [
        {
            "path": "docs/adder/ffi",
            "alias": "ffi"
        },
        {
            "path": "docs/adder/gen/interface/docs/adder/add",
            "alias": "add"
        }
    ]
}

5. WebAssembly 컴포넌트 빌드하기

MoonBit 코드를 WebAssembly 코어 모듈로 빌드하십시오:

moon build

생성한 모듈로부터 올바른 WebAssembly 컴포넌트를 만들려면 wasm-tools를 사용하십시오:

wasm-tools component embed wit target/wasm/release/build/gen/gen.wasm \
    --encoding utf16 \
    --output adder.wasm
wasm-tools component new adder.wasm --output adder.component.wasm

wasm-tools를 사용하여 컴포넌트의 인터페이스를 확인할 수 있습니다:

wasm-tools component wit adder.component.wasm

출력되는 WIT는 다음과 완전히 같지는 않더라도 비슷해야 합니다:

package root:component;

world root {
  export docs:adder/add@0.1.0;
}
package docs:adder@0.1.0 {
  interface add {
    add: func(x: u32, y: u32) -> u32;
  }
}

6. 컴포넌트 테스트하기

예제 호스트 사용하기

컴포넌트를 테스트하려면 이 저장소에서 제공하는 example-host를 사용하십시오:

git clone https://github.com/bytecodealliance/component-docs.git
cd component-docs/component-model/examples/example-host
cp /path/to/adder.component.wasm .
cargo run --release -- 5 3 adder.component.wasm

예상 출력:

5 + 3 = 8

Wasmtime 사용하기

wasmtime으로 컴포넌트를 직접 테스트할 수도 있습니다:

$ wasmtime run --invoke 'add(10, 20)' adder.component.wasm
30

고급

–derive-eq –derive-show

이 두 옵션은 생성된 모든 타입에 derive(Eq) 및/또는 derive(Show)를 추가합니다.

–derive-error

이 옵션은 이름에 ’Error’가 포함된 variant / 열거형을 하위 오류(suberror)로 생성합니다. 이를 통해 MoonBit의 오류 처리와 더 쉽게 통합할 수 있습니다.

예를 들어, 다음 인터페이스의 경우:

package docs:adder@0.1.0;

interface add {
    variant computation-error {
        overflow
    }
    add: func(x: u32, y: u32) -> result<u32, computation-error>;
}

world adder {
    import add;
}

다음 타입과 함수가 생성됩니다

#![allow(unused)]
fn main() {
// Generated by `wit-bindgen` 0.45.0. DO NOT EDIT!

///|
pub(all) suberror ComputationError {
  Overflow
} derive(Show, Eq)

///|
pub fn add(x : UInt, y : UInt) -> Result[UInt, ComputationError] {
  let return_area = @ffi.malloc(8)
  wasmImportAdd(x.reinterpret_as_int(), y.reinterpret_as_int(), return_area)
  let lifted4 = match @ffi.load8_u(return_area + 0) {
    0 => Result::Ok(@ffi.load32(return_area + 4).reinterpret_as_uint())
    1 => {
      let lifted = match @ffi.load8_u(return_area + 4) {
        0 => ComputationError::Overflow
        _ => panic()
      }
      Result::Err(lifted)
    }
    _ => panic()
  }
  @ffi.free(return_area)
  return lifted4
}
}

이는 다음과 같이 사용할 수 있습니다:

#![allow(unused)]
fn main() {
// Generated by `wit-bindgen` 0.45.0.

///|
fn init {
  let _ = @add.add(1, 2).unwrap_or_error() catch { Overflow => ... }

}
}

–ignore-stub

이는 인터페이스가 업데이트되어 프로젝트를 다시 생성하려고 하지만 stub 파일은 변경되지 않기를 원하는 경우에 해당합니다. 이러한 수정을 방지하려면 --ignore-stub 옵션을 사용할 수 있습니다.

–project-name

기본적으로 프로젝트 이름은 MoonBit 파일에 정의된 이름에 따라 생성됩니다. 이 옵션을 사용하여 프로젝트 이름을 지정할 수 있습니다. 더 큰 프로젝트의 일부로 프로젝트를 생성하는 경우에도 이 옵션을 사용할 수 있습니다.

–gen-dir

기본적으로 내보내기 부분은 gen 아래에 생성됩니다. 이 옵션을 사용하여 다른 디렉터리를 지정할 수 있습니다.

참고 자료 및 추가 읽을거리


원문 © 2023 The Bytecode Alliance Contributors · WebAssembly Components Documentation · CC BY 4.0
Yeokja 한국어 번역·편집 · Anthropic 사의 claude-sonnet-5 모델을 활용하여 번역되었으며 학습을 모두 비허용한 상태로 작업하였습니다 · 이 번역은 원문을 수정한 문서이며 CC BY 4.0으로 제공합니다.