Modular Programming — Headers, Makefiles, Libraries

বাস্তব প্রোজেক্টের সংগঠন

~35 min Intermediate 10 practice problems Live code

1. Why Split Code?

৫,০০০ লাইনের একটি ফাইল maintain করা অসম্ভব। Logical unit অনুযায়ী আলাদা .c/.h ফাইলে ভাগ করুন। Linker সব object মিলিয়ে একটি executable বানায়।

ছোট ফাইল মানে — দ্রুত re-compile (শুধু পরিবর্তিত ফাইল rebuild হবে), parallel development, পরিষ্কার dependency, এবং অন্যের কোড বোঝা সহজ।

2. Header vs Source

.h (header).c (source)
Containsdeclarations, types, macrosfunction bodies
Included byother .c filesnever included
Purposeinterface (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 তিনটি ফাইলে ভাগ হবে।

single_file_demo.c
#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

TypeLinux ext.Windows ext.How used
Static.a.libCode copied into your executable at link time
Shared.so.dllLoaded 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
Static library-তে library-র object code আপনার executable-এ কপি হয়ে যায় — single file, কিন্তু size বড়। Shared library আলাদা ফাইল, multiple প্রোগ্রাম একই copy use করতে পারে — মোট RAM usage কম।

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

  1. Split any earlier lecture program into at least 2 .c/.h pairs.
    আগের যেকোনো একটি প্রোগ্রামকে কমপক্ষে ২টি .c/.h জোড়ায় ভাগ করুন।
    ✨ Show Answer

    Section 2-এর math_utils.h/.c-ই একটি মিনিমাল example। একইভাবে task.h/task.c + main.c ভাগ করুন।

  2. Write a Makefile for that project.
    সেই project-এর জন্য একটি Makefile লিখুন।
    ✨ Show Answer

    Section 4-এর template copy করে file/object নাম আপনার প্রোজেক্ট অনুযায়ী পাল্টে দিন।

  3. Run make; change one file; run make again — observe only it rebuilds.
    make চালান; একটি ফাইল পরিবর্তন করুন; আবার make চালান — শুধু সেটিই rebuild হবে।
    ✨ Show Answer

    make timestamp দেখে — যে source .o-র চেয়ে নতুন, শুধু সেটিই recompile হবে। এক ফাইল edit করলে দেখবেন terminal-এ শুধু দুটি command execute হয়: একটি .o এবং একটি link।

  4. 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
  5. 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 inline function বা #define macro — এগুলো header-এ থাকতে পারে।

  6. What happens if two .c files define a global int count? Fix it.
    দুটি .c-তে একই নামে global int count থাকলে কী হবে? কীভাবে ঠিক করবেন?
    ✨ Show Answer

    Linker error — "multiple definition of count"। সমাধান: একটি .c-তে int count = 0; রাখুন (definition); অন্যগুলোতে extern int count; declare করুন। অথবা একটিকে static int count; বানিয়ে file-private করে দিন।

  7. Use static to 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 উন্মুক্ত থাকলো; trim internal detail।

  8. 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

    সাধারণত -O2 runtime ২-৫ গুণ দ্রুত করে; size কমতেও পারে, বাড়তেও পারে (inlining-এর কারণে)।

  9. Read a real open-source Makefile and explain three rules you see.
    একটি বাস্তব open-source Makefile পড়ে তিনটি rule ব্যাখ্যা করুন।
    ✨ Show Answer

    সাধারণ rule: (১) all: target — default goal। (২) %.o: %.c pattern rule — যেকোনো .c থেকে .o বানানোর নিয়ম। (৩) .PHONY: clean install — যেসব target-এ আসল file নেই।

  10. 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 (শব্দকোষ)

TermMeaningবাংলায়
ModuleA 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 UnitOne .c file plus everything it includes — what the compiler sees.একটি .c এবং তার include-গুলো — compile-এর একক।
LinkageWhether a name is visible across translation units.একটি নাম একাধিক unit-এ দেখা যায় কিনা।
Internal Linkagestatic — visible only in its own file.static — শুধু নিজ ফাইলে দৃশ্যমান।
External LinkageDefault — visible across translation units.Default — সব unit-এ দৃশ্যমান।
LibraryA 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 ভাগাভাগি করে।
MakefileRecipe file telling make how to build.make-কে build নির্দেশ দেওয়ার ফাইল।
Target / DependencyWhat to build, and what it depends on.কী build হবে এবং তার dependency।
Incremental BuildRebuild only what changed.শুধু পরিবর্তিত অংশ rebuild করা।

Summary — Module 23

Responsibility অনুযায়ী ভাগ করুন। Header declare করে; source implement করে। Header guard ব্যবহার করুন। Makefile বা CMake দিয়ে automate করুন। Internal জিনিস static রাখুন। Library দিয়ে একই কোড একাধিক project-এ ব্যবহার করুন।

Next Module → Error handling ও defensive programming।