হ্যালো, কার্গো! (Hello, Cargo!)
কার্গো (Cargo) হল Rust-এর বিল্ড সিস্টেম এবং প্যাকেজ ম্যানেজার। বেশিরভাগ Rustacean তাদের Rust প্রোজেক্টগুলো ম্যানেজ করার জন্য এই টুলটি ব্যবহার করেন, কারণ Cargo আপনার হয়ে অনেক কাজ করে দেয়। যেমন, আপনার কোড বিল্ড করা, আপনার কোডের জন্য প্রয়োজনীয় লাইব্রেরিগুলো ডাউনলোড করা এবং সেই লাইব্রেরিগুলো বিল্ড করা। (যে লাইব্রেরিগুলোর ওপর আপনার কোড নির্ভর করে, সেগুলোকে আমরা ডিপেন্ডেন্সি (dependencies) বলি।)
সবচেয়ে সহজ Rust প্রোগ্রামগুলো, যেমনটি আমরা এতক্ষণ লিখেছি, সেগুলোর কোনো ডিপেন্ডেন্সি নেই। আমরা যদি “Hello, world!” প্রোজেক্টটি Cargo দিয়ে তৈরি করতাম, তাহলে Cargo-র কেবল সেই অংশটি ব্যবহৃত হত যেটি আপনার কোড বিল্ড করার দায়িত্বে রয়েছে। আপনি যখন আরও জটিল Rust প্রোগ্রাম লিখবেন, তখন আপনাকে ডিপেন্ডেন্সি যোগ করতে হবে। আর আপনি যদি Cargo ব্যবহার করে একটি প্রোজেক্ট শুরু করেন, তাহলে ডিপেন্ডেন্সি যোগ করা অনেক সহজ হয়ে যাবে।
যেহেতু বেশিরভাগ Rust প্রোজেক্ট Cargo ব্যবহার করে, তাই এই বইয়ের বাকি অংশে ধরে নেওয়া হবে যে আপনিও Cargo ব্যবহার করছেন। আপনি যদি “ইন্সটলেশন” বিভাগে আলোচিত অফিশিয়াল ইন্সটলারগুলো ব্যবহার করে থাকেন, তাহলে Cargo Rust-এর সাথেই ইন্সটল হয়ে যায়। আপনি যদি অন্য কোনো উপায়ে Rust ইন্সটল করে থাকেন, তাহলে আপনার টার্মিনালে নিচের কমান্ডটি লিখে পরীক্ষা করুন যে Cargo ইন্সটল করা আছে কিনা:
$ cargo --version
যদি আপনি একটি ভার্সন নম্বর দেখতে পান, তাহলে বুঝবেন যে এটি ইন্সটল করা আছে! যদি command not found
-এর মতো কোনো এরর দেখতে পান, তাহলে Cargo আলাদাভাবে ইন্সটল করার পদ্ধতি জানার জন্য আপনার ইন্সটলেশন পদ্ধতির ডকুমেন্টেশন দেখুন।
Cargo দিয়ে একটি প্রোজেক্ট তৈরি করা (Creating a Project with Cargo)
আসুন, Cargo ব্যবহার করে একটি নতুন প্রোজেক্ট তৈরি করি এবং দেখি যে এটি আমাদের আগের “Hello, world!” প্রোজেক্ট থেকে কীভাবে আলাদা। আপনার projects ডিরেক্টরিতে (অথবা আপনি যেখানে আপনার কোড রাখার সিদ্ধান্ত নিয়েছেন সেখানে) ফিরে যান। তারপর, যেকোনো অপারেটিং সিস্টেমে, নিচের কমান্ডগুলো চালান:
$ cargo new hello_cargo
$ cd hello_cargo
প্রথম কমান্ডটি hello_cargo নামে একটি নতুন ডিরেক্টরি এবং প্রোজেক্ট তৈরি করে। আমরা আমাদের প্রোজেক্টের নাম দিয়েছি hello_cargo, এবং Cargo একই নামের একটি ডিরেক্টরিতে এর ফাইলগুলো তৈরি করে।
hello_cargo ডিরেক্টরিতে যান এবং ফাইলগুলোর তালিকা দেখুন। আপনি দেখতে পাবেন যে Cargo আমাদের জন্য দুটি ফাইল এবং একটি ডিরেক্টরি তৈরি করেছে: একটি Cargo.toml ফাইল এবং একটি src ডিরেক্টরি, যার ভেতরে একটি main.rs ফাইল রয়েছে।
এটি একটি নতুন Git রিপোজিটরি এবং একটি .gitignore ফাইলও ইনিশিয়ালাইজ করেছে। আপনি যদি একটি বিদ্যমান Git রিপোজিটরির মধ্যে cargo new
চালান, তাহলে Git ফাইলগুলো তৈরি হবে না; আপনি cargo new --vcs=git
ব্যবহার করে এই আচরণটিকে ওভাররাইড করতে পারেন।
দ্রষ্টব্য: Git হল একটি বহুল ব্যবহৃত ভার্সন কন্ট্রোল সিস্টেম। আপনি
cargo new
-কে অন্য কোনো ভার্সন কন্ট্রোল সিস্টেম ব্যবহার করতে বা কোনো ভার্সন কন্ট্রোল সিস্টেম ব্যবহার না করার জন্য--vcs
ফ্ল্যাগ ব্যবহার করতে পারেন। উপলব্ধ অপশনগুলো দেখতেcargo new --help
চালান।
আপনার পছন্দের টেক্সট এডিটরে Cargo.toml খুলুন। এটি Listing 1-2-এর কোডের মতো হওয়া উচিত।
[package]
name = "hello_cargo"
version = "0.1.0"
edition = "2024"
[dependencies]
এই ফাইলটি TOML (Tom’s Obvious, Minimal Language) ফরম্যাটে রয়েছে, যেটি Cargo-র কনফিগারেশন ফরম্যাট।
প্রথম লাইন, [package]
, হল একটি সেকশন হেডিং, যা নির্দেশ করে যে নিচের স্টেটমেন্টগুলো একটি প্যাকেজ কনফিগার করছে। আমরা যখন এই ফাইলে আরও তথ্য যোগ করব, তখন আমরা অন্যান্য সেকশনও যোগ করব।
পরের তিনটি লাইন আপনার প্রোগ্রাম কম্পাইল করার জন্য Cargo-র প্রয়োজনীয় কনফিগারেশন তথ্য সেট করে: নাম, ভার্সন এবং ব্যবহার করার জন্য Rust-এর এডিশন। আমরা Appendix E-তে edition
কী সম্পর্কে আলোচনা করব।
শেষ লাইন, [dependencies]
, হল আপনার প্রোজেক্টের যেকোনো ডিপেন্ডেন্সি তালিকাভুক্ত করার জন্য একটি সেকশনের শুরু। Rust-এ, কোডের প্যাকেজগুলোকে ক্রেটস (crates) বলা হয়। এই প্রোজেক্টের জন্য আমাদের অন্য কোনো ক্রেটের প্রয়োজন হবে না, কিন্তু চ্যাপ্টার ২-এর প্রথম প্রোজেক্টে আমাদের প্রয়োজন হবে, তাই আমরা তখন এই ডিপেন্ডেন্সি সেকশনটি ব্যবহার করব।
এবার src/main.rs খুলুন এবং দেখুন:
Filename: src/main.rs
fn main() { println!("Hello, world!"); }
Cargo আপনার জন্য একটি “Hello, world!” প্রোগ্রাম তৈরি করেছে, ঠিক যেমনটি আমরা Listing 1-1-এ লিখেছিলাম! এখনও পর্যন্ত, আমাদের প্রোজেক্ট এবং Cargo-র তৈরি করা প্রোজেক্টের মধ্যে পার্থক্য হল, Cargo কোডটিকে src ডিরেক্টরির মধ্যে রেখেছে এবং আমাদের টপ ডিরেক্টরিতে একটি Cargo.toml কনফিগারেশন ফাইল রয়েছে।
Cargo আশা করে যে আপনার সোর্স ফাইলগুলো src ডিরেক্টরির মধ্যে থাকবে। টপ-লেভেল প্রোজেক্ট ডিরেক্টরিটি শুধুমাত্র README ফাইল, লাইসেন্স তথ্য, কনফিগারেশন ফাইল এবং আপনার কোডের সাথে সম্পর্কিত নয় এমন যেকোনো কিছুর জন্য। Cargo ব্যবহার করা আপনাকে আপনার প্রোজেক্টগুলো সংগঠিত করতে সাহায্য করে। সবকিছুর জন্য একটি নির্দিষ্ট জায়গা রয়েছে এবং সবকিছু তার নিজের জায়গায় থাকে।
আপনি যদি এমন একটি প্রোজেক্ট শুরু করেন যেটি Cargo ব্যবহার করে না, যেমনটি আমরা “Hello, world!” প্রোজেক্টের ক্ষেত্রে করেছিলাম, তাহলে আপনি এটিকে Cargo ব্যবহার করে এমন একটি প্রোজেক্টে রূপান্তর করতে পারেন। প্রোজেক্ট কোডটিকে src ডিরেক্টরির মধ্যে সরিয়ে নিন এবং একটি উপযুক্ত Cargo.toml ফাইল তৈরি করুন। cargo init
চালালে সহজেই সেই Cargo.toml ফাইলটি পেয়ে যাবেন, এটি আপনার জন্য স্বয়ংক্রিয়ভাবে ফাইলটি তৈরি করে দেবে।
একটি Cargo প্রোজেক্ট বিল্ড এবং রান করা (Building and Running a Cargo Project)
এখন দেখা যাক, Cargo দিয়ে “Hello, world!” প্রোগ্রাম বিল্ড এবং রান করলে কী কী পার্থক্য হয়! আপনার hello_cargo ডিরেক্টরি থেকে, নিচের কমান্ডটি লিখে আপনার প্রোজেক্ট বিল্ড করুন:
$ cargo build
Compiling hello_cargo v0.1.0 (file:///projects/hello_cargo)
Finished dev [unoptimized + debuginfo] target(s) in 2.85 secs
এই কমান্ডটি আপনার বর্তমান ডিরেক্টরির পরিবর্তে target/debug/hello_cargo-তে (অথবা Windows-এ target\debug\hello_cargo.exe) একটি এক্সিকিউটেবল ফাইল তৈরি করে। ডিফল্ট বিল্ডটি যেহেতু একটি ডিবাগ বিল্ড, তাই Cargo বাইনারিটিকে debug নামের একটি ডিরেক্টরিতে রাখে। আপনি এই কমান্ডটি দিয়ে এক্সিকিউটেবলটি চালাতে পারেন:
$ ./target/debug/hello_cargo # or .\target\debug\hello_cargo.exe on Windows
Hello, world!
যদি সবকিছু ঠিকঠাক চলে, তাহলে টার্মিনালে Hello, world!
প্রিন্ট হওয়া উচিত। প্রথমবারের মতো cargo build
চালালে, Cargo টপ লেভেলে একটি নতুন ফাইলও তৈরি করে: Cargo.lock। এই ফাইলটি আপনার প্রোজেক্টের ডিপেন্ডেন্সিগুলোর সঠিক ভার্সন ট্র্যাক করে। এই প্রোজেক্টে কোনো ডিপেন্ডেন্সি নেই, তাই ফাইলটি কিছুটা ফাঁকা। আপনাকে কখনোই এই ফাইলটি ম্যানুয়ালি পরিবর্তন করতে হবে না; Cargo নিজেই এর বিষয়বস্তু পরিচালনা করে।
আমরা cargo build
দিয়ে একটি প্রোজেক্ট বিল্ড করলাম এবং ./target/debug/hello_cargo
দিয়ে চালালাম। কিন্তু আমরা cargo run
ব্যবহার করেও কোড কম্পাইল করতে পারি এবং তারপর ஒரே কমান্ডে প্রাপ্ত এক্সিকিউটেবল চালাতে পারি:
$ cargo run
Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs
Running `target/debug/hello_cargo`
Hello, world!
cargo build
চালানোর পরে বাইনারির পুরো পাথ ব্যবহার করার পরিবর্তে cargo run
ব্যবহার করা বেশি সুবিধাজনক। তাই বেশিরভাগ ডেভেলপার cargo run
ব্যবহার করেন।
লক্ষ্য করুন যে, এবার আমরা Cargo-কে hello_cargo
কম্পাইল করছে এমন কোনো আউটপুট দেখতে পাইনি। Cargo বুঝতে পেরেছে যে ফাইলগুলো পরিবর্তন হয়নি, তাই এটি রি-বিল্ড না করেই বাইনারিটি চালিয়ে দিয়েছে। আপনি যদি আপনার সোর্স কোড পরিবর্তন করতেন, তাহলে Cargo চালানোর আগে প্রোজেক্টটি রি-বিল্ড করত এবং আপনি এই আউটপুটটি দেখতে পেতেন:
$ cargo run
Compiling hello_cargo v0.1.0 (file:///projects/hello_cargo)
Finished dev [unoptimized + debuginfo] target(s) in 0.33 secs
Running `target/debug/hello_cargo`
Hello, world!
Cargo cargo check
নামেও একটি কমান্ড সরবরাহ করে। এই কমান্ডটি দ্রুত আপনার কোড পরীক্ষা করে দেখে যে এটি কম্পাইল হয় কিনা, কিন্তু কোনো এক্সিকিউটেবল তৈরি করে না:
$ cargo check
Checking hello_cargo v0.1.0 (file:///projects/hello_cargo)
Finished dev [unoptimized + debuginfo] target(s) in 0.32 secs
আপনি কেন একটি এক্সিকিউটেবল চাইবেন না? প্রায়শই, cargo check
, cargo build
-এর চেয়ে অনেক দ্রুত, কারণ এটি এক্সিকিউটেবল তৈরির ধাপটি এড়িয়ে যায়। কোড লেখার সময় আপনি যদি ক্রমাগত আপনার কাজ পরীক্ষা করতে থাকেন, তাহলে cargo check
ব্যবহার করলে আপনার প্রোজেক্ট কম্পাইল হচ্ছে কিনা, তা জানার প্রক্রিয়াটি দ্রুত হবে! তাই, অনেক Rustacean তাদের প্রোগ্রাম লেখার সময় নিয়মিতভাবে cargo check
চালান, যাতে এটি কম্পাইল হচ্ছে কিনা তা নিশ্চিত করা যায়। তারপর যখন তারা এক্সিকিউটেবল ব্যবহার করতে প্রস্তুত হন, তখন তারা cargo build
চালান।
আসুন, Cargo সম্পর্কে আমরা এ পর্যন্ত যা শিখেছি তার পুনরাবৃত্তি করি:
- আমরা
cargo new
ব্যবহার করে একটি প্রোজেক্ট তৈরি করতে পারি। - আমরা
cargo build
ব্যবহার করে একটি প্রোজেক্ট বিল্ড করতে পারি। - আমরা
cargo run
ব্যবহার করে এক ধাপে একটি প্রোজেক্ট বিল্ড এবং রান করতে পারি। - আমরা
cargo check
ব্যবহার করে কোনো বাইনারি তৈরি না করে এরর আছে কিনা তা পরীক্ষা করার জন্য একটি প্রোজেক্ট বিল্ড করতে পারি। - আমাদের কোডের মতোই একই ডিরেক্টরিতে বিল্ডের ফলাফল সংরক্ষণ করার পরিবর্তে, Cargo এটিকে target/debug ডিরেক্টরিতে সংরক্ষণ করে।
Cargo ব্যবহারের আরেকটি সুবিধা হল, আপনি কোন অপারেটিং সিস্টেমে কাজ করছেন তা নির্বিশেষে কমান্ডগুলো একই থাকে। তাই, এখন থেকে, আমরা Linux এবং macOS-এর জন্য আলাদা এবং Windows-এর জন্য আলাদা কোনো সুনির্দিষ্ট নির্দেশ দেব না।
রিলিজের জন্য বিল্ড করা (Building for Release)
যখন আপনার প্রোজেক্টটি অবশেষে রিলিজের জন্য প্রস্তুত হবে, তখন আপনি অপটিমাইজেশন সহ কম্পাইল করার জন্য cargo build --release
ব্যবহার করতে পারেন। এই কমান্ডটি target/debug-এর পরিবর্তে target/release-এ একটি এক্সিকিউটেবল তৈরি করবে। অপটিমাইজেশনগুলো আপনার Rust কোডকে দ্রুততর করে, কিন্তু এগুলো চালু করলে আপনার প্রোগ্রাম কম্পাইল হতে বেশি সময় লাগে। এই কারণেই দুটি ভিন্ন প্রোফাইল রয়েছে: একটি ডেভেলপমেন্টের জন্য, যখন আপনি দ্রুত এবং ঘন ঘন রি-বিল্ড করতে চান এবং অন্যটি ফাইনাল প্রোগ্রাম বিল্ড করার জন্য, যেটি আপনি একজন ব্যবহারকারীকে দেবেন, যা বারবার রি-বিল্ড করা হবে না এবং যত দ্রুত সম্ভব চলবে। আপনি যদি আপনার কোডের চলার সময় বেঞ্চমার্ক করেন, তাহলে cargo build --release
চালাতে এবং target/release-এর এক্সিকিউটেবল দিয়ে বেঞ্চমার্ক করতে ভুলবেন না।
Cargo-কে নিয়ম হিসেবে ধরা (Cargo as Convention)
সরল প্রোজেক্টগুলোর ক্ষেত্রে, Cargo শুধু rustc
ব্যবহারের চেয়ে বেশি কিছু সুবিধা দেয় না, তবে আপনার প্রোগ্রামগুলো আরও জটিল হয়ে উঠলে এটি নিজের কার্যকারিতা প্রমাণ করবে। একবার প্রোগ্রামগুলো একাধিক ফাইলে বড় হয়ে গেলে বা কোনো ডিপেন্ডেন্সির প্রয়োজন হলে, Cargo-কে দিয়ে বিল্ডের সমন্বয় করানো অনেক সহজ।
যদিও hello_cargo
প্রোজেক্টটি সহজ, তবুও এটি এখন আপনার বাকি Rust ক্যারিয়ারে আপনি যে আসল টুলিং ব্যবহার করবেন তার অনেকটাই ব্যবহার করে। আসলে, যেকোনো বিদ্যমান প্রোজেক্টে কাজ করার জন্য, আপনি Git ব্যবহার করে কোডটি চেক আউট করতে, সেই প্রোজেক্টের ডিরেক্টরিতে যেতে এবং বিল্ড করতে নিচের কমান্ডগুলো ব্যবহার করতে পারেন:
$ git clone example.org/someproject
$ cd someproject
$ cargo build
Cargo সম্পর্কে আরও তথ্যের জন্য, এর ডকুমেন্টেশন দেখুন।
সারসংক্ষেপ (Summary)
আপনি ইতিমধ্যেই আপনার Rust যাত্রায় একটি দুর্দান্ত সূচনা করেছেন! এই চ্যাপ্টারে, আপনি শিখেছেন কীভাবে:
rustup
ব্যবহার করে Rust-এর সর্বশেষ স্থিতিশীল ভার্সন ইন্সটল করবেন- একটি নতুন Rust ভার্সনে আপডেট করবেন
- লোকালি ইন্সটল করা ডকুমেন্টেশন খুলবেন
- সরাসরি
rustc
ব্যবহার করে একটি “Hello, world!” প্রোগ্রাম লিখবেন এবং চালাবেন - Cargo-র নিয়ম ব্যবহার করে একটি নতুন প্রোজেক্ট তৈরি করবেন এবং চালাবেন
Rust কোড পড়া এবং লেখার অভ্যাসের জন্য এটি একটি আরও বড় প্রোগ্রাম তৈরি করার উপযুক্ত সময়। তাই, চ্যাপ্টার ২-তে, আমরা একটি অনুমান করার গেম (guessing game) প্রোগ্রাম তৈরি করব। আপনি যদি Rust-এ সাধারণ প্রোগ্রামিং কনসেপ্টগুলো কীভাবে কাজ করে তা শিখে শুরু করতে চান, তাহলে চ্যাপ্টার ৩ দেখুন এবং তারপর চ্যাপ্টার ২-এ ফিরে আসুন।