GCC(GNU project C and C++ compiler)

gcc编译过程

  • 预处理,处理源码中的预编译指令,如include define
  • 编译,将源码编译成汇编语言代码
  • 汇编,将汇编代码翻译成机器语言,生成.o文件
  • 链接,将上述过程生成的目标文件与系统库中的目标文件和库文件链接起来,生成可执行文件

gcc 命令

gcc [options] [filenames]

  • -Wall:允许所有有用的警告;
  • -o:定义输出文件;
  • -c:只编译汇编生成.o目标文件,不链接;
  • -S:只编译生成汇编代码
  • -I:设置头文件的搜索路径;
  • -l:链接外部库文件
  • -L:设置库文件的搜索路径;
  • -O:O1,O2,O3,O4,O5优化级别;
  • -g:gdb调试用,在可执行程序中包含标准调试信息;
  • -w:关闭所有警告;
  • -E完成预处理/预编译停止;

链接库文件神马的没用过啊,只知道链接自定义的头文件用-I 指定头文件所在文件夹路径就OK了

gcc例子

ex01 生成汇编代码

finalize@junjie:~/ex01$ gcc -S helloworld.c
finalize@junjie:~/ex01$ cat helloworld.s
    .file   "helloworld.c"
    .section    .rodata
.LC0:
    .string "hello world!"
    .text
    .globl  main
    .type   main, @function
main:
.LFB0:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    movl    $.LC0, %edi
    call    puts
    movl    $0, %eax
    popq    %rbp
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE0:
    .size   main, .-main
    .ident  "GCC: (Ubuntu 4.8.2-19ubuntu1) 4.8.2"
    .section    .note.GNU-stack,"",@progbits
finalize@junjie:~/ex01$ gcc -o hello helloworld.s
finalize@junjie:~/ex01$ ./hello
hello world!
finalize@junjie:~/ex01$

ex02 使用-Wall选项

finalize@junjie:~/ex02$ cat bad.c 
/* bad.c */
#include <stdio.h>
int main(int argc, char **argv){
    printf("Two plus two is %f\n", 4);
    return 0;
}

finalize@junjie:~/ex02$ gcc -Wall bad.c
bad.c: In function ‘main’:
bad.c:4:5: warning: format ‘%f’ expects argument of type ‘double’, but argument 2 has type ‘int’ [-Wformat=]
     printf("Two plus two is %f\n", 4);
     ^
finalize@junjie:~/ex02$

ex03 含有头文件的编译

finalize@junjie:~/ex03$ ls -l
total 0
drwxrwxrwx 1 root root   0 May 12 20:29 d1
drwxrwxrwx 1 root root 240 May 16 22:00 d2
finalize@junjie:~/ex03$ ls -l d1
total 1
-rwxrwxrwx 1 root root 48 Apr  6 12:17 hello.h
finalize@junjie:~/ex03$ ls -l d2
total 1
-rwxrwxrwx 1 root root 124 Apr  6 12:17 hello.c
-rwxrwxrwx 1 root root 104 May 16 21:57 main.c
finalize@junjie:~/ex03$ cd d2
finalize@junjie:~/ex03/d2$ gcc -I ../d1 hello.c main.c
finalize@junjie:~/ex03/d2$ ls -l
total 13
-rwxrwxrwx 1 root root 8574 May 16 22:01 a.out
-rwxrwxrwx 1 root root  124 Apr  6 12:17 hello.c
-rwxrwxrwx 1 root root  104 May 16 21:57 main.c
finalize@junjie:~/ex03/d2$ ./a.out
Hello, world!
finalize@junjie:~/ex03/d2$

gdb(GNU project C and C++ compiler)

gdb基本命令

  • file 装入想要调试的可执行文件;
  • kill 终止正在调试的程序;
  • continue 继续执行,直到遇到下一个断点
  • list 列出产生执行文件的源代码的一部分;
  • next 执行一行源代码但不进入函数内部;
  • step 执行一行源代码而且进入函数内部;
  • run 执行当前被调试的程序;
  • quit 终止 gdb ;
  • watch 使你能监视一个变量的值而不管它何时被改变;
  • break 在代码里设置断点, 这将使程序执行到这里时被挂起;
  • make 使你能不退出 gdb 就可以重新产生可执行文件;
  • shell 使你能不离开 gdb 就执行 UNIX shell 命令.

gdb调试举例

在可执行程序中包含标准调试信息

finalize@junjie:~/ex06$ ls -l
total 1
-rwxrwxrwx 1 root root 209 Apr  6 12:31 gdbtest.c
-rwxrwxrwx 1 root root 130 Apr  6 12:30 sum.c
finalize@junjie:~/ex06$ gcc -g sum.c gdbtest.c -o gdbtest
finalize@junjie:~/ex06$ ls -l
total 13
-rwxrwxrwx 1 root root 10165 May 16 22:17 gdbtest
-rwxrwxrwx 1 root root   209 Apr  6 12:31 gdbtest.c
-rwxrwxrwx 1 root root   130 Apr  6 12:30 sum.c
finalize@junjie:~/ex06$

用gdb设置断点进行调试

finalize@junjie:~/ex06$ gdb gdbtest
GNU gdb (Ubuntu 7.7.1-0ubuntu5~14.04.2) 7.7.1
Copyright (C) 2014 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from gdbtest...done.
(gdb) list
1   /* gdbtest.c */
2   #include <stdio.h> 
3   
4   int sum(int m);
5   
6   int main(int argc, char **argv){
7       int i, n = 0;
8       sum(50);
9       for(i=1; i<=50; i++){
10          n += i;
(gdb) break 9
Breakpoint 1 at 0x400593: file gdbtest.c, line 9.
(gdb) break sum
Breakpoint 2 at 0x400538: file sum.c, line 3.
(gdb) break 10 if i==10
Breakpoint 3 at 0x40059c: file gdbtest.c, line 10.
(gdb) info break
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x0000000000400593 in main at gdbtest.c:9
2       breakpoint     keep y   0x0000000000400538 in sum at sum.c:3
3       breakpoint     keep y   0x000000000040059c in main at gdbtest.c:10
    stop only if i==10
(gdb) run
Starting program: /ex06/gdbtest

Breakpoint 2, sum (m=50) at sum.c:3
3       int i, n = 0;
(gdb) print i
$1 = 4195869
(gdb) print n
$2 = 0
(gdb) next
4       for(i=1; i<=m; i++){
(gdb) step
5           n += i;
(gdb) print i
$3 = 1

make

make能够根据文件的时间戳自动发现更新过的源文件,并通过读入Makefile文件来对更新的源文件进行编译而对其它文件只进行链接操作。

makefile的格式

target:dependency_file command (command之前有个tab)

例:

源代码:

/* hello.h */
void hello (const char * name);

/* hello.c */
#include <stdio.h> 
#include "hello.h" 
void hello (const char * name){ 
    printf ("Hello, %s!\n", name); 
} 

/* main.c */
#include "hello.h" 
int  main (int argc, char **argv){ 
    hello ("world"); 
    return 0; 
} 

makefile

main:main.o hello.o
    gcc main.o hello.o -o main
main.o:main.c
    gcc -Wall -c main.c -o main.o
hello.o:hello.c hello.h
    gcc -Wall -c hello.c -o hello.o

运行make

finalize@junjie:~/ex07$ make main
gcc -Wall -c main.c -o main.o
gcc -Wall -c hello.c -o hello.o
gcc main.o hello.o -o main
finalize@junjie:~/ex07$./main
Hello, world!
finalize@junjie:~/ex07$

makefile中变量的使用

  • 变量定义 OBJS=var
  • 变量使用 $(OBJS)

更改上述makefile内容为

OBJS=main.o hello.o
CC=gcc -Wall -c
main:$(OBJS)
    gcc $(OBJS) -o main
main.o:main.c
    $(CC) main.c -o main.o
hello.o:hello.c hello.h
    $(CC) hello.c -o hello.o

makefile中常见的自动变量

  • $@ 目标文件的完整名称
  • $^ 所有不重复的依赖文件,以空格分开
  • $< 第一个依赖文件
  • $* 不包含扩展名的目标文件名称
  • $+ 所有依赖文件,以出现的先后顺序,包括重复文件
  • $? 所有时间戳比目标文件旧的依赖文件

将上述makefile改为

OBJS=main.o hello.o
CC=gcc -Wall -c
main:$(OBJS)
    gcc $^ -o $@
main.o:main.c
    $(CC) $^ -o $@
hello.o:hello.c hello.h
    $(CC) $< -o $@