Compiler
Translates source code (written in programming languages) into machine code (0s and 1s)
make command
makeis an automation tool, not the compiler itself. It simplifies the build process by running the actual compiler (likeclang) with the correct commands and arguments for youmakevs.clang- Using
clangdirectly (The manual way)clang hello.c: This works, but it outputs a generic file nameda.out(assembly output), and you lose your desired program nameclang -o hello hello.c: The-o helloflag tellsclangto create an output file namedhellofrom the source filehello.cclang -o hello hello.c -lcs50: You also need to explicitly state libraries (-lindicates link)
- Using
make(The automated way)make hello: Automatically runsclang -o hello hello.c, also no need to state libraries
- Using
- Note about libraries
- C standard library
- The default toolbox that comes with every C compiler, and the linker always checks this toolbox automatically
- When using
clangyou don’t need to specify with-l - Ex.
stdio.h
- External libraries
- Need to specify with
-lwithclang - Ex.
cs50.h
- Need to specify with
- C standard library
The steps of “compiling”
- Saying that
makecommand “compiles” your code is abstracting a 4-lvl process, and we just call the entire process “compiling”
Preprocessing
- Main steps
- The preprocessor directive
#include <stdio.h>finds the header filestdio.h- the
.hfile almost entirely just contains function prototypes (declarations) & not the full function logic.
- the
- It “copy-pastes” the entire text content of that
stdio.hfile into your.cfile
- The preprocessor directive
- Preprocessor directives
- a specific command to the preprocessor (the program that runs right before the main compiler), starts with
# #include- Find the file named after this, and copy-paste its EENTIRE contents right here in my code, effectively replacing the#includeline#if,#else,#endifare other preprocessor directives
- a specific command to the preprocessor (the program that runs right before the main compiler), starts with
- Header file
- a real file on the computer that ends with a
.hextension, contains prototypes/declarations - Ex)
<stdio.h>- stands for “Standard Input/Output Header” - contains the declarations for functions like
printf()andscanf()
- stands for “Standard Input/Output Header” - contains the declarations for functions like
- a real file on the computer that ends with a
(Actual) Compiling
- Gets the preprocessed code & translates it to assembly code
Assembling
- convert the assembly code to binary (
0s and1s)
Linking
- Like the final step that assembles the complete puzzle
- After the compiler turns your
hello.cinto a machine-code “object file” (hello.o), that file has “gaps” or “placeholders” for any functions you used but didn’t write, likeprintf() - Steps
- The linker looks at those function calls (ex.
printf()) - It finds the actual, pre-compiled machine code for those functions in the C standard library
- It “stitches” that library’s machine code together with your machine code.
- The result is one single, complete, runnable executable file
- The linker looks at those function calls (ex.
- Other things to know
- The
-oFlag:-osimply tells the linker what to output the final executable file as (e.g.,clang -o hello hello.c). - Decompiling: Reversing this process (turning the final machine code back into C) is called “decompiling,” and it’s extremely difficult and ambiguous because much of the original source code’s structure is lost
- The
📌Decompiling/Reversing the process?
- Can you actually decompile/reverse the process? If you have only
0s and1s, can you make it back to source code? - While you technically can, it becomes harder and more ambiguous
- Ex. You wouldn’t know if you used a for loop, a while loop, etc