梁越

gcc编译原理和顺序

0 人看过

重温编译

例如我有一个简单的程序

/*cpp文件*/
#include <cstdio>
#include <iostream>
#include "data.h"

int main()
{
    printf("hello from epoll!\n");
    TreeNode *root = new TreeNode(1);
    std::cout<<(root->value);
    return 0;
}
/*头文件*/
#pragma once

struct TreeNode {
    int value;
    TreeNode *next;

    TreeNode(int x) :value(x){};
};

预处理

这个流程主要是处理头文件(#include)和宏定义(#define)

使用gcc的-E只预处理,生成.ii文件

gcc -E main.cpp -o main.ii

生成的.ii文件有10000多行,其实是把库函数所有声明和结构合并在一起

编译

这个过程是将上一步生成的文件编译成汇编能够识别的文件

使用gcc的-S参数只编译,生成.s文件,下面是部分代码

gcc -S main.ii -o main.s
.file   "main.cpp"
      2     .local  _ZStL8__ioinit
      3     .comm   _ZStL8__ioinit,1,1
      4     .section    .text._ZN8TreeNodeC2Ei,"axG",@progbits,_ZN8TreeNodeC5Ei,comdat
      5     .align 2
      6     .weak   _ZN8TreeNodeC2Ei
      7     .type   _ZN8TreeNodeC2Ei, @function
      8 _ZN8TreeNodeC2Ei:
      9 .LFB972:
     10     .cfi_startproc
     11     pushq   %rbp
     12     .cfi_def_cfa_offset 16
     13     .cfi_offset 6, -16
     14     movq    %rsp, %rbp
     15     .cfi_def_cfa_register 6
     16     movq    %rdi, -8(%rbp)
     17     movl    %esi, -12(%rbp)
     18     movq    -8(%rbp), %rax
     19     movl    -12(%rbp), %edx
     20     movl    %edx, (%rax)
     21     popq    %rbp
     22     .cfi_def_cfa 7, 8
     23     ret
     24     .cfi_endproc
     25 .LFE972:
     26     .size   _ZN8TreeNodeC2Ei, .-_ZN8TreeNodeC2Ei
     27     .weak   _ZN8TreeNodeC1Ei
     28     .set    _ZN8TreeNodeC1Ei,_ZN8TreeNodeC2Ei

汇编

这个步骤主要是把.s文件翻译成二进制机器指令文件.o

gcc使用-c参数

gcc -c main.s -o main.o
^?ELF^B^A^A^@^@^@^@^@^@^@^@^@^A^@>^@^A^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@ ^G^@^@^@^@^@^@^@^@^@^@@^@^@^@^@^        @@^@^Q^@^P^@^A^@^@^@^F^@^@^@UH<89>åSH<83>ì^X¿^@^@^@^@è^@^@^@^@¿^P^@^@^@è^@^@^@^@H<89>þ^A^@^@^@H<89>ßè^@^@^@^        @H<89>]èH<8b>Eè<8b>^@<89>Æ¿^@^@^@^@è^@^@^@^@¸^@^@^@^@H<83>Ä^X[]ÃUH<89>åH<83>ì^P<89>}ü<89>uø<83>}ü^Au'<81>}øÿÿ        ^@^@u^^¿^@^@^@^@è^@^@^@^@º^@^@^@^@¾^@^@^@^@¿^@^@^@^@è^@^@^@^@ÉÃUH<89>å¾ÿÿ^@^@¿^A^@^@^@è°ÿÿÿ]Ã^@UH<89>åH<89>}ø        <89>uôH<8b>Eø<8b>Uô<89>^P]Ãhello from epoll!^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@GCC: (GNU) 4.8.5 20150623 (Red Ha        t 4.8.5-44)^@^@^@^T^@^@^@^@^@^@^@^AzR^@^Ax^P^A^[^L^G^H<90>^A^@^@^\^@^@^@^\^@^@^@^@^@^@^@^V^@^@^@^@A^N^P<86>^B        C^M^FQ^L^G^H^@^@^@ ^@^@^@<^@^@^@^@^@^@^@O^@^@^@^@A^N^P<86>^BC^M^FE<83>^C^BE^L^G^H^@^@^@^\^@^@^@`^@^@^@^@^@^@^        @=^@^@^@^@A^N^P<86>^BC^M^Fx^L^G^H^@^@^@ ^@^@^@<80>^@^@^@^@^@^@^@^U^@^@^@^@A^N^P<86>^BC^M^FP^L^G^H^@^@^@^@^@^@        ^@^@^@^@^@^@

链接

这个步骤主要是把相关的静态库.a文件和动态库.so文件拼起来

对于使用gcc的,可以用-L参数声明库文件地址,也可以使用一下参数

gcc -xc++ -lstdc++ -shared-libgcc 这里会声明使用c++标准库

gcc -xc++ -lstdc++ -shared-libgcc main.cpp -o main2

或者使用g++,g++的好处就是能够自动链接

g++ main.cpp -o main3

再或者就是使用make或者cmake工具指定库地址来完成整个编译过程