Elixir 프로젝트를 진행하고 있었는데 사용하고 싶었던 특정 오픈 소스 패키지가 Go로 작성,
Elixir의 Go 코드와 인터페이스하는 다양한 방법을 검색했습니다. NIF를 사용하여 Elixir의 Rust 코드를 인터페이스하는 것이 매우 간단하다는 것을 알고 있지만 내가 발견한 Go와 유사한 것은 없습니다.
대부분은 포트를 사용하도록 이끌었고 WASI(WebAssembly System Interface)도 옵션이라는 것을 깨닫기 전에 거의 포기하려고 했습니다. 나는 잠시 동안 Web Assembly에 대해 들었고 이것은 그것을 시도하기에 좋은 순간이었습니다. 나는 또한 Elixir에서 WASI 바이너리를 실행하는 좋은 옵션처럼 보이는 Wasmex를 발견했습니다. Philipp Tessenow(wasmex의 창시자)는 이 모든 것을 작동시키는 데 중요한 역할을 했으며 최종 작업 솔루션으로 안내해 주었으므로 감사합니다.
내가 알아 내야 할 몇 가지 사항이있었습니다.
- Go 코드를 WASI로 컴파일하는 방법
- Elixir 호스트에서 WASI 바이너리를 실행하는 방법
- WASI 바이너리에 데이터를 전달하는 방법
- WASI 바이너리에서 데이터를 가져오는 방법
하나씩 살펴 보겠습니다.
1. Go 코드를 WASI로 컴파일하는 방법
이것은 쉬웠습니다. 일부 빠른 Google-fu는 WASI를 출력 대상으로 지원하므로 사용해야한다고 알려주었습니다. 메인 Go 컴파일러는 WASM 지원도 추가했지만 내가 아는 한 현재 WASI 대상으로 컴파일되지 않습니다.tinygo
이것은이 전체 설정을 테스트하는 데 사용한 샘플 Go 코드입니다.
package main
import "fmt"
func main() {}
//export greet
func greet() {
fmt.Println("Hello world")
}
그리고 다음 명령을 사용하여 코드를 WASI로 컴파일했습니다.
$ tinygo build -o main.wasm -scheduler=none --no-debug -target wasi main.go
Tinygo는 주석을 사용하여 WASI 호스트로 내보내야 하는 함수에 대해 컴파일러를 안내합니다. 그러한 주석 중 하나가 위의 코드에 있습니다. 그러면 함수가 내보내지고 WASI 호스트(Elixir/Wasmex)에서 호출할 수 있습니다. tinygo에 WASI 호스트에서 함수를 가져오도록 지시하기 위해 추가할 수 있는 몇 가지 주석도 있지만 여기서는 사용하지 않을 것입니다. 또한 코드가 작동하려면 빈 함수를 추가해야 합니다.// export greetgreetmain
위에서 공유한 명령에서 플래그를 가지고 놀 수 있습니다. 이 플래그 조합을 발견하여 가장 작은 WASI / WASM 바이너리를 생성했습니다.tinygobuild
2. Elixir 호스트에서 WASI 바이너리를 실행하는 방법
이것은 또한 알아 내기가 매우 쉬웠습니다. 일단 mix dependency로 설치되면, 다음과 같이 WASI 바이너리를 실행할 수 있습니다:wasmex
binary = File.read!("./native/main.wasm")
{:ok, pid} = Wasmex.start_link(%{bytes: binary, wasi: true})
Wasmex.call_function(pid, "greet", [])
3. WASI 바이너리에 데이터를 전달하는 방법
이제 WASI 바이너리에 데이터를 전달하는 방법을 알아 내야했습니다. 이 문제에 대해 몇 가지 방법이 있기 때문에 이것은 약간 까다 롭습니다. 가장 유명한 두 가지는 공유 WASI 메모리를 통해 데이터를 전달하거나 데이터를 복사하는 것입니다. 함수를 매개 변수화하고 다음과 같이 직접 인수를 사용할 수도 있습니다.stdin
func add(a, b int32) int32 {
return a + b
}
그러나 이것은 문자열에서는 작동하지 않습니다. WASI 사양은 현재 문자열 입력을 지원하지 않습니다. 일부 문자열을 입력으로 전달하고 싶었 기 때문에 이와 같이 함수를 단순히 매개 변수화 할 수 없었습니다.
WASI 메모리를 사용하고 여러 가지 자습서를 사용하여 해당 방법을 통해 입력을 전달하려고 시도했지만 아무데도 얻을 수 없었습니다. 나는 모든 종류의 오류를 얻고 있었고 웹 어셈블리의 세계에 익숙하지 않았기 때문에 저항이 가장 적은 경로를 선택하기로 결정하고 파이프를 사용하게되었습니다.
파이프를 사용하여 이진 입력을 Go에 전달하는 방법은 다음과 같습니다.
binary = File.read!("./native/main.wasm")
{:ok, stdin_pipe} = Wasmex.Pipe.new()
wasi = %Wasmex.Wasi.WasiOptions{args: [], stdin: stdin_pipe}
{:ok, pid} = Wasmex.start_link(%{bytes: binary, wasi: wasi})
Wasmex.Pipe.write(stdin_pipe, "Hello world!")
Wasmex.Pipe.seek(stdin_pipe, 0)
{:ok, []} = Wasmex.call_function(pid, :greet, [])
이 코드는 다음과 같이 함수의 Go 측에서 읽을 수 있는 파이프에 넣습니다."Hello world"stdingreet
func greet() {
// Here data will contain "Hello world"
data, _ := io.ReadAll(os.Stdin)
}
4. WASI 바이너리에서 데이터를 가져오는 방법
파이프를 사용하는 방법과 유사하게 파이프를 사용할 수 있습니다. 먼저 인사말을 출력하도록 Go 코드를 수정해 보겠습니다.stdinstdoutstdout
import "fmt"
func greet() {
data, _ := io.ReadAll(os.Stdin)
fmt.Println("👋 Data from Elixir:", string(data))
}
이제 파이프를 사용해 보겠습니다.stdout
binary = File.read!("./native/main.wasm")
{:ok, stdout_pipe} = Wasmex.Pipe.new()
{:ok, stdin_pipe} = Wasmex.Pipe.new()
wasi = %Wasmex.Wasi.WasiOptions{args: [], stdout: stdout_pipe, stdin: stdin_pipe}
{:ok, pid} = Wasmex.start_link(%{bytes: binary, wasi: wasi})
# Put data in stdin pipe
Wasmex.Pipe.write(stdin_pipe, "Yasoob here!")
Wasmex.Pipe.seek(stdin_pipe, 0)
# Call the greet function
{:ok, []} = Wasmex.call_function(pid, :greet, [])
# Read data from stdout
Wasmex.Pipe.seek(stdout_pipe, 0)
IO.puts(Wasmex.Pipe.read(stdout_pipe))
화면에 인쇄되어야 합니다.👋 Data from Elixir: Yasoob here!
결론
Web Assembly에 대해 배우면서 WASI를 사용하여 Elixir에서 Go 코드를 호출하는 것이 그리 어렵지 않다는 것을 알게 되어 즐거웠습니다. Go 코드의 복잡성이 증가함에 따라이 접근 방식에 대한 몇 가지주의 사항이 있어야한다고 확신하지만 대부분의 기본 사용 사례에서는 완벽한 솔루션입니다. 이 솔루션의 메모리 사용량을 벤치마킹하지는 않았지만 현 단계에서는 내 프로젝트에 대한 우려가 없습니다. 푸시가 발생하면 항상 포트 기반 솔루션으로 진행할 수 있습니다.
이 작은 노력으로 Elixir에 관련 라이브러리나 패키지가 없더라도 Go를 참고할 수 있고 Elixir에서 Go를 인터페이스할 수 있다는 것을 깨달았습니다. Rust는 항상 Rustler를 통한 옵션이었지만 이제 Go는 Rust에 무언가가 존재하지 않는 경우에도 실행 가능한 옵션입니다
'개발 언어 > Etc.' 카테고리의 다른 글
CodePen 사용법: 프론트엔드 개발의 시작 (2) | 2025.06.03 |
---|---|
데이터 분석을 위한 새로운 기술: Pandas와 SQL을 사용하여 복잡한 데이터를 쉽게 처리 (4) | 2025.05.25 |
[초보 가이드] 옵시디안 플러그인, 'Hello World'부터 시작하기 (3) | 2025.05.19 |
Figma의 가장 큰 업데이트 - Figma Config 2025 (5) | 2025.05.13 |
딸기처럼 달콤한 AI 브라우저의 등장, 시간을 절약하고 당신의 생각을 확장하세요! (2) | 2025.05.11 |