linux中gcc和gdb和makefile

gcc编译器

GCC 是Linux 下的编译工具集, 是GNU Compiler Collection 的缩写,包含**gcc、g++**等编译器。这个工具集不仅包含编译器,还包含其他工具集, 例如ar 、nm 等。

GCC 下常见的编译器

GCC 编译器命令含义
cc指的是C 语言编译器
gcc指的是C 语言编译器
g++指的是C++语言编译器
cpp指的是预处理编译器

系统默认的头文件,

[root@lc133 ceshi]# cpp -v
...
#include <...> 搜索从这里开始:
 /usr/lib/gcc/x86_64-redhat-linux/4.8.5/include
 /usr/local/include
 /usr/include
....

库文件路径

找gcc的环境变量LIBRARY_PATH
再找内定目录 /lib /usr/lib /usr/local/lib

gcc编译4步骤: 预处理、编译、汇编、连接。

常用参数:
-c			预处理,编译,和汇编,也就是他只把程序做成.o目标文件
-S			预处理和编译,就是指把文件编译成为汇编代码
-E			预处理,这个不生成文件, 你需要把它重定向到一个输出文件里面。
-o			制定目标名称, 默认的时候, gcc 编译出来的文件是 a.out,
-C			在预处理的时候, 不删除注释信息, 一般和-E使用, 有时候分析程序
-O0 、-O1 、-O2 、-O3	编译器的优化选项的 4 个级别,-O0 表示没有优化, -O1 为默认值,-O3 优化级别最高。
-g:			编译时添加调试语句。 主要支持 gdb 调试。
-Wall: 		显示所有警告信息。
-D:			向程序中“动态”注册宏定义。   #define NAME VALUE
-I:			指定头文件所在目录位置。

优化的简单介绍

O1优化会消耗较多的编译时间,它主要对代码的分支,常量以及表达式等进行优化。

O2会尝试更多的寄存器级的优化以及指令级的优化,它会在编译期间占用更多的内存和编译时间。

O3在O2的基础上进行更多的优化,例如使用伪寄存器网络,普通函数的内联,以及针对循环的更多优化。

预处理

作用:展开宏,头文件,替换条件编译,删除注释,空行,空白

-E参数生成.i文件

[root@lc133 ceshi]# gcc -E hello.c -o hello.i

编译

检查语法规范,消耗时间,系统资源最多

-S参数生成.s文件

[root@lc133 ceshi]# gcc -S hello.i -o hello.s

汇编

汇编指令翻译成机器指令

-c生成.o文件

[root@lc133 ceshi]# gcc -c hello.s -o hello.o

一般直接-c参数直接生成目标文件

链接

数据段合并,一般将内存空间的只读空间合并。读写空间合并,缩小内存的占用空间。

地址回填,main函数的地址与其他函数地址是相对的,main的地址确定,其他函数的地址才能确定。如果是动态库中的函数的话,他们的地址是运行时确定的,不是链接时确定的。

[root@lc133 ceshi]# ls
hello.c
[root@lc133 ceshi]# gcc -E hello.c -o hello.i
[root@lc133 ceshi]# gcc -S hello.i -o hello.s
[root@lc133 ceshi]# gcc -c hello.s -o hello.o
[root@lc133 ceshi]# gcc hello.o -o hello
[root@lc133 ceshi]# ./hello
Hello World!

多文件编译

[root@lc133 ceshi]# cat democ1.c democ1.h main.c
#include <stdio.h>

void add(int a,int b){printf("a+b=%d\n",a+b);}
void sub(int a,int b){printf("a-b=%d\n",a-b);}
void mul(int a,int b){printf("a*b=%d\n",a*b);}
void div1(int a,int b){printf("a/b=%d\n",a/b);}

#ifndef DEMOC1_H
#define DEMOC1_H
void add(int a,int b);
void sub(int a,int b);
void mul(int a,int b);
void div1(int a,int b);
#endif // DEMOC1_H

#include <stdio.h>
#include  "democ1.h"
int main()
{
    int a=14,b=7;
    add(a,b);
    sub(a,b);
    mul(a,b);
    div1(a,b);
    printf("Hello World!\n");
    return 0;
}

当源文件,头文件在同一目录下时,将源文件一起链接

[root@lc133 ceshi]# gcc main.c democ1.c -o test
[root@lc133 ceshi]# ./test
a+b=21
a-b=7
a*b=98
a/b=2
Hello World!

不在同一文件-I参数指定头文件

[root@lc133 ceshi]# ls
hea  scr  sou  test
[root@lc133 ceshi]# gcc ./sou/main.c ./sou/democ1.c -I ./hea/ -o test
[root@lc133 ceshi]# ./test
a+b=21
a-b=7
a*b=98
a/b=2
Hello World!

静态库与动态库

静态库在文件中静态展开,所以有多少文件就展开多少次,非常吃内存,100M展开100次,就是1G,但是这样的好处就是静态加载的速度快,静态库在程序编译时会被连接到目标代码中,程序运行时将不再需要该静态库,因此体积较大。

静态库对函数库的链接是放在编译时期完成的。

程序在运行时与函数库再无瓜葛,移植方便。

浪费空间和资源,因为所有相关的目标文件与牵涉到的函数库被链接合成一个可执行文件。

使用动态库会将动态库加载到内存,10个文件也只需要加载一次,然后这些文件用到库的时候临时去加载,速度慢一些,但是很省内存,动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入,因此在程序运行时还需要动态库存在,因此代码体积较小。

动态库把对一些库函数的链接载入推迟到程序运行的时期。

可以实现进程之间的资源共享。(因此动态库也称为共享库)

将一些程序升级变得简单。

甚至可以真正做到链接载入完全由程序员在程序代码中控制(显示调用)。

制作静态库

说明:

静态库名字:lib库名.a

静态库生成指令,ar rcs libname.a file1.o file2.o …

1.编译源码生成.o文件

[root@lc133 sou]# gcc -c democ1.c -o democ1.o

2.生成静态库

[root@lc133 sou]# ar rcs libmylib.a democ1.o

3.使用静态库,

[root@lc133 sou]# gcc main.c libmylib.a -I ../hea/ -o test

删除静态库后test依旧能运行,所以程序在运行时与函数库再无瓜葛

但是文件体积较大

[root@lc133 sou]# ll
总用量 20
-rw-r--r-- 1 root root  209 11月 29 11:30 democ1.c
-rw-r--r-- 1 root root  174 11月 29 11:07 main.c
-rwxr-xr-x 1 root root 8552 11月 29 13:45 test

生成动态库

生成位置无关的.o文件

[root@lc133 sou]# gcc -c democ1.c -o democ1.o -fPIC

使用这个参数过后,生成的函数就和位置无关,挂上@plt标识,等待动态绑定

使用 gcc -shared制作动态库

[root@lc133 sou]# gcc -shared -o libmylib.so democ1.o

编译可执行程序时指定所使用的动态库。-l:指定库名 -L:指定库路径

[root@lc133 sou]# gcc main.c -o dong -l mylib -L . -I ../hea/

执行动态库生成程序需要配置动态库路径

1.动态库路径写入 配置文件,ldconfig生效

动态库所在位置执行命令

[root@lc133 sou]# pwd >> /etc/ld.so.conf
[root@lc133 sou]# ldconfig
[root@lc133 sou]# ./dong
a+b=21
a-b=7
a*b=98
a/b=2
Hello World!
[root@lc133 sou]#

2.配置环境变量LD_LIBRARY_PATH,

临时生效

[root@lc133 sou]# export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/root/ceshi/sou

永久生效写入环境变量配置文件,全局配置文件或者用户环境配置文件.(点)或者source重读配置文件

[root@lc133 sou]# export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/root/ceshi/sou >> /etc/profile
[root@lc133 sou]# source /etc/profile
[root@lc133 sou]# ./dong
a+b=21
a-b=7
a*b=98
a/b=2
Hello World!

对比两库生成的程序

[root@lc133 sou]# ldd dong
        linux-vdso.so.1 =>  (0x00007ffef4ffd000)
        libmylib.so (0x00007fef9529e000)
        libc.so.6 => /lib64/libc.so.6 (0x00007fef94ed0000)
        /lib64/ld-linux-x86-64.so.2 (0x00007fef954a0000)
[root@lc133 sou]# ldd jing
        linux-vdso.so.1 =>  (0x00007fffe4732000)
        libc.so.6 => /lib64/libc.so.6 (0x00007f75b29de000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f75b2dac000)

动态库程序有一个链接到自己的动态库libmylib.so

[root@lc133 sou]# objdump -sD jing > jing.txt
[root@lc133 sou]# objdump -sD dong > dong.txt
[root@lc133 sou]# cat jing.txt 
...
000000000040057d <main>:
  40057d:       55                      push   %rbp
  40057e:       48 89 e5                mov    %rsp,%rbp
  400581:       48 83 ec 10             sub    $0x10,%rsp
  400585:       c7 45 fc 0e 00 00 00    movl   $0xe,-0x4(%rbp)
  40058c:       c7 45 f8 07 00 00 00    movl   $0x7,-0x8(%rbp)
  400593:       8b 55 f8                mov    -0x8(%rbp),%edx
  400596:       8b 45 fc                mov    -0x4(%rbp),%eax
  400599:       89 d6                   mov    %edx,%esi
  40059b:       89 c7                   mov    %eax,%edi
  40059d:       e8 3e 00 00 00          callq  4005e0 <add>
  4005a2:       8b 55 f8                mov    -0x8(%rbp),%edx
  4005a5:       8b 45 fc                mov    -0x4(%rbp),%eax
  4005a8:       89 d6                   mov    %edx,%esi
  4005aa:       89 c7                   mov    %eax,%edi
  4005ac:       e8 58 00 00 00          callq  400609 <sub>
  4005b1:       8b 55 f8                mov    -0x8(%rbp),%edx
  4005b4:       8b 45 fc                mov    -0x4(%rbp),%eax
  4005b7:       89 d6                   mov    %edx,%esi
  4005b9:       89 c7                   mov    %eax,%edi
  4005bb:       e8 74 00 00 00          callq  400634 <mul>
  4005c0:       8b 55 f8                mov    -0x8(%rbp),%edx
  4005c3:       8b 45 fc                mov    -0x4(%rbp),%eax
  4005c6:       89 d6                   mov    %edx,%esi
  4005c8:       89 c7                   mov    %eax,%edi
  4005ca:       e8 8d 00 00 00          callq  40065c <div1>
  4005cf:       bf 20 07 40 00          mov    $0x400720,%edi
  4005d4:       e8 77 fe ff ff          callq  400450 <puts@plt>
  4005d9:       b8 00 00 00 00          mov    $0x0,%eax
  4005de:       c9                      leaveq
  4005df:       c3                      retq
...

[root@lc133 sou]# cat dong.txt
...
000000000040070d <main>:
  40070d:       55                      push   %rbp
  40070e:       48 89 e5                mov    %rsp,%rbp
  400711:       48 83 ec 10             sub    $0x10,%rsp
  400715:       c7 45 fc 0e 00 00 00    movl   $0xe,-0x4(%rbp)
  40071c:       c7 45 f8 07 00 00 00    movl   $0x7,-0x8(%rbp)
  400723:       8b 55 f8                mov    -0x8(%rbp),%edx
  400726:       8b 45 fc                mov    -0x4(%rbp),%eax
  400729:       89 d6                   mov    %edx,%esi
  40072b:       89 c7                   mov    %eax,%edi
  40072d:       e8 7e fe ff ff          callq  4005b0 <add@plt>
  400732:       8b 55 f8                mov    -0x8(%rbp),%edx
  400735:       8b 45 fc                mov    -0x4(%rbp),%eax
  400738:       89 d6                   mov    %edx,%esi
  40073a:       89 c7                   mov    %eax,%edi
  40073c:       e8 cf fe ff ff          callq  400610 <sub@plt>
  400741:       8b 55 f8                mov    -0x8(%rbp),%edx
  400744:       8b 45 fc                mov    -0x4(%rbp),%eax
  400747:       89 d6                   mov    %edx,%esi
  400749:       89 c7                   mov    %eax,%edi
  40074b:       e8 b0 fe ff ff          callq  400600 <mul@plt>
  400750:       8b 55 f8                mov    -0x8(%rbp),%edx
  400753:       8b 45 fc                mov    -0x4(%rbp),%eax
  400756:       89 d6                   mov    %edx,%esi
  400758:       89 c7                   mov    %eax,%edi
  40075a:       e8 91 fe ff ff          callq  4005f0 <div1@plt>
  40075f:       bf 00 08 40 00          mov    $0x400800,%edi
  400764:       e8 57 fe ff ff          callq  4005c0 <puts@plt>
  400769:       b8 00 00 00 00          mov    $0x0,%eax
  40076e:       c9                      leaveq
  40076f:       c3                      retq
...

利用objdump反汇编对比

静态库程序

  40059d:       e8 3e 00 00 00          callq  4005e0 <add>

动态库程序

40072d:       e8 7e fe ff ff          callq  4005b0 <add@plt>

动态库add函数多了一个@plt标识

gdb调试命令

用gcc/g++编译源程序需要加-g参数

[root@lc133 ceshi]# gcc ./sou/ceshi.c ./sou/ceshi1.c -I ./hea/ -o ceshi  -g

使用gdb调试

[root@lc133 ceshi]# gdb ceshi

基本调试命令

命令                   命令缩写             命令说明 
set args                                设置主程序的参数。设置main函数命令行参数 (在 start、run 之前)
run                     r               开始运行程序。运行到第一个断点位置,如果没有断点就直接运行结束。可以使用run查找段错误出现位置。
run 字串1 字串2 ...: 					设置main函数命令行参数

list					l				 list 1  列出源码。根据源码指定 行号设置断点。
break                   b               设置断点。
b 20 if i = 5:							设置条件断点。
delete breakpoint						删除断点,breakpoint填写对应的序号
info b: 								查看断点信息表
next                    n               执行当前行。如果当前行包含函数调用,不会进入函数。
step                    s               执行当前行。如果当前行包含函数调用,则进入函数,执行函数体第一条语句。注意,如果函数是库函数或者第三方提供的函数,由于没有源代码,也无法进入函数体。
finish					f				结束当前函数调用。 
print                   p               显示变量或表达式的值。
continue                c               继续运行程序,直到下一个断点或者程序结束。
set var name = value                    设置变量的值。
ptype:									查看变量类型。
display:								设置跟踪变量
undisplay:								取消设置跟踪变量。
quit                    q               退出gdb环境。

jump					j				使程序从当前要执行的代码处,直接跳转到指定位置处继续执行后续的代码。

bt:										列出当前程序正存活着的栈帧。
frame: 									根据栈帧编号,切换栈帧。

core文件

core文件其实就是内存的映像,当程序崩溃时,存储内存的相应信息,用于对程序进行调试。当程序崩溃时便会产生core文件,其实准确的应该说是core dump文件,默认生成位置与可执行程序位于同一目录下,文件名为core。

产生coredump的条件,首先需要确认当前会话的ulimit –c,若为0,则不会产生对应的coredump,需要进行修改和设置。

[root@lc133 sou]# ulimit -c
0
[root@lc133 sou]# ulimit -a  #第一条
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 7667
max locked memory       (kbytes, -l) 8192
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 7667
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

让core文件能够产生,设置core大小为无限制:

[root@lc133 sou]# ulimit -c unlimited
[root@lc133 sou]# ulimit -c
unlimited

可以将unlimited改成合适的大小,单位为blocks(KB)

永久开启core dump功能,可修改配置文件/etc/security/limits.conf

core dump默认会生成在程序的工作目录

[root@lc133 ceshi]# cat -n ccc.c
     1  #include <stdio.h>
     2  #include<stdlib.h>
     3  int main()
     4  {
     5
     6      int* q=(int *)malloc(50);
     7      scanf("%d\n",q);
     8      printf("数字 %d\n", *q);
     9
    10
    11      char* p=(char *)malloc(50);
    12      scanf("%s",p);
    13      printf("字符串 :%s\n", *p);
    14      return 0;
    15  }
    16
[root@lc133 ceshi]# gcc ccc.c -o test -g
[root@lc133 ceshi]# ./test
45
56
数字 45
段错误(吐核)
[root@lc133 ceshi]# ls
ccc.c  ceshi  core.25985  data  hea  scr  sou  test
[root@lc133 ceshi]# gdb core.25985
GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-120.el7
Copyright (C) 2013 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-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
[New LWP 25985]
Missing separate debuginfo for the main executable file
Try: yum --enablerepo='*debug*' install /usr/lib/debug/.build-id/b3/404b397629e80cd6cfd11c589566bf1f772703
Core was generated by `./test'.
Program terminated with signal 11, Segmentation fault.
#0  0x00007fa2ab055079 in ?? ()
"/root/ceshi/core.25985" is a core file.
Please specify an executable to debug.
(gdb)

Core was generated by `./test’. core文件由当前目录test产生

Program terminated with signal 11, Segmentation fault. 告诉我们信号中断了我们的程序,发生了段错误。

[root@lc133 ceshi]# gdb test
GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-120.el7
Copyright (C) 2013 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-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /root/ceshi/test...done.
(gdb) core-file ./core.25985
[New LWP 25985]
Core was generated by `./test'.
Program terminated with signal 11, Segmentation fault.
#0  0x00007fa2ab055079 in vfprintf () from /lib64/libc.so.6
Missing separate debuginfos, use: debuginfo-install glibc-2.17-326.el7_9.x86_64
(gdb) bt
#0  0x00007fa2ab055079 in vfprintf () from /lib64/libc.so.6
#1  0x00007fa2ab05b4e9 in printf () from /lib64/libc.so.6
#2  0x000000000040066f in main () at ccc.c:13
(gdb)

gdb 调试程序,进入gdb环境后,core-file core的名字,敲bt命令,这是gdb查看back trace的命令,查看函数的调用的栈帧和层级关系。可以看到main函数的13行出错。*p该为p就正确了。

更改core文件生成目录

[root@lc133 ceshi]# echo $PWD/data/core.%e.%p > /proc/sys/kernel/core_pattern
%%,单个%号字符
%p,所dump进程的进程ID
%u,所dump的实际用户ID
%g,所dump进程的实际组ID
%s,导致本次coredump的信号
%t,coredump的时间戳
%e,程序文件名

centos7gdb调试中的一个报错

Missing separate debuginfos, use: debuginfo-install glibc-2.17-326.el7_9.x86_64

安装glibc,执行debuginfo-install glib,修改文件enabled=1

yum install glibc
debuginfo-install glib
[root@lc133 ~]# more /etc/yum.repos.d/CentOS-Debuginfo.repo
....
[base-debuginfo]
name=CentOS-7 - Debuginfo
baseurl=http://debuginfo.centos.org/7/$basearch/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-Debug-7
enabled=1

100个gdb小技巧 https://wizardforcel.gitbooks.io/100-gdb-tips/content/index.html

关于Makefile

makefile是一个文件,定义了一系列的规则来指定哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为 makefile就像一个shell脚本一样,也可以执行操作系统的命令。

make:是一个解释makefile中指令的命令工具。

目的:更好的维护大量代码,减少编译时间。

一个规则:

目标:依赖条件
	(一个tab缩进)命令

注意:

1.目标的时间必须晚于依赖条件的时间,否则,更新目标

修改.c文件后,.c文件的修改时间发生变化,会出现目标文件的时间早于作为依赖材料.c的时间,出现这种情况的.c文件会重新编译。

2.依赖条件如果不存在,找寻新的规则去产生依赖条件。

3.makefile默认第一个目标为终极目标,如果第一个目标生成成功,后面的指令将不会被执行,可以使用ALL:指定 makefile 的终极目标。

两个函数:

src = $(wildcard ./*.c): 匹配当前工作目录下的所有.c 文件。将文件名组成列表,赋值给变量 src。

obj = $(patsubst %.c, %.o, $(src)): 将参数3中,包含参数1的部分,替换为参数2。

clean: (没有依赖)

​ -rm -rf $(obj) a.out

“-”:作用是,删除不存在文件时,不报错。顺序执行结束。

“@”不显示命令本身,只显示结果

clean用途: 清除编译生成的中间.o文件和最终目标文件

三个自动变量:

$@: 在规则的命令中,表示规则中的目标。

$^: 在规则的命令中,表示所有依赖条件。

$<: 在规则的命令中,表示第一个依赖条件。如果将该变量应用在模式规则中,它可将依赖条件列表中的依赖依次取出,套用模式规则。

模式规则:

%.o:%.c
	gcc -c $< -o %@

静态模式规则:

$(obj):%.o:%.c
	gcc -c $< -o %@

伪目标:

.PHONY: clean ALL

make clean 如果当前目录下有同名clean文件,则不执行clean对应的命令,声明目标为伪目标之后,makefile将不会该判断目标是否存在或者该目标是否需要更新

make常用参数:

-n:非执行模式,输出所有执行命令,但并不执行;
-f:指定“makefile”文件;
其他:
-i:忽略命令执行返回的出错信息;
-s:沉默模式,在执行之前不输出相应的命令行信息;
-r:禁止使用build-in规则;
-t:更新目标文件;
-q:make操作将根据目标文件是否已经更新返回"0"或非"0"的状态信息;
-p:输出所有宏定义和目标文件描述;
-d:Debug模式,输出有关文件和检测时间的详细信息。

示例

使用gcc编译,./src/*.c 制定目录下的全部.c文件,-I制定头文件目录,-o生成指定文件,-g 可使用gdb调试,-Wall显示所有告警信息。

[lc@lc133 maketest]$ ls
homeWork  inc  obj  src
[lc@lc133 maketest]$ gcc ./src/*.c -I ./inc/ -o test -g -Wall
[lc@lc133 maketest]$ ./test
10+5=15
10-5=5
10/5=1

写一个makefile,all指定终极目标,test目标文件,./src/*.c依赖文件,后面一行(一个tab)加命令

all:test
test:./src/*.c
        gcc ./src/*.c -I ./inc/ -o test -g -Wall

-f指定makefile文件,-n看一下要执行的命令

[lc@lc133 maketest]$ make -f test.mk -n
gcc ./src/*.c -I ./inc/ -o test -g -Wall

检查没问题编译

[lc@lc133 maketest]$ make -f test.mk
gcc ./src/*.c -I ./inc/ -o test -g -Wall
[lc@lc133 maketest]$ ./test
10+5=15
10-5=5
10/5=1

结合前面的规则,两个函数,三个变量进行修改,加了一步在obj目录下生成目标文件

src = $(wildcard ./src/*.c)
obj = $(patsubst ./src/%.c, ./obj/%.o, $(src))
my_args= -g -Wall
my_file=test
my_inc=./inc

.PHONY:ALL clean

all:$(my_file)
$(my_file):$(obj)
        @gcc $^ -o $(my_file) $(my_args)
$(obj): ./obj/%.o:./src/%.c
        @gcc -c $< -I $(my_inc) -o $@ $(my_args)
clean:
        @-rm -rf $(my_file) $(obj)

make编译:

[lc@lc133 maketest]$ make -f test.mk -n
gcc -c src/div1.c -I ./inc -o obj/div1.o -g -Wall
gcc -c src/mul.c -I ./inc -o obj/mul.o -g -Wall
gcc -c src/hello.c -I ./inc -o obj/hello.o -g -Wall
gcc -c src/add.c -I ./inc -o obj/add.o -g -Wall
gcc -c src/sub.c -I ./inc -o obj/sub.o -g -Wall
gcc obj/div1.o obj/mul.o obj/hello.o obj/add.o obj/sub.o -o test -g -Wall
[lc@lc133 maketest]$ make -f test.mk
[lc@lc133 maketest]$ ./test
10+5=15
10-5=5
10/5=1
[lc@lc133 maketest]$ ls
homeWork  inc  obj  src  test  test.mk
[lc@lc133 maketest]$ make -f test.mk clean
[lc@lc133 maketest]$ ls
homeWork  inc  obj  src  test.mk

在hello.c源文件中,添加乘法,执行make,make只对乘法模块重新编译,其他的并没有参加重新编译。可以更好的维护大量代码,以及减少编译时间。

[lc@lc133 maketest]$ vi ./src/hello.c
[lc@lc133 maketest]$ make -f test.mk  -n
gcc -c src/hello.c -I ./inc -o obj/hello.o -g -Wall
gcc obj/div1.o obj/mul.o obj/hello.o obj/add.o obj/sub.o -o test -g -Wall
[lc@lc133 maketest]$ make -f test.mk
[lc@lc133 maketest]$ ./test
10+5=15
10-5=5
10/5=1
10x5=50
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值