Modular Programming — Headers, Makefiles, Libraries
বাস্তব প্রোজেক্টের সংগঠন
1. Why Split Code?
৫,০০০ লাইনের একটি ফাইল maintain করা অসম্ভব। Logical unit অনুযায়ী আলাদা .c/.h ফাইলে ভাগ করুন। Linker সব object মিলিয়ে একটি executable বানায়।
2. Header vs Source
| .h (header) | .c (source) | |
|---|---|---|
| Contains | declarations, types, macros | function bodies |
| Included by | other .c files | never included |
| Purpose | interface (API) | implementation |
/* math_utils.h — the public API */
#ifndef MATH_UTILS_H
#define MATH_UTILS_H
int gcd(int a, int b);
int lcm(int a, int b);
#endif
/* math_utils.c — the implementation */
#include "math_utils.h"
int gcd(int a, int b) { return b ? gcd(b, a % b) : a; }
int lcm(int a, int b) { return a / gcd(a, b) * b; }
3. Separate Compilation
gcc -c main.c -o main.o
gcc -c math_utils.c -o math_utils.o
gcc main.o math_utils.o -o app
শুধু যে ফাইলটি পরিবর্তন হয়েছে সেটি recompile করলেই চলে — বড় প্রোজেক্টে এটা অনেক সময় বাঁচায়।
4. Makefile — Automate It
CC = gcc
CFLAGS = -std=c17 -Wall -Wextra -g
OBJS = main.o math_utils.o
app: $(OBJS)
$(CC) $(CFLAGS) -o $@ $(OBJS)
main.o: main.c math_utils.h
$(CC) $(CFLAGS) -c main.c
math_utils.o: math_utils.c math_utils.h
$(CC) $(CFLAGS) -c math_utils.c
clean:
rm -f $(OBJS) app
make চালান — যা যা পুরনো, শুধু সেগুলোই rebuild হবে। make clean মুছে দেয় সব।
5. Putting It All Together — Live Demo
Online runner-এ একাধিক ফাইল তৈরি করা যায় না, তাই নিচে একই idea একটি ফাইলে দেখাচ্ছি — আসল প্রোজেক্টে এই code তিনটি ফাইলে ভাগ হবে।
#include <stdio.h>
/* --- math_utils.h would contain: --- */
int gcd(int a, int b);
int lcm(int a, int b);
/* --- math_utils.c would contain: --- */
int gcd(int a, int b) { return b ? gcd(b, a % b) : a; }
int lcm(int a, int b) { return a / gcd(a, b) * b; }
/* --- main.c would contain: --- */
int main(void) {
printf("gcd(48, 36) = %d\n", gcd(48, 36));
printf("lcm(4, 6) = %d\n", lcm(4, 6));
return 0;
}
6. Static vs Shared Libraries
| Type | Linux ext. | Windows ext. | How used |
|---|---|---|---|
| Static | .a | .lib | Code copied into your executable at link time |
| Shared | .so | .dll | Loaded at runtime; multiple programs share one copy |
# Build a static library
gcc -c math_utils.c -o math_utils.o
ar rcs libmath.a math_utils.o
# Link against it
gcc main.o -L. -lmath -o app
7. Internal Linkage — static
// in math_utils.c
static int helper(int x) { ... } // not visible outside this file
অন্য .c ফাইলে দরকার না হলে function-কে static বানিয়ে file-এ সীমাবদ্ধ রাখুন। এতে name collision এড়ানো যায় এবং API ছোট থাকে।
8. Practice Problems
- Split any earlier lecture program into at least 2
.c/.hpairs.আগের যেকোনো একটি প্রোগ্রামকে কমপক্ষে ২টি.c/.hজোড়ায় ভাগ করুন।✨ Show Answer
Section 2-এর
math_utils.h/.c-ই একটি মিনিমাল example। একইভাবেtask.h/task.c+main.cভাগ করুন। - Write a Makefile for that project.সেই project-এর জন্য একটি Makefile লিখুন।
✨ Show Answer
Section 4-এর template copy করে file/object নাম আপনার প্রোজেক্ট অনুযায়ী পাল্টে দিন।
- Run
make; change one file; runmakeagain — observe only it rebuilds.makeচালান; একটি ফাইল পরিবর্তন করুন; আবারmakeচালান — শুধু সেটিই rebuild হবে।✨ Show Answer
maketimestamp দেখে — যে source.o-র চেয়ে নতুন, শুধু সেটিই recompile হবে। এক ফাইল edit করলে দেখবেন terminal-এ শুধু দুটি command execute হয়: একটি.oএবং একটি link। - Build a static library with two modules and link it into an app.দুটি module দিয়ে একটি static library বানান ও app-এ link করুন।
✨ Show Answer
gcc -c math_utils.c -o math_utils.o gcc -c string_utils.c -o string_utils.o ar rcs libmy.a math_utils.o string_utils.o gcc main.c -L. -lmy -o app ./app - Explain why headers should not contain function bodies.Header-এ কেন function body রাখা উচিত নয়?
✨ Show Answer
একই header একাধিক
.c-তে include হলে প্রতিটি.c-তে ওই function-এর copy তৈরি হয়। Linker তখন "multiple definition" error দেয়। Exception:static inlinefunction বা#definemacro — এগুলো header-এ থাকতে পারে। - What happens if two .c files define a global
int count? Fix it.দুটি.c-তে একই নামে globalint countথাকলে কী হবে? কীভাবে ঠিক করবেন?✨ Show Answer
Linker error — "multiple definition of count"। সমাধান: একটি
.c-তেint count = 0;রাখুন (definition); অন্যগুলোতেextern int count;declare করুন। অথবা একটিকেstatic int count;বানিয়ে file-private করে দিন। - Use
staticto make a helper file-local.staticদিয়ে একটি helper function file-এর ভেতরে সীমাবদ্ধ রাখুন।✨ Show Answer
// io.c static void trim(char *s) { ... } // only io.c can use it void read_config(void) { // ... trim(line); }Public API-তে শুধু
read_configউন্মুক্ত থাকলো;triminternal detail। - Build the same project with and without
-O2; compare binary size and speed.-O2দিয়ে ও ছাড়া build করে binary size ও speed তুলনা করুন।✨ Show Answer
gcc prog.c -o prog_debug # no optimization gcc -O2 prog.c -o prog_fast # optimized ls -l prog_debug prog_fast # binary size time ./prog_debug # runtime time ./prog_fastসাধারণত
-O2runtime ২-৫ গুণ দ্রুত করে; size কমতেও পারে, বাড়তেও পারে (inlining-এর কারণে)। - Read a real open-source Makefile and explain three rules you see.একটি বাস্তব open-source Makefile পড়ে তিনটি rule ব্যাখ্যা করুন।
✨ Show Answer
সাধারণ rule: (১)
all:target — default goal। (২)%.o: %.cpattern rule — যেকোনো.cথেকে.oবানানোর নিয়ম। (৩).PHONY: clean install— যেসব target-এ আসল file নেই। - Convert your Makefile to a minimal
CMakeLists.txt.আপনার Makefile-কে ছোটCMakeLists.txt-এ রূপান্তর করুন।✨ Show Answer
cmake_minimum_required(VERSION 3.10) project(myapp C) set(CMAKE_C_STANDARD 17) add_executable(app main.c math_utils.c) target_compile_options(app PRIVATE -Wall -Wextra)Build করতে:
cmake -B build && cmake --build build।
Glossary (শব্দকোষ)
| Term | Meaning | বাংলায় |
|---|---|---|
| Module | A logically separate unit of code (one .c + .h). | লজিক্যালি আলাদা code unit। |
Header File (.h) | Contains declarations shared between source files. | একাধিক source-এর মাঝে শেয়ার-করা declaration। |
Source File (.c) | Contains the implementation. | Implementation থাকার ফাইল। |
| Translation Unit | One .c file plus everything it includes — what the compiler sees. | একটি .c এবং তার include-গুলো — compile-এর একক। |
| Linkage | Whether a name is visible across translation units. | একটি নাম একাধিক unit-এ দেখা যায় কিনা। |
| Internal Linkage | static — visible only in its own file. | static — শুধু নিজ ফাইলে দৃশ্যমান। |
| External Linkage | Default — visible across translation units. | Default — সব unit-এ দৃশ্যমান। |
| Library | A reusable bundle of compiled code. | পুনঃব্যবহারযোগ্য compiled code-এর bundle। |
Static Library (.a) | Linked into the executable at build time. | Build-time-এ executable-এ যুক্ত হয়। |
Shared Library (.so / .dll) | Loaded at runtime, shared between programs. | Runtime-এ load হয়, একাধিক program ভাগাভাগি করে। |
| Makefile | Recipe file telling make how to build. | make-কে build নির্দেশ দেওয়ার ফাইল। |
| Target / Dependency | What to build, and what it depends on. | কী build হবে এবং তার dependency। |
| Incremental Build | Rebuild only what changed. | শুধু পরিবর্তিত অংশ rebuild করা। |
Summary — Module 23
Responsibility অনুযায়ী ভাগ করুন। Header declare করে; source implement করে। Header guard ব্যবহার করুন। Makefile বা CMake দিয়ে automate করুন। Internal জিনিস static রাখুন। Library দিয়ে একই কোড একাধিক project-এ ব্যবহার করুন।