>백엔드 개발 >파이썬 튜토리얼 >웹어셈블리용 빌드

웹어셈블리용 빌드

Mary-Kate Olsen
Mary-Kate Olsen원래의
2024-12-02 01:26:09319검색

Building for WebAssembly

저는 현재 Rust의 Python 인터프리터인 Memphis에 대한 두 가지 흥미로운 주제, 즉 WebAssembly용 빌드와 CPython 내장을 탐구하고 있습니다. 이번 주에 보고할 주요 일정이 없기 때문에 진행 중인 생각을 몇 가지 공유해야겠다고 생각했습니다. 저에게 Memphis는 실용적인 실험을 통해 개념적 이해를 확장하기 위한 프로젝트였습니다. 바라건대 이 게시물이 제가 탐구하고 있는 몇 가지 디자인 결정을 안내하면서 여러분에게도 같은 역할을 할 수 있기를 바랍니다.

브라우저의 Python

Memphis를 WebAssembly 대상으로 컴파일하는 것은 한동안 마음속에 품고 있었는데, 두 주 전 토요일에 마침내 시도해 보았습니다. 미지근한 드립커피를 코스터에 담은 채 관절을 깨물고 시작했습니다.

WebAssembly는 기존 JavaScript 환경을 보완하는 최신 웹 브라우저 내의 샌드박스 실행 환경입니다. Wasm 환경은 네이티브 코드에 더 가깝고 보다 성능이 뛰어난 CPU 컨텍스트를 활용하는 작업에 사용될 수 있습니다. 숫자 계산이나 어리석은 바쁜 루프를 생각해보세요. 나는 성능적인 측면보다는 그것이 가능하다는 점에서 더 관심을 가졌다. Rust의 판매 포인트 중 하나는 말 그대로 수백만 달러 중 Wasm을 표적으로 삼을 수 있다는 것입니다. 어떻게 물어볼 수 있습니까? 이는 Rust가 LLVM을 컴파일러 백엔드로 사용하기 때문에 가능합니다. Rust 컴파일러 프런트엔드는 LLVM IR(Intermediate Representation) 코드를 생성하고 LLVM은 이를 수십 개의 타겟에 대한 네이티브 코드로 컴파일할 수 있습니다.

그것은 꽤 엄청난 혜택이고 Just Work for Memphis인지 궁금했습니다. 이전에는 브라우저에서 Python을 실행하는 것에 대해 말 그대로 전혀 생각해본 적이 없었기 때문에 이번이 Wasm 학습 곡선을 테스트할 수 있는 완벽한 기회처럼 보였습니다.

wasm-pack 설정 및 WebAssembly용 빌드

AI 어시스턴트를 실행하고 발사 순서를 물었습니다. 삐삐삐삐 소리가 났습니다. 다음은 제가 학습한 내용을 주석으로 표시한 단계입니다.

# wasm-pack helps compile our Rust code to WebAssembly and bundle it
# with JavaScript bindings we can call from our HTML/JavaScript page.
cargo install wasm-pack

# wasm-pack also downloads the wasm32-unknown-unknown target via
# rustup for us. If for whatever reason it does not, you can use this: 
# rustup target add wasm32-unknown-unknown
# We must specify a feature flag because our wasm_bindgen interface is
# behind the wasm feature flag.
wasm-pack build --target web --out-dir wasm_ui/pkg -- --features wasm

첫 시도만에 빌드 성공! 그러나 Rust 바이너리의 어떤 함수도 WebAssembly에서 호출할 수 있도록 표시하지 않았기 때문에 별 효과가 없습니다.

이를 위해 wasm-bindgen 상자를 설치할 수 있으며, 이를 기능 플래그 뒤에 두었습니다. 이것을 Cargo.toml에 추가했습니다.

[dependencies]
wasm-bindgen = { version = "0.2", optional = true }

[features]
wasm = ["wasm-bindgen"]

다음은 src/lib.rs 파일의 wasm 기능 플래그 뒤에 추가한 작은 코드입니다. Greeting 기능은 #[wasm_bindgen]으로 장식되어 이 기호를 JavaScript에서 사용할 수 있습니다.

# wasm-pack helps compile our Rust code to WebAssembly and bundle it
# with JavaScript bindings we can call from our HTML/JavaScript page.
cargo install wasm-pack

# wasm-pack also downloads the wasm32-unknown-unknown target via
# rustup for us. If for whatever reason it does not, you can use this: 
# rustup target add wasm32-unknown-unknown
# We must specify a feature flag because our wasm_bindgen interface is
# behind the wasm feature flag.
wasm-pack build --target web --out-dir wasm_ui/pkg -- --features wasm

JavaScript 인터페이스 생성

또한 AI 비서에게 Wasm 인터페이스를 테스트하는 데 사용할 수 있는 가장 작은 JavaScript 조각을 요청했습니다. init()를 호출하면 브라우저는 .wasm 파일을 로드하고 JIT 컴파일 단계를 수행하여 이식 가능한 WebAssembly 바이너리를 네이티브 코드로 변환하고 WebAssembly 런타임을 위한 메모리를 초기화합니다.

[dependencies]
wasm-bindgen = { version = "0.2", optional = true }

[features]
wasm = ["wasm-bindgen"]

기적 중의 기적처럼 Just Work. 물론 저는 브라우저에서 Python 코드를 실행하지 않았지만 바이너리와의 인터페이스는 Java를 거의 설치할 수 없는 젊은 제가 과소평가하고 싶지 않은 큰 단계였습니다.

다음 단계는 JavaScript에 정의된 Python 표현식을 제공하고 Wasm 바이너리가 숫자를 처리하도록 하는 것이었습니다. REPL 게시물에서 언급했듯이 소프트웨어 프로젝트의 모든 진입점은 추상화를 개선할 수 있는 기회이며, 여기서도 확실히 그럴 것입니다. Memphis 저장소를 살펴보면서 저는 와, 문자열을 전달하고 Python으로 평가할 수 있는 더 나은 인터페이스가 있어야 한다는 것을 깨달았습니다. 제가 말했듯이 저는 새로운 진입점을 좋아합니다.

당분간은 크로스체크 어댑터를 사용하겠습니다. Crosscheck는 트리워크 인터프리터와 바이트코드 VM이 주어진 Python 입력에 대해 동일한 동작을 생성하는지 검증하기 위해 진행 중인 테스트 프레임워크입니다. 승무원이 하는 일을 따서 명명한 것입니다.

업데이트된 Rust 코드는 다음과 같습니다.

#[cfg(feature = "wasm")]
mod wasm {
    use wasm_bindgen::prelude::wasm_bindgen;

    // Export a function to JavaScript
    #[wasm_bindgen]
    pub fn greet() -> String {
        "Hello from WebAssembly!".to_string()
    }
}

다음은 새로운 Rust 평가 함수를 호출하는 업데이트된 JavaScript 코드입니다.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Wasm Test</title>
</head>
<body>
    <script type="module">
        import init, { greet } from './pkg/memphis.js';

        async function run() {
            await init();
            console.log(greet());
        }

        run();
    </script>
</body>
</html>

웹어셈블리 오류 디버깅

이제 실행해보니………콘솔 오류가 발생했습니다. 구현되지 않은 오류로 인해 충돌이 발생했습니다.

좀 둘러봤는데 원인이 무엇인지 명확하지 않았습니다. 원본 Rust 함수에 대한 참조가 없는 단지 어셈블리 블록인 Wasm 빌드의 경우 소스를 클릭할 수 있습니다.

AI 채팅/구글링을 하다가 두 가지 유용한 접근 방식을 찾았습니다. 하나는 브라우저 콘솔에 Rust 코드의 로그 문을 표시하는 Wasm 빌드에 사용되는 console_log입니다. 이것은 일부 도움이 되었지만 제가 실제로 찾고 있던 것은 스택 추적이었습니다. console_error_panic_hook를 입력합니다. 그것은 나에게 즉시 CLUTCH인 Rust 스택 추적을 제공했습니다. 당신이 자신만의 Wasm 빌드를 하고 있다면, 지금 이 글을 읽는 것을 멈추고 이 상자를 추가하세요. 이 게시물을 끝까지 읽지 않으셔도 상관 없습니다. 페리스는 당신이 이 상자를 사용하길 원할까요?. Wasm 인터페이스에 추가한 방법은 다음과 같습니다.

#[cfg(feature = "wasm")]
mod wasm {
    use wasm_bindgen::prelude::wasm_bindgen;

    use crosscheck::{InterpreterTest, TreewalkAdapter};

    // Export a function to JavaScript
    #[wasm_bindgen]
    pub fn greet() -> String {
        "Hello from WebAssembly!".to_string()
    }

    #[wasm_bindgen]
    pub fn evaluate(code: String) -> String {
        let result = TreewalkAdapter.execute(&code);
        format!("{}", result)
    }
}

내 스택 추적이 내 범인을 지적했습니다. 나는 std::env를 사용하여 Wasm 런타임에서 허용되지 않는 일부 OS 리소스를 요청하고 있었습니다(샌드박스 부분). 나는 이러한 호출을 기능 플래그 뒤에 두고(호스트 시스템에서 Python 표준 lib의 위치를 ​​해킹으로 결정하는 방법과 관련이 있음) 빌드를 다시 시작했습니다. 내 반환 유형을 올바르게 표시하는 것과 관련된 몇 가지 작은 실패 이후….

효과가 있었습니다. 현재 브라우저 콘솔에 표시되는 내용은 다음과 같습니다.

# wasm-pack helps compile our Rust code to WebAssembly and bundle it
# with JavaScript bindings we can call from our HTML/JavaScript page.
cargo install wasm-pack

# wasm-pack also downloads the wasm32-unknown-unknown target via
# rustup for us. If for whatever reason it does not, you can use this: 
# rustup target add wasm32-unknown-unknown
# We must specify a feature flag because our wasm_bindgen interface is
# behind the wasm feature flag.
wasm-pack build --target web --out-dir wasm_ui/pkg -- --features wasm

tldr 브라우저에서 Python을 실행할 수 있습니다. (그들의 공로로 RustPython은 이 작업도 수행합니다: https://rustpython.github.io/demo/. 나는 그들의 프로젝트를 깊이 살펴보지 않았지만 포괄적인 것 같습니다.) Python 목록 이해력은 JavaScript에서 문자열 형식으로 정의되며 응답 목록은 Wasm으로 컴파일된 Rust 코드에 의해 평가되고 JavaScript로 표시될 수 있는 문자열로 다시 변환됩니다.

이 설정은 현재 표현식만 지원합니다. 명령문을 평가하고 나중에 결과를 다시 읽으려면 Rust 측에서 상태를 유지해야 합니다. 나는 또한 JavaScript REPL을 구축하는 꿈을 꿉니다. 그건 미래의 나(그리고 지루한 꿈)에게 문제인 것 같네요.

말이 너무 길어서 임베디드 파이썬에 대한 논의는 다음 주 월요일까지 미루겠습니다.

미끼와 전환에 대해 사과드립니다. 콘텐츠 달력은 누구도 기다려주지 않습니다.

분명히 말하자면 임베디드 Python이란 "임베디드 시스템" 환경에서 Python을 실행하는 것이 아니라 Memphis 내부에 CPython 인터프리터를 내장하는 것을 의미합니다. 이유 없이 힘든 일이겠죠. FUN이 힘든 멤피스와는 다르게.


이런 게시물을 받은편지함으로 직접 받아보려면 여기에서 구독하세요!

다른 곳

저는 소프트웨어 엔지니어를 멘토링하는 것 외에도 성인 자폐증 진단을 받은 경험에 대해서도 글을 씁니다. 코드는 적고 농담 수는 동일합니다.

  • 나는 왜 인정을 갈망하는가? - Scratch dot org
  • 에서

위 내용은 웹어셈블리용 빌드의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.