BA372 — Compile, Interpret or Byte-compile?
- Compilation (traditional); e.g., C, C++, Fortran:
- Translates source code into cpu-specific(!!) binary and stores the translation.
- Example: "Hello, world" in C:
Compile into binary hello.o:
gcc -c hello.c —> generates a file hello.o
!!! hello.o is not an executable file/program !!!
To make an executable program, the code from hello.o must be linked with the binary version of printf().
- Why not? Because it ONLY contains the compiled code from hello.c; not the code of the function/method printf().
After compilation, we must execute this link step; i.e., link the hello.o file with any needed codes from the standard library
and write the result to the executable file HELLO.
- The binary version of printf() lives in the .o file packaged up in the standard library.
gcc hello.o -o HELLO
What happens when we include a call to a function for which no code was written?
void foo(char *); //In C all called methods must be declared upfront so that the compiler
//can check if you are calling the method correctly.
gcc -c hello.c
But what happens when we try linking this code into an executable named HELLO?
gcc hello.o -o HELLO
hello.o: In function `main':
hello.c:(.text+0xa): undefined reference to `foo'
collect2: error: ld returned 1 exit status
Solution: write code for the method foo(), store it in hello.c or in a different file; e.g., foo.c, compile and link both files:
gcc -c hello.c foo.c
gcc hello.o foo.o -o HELLO
Test question: what is a code library? Answer: a file of precompiled codes which can be linked with your code.
Note: two types of linking: static linking and dynamic linking:
- Static linking: all binary codes are stored in the executable file.
- Dynamic linking: only references(!) to the binary codes are stored in the executable file. References are invoked at run time.
- Windows: *.dll (dynamic link library); Linux/Unix: *.so (shared object); mac OS: *.dylib (dynamic library).
- Statically linked programs are portable across systems with the same CPU/OS.
- Dynamically linked programs must also have the libraries installed.
- Statically linked programs are larger and take more memory to load.
- Translates source code into cpu-specific binary AND(!) executes the translation.
- Any linking of library codes happens dynamically at run-time.
- Unlike in case of compilation; the translation is not stored in a file.
- No executable files are generated.
- Every time the program is run, the translation must occur:
- Interpreted code runs (much) slower than compiled code.
- Interpreted code is written (much) faster than compiled code.
- Why? Because interpreted code does not require declaring variables and variable types!!!: PHP example (run at phptester.net):
$my_array = 1;
$my_array = -99.99;
$my_array = "mystring";
for ($i = 0; $i < 3; $i++)
print ($i+1 . ": " . $my_array[$i] . "<br/>");
Byte compilation; e.g., Java, .NET (C#, J#):
- Translates source code into non-cpu-specific(!!) intermediate binary (aka byte-code) and stores the translation in a file.
- e.g., "Hello, world" in Java:
javac hello.java —> generates a compiled file hello.class
The compiled code can now be run through an interpreter (aka a virtual machine) which translates it into cpu-specific binary and runs it.
Any linking of library codes happens dynamically.
In the cases of Java and .NET, the rules for intermediate byte-code are published and anyone is free to write a VM for any platform.
- Java: Java Virtual Machine (JVM)
- .NET: Common Language Runtime (CLR)
- Note: These 'VM's are nothing like what we commonly call a 'virtual machine.'
Byte-compiled code is faster than interpreted codes but slower than compiled code.
Since byte-compiled code is compiled, byte-compiled languages are strictly typed (must declare variables).
This means that byte-compiled code takes longer to write than interpreted code.
- —> "Java runs everywhere."