GCC编译工具链中的 gcc 可执行程序,实际上是个驱动程序(Driver),其根据输入的参数,然后调用其它不同的程序,对输入文件进行处理,包括编译、链接等。可以通过以下命令查看:
gcc -v hello.c
$ gcc -v hello.c
.../usr/libexec/gcc/x86_64-linux-gnu/13/cc1 -quiet -v -imultiarch x86_64-linux-gnu hello.c -quiet -dumpdir a- -dumpbase hello.c -dumpbase-ext .c -mtune=generic -march=x86-64 -version -fasynchronous-unwind-tables -fstack-protector-strong -Wformat -Wformat-security -fstack-clash-protection -fcf-protection -o /tmp/ccNZ9EWv.s
...
as -v --64 -o /tmp/ccXjJNFZ.o /tmp/ccNZ9EWv.s
.../usr/libexec/gcc/x86_64-linux-gnu/13/collect2 -plugin /usr/libexec/gcc/x86_64-linux-gnu/13/liblto_plugin.so -plugin-opt=/usr/libexec/gcc/x86_64-linux-gnu/13/lto-wrapper -plugin-opt=-fresolution=/tmp/ccCoWozh.res -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s --build-id --eh-frame-hdr -m elf_x86_64 --hash-style=gnu --as-needed -dynamic-linker /lib64/ld-linux-x86-64.so.2 -pie -z now -z relro
/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/Scrt1.o /usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/13/crtbeginS.o -L/usr/lib/gcc/x86_64-linux-gnu/13 -L/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/13/../../../../lib -L/lib/x86_64-linux-gnu -L/lib/../lib -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/13/../../.. /tmp/ccXjJNFZ.o -lgcc --push-state --as-needed -lgcc_s --pop-state -lc -lgcc --push-state --as-needed -lgcc_s --pop-state /usr/lib/gcc/x86_64-linux-gnu/13/crtendS.o /usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/crtn.o
COLLECT_GCC_OPTIONS='-v' '-mtune=generic' '-march=x86-64' '-dumpdir' 'a.'
也就是 gcc 根据其输入参数,驱动(Driver)了其它工具来最终完成整个编译的任务。
其中,属于编译器部分的是 cc1 程序。其源代码入口为 <gcc-project>/gcc/main.cc 中的 main 函数:
找到程序入口后,就可以顺着程序的代码逻辑,一步步往下看 cc1 程序的代码了。
这里,有个认识点,就是,在查阅源代码时,要注意对代码的抽象理解。具体到C/C++的代码时,其最小抽象单元是函数,也就是理解函数在业务逻辑中的抽象意涵,也就是,知道函数的原型(Prototype),即其输入、输出、函数名,就能明白其作用。再往上抽象一层就是,类(Class),即对数据结构及相关处理函数的封装。再往上一层抽象就是库(library)。再往上就是包(Package)。这样一步步往上抽象,来组织管理整个程序代码,以使得其复杂度可以控制在便于维护及理解的程度。