مقدمة في WebAssembly وC++
\n\nيبحث تطوير الويب الحديث باستمرار عن طرق لتحسين الأداء. WebAssembly (Wasm) هو تنسيق تعليمات ثنائي منخفض المستوى يتم تنفيذه في المتصفح بسرعة تقترب من السرعة الأصلية. بالاقتران مع C++، واحدة من أسرع لغات البرمجة وأكثرها قوة، يفتح Wasm آفاقًا جديدة: من الألعاب عالية الأداء والمحاكاة إلى خوارزميات معالجة البيانات المعقدة مباشرة في المتصفح.
\n\nفي هذه المقالة، سننتقل من الأساسيات إلى التطبيق العملي: سنشرح كيفية ترجمة كود C++ إلى WebAssembly، وتشغيله في المتصفح، وتحسينه لتحقيق أقصى أداء.
\n\n1. الأدوات وإعداد البيئة
\n\nالأداة الرئيسية لترجمة C++ إلى WebAssembly هي مجموعة المترجمات Emscripten. يقوم بتحويل LLVM bytecode إلى Wasm ويقوم تلقائيًا بإنشاء كود JavaScript اللازم (glue code) لتحميل الوحدة.
\n\nتثبيت Emscripten
\nالطريقة الموصى بها للتثبيت هي من خلال مدير الحزم emsdk:
# استنساخ المستودع\ngit clone https://github.com/emscripten-core/emsdk.git\ncd emsdk\n\n# تثبيت وتفعيل أحدث إصدار\n./emsdk install latest\n./emsdk activate latest\n\n# إضافة متغيرات البيئة (متغيرات الصدفة)\nsource ./emsdk_env.sh\n\nبعد التثبيت، سيكون لديك الأوامر emcc (مترجم) و em++ (مترجم C++)، وهما غلافان حول Clang.
2. ترجمة C++ إلى WebAssembly
\n\nلنأخذ مثالًا بسيطًا. لننشئ ملفًا باسم hello.cpp:
#include <emscripten/emscripten.h>\n\n// دالة متاحة من JavaScript\nextern "C" {\n int EMSCRIPTEN_KEEPALIVE add(int a, int b) {\n return a + b;\n }\n}\n\nالعنصر المهم هو الماكرو EMSCRIPTEN_KEEPALIVE. يمنع إزالة الدالة بواسطة المحسن ويجعلها قابلة للتصدير.
لنقم بترجمة الكود الخاص بنا:
\n\nem++ hello.cpp -o hello.html -s WASM=1 -s EXPORTED_FUNCTIONS='["_add"]' -O3\n\nدعنا نشرح العلامات:
\n- \n
-o hello.html— ينشئ ملف HTML مع مثال للتشغيل. \n -s WASM=1— يحدد بوضوح توليد Wasm (مفعل افتراضيًا). \n -s EXPORTED_FUNCTIONS='["_add"]'— قائمة الدوال المصدرة (مع البادئة_). \n -O3— مستوى عالٍ من التحسين. \n
النتيجة هي ثلاثة ملفات: hello.html و hello.js (glue code) و hello.wasm.
3. التفاعل مع JavaScript
\n\nبعد الترجمة، يمكننا استدعاء دالة C++ الخاصة بنا من JavaScript. إليك كود تحميل الوحدة الأدنى:
\n\n<!DOCTYPE html>\n<html>\n<head>\n <script>\n var Module = {};\n Module.onRuntimeInitialized = function() {\n // الدالة add متاحة الآن\n var result = Module._add(5, 7);\n console.log("النتيجة: " + result); // 12\n };\n </script>\n <script src="hello.js"></script>\n</head>\n<body></body>\n</html>\n\nالنقاط الرئيسية:
\n- \n
Module.onRuntimeInitialized— حدث يتم استدعاؤه بعد تحميل وحدة Wasm. \n - أسماء الدوال في JavaScript تحصل على البادئة
_(مثل_add). \n - لنقل هياكل البيانات المعقدة (سلاسل، مصفوفات) يتم استخدام
Module._mallocوالمؤشرات. \n
تمرير السلاسل النصية
\nمثال لدالة ترجع تحية:
\n\n// كود C++\nextern "C" {\n const char* EMSCRIPTEN_KEEPALIVE greet(const char* name) {\n static std::string msg = "مرحبًا، " + std::string(name) + "!";\n return msg.c_str();\n }\n}\n\nفي JavaS