【Linux】make/makefile/gdb调试技巧/进度条小程序

目录

一、sudo提权:

二、自动化构建工具make与Makefile

makefile:

make:

是否重新执行make:

伪目标:

三、进度条小程序:

四、Linux调试器gdb:

1.、前景提要:

2、进入与退出:

3、运行代码与打断点:

4、逐过程与逐语句:

5、监视:

6、其他:


一、sudo提权:

Linux的权限是指对文件或目录的读、写、执行的控制,Linux的权限分为三个级别:文件所有者文件所属组其他人,Linux下还有超级用户(root)和普通用户的区别,超级用户可以做任何事情,普通用户受到限制,所以每次当我们在使用普通账号的时候,如果要安装软件,或者搞啥需要root权限的时候,可以直接切换账号,但是这样比较麻烦,有种“杀鸡用牛刀”的感觉了。

为了解决这种问题,就有一种指令sudo,能够帮助我们从普通账号的权限暂时升级拥有root的权限,这是借助了root的身份,所以创建出来的文件之类的拥有者就是root。

但是尽管安装了sudo这个指令,但是最开始是用不好的,需要让root将当前账号加入白名单

首先使用root账号,在根目录下,进入etc目录,找到sudoers文件,并打开它

如下,打开后在root账号下增加自己的用户名,后面将root的后面cv下来,即可

这样,在以后遇到普通用户被拒绝的情况下,只要进行sudo提权,就可以暂时使用root的身份了,在执行sudo提权后的代码需要输入的密码是当前普通账号的密码。

二、自动化构建工具make与Makefile

在我们实际的操作中,如果想编译代码,就需要自己手动地输入g++/gcc ...... 这是很繁琐的,如果在大型的项目中,有许多文件,那么是不是一个一个地编译呢,这样不仅很麻烦,而且还有可能在删除的时候就会出错导致删除出错误的文件,那么为了解决这一问题,就引入了make与makefile

make是一个指令,makefile使一个文件,二者相互搭配使用,帮助项目完成自动化构建

makefile:

Makefile是一种脚本,定义了项目中各个文件之间的依赖关系依赖方法(构建过程)

依赖关系:

依赖关系定义了一个目标是如何生成的,即目标文件需要哪些源文件和头文件,

如下,在这个目录下只有一个test.cpp文件,然后我需要编译形成一个mytest文件,就可以写成:

mytest:test.cpp   这样的形式,由于test.cpp文件的改变会影响mytest文件,所以说mytest文件依赖于test.c文件,这就是个依赖关系。

依赖方法:

借助上面的例子:

mytest依赖于test.cpp,而cpp.c通过 g++ -o mytest test.cpp 这个指令就可以得到mytest,那么mytest依赖于test.cpp的依赖方法就是g++ -o mytest test.cpp。

上述中,为了方便采用了两个组合字符:

$@ 这个就代表着:左边的内容

$^ 这个就代表着:右边的所有内容

make:

make命令会读取Makefile,按照其中的规则来自动化编译和链接‌。它是一个命令工具,用于解释Makefile中的指令。make会根据Makefile中的规则执行命令,完成项目的自动化构建‌

如上,当在Makefile文件中写入上述指令后,在编译就只需要输入一个make就可以自动完成编译,编译出一个可执行程序mytest,这样就可以直接运行了

原理:

1、make会在当前目录下找名字叫“Makefile”或“makefile”的文件
2、如果找到,它会找文件中的第一个目标文件,在上面的例子中,他会找到“mytest”这个文件,并把这个文件作为最终的目标文件
3、如果mytest文件不存在,或是mytest所依赖的后面的test.cpp文件的文件修改时间要比mytest这个文件新,那么,他就会执行后面所定义的命令来生成mytest这个文件
4、如果mytest所依赖的test.cpp文件不存在,那么make会在当前文件中找目标为test.cpp文件的依赖性,如果找到则再根据那一个规则生成test.cpp文件
5、这就是整个make的依赖性,make会一层又一层地去找文件的依赖关系,直到最终编译出第一个目标文件
6、在找寻的过程中,如果出现错误,比如最后被依赖的文件找不到,那么make就会直接退出,并报错,而对于所定义的命令的错误,或是编译不成功,make根本不理

          在进行多项目编译的时候,:后面跟着的就是一个项目中的各个源文件

是否重新执行make:

make会根据源文件和目标文件的新旧,判定是否需要重新执行依赖关系,进行编译。

首先了解一个指令:stat

用法:stat 文件名

作用:可以查看文件的状态信息,在这里我们先主要看Access,Modify,Change

Access:是文件最近一次的访问时间,但是因为访问文件过于频繁,如果一直修改的话,导致运行速率会有所降低的,所以Access会过几次操作之后才会更新一次

Modify:是文件内容最近一次的修改时间,例如用vim,nano在文件内容中增删改

Change:是文件属性最近一次的修改时间,包括权限,大小等等

OK,了解上述文件的时间过后,现在来看看关于make的重新执行:

首先,当文件编译过后会有一个可执行文件,如下面的mytest,这个mytest所依赖的文件test.cpp也会有这三个时间,主要观察的是Modify的时间,如果可执行文件的最近Modify时间比它所依赖的test.cpp的时间要新就证明在编译后,test.cpp文件没有被修改,所以就不能够重新make编译

但是如果对test.cpp继续写入内容导致其Modify时间改变,那么此时的就能够重新编译了,这样就可以避免大量重复编译而消耗时间

但是如果我就想要make总是被执行呢?

伪目标:

用法 :.PHONY  文件名

当一个目标的依赖包含伪目标时,伪目标所定义的命令总是会被执行。

所以当我们对上述Makefile中进行增加伪目标

这样的话无论mytest和test.cpp文件的时间无论新旧都会执行对应的依赖方法,所以在外面无论test.cpp无论是否进行修改都能够一直进行编译

其原理就是在外面忽略了mytest文件,无论这个文件是否存在,都会把make当做指令强制运行

那么在项目清理中就可以伪目标

.PHONY用于标记目标为“伪目标”,即它不依赖于文件名。在运行make clean时,即使当前目录下有一个名为“clean”的文件,make也会忽略这个文件,把clean当作命令来执行
.PHONY:aa可以写成make aa

因为它不需要检查目标文件是否已经存在,直接执行相应的规则

补充:

如果用make的时不想看到我所执行的依赖方法,那么就在Makefile文件中的依赖方法前加@即可

三、进度条小程序:

前提知识:

1、在Linux中是以一行一行为缓冲区的,每当缓冲区被填满或者程序结束或者强制刷新才会在屏幕上打印缓冲区的东西。

强制刷新缓冲区可以用函数fflush(stdout)来进行缓冲区的刷新,

2、\r 与 \n,这是回车与换行,回车是将光标移动到本行的开头,换行是指从当前行向下移动一格

这样就可以每次写入东西的时候提前回车,这样的话就可以覆盖之前写的了

这样就可以先写一个简单的倒计时:

int main()
{ 
    int count = 10;
    while(count>=0)
    {
        printf("%-2d\r",count);
        fflush(stdout);
        sleep(1);
        count--;
    }
 	printf("\n");
    return 0;
}

那么就可以用以上的知识写一个进度条出来了,如下所示。这样就是一个基本进度条的代码了,在main函数中调用,传参的是每次增加的时间   /单位微秒,例如在主函数中调用该函数并传50000

#define BODY '='
#define HEAD '>'
#define NUM 102
#define TOP 100

void processBar(int speed)
{
	char bar[NUM];
	memset(bar,'\0',sizeof(bar));
	int count = 0;
	int len = strlen(lable);
	while(count <= TOP)
	{
		printf("[%-100s][%d%%][%c]\r",bar,count,lable[count%len]);
		fflush(stdout);
		bar[count++] = BODY;
	 	if(count < 100 ) bar[count] = HEAD;
		usleep(speed);
	}
	printf("\n");
}

但是在实际上使用的时候并不是这样的,毕竟要使用者才知道此时加载了多少,所以就只需要一个打印当前进度的函数,然后循环在调用的时候传入当前进度,还可以加上颜色代码之类

#include<unistd.h>

const char* lable="|/-\\";
char bar[NUM];

#define GREEN "\033[0;32;32m"
#define NONE "\033[m"
#define RED  "\033[41m"

void processBar(int rate)
{
	if(rate < 0 || rate > 100) return;

	int len = strlen(lable);
	printf("\033[47m\033[30m\033[1m[%-100s][%d%%][%c]\r\033[0m",bar,rate,lable[rate%len]);
	fflush(stdout);
	bar[rate++] = BODY;
 	if(rate < 100 ) bar[rate] = HEAD;
}

void initBar()
{
	memset(bar,'\0',sizeof(bar));
}


void download(callback_t cb)
{
	int total = 1000;
	int cur = 0;

	while(cur <= total)
	{
		usleep(50000);//模拟下载时间
		
		int rate = cur*100/total;
		cb(rate);
		cur += 10;
	}
	printf("\n");
}

int main()
{
	printf("download1:\n");
	download(processBar);
	initBar();
	printf("download2:\n");
	download(processBar);
	initBar();
	printf("download3:\n");
	download(processBar);
	initBar();
	printf("download4:\n");
	download(processBar);
	initBar();
    return 0;
}

四、Linux调试器gdb:

1.、前景提要:

首先,在操作系统中要先安装gdp调试工具,安装好之后就可以进行调试了,但是在这之前要了解release和dubug两个版本的不同:

release:这基本上算是完整品了,一般在程序猿的项目开发做完之后就可以以release的形式发布出去,在release中就没有调试信息的,毕竟发布出去的项目就已经经过多方面的测试出问题了就不需要在进行调试了

debug:这就是一般程序猿在开发的时候所使用的模式,里面包含着调试信息,这样才能经过gdb工具调试代码

如下使用了指令readelf,这个是能够 显示 elf 格式文件的信息

下面这个是看不到调试信息的,因为Linux中默认编译后的版本是release版本,想要变成debug版本就需要在编译中加上-g选项即可。

如下,在Makefile文件中的编译增加-g选项,这样的话重新编译之后在用readelf查看就可以找到debug的调试信息了。

2、进入与退出:

这样就在编译过后就可以调试可执行程序的文件,通过  gdb  可执行程序名,来进入调试状态

如上,当在左下角出现(gdb)并且没有出现报错就证明进入了调试模式

然后看自己所写的代码就是通过

list / l    行号 :这就是显示源代码,每次只显示10行,下一次使用就是接着上次的位置往下列

list / l    函数名:这就是列出某个函数的源代码

一般情况下,就输入 l 0即可

最后如果在调试过程中退出就可以是quit 或者简写q即可

3、运行代码与打断点:

在调试状态下,就可以直接输入指令run(简写r)来运行此代码,这个就是类似于 vs2022 的F5

关于断点:

语法:break(简写成b)   语句行就可以进行断点的打入,用delete(简写d)进行断点的删除,删除的话要的是断点的编号。

但是尽管打断点之后,在展示的过程中依然是看不到断点的样式的,这样的话就需要我们使用指令info b来观察断点的信息:(主要观察下面红框框中的信息即可)

编号是表示每一个断点的编号,通过编号的区别来将断点区分开,

中间断点的状态(是否开启)可以使用disable来进行关,用enable来进行开

当打断点之后就可以用 continue (简写c) 从一个断点运行到下一个断点

4、逐过程与逐语句:

在vs2022中,逐过程(F10)在遇到函数时,会把函数从整体上看做一条语句,会跳过当前函数块,
逐语句(F11)在遇到函数时,认为函数由多条语句构成,不会跳过当前函数块,会进入函数内部

在Linux的调试中,也有类似于上述的功能,

next(简写n)就是F10,step(简写s)就是F11

5、监视:

bt :查看当前程序堆栈的调用情况

p 变量名 : 查看指定变量的大小

display 变量名 : 一直查看指令变量的大小

6、其他:

finish 函数名,立刻执行完当前函数。

在进入很长的循环的时候,那么不能一句句语句去执行,所以就需要until来进行语句的跳转

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/907664.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Flutter实战短视频课程

1、课程导学 一套代研运行多蜡 体州一致&#xff0c;目胜能优昇 未来大趋势 不改交原生项目的基础上&#xff0c;扩展Flutter能力 Flutter原生灵话切涣 0入侵 最简单、最通用 最新Flutter 3,x新特性讲解 大量flutter官方组件和api学习 最常用的第三方库使用及原理解析 自研组…

程序员的新电脑到手后应该做哪些必要设置?

吃水果要剥皮&#xff0c;用 Windows 也一样&#xff0c;如果是 Win 10 的话&#xff0c;刚装完系统就需要屏蔽一些功能&#xff0c;才能更顺畅快速&#xff1a; 隐藏任务栏上的搜索框和小娜&#xff0c;需要搜索时wins就会出现禁用开始目录的app自动推荐删除人脉图标删除任务…

unocss 添加支持使用本地 svg 预设图标,并支持更改大小

安装 pnpm install iconify/utils 在配置文件 unocss.config.ts&#xff1a; presets > presetIcons 选项中 通过 FileSystemIconLoader 加载本地图标&#xff0c;并指定目录。 import presetWeapp from unocss-preset-weapp import { extractorAttributify, transformer…

Zig 语言通用代码生成器:逻辑,发布冒烟测试版二之二

Zig 语言通用代码生成器&#xff1a;逻辑&#xff0c;发布冒烟测试版二之二 Zig 语言通用代码生成器&#xff1a;逻辑&#xff0c;已发布冒烟测试版二。此版本完善了代码生成物。支持多对多关系。修复了所有单域动词。并有更多缺陷修复。暂时不支持图片类型。暂时不支持日期和…

Vue3的router和Vuex的学习笔记整理

一、路由的基本搭建 1、安装 npm install vue-router --registryhttps://registry.npmmirror.com 2、配置路由模块 第一步&#xff1a;src/router/index.js创建文件 第二步&#xff1a;在src/view下面创建两个vue文件&#xff0c;一个叫Home.vue和About.vue 第三步&#x…

远程连接服务

目录 一、远程连接服务器简介 二、连接加密技术简介 三、认证阶段 四、ssh实验 1.修改ssh服务器的端口号 2.拒绝root账户远程登录 3.允许特定用户ssh登录&#xff0c;其他用户无法登录 4.ssh-keygen 一、远程连接服务器简介 概念&#xff1a; 远程连接服务器通过文字或…

JS中面向对象

一、对象 1.认识对象 在JavaScript中&#xff0c;对象&#xff08;Object&#xff09;是一种复合数据类型&#xff0c;它允许你存储键值对。对象的属性是连接到对象的变量&#xff0c;而函数或方法是属于对象的函数。 JavaScript中的对象类似于哈希表&#xff0c;其中键可以是…

【工具变量】“宽带中国”试点城市名单匹配数据集(2000-2023年)

参照秦文晋&#xff08;2022&#xff09;的《网络基础设施建设对数字经济发展的影响研究——基于"宽带中国"试点政策的准自然实验》一文中的做法&#xff0c;将选为“宽带中国”试点城市的虚拟变量作为核心解释变量&#xff0c;当一个城市被批复成为“宽带中国”试点…

Matlab车牌识别课程设计报告(附源代码)

Matlab车牌识别系统 分院&#xff08;系&#xff09; 信息科学与工程 专业 学生姓名 学号 设计题目 车牌识别系统设计 内容及要求&#xff1a; 车牌定位系统的目的在于正确获取整个图像中车牌的区域&#xff0c; 并识别出车牌号。通过设计实现车牌识别系…

基于OSS搭建在线教育视频课程分享网站

OSS对象存储服务是海量、安全、低成本、高持久的存储服务。适合于存储大规模非结构化数据&#xff0c;如图片、视频、备份文件和容器/虚拟机镜像等。 安装nginx wget https://nginx.org/download/nginx-1.20.2.tar.gz yum -y install zlib zlib-devel gcc-c pcre-devel open…

Edit Data. Create Cell Editors. Validate User Input 编辑数据。创建 Cell Editors。验证用户输入

Goto Data Grid 数据网格 Edit Data. Create Cell Editors. Validate User Input 编辑数据。创建 Cell Editors。验证用户输入 Get and Modify Cell Values in Code 在代码中获取和修改单元格值 仅当 Grid 及其列已完全初始化时&#xff0c;才使用以下方法。如果需要在表单仍…

【JavaEE初阶 — 多线程】Thread的常见构造方法&属性

目录 Thread类的属性 1.Thread 的常见构造方法 2.Thread 的几个常见属性 2.1 前台线程与后台线程 2.2 setDaemon() 2.3 isAlive() Thread类的属性 Thread 类是JVM 用来管理线程的一个类&#xff0c;换句话说&#xff0c;每个线程都有一个唯一的Thread 对象与之关联&am…

【设计模式】如何用C++实现依赖倒置

【设计模式】如何用C实现依赖倒置 一、什么是依赖倒置&#xff1f; 依赖倒置原则&#xff08;Dependency Inversion Principle&#xff0c;DIP&#xff09;是SOLID面向对象设计原则中的一项。它的核心思想是&#xff1a; 高层模块不应该依赖于低层模块&#xff0c;两者都应该…

【文献及模型、制图分享】中国城市家庭食物浪费行为及减量对策——以郑州市为例

文献介绍 减少食物浪费是保障粮食安全的重要途径。家庭是社会的基本单元&#xff0c;不仅是产生食物浪费的主要场景&#xff0c;也是开展反食品浪费教育的重要场所。本文以河南省郑州市为例&#xff0c;基于1315份城市家庭食物浪费一手调查数据&#xff0c;首次将城市家庭食物…

【Linux】从零开始使用多路转接IO --- poll

碌碌无为&#xff0c;则余生太长&#xff1b; 欲有所为&#xff0c;则人生苦短。 --- 中岛敦 《山月记》--- 从零开始使用多路转接IO 1 前言1 poll接口介绍3 代码编写4 总结 1 前言 上一篇文章我们学习了多路转接中的Select&#xff0c;其操作很简单&#xff0c;但有一些缺…

linux网络编程自定义协议和多进程多线程并发

1.三次握手及后面过程 计算机A是客户端, B是服务端 1.1三次握手&#xff1a; 1客户端给服务端SYN报文 2服务端返回SYNACK报文 3客户端返回ACK报文 客户端发完ACK后加入到服务端的维护队列中&#xff0c;accept()调用后就能和客户端建立连接&#xff0c;然后建立通讯 1.2关闭…

[CARLA系列--01]CARLA 0.9.15 在Windows下的安装教程(一)

Carla是一款开源的自动驾驶仿真器&#xff0c;它基本可以用来帮助训练自动驾驶的所有模块&#xff0c;包括感知系统&#xff0c;Localization, 规划系统等等.Carla这个产品目前已经更新到了最新的0.9.15版本,目前遇到好多人在windows系统上如何安装可编辑版的Carla遇到了好多问…

【Qt聊天室客户端】用户信息界面设置功能实现

1. 按钮禁用关系梳理 基本逻辑梳理 用户界面-申请好友按钮 只有当前用户不是你的好友时&#xff0c;该按钮才可以使用&#xff0c;否则是禁用状态 用户界面-发送消息与删除好友 当前用户是你的好友时&#xff0c;按钮才可以使用&#xff0c;否则这两个按钮禁用区分是否是你好…

一张图简单讲述Mamba的演进过程

这张图表提供了 RNN&#xff08;1986&#xff09;、LSTM&#xff08;1997&#xff09;、Transformer&#xff08;2017&#xff09;和 Mamba&#xff08;2024&#xff09;四种不同的神经网络架构在训练阶段、测试阶段和额外问题方面的对比。可以看出&#xff0c;Mamba 作为一种最…

redis v6.0.16 安装 基于Ubuntu 22.04

redis安装 基于Ubuntu 22.04 本文演示如何在ubuntu22.04下&#xff0c;安装redis v6.0.16&#xff0c;并配置测试远程访问。 Step1 更新环境 sudo apt updateStep2 安装redis sudo apt install redis-server -yStep3 启动 sudo systemctl restart redissudo systemctl sta…