• GDB及Makefile学习(20201217王菁)


    GDB

    (1)下载安装gdb: sudo apt-get install gdb
    (2)启动gdb gdb test

    (3)启动后界面如下:
    参考老师所给ppt内容

    我们可以输入(gdb) l列出文件的代码清单

    ·(gdb) b
    1.函数断点:在进入指定函数时停住。
    2.行断点:在指定行号停住。eg: (gdb) b 8
    3.条件断点:break ... if
    4.临时断点:tb 行号

    **·(gdb) r **运行被调试的程序。如果此前没有下过断点,则执行完整个程序;如果有断点,则程序暂停在第一个可用断点处。

    **·(gdb) p i **显示指定变量(临时变量或全局变量)的值 ,这里就是打印输出变量i的值

    ·(gdb) finish 使一个函数结束

    **·(gdb) q **退出断点调试

    Makefile

    什么是makefile?

    makefile关系到了整个工程的编译规则。一个工程中的源文件不计其数,并且按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为makefile就像一个 Shell脚本一样,其中也可以执行操作系统的命令。
    makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。

    compile和link(链接)的概念

    源码compile(检查语法,有函数声明即可通过)后得到中间文件(UNIX是.o);
    对中间文件进行打包得到库文件(UNIX是.a);
    把它们link(将xx.o和xx.a合成一坨一个可执行文件)——链接函数和全局变量等,找不到函数实现就会出现link error——得到可执行文件UNIX无后缀

    makefile和shell的区别

    作用:
    ·shell是为了重用terminal内的命令服务的,是系统程序员与OS内核的交互接口;
    ·makefile是用于工程compile/link用的;
    ·makefile内可写shell命令、调用shell脚本,如:+ ./xxx.sh;
    ·shell内 =号不允许有空格,makefile内 =号空格无碍;
    ·shell内开头要写 #!/bin/bash,后缀名是.sh;
    ·shell内是自上而下执行,有数组、循环等;makefile内执行shell命令是一行独立一个进程,若想一个进程统一执行,得在末尾用 \ 表同一行。
    ·shell内通配符:*;makefile内通配符:%;
    ·shell内变量用 {},命令串用 ();makefile中访问变量用 $() 或 ${} 都行;
    编写格式:

    目标target:   所需prerequisites
    (TAB) command (任意的Shell命令)
    	
    label:
    (TAB) command...
    

    makefile简单示例

    示例①:我们创建一个project文件夹,在里边新建一个简单的test.c工程:

    #include <stdio.h>
    int main()
    {
        printf("hello world\n");
        return 0;
    }
    

    根据我们上文列出的makefile编写规则

    target: dependencies****
    	command
    

    我们编写以下makefile文件
    先用vim makefile 创建一个makefile文件,文件内写入如下内容:

    test: test.c
    	gcc test.c -o test
    

    发现运行成功

    事例②:
    我们创建以下几个文件:
    main.c:

    #include "tool.h"
    #include "bar.h"
    #include <stdio.h>
    int main()
    {
    	int arr[5] = {1,9,3,8,0};
    	int min = find_min(arr, 5);
    	int max = find_max(arr, 5);
    	printf("min = %d\n", min);
    	printf("max = %d\n", max);
    	return 0;	
    }
    

    tool.h:
    int find_max(int arr[], int n);

    tool.c:

    #include "tool.h"
    int find_max(int arr[], int n)
    {
    	int m = arr[0];
    	for(int i = 0; i < n; i++)
    	{
    		if(arr[i] > m)
    		{
    			m = arr[i];
    		}
    	}
    	return m;
    }
    

    bar.h:
    int find_min(int arr[], int n);

    bar.c:

    #include "bar.h"
    int find_min(int arr[], int n)
    {
    	int m = arr[0];
    	for(int i = 0; i < n; i++)
    	{	
    		if(arr[i] < m)
    		{
    			m = arr[i];
    		}
    	}
    	return m;
    }
    
    第一阶段makefile

    编写makefile:

    main: main.c tool.o bar.o
    	gcc main.c tool.o bar.o -o main
    
    tool.o: tool.c
    	gcc -c tool.c
    
    bar.o: bar.c
    	gcc -c bar.c
    
    clean:
    	rm *.o main
    

    首先,要从最终生成的可执行文件写起,此处为 main。还是先写
    target - main,dependencies - main.c tool.o bar.o,
    换行之后按下 tab 键,再写 command - gcc main.c tool.o bar.o -o main
    然后,开始写依赖项 tool.o bar.o
    依赖中间文件 .o 文件生成最终的可执行文件,可以避免编译整个文件。哪个文件发生了改变,只需编译该文件对应的 .o 文件即可。之后再与其他文件共同生成最终的可执行文件。

    从图中可以看出,terminal 中的执行顺序是与 Makefile 中的书写顺序相反的,将 Makefile 中的内容由下至上执行

    第二、三阶段makefile

    makefile变量
    使用OBJ变量、省去指令内容,自动推导:

    这种自动推导过程叫做隐含规则
    “隐含规则”也就是一种惯例,make会按照这种“惯例”心照不喧地来运行,那怕我们的Makefile中没有书写这样的规则。例如,把[.c]文件编译成[.o]文件这一规则,你根本就不用写出来,make会自动推导出这种规则,并生成我们需要的[.o]文件。

    第四阶段makefile

    自动变量($^ $< $@)
    具体意义如下:
    $@ :指代当前规则下的目标文件列表
    $< :指代依赖文件列表中的第一个依赖文件
    $^ : 指代依赖文件列表中所有依赖文件
    $? : 指代依赖文件列表中新于对应目标文件的文件列表

    多个文件makefile的编译

    如果有多个文件,这时候不能并列写编译,而是要在开头添加all声明
    依旧拿我们刚才的例子,这次我们在两个目标程序前添加一个all,随后编译运行,成功~
    makefile:

    all:main_max main_min
    main_max: main_max.c tool.o bar.o
    	gcc main_max.c tool.o bar.o -o main_max
    main_min: main_min.c tool.o bar.o
    	gcc main_min.c tool.o bar.o -o main_min
    tool.o: tool.c
    	gcc -c tool.c
    bar.o: bar.c
    	gcc -c bar.c
    clean:
    	rm *.o main_max main_min
    

    makefile的工作原理

    目标的生成: a. 检查规则中的依赖文件是否存在; b. 若依赖文件不存在,则寻找是否有规则用来生成该依赖文件

    比如上图中,生成calculator的规则是gcc main.o add.o sub.o mul.o div.o -o,Makefil会先检查main.o, add.o, sub.o, mul.o, div.o是否存在,如果不存在,就会再寻找是否有规则可以生成该依赖文件。

    比如缺少了main.o这个依赖,Makefile就会在下面寻找是否有规则生成main.o。当它发现gcc main.c -o main.o这条规则可以生成main.o时,它就利用此规则生成main.o,然后再生成终极目标calculator。
    目标的更新: a. 检查目标的所有依赖,任何一个依赖有更新时,就重新生成目标; b. 目标文件比依赖文件时间晚,则需要更新。

    参考博客:
    [https://blog.csdn.net/weixin_44498318/article/details/115769976?utm_medium=distribute.pc_relevant.none-task-blog-2defaultbaidujs_baidulandingword~default-8-115769976-blog-125890413.pc_relevant_multi_platform_whitelistv3&spm=1001.2101.3001.4242.5&utm_relevant_index=11](Linux Makefile快速入门)
    https://blog.csdn.net/qq_34623621/article/details/121537317

  • 相关阅读:
    tip6: 程序不工作就是最大的异常
    简单实用的Code Review工具
    HDU4008 Parent and son [树形DP]
    HDU4004 The Frog's Games [二分]
    HDU4006 The kth great number [堆]
    HDU4024 Dwarven Sniper’s hunting [二分]
    HDU4005 The war [树形DP]
    HDU4009 Transfer water [最小树形图]
    HDU4023 Game [贪心+博弈]
    HDU4007 Dave [杂题]
  • 原文地址:https://www.cnblogs.com/ssssspm/p/16754077.html
Copyright © 2020-2023  润新知