c语言编译器

参考:

GCC官网地址: https://gcc.gnu.org/在新窗口打开
GCC官方文档: https://gcc.gnu.org/onlinedocs/在新窗口打开

GCC(GNU Compiler Collection,GNU编译程序集合)是GNU项目的一个产品,是最重要的开放源码软件。如Python就是由C语言开发,由GNU编译程序编译的!

GCC常见的组成部分:

模块说明备注
configureGCC源码树根目录中的一个脚本,用于设置配置值和创建GCC编译程序必须的make程序文件。
gcc该驱动程序等同于执行编译程序和链接程序以产生需要的输出。只能编译c语言
c++gcc的一个版本,默认语言为C++,而且在链接的时候自动包含标准C++库,这和g++一样。
g++gcc的一个版本,默认语言为G++,而且在链接的时候自动包含标准C++库,这和c++一样。向下兼容,同时能编译C/C++语言
一般选择此作为编译工具
libgcc该库包含的例程段被作为编译程序的一部分,是因为它们可以被链接到实际的可执行程序中。它们是例程,链接到可执行程序,来执行基本的任务,例如浮点运算。这些库中的例程通常都是平台相关的。
libstdc++运行时库,包括定义为标准语言一部分的所有的C++类和函数。

GCC包含的常见软件:

工具说明备注
ar这是一个程序,可通过文档添加、删除和析取文件来维护库文件。通常使用该文件是为了创建和管理链接程序使用的目标库文档。该程序是binutils包的一部分。编译静态库是用到
asGNU汇编器。实际上它是一族汇编器,因为它可以被编译或者能够在各种不同平台上工作。该程序是binutils包的一部分。简单说:将C/C++源文件转换成汇编语言
autoconf产生的shell脚本自动配置源代码包取编译某个特定版本的UNIX。
gdbGNU调试器。可用于检查程序运行时的值和行为。各种IDE(vscode/visualstudio/...)底层调用该工具
GNATS(GNU Bug Tracking System)一个跟踪GCC和其他GNU程序问题的在线系统。经常在别人工程中下载库编译安装时经常看到这东西
gprof该程序会监督编译程序的执行过程,并报告程序中各个函数的运行时间,可以根据所提供的配置车文件来优化程序。该程序是binutils包的一部分。静态库/动态库都用到
新手经常碰到的问题大概率与此库相关,如 ld error ...
ldGNU连接程序。该程序将目标文件的集合组成可执行程序。该程序是binutils包的一部分。
libtool一个基本库,支持make程序的描述文件使用的简化共享库用法的脚本。
make一个工具程序,它会读makefile脚本来确定程序中哪部分需要编译和连接,然后发布必要的命令。它读出的脚本(makefile或Makefile)定义了文件关系和依赖关系。make工具的支持库

基础概念

文件后缀解释

后缀(Suffix)说明(File Contains)
.c源文件
C source code that is to be preprocessed.
.h头文件
C source code header file.
.i预处理文件
C source code that is not to be preprocessed.
This type of file is produced as an intermediate step in compilation.
.s汇编语言文件
Assembly language code.
this type of file is produced as an intermediate step in compilation.
.o目标文件
An object file in a format appropriate to be supplied to the linker.
This type of file is produced as an intermediate step in compilation.
.a静态库文件
Static object library (archive).
.so
.lib/.dll (for windows)
动态库/共享库/运行时库文件
Shared object library.

编译过程

↓
↓ hello.c (源文件,文本)
↓ 
预处理器(cpp) —— 注释、宏定义
↓
↓ hello.i (修改了的源程序,文本)
↓
编译器(ccl)
↓
↓ hello.s (汇编程序,文本)
↓
汇编器(as)
↓
↓ hello.o (目标程序,二进制)(可重定位程序,relocatable object program)
↓
链接器(ld)
↓
↓ ←←← prinf.o (链接二进制)
↓
↓ hello (目标程序,二进制)(可执行文件)

简单来说: 首先把源代码编译成目标文件, 然后把目标文件链接起来。

创建可执行文件

hello.c

#include <stdio.h>

int main(int argc, char* argv[])
{
  printf("Hello World!\n");
  return 0;
}

预处理 .i

hello.i

gcc -E hello.c # 输出控制台
gcc -E hello.c -o hello.i 
version https://git-lfs.github.com/spec/v1
oid sha256:505554e9290cb0124f5b6014f5c5b38838e945cd0f7cfe4ccc5c3e68ee32596b
size 17982

生成汇编语言 .s

hello.s

gcc -S hello.c
gcc -S hello.c -o hello.s
	.file	"hello.c"
	.text
	.section	.rodata
.LC0:
	.string	"Hello World!"
	.text
	.globl	main
	.type	main, @function
main:
.LFB0:
	.cfi_startproc
	endbr64
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset 6, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register 6
	subq	$16, %rsp
	movl	%edi, -4(%rbp)
	movq	%rsi, -16(%rbp)
	leaq	.LC0(%rip), %rax
	movq	%rax, %rdi
	call	puts@PLT
	movl	$0, %eax
	leave
	.cfi_def_cfa 7, 8
	ret
	.cfi_endproc
.LFE0:
	.size	main, .-main
	.ident	"GCC: (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0"
	.section	.note.GNU-stack,"",@progbits
	.section	.note.gnu.property,"a"
	.align 8
	.long	1f - 0f
	.long	4f - 1f
	.long	5
0:
	.string	"GNU"
1:
	.align 8
	.long	0xc0000002
	.long	3f - 2f
2:
	.long	0x3
3:
	.align 8
4:

生成目标文件 .o

hello.o

gcc -c hello.c
gcc -c hello.c -o hello.h
# 编译多个.c文件
gcc -c hello1.c hello2.c # ...
$ ll hello.o
-rwxrwxrwx 1 uv01 uv01 1512 Mar  9 14:59 hello.o* 
$ file hello.o
hello.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped
# ELF —— Executable and Linking Format,可执行可连接格式
# 64-bit
# LSB —— Least Significant Bit,最小标识位/最低位有效。表示时是小端模式的程序
# relocatable —— 可重定位,运行时才指定内存位置?
# x86-64 —— cpu架构
# version 1 (SYSV) —— System V | 程序初始化方案?
# stripped/not stripped 
#   + stripped     —— 将程序中的符号表的信息剔除掉了,优点: 1. 可执行文件体积减少; 2. 程序更难以被调试/逆向/破解
#   + not stripped —— 保留了上述信息,便于调试

# 命令: readelf -h —— 查看二进制文件头文件
# Linux的可执行文件一般是elf格式(Executable and Linking Format,可执行可连接格式)的,在这个可执行文件的头部包含了很多重要的信息:如文件格式,加载地址,符号表等。
$ readelf -h hello.o 
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              REL (Relocatable file) # 💡文件类型 ❗可重定位,运行时才指定内存位置?
  Machine:                           Advanced Micro Devices X86-64 # 适配的cpu架构
  Version:                           0x1
  Entry point address:               0x0 # 💡程序入口地址 ❗无指定
  Start of program headers:          0 (bytes into file)
  Start of section headers:          616 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           0 (bytes)
  Number of program headers:         0
  Size of section headers:           64 (bytes)
  Number of section headers:         14
  Section header string table index: 13
$ ./hello.o # 未可执行
-bash: ./hello.o: cannot execute binary file: Exec format error 

生成可执行文件

hello

gcc hello.c
gcc hello.c -o hello
$ ll hello # 大了10倍,链接了静态库?
-rwxrwxrwx 1 uv01 uv01 15960 Mar  9 15:06 hello* 
$ file hello 
hello: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=2b5da4e7b90b64972cb49265c24db07574df467a, for GNU/Linux 3.2.0, not stripped
# dynamically linked —— 动态链接的!
# interpreter /lib64/ld-linux-x86-64.so.2
# BuildID[sha1]=2b5da4e7b90b64972cb49265c24db07574df467a
# for GNU/Linux 3.2.0
# not stripped
$ readelf -h hello 
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              DYN (Position-Independent Executable file) # 💡文件类型
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x1060 # 💡程序入口地址 ❗已指定
  Start of program headers:          64 (bytes into file)
  Start of section headers:          13976 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         13
  Size of section headers:           64 (bytes)
  Number of section headers:         31
  Section header string table index: 30
$ ./hello
Hello World!

创建静态库 .a

static library 静态库是在链接可执行文件时,代码段和数据段直接拷贝到可执行文件中

代码

calc.c

#include <stdio.h>

int add(int a, int b);
int c2i(char* s);

int main(int argc, char* argv[])
{
  int a = c2i(argv[1]);
  int b = c2i(argv[2]);
  printf("%d + %d = %d\n", a, b, add(a, b));
}

add.c

int add(int a, int b)
{
    return a + b;
}

tfunc.c

int c2i(char* s)
{
    return atoi(s);
}

生成目标文件 .o

gcc -c add.c -o add.o
gcc -c tfunc.c -o tfunc.o
# gcc -c lib1.c lib2.c ...
gcc -c add.c tfunc.c
$ readelf -h add.o tfunc.o
File: add.o
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              REL (Relocatable file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x0
  Start of program headers:          0 (bytes into file)
  Start of section headers:          464 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           0 (bytes)
  Number of program headers:         0
  Size of section headers:           64 (bytes)
  Number of section headers:         12
  Section header string table index: 11
File: tfunc.o
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              REL (Relocatable file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x0
  Start of program headers:          0 (bytes into file)
  Start of section headers:          536 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           0 (bytes)
  Number of program headers:         0
  Size of section headers:           64 (bytes)
  Number of section headers:         13
  Section header string table index: 12

编译静态库 .a

# 库文件命名规范 lib<库名>.a
ar -r liboperation.a add.o tfunc.o
$ file liboperation.a 
liboperation.a: current ar archive
$ ar -t liboperation.a # display contents of the archive
add.o
tfunc.o
$ readelf -h liboperation.a # 查看库头文件
File: liboperation.a(add.o)
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              REL (Relocatable file) # 💡文件类型
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x0
  Start of program headers:          0 (bytes into file)
  Start of section headers:          464 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           0 (bytes)
  Number of program headers:         0
  Size of section headers:           64 (bytes)
  Number of section headers:         12
  Section header string table index: 11
File: liboperation.a(tfunc.o)
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              REL (Relocatable file) # 💡文件类型
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x0
  Start of program headers:          0 (bytes into file)
  Start of section headers:          536 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           0 (bytes)
  Number of program headers:         0
  Size of section headers:           64 (bytes)
  Number of section headers:         13
  Section header string table index: 12
$ readelf -S add.o # 地址均未指定
There are 12 section headers, starting at offset 0x1d0:

Section Headers:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
  [ 0]                   NULL             0000000000000000  00000000
       0000000000000000  0000000000000000           0     0     0
  [ 1] .text             PROGBITS         0000000000000000  00000040
       0000000000000018  0000000000000000  AX       0     0     1
  [ 2] .data             PROGBITS         0000000000000000  00000058
       0000000000000000  0000000000000000  WA       0     0     1
  [ 3] .bss              NOBITS           0000000000000000  00000058
       0000000000000000  0000000000000000  WA       0     0     1
  [ 4] .comment          PROGBITS         0000000000000000  00000058
       000000000000002c  0000000000000001  MS       0     0     1
  [ 5] .note.GNU-stack   PROGBITS         0000000000000000  00000084
       0000000000000000  0000000000000000           0     0     1
  [ 6] .note.gnu.pr[...] NOTE             0000000000000000  00000088
       0000000000000020  0000000000000000   A       0     0     8
  [ 7] .eh_frame         PROGBITS         0000000000000000  000000a8
       0000000000000038  0000000000000000   A       0     0     8
  [ 8] .rela.eh_frame    RELA             0000000000000000  00000150
       0000000000000018  0000000000000018   I       9     7     8
  [ 9] .symtab           SYMTAB           0000000000000000  000000e0
       0000000000000060  0000000000000018          10     3     8
  [10] .strtab           STRTAB           0000000000000000  00000140
       000000000000000b  0000000000000000           0     0     1
  [11] .shstrtab         STRTAB           0000000000000000  00000168
       0000000000000067  0000000000000000           0     0     1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  D (mbind), l (large), p (processor specific)

链接静态库

提示

动态链接执行很复杂,比静态链接执行时间长。 但是,极大的节省了 size。 其中用到的 PIC 和动态链接技术是计算机发展史上非常重要的一个里程碑。

# gcc [.c] [.a] -o [.o]
# gcc [.c] -o [.o] -l[库名] -L[库路径]
gcc calc.c liboperation.a -o calc

# 也可以直接使用.o文件链接
gcc calc.o tfunc.o add.o -o calc

$ ./calc 1 2
1 + 2 = 3
$ file calc
calc: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=50ba230b15340df52d926d4a374a9938bd2c6917, for GNU/Linux 3.2.0, not stripped
$ ldd calc # 查看可执行程序的依赖
        linux-vdso.so.1 (0x00007fffc95dd000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f38e7817000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f38e7a4d000)
$ readelf -l calc

Elf file type is DYN (Position-Independent Executable file)
Entry point 0x1080
There are 13 program headers, starting at offset 64

Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  PHDR           0x0000000000000040 0x0000000000000040 0x0000000000000040
                 0x00000000000002d8 0x00000000000002d8  R      0x8
  INTERP         0x0000000000000318 0x0000000000000318 0x0000000000000318
                 0x000000000000001c 0x000000000000001c  R      0x1
      [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
  LOAD           0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000660 0x0000000000000660  R      0x1000
  LOAD           0x0000000000001000 0x0000000000001000 0x0000000000001000
                 0x0000000000000225 0x0000000000000225  R E    0x1000
  LOAD           0x0000000000002000 0x0000000000002000 0x0000000000002000
                 0x0000000000000144 0x0000000000000144  R      0x1000
  LOAD           0x0000000000002db0 0x0000000000003db0 0x0000000000003db0
                 0x0000000000000260 0x0000000000000268  RW     0x1000
  DYNAMIC        0x0000000000002dc0 0x0000000000003dc0 0x0000000000003dc0
                 0x00000000000001f0 0x00000000000001f0  RW     0x8
  NOTE           0x0000000000000338 0x0000000000000338 0x0000000000000338
                 0x0000000000000030 0x0000000000000030  R      0x8
  NOTE           0x0000000000000368 0x0000000000000368 0x0000000000000368
                 0x0000000000000044 0x0000000000000044  R      0x4
  GNU_PROPERTY   0x0000000000000338 0x0000000000000338 0x0000000000000338
                 0x0000000000000030 0x0000000000000030  R      0x8
  GNU_EH_FRAME   0x0000000000002014 0x0000000000002014 0x0000000000002014
                 0x0000000000000044 0x0000000000000044  R      0x4
  GNU_STACK      0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000000 0x0000000000000000  RW     0x10
  GNU_RELRO      0x0000000000002db0 0x0000000000003db0 0x0000000000003db0
                 0x0000000000000250 0x0000000000000250  R      0x1

 Section to Segment mapping:
  Segment Sections...
   00
   01     .interp
   02     .interp .note.gnu.property .note.gnu.build-id .note.ABI-tag .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt
   03     .init .plt .plt.got .plt.sec .text .fini
   04     .rodata .eh_frame_hdr .eh_frame
   05     .init_array .fini_array .dynamic .got .data .bss
   06     .dynamic
   07     .note.gnu.property
   08     .note.gnu.build-id .note.ABI-tag
   09     .note.gnu.property
   10     .eh_frame_hdr
   11
   12     .init_array .fini_array .dynamic .got

创建动态库 .so

shared library 不像静态库是在链接可执行文件时,代码段和数据段直接拷贝到可执行文件中。 动态库来是在运行时加载动态库代码,因此无法在编译和链接阶段获取代码段的符号地址(代码段的符号包括引用的全局数据,调用的函数等)。

生成目标文件 .o

# gcc -c -fpic [.c/.cpp] [.c/.cpp] ...
# -fpic/-fPIC 
#       PIC(position independent code)
#       -fPIC 与生成动态链接可以说没有直接关系,不用fPIC依然可以编译出so文件。
#       但是如果不加 -fPIC 则加载 .so 文件的代码段时,代码段引用的数据对象需要重定位。
#       重定位会修改代码段的内容,这就造成每个使用这个 .so 文件代码段的进程在内核里都会生成这个 .so 文件代码段的copy。
#       由于于这个 .so 文件代码段和数据段内存映射的位置不一样,每个copy都不一样。
#       💡一般用fPIC来生成so,而生成a时则不用fPIC
# 
#       不使用fPIC编译so的情况:(满足以下4个条件)
#       1. 该库可能需要经常更新
#       2. 该库需要非常高的效率(尤其是有很多全局量的使用时)
#       3. 该库并不很大
#       4. 该库基本不需要被多个应用程序共享
gcc -c -fpic tfunc.c add.c
$ file tfunc.o add.o
tfunc.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped
add.o:   ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped
$ readelf -h add.o tfunc.o
File: add.o
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              REL (Relocatable file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x0
  Start of program headers:          0 (bytes into file)
  Start of section headers:          464 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           0 (bytes)
  Number of program headers:         0
  Size of section headers:           64 (bytes)
  Number of section headers:         12
  Section header string table index: 11
File: tfunc.o
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              REL (Relocatable file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x0
  Start of program headers:          0 (bytes into file)
  Start of section headers:          536 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           0 (bytes)
  Number of program headers:         0
  Size of section headers:           64 (bytes)
  Number of section headers:         13
  Section header string table index: 12

生成动态库 .so

# gcc -shared [.o] [.o] ... -o [lib库名.so]
# -shared —— 生成共享目标文件。通常用在建立共享库时。
#            💡是否添加 -fPIC 的问题:
#            从GCC来看,shared应该是包含fPIC选项的,但似乎不是所以系统都支持,所以最好显式加上fPIC选项。
gcc -shared tfunc.o add.o -o liboperation.so
$ file liboperation.so
liboperation.so: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, BuildID[sha1]=a95332c5ba7a9350a185a84281e834d6285908e1, not stripped
$ readelf -h liboperation.so
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              DYN (Shared object file) # 💡文件类型
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x0
  Start of program headers:          64 (bytes into file)
  Start of section headers:          13696 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         11
  Size of section headers:           64 (bytes)
  Number of section headers:         29
  Section header string table index: 28

链接动态库

# gcc [.c/.cpp] -o [可执行文件名] -l[库名] -L[库路径] -Wl,-rpath=[库路径]
# -Wl.option —— 此选项传递option给链接
#               多个option中间用逗号","分割
# -rpath              —— 运行时动态库路径
# -l[库名] -L[库路径]  —— 编译时动态库路径
gcc calc.c -o calc -loperation -L$(pwd) -Wl,-rpath=$(pwd) 
$ file calc
calc: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=121f5be582653e7d6f188f0aabcaaf085217becc, for GNU/Linux 3.2.0, not stripped
$ ldd calc # 查看可执行程序的依赖
        linux-vdso.so.1 (0x00007ffe9476e000)
        liboperation.so => ./liboperation.so (0x00007f527e631000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f527e402000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f527e63d000)

GCC默认头文件搜索路径

$ echo | gcc -v -x -c -E -
/usr/lib/gcc/x86_64-linux-gnu/7/include
/usr/local/include
/usr/lib/gcc/x86_64-linux-gnu/7/include-fixed
/usr/include/x86_64-linux-gnu
/usr/include

todo 作用