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 아래에 생성됩니다. 이 옵션을 사용하여 다른 디렉터리를 지정할 수 있습니다.