5.3.1 · Coding › Build Systems & Toolchain
Jab tum gcc hello.c -o hello type karte ho, toh yeh lagta hai ek hi step hai. Lekin andar se, tumhari .c file ek 4 transformations ki pipeline se guzarti hai, har ek uss same program ki ek zyada machine-jaisi form produce karta hai. Isko ek factory line ki tarah socho: raw text andar → executable binary bahar.
Preprocessing → Compilation → Assembly → Linking
.c → .i → .s → .o → executable
Intuition Stages mein kyun split kiya?
Ek CPU sirf raw bytes (opcodes) samajhta hai. Insaan English-jaisa C likhte hain. Us gap ko EK giant step mein pata karna debug karna, port karna, ya optimize karna impossible hoga. Isliye hum divide and conquer karte hain:
Text-level edits (macros, includes) language matter karne se pehle handle hote hain → preprocessor .
Language → CPU-specific assembly (human-readable machine code) → compiler .
Assembly → raw bytes → assembler .
Bahut saare byte-files + libraries ko ek runnable file mein silna → linker .
Har stage ka EK hi kaam hota hai, isliye har ek ko independently replace, optimize, ya inspect kiya ja sakta hai.
Ek text substitution engine jo compilation se pehle run karta hai. Yeh # se shuru hone wali saari lines (directives) handle karta hai aur ek translation unit produce karta hai — pure C jisme koi # lines nahi bacha hota.
YEH KYA karta hai:
#include <stdio.h> → us header file ka poora content physically paste kar deta hai.
#define PI 3.14 → har PI token ko 3.14 se replace kar deta hai.
#ifdef / #ifndef / #endif → code ke blocks ko conditionally rakhta ya delete karta hai.
Comments strip kar deta hai.
ISKO kaise dekhen:
gcc -E hello.c -o hello.i # -E = stop after preprocessing
Worked example Macro expansion
#define SQ ( x ) ((x) * (x))
int y = SQ ( 3 + 1 );
Preprocessing ke baad → int y = ((3+1)*(3+1)); = 16.
Inner parentheses kyun? Kyunki macro pure text paste hai. Unke bina, SQ(3+1) ban jaata 3+1*3+1 = 7. Preprocessor math nahi jaanta — sirf text!
Definition Compiler (proper)
Preprocessed C (.i) ko assembly language (.s) mein translate karta hai — ek human-readable, CPU-architecture-specific instruction listing. Yahan syntax checking, type checking, aur optimization hoti hai.
ANDAR kya hota hai:
Lexing → text ko tokens mein tod deta hai.
Parsing → ek Abstract Syntax Tree (AST) banata hai.
Semantic analysis → type checks (yahi se tumhari zyaadatar errors aati hain!).
Optimization → jaise constant folding 2*3 → 6.
Code generation → target CPU ke liye assembly emit karta hai (x86, ARM…).
ISKO kaise dekhen:
gcc -S hello.i -o hello.s # -S = stop after compilation
.s kaisa dikhta hai
int main(){return 42;} compile ho sakta hai:
main:
mov eax , 42 ; put 42 in return register
ret ; return
eax kyun? x86 par, convention (the ABI) ke hisaab se function ka return value eax register mein pass hota hai.
Assembly mnemonics (.s) ko raw machine code (binary opcodes) mein translate karta hai, jo ek object file (.o) mein package hota hai — ek relocatable binary jo abhi runnable nahi hai.
ABHI runnable kyun nahi? Kyunki yeh aisi functions call kar sakta hai (jaise printf) jo doosri files mein rehti hain. Unke addresses abhi unknown placeholders hain.
ISKO kaise dekhen:
gcc -c hello.s -o hello.o # -c = compile+assemble, stop before linking
Worked example Object file mein hota hai
Tumhari functions ke liye machine code
ek symbol table : "Main main define karta hun", "Mujhe printf chahiye (undefined)"
relocation entries : "Yeh address baad mein patch karna".
Ek ya zyada object files plus library code ko mila kar ek single executable banata hai. Yeh symbols resolve karta hai (har "mujhe X chahiye" ko kisi "main X define karta hun" se match karta hai) aur addresses fix up karta hai (relocation).
YEH kya resolve karta hai:
Tumhara hello.o kehta hai "mujhe printf chahiye". Linker C standard library (libc) ke andar printf dhundhta hai aur address patch kar deta hai.
Do prakar:
Static linking → library code executable mein copy ho jaata hai (bada file, self-contained).
Dynamic linking → sirf ek reference store hota hai; actual .so/.dll runtime par load hoti hai (chota file, shared).
KAISE:
gcc hello.o -o hello # links, produces executable
Worked example Classic linker error
undefined reference to `foo'
Matlab: koi object file foo use kar raha hai, lekin koi bhi object file ya library usse define nahi karti. Yeh ek link-time error hai, compile error NAHI — har file ki compilation individually succeed hui thi!
Common mistake "Header files alag compile hoti hain."
Kyun sahi lagta hai: Tum unhe #include karte ho, toh woh input files lagte hain.
Fix: Headers compile NAHI hote. Woh preprocessing ke dauran paste in hote hain. Sirf resulting translation unit compile hota hai. Ek header bas text reuse hai.
undefined reference ek compiler error hai, toh syntax fix karo."
Kyun sahi lagta hai: gcc ke dauran saari errors ek jaisi lagti hain.
Fix: Yeh ek linker error hai. Tumhara syntax theek hai; tum definition dena bhool gaye (jaise sahi .o ya -lmath link nahi kiya). Missing source/library add karo, syntax fix nahi.
Common mistake "Macros C aur math samajhte hain."
Kyun sahi lagta hai: Woh functions jaisi dikhte hain.
Fix: Macros stupid text substitution hain. SQ(3+1) bina inner parens ke galat results deta hai. Macro args ko hamesha parenthesize karo.
.o files seedha run ki ja sakti hain."
Kyun sahi lagta hai: Unme machine code hota hai.
Fix: Woh relocatable hain — unresolved symbols & placeholder addresses se bhari hain. Sirf linking ke baad hi ek runnable executable hota hai.
Recall Answer padhne se pehle predict karo
Tum do files alag compile karte ho, dono succeed karti hain, lekin final step undefined reference to 'helper' ke saath fail ho jaata hai. Kaun sa stage fail hua aur kyun?
(Answer: linker . Har file theek se compile hui kyunki compiler ko sirf helper ki declaration/signature jaani chahiye thi. Definition kabhi linker ko provide nahi ki gayi.)
Intuition Agar sirf yeh yaad rakho
Order: preprocess → compile → assemble → link .
Preprocessor = text paste (# lines). Compiler = C→assembly + type checks. Assembler = assembly→.o. Linker = combine + resolve symbols.
undefined reference = link error; expected ';' = compile error; #include issues = preprocess .
"Patrick Carl Always Links" → P reprocess, C ompile, A ssemble, L ink.
File extensions follow karte hain: .c → .i → .s → .o → exe.
Recall Feynman: 12-saal ke bachhe ko samjhao
Socho tumne English mein ek recipe likhi. Pehle, ek helper saari sub-recipes jo tumne reference ki thi copy karke laata hai aur shorthand notes theek karta hai (preprocess ). Phir ek translator use chef ki special cooking-shorthand mein rewrite karta hai (compile ). Ek doosra insaan us shorthand ko exact robot-arm button presses mein badalta hai (assemble ) — lekin recipe abhi bhi kehti hai "doosri kitchen se sauce lo". Aakhir mein, linker doosri kitchens se saari sauces collect karne dauda jaata hai aur sab kuch ek FINISHED cookbook mein glue kar deta hai jise robot start-to-finish run kar sake.
4 compilation stages order mein kya hain? Preprocessing → Compilation → Assembly → Linking
Preprocessing ke baad kaun sa gcc flag rukta hai? -E (.i produce karta hai)
Compilation ke baad kaun sa gcc flag rukta hai (assembly emit karta hai)? -S (.s produce karta hai)
Kaun sa gcc flag compile+assemble karta hai lekin link nahi karta? -c (.o produce karta hai)
Preprocessor #include ke saath actually kya karta hai? Poori header file ka text source mein physically paste kar deta hai.
Translation unit kya hai? Preprocessor ka pure-C output (koi # directives nahi bache), jo compiler ka actual input hai.
SQ(x) ((x)*(x)) ko parenthesize kyun kiya gaya hai?Macros text substitution hain; parens ke bina, operator precedence SQ(3+1) jaisi expressions tod deta hai.
Assembler kya produce karta hai aur woh runnable kyun nahi hota? Ek object file (.o) machine code ke saath, lekin usmein unresolved symbols aur placeholder addresses hain.
Linker ka main kaam kya hai? Object files + libraries combine karna, symbols resolve karna, aur addresses ko ek executable mein relocate karna.
undefined reference to 'x' kis stage par aata hai?Linking par — ek symbol use kiya gaya lekin kabhi define nahi kiya gaya.
Static vs dynamic linking? Static library code ko executable mein copy karta hai; dynamic ek reference store karta hai jo runtime par shared library se load hota hai.
Type-checking errors kis stage par hoti hain? Compilation stage par (semantic analysis ke dauran).
Object file ke symbol table mein kya hota hai? Woh symbols jo woh define karta hai aur woh symbols jo use chahiye (undefined references).
C program ke liye file extension chain? .c → .i → .s → .o → executable
Lex parse type-check optimize