Linux项目自动化构建工具
会不会写makefile,从一个侧面说明了一个人是否具备完成大型工程的能力
make是一个命令工具,是一个解释makefile中指令的命令工具,make是一条命令,makefile是一个文件,两个搭配使用,完成项目自动化构建
例如makefile:
先touch makefile
后vim makefile写东西例如:
mytest:test.c file.x file.x 依赖关系,多个的话用空格隔开 mytest为目标文件
gcc -0 mytest test.c 依赖方法,前面用tab空出
.PHONY:clear clear对应的方法总是会执行的,不会出现提醒
clear:
rm -rf mytest
又例如:
code.exe:code.c
gcc -0 $@ $^ @表示目标文件,^表示依赖文件列表,$表示取出的意思,就如下图所示$@ 表示 code.exe,$^ 表示code.c
make后出现 gcc -o code.exe code.c
但是实际上依赖关系为:
code.exe:code.o 先执行这组依赖关系但是找不到code.o所以make会自动找下一组依赖关系
gcc code.o -o code.exe
code.o:code.s make/makefile会自动根据文件中的依赖关系进行自动推导,帮找我们执行
gcc -c code.s -o code.o 所有相关的依赖关系 (相当于找不到依赖入栈,找到出栈)-相当于递归
code.s:code.i
gcc -S code.i -o code.s
code.i:code.c 找到这组依赖关系了,然后执行之前的关系
gcc -E code.c -o code.i
.PHONY:clean
clean:
rm -rf code.i code.s code.o code.exe
makefile变量名
当然你也可以用变量名(相当于c语言的宏定义) makefile中的变量名等号两侧无空格,多文件用空格隔开
bin=code.exe
src=code.c
$(bun):$(src)
gcc -0 $@ $^
@echo "compiler $(bin) to $(src)" 意味着依赖方法可以写指令
.PHONY:clean
rm -rf $(bin)
//@rm -rf $(bin) 加@就意味着不显示这个命令执行过程而是直接执行
但是最终为code.exe:code.c因为编译器在翻译的时候一步到位了 makefile注释用#字符
make会根据makefile的内容完成编译,make的检测顺序是从上往下,直接make就执行第一个,再make就不行了而要加命令make clear
makefile对最新的可执行文件默认不想再重新形成-是为了提高效率毕竟有的代码跑一次要很长时间(一小时甚至更久)当然你也可以强制用.PHONY:mytest
makefile怎么知道我的程序需要被编译呢?是因为将可执行文件与源文件的时间进行对比,源文件最新需要编译,可执行文件最新不需要编译,我们一般是先写源代码后形成可执行文件所以可执行文件最新,如果我们修改了源代码那么源代码最新
用stat file 查看最近修改的时间(Modify那一行)
如果一个文件已经有了那么再touch一下就会改变它的修改时间(Modify)
例如:
[wwz@wwz ~]$ stat testvim.c
File : ‘testvim.c’
Size : 328 Blocks : 8 IO Block : 4096 regular file
Device : fd01h / 64769d Inode : 1065957 Links : 1
Access : (0664 / -rw - rw - r--) Uid : (1000 / wwz) Gid : (1000 / wwz)
Access : 2024 - 02 - 01 13 : 48 : 37.153974126 + 0800
Modify : 2024 - 02 - 01 13 : 48 : 37.149973804 + 0800
Change : 2024 - 02 - 01 13 : 48 : 37.149973804 + 0800
Birth : -
解析:
这是一个文件`testvim.c`的详细信息,其中包括:
- 文件大小为328字节
- 占用8个磁盘块,每个磁盘块大小为4096字节
- 是一个普通文件
- 设备号为fd01h / 64769d
- Inode号为1065957
- 链接数为1
- 文件权限为0664( - rw - rw - r--),即所有者和同组用户有读写权限,其他用户只有读权限
- 所有者的用户ID为1000,用户名为wwz
- 所在组的组ID为1000,组名为wwz
- 上次访问时间为2024 - 02 - 01 13:48 : 37.153974126 + 0800
- 上次修改时间为2024 - 02 - 01 13:48 : 37.149973804 + 0800
- 元数据(如权限、所有者等)上次更改时间为2024 - 02 - 01 13:48 : 37.149973804 + 0800
"Access"表示最后一次访问文件的时间。在这个例子中,文件testvim.c的最后访问时间是2024 - 02 - 01 13:48 : 37.153974126 + 0800。
"Modify"表示最后一次修改文件内容的时间。在这个例子中,文件testvim.c的最后修改时间是2024 - 02 - 01 13:48 : 37.149973804 + 0800。
"Change"表示最后一次修改文件元数据(如权限、所有者等)的时间。在这个例子中,文件testvim.c的元数据上次更改时间是2024 - 02 - 01 13:48 : 37.149973804 + 0800。
缓冲区
/n ->回车和换行两个动作 先回车后换行 回车是到当前行最开始位置,换行是当前位置下一行
缓冲区:
例如在linux中一个代码是:
#include<stdio.h>
#include<unistd.h>
int main() {
printf("hello linux");
sleep(3);
return 0;
}
在c语言中函数是从上到下的,先执行printf后sleep但是打印的时候确是先休眠后打印
这是因为在休眠的时候printf的数据在缓冲区(本质内存空间),缓冲区是计算机内存中的一块区域,主要作用是暂时存储数据,以便在适当的时候将这些数据发送到相应的设备
程序结束(return 0)时,一般要强制冲刷缓冲区,所以数据出现在显示屏上 缓冲区满了也会进行刷新
但是如果是printf("hello linux\n");他是直接打印了而不是等休眠结束在打印这是因为对于显示器缓冲区‘\n’会让数据立即刷新而不是让缓冲区的数据定时刷新,但是他对'\n'后面的数据就不管了例如printf("hello\nlinux\n")
1 #include<stdio.h>
2 #include<unistd.h>
3 int main() {
4 int aou = 9;
5 while (aou >= 0) {
6 printf("倒计时%d\r", aou);
7 aou--;
8 fflush(stdout);
9 sleep(2);
}
11 return 0;
}
对于printf的\r的作用是回车即将光标回到这一行最开始,光标在哪就在哪写又因为有个fflush(stdout)强制刷新所以没覆盖就刷新到显示器上
但是如果没有fflush(stdout)最后就不会打印任何数据因为光标覆盖了数据只回车没换行
当你往显示器上写了123数字时,实际上往显示器上写了1字符2字符3字符,其实写了三个字符,所以显示器叫做字符设备,往显示器上打印的任何东西都叫字符
cou=123;printf("%d",cou);往显示器上打印123,虽然printf里有个%d但这个%d不是给显示器说的而是给printf说我这个变量cou的格式的,所以printf把对应的123转化为1字符2字符3字符然后往显示屏上打印
那么同样应用于\r,更好理解回车光标覆盖
#include<stdio.h>
#include<unistd.h>
int main() {
int aou = 10;
while (aou >= 0) {
printf("倒计时%d\r", aou);
aou--;
fflush(stdout);
sleep(2);
}
return 0;
}
往显示屏打印1字符0字符-10,但到9时字符就变短了,最后的0没法覆盖所以用printf("倒计时%2d\r", aou);
#pragma once 是C/C++中的预处理指令,用于确保头文件只被编译一次。这个指令通常放置在头文件的开头,作为头文件保护措施,以防止多次包含同一个头文件导致的重复定义错误。
进度条代码
[wwz@wwz process]$ cat processbar.c
#include"processbar.h"
#include<unistd.h> //调用usleep
#include<string.h>
#define length 101
#define stal '#'
const char* tata = "|/-\\";
void probar() {
char bar[length];
memset(bar, '\0', sizeof(bar));
int aut = 0;
while (aut <= 100) {
printf("[%-100s][%3d%%][%c]\r", bar, aut, tata[aut % 4]);// -100意味着左对齐 %3d意味着右对齐 记得\r
fflush(stdout);//强制冲刷
bar[aut++] = '#';
usleep(20000);//暂停2微秒
}
printf("\n");//一定加\n,不然的话[wwz@wwz process]$会覆盖打印的内容上,得换行
}