闲来无事,便来聊聊Hello World的“前世今生”
所谓“前世”,便是Hello World是如何产生的。所谓“今生”,则是Hello World是如何运行的。
一个Hello World的源程序是最简单不过了:
#include <stdio.h>
int main(int argc, char** argv) {
printf("Hello World");
}
要产生它也是很简单的一句话:
gcc -o hello.exe hello.c
可是正如简单的种子萌芽,其内部的生化反应相当复杂, 一个从hello.c到hello.exe的过程也是相当繁复的。
大致的过程是
- 编译 : .c -> .s
- 装配 : .s -> .o
- 链接: .o + 一大波库 -> 可执行的格式
这其中每一步展开了都能说上老半天。
以下以GCC,Linux,X86为例。
首先,奇怪的是,上面的三大步骤,怎么看不到呢?明明一行命令就可以了啊。
真相是这样的: “gcc" 本身是一个Driver。GCC 是 GNU Compiler Collection 的缩写,不是GNU C Compiler 意思哦! 所谓Collecton,就是包含了一堆工具。 所谓Driver,就是负责以上三个步骤的执行,其中第一步步骤就是调用C编译器。第二部步骤呢,就是去调用装配器(Assembler)来完成,最后一个步骤则指挥链接器(Ld)去完成。
口说无凭,眼见为实:
gcc -o hello.exe hello.c -v // -v 让它现出原形!
Using built-in specs.COLLECT_GCC=gcc 首先输出GCC自身的信息
COLLECT_LTO_WRAPPER=/usr/lib/gcc/i686-pc-linux-gnu/4.9.0/lto-wrapper
Target: i686-pc-linux-gnu 这里告诉我们生成的代码是在PC Linux上运行的
Configured with: /build/gcc/src/gcc-4.9-20140604/configure --p