WebAssembly কি এবং কোথা থেকে এসেছে? , আমি ব্যাখ্যা করেছি কিভাবে আমরা আজকের WebAssembly এর সাথে শেষ করেছি। এই নিবন্ধে, আমি আপনাকে একটি বিদ্যমান সি প্রোগ্রাম, mkbitmap
, WebAssembly-তে কম্পাইল করার আমার পদ্ধতি দেখাব। এটি হ্যালো ওয়ার্ল্ড উদাহরণের চেয়ে জটিল, কারণ এতে ফাইলগুলির সাথে কাজ করা, ওয়েব অ্যাসেম্বলি এবং জাভাস্ক্রিপ্ট ল্যান্ডগুলির মধ্যে যোগাযোগ করা এবং একটি ক্যানভাসে আঁকার অন্তর্ভুক্ত, তবে এটি এখনও আপনাকে অভিভূত না করার জন্য যথেষ্ট পরিচালনাযোগ্য৷
নিবন্ধটি ওয়েব ডেভেলপারদের জন্য লেখা হয়েছে যারা WebAssembly শিখতে চান এবং ধাপে ধাপে দেখায় যে আপনি যদি mkbitmap
এর মত কিছু WebAssembly-তে কম্পাইল করতে চান তাহলে আপনি কীভাবে এগিয়ে যেতে পারেন। একটি ন্যায্য সতর্কতা হিসাবে, প্রথম রানে কম্পাইল করার জন্য একটি অ্যাপ বা লাইব্রেরি না পাওয়া সম্পূর্ণ স্বাভাবিক, এই কারণেই নীচে বর্ণিত কিছু পদক্ষেপ কাজ করছে না, তাই আমাকে ব্যাকট্র্যাক করতে হবে এবং অন্যভাবে আবার চেষ্টা করতে হবে। নিবন্ধটি ম্যাজিক চূড়ান্ত সংকলন আদেশটি এমনভাবে দেখায় না যেন এটি আকাশ থেকে নেমে গেছে, বরং আমার প্রকৃত অগ্রগতি বর্ণনা করে, কিছু হতাশা অন্তর্ভুক্ত।
mkbitmap
সম্পর্কে
mkbitmap
C প্রোগ্রাম একটি চিত্র পড়ে এবং এটিতে নিম্নলিখিত এক বা একাধিক ক্রিয়াকলাপ প্রয়োগ করে, এই ক্রমে: ইনভার্সন, হাইপাস ফিল্টারিং, স্কেলিং এবং থ্রেশহোল্ডিং। প্রতিটি অপারেশন পৃথকভাবে নিয়ন্ত্রিত এবং চালু বা বন্ধ করা যেতে পারে। mkbitmap
এর প্রধান ব্যবহার হল রঙ বা গ্রেস্কেল ছবিগুলিকে অন্য প্রোগ্রামের জন্য ইনপুট হিসাবে উপযুক্ত ফর্ম্যাটে রূপান্তর করা, বিশেষ করে ট্রেসিং প্রোগ্রাম potrace
যা SVGcode- এর ভিত্তি তৈরি করে। একটি প্রিপ্রসেসিং টুল হিসেবে, mkbitmap
বিশেষভাবে স্ক্যান করা লাইন আর্ট, যেমন কার্টুন বা হাতে লেখা পাঠ্যকে উচ্চ-রেজোলিউশনের দ্বি-লেভেল ইমেজে রূপান্তর করার জন্য উপযোগী।
আপনি mkbitmap
ব্যবহার করে এটিকে অনেকগুলি অপশন এবং এক বা একাধিক ফাইলের নাম পাস করে। সমস্ত বিবরণের জন্য, টুলের ম্যান পৃষ্ঠাটি দেখুন:
$ mkbitmap [options] [filename...]
কোড পান
প্রথম ধাপ হল mkbitmap
এর সোর্স কোড প্রাপ্ত করা। আপনি প্রকল্পের ওয়েবসাইটে এটি খুঁজে পেতে পারেন। এই লেখার সময়, potrace-1.16.tar.gz সর্বশেষ সংস্করণ।
স্থানীয়ভাবে কম্পাইল এবং ইনস্টল করুন
পরবর্তী ধাপ হল টুলটি স্থানীয়ভাবে কম্পাইল করা এবং ইনস্টল করা যাতে এটি কীভাবে আচরণ করে তার অনুভূতি পেতে। INSTALL
ফাইলটিতে নিম্নলিখিত নির্দেশাবলী রয়েছে:
প্যাকেজের সোর্স কোড ধারণকারী ডিরেক্টরিতে
cd
এবং আপনার সিস্টেমের জন্য প্যাকেজ কনফিগার করতে./configure
টাইপ করুন।configure
চালানোর জন্য কিছু সময় লাগতে পারে। চালানোর সময়, এটি কোন বৈশিষ্ট্যগুলি পরীক্ষা করছে তা বলে কিছু বার্তা প্রিন্ট করে৷প্যাকেজ কম্পাইল করতে
make
টাইপ করুন।ঐচ্ছিকভাবে, প্যাকেজের সাথে আসা যেকোনো স্ব-পরীক্ষা চালানোর জন্য
make check
টাইপ করুন, সাধারণত সদ্য নির্মিত আনইনস্টল করা বাইনারি ব্যবহার করে।প্রোগ্রাম এবং যেকোনো ডেটা ফাইল এবং ডকুমেন্টেশন ইনস্টল করতে
make install
টাইপ করুন। রুটের মালিকানাধীন একটি প্রিফিক্সে ইনস্টল করার সময়, প্যাকেজটিকে নিয়মিত ব্যবহারকারী হিসাবে কনফিগার এবং তৈরি করার পরামর্শ দেওয়া হয় এবং শুধুমাত্রmake install
ফেজটি রুট সুবিধা সহ কার্যকর করা হয়।
এই পদক্ষেপগুলি অনুসরণ করে, আপনার দুটি এক্সিকিউটেবল, potrace
এবং mkbitmap
এর সাথে শেষ হওয়া উচিত — পরেরটি এই নিবন্ধের ফোকাস। আপনি mkbitmap --version
চালিয়ে এটি সঠিকভাবে কাজ করেছে তা যাচাই করতে পারেন। এখানে আমার মেশিন থেকে চারটি ধাপের আউটপুট, সংক্ষিপ্ততার জন্য ভারীভাবে ছাঁটা:
ধাপ 1, ./configure
:
$ ./configure
checking for a BSD-compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
checking for a thread-safe mkdir -p... ./install-sh -c -d
checking for gawk... no
checking for mawk... no
checking for nawk... no
checking for awk... awk
checking whether make sets $(MAKE)... yes
[…]
config.status: executing libtool commands
ধাপ 2, make
:
$ make
/Applications/Xcode.app/Contents/Developer/usr/bin/make all-recursive
Making all in src
clang -DHAVE_CONFIG_H -I. -I.. -g -O2 -MT main.o -MD -MP -MF .deps/main.Tpo -c -o main.o main.c
mv -f .deps/main.Tpo .deps/main.Po
[…]
make[2]: Nothing to be done for `all-am'.
ধাপ 3, make check
:
$ make check
Making check in src
make[1]: Nothing to be done for `check'.
Making check in doc
make[1]: Nothing to be done for `check'.
[…]
============================================================================
Testsuite summary for potrace 1.16
============================================================================
# TOTAL: 8
# PASS: 8
# SKIP: 0
# XFAIL: 0
# FAIL: 0
# XPASS: 0
# ERROR: 0
============================================================================
make[1]: Nothing to be done for `check-am'.
ধাপ 4, sudo make install
:
$ sudo make install
Password:
Making install in src
.././install-sh -c -d '/usr/local/bin'
/bin/sh ../libtool --mode=install /usr/bin/install -c potrace mkbitmap '/usr/local/bin'
[…]
make[2]: Nothing to be done for `install-data-am'.
এটি কাজ করেছে কিনা তা পরীক্ষা করতে, mkbitmap --version
চালান:
$ mkbitmap --version
mkbitmap 1.16. Copyright (C) 2001-2019 Peter Selinger.
আপনি যদি সংস্করণের বিশদ বিবরণ পান, আপনি সফলভাবে mkbitmap
কম্পাইল এবং ইনস্টল করেছেন। এরপর, WebAssembly-এর সাথে এই ধাপগুলির সমতুল্য কাজ করুন।
WebAssembly এ mkbitmap
কম্পাইল করুন
Emscripten হল WebAssembly-এ C/C++ প্রোগ্রাম কম্পাইল করার একটি টুল। এমস্ক্রিপ্টেন এর বিল্ডিং প্রজেক্ট ডকুমেন্টেশন নিম্নলিখিতটি বলে:
Emscripten দিয়ে বড় প্রকল্প তৈরি করা খুবই সহজ। Emscripten দুটি সহজ স্ক্রিপ্ট প্রদান করে যা আপনার মেকফাইলগুলিকে
gcc
এর ড্রপ-ইন প্রতিস্থাপন হিসাবেemcc
ব্যবহার করার জন্য কনফিগার করে — বেশিরভাগ ক্ষেত্রে আপনার প্রকল্পের বর্তমান বিল্ড সিস্টেম অপরিবর্তিত থাকে।
ডকুমেন্টেশন তারপর চলে (সংক্ষিপ্ততার জন্য একটু সম্পাদিত):
যে ক্ষেত্রে আপনি সাধারণত নিম্নলিখিত কমান্ড দিয়ে তৈরি করেন তা বিবেচনা করুন:
./configure
make
Emscripten দিয়ে তৈরি করতে, আপনি পরিবর্তে নিম্নলিখিত কমান্ডগুলি ব্যবহার করবেন:
emconfigure ./configure
emmake make
তাই মূলত ./configure
হয়ে যায় emconfigure ./configure
এবং make
হয়ে যায় emmake make
। নিম্নলিখিতটি mkbitmap
দিয়ে কীভাবে এটি করতে হয় তা প্রদর্শন করে।
ধাপ 0, make clean
:
$ make clean
Making clean in src
rm -f potrace mkbitmap
test -z "" || rm -f
rm -rf .libs _libs
[…]
rm -f *.lo
ধাপ 1, emconfigure ./configure
:
$ emconfigure ./configure
configure: ./configure
checking for a BSD-compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
checking for a thread-safe mkdir -p... ./install-sh -c -d
checking for gawk... no
checking for mawk... no
checking for nawk... no
checking for awk... awk
[…]
config.status: executing libtool commands
ধাপ 2, emmake make
:
$ emmake make
make: make
/Applications/Xcode.app/Contents/Developer/usr/bin/make all-recursive
Making all in src
/opt/homebrew/Cellar/emscripten/3.1.36/libexec/emcc -DHAVE_CONFIG_H -I. -I.. -g -O2 -MT main.o -MD -MP -MF .deps/main.Tpo -c -o main.o main.c
mv -f .deps/main.Tpo .deps/main.Po
[…]
make[2]: Nothing to be done for `all'.
সবকিছু ঠিকঠাক থাকলে, এখন ডিরেক্টরির কোথাও .wasm
ফাইল থাকা উচিত। আপনি find . -name "*.wasm"
:
$ find . -name "*.wasm"
./a.wasm
./src/mkbitmap.wasm
./src/potrace.wasm
শেষ দুটি আশাপ্রদ দেখায়, তাই src/
ডিরেক্টরিতে cd
। এখন দুটি নতুন অনুরূপ ফাইল আছে, mkbitmap
এবং potrace
. এই নিবন্ধের জন্য, শুধুমাত্র mkbitmap
প্রাসঙ্গিক। তাদের কাছে .js
এক্সটেনশন না থাকার বিষয়টি একটু বিভ্রান্তিকর, কিন্তু তারা আসলে জাভাস্ক্রিপ্ট ফাইল, দ্রুত head
কলের মাধ্যমে যাচাইযোগ্য:
$ cd src/
$ head -n 20 mkbitmap
// include: shell.js
// The Module object: Our interface to the outside world. We import
// and export values on it. There are various ways Module can be used:
// 1. Not defined. We create it here
// 2. A function parameter, function(Module) { ..generated code.. }
// 3. pre-run appended it, var Module = {}; ..generated code..
// 4. External script tag defines var Module.
// We need to check if Module already exists (e.g. case 3 above).
// Substitution will be replaced with actual code on later stage of the build,
// this way Closure Compiler will not mangle it (e.g. case 4. above).
// Note that if you want to run closure, and also to use Module
// after the generated code, you will need to define var Module = {};
// before the code. Then that object will be used in the code, and you
// can continue to use Module afterwards as well.
var Module = typeof Module != 'undefined' ? Module : {};
// --pre-jses are emitted after the Module integration code, so that they can
// refer to Module (if they choose; they can also define Module)
mv mkbitmap mkbitmap.js
(এবং যদি আপনি চান যথাক্রমে mv potrace potrace.js
) কল করে জাভাস্ক্রিপ্ট ফাইলটির নাম পরিবর্তন করে mkbitmap.js
করুন। node mkbitmap.js --version
চালানোর মাধ্যমে কমান্ড লাইনে Node.js-এর সাহায্যে ফাইলটি চালানোর মাধ্যমে এটি কাজ করে কিনা তা দেখার জন্য এখন প্রথম পরীক্ষার সময় এসেছে:
$ node mkbitmap.js --version
mkbitmap 1.16. Copyright (C) 2001-2019 Peter Selinger.
আপনি সফলভাবে WebAssembly এ mkbitmap
কম্পাইল করেছেন। এখন পরবর্তী ধাপ হল এটি ব্রাউজারে কাজ করা।
ব্রাউজারে WebAssembly সহ mkbitmap
mkbitmap.js
এবং mkbitmap.wasm
ফাইলগুলিকে mkbitmap
নামে একটি নতুন ডিরেক্টরিতে অনুলিপি করুন এবং একটি index.html
HTML বয়লারপ্লেট ফাইল তৈরি করুন যা mkbitmap.js
জাভাস্ক্রিপ্ট ফাইল লোড করে।
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>mkbitmap</title>
</head>
<body>
<script src="mkbitmap.js"></script>
</body>
</html>
একটি স্থানীয় সার্ভার শুরু করুন যা mkbitmap
ডিরেক্টরি পরিবেশন করে এবং এটি আপনার ব্রাউজারে খুলুন। আপনি একটি প্রম্পট দেখতে পাবেন যা আপনাকে ইনপুট জিজ্ঞাসা করবে। এটি প্রত্যাশিত, যেহেতু, টুলের ম্যান পৃষ্ঠা অনুসারে , "[i]f কোন ফাইলের নাম আর্গুমেন্ট দেওয়া হয় না, তাহলে mkbitmap একটি ফিল্টার হিসাবে কাজ করে, স্ট্যান্ডার্ড ইনপুট থেকে পড়া" , যা Emscripten-এর জন্য ডিফল্টভাবে একটি prompt()
।
স্বয়ংক্রিয় মৃত্যুদন্ড প্রতিরোধ করুন
mkbitmap
অবিলম্বে কার্যকর করা বন্ধ করতে এবং পরিবর্তে এটিকে ব্যবহারকারীর ইনপুটের জন্য অপেক্ষা করতে, আপনাকে এমস্ক্রিপেনের Module
অবজেক্ট বুঝতে হবে। Module
হল একটি গ্লোবাল জাভাস্ক্রিপ্ট অবজেক্ট যার গুণাবলী রয়েছে যেগুলি এমস্ক্রিপ্টেন-উত্পাদিত কোড এটির সম্পাদনের বিভিন্ন পয়েন্টে কল করে। আপনি কোডের সম্পাদন নিয়ন্ত্রণ করতে Module
একটি বাস্তবায়ন প্রদান করতে পারেন। যখন একটি Emscripten অ্যাপ্লিকেশন শুরু হয়, এটি Module
অবজেক্টের মানগুলি দেখে এবং সেগুলি প্রয়োগ করে।
mkbitmap
এর ক্ষেত্রে, Module.noInitialRun
true
তে সেট করুন যাতে প্রম্পটটি প্রদর্শিত হতে প্রাথমিক রান রোধ করা যায়। script.js
নামে একটি স্ক্রিপ্ট তৈরি করুন, এটিকে index.html
এ <script src="mkbitmap.js"></script>
এর আগে অন্তর্ভুক্ত করুন এবং script.js
এ নিম্নলিখিত কোডটি যোগ করুন। আপনি এখন অ্যাপটি পুনরায় লোড করলে, প্রম্পটটি চলে যাওয়া উচিত।
var Module = {
// Don't run main() at page load
noInitialRun: true,
};
আরও কিছু বিল্ড পতাকা সহ একটি মডুলার বিল্ড তৈরি করুন
অ্যাপটিতে ইনপুট দেওয়ার জন্য, আপনি Module.FS
এ Emscripten-এর ফাইল সিস্টেম সমর্থন ব্যবহার করতে পারেন। ডকুমেন্টেশনের ফাইল সিস্টেম সমর্থন বিভাগটি বলে:
Emscripten স্বয়ংক্রিয়ভাবে ফাইল সিস্টেম সমর্থন অন্তর্ভুক্ত করার সিদ্ধান্ত নেয়। অনেক প্রোগ্রামের ফাইলের প্রয়োজন হয় না, এবং ফাইল সিস্টেম সমর্থন আকারে নগণ্য নয়, তাই এমস্ক্রিপ্টেন এটি অন্তর্ভুক্ত করা এড়িয়ে যায় যখন এটি কোন কারণ দেখতে পায় না। এর মানে হল যে যদি আপনার C/C++ কোড ফাইলগুলি অ্যাক্সেস না করে, তাহলে
FS
অবজেক্ট এবং অন্যান্য ফাইল সিস্টেম APIগুলি আউটপুটে অন্তর্ভুক্ত করা হবে না। এবং, অন্যদিকে, যদি আপনার C/C++ কোড ফাইল ব্যবহার করে, তাহলে ফাইল সিস্টেম সমর্থন স্বয়ংক্রিয়ভাবে অন্তর্ভুক্ত হবে।
দুর্ভাগ্যবশত mkbitmap
হল এমন একটি ক্ষেত্রে যেখানে Emscripten স্বয়ংক্রিয়ভাবে ফাইল সিস্টেম সমর্থন অন্তর্ভুক্ত করে না, তাই আপনাকে এটি করতে স্পষ্টভাবে বলতে হবে। এর মানে হল CFLAGS
আর্গুমেন্টের মাধ্যমে আরও কয়েকটি পতাকা সেট করার সাথে আপনাকে পূর্বে বর্ণিত emconfigure
এবং emmake
পদক্ষেপগুলি অনুসরণ করতে হবে। নিম্নলিখিত পতাকাগুলি অন্যান্য প্রকল্পগুলির জন্যও কার্যকর হতে পারে।
-
-sFILESYSTEM=1
সেট করুন যাতে ফাইল সিস্টেম সমর্থন অন্তর্ভুক্ত করা হয়। - সেট করুন
-sEXPORTED_RUNTIME_METHODS=FS,callMain
যাতেModule.FS
এবংModule.callMain
রপ্তানি হয়। - একটি আধুনিক ES6 মডিউল তৈরি করতে
-sMODULARIZE=1
এবং-sEXPORT_ES6
সেট করুন। - প্রারম্ভিক রান রোধ করতে
-sINVOKE_RUN=0
সেট করুন যা প্রম্পটটি প্রদর্শিত হতে পারে।
এছাড়াও, এই বিশেষ ক্ষেত্রে, আপনি WebAssembly-এর জন্য যে configure
স্ক্রিপ্টটি কম্পাইল করছেন তা জানাতে আপনাকে --host
পতাকা wasm32
এ সেট করতে হবে।
চূড়ান্ত emconfigure
কমান্ড এই মত দেখায়:
$ emconfigure ./configure --host=wasm32 CFLAGS='-sFILESYSTEM=1 -sEXPORTED_RUNTIME_METHODS=FS,callMain -sMODULARIZE=1 -sEXPORT_ES6 -sINVOKE_RUN=0'
emmake make
আবার চালাতে ভুলবেন না এবং সদ্য তৈরি করা ফাইলগুলিকে mkbitmap
ফোল্ডারে কপি করুন।
index.html
পরিবর্তন করুন যাতে এটি শুধুমাত্র ES মডিউল script.js
লোড করে, যেখান থেকে আপনি mkbitmap.js
মডিউল আমদানি করেন।
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>mkbitmap</title>
</head>
<body>
<!-- No longer load `mkbitmap.js` here -->
<script src="script.js" type="module"></script>
</body>
</html>
// This is `script.js`.
import loadWASM from './mkbitmap.js';
const run = async () => {
const Module = await loadWASM();
console.log(Module);
};
run();
আপনি যখন ব্রাউজারে অ্যাপটি খুলবেন, তখন আপনি Module
অবজেক্টটি DevTools কনসোলে লগ করা দেখতে পাবেন এবং প্রম্পটটি চলে গেছে, যেহেতু mkbitmap
এর main()
ফাংশন আর শুরুতে বলা হয় না।
ম্যানুয়ালি প্রধান ফাংশন চালান
পরবর্তী ধাপ হল Module.callMain()
চালিয়ে mkbitmap
এর main()
ফাংশনকে ম্যানুয়ালি কল করা। callMain()
ফাংশন আর্গুমেন্টের একটি অ্যারে নেয়, যা আপনি কমান্ড লাইনে যা পাস করবেন তার সাথে একের পর এক মেলে। যদি কমান্ড লাইনে আপনি mkbitmap -v
চালান, আপনি ব্রাউজারে Module.callMain(['-v'])
কল করবেন। এটি DevTools কনসোলে mkbitmap
সংস্করণ নম্বর লগ করে।
// This is `script.js`.
import loadWASM from './mkbitmap.js';
const run = async () => {
const Module = await loadWASM();
Module.callMain(['-v']);
};
run();
স্ট্যান্ডার্ড আউটপুট রিডাইরেক্ট করুন
ডিফল্টরূপে স্ট্যান্ডার্ড আউটপুট ( stdout
) হল কনসোল। যাইহোক, আপনি এটিকে অন্য কিছুতে পুনঃনির্দেশ করতে পারেন, উদাহরণস্বরূপ, একটি ফাংশন যা একটি ভেরিয়েবলে আউটপুট সংরক্ষণ করে। এর মানে আপনি Module.print
প্রপার্টি সেট করে HTML-এ আউটপুট যোগ করতে পারেন।
// This is `script.js`.
import loadWASM from './mkbitmap.js';
const run = async () => {
let consoleOutput = 'Powered by ';
const Module = await loadWASM({
print: (text) => (consoleOutput += text),
});
Module.callMain(['-v']);
document.body.textContent = consoleOutput;
};
run();
মেমরি ফাইল সিস্টেমে ইনপুট ফাইল পান
মেমরি ফাইল সিস্টেমে ইনপুট ফাইল পেতে, আপনাকে কমান্ড লাইনে mkbitmap filename
সমতুল্য প্রয়োজন। আমি কীভাবে এটির সাথে যোগাযোগ করি তা বোঝার জন্য, প্রথমে mkbitmap
কীভাবে তার ইনপুট আশা করে এবং তার আউটপুট তৈরি করে তার কিছু পটভূমি।
mkbitmap
এর সমর্থিত ইনপুট ফর্ম্যাটগুলি হল PNM ( PBM , PGM , PPM ) এবং BMP ৷ আউটপুট ফরম্যাটগুলি হল বিটম্যাপের জন্য PBM এবং গ্রেম্যাপের জন্য PGM। যদি একটি filename
আর্গুমেন্ট দেওয়া হয়, mkbitmap
ডিফল্টরূপে একটি আউটপুট ফাইল তৈরি করবে যার নাম ইনপুট ফাইলের নাম থেকে .pbm
এ প্রত্যয় পরিবর্তন করে প্রাপ্ত করা হয়েছে। উদাহরণস্বরূপ, ইনপুট ফাইলের নাম example.bmp
এর জন্য, আউটপুট ফাইলের নাম হবে example.pbm
।
এমস্ক্রিপ্টেন একটি ভার্চুয়াল ফাইল সিস্টেম সরবরাহ করে যা স্থানীয় ফাইল সিস্টেমকে অনুকরণ করে, যাতে সিঙ্ক্রোনাস ফাইল API ব্যবহার করে নেটিভ কোড কম্পাইল করা যায় এবং সামান্য বা কোন পরিবর্তন ছাড়াই চালানো যায়। mkbitmap
একটি ইনপুট ফাইল পড়ার জন্য যেন এটি একটি filename
কমান্ড লাইন আর্গুমেন্ট হিসাবে পাস করা হয়েছে, আপনাকে Emscripten প্রদান করে FS
অবজেক্ট ব্যবহার করতে হবে।
FS
অবজেক্টটি একটি ইন-মেমরি ফাইল সিস্টেম দ্বারা সমর্থিত (সাধারণত MEMFS হিসাবে উল্লেখ করা হয়) এবং এতে একটি writeFile()
ফাংশন রয়েছে যা আপনি ভার্চুয়াল ফাইল সিস্টেমে ফাইল লিখতে ব্যবহার করেন। নিম্নলিখিত কোড নমুনায় দেখানো হিসাবে আপনি writeFile()
ব্যবহার করেন।
ফাইল লেখার অপারেশন কাজ করেছে তা যাচাই করতে, '/'
প্যারামিটার দিয়ে FS
অবজেক্টের readdir()
ফাংশন চালান। আপনি example.bmp
এবং অনেকগুলি ডিফল্ট ফাইল দেখতে পাবেন যা সর্বদা স্বয়ংক্রিয়ভাবে তৈরি হয় ।
উল্লেখ্য যে সংস্করণ নম্বর প্রিন্ট করার জন্য Module.callMain(['-v'])
এর আগের কলটি সরিয়ে দেওয়া হয়েছিল। এটি এই কারণে যে Module.callMain()
একটি ফাংশন যা সাধারণত শুধুমাত্র একবার চালানোর আশা করে।
// This is `script.js`.
import loadWASM from './mkbitmap.js';
const run = async () => {
const Module = await loadWASM();
const buffer = await fetch('https://example.com/example.bmp').then((res) => res.arrayBuffer());
Module.FS.writeFile('example.bmp', new Uint8Array(buffer));
console.log(Module.FS.readdir('/'));
};
run();
প্রথম প্রকৃত মৃত্যুদন্ড
সবকিছু ঠিক রেখে, Module.callMain(['example.bmp'])
চালিয়ে mkbitmap
চালান। MEMFS' '/'
ফোল্ডারের বিষয়বস্তু লগ করুন, এবং আপনি example.bmp
ইনপুট ফাইলের পাশে নতুন তৈরি example.pbm
আউটপুট ফাইলটি দেখতে পাবেন।
// This is `script.js`.
import loadWASM from './mkbitmap.js';
const run = async () => {
const Module = await loadWASM();
const buffer = await fetch('https://example.com/example.bmp').then((res) => res.arrayBuffer());
Module.FS.writeFile('example.bmp', new Uint8Array(buffer));
Module.callMain(['example.bmp']);
console.log(Module.FS.readdir('/'));
};
run();
মেমরি ফাইল সিস্টেম থেকে আউটপুট ফাইল পান
FS
অবজেক্টের readFile()
ফাংশন মেমরি ফাইল সিস্টেমের শেষ ধাপে তৈরি example.pbm
পেতে সক্ষম করে। ফাংশনটি একটি Uint8Array
প্রদান করে যা আপনি একটি File
অবজেক্টে রূপান্তর করেন এবং ডিস্কে সংরক্ষণ করেন, কারণ ব্রাউজারগুলি সাধারণত সরাসরি ইন-ব্রাউজার দেখার জন্য PBM ফাইল সমর্থন করে না। ( একটি ফাইল সংরক্ষণ করার আরও মার্জিত উপায় আছে, কিন্তু একটি গতিশীলভাবে তৈরি <a download>
ব্যবহার করা সবচেয়ে ব্যাপকভাবে সমর্থিত।) একবার ফাইলটি সংরক্ষিত হলে, আপনি এটি আপনার প্রিয় চিত্র দর্শকে খুলতে পারেন।
// This is `script.js`.
import loadWASM from './mkbitmap.js';
const run = async () => {
const Module = await loadWASM();
const buffer = await fetch('https://example.com/example.bmp').then((res) => res.arrayBuffer());
Module.FS.writeFile('example.bmp', new Uint8Array(buffer));
Module.callMain(['example.bmp']);
const output = Module.FS.readFile('example.pbm', { encoding: 'binary' });
const file = new File([output], 'example.pbm', {
type: 'image/x-portable-bitmap',
});
const a = document.createElement('a');
a.href = URL.createObjectURL(file);
a.download = file.name;
a.click();
};
run();
একটি ইন্টারেক্টিভ UI যোগ করুন
এই মুহুর্তে, ইনপুট ফাইলটি হার্ডকোড করা হয়েছে এবং mkbitmap
ডিফল্ট প্যারামিটারের সাথে চলে। চূড়ান্ত পদক্ষেপ হল ব্যবহারকারীকে গতিশীলভাবে একটি ইনপুট ফাইল নির্বাচন করতে দেওয়া, mkbitmap
পরামিতিগুলিকে টুইক করা এবং তারপর নির্বাচিত বিকল্পগুলির সাথে টুলটি চালান।
// Corresponds to `mkbitmap -o output.pbm input.bmp -s 8 -3 -f 4 -t 0.45`.
Module.callMain(['-o', 'output.pbm', 'input.bmp', '-s', '8', '-3', '-f', '4', '-t', '0.45']);
PBM ইমেজ ফরম্যাট পার্স করা বিশেষভাবে কঠিন নয়, তাই কিছু জাভাস্ক্রিপ্ট কোড দিয়ে, আপনি আউটপুট ইমেজের একটি প্রিভিউও দেখাতে পারেন। এটি করার একটি উপায়ের জন্য নীচে এমবেডেড ডেমোর উত্স কোডটি দেখুন৷
উপসংহার
অভিনন্দন, আপনি সফলভাবে WebAssembly-তে mkbitmap
কম্পাইল করেছেন এবং এটি ব্রাউজারে কাজ করেছেন! কিছু শেষ প্রান্ত ছিল এবং এটি কাজ না হওয়া পর্যন্ত আপনাকে একাধিকবার টুলটি কম্পাইল করতে হয়েছিল, কিন্তু আমি উপরে লিখেছি, এটি অভিজ্ঞতার অংশ। আপনি আটকে গেলে StackOverflow এর webassembly
ট্যাগটিও মনে রাখবেন। শুভ কম্পাইলিং!
স্বীকৃতি
এই নিবন্ধটি স্যাম ক্লেগ এবং রাচেল অ্যান্ড্রু দ্বারা পর্যালোচনা করা হয়েছিল।
,WebAssembly কি এবং কোথা থেকে এসেছে? , আমি ব্যাখ্যা করেছি কিভাবে আমরা আজকের WebAssembly এর সাথে শেষ করেছি। এই নিবন্ধে, আমি আপনাকে একটি বিদ্যমান সি প্রোগ্রাম, mkbitmap
, WebAssembly-তে কম্পাইল করার আমার পদ্ধতি দেখাব। এটি হ্যালো ওয়ার্ল্ড উদাহরণের চেয়ে জটিল, কারণ এতে ফাইলগুলির সাথে কাজ করা, ওয়েব অ্যাসেম্বলি এবং জাভাস্ক্রিপ্ট ল্যান্ডগুলির মধ্যে যোগাযোগ করা এবং একটি ক্যানভাসে আঁকার অন্তর্ভুক্ত, তবে এটি এখনও আপনাকে অভিভূত না করার জন্য যথেষ্ট পরিচালনাযোগ্য৷
নিবন্ধটি ওয়েব ডেভেলপারদের জন্য লেখা হয়েছে যারা WebAssembly শিখতে চান এবং ধাপে ধাপে দেখায় যে আপনি যদি mkbitmap
এর মত কিছু WebAssembly-তে কম্পাইল করতে চান তাহলে আপনি কীভাবে এগিয়ে যেতে পারেন। একটি ন্যায্য সতর্কতা হিসাবে, প্রথম রানে কম্পাইল করার জন্য একটি অ্যাপ বা লাইব্রেরি না পাওয়া সম্পূর্ণ স্বাভাবিক, এই কারণেই নীচে বর্ণিত কিছু পদক্ষেপ কাজ করছে না, তাই আমাকে ব্যাকট্র্যাক করতে হবে এবং অন্যভাবে আবার চেষ্টা করতে হবে। নিবন্ধটি ম্যাজিক চূড়ান্ত সংকলন আদেশটি এমনভাবে দেখায় না যেন এটি আকাশ থেকে নেমে গেছে, বরং আমার প্রকৃত অগ্রগতি বর্ণনা করে, কিছু হতাশা অন্তর্ভুক্ত।
mkbitmap
সম্পর্কে
mkbitmap
C প্রোগ্রাম একটি চিত্র পড়ে এবং এটিতে নিম্নলিখিত এক বা একাধিক ক্রিয়াকলাপ প্রয়োগ করে, এই ক্রমে: ইনভার্সন, হাইপাস ফিল্টারিং, স্কেলিং এবং থ্রেশহোল্ডিং। প্রতিটি অপারেশন পৃথকভাবে নিয়ন্ত্রিত এবং চালু বা বন্ধ করা যেতে পারে। mkbitmap
এর প্রধান ব্যবহার হল রঙ বা গ্রেস্কেল ছবিগুলিকে অন্য প্রোগ্রামের জন্য ইনপুট হিসাবে উপযুক্ত ফর্ম্যাটে রূপান্তর করা, বিশেষ করে ট্রেসিং প্রোগ্রাম potrace
যা SVGcode- এর ভিত্তি তৈরি করে। একটি প্রিপ্রসেসিং টুল হিসেবে, mkbitmap
বিশেষভাবে স্ক্যান করা লাইন আর্ট, যেমন কার্টুন বা হাতে লেখা পাঠ্যকে উচ্চ-রেজোলিউশনের দ্বি-লেভেল ইমেজে রূপান্তর করার জন্য উপযোগী।
আপনি mkbitmap
ব্যবহার করে এটিকে অনেকগুলি অপশন এবং এক বা একাধিক ফাইলের নাম পাস করে। সমস্ত বিবরণের জন্য, টুলের ম্যান পৃষ্ঠাটি দেখুন:
$ mkbitmap [options] [filename...]
কোড পান
প্রথম ধাপ হল mkbitmap
এর সোর্স কোড প্রাপ্ত করা। আপনি প্রকল্পের ওয়েবসাইটে এটি খুঁজে পেতে পারেন। এই লেখার সময়, potrace-1.16.tar.gz সর্বশেষ সংস্করণ।
স্থানীয়ভাবে কম্পাইল এবং ইনস্টল করুন
পরবর্তী ধাপ হল টুলটি স্থানীয়ভাবে কম্পাইল করা এবং ইনস্টল করা যাতে এটি কীভাবে আচরণ করে তার অনুভূতি পেতে। INSTALL
ফাইলটিতে নিম্নলিখিত নির্দেশাবলী রয়েছে:
প্যাকেজের সোর্স কোড ধারণকারী ডিরেক্টরিতে
cd
এবং আপনার সিস্টেমের জন্য প্যাকেজ কনফিগার করতে./configure
টাইপ করুন।configure
চালানোর জন্য কিছু সময় লাগতে পারে। চালানোর সময়, এটি কোন বৈশিষ্ট্যগুলি পরীক্ষা করছে তা বলে কিছু বার্তা প্রিন্ট করে৷প্যাকেজ কম্পাইল করতে
make
টাইপ করুন।ঐচ্ছিকভাবে, প্যাকেজের সাথে আসা যেকোনো স্ব-পরীক্ষা চালানোর জন্য
make check
টাইপ করুন, সাধারণত সদ্য নির্মিত আনইনস্টল করা বাইনারি ব্যবহার করে।প্রোগ্রাম এবং যেকোনো ডেটা ফাইল এবং ডকুমেন্টেশন ইনস্টল করতে
make install
টাইপ করুন। রুটের মালিকানাধীন একটি প্রিফিক্সে ইনস্টল করার সময়, প্যাকেজটিকে নিয়মিত ব্যবহারকারী হিসাবে কনফিগার এবং তৈরি করার পরামর্শ দেওয়া হয় এবং শুধুমাত্রmake install
ফেজটি রুট সুবিধা সহ কার্যকর করা হয়।
এই পদক্ষেপগুলি অনুসরণ করে, আপনার দুটি এক্সিকিউটেবল, potrace
এবং mkbitmap
এর সাথে শেষ হওয়া উচিত — পরেরটি এই নিবন্ধের ফোকাস। আপনি mkbitmap --version
চালিয়ে এটি সঠিকভাবে কাজ করেছে তা যাচাই করতে পারেন। এখানে আমার মেশিন থেকে চারটি ধাপের আউটপুট, সংক্ষিপ্ততার জন্য ভারীভাবে ছাঁটা:
ধাপ 1, ./configure
:
$ ./configure
checking for a BSD-compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
checking for a thread-safe mkdir -p... ./install-sh -c -d
checking for gawk... no
checking for mawk... no
checking for nawk... no
checking for awk... awk
checking whether make sets $(MAKE)... yes
[…]
config.status: executing libtool commands
ধাপ 2, make
:
$ make
/Applications/Xcode.app/Contents/Developer/usr/bin/make all-recursive
Making all in src
clang -DHAVE_CONFIG_H -I. -I.. -g -O2 -MT main.o -MD -MP -MF .deps/main.Tpo -c -o main.o main.c
mv -f .deps/main.Tpo .deps/main.Po
[…]
make[2]: Nothing to be done for `all-am'.
ধাপ 3, make check
:
$ make check
Making check in src
make[1]: Nothing to be done for `check'.
Making check in doc
make[1]: Nothing to be done for `check'.
[…]
============================================================================
Testsuite summary for potrace 1.16
============================================================================
# TOTAL: 8
# PASS: 8
# SKIP: 0
# XFAIL: 0
# FAIL: 0
# XPASS: 0
# ERROR: 0
============================================================================
make[1]: Nothing to be done for `check-am'.
ধাপ 4, sudo make install
:
$ sudo make install
Password:
Making install in src
.././install-sh -c -d '/usr/local/bin'
/bin/sh ../libtool --mode=install /usr/bin/install -c potrace mkbitmap '/usr/local/bin'
[…]
make[2]: Nothing to be done for `install-data-am'.
এটি কাজ করেছে কিনা তা পরীক্ষা করতে, mkbitmap --version
চালান:
$ mkbitmap --version
mkbitmap 1.16. Copyright (C) 2001-2019 Peter Selinger.
আপনি যদি সংস্করণের বিশদ বিবরণ পান, আপনি সফলভাবে mkbitmap
কম্পাইল এবং ইনস্টল করেছেন। এরপর, WebAssembly-এর সাথে এই ধাপগুলির সমতুল্য কাজ করুন।
WebAssembly এ mkbitmap
কম্পাইল করুন
Emscripten হল WebAssembly-এ C/C++ প্রোগ্রাম কম্পাইল করার একটি টুল। এমস্ক্রিপ্টেন এর বিল্ডিং প্রজেক্ট ডকুমেন্টেশন নিম্নলিখিতটি বলে:
Emscripten দিয়ে বড় প্রকল্প তৈরি করা খুবই সহজ। Emscripten দুটি সহজ স্ক্রিপ্ট প্রদান করে যা আপনার মেকফাইলগুলিকে
gcc
এর ড্রপ-ইন প্রতিস্থাপন হিসাবেemcc
ব্যবহার করার জন্য কনফিগার করে — বেশিরভাগ ক্ষেত্রে আপনার প্রকল্পের বর্তমান বিল্ড সিস্টেম অপরিবর্তিত থাকে।
ডকুমেন্টেশন তারপর চলে (সংক্ষিপ্ততার জন্য একটু সম্পাদিত):
যে ক্ষেত্রে আপনি সাধারণত নিম্নলিখিত কমান্ড দিয়ে তৈরি করেন তা বিবেচনা করুন:
./configure
make
Emscripten দিয়ে তৈরি করতে, আপনি পরিবর্তে নিম্নলিখিত কমান্ডগুলি ব্যবহার করবেন:
emconfigure ./configure
emmake make
তাই মূলত ./configure
হয়ে যায় emconfigure ./configure
এবং make
হয়ে যায় emmake make
। নিম্নলিখিতটি mkbitmap
দিয়ে কীভাবে এটি করতে হয় তা প্রদর্শন করে।
ধাপ 0, make clean
:
$ make clean
Making clean in src
rm -f potrace mkbitmap
test -z "" || rm -f
rm -rf .libs _libs
[…]
rm -f *.lo
ধাপ 1, emconfigure ./configure
:
$ emconfigure ./configure
configure: ./configure
checking for a BSD-compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
checking for a thread-safe mkdir -p... ./install-sh -c -d
checking for gawk... no
checking for mawk... no
checking for nawk... no
checking for awk... awk
[…]
config.status: executing libtool commands
ধাপ 2, emmake make
:
$ emmake make
make: make
/Applications/Xcode.app/Contents/Developer/usr/bin/make all-recursive
Making all in src
/opt/homebrew/Cellar/emscripten/3.1.36/libexec/emcc -DHAVE_CONFIG_H -I. -I.. -g -O2 -MT main.o -MD -MP -MF .deps/main.Tpo -c -o main.o main.c
mv -f .deps/main.Tpo .deps/main.Po
[…]
make[2]: Nothing to be done for `all'.
সবকিছু ঠিকঠাক থাকলে, এখন ডিরেক্টরির কোথাও .wasm
ফাইল থাকা উচিত। আপনি find . -name "*.wasm"
:
$ find . -name "*.wasm"
./a.wasm
./src/mkbitmap.wasm
./src/potrace.wasm
শেষ দুটি আশাপ্রদ দেখায়, তাই src/
ডিরেক্টরিতে cd
। এখন দুটি নতুন অনুরূপ ফাইল আছে, mkbitmap
এবং potrace
. এই নিবন্ধের জন্য, শুধুমাত্র mkbitmap
প্রাসঙ্গিক। তাদের কাছে .js
এক্সটেনশন না থাকার বিষয়টি একটু বিভ্রান্তিকর, কিন্তু তারা আসলে জাভাস্ক্রিপ্ট ফাইল, দ্রুত head
কলের মাধ্যমে যাচাইযোগ্য:
$ cd src/
$ head -n 20 mkbitmap
// include: shell.js
// The Module object: Our interface to the outside world. We import
// and export values on it. There are various ways Module can be used:
// 1. Not defined. We create it here
// 2. A function parameter, function(Module) { ..generated code.. }
// 3. pre-run appended it, var Module = {}; ..generated code..
// 4. External script tag defines var Module.
// We need to check if Module already exists (e.g. case 3 above).
// Substitution will be replaced with actual code on later stage of the build,
// this way Closure Compiler will not mangle it (e.g. case 4. above).
// Note that if you want to run closure, and also to use Module
// after the generated code, you will need to define var Module = {};
// before the code. Then that object will be used in the code, and you
// can continue to use Module afterwards as well.
var Module = typeof Module != 'undefined' ? Module : {};
// --pre-jses are emitted after the Module integration code, so that they can
// refer to Module (if they choose; they can also define Module)
mv mkbitmap mkbitmap.js
(এবং যদি আপনি চান যথাক্রমে mv potrace potrace.js
) কল করে জাভাস্ক্রিপ্ট ফাইলটির নাম পরিবর্তন করে mkbitmap.js
করুন। node mkbitmap.js --version
চালানোর মাধ্যমে কমান্ড লাইনে Node.js-এর সাহায্যে ফাইলটি চালানোর মাধ্যমে এটি কাজ করে কিনা তা দেখার জন্য এখন প্রথম পরীক্ষার সময় এসেছে:
$ node mkbitmap.js --version
mkbitmap 1.16. Copyright (C) 2001-2019 Peter Selinger.
আপনি সফলভাবে WebAssembly এ mkbitmap
কম্পাইল করেছেন। এখন পরবর্তী ধাপ হল এটি ব্রাউজারে কাজ করা।
ব্রাউজারে WebAssembly সহ mkbitmap
mkbitmap.js
এবং mkbitmap.wasm
ফাইলগুলিকে mkbitmap
নামে একটি নতুন ডিরেক্টরিতে অনুলিপি করুন এবং একটি index.html
HTML বয়লারপ্লেট ফাইল তৈরি করুন যা mkbitmap.js
জাভাস্ক্রিপ্ট ফাইল লোড করে।
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>mkbitmap</title>
</head>
<body>
<script src="mkbitmap.js"></script>
</body>
</html>
একটি স্থানীয় সার্ভার শুরু করুন যা mkbitmap
ডিরেক্টরি পরিবেশন করে এবং এটি আপনার ব্রাউজারে খুলুন। আপনি একটি প্রম্পট দেখতে পাবেন যা আপনাকে ইনপুট জিজ্ঞাসা করবে। এটি প্রত্যাশিত, যেহেতু, টুলের ম্যান পৃষ্ঠা অনুসারে , "[i]f কোন ফাইলের নাম আর্গুমেন্ট দেওয়া হয় না, তাহলে mkbitmap একটি ফিল্টার হিসাবে কাজ করে, স্ট্যান্ডার্ড ইনপুট থেকে পড়া" , যা Emscripten-এর জন্য ডিফল্টভাবে একটি prompt()
।
স্বয়ংক্রিয় মৃত্যুদন্ড প্রতিরোধ করুন
mkbitmap
অবিলম্বে কার্যকর করা বন্ধ করতে এবং পরিবর্তে এটিকে ব্যবহারকারীর ইনপুটের জন্য অপেক্ষা করতে, আপনাকে এমস্ক্রিপেনের Module
অবজেক্ট বুঝতে হবে। Module
হল একটি গ্লোবাল জাভাস্ক্রিপ্ট অবজেক্ট যার গুণাবলী রয়েছে যেগুলি এমস্ক্রিপ্টেন-উত্পাদিত কোড এটির সম্পাদনের বিভিন্ন পয়েন্টে কল করে। আপনি কোডের সম্পাদন নিয়ন্ত্রণ করতে Module
একটি বাস্তবায়ন প্রদান করতে পারেন। যখন একটি Emscripten অ্যাপ্লিকেশন শুরু হয়, এটি Module
অবজেক্টের মানগুলি দেখে এবং সেগুলি প্রয়োগ করে।
mkbitmap
এর ক্ষেত্রে, Module.noInitialRun
true
তে সেট করুন যাতে প্রম্পটটি প্রদর্শিত হতে প্রাথমিক রান রোধ করা যায়। script.js
নামে একটি স্ক্রিপ্ট তৈরি করুন, এটিকে index.html
এ <script src="mkbitmap.js"></script>
এর আগে অন্তর্ভুক্ত করুন এবং script.js
এ নিম্নলিখিত কোডটি যোগ করুন। আপনি এখন অ্যাপটি পুনরায় লোড করলে, প্রম্পটটি চলে যাওয়া উচিত।
var Module = {
// Don't run main() at page load
noInitialRun: true,
};
আরও কিছু বিল্ড পতাকা সহ একটি মডুলার বিল্ড তৈরি করুন
অ্যাপটিতে ইনপুট দেওয়ার জন্য, আপনি Module.FS
এ Emscripten-এর ফাইল সিস্টেম সমর্থন ব্যবহার করতে পারেন। ডকুমেন্টেশনের ফাইল সিস্টেম সমর্থন বিভাগটি বলে:
Emscripten স্বয়ংক্রিয়ভাবে ফাইল সিস্টেম সমর্থন অন্তর্ভুক্ত করার সিদ্ধান্ত নেয়। অনেক প্রোগ্রামের ফাইলের প্রয়োজন হয় না, এবং ফাইল সিস্টেম সমর্থন আকারে নগণ্য নয়, তাই এমস্ক্রিপ্টেন এটি অন্তর্ভুক্ত করা এড়িয়ে যায় যখন এটি কোন কারণ দেখতে পায় না। এর মানে হল যে যদি আপনার C/C++ কোড ফাইলগুলি অ্যাক্সেস না করে, তাহলে
FS
অবজেক্ট এবং অন্যান্য ফাইল সিস্টেম APIগুলি আউটপুটে অন্তর্ভুক্ত করা হবে না। এবং, অন্যদিকে, যদি আপনার C/C++ কোড ফাইল ব্যবহার করে, তাহলে ফাইল সিস্টেম সমর্থন স্বয়ংক্রিয়ভাবে অন্তর্ভুক্ত হবে।
দুর্ভাগ্যবশত mkbitmap
হল এমন একটি ক্ষেত্রে যেখানে Emscripten স্বয়ংক্রিয়ভাবে ফাইল সিস্টেম সমর্থন অন্তর্ভুক্ত করে না, তাই আপনাকে এটি করতে স্পষ্টভাবে বলতে হবে। এর মানে হল CFLAGS
আর্গুমেন্টের মাধ্যমে আরও কয়েকটি পতাকা সেট করার সাথে আপনাকে পূর্বে বর্ণিত emconfigure
এবং emmake
পদক্ষেপগুলি অনুসরণ করতে হবে। নিম্নলিখিত পতাকাগুলি অন্যান্য প্রকল্পগুলির জন্যও কার্যকর হতে পারে।
-
-sFILESYSTEM=1
সেট করুন যাতে ফাইল সিস্টেম সমর্থন অন্তর্ভুক্ত করা হয়। - সেট করুন
-sEXPORTED_RUNTIME_METHODS=FS,callMain
যাতেModule.FS
এবংModule.callMain
রপ্তানি হয়। - একটি আধুনিক ES6 মডিউল তৈরি করতে
-sMODULARIZE=1
এবং-sEXPORT_ES6
সেট করুন। - প্রারম্ভিক রান রোধ করতে
-sINVOKE_RUN=0
সেট করুন যা প্রম্পটটি প্রদর্শিত হতে পারে।
এছাড়াও, এই বিশেষ ক্ষেত্রে, আপনি WebAssembly-এর জন্য যে configure
স্ক্রিপ্টটি কম্পাইল করছেন তা জানাতে আপনাকে --host
পতাকা wasm32
এ সেট করতে হবে।
চূড়ান্ত emconfigure
কমান্ড এই মত দেখায়:
$ emconfigure ./configure --host=wasm32 CFLAGS='-sFILESYSTEM=1 -sEXPORTED_RUNTIME_METHODS=FS,callMain -sMODULARIZE=1 -sEXPORT_ES6 -sINVOKE_RUN=0'
emmake make
আবার চালাতে ভুলবেন না এবং সদ্য তৈরি করা ফাইলগুলিকে mkbitmap
ফোল্ডারে কপি করুন।
index.html
পরিবর্তন করুন যাতে এটি শুধুমাত্র ES মডিউল script.js
লোড করে, যেখান থেকে আপনি mkbitmap.js
মডিউল আমদানি করেন।
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>mkbitmap</title>
</head>
<body>
<!-- No longer load `mkbitmap.js` here -->
<script src="script.js" type="module"></script>
</body>
</html>
// This is `script.js`.
import loadWASM from './mkbitmap.js';
const run = async () => {
const Module = await loadWASM();
console.log(Module);
};
run();
আপনি যখন ব্রাউজারে অ্যাপটি খুলবেন, তখন আপনি Module
অবজেক্টটি DevTools কনসোলে লগ করা দেখতে পাবেন এবং প্রম্পটটি চলে গেছে, যেহেতু mkbitmap
এর main()
ফাংশন আর শুরুতে বলা হয় না।
ম্যানুয়ালি প্রধান ফাংশন চালান
পরবর্তী ধাপ হল Module.callMain()
চালিয়ে mkbitmap
এর main()
ফাংশনকে ম্যানুয়ালি কল করা। callMain()
ফাংশন আর্গুমেন্টের একটি অ্যারে নেয়, যা আপনি কমান্ড লাইনে যা পাস করবেন তার সাথে একের পর এক মেলে। যদি কমান্ড লাইনে আপনি mkbitmap -v
চালান, আপনি ব্রাউজারে Module.callMain(['-v'])
কল করবেন। এটি DevTools কনসোলে mkbitmap
সংস্করণ নম্বর লগ করে।
// This is `script.js`.
import loadWASM from './mkbitmap.js';
const run = async () => {
const Module = await loadWASM();
Module.callMain(['-v']);
};
run();
স্ট্যান্ডার্ড আউটপুট রিডাইরেক্ট করুন
ডিফল্টরূপে স্ট্যান্ডার্ড আউটপুট ( stdout
) হল কনসোল। যাইহোক, আপনি এটিকে অন্য কিছুতে পুনঃনির্দেশ করতে পারেন, উদাহরণস্বরূপ, একটি ফাংশন যা একটি ভেরিয়েবলে আউটপুট সংরক্ষণ করে। এর মানে আপনি Module.print
প্রপার্টি সেট করে HTML-এ আউটপুট যোগ করতে পারেন।
// This is `script.js`.
import loadWASM from './mkbitmap.js';
const run = async () => {
let consoleOutput = 'Powered by ';
const Module = await loadWASM({
print: (text) => (consoleOutput += text),
});
Module.callMain(['-v']);
document.body.textContent = consoleOutput;
};
run();
মেমরি ফাইল সিস্টেমে ইনপুট ফাইল পান
মেমরি ফাইল সিস্টেমে ইনপুট ফাইল পেতে, আপনাকে কমান্ড লাইনে mkbitmap filename
সমতুল্য প্রয়োজন। আমি কীভাবে এটির সাথে যোগাযোগ করি তা বোঝার জন্য, প্রথমে mkbitmap
কীভাবে তার ইনপুট আশা করে এবং তার আউটপুট তৈরি করে তার কিছু পটভূমি।
mkbitmap
এর সমর্থিত ইনপুট ফর্ম্যাটগুলি হল PNM ( PBM , PGM , PPM ) এবং BMP ৷ আউটপুট ফরম্যাটগুলি হল বিটম্যাপের জন্য PBM এবং গ্রেম্যাপের জন্য PGM। যদি একটি filename
আর্গুমেন্ট দেওয়া হয়, mkbitmap
ডিফল্টরূপে একটি আউটপুট ফাইল তৈরি করবে যার নাম ইনপুট ফাইলের নাম থেকে .pbm
এ প্রত্যয় পরিবর্তন করে প্রাপ্ত করা হয়েছে। উদাহরণস্বরূপ, ইনপুট ফাইলের নাম example.bmp
এর জন্য, আউটপুট ফাইলের নাম হবে example.pbm
।
এমস্ক্রিপ্টেন একটি ভার্চুয়াল ফাইল সিস্টেম সরবরাহ করে যা স্থানীয় ফাইল সিস্টেমকে অনুকরণ করে, যাতে সিঙ্ক্রোনাস ফাইল API ব্যবহার করে নেটিভ কোড কম্পাইল করা যায় এবং সামান্য বা কোন পরিবর্তন ছাড়াই চালানো যায়। mkbitmap
একটি ইনপুট ফাইল পড়ার জন্য যেন এটি একটি filename
কমান্ড লাইন আর্গুমেন্ট হিসাবে পাস করা হয়েছে, আপনাকে Emscripten প্রদান করে FS
অবজেক্ট ব্যবহার করতে হবে।
FS
অবজেক্টটি একটি ইন-মেমরি ফাইল সিস্টেম দ্বারা সমর্থিত (সাধারণত MEMFS হিসাবে উল্লেখ করা হয়) এবং এতে একটি writeFile()
ফাংশন রয়েছে যা আপনি ভার্চুয়াল ফাইল সিস্টেমে ফাইল লিখতে ব্যবহার করেন। নিম্নলিখিত কোড নমুনায় দেখানো হিসাবে আপনি writeFile()
ব্যবহার করেন।
ফাইল লেখার অপারেশন কাজ করেছে তা যাচাই করতে, '/'
প্যারামিটার দিয়ে FS
অবজেক্টের readdir()
ফাংশন চালান। আপনি example.bmp
এবং অনেকগুলি ডিফল্ট ফাইল দেখতে পাবেন যা সর্বদা স্বয়ংক্রিয়ভাবে তৈরি হয় ।
উল্লেখ্য যে সংস্করণ নম্বর প্রিন্ট করার জন্য Module.callMain(['-v'])
এর আগের কলটি সরিয়ে দেওয়া হয়েছিল। এটি এই কারণে যে Module.callMain()
একটি ফাংশন যা সাধারণত শুধুমাত্র একবার চালানোর আশা করে।
// This is `script.js`.
import loadWASM from './mkbitmap.js';
const run = async () => {
const Module = await loadWASM();
const buffer = await fetch('https://example.com/example.bmp').then((res) => res.arrayBuffer());
Module.FS.writeFile('example.bmp', new Uint8Array(buffer));
console.log(Module.FS.readdir('/'));
};
run();
প্রথম প্রকৃত মৃত্যুদন্ড
সবকিছু ঠিক রেখে, Module.callMain(['example.bmp'])
চালিয়ে mkbitmap
চালান। MEMFS' '/'
ফোল্ডারের বিষয়বস্তু লগ করুন, এবং আপনি example.bmp
ইনপুট ফাইলের পাশে নতুন তৈরি example.pbm
আউটপুট ফাইলটি দেখতে পাবেন।
// This is `script.js`.
import loadWASM from './mkbitmap.js';
const run = async () => {
const Module = await loadWASM();
const buffer = await fetch('https://example.com/example.bmp').then((res) => res.arrayBuffer());
Module.FS.writeFile('example.bmp', new Uint8Array(buffer));
Module.callMain(['example.bmp']);
console.log(Module.FS.readdir('/'));
};
run();
মেমরি ফাইল সিস্টেম থেকে আউটপুট ফাইল পান
FS
অবজেক্টের readFile()
ফাংশন মেমরি ফাইল সিস্টেমের শেষ ধাপে তৈরি example.pbm
পেতে সক্ষম করে। ফাংশনটি একটি Uint8Array
প্রদান করে যা আপনি একটি File
অবজেক্টে রূপান্তর করেন এবং ডিস্কে সংরক্ষণ করেন, কারণ ব্রাউজারগুলি সাধারণত সরাসরি ইন-ব্রাউজার দেখার জন্য PBM ফাইল সমর্থন করে না। ( একটি ফাইল সংরক্ষণ করার আরও মার্জিত উপায় আছে, কিন্তু একটি গতিশীলভাবে তৈরি <a download>
ব্যবহার করা সবচেয়ে ব্যাপকভাবে সমর্থিত।) একবার ফাইলটি সংরক্ষিত হলে, আপনি এটি আপনার প্রিয় চিত্র দর্শকে খুলতে পারেন।
// This is `script.js`.
import loadWASM from './mkbitmap.js';
const run = async () => {
const Module = await loadWASM();
const buffer = await fetch('https://example.com/example.bmp').then((res) => res.arrayBuffer());
Module.FS.writeFile('example.bmp', new Uint8Array(buffer));
Module.callMain(['example.bmp']);
const output = Module.FS.readFile('example.pbm', { encoding: 'binary' });
const file = new File([output], 'example.pbm', {
type: 'image/x-portable-bitmap',
});
const a = document.createElement('a');
a.href = URL.createObjectURL(file);
a.download = file.name;
a.click();
};
run();
একটি ইন্টারেক্টিভ UI যোগ করুন
এই মুহুর্তে, ইনপুট ফাইলটি হার্ডকোড করা হয়েছে এবং mkbitmap
ডিফল্ট প্যারামিটারের সাথে চলে। চূড়ান্ত পদক্ষেপ হল ব্যবহারকারীকে গতিশীলভাবে একটি ইনপুট ফাইল নির্বাচন করতে দেওয়া, mkbitmap
পরামিতিগুলিকে টুইক করা এবং তারপর নির্বাচিত বিকল্পগুলির সাথে টুলটি চালান।
// Corresponds to `mkbitmap -o output.pbm input.bmp -s 8 -3 -f 4 -t 0.45`.
Module.callMain(['-o', 'output.pbm', 'input.bmp', '-s', '8', '-3', '-f', '4', '-t', '0.45']);
PBM ইমেজ ফরম্যাট পার্স করা বিশেষভাবে কঠিন নয়, তাই কিছু জাভাস্ক্রিপ্ট কোড দিয়ে, আপনি আউটপুট ইমেজের একটি প্রিভিউও দেখাতে পারেন। এটি করার একটি উপায়ের জন্য নীচে এমবেডেড ডেমোর উত্স কোডটি দেখুন৷
উপসংহার
অভিনন্দন, আপনি সফলভাবে WebAssembly-তে mkbitmap
কম্পাইল করেছেন এবং এটি ব্রাউজারে কাজ করেছেন! কিছু শেষ প্রান্ত ছিল এবং এটি কাজ না হওয়া পর্যন্ত আপনাকে একাধিকবার টুলটি কম্পাইল করতে হয়েছিল, কিন্তু আমি উপরে লিখেছি, এটি অভিজ্ঞতার অংশ। আপনি আটকে গেলে StackOverflow এর webassembly
ট্যাগটিও মনে রাখবেন। শুভ কম্পাইলিং!
স্বীকৃতি
এই নিবন্ধটি স্যাম ক্লেগ এবং রাচেল অ্যান্ড্রু দ্বারা পর্যালোচনা করা হয়েছিল।
,WebAssembly কি এবং কোথা থেকে এসেছে? , আমি ব্যাখ্যা করেছি কিভাবে আমরা আজকের WebAssembly এর সাথে শেষ করেছি। এই নিবন্ধে, আমি আপনাকে একটি বিদ্যমান সি প্রোগ্রাম, mkbitmap
, WebAssembly-তে কম্পাইল করার আমার পদ্ধতি দেখাব। এটি হ্যালো ওয়ার্ল্ড উদাহরণের চেয়ে জটিল, কারণ এতে ফাইলগুলির সাথে কাজ করা, ওয়েব অ্যাসেম্বলি এবং জাভাস্ক্রিপ্ট ল্যান্ডগুলির মধ্যে যোগাযোগ করা এবং একটি ক্যানভাসে আঁকার অন্তর্ভুক্ত, তবে এটি এখনও আপনাকে অভিভূত না করার জন্য যথেষ্ট পরিচালনাযোগ্য৷
নিবন্ধটি ওয়েব ডেভেলপারদের জন্য লেখা হয়েছে যারা WebAssembly শিখতে চান এবং ধাপে ধাপে দেখায় যে আপনি যদি mkbitmap
এর মত কিছু WebAssembly-তে কম্পাইল করতে চান তাহলে আপনি কীভাবে এগিয়ে যেতে পারেন। একটি ন্যায্য সতর্কতা হিসাবে, প্রথম রানে কম্পাইল করার জন্য একটি অ্যাপ বা লাইব্রেরি না পাওয়া সম্পূর্ণ স্বাভাবিক, এই কারণেই নীচে বর্ণিত কিছু পদক্ষেপ কাজ করছে না, তাই আমাকে ব্যাকট্র্যাক করতে হবে এবং অন্যভাবে আবার চেষ্টা করতে হবে। নিবন্ধটি ম্যাজিক চূড়ান্ত সংকলন আদেশটি এমনভাবে দেখায় না যেন এটি আকাশ থেকে নেমে গেছে, বরং আমার প্রকৃত অগ্রগতি বর্ণনা করে, কিছু হতাশা অন্তর্ভুক্ত।
mkbitmap
সম্পর্কে
mkbitmap
C প্রোগ্রাম একটি চিত্র পড়ে এবং এটিতে নিম্নলিখিত এক বা একাধিক ক্রিয়াকলাপ প্রয়োগ করে, এই ক্রমে: ইনভার্সন, হাইপাস ফিল্টারিং, স্কেলিং এবং থ্রেশহোল্ডিং। প্রতিটি অপারেশন পৃথকভাবে নিয়ন্ত্রিত এবং চালু বা বন্ধ করা যেতে পারে। mkbitmap
এর প্রধান ব্যবহার হল রঙ বা গ্রেস্কেল ছবিগুলিকে অন্য প্রোগ্রামের জন্য ইনপুট হিসাবে উপযুক্ত ফর্ম্যাটে রূপান্তর করা, বিশেষ করে ট্রেসিং প্রোগ্রাম potrace
যা SVGcode- এর ভিত্তি তৈরি করে। একটি প্রিপ্রসেসিং টুল হিসেবে, mkbitmap
বিশেষভাবে স্ক্যান করা লাইন আর্ট, যেমন কার্টুন বা হাতে লেখা পাঠ্যকে উচ্চ-রেজোলিউশনের দ্বি-লেভেল ইমেজে রূপান্তর করার জন্য উপযোগী।
আপনি mkbitmap
ব্যবহার করে এটিকে অনেকগুলি অপশন এবং এক বা একাধিক ফাইলের নাম পাস করে। সমস্ত বিবরণের জন্য, টুলের ম্যান পৃষ্ঠাটি দেখুন:
$ mkbitmap [options] [filename...]
কোড পান
প্রথম ধাপ হল mkbitmap
এর সোর্স কোড প্রাপ্ত করা। আপনি প্রকল্পের ওয়েবসাইটে এটি খুঁজে পেতে পারেন। এই লেখার সময়, potrace-1.16.tar.gz সর্বশেষ সংস্করণ।
স্থানীয়ভাবে কম্পাইল এবং ইনস্টল করুন
পরবর্তী ধাপ হল টুলটি স্থানীয়ভাবে কম্পাইল করা এবং ইনস্টল করা যাতে এটি কীভাবে আচরণ করে তার অনুভূতি পেতে। INSTALL
ফাইলটিতে নিম্নলিখিত নির্দেশাবলী রয়েছে:
প্যাকেজের সোর্স কোড ধারণকারী ডিরেক্টরিতে
cd
এবং আপনার সিস্টেমের জন্য প্যাকেজ কনফিগার করতে./configure
টাইপ করুন।configure
চালানোর জন্য কিছু সময় লাগতে পারে। চালানোর সময়, এটি কোন বৈশিষ্ট্যগুলি পরীক্ষা করছে তা বলে কিছু বার্তা প্রিন্ট করে৷প্যাকেজ কম্পাইল করতে
make
টাইপ করুন।ঐচ্ছিকভাবে, প্যাকেজের সাথে আসা যেকোনো স্ব-পরীক্ষা চালানোর জন্য
make check
টাইপ করুন, সাধারণত সদ্য নির্মিত আনইনস্টল করা বাইনারি ব্যবহার করে।প্রোগ্রাম এবং যেকোনো ডেটা ফাইল এবং ডকুমেন্টেশন ইনস্টল করতে
make install
টাইপ করুন। রুটের মালিকানাধীন একটি প্রিফিক্সে ইনস্টল করার সময়, প্যাকেজটিকে নিয়মিত ব্যবহারকারী হিসাবে কনফিগার এবং তৈরি করার পরামর্শ দেওয়া হয় এবং শুধুমাত্রmake install
ফেজটি রুট সুবিধা সহ কার্যকর করা হয়।
এই পদক্ষেপগুলি অনুসরণ করে, আপনার দুটি এক্সিকিউটেবল, potrace
এবং mkbitmap
এর সাথে শেষ হওয়া উচিত — পরেরটি এই নিবন্ধের ফোকাস। আপনি mkbitmap --version
চালিয়ে এটি সঠিকভাবে কাজ করেছে তা যাচাই করতে পারেন। এখানে আমার মেশিন থেকে চারটি ধাপের আউটপুট, সংক্ষিপ্ততার জন্য ভারীভাবে ছাঁটা:
ধাপ 1, ./configure
:
$ ./configure
checking for a BSD-compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
checking for a thread-safe mkdir -p... ./install-sh -c -d
checking for gawk... no
checking for mawk... no
checking for nawk... no
checking for awk... awk
checking whether make sets $(MAKE)... yes
[…]
config.status: executing libtool commands
ধাপ 2, make
:
$ make
/Applications/Xcode.app/Contents/Developer/usr/bin/make all-recursive
Making all in src
clang -DHAVE_CONFIG_H -I. -I.. -g -O2 -MT main.o -MD -MP -MF .deps/main.Tpo -c -o main.o main.c
mv -f .deps/main.Tpo .deps/main.Po
[…]
make[2]: Nothing to be done for `all-am'.
ধাপ 3, make check
:
$ make check
Making check in src
make[1]: Nothing to be done for `check'.
Making check in doc
make[1]: Nothing to be done for `check'.
[…]
============================================================================
Testsuite summary for potrace 1.16
============================================================================
# TOTAL: 8
# PASS: 8
# SKIP: 0
# XFAIL: 0
# FAIL: 0
# XPASS: 0
# ERROR: 0
============================================================================
make[1]: Nothing to be done for `check-am'.
ধাপ 4, sudo make install
:
$ sudo make install
Password:
Making install in src
.././install-sh -c -d '/usr/local/bin'
/bin/sh ../libtool --mode=install /usr/bin/install -c potrace mkbitmap '/usr/local/bin'
[…]
make[2]: Nothing to be done for `install-data-am'.
এটি কাজ করেছে কিনা তা পরীক্ষা করতে, mkbitmap --version
চালান:
$ mkbitmap --version
mkbitmap 1.16. Copyright (C) 2001-2019 Peter Selinger.
আপনি যদি সংস্করণের বিশদ বিবরণ পান, আপনি সফলভাবে mkbitmap
কম্পাইল এবং ইনস্টল করেছেন। এরপর, WebAssembly-এর সাথে এই ধাপগুলির সমতুল্য কাজ করুন।
WebAssembly এ mkbitmap
কম্পাইল করুন
এমস্ক্রিপ্টন হ'ল সি/সি ++ প্রোগ্রামগুলি ওয়েবসেম্ব্লে সংকলনের জন্য একটি সরঞ্জাম। এমস্ক্রিপ্টের বিল্ডিং প্রকল্পগুলির ডকুমেন্টেশনগুলি নিম্নলিখিতগুলি জানিয়েছে:
এমস্ক্রিপ্টেন সহ বড় প্রকল্পগুলি তৈরি করা খুব সহজ। এমএসক্রিপ্টেন দুটি সাধারণ স্ক্রিপ্ট সরবরাহ করে যা
gcc
জন্য ড্রপ-ইন প্রতিস্থাপন হিসাবেemcc
ব্যবহার করতে আপনার মেকফাইলগুলি কনফিগার করে-বেশিরভাগ ক্ষেত্রে আপনার প্রকল্পের বাকি বর্তমান বিল্ড সিস্টেমটি অপরিবর্তিত রয়েছে।
ডকুমেন্টেশনটি তখন চলে যায় (ব্রেভিটির জন্য কিছুটা সম্পাদিত):
আপনি সাধারণত নিম্নলিখিত কমান্ডগুলি দিয়ে তৈরি করা কেসটি বিবেচনা করুন:
./configure
make
এমস্ক্রিপ্টেন দিয়ে তৈরি করতে, আপনি পরিবর্তে নিম্নলিখিত কমান্ডগুলি ব্যবহার করবেন:
emconfigure ./configure
emmake make
সুতরাং মূলত ./configure
emconfigure ./configure
হয়ে make
emmake make
নিম্নলিখিতগুলি mkbitmap
দিয়ে কীভাবে এটি করবেন তা প্রদর্শন করে।
পদক্ষেপ 0, make clean
:
$ make clean
Making clean in src
rm -f potrace mkbitmap
test -z "" || rm -f
rm -rf .libs _libs
[…]
rm -f *.lo
পদক্ষেপ 1, emconfigure ./configure
:
$ emconfigure ./configure
configure: ./configure
checking for a BSD-compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
checking for a thread-safe mkdir -p... ./install-sh -c -d
checking for gawk... no
checking for mawk... no
checking for nawk... no
checking for awk... awk
[…]
config.status: executing libtool commands
পদক্ষেপ 2, emmake make
:
$ emmake make
make: make
/Applications/Xcode.app/Contents/Developer/usr/bin/make all-recursive
Making all in src
/opt/homebrew/Cellar/emscripten/3.1.36/libexec/emcc -DHAVE_CONFIG_H -I. -I.. -g -O2 -MT main.o -MD -MP -MF .deps/main.Tpo -c -o main.o main.c
mv -f .deps/main.Tpo .deps/main.Po
[…]
make[2]: Nothing to be done for `all'.
যদি সবকিছু ঠিকঠাক হয়ে যায় তবে এখন ডিরেক্টরিতে কোথাও কোথাও ফাইল .wasm
উচিত। আপনি find . -name "*.wasm"
:
$ find . -name "*.wasm"
./a.wasm
./src/mkbitmap.wasm
./src/potrace.wasm
দুটি শেষগুলি আশাব্যঞ্জক দেখায়, তাই src/
ডিরেক্টরিতে cd
। mkbitmap
এবং potrace
এখন দুটি নতুন সংশ্লিষ্ট ফাইল রয়েছে। এই নিবন্ধটির জন্য, কেবল mkbitmap
প্রাসঙ্গিক। তাদের কাছে .js
এক্সটেনশন নেই তা কিছুটা বিভ্রান্তিকর, তবে তারা আসলে জাভাস্ক্রিপ্ট ফাইলগুলি, দ্রুত head
কল দিয়ে যাচাইযোগ্য:
$ cd src/
$ head -n 20 mkbitmap
// include: shell.js
// The Module object: Our interface to the outside world. We import
// and export values on it. There are various ways Module can be used:
// 1. Not defined. We create it here
// 2. A function parameter, function(Module) { ..generated code.. }
// 3. pre-run appended it, var Module = {}; ..generated code..
// 4. External script tag defines var Module.
// We need to check if Module already exists (e.g. case 3 above).
// Substitution will be replaced with actual code on later stage of the build,
// this way Closure Compiler will not mangle it (e.g. case 4. above).
// Note that if you want to run closure, and also to use Module
// after the generated code, you will need to define var Module = {};
// before the code. Then that object will be used in the code, and you
// can continue to use Module afterwards as well.
var Module = typeof Module != 'undefined' ? Module : {};
// --pre-jses are emitted after the Module integration code, so that they can
// refer to Module (if they choose; they can also define Module)
mv mkbitmap mkbitmap.js
(এবং mv potrace potrace.js
যথাক্রমে আপনি চাইলে) কল করে জাভাস্ক্রিপ্ট ফাইলটি mkbitmap.js
নামকরণ করুন। এখন প্রথম পরীক্ষার সময়টি দেখার সময় এসেছে যে এটি নোড.জেএস দিয়ে ফাইলটি কমান্ড লাইনে কার্যকর করে node mkbitmap.js --version
চালাচ্ছে:
$ node mkbitmap.js --version
mkbitmap 1.16. Copyright (C) 2001-2019 Peter Selinger.
আপনি সাফল্যের সাথে mkbitmap
ওয়েবসেম্বলিতে সংকলন করেছেন। এখন পরবর্তী পদক্ষেপটি হ'ল এটি ব্রাউজারে কাজ করা।
ব্রাউজারে ওয়েবসেম্বল সহ mkbitmap
mkbitmap.js
এবং mkbitmap.wasm
ফাইলগুলি mkbitmap
নামে একটি নতুন ডিরেক্টরিতে অনুলিপি করুন এবং mkbitmap.js
জাভাস্ক্রিপ্ট ফাইলটি লোড করে এমন একটি index.html
।
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>mkbitmap</title>
</head>
<body>
<script src="mkbitmap.js"></script>
</body>
</html>
একটি স্থানীয় সার্ভার শুরু করুন যা mkbitmap
ডিরেক্টরি পরিবেশন করে এবং এটি আপনার ব্রাউজারে খুলুন। আপনার একটি প্রম্পট দেখতে হবে যা আপনাকে ইনপুট জন্য জিজ্ঞাসা করে। এটি যেমনটি প্রত্যাশিত, যেহেতু, সরঞ্জামটির ম্যান পৃষ্ঠা অনুসারে , "[i] f কোনও ফাইলের নাম যুক্তি দেওয়া হয়নি, তারপরে এমকেবিটম্যাপ একটি ফিল্টার হিসাবে কাজ করে, স্ট্যান্ডার্ড ইনপুট থেকে পড়া" , যা ডিফল্টরূপে এমস্ক্রিপ্টের জন্য একটি prompt()
।
স্বয়ংক্রিয় সম্পাদন প্রতিরোধ করুন
mkbitmap
তাত্ক্ষণিকভাবে সম্পাদন করা থেকে বিরত রাখতে এবং পরিবর্তে এটি ব্যবহারকারীর ইনপুটটির জন্য অপেক্ষা করতে, আপনাকে এমএসক্রিপ্টেনের Module
অবজেক্টটি বুঝতে হবে। Module
হ'ল একটি বিশ্বব্যাপী জাভাস্ক্রিপ্ট অবজেক্ট যা এর সম্পাদনের বিভিন্ন পয়েন্টে এমএসক্রিপ্টেন-উত্পাদিত কোড কল করে এমন বৈশিষ্ট্য সহ। কোড কার্যকরকরণ নিয়ন্ত্রণ করতে আপনি Module
একটি বাস্তবায়ন সরবরাহ করতে পারেন। যখন একটি এমস্ক্রিপ্টেন অ্যাপ্লিকেশন শুরু হয়, এটি Module
অবজেক্টের মানগুলি দেখায় এবং সেগুলি প্রয়োগ করে।
mkbitmap
ক্ষেত্রে, প্রম্পটটি উপস্থিত হওয়ার কারণে প্রাথমিক রান রোধ করতে Module.noInitialRun
সেট করুন true
script.js
নামে একটি স্ক্রিপ্ট তৈরি করুন, এটি <script src="mkbitmap.js"></script>
index.html
এর আগে অন্তর্ভুক্ত করুন এবং script.js
নিম্নলিখিত কোডটি যুক্ত করুন। আপনি যখন এখন অ্যাপটি পুনরায় লোড করবেন তখন প্রম্পটটি চলে যাওয়া উচিত।
var Module = {
// Don't run main() at page load
noInitialRun: true,
};
আরও কিছু বিল্ড ফ্ল্যাগ সহ একটি মডুলার বিল্ড তৈরি করুন
অ্যাপটিতে ইনপুট সরবরাহ করতে, আপনি Module.FS
এমএসক্রিপ্টের ফাইল সিস্টেম সমর্থন ব্যবহার করতে পারেন। ডকুমেন্টেশনের ফাইল সিস্টেম সমর্থন বিভাগ সহ :
এমস্ক্রিপ্টেন সিদ্ধান্ত নেয় যে ফাইল সিস্টেম সমর্থন স্বয়ংক্রিয়ভাবে অন্তর্ভুক্ত করা উচিত কিনা। অনেক প্রোগ্রামের ফাইলের প্রয়োজন হয় না, এবং ফাইল সিস্টেম সমর্থন আকারে নগণ্য নয়, তাই এমএসক্রিপ্টেন এড়িয়ে চলে যখন এটি কোনও কারণ দেখেন না। এর অর্থ হ'ল যদি আপনার সি/সি ++ কোড ফাইলগুলি অ্যাক্সেস না করে তবে
FS
অবজেক্ট এবং অন্যান্য ফাইল সিস্টেমের এপিআইগুলি আউটপুটটিতে অন্তর্ভুক্ত করা হবে না। এবং অন্যদিকে, যদি আপনার সি/সি ++ কোড ফাইল ব্যবহার করে, তবে ফাইল সিস্টেম সমর্থন স্বয়ংক্রিয়ভাবে অন্তর্ভুক্ত করা হবে।
দুর্ভাগ্যক্রমে mkbitmap
এমন একটি ক্ষেত্রে যেখানে এমএসক্রিপ্টেন স্বয়ংক্রিয়ভাবে ফাইল সিস্টেম সমর্থন অন্তর্ভুক্ত করে না, তাই আপনাকে এটি করার জন্য স্পষ্টভাবে এটি বলতে হবে। এর অর্থ আপনাকে CFLAGS
আর্গুমেন্টের মাধ্যমে আরও কয়েকটি পতাকা সেট করে পূর্বে বর্ণিত emconfigure
এবং emmake
পদক্ষেপগুলি অনুসরণ করতে হবে। নিম্নলিখিত পতাকাগুলি অন্যান্য প্রকল্পগুলির জন্যও কার্যকর হতে পারে।
- সেট
-sFILESYSTEM=1
সুতরাং ফাইল সিস্টেম সমর্থন অন্তর্ভুক্ত করা হয়েছে। - সেট
-sEXPORTED_RUNTIME_METHODS=FS,callMain
এসওModule.FS
এবংModule.callMain
রফতানি করা হয়। - একটি আধুনিক ইএস 6 মডিউল তৈরি করতে
-sMODULARIZE=1
এবং-sEXPORT_ES6
সেট করুন। - প্রম্পটটি উপস্থিত হওয়ার কারণে প্রাথমিক রান রোধ করতে সেট
-sINVOKE_RUN=0
সেট করুন।
এছাড়াও, এই বিশেষ ক্ষেত্রে, আপনি ওয়েবসেম্বলির জন্য সংকলন করছেন এমন configure
স্ক্রিপ্টটি বলতে আপনাকে --host
ফ্ল্যাগটি wasm32
এ সেট করতে হবে।
চূড়ান্ত emconfigure
কমান্ডটি এর মতো দেখাচ্ছে:
$ emconfigure ./configure --host=wasm32 CFLAGS='-sFILESYSTEM=1 -sEXPORTED_RUNTIME_METHODS=FS,callMain -sMODULARIZE=1 -sEXPORT_ES6 -sINVOKE_RUN=0'
emmake make
আবার চালাতে ভুলবেন না এবং mkbitmap
ফোল্ডারে নতুনভাবে তৈরি ফাইলগুলি অনুলিপি করুন।
index.html
সংশোধন mkbitmap.js
script.js
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>mkbitmap</title>
</head>
<body>
<!-- No longer load `mkbitmap.js` here -->
<script src="script.js" type="module"></script>
</body>
</html>
// This is `script.js`.
import loadWASM from './mkbitmap.js';
const run = async () => {
const Module = await loadWASM();
console.log(Module);
};
run();
আপনি যখন ব্রাউজারে এখনই অ্যাপটি খুলবেন, আপনার Module
অবজেক্টটি ডেভটুলস কনসোলে লগ ইন করা উচিত এবং প্রম্পটটি চলে গেছে, যেহেতু mkbitmap
main()
ফাংশনটি আর শুরুতে কল করা হয় না।
ম্যানুয়ালি মূল ফাংশনটি সম্পাদন করুন
পরবর্তী পদক্ষেপটি হ'ল ম্যানুয়ালি mkbitmap
এর main()
ফাংশনটি Module.callMain()
চালিয়ে কল করা। callMain()
ফাংশনটি আর্গুমেন্টের একটি অ্যারে নেয়, যা আপনি কমান্ড লাইনে যা পাস করবেন তা একের পর এক মেলে। যদি কমান্ড লাইনে আপনি mkbitmap -v
চালনা করেন তবে আপনি ব্রাউজারে Module.callMain(['-v'])
কল করবেন। এটি ডিভটুলস কনসোলে mkbitmap
সংস্করণ নম্বরটি লগ করে।
// This is `script.js`.
import loadWASM from './mkbitmap.js';
const run = async () => {
const Module = await loadWASM();
Module.callMain(['-v']);
};
run();
স্ট্যান্ডার্ড আউটপুট পুনঃনির্দেশ
ডিফল্টরূপে স্ট্যান্ডার্ড আউটপুট ( stdout
) হ'ল কনসোল। তবে, আপনি এটিকে অন্য কোনও কিছুতে পুনর্নির্দেশ করতে পারেন, উদাহরণস্বরূপ, এমন একটি ফাংশন যা আউটপুটটিকে একটি ভেরিয়েবলে সঞ্চয় করে। এর অর্থ আপনি Module.print
সম্পত্তি সেট করে এইচটিএমএলে আউটপুট যুক্ত করতে পারেন।
// This is `script.js`.
import loadWASM from './mkbitmap.js';
const run = async () => {
let consoleOutput = 'Powered by ';
const Module = await loadWASM({
print: (text) => (consoleOutput += text),
});
Module.callMain(['-v']);
document.body.textContent = consoleOutput;
};
run();
মেমরি ফাইল সিস্টেমে ইনপুট ফাইলটি পান
মেমরি ফাইল সিস্টেমে ইনপুট ফাইলটি পেতে আপনার কমান্ড লাইনে mkbitmap filename
সমতুল্য প্রয়োজন। আমি কীভাবে এটির কাছে পৌঁছেছি তা বুঝতে, প্রথমে mkbitmap
কীভাবে তার ইনপুটটি প্রত্যাশা করে এবং এর আউটপুট তৈরি করে তার কিছু ব্যাকগ্রাউন্ড।
mkbitmap
সমর্থিত ইনপুট ফর্ম্যাটগুলি হ'ল পিএনএম ( পিবিএম , পিজিএম , পিপিএম ) এবং বিএমপি । আউটপুট ফর্ম্যাটগুলি বিটম্যাপগুলির জন্য পিবিএম এবং গ্রিম্যাপগুলির জন্য পিজিএম। যদি কোনও filename
যুক্তি দেওয়া হয়, mkbitmap
ডিফল্টরূপে একটি আউটপুট ফাইল তৈরি করবে যার নাম ইনপুট ফাইলের নাম থেকে এর প্রত্যয়টি .pbm
এ পরিবর্তন করে প্রাপ্ত হয়। উদাহরণস্বরূপ, ইনপুট ফাইলের নাম example.bmp
-র জন্য, আউটপুট ফাইলের নামটি example.pbm
হবে P
এমস্ক্রিপ্টেন একটি ভার্চুয়াল ফাইল সিস্টেম সরবরাহ করে যা স্থানীয় ফাইল সিস্টেমকে অনুকরণ করে, যাতে সিঙ্ক্রোনাস ফাইল এপিআই ব্যবহার করে নেটিভ কোডটি সংকলন করা যায় এবং সামান্য বা কোনও পরিবর্তন ছাড়াই চালানো যায়। mkbitmap
জন্য কোনও ইনপুট ফাইলটি পড়ার জন্য যেমন এটি filename
কমান্ড লাইন যুক্তি হিসাবে পাস করা হয়েছে, আপনাকে এমস্ক্রিপ্টেন সরবরাহ করে এমন FS
অবজেক্টটি ব্যবহার করতে হবে।
FS
অবজেক্টটি একটি ইন-মেমরি ফাইল সিস্টেম দ্বারা সমর্থিত (সাধারণত এমইএমএফএস হিসাবে পরিচিত) এবং ভার্চুয়াল ফাইল সিস্টেমে ফাইলগুলি লেখার জন্য আপনি একটি writeFile()
ফাংশন রয়েছে যা আপনি ব্যবহার করেন। আপনি নিম্নলিখিত কোড নমুনায় প্রদর্শিত হিসাবে writeFile()
ব্যবহার করেন।
ফাইল লেখার অপারেশনটি যাচাই করতে, FS
অবজেক্টের readdir()
ফাংশনটি প্যারামিটার '/'
দিয়ে চালান। আপনি example.bmp
এবং বেশ কয়েকটি ডিফল্ট ফাইল দেখতে পাবেন যা সর্বদা স্বয়ংক্রিয়ভাবে তৈরি হয় ।
নোট করুন যে সংস্করণ নম্বর মুদ্রণের জন্য Module.callMain(['-v'])
এর আগের কলটি সরানো হয়েছিল। এটি Module.callMain()
এমন একটি ফাংশন যা সাধারণত একবারে চালানোর প্রত্যাশা করে।
// This is `script.js`.
import loadWASM from './mkbitmap.js';
const run = async () => {
const Module = await loadWASM();
const buffer = await fetch('https://example.com/example.bmp').then((res) => res.arrayBuffer());
Module.FS.writeFile('example.bmp', new Uint8Array(buffer));
console.log(Module.FS.readdir('/'));
};
run();
প্রথম প্রকৃত সম্পাদন
জায়গায় থাকা সমস্ত কিছুর সাথে, Module.callMain(['example.bmp'])
চালিয়ে mkbitmap
সম্পাদন করুন। এমইএমএফএস ' '/'
ফোল্ডারের বিষয়বস্তু লগ করুন এবং আপনার সদ্য নির্মিত example.pbm
দেখতে হবে example.bmp
// This is `script.js`.
import loadWASM from './mkbitmap.js';
const run = async () => {
const Module = await loadWASM();
const buffer = await fetch('https://example.com/example.bmp').then((res) => res.arrayBuffer());
Module.FS.writeFile('example.bmp', new Uint8Array(buffer));
Module.callMain(['example.bmp']);
console.log(Module.FS.readdir('/'));
};
run();
মেমরি ফাইল সিস্টেমের বাইরে আউটপুট ফাইলটি পান
FS
অবজেক্টের readFile()
ফাংশনটি মেমরি ফাইল সিস্টেমের শেষ ধাপে তৈরি example.pbm
তৈরি করতে সক্ষম করে। ফাংশনটি এমন একটি Uint8Array
ফেরত দেয় যা আপনি কোনও File
অবজেক্টে রূপান্তর করেন এবং ডিস্কে সংরক্ষণ করেন, কারণ ব্রাউজারগুলি সাধারণত ব্রাউজার দেখার জন্য পিবিএম ফাইলগুলিকে সমর্থন করে না। ( কোনও ফাইল সংরক্ষণের আরও মার্জিত উপায় রয়েছে তবে গতিশীলভাবে তৈরি করা <a download>
ব্যবহার করা সর্বাধিক বহুল সমর্থিত)) ফাইলটি সংরক্ষণ করা হলে আপনি এটি আপনার প্রিয় চিত্র দর্শকের মধ্যে খুলতে পারেন।
// This is `script.js`.
import loadWASM from './mkbitmap.js';
const run = async () => {
const Module = await loadWASM();
const buffer = await fetch('https://example.com/example.bmp').then((res) => res.arrayBuffer());
Module.FS.writeFile('example.bmp', new Uint8Array(buffer));
Module.callMain(['example.bmp']);
const output = Module.FS.readFile('example.pbm', { encoding: 'binary' });
const file = new File([output], 'example.pbm', {
type: 'image/x-portable-bitmap',
});
const a = document.createElement('a');
a.href = URL.createObjectURL(file);
a.download = file.name;
a.click();
};
run();
একটি ইন্টারেক্টিভ ইউআই যুক্ত করুন
এই মুহুর্তে, ইনপুট ফাইলটি হার্ডকোডড এবং mkbitmap
ডিফল্ট পরামিতিগুলির সাথে চলে। চূড়ান্ত পদক্ষেপটি হ'ল ব্যবহারকারীকে গতিশীলভাবে একটি ইনপুট ফাইল নির্বাচন করা, mkbitmap
প্যারামিটারগুলি টুইট করা এবং তারপরে নির্বাচিত বিকল্পগুলির সাথে সরঞ্জামটি চালানো।
// Corresponds to `mkbitmap -o output.pbm input.bmp -s 8 -3 -f 4 -t 0.45`.
Module.callMain(['-o', 'output.pbm', 'input.bmp', '-s', '8', '-3', '-f', '4', '-t', '0.45']);
পিবিএম চিত্রের ফর্ম্যাটটি পার্স করা বিশেষভাবে শক্ত নয়, তাই কিছু জাভাস্ক্রিপ্ট কোডের সাহায্যে আপনি আউটপুট চিত্রের একটি পূর্বরূপও দেখাতে পারেন। এটি করার এক উপায়ের জন্য নীচের এম্বেড থাকা ডেমোর উত্স কোডটি দেখুন।
উপসংহার
অভিনন্দন, আপনি সাফল্যের সাথে mkbitmap
ওয়েবসেম্পলিতে সংকলন করেছেন এবং এটি ব্রাউজারে কাজ করেছেন! কিছু মৃত প্রান্ত ছিল এবং এটি কাজ না করা পর্যন্ত আপনাকে সরঞ্জামটি একাধিকবার সংকলন করতে হয়েছিল, তবে আমি উপরে লিখেছি, এটি অভিজ্ঞতার অংশ। আপনি যদি আটকে যান তবে স্ট্যাকওভারফ্লোর webassembly
ট্যাগটিও মনে রাখবেন। শুভ সংকলন!
স্বীকৃতি
এই নিবন্ধটি স্যাম ক্লেগ এবং রাহেল অ্যান্ড্রু পর্যালোচনা করেছেন।
,ওয়েবসেম্বলি কী এবং এটি কোথা থেকে এসেছে? , আমি ব্যাখ্যা করেছি যে আমরা কীভাবে আজকের ওয়েবসেম্বলিটি দিয়ে শেষ করেছি। এই নিবন্ধে, আমি আপনাকে একটি বিদ্যমান সি প্রোগ্রাম, mkbitmap
সংকলন করার জন্য আমার পদ্ধতির ওয়েবসেম্বিতে দেখাব। এটি হ্যালো ওয়ার্ল্ড উদাহরণের চেয়ে আরও জটিল, কারণ এটিতে ফাইলগুলির সাথে কাজ করা, ওয়েবসেম্বলি এবং জাভাস্ক্রিপ্ট জমিগুলির মধ্যে যোগাযোগ করা এবং একটি ক্যানভাসে অঙ্কন অন্তর্ভুক্ত রয়েছে তবে এটি আপনাকে অভিভূত না করার পক্ষে এখনও যথেষ্ট পরিচালনাযোগ্য।
নিবন্ধটি ওয়েব বিকাশকারীদের জন্য লেখা হয়েছে যারা ওয়েবসেম্বলি শিখতে চান এবং ধাপে ধাপে দেখায় যে আপনি যদি mkbitmap
মতো কিছু সংকলন করতে চান তবে আপনি কীভাবে এগিয়ে যেতে পারেন। ন্যায্য সতর্কতা হিসাবে, প্রথম রানে সংকলন করার জন্য কোনও অ্যাপ্লিকেশন বা গ্রন্থাগার না পাওয়া সম্পূর্ণ স্বাভাবিক, এ কারণেই নীচে বর্ণিত কয়েকটি পদক্ষেপ কাজ না করে শেষ হয়েছিল, তাই আমার ব্যাকট্র্যাক করা দরকার এবং আবার আলাদাভাবে চেষ্টা করা দরকার। নিবন্ধটি ম্যাজিক ফাইনাল সংকলন কমান্ডটি এমনভাবে দেখায় না যেন এটি আকাশ থেকে নেমে গেছে, বরং আমার আসল অগ্রগতি বর্ণনা করে, কিছু হতাশা অন্তর্ভুক্ত।
mkbitmap
সম্পর্কে
mkbitmap
সি প্রোগ্রামটি একটি চিত্র পড়ে এবং এই ক্রমে এটিতে নিম্নলিখিত এক বা একাধিক ক্রিয়াকলাপ প্রয়োগ করে: বিপরীত, হাইপাস ফিল্টারিং, স্কেলিং এবং থ্রেশহোল্ডিং। প্রতিটি অপারেশন স্বতন্ত্রভাবে নিয়ন্ত্রিত এবং চালু বা বন্ধ করা যেতে পারে। mkbitmap
মূল ব্যবহার হ'ল রঙ বা গ্রেস্কেল চিত্রগুলিকে অন্যান্য প্রোগ্রামগুলির ইনপুট হিসাবে উপযুক্ত ফর্ম্যাটে রূপান্তর করা, বিশেষত ট্রেসিং প্রোগ্রাম potrace
যা এসভিজকোডের ভিত্তি তৈরি করে। প্রিপ্রোসেসিং সরঞ্জাম হিসাবে, mkbitmap
উচ্চ-রেজোলিউশন বিলেভেল চিত্রগুলিতে কার্টুন বা হস্তাক্ষর পাঠ্য হিসাবে স্ক্যান করা লাইন শিল্পকে রূপান্তর করার জন্য বিশেষভাবে কার্যকর।
আপনি mkbitmap
বেশ কয়েকটি বিকল্প এবং এক বা একাধিক ফাইলের নাম পাস করে ব্যবহার করেন। সমস্ত তথ্যের জন্য, সরঞ্জামটির ম্যান পৃষ্ঠা দেখুন:
$ mkbitmap [options] [filename...]
কোড পান
প্রথম পদক্ষেপটি mkbitmap
উত্স কোডটি অর্জন করা। আপনি এটি প্রকল্পের ওয়েবসাইটে খুঁজে পেতে পারেন। এই লেখার সময়, পট্রেস -1.16.tar.gz সর্বশেষতম সংস্করণ।
স্থানীয়ভাবে সংকলন করুন এবং ইনস্টল করুন
পরবর্তী পদক্ষেপটি হ'ল এটি কীভাবে আচরণ করে তার অনুভূতি পেতে স্থানীয়ভাবে সরঞ্জামটি সংকলন করা এবং ইনস্টল করা। INSTALL
ফাইলটিতে নিম্নলিখিত নির্দেশাবলী রয়েছে:
আপনার সিস্টেমের জন্য প্যাকেজটি কনফিগার করতে প্যাকেজের উত্স কোড এবং টাইপ
./configure
সহ ডিরেক্টরিতেcd
।চলমান
configure
কিছুটা সময় নিতে পারে। চালানোর সময়, এটি কোন বৈশিষ্ট্যগুলি পরীক্ষা করছে তা বলে কিছু বার্তা প্রিন্ট করে৷প্যাকেজ সংকলন করতে টাইপ
make
।Ally চ্ছিকভাবে, প্যাকেজের সাথে আসা যে কোনও স্ব-পরীক্ষা চালানোর জন্য টাইপ
make check
, সাধারণত সবেমাত্র নির্মিত আনইনস্টলযুক্ত বাইনারিগুলি ব্যবহার করে।প্রোগ্রামগুলি এবং কোনও ডেটা ফাইল এবং ডকুমেন্টেশন ইনস্টল করতে
make install
। রুটের মালিকানাধীন একটি উপসর্গে ইনস্টল করার সময়, এটি প্যাকেজটি নিয়মিত ব্যবহারকারী হিসাবে কনফিগার করা এবং নির্মিত হওয়ার পরামর্শ দেওয়া হয় এবং কেবলমাত্রmake install
ফেজটি মূলের সুবিধাগুলি দিয়ে কার্যকর করা হয়।
এই পদক্ষেপগুলি অনুসরণ করে, আপনার দুটি এক্সিকিউটেবল, potrace
এবং mkbitmap
দিয়ে শেষ করা উচিত - পরবর্তীটি এই নিবন্ধটির কেন্দ্রবিন্দু। আপনি mkbitmap --version
চালিয়ে সঠিকভাবে কাজ করেছেন তা যাচাই করতে পারেন। এখানে আমার মেশিন থেকে চারটি ধাপের আউটপুট রয়েছে, ব্রেভিটির জন্য ভারী ছাঁটাই করা হয়েছে:
পদক্ষেপ 1, ./configure
:
$ ./configure
checking for a BSD-compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
checking for a thread-safe mkdir -p... ./install-sh -c -d
checking for gawk... no
checking for mawk... no
checking for nawk... no
checking for awk... awk
checking whether make sets $(MAKE)... yes
[…]
config.status: executing libtool commands
পদক্ষেপ 2, make
:
$ make
/Applications/Xcode.app/Contents/Developer/usr/bin/make all-recursive
Making all in src
clang -DHAVE_CONFIG_H -I. -I.. -g -O2 -MT main.o -MD -MP -MF .deps/main.Tpo -c -o main.o main.c
mv -f .deps/main.Tpo .deps/main.Po
[…]
make[2]: Nothing to be done for `all-am'.
পদক্ষেপ 3, make check
:
$ make check
Making check in src
make[1]: Nothing to be done for `check'.
Making check in doc
make[1]: Nothing to be done for `check'.
[…]
============================================================================
Testsuite summary for potrace 1.16
============================================================================
# TOTAL: 8
# PASS: 8
# SKIP: 0
# XFAIL: 0
# FAIL: 0
# XPASS: 0
# ERROR: 0
============================================================================
make[1]: Nothing to be done for `check-am'.
পদক্ষেপ 4, sudo make install
:
$ sudo make install
Password:
Making install in src
.././install-sh -c -d '/usr/local/bin'
/bin/sh ../libtool --mode=install /usr/bin/install -c potrace mkbitmap '/usr/local/bin'
[…]
make[2]: Nothing to be done for `install-data-am'.
এটি কাজ করেছে কিনা তা যাচাই করতে, mkbitmap --version
:
$ mkbitmap --version
mkbitmap 1.16. Copyright (C) 2001-2019 Peter Selinger.
আপনি যদি সংস্করণ বিশদটি পান তবে আপনি সফলভাবে সংকলন করেছেন এবং mkbitmap
ইনস্টল করেছেন। এরপরে, এই পদক্ষেপগুলির সমতুল্য করুন ওয়েবসেম্বলির সাথে কাজ করুন।
ওয়েবসেম্বিতে mkbitmap
সংকলন করুন
এমস্ক্রিপ্টন হ'ল সি/সি ++ প্রোগ্রামগুলি ওয়েবসেম্ব্লে সংকলনের জন্য একটি সরঞ্জাম। এমস্ক্রিপ্টের বিল্ডিং প্রকল্পগুলির ডকুমেন্টেশনগুলি নিম্নলিখিতগুলি জানিয়েছে:
এমস্ক্রিপ্টেন সহ বড় প্রকল্পগুলি তৈরি করা খুব সহজ। এমএসক্রিপ্টেন দুটি সাধারণ স্ক্রিপ্ট সরবরাহ করে যা
gcc
জন্য ড্রপ-ইন প্রতিস্থাপন হিসাবেemcc
ব্যবহার করতে আপনার মেকফাইলগুলি কনফিগার করে-বেশিরভাগ ক্ষেত্রে আপনার প্রকল্পের বাকি বর্তমান বিল্ড সিস্টেমটি অপরিবর্তিত রয়েছে।
ডকুমেন্টেশনটি তখন চলে যায় (ব্রেভিটির জন্য কিছুটা সম্পাদিত):
আপনি সাধারণত নিম্নলিখিত কমান্ডগুলি দিয়ে তৈরি করা কেসটি বিবেচনা করুন:
./configure
make
এমস্ক্রিপ্টেন দিয়ে তৈরি করতে, আপনি পরিবর্তে নিম্নলিখিত কমান্ডগুলি ব্যবহার করবেন:
emconfigure ./configure
emmake make
সুতরাং মূলত ./configure
emconfigure ./configure
হয়ে make
emmake make
নিম্নলিখিতগুলি mkbitmap
দিয়ে কীভাবে এটি করবেন তা প্রদর্শন করে।
পদক্ষেপ 0, make clean
:
$ make clean
Making clean in src
rm -f potrace mkbitmap
test -z "" || rm -f
rm -rf .libs _libs
[…]
rm -f *.lo
পদক্ষেপ 1, emconfigure ./configure
:
$ emconfigure ./configure
configure: ./configure
checking for a BSD-compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
checking for a thread-safe mkdir -p... ./install-sh -c -d
checking for gawk... no
checking for mawk... no
checking for nawk... no
checking for awk... awk
[…]
config.status: executing libtool commands
পদক্ষেপ 2, emmake make
:
$ emmake make
make: make
/Applications/Xcode.app/Contents/Developer/usr/bin/make all-recursive
Making all in src
/opt/homebrew/Cellar/emscripten/3.1.36/libexec/emcc -DHAVE_CONFIG_H -I. -I.. -g -O2 -MT main.o -MD -MP -MF .deps/main.Tpo -c -o main.o main.c
mv -f .deps/main.Tpo .deps/main.Po
[…]
make[2]: Nothing to be done for `all'.
যদি সবকিছু ঠিকঠাক হয়ে যায় তবে এখন ডিরেক্টরিতে কোথাও কোথাও ফাইল .wasm
উচিত। আপনি find . -name "*.wasm"
:
$ find . -name "*.wasm"
./a.wasm
./src/mkbitmap.wasm
./src/potrace.wasm
দুটি শেষগুলি আশাব্যঞ্জক দেখায়, তাই src/
ডিরেক্টরিতে cd
। mkbitmap
এবং potrace
এখন দুটি নতুন সংশ্লিষ্ট ফাইল রয়েছে। এই নিবন্ধটির জন্য, কেবল mkbitmap
প্রাসঙ্গিক। তাদের কাছে .js
এক্সটেনশন নেই তা কিছুটা বিভ্রান্তিকর, তবে তারা আসলে জাভাস্ক্রিপ্ট ফাইলগুলি, দ্রুত head
কল দিয়ে যাচাইযোগ্য:
$ cd src/
$ head -n 20 mkbitmap
// include: shell.js
// The Module object: Our interface to the outside world. We import
// and export values on it. There are various ways Module can be used:
// 1. Not defined. We create it here
// 2. A function parameter, function(Module) { ..generated code.. }
// 3. pre-run appended it, var Module = {}; ..generated code..
// 4. External script tag defines var Module.
// We need to check if Module already exists (e.g. case 3 above).
// Substitution will be replaced with actual code on later stage of the build,
// this way Closure Compiler will not mangle it (e.g. case 4. above).
// Note that if you want to run closure, and also to use Module
// after the generated code, you will need to define var Module = {};
// before the code. Then that object will be used in the code, and you
// can continue to use Module afterwards as well.
var Module = typeof Module != 'undefined' ? Module : {};
// --pre-jses are emitted after the Module integration code, so that they can
// refer to Module (if they choose; they can also define Module)
mv mkbitmap mkbitmap.js
(এবং mv potrace potrace.js
যথাক্রমে আপনি চাইলে) কল করে জাভাস্ক্রিপ্ট ফাইলটি mkbitmap.js
নামকরণ করুন। এখন প্রথম পরীক্ষার সময়টি দেখার সময় এসেছে যে এটি নোড.জেএস দিয়ে ফাইলটি কমান্ড লাইনে কার্যকর করে node mkbitmap.js --version
চালাচ্ছে:
$ node mkbitmap.js --version
mkbitmap 1.16. Copyright (C) 2001-2019 Peter Selinger.
আপনি সাফল্যের সাথে mkbitmap
ওয়েবসেম্বলিতে সংকলন করেছেন। এখন পরবর্তী পদক্ষেপটি হ'ল এটি ব্রাউজারে কাজ করা।
ব্রাউজারে ওয়েবসেম্বল সহ mkbitmap
mkbitmap.js
এবং mkbitmap.wasm
ফাইলগুলি mkbitmap
নামে একটি নতুন ডিরেক্টরিতে অনুলিপি করুন এবং mkbitmap.js
জাভাস্ক্রিপ্ট ফাইলটি লোড করে এমন একটি index.html
।
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>mkbitmap</title>
</head>
<body>
<script src="mkbitmap.js"></script>
</body>
</html>
একটি স্থানীয় সার্ভার শুরু করুন যা mkbitmap
ডিরেক্টরি পরিবেশন করে এবং এটি আপনার ব্রাউজারে খুলুন। আপনার একটি প্রম্পট দেখতে হবে যা আপনাকে ইনপুট জন্য জিজ্ঞাসা করে। এটি যেমনটি প্রত্যাশিত, যেহেতু, সরঞ্জামটির ম্যান পৃষ্ঠা অনুসারে , "[i] f কোনও ফাইলের নাম যুক্তি দেওয়া হয়নি, তারপরে এমকেবিটম্যাপ একটি ফিল্টার হিসাবে কাজ করে, স্ট্যান্ডার্ড ইনপুট থেকে পড়া" , যা ডিফল্টরূপে এমস্ক্রিপ্টের জন্য একটি prompt()
।
স্বয়ংক্রিয় সম্পাদন প্রতিরোধ করুন
mkbitmap
তাত্ক্ষণিকভাবে সম্পাদন করা থেকে বিরত রাখতে এবং পরিবর্তে এটি ব্যবহারকারীর ইনপুটটির জন্য অপেক্ষা করতে, আপনাকে এমএসক্রিপ্টেনের Module
অবজেক্টটি বুঝতে হবে। Module
হ'ল একটি বিশ্বব্যাপী জাভাস্ক্রিপ্ট অবজেক্ট যা এর সম্পাদনের বিভিন্ন পয়েন্টে এমএসক্রিপ্টেন-উত্পাদিত কোড কল করে এমন বৈশিষ্ট্য সহ। কোড কার্যকরকরণ নিয়ন্ত্রণ করতে আপনি Module
একটি বাস্তবায়ন সরবরাহ করতে পারেন। যখন একটি এমস্ক্রিপ্টেন অ্যাপ্লিকেশন শুরু হয়, এটি Module
অবজেক্টের মানগুলি দেখায় এবং সেগুলি প্রয়োগ করে।
mkbitmap
ক্ষেত্রে, প্রম্পটটি উপস্থিত হওয়ার কারণে প্রাথমিক রান রোধ করতে Module.noInitialRun
সেট করুন true
script.js
নামে একটি স্ক্রিপ্ট তৈরি করুন, এটি <script src="mkbitmap.js"></script>
index.html
এর আগে অন্তর্ভুক্ত করুন এবং script.js
নিম্নলিখিত কোডটি যুক্ত করুন। আপনি যখন এখন অ্যাপটি পুনরায় লোড করবেন তখন প্রম্পটটি চলে যাওয়া উচিত।
var Module = {
// Don't run main() at page load
noInitialRun: true,
};
আরও কিছু বিল্ড ফ্ল্যাগ সহ একটি মডুলার বিল্ড তৈরি করুন
অ্যাপটিতে ইনপুট সরবরাহ করতে, আপনি Module.FS
এমএসক্রিপ্টের ফাইল সিস্টেম সমর্থন ব্যবহার করতে পারেন। ডকুমেন্টেশনের ফাইল সিস্টেম সমর্থন বিভাগ সহ :
এমস্ক্রিপ্টেন সিদ্ধান্ত নেয় যে ফাইল সিস্টেম সমর্থন স্বয়ংক্রিয়ভাবে অন্তর্ভুক্ত করা উচিত কিনা। অনেক প্রোগ্রামের ফাইলের প্রয়োজন হয় না, এবং ফাইল সিস্টেম সমর্থন আকারে নগণ্য নয়, তাই এমএসক্রিপ্টেন এড়িয়ে চলে যখন এটি কোনও কারণ দেখেন না। এর অর্থ হ'ল যদি আপনার সি/সি ++ কোড ফাইলগুলি অ্যাক্সেস না করে তবে
FS
অবজেক্ট এবং অন্যান্য ফাইল সিস্টেমের এপিআইগুলি আউটপুটটিতে অন্তর্ভুক্ত করা হবে না। এবং অন্যদিকে, যদি আপনার সি/সি ++ কোড ফাইল ব্যবহার করে, তবে ফাইল সিস্টেম সমর্থন স্বয়ংক্রিয়ভাবে অন্তর্ভুক্ত করা হবে।
দুর্ভাগ্যক্রমে mkbitmap
এমন একটি ক্ষেত্রে যেখানে এমএসক্রিপ্টেন স্বয়ংক্রিয়ভাবে ফাইল সিস্টেম সমর্থন অন্তর্ভুক্ত করে না, তাই আপনাকে এটি করার জন্য স্পষ্টভাবে এটি বলতে হবে। এর অর্থ আপনাকে CFLAGS
আর্গুমেন্টের মাধ্যমে আরও কয়েকটি পতাকা সেট করে পূর্বে বর্ণিত emconfigure
এবং emmake
পদক্ষেপগুলি অনুসরণ করতে হবে। নিম্নলিখিত পতাকাগুলি অন্যান্য প্রকল্পগুলির জন্যও কার্যকর হতে পারে।
- সেট
-sFILESYSTEM=1
সুতরাং ফাইল সিস্টেম সমর্থন অন্তর্ভুক্ত করা হয়েছে। - সেট
-sEXPORTED_RUNTIME_METHODS=FS,callMain
এসওModule.FS
এবংModule.callMain
রফতানি করা হয়। - একটি আধুনিক ইএস 6 মডিউল তৈরি করতে
-sMODULARIZE=1
এবং-sEXPORT_ES6
সেট করুন। - প্রম্পটটি উপস্থিত হওয়ার কারণে প্রাথমিক রান রোধ করতে সেট
-sINVOKE_RUN=0
সেট করুন।
এছাড়াও, এই বিশেষ ক্ষেত্রে, আপনি ওয়েবসেম্বলির জন্য সংকলন করছেন এমন configure
স্ক্রিপ্টটি বলতে আপনাকে --host
ফ্ল্যাগটি wasm32
এ সেট করতে হবে।
চূড়ান্ত emconfigure
কমান্ডটি এর মতো দেখাচ্ছে:
$ emconfigure ./configure --host=wasm32 CFLAGS='-sFILESYSTEM=1 -sEXPORTED_RUNTIME_METHODS=FS,callMain -sMODULARIZE=1 -sEXPORT_ES6 -sINVOKE_RUN=0'
emmake make
আবার চালাতে ভুলবেন না এবং mkbitmap
ফোল্ডারে নতুনভাবে তৈরি ফাইলগুলি অনুলিপি করুন।
index.html
সংশোধন mkbitmap.js
script.js
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>mkbitmap</title>
</head>
<body>
<!-- No longer load `mkbitmap.js` here -->
<script src="script.js" type="module"></script>
</body>
</html>
// This is `script.js`.
import loadWASM from './mkbitmap.js';
const run = async () => {
const Module = await loadWASM();
console.log(Module);
};
run();
আপনি যখন ব্রাউজারে এখনই অ্যাপটি খুলবেন, আপনার Module
অবজেক্টটি ডেভটুলস কনসোলে লগ ইন করা উচিত এবং প্রম্পটটি চলে গেছে, যেহেতু mkbitmap
main()
ফাংশনটি আর শুরুতে কল করা হয় না।
ম্যানুয়ালি মূল ফাংশনটি সম্পাদন করুন
পরবর্তী পদক্ষেপটি হ'ল ম্যানুয়ালি mkbitmap
এর main()
ফাংশনটি Module.callMain()
চালিয়ে কল করা। callMain()
ফাংশনটি আর্গুমেন্টের একটি অ্যারে নেয়, যা আপনি কমান্ড লাইনে যা পাস করবেন তা একের পর এক মেলে। যদি কমান্ড লাইনে আপনি mkbitmap -v
চালনা করেন তবে আপনি ব্রাউজারে Module.callMain(['-v'])
কল করবেন। এটি ডিভটুলস কনসোলে mkbitmap
সংস্করণ নম্বরটি লগ করে।
// This is `script.js`.
import loadWASM from './mkbitmap.js';
const run = async () => {
const Module = await loadWASM();
Module.callMain(['-v']);
};
run();
স্ট্যান্ডার্ড আউটপুট পুনঃনির্দেশ
ডিফল্টরূপে স্ট্যান্ডার্ড আউটপুট ( stdout
) হ'ল কনসোল। তবে, আপনি এটিকে অন্য কোনও কিছুতে পুনর্নির্দেশ করতে পারেন, উদাহরণস্বরূপ, এমন একটি ফাংশন যা আউটপুটটিকে একটি ভেরিয়েবলে সঞ্চয় করে। এর অর্থ আপনি Module.print
সম্পত্তি সেট করে এইচটিএমএলে আউটপুট যুক্ত করতে পারেন।
// This is `script.js`.
import loadWASM from './mkbitmap.js';
const run = async () => {
let consoleOutput = 'Powered by ';
const Module = await loadWASM({
print: (text) => (consoleOutput += text),
});
Module.callMain(['-v']);
document.body.textContent = consoleOutput;
};
run();
মেমরি ফাইল সিস্টেমে ইনপুট ফাইলটি পান
মেমরি ফাইল সিস্টেমে ইনপুট ফাইলটি পেতে আপনার কমান্ড লাইনে mkbitmap filename
সমতুল্য প্রয়োজন। আমি কীভাবে এটির কাছে পৌঁছেছি তা বুঝতে, প্রথমে mkbitmap
কীভাবে তার ইনপুটটি প্রত্যাশা করে এবং এর আউটপুট তৈরি করে তার কিছু ব্যাকগ্রাউন্ড।
mkbitmap
সমর্থিত ইনপুট ফর্ম্যাটগুলি হ'ল পিএনএম ( পিবিএম , পিজিএম , পিপিএম ) এবং বিএমপি । আউটপুট ফর্ম্যাটগুলি বিটম্যাপগুলির জন্য পিবিএম এবং গ্রিম্যাপগুলির জন্য পিজিএম। যদি কোনও filename
যুক্তি দেওয়া হয়, mkbitmap
ডিফল্টরূপে একটি আউটপুট ফাইল তৈরি করবে যার নাম ইনপুট ফাইলের নাম থেকে এর প্রত্যয়টি .pbm
এ পরিবর্তন করে প্রাপ্ত হয়। উদাহরণস্বরূপ, ইনপুট ফাইলের নাম example.bmp
-র জন্য, আউটপুট ফাইলের নামটি example.pbm
হবে P
এমস্ক্রিপ্টেন একটি ভার্চুয়াল ফাইল সিস্টেম সরবরাহ করে যা স্থানীয় ফাইল সিস্টেমকে অনুকরণ করে, যাতে সিঙ্ক্রোনাস ফাইল এপিআই ব্যবহার করে নেটিভ কোডটি সংকলন করা যায় এবং সামান্য বা কোনও পরিবর্তন ছাড়াই চালানো যায়। mkbitmap
জন্য কোনও ইনপুট ফাইলটি পড়ার জন্য যেমন এটি filename
কমান্ড লাইন যুক্তি হিসাবে পাস করা হয়েছে, আপনাকে এমস্ক্রিপ্টেন সরবরাহ করে এমন FS
অবজেক্টটি ব্যবহার করতে হবে।
FS
অবজেক্টটি একটি ইন-মেমরি ফাইল সিস্টেম দ্বারা সমর্থিত (সাধারণত এমইএমএফএস হিসাবে পরিচিত) এবং ভার্চুয়াল ফাইল সিস্টেমে ফাইলগুলি লেখার জন্য আপনি একটি writeFile()
ফাংশন রয়েছে যা আপনি ব্যবহার করেন। আপনি নিম্নলিখিত কোড নমুনায় প্রদর্শিত হিসাবে writeFile()
ব্যবহার করেন।
ফাইল লেখার অপারেশনটি যাচাই করতে, FS
অবজেক্টের readdir()
ফাংশনটি প্যারামিটার '/'
দিয়ে চালান। আপনি example.bmp
এবং বেশ কয়েকটি ডিফল্ট ফাইল দেখতে পাবেন যা সর্বদা স্বয়ংক্রিয়ভাবে তৈরি হয় ।
নোট করুন যে সংস্করণ নম্বর মুদ্রণের জন্য Module.callMain(['-v'])
এর আগের কলটি সরানো হয়েছিল। এটি Module.callMain()
এমন একটি ফাংশন যা সাধারণত একবারে চালানোর প্রত্যাশা করে।
// This is `script.js`.
import loadWASM from './mkbitmap.js';
const run = async () => {
const Module = await loadWASM();
const buffer = await fetch('https://example.com/example.bmp').then((res) => res.arrayBuffer());
Module.FS.writeFile('example.bmp', new Uint8Array(buffer));
console.log(Module.FS.readdir('/'));
};
run();
প্রথম প্রকৃত সম্পাদন
জায়গায় থাকা সমস্ত কিছুর সাথে, Module.callMain(['example.bmp'])
চালিয়ে mkbitmap
সম্পাদন করুন। এমইএমএফএস ' '/'
ফোল্ডারের বিষয়বস্তু লগ করুন এবং আপনার সদ্য নির্মিত example.pbm
দেখতে হবে example.bmp
// This is `script.js`.
import loadWASM from './mkbitmap.js';
const run = async () => {
const Module = await loadWASM();
const buffer = await fetch('https://example.com/example.bmp').then((res) => res.arrayBuffer());
Module.FS.writeFile('example.bmp', new Uint8Array(buffer));
Module.callMain(['example.bmp']);
console.log(Module.FS.readdir('/'));
};
run();
মেমরি ফাইল সিস্টেমের বাইরে আউটপুট ফাইলটি পান
FS
অবজেক্টের readFile()
ফাংশনটি মেমরি ফাইল সিস্টেমের শেষ ধাপে তৈরি example.pbm
তৈরি করতে সক্ষম করে। ফাংশনটি এমন একটি Uint8Array
ফেরত দেয় যা আপনি কোনও File
অবজেক্টে রূপান্তর করেন এবং ডিস্কে সংরক্ষণ করেন, কারণ ব্রাউজারগুলি সাধারণত ব্রাউজার দেখার জন্য পিবিএম ফাইলগুলিকে সমর্থন করে না। ( কোনও ফাইল সংরক্ষণের আরও মার্জিত উপায় রয়েছে তবে গতিশীলভাবে তৈরি করা <a download>
ব্যবহার করা সর্বাধিক বহুল সমর্থিত)) ফাইলটি সংরক্ষণ করা হলে আপনি এটি আপনার প্রিয় চিত্র দর্শকের মধ্যে খুলতে পারেন।
// This is `script.js`.
import loadWASM from './mkbitmap.js';
const run = async () => {
const Module = await loadWASM();
const buffer = await fetch('https://example.com/example.bmp').then((res) => res.arrayBuffer());
Module.FS.writeFile('example.bmp', new Uint8Array(buffer));
Module.callMain(['example.bmp']);
const output = Module.FS.readFile('example.pbm', { encoding: 'binary' });
const file = new File([output], 'example.pbm', {
type: 'image/x-portable-bitmap',
});
const a = document.createElement('a');
a.href = URL.createObjectURL(file);
a.download = file.name;
a.click();
};
run();
একটি ইন্টারেক্টিভ ইউআই যুক্ত করুন
এই মুহুর্তে, ইনপুট ফাইলটি হার্ডকোডড এবং mkbitmap
ডিফল্ট পরামিতিগুলির সাথে চলে। চূড়ান্ত পদক্ষেপটি হ'ল ব্যবহারকারীকে গতিশীলভাবে একটি ইনপুট ফাইল নির্বাচন করা, mkbitmap
প্যারামিটারগুলি টুইট করা এবং তারপরে নির্বাচিত বিকল্পগুলির সাথে সরঞ্জামটি চালানো।
// Corresponds to `mkbitmap -o output.pbm input.bmp -s 8 -3 -f 4 -t 0.45`.
Module.callMain(['-o', 'output.pbm', 'input.bmp', '-s', '8', '-3', '-f', '4', '-t', '0.45']);
পিবিএম চিত্রের ফর্ম্যাটটি পার্স করা বিশেষভাবে শক্ত নয়, তাই কিছু জাভাস্ক্রিপ্ট কোডের সাহায্যে আপনি আউটপুট চিত্রের একটি পূর্বরূপও দেখাতে পারেন। এটি করার এক উপায়ের জন্য নীচের এম্বেড থাকা ডেমোর উত্স কোডটি দেখুন।
উপসংহার
অভিনন্দন, আপনি সাফল্যের সাথে mkbitmap
ওয়েবসেম্পলিতে সংকলন করেছেন এবং এটি ব্রাউজারে কাজ করেছেন! কিছু মৃত প্রান্ত ছিল এবং এটি কাজ না করা পর্যন্ত আপনাকে সরঞ্জামটি একাধিকবার সংকলন করতে হয়েছিল, তবে আমি উপরে লিখেছি, এটি অভিজ্ঞতার অংশ। আপনি যদি আটকে যান তবে স্ট্যাকওভারফ্লোর webassembly
ট্যাগটিও মনে রাখবেন। শুভ সংকলন!
স্বীকৃতি
এই নিবন্ধটি স্যাম ক্লেগ এবং রাহেল অ্যান্ড্রু পর্যালোচনা করেছেন।