Ich untersuche derzeit zwei interessante Themen für Memphis, meinen Python-Interpreter in Rust: Erstellen für WebAssembly und Einbetten von CPython. Da es diese Woche keine wichtigen Meilensteine zu vermelden gibt, dachte ich, ich würde einige laufende Gedanken mitteilen. Für mich war Memphis ein Projekt zur Erweiterung meines konzeptionellen Verständnisses durch praktische Experimente – hoffentlich kann dieser Beitrag das Gleiche für Sie bewirken, während wir einige der Designentscheidungen durchgehen, die ich untersuche.
Das Kompilieren von Memphis zu einem WebAssembly-Ziel hatte ich schon seit einiger Zeit im Hinterkopf, und vor zwei Samstagen habe ich es endlich versucht. Mit einer lauwarmen Tasse Filterkaffee auf meinem Untersetzer ließ ich meine Fingerknöchel knacken und begann.
WebAssembly ist eine Sandbox-Ausführungsumgebung in modernen Webbrowsern, die die traditionelle JavaScript-Umgebung ergänzt. Die Wasm-Umgebung ist näher am nativen Code und kann für Aufgaben verwendet werden, die von einem leistungsfähigeren CPU-Kontext profitieren. Denken Sie an Zahlenverarbeitung oder alberne Besetztschleifen. Mich interessierte es weniger aus Performance-Perspektive als vielmehr, weil es überhaupt möglich war. Eines der Verkaufsargumente von Rust (im wahrsten Sinne des Wortes Bajillions) ist, dass es Wasm ins Visier nehmen kann. Wie geht das, könnte man fragen? Dies ist möglich, weil Rust LLVM als Compiler-Backend verwendet. Das Rust-Compiler-Frontend erzeugt LLVM Intermediate Representation (IR)-Code und LLVM kann diesen zu nativem Code für Dutzende von Zielen kompilieren.
Das ist ein ziemlich großer Vorteil und ich war neugierig, ob es nur für Memphis funktionieren würde. Ich hatte zuvor praktisch überhaupt nicht darüber nachgedacht, Python im Browser auszuführen, daher schien dies eine perfekte Gelegenheit zu sein, die Wasm-Lernkurve auszuprobieren.
Ich habe meinen KI-Assistenten gestartet und nach der Startsequenz gefragt. Es machte einen Piep-Boop-Piep-Boop. Unten sind die Schritte aufgeführt, die ich mit meinen Erkenntnissen auf dem Weg kommentiert habe.
# 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
Der Aufbau ist mir beim ersten Versuch gelungen! Da wir jedoch in unserer Rust-Binärdatei keine Funktionen als für den Aufruf von WebAssembly verfügbar markiert haben, bewirkt dies nicht viel.
Dazu können wir die wasm-bindgen-Kiste installieren, die ich hinter ein Feature-Flag gestellt habe. Ich habe dies zu meinem Cargo.toml hinzugefügt.
[dependencies] wasm-bindgen = { version = "0.2", optional = true } [features] wasm = ["wasm-bindgen"]
Hier ist ein kleiner Code, den ich meiner Datei src/lib.rs hinter dem Feature-Flag wasm hinzugefügt habe. Die Begrüßungsfunktion ist mit #[wasm_bindgen] versehen, um dieses Symbol in JavaScript verfügbar zu machen.
# 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
Ich habe auch meinen KI-Assistenten um das kleinstmögliche Stück JavaScript gebeten, das ich zum Testen meiner Wasm-Schnittstelle verwenden könnte. Wenn wir init() aufrufen, lädt der Browser die .wasm-Datei, führt einen JIT-Kompilierungsschritt durch, um die portable WebAssembly-Binärdatei in nativen Code zu konvertieren, und initialisiert den Speicher für die WebAssembly-Laufzeitumgebung.
[dependencies] wasm-bindgen = { version = "0.2", optional = true } [features] wasm = ["wasm-bindgen"]
Wie ein Wunder unter Wundern hat es einfach funktioniert. Zugegeben, ich habe keinen Python-Code im Browser ausgeführt, aber die Schnittstelle zu meiner Binärdatei war ein RIESIGER Schritt, den mein jüngeres Ich, das Java kaum installieren konnte, nicht unterschätzen wollte.
Der nächste Schritt bestand darin, ihm einen in JavaScript definierten Python-Ausdruck zu geben und die Wasm-Binärdatei die Zahlen verarbeiten zu lassen. Wie ich in meinem REPL-Beitrag erwähnt habe, ist jeder Einstiegspunkt in ein Softwareprojekt eine Gelegenheit, meine Abstraktionen zu verbessern, und das wäre auch hier sicherlich wieder der Fall. Als ich mein Memphis-Repo durchblätterte, wurde mir klar: Wow, ich sollte wirklich eine bessere Schnittstelle haben, um einen String zu übergeben und ihn als Python auszuwerten. Wie ich schon sagte, ich LIEBE neue Einstiegspunkte.
Vorerst würde ich meinen Crosscheck-Adapter verwenden. Crosscheck ist mein in Arbeit befindliches Testframework, um zu validieren, dass der Treewalk-Interpreter und die Bytecode-VM das gleiche Verhalten für eine bestimmte Python-Eingabe erzeugen. Es ist nach der Tätigkeit von Flugbegleitern benannt.
Hier ist mein aktualisierter Rust-Code.
#[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() } }
Hier ist mein aktualisierter JavaScript-Code, der die neue Rust-Evaluierungsfunktion aufruft.
<!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>
Als ich es nun ausführte, bekam ich……… einen Konsolenfehler. Es stürzte mit einem nicht implementierten Fehler ab.
Ich habe ein wenig herumgestöbert und es war nicht klar, was die Ursache dafür war. Sie können in die Quelle klicken, aber für einen Wasm-Build, der nur ein Assemblyblock ohne Verweise auf die ursprünglichen Rust-Funktionen ist.
Ich habe ein bisschen über KI gechattet/gegoogelt und zwei hilfreiche Ansätze gefunden. Eine davon ist console_log zur Verwendung in Wasm-Builds, das Protokollanweisungen aus Ihrem Rust-Code in Ihrer Browserkonsole anzeigt. Das hat einigen geholfen, aber was ich wirklich suchte, war ein Stack-Trace. Geben Sie console_error_panic_hook ein. Es gab mir sofort den Rust-Stack-Trace, nämlich CLUTCH. Wenn Sie Ihren eigenen Wasm-Build erstellen, hören Sie jetzt auf, dies zu lesen, und fügen Sie diese Kiste hinzu. Es macht mir nicht einmal etwas aus, wenn Sie diesen Beitrag nie zu Ende lesen. Ferris möchte, dass du diese Kiste benutzt? So habe ich es zu meiner Wasm-Schnittstelle hinzugefügt.
#[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) } }
Mein Stack-Trace hat mich auf meinen Übeltäter hingewiesen: Ich habe std::env verwendet, um einige Betriebssystemressourcen anzufordern, die in einer Wasm-Laufzeitumgebung nicht zulässig sind (das ist der Sandbox-Teil). Ich habe diese Aufrufe hinter ein Feature-Flag gestellt (sie hängen damit zusammen, wie ich den Speicherort der Python-Standardbibliothek auf dem Host-Rechner mühsam ermittle) und habe meinen Build erneut gestartet. Nach ein paar kleinen Fehlern im Zusammenhang mit der korrekten Anzeige meiner Rückgabetypen ….
ES FUNKTIONIERTE. Folgendes sehe ich jetzt in meiner Browserkonsole.
# 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 Ich kann Python im Browser ausführen. (Zu ihrer Ehre muss man sagen, dass RustPython dies auch tut: https://rustpython.github.io/demo/. Ich habe mir ihr Projekt nicht näher angesehen, aber es scheint umfassend zu sein.) Das Python-Listenverständnis ist in JavaScript in Stringform definiert und Die Antwortliste wird durch den zu Wasm kompilierten Rust-Code ausgewertet und zurück in einen String umgewandelt, der von JavaScript angezeigt werden kann.
Dieses Setup unterstützt derzeit nur Ausdrücke. Um Anweisungen auszuwerten (und später ihre Ergebnisse zurückzulesen), muss ich den Status auf der Rust-Seite beibehalten. Ich träume auch davon, eine JavaScript-REPL zu erstellen. Das klingt nach einem Problem für mein zukünftiges Ich (und ehrlich gesagt nach einem langweiligen Traum).
Ich habe lange genug gesprochen, deshalb werde ich mich mit der Diskussion über eingebettetes Python bis nächsten Montag zurückhalten.
Entschuldigung für den Köder und den Wechsel. Der Inhaltskalender wartet auf niemanden.
Um es klar auszudrücken: Mit eingebettetem Python meine ich die Einbettung eines CPython-Interpreters in Memphis und nicht die Ausführung von Python in einer Umgebung mit „eingebetteten Systemen“. Das wäre ohne Grund schwierig. Im Gegensatz zu Memphis, wo es für SPASS schwierig ist.
Wenn Sie weitere Beiträge wie diesen direkt in Ihrem Posteingang erhalten möchten, können Sie sich hier anmelden!
Neben der Betreuung von Software-Ingenieuren schreibe ich auch über meine Erfahrungen als Erwachsener, bei dem Autismus diagnostiziert wurde. Weniger Code und die gleiche Anzahl an Witzen.
Das obige ist der detaillierte Inhalt vonErstellen für WebAssembly. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!