Linux服务器开发-基础教程总结(1)-基础教程
目录
- 前言
- 正文
- 1. 使用tar对文件进行压缩
- 2. gcc的整个编译过程
- 3. gcc的其他一些参数:
- 4. lib静态库文件
- 5. 共享库(动态库)
- 6. GDB调试
- 7. MakeFile
- 基础知识
- 8. C库函数
- 9. 库函数与系统函数之间的关系
- 10. open函数的使用
- 11. read函数的使用
- 12. readAndWrite函数的应用
- 13.lseek
- 14. stat函数
- 15. access
- 16. truncate
- 17. link
- 18. 常用命令
- 19. dup,dup2(复制现有的文件描述符)
- 20. fcntl
- 总结
- 参考
前言
本篇文章是观看视频所做的一些笔记。
正文
1. 使用tar对文件进行压缩
tar 参数: 不使用z/j 参数 命令只能对文件或目录打包
- c——创建——压缩
- x——释放——解压缩
- v——显示提示信息——压缩解压缩 可省略
- f——指定压缩文件的名字
z-——使用gzip的方式压缩文件 .gz
j——使用 bzip2的方式压缩文件 .bz2
压缩:
tar zcvf 生成的压缩包的名字(xxxx.tar.gz)
tar jcvf 生成的压缩包的名字(xxx.tar.bz2)
2. gcc的整个编译过程
预处理->编译->汇编->链接
编译期间是最耗时的。
- 这个编译过程很简单,我用罗列的方式应该就看起来简单很多了。
首先,准备一个main.c ,我相信这个过程应该大家都是会的。然后正式开始编译:
gcc -E main.c -o main.i
gcc -S main.i -o main.s
gcc -c main.s -o main.o
gcc main.o -o main
最后直接执行这个./main即可。
看出来猫腻了吗,那个参数分别是E S c . -o 表示的是要生成的文件的名称,分别是i ,s ,o 。就这样记忆应该就可以记录下来了。
当然上面这个过程只是让你了解gcc编译的而整个过程,而实际上,你可以直接用一条指令就可以解决这样的问题了。
gcc main.c -o main
直接一条命令就可以将main.c 编译成功了。
3. gcc的其他一些参数:
-I : 指定头文件的路径
-D: 指定一个宏,相当于在文件中define 了一个宏。
-Wall :编译期间输出警告
-g:gdb调试时需要该参数
-L :后面接要依赖的库的目录
-l: 后面接具体依赖的库的名字,注意要去掉lib这个前缀。
-fPIC:就可以生成与位置无关的代码
-O(1-3):表示优化的级别 -O1 或-O2 或-O3
4. lib静态库文件
制作步骤:
- 生产对应的.o文件 —>c -o -c
- 将生成的.o文件打包 ar rcs+静态库的名字(libMytest.a)+生成的所有的.o
使用: main.c -L -l
gcc main.c -LlibPath -llibName -o app -Iinclude
发布 和使用静态库
3. 发布.a文件
4. 给.h文件
优点:
5. 由于静态库以及被打包到可执行文件中了,所以,在发布的时候就不用再发布静态库了。
6. 加载库的速度快。
缺点 :
7. 可执行文件中会变大。
8. 升级很麻烦,需要重新编译程序。
5. 共享库(动态库)
- 命令规则
lib +名字+ .so
- 制作步骤
生成与位置无关的代码(生成与位置无关的.o)
gcc -fPIC -c *.c -Iinclude
将.o打包成共享库
- 打包方式
gcc -shared -o lib名字.so *.o
- 使用方式
gcc main.c lib/libmy.so -o app
gcc main.c -LlibPath -lmytest -Iinclude -o app
- 查找依赖的库
ldd myApp
一般是先去查找环境变量
- 应用程序不能执行,动态连接器连接不到自己制作的库
- 临时设置的方法
export LD_LIARARY_PATH = ./lib
- 永久设置的方法
- 找到动态链接库的配置文件:/etc/ld.so.conf
- 在该文件中添加动态库的目录(绝对路径)
- 更新 :sudo ldconfig -v
6. GDB调试
- 注意使用gcc编译程序的时候要使用-g的选项,才会是生成的可执行文件里面有行号,才可以进行操作。
- l :显示程序
- b num: 打断点
- i: info的意思
- i b: 代表显示出断点信息
- start :让程序启动,会开始跑到断点的那个地方
- n:next就是一步一步向后走,直接就执行完函数体了
- c: 就是continue 继续跑
- s: step进入到函数体的内部
- p: printf 表示的是打印某个变量
- ptype: 显示某个变量的类型
- start和run的区别:默认情况下,run 指令会一直执行程序,直到程序执行结束。如果程序中手动设置有断点,则 run 指令会执行程序至第一个断点处. start 指令会执行程序至 main() 主函数的起始位置,即在 main() 函数的第一行语句处停止执行(该行代码尚未执行)。
- file 文件名(绝对路径): 可以通过file命令指定要进行gdb调试的文件。
- –args: 指定需要传递给程序的数据
- set args: 可以借助 set args 命令指定目标调试程序启动所需要的数据
- run® 数据:可以使用run 或者start启动目标程序时,指定其所需要的数据。
- cd /tmp/demo :将 GDB 调试器的工作目录修改为 /tmp/demo
- path /temp/demo :某些场景中,目标调试程序的执行还需要临时修改 PATH 环境变量,此时就可以借助 path 指令
- run >a.txt: 通过run > 可以将运行的程序的输出结果输出到a.txt.
- watch cond: watch 称为监控断点,cond 表示要监控的变量
- catch event:建立捕捉断点的方式很简单
- catch 库的名称:监控库的加载(使用ldd App 可以获知其运行所需加载的动态库)
- break … if cond: 在某种条件下使断点发挥其作用。
- condition bnum expression:参数 bnum 用于代指目标断点的编号;参数 expression 表示为断点添加或修改的条件表达式。用于为 bnum 编号的断点添加或修改 expression 条件表达式
- condition bnum:用于删除 bnum 编号断点的条件表达式,使其变成普通的无条件断点
- ignore bnum count: 参数 bnum 为某个断点的编号;参数 count 用于指定该断点失效的次数。仅为一个整数,它用来表示该断点失效的次数
- next,step,until :都可以控制GDB调试器每次只执行一行代码。
- step next基本相同:但当step遇到函数时,会进入到函数内部,并在函数第一行代码处停下。
- until:不带参数的 until 命令,可以使 GDB 调试器快速运行完当前的循环体,并运行至循环体外停止。注意,until 命令并非任何情况下都会发挥这个作用,只有当执行至循环体尾部(最后一行代码)时,until 命令才会发生此作用。
- until location:location只是行号。
- finish:如果是在循环体内非最后一次循环,直接finish是出不来的。可以把循环的位置的断点去掉。就可以跳出函数体了。
- set var 变量名= 赋值:设置变量的值
- display 变量名:自动打印变量值,设置追踪变量
- undisplay:取消追踪变量
- info display:获取编号
- u: 跳出循环的命令
- quit:退出gdb
7. MakeFile
基础知识
-
makefile中的shell的含义:
-
在规则中需要使用符号 本 身 的 地 方 , 需 要 书 写 两 个 连 续 的 本身的地方,需要书写两个连续的 本身的地方,需要书写两个连续的$
-
$? 表示比目标还要新的依赖文件列表
-
分号是分隔符,反斜线是换行符,反斜杠是转义字符。
-
CUR_C := $(filter %.c, ( C U R S R C ) ) : 过 滤 掉 所 有 (CUR_SRC)):过滤掉所有 (CURSRC)):过滤掉所有(CUR_SRC)里面不符合%.c的文件 “filter”函数可以用来去除一个变量中的某些字符串.
-
cat 111.txt | tr [a-z] [A-Z] > 222.txt:tr命令用于转换文本文件中的字符
-
$(strip STRINT)
函数名称:去空格函数—strip。
函数功能:去掉字串(若干单词,使用若干空字符分割) “STRINT”开头和结尾的
空字符,并将其中多个连续空字符合并为一个空字符。
返回值:无前导和结尾空字符、使用单一空格分割的多单词字符串。
函数说明:空字符包括空格、[Tab]等不可显示字符。 -
$1表示取值
-
$(foreach var text commond):
var:局部变量
text:文件列表,空格隔开,每一次取一个值赋值为变量var
commond:对var变量进行操作(一般会使用var变量,不然没意义),每次操作结果都会以空格隔开,最后返回空格隔开的列表。 -
call:call函数是唯一一个可以用来创建新的参数化的函数。 ( c a l l < e x p r e s s i o n > ; , < p a r m 1 > ; , < p a r m 2 > ; , < p a r m 3 > ; . . . ) 当 m a k e 执 行 这 个 函 数 时 , < e x p r e s s i o n > ; 参 数 中 的 变 量 , 如 (call <expression>;,<parm1>;,<parm2>;,<parm3>;...) 当make执行这个函数时,<expression>;参数中的变量,如 (call<expression>;,<parm1>;,<parm2>;,<parm3>;...)当make执行这个函数时,<expression>;参数中的变量,如(1), ( 2 ) , (2), (2),(3)等,会被参数< parm1>;,;,;依次取代。而;的返回值就是 call函数的返回值。
-
=:代表的是赋值的意思:OBJECTS=$(SOURCES:.cpp=.o):代表的是将SOURCES 中的.o都代替成.cpp。
-
wildcard取所有目录下的.c文件。
-
四种赋值方式
简单赋值 ( := ) 编程语言中常规理解的赋值方式,只对当前语句的变量有效。
递归赋值 ( = ) 赋值语句可能影响多个变量,所有目标变量相关的其他变量都受影响。
条件赋值 ( ?= ) 如果变量未定义,则使用符号中的值定义变量。如果该变量已经赋值,则该赋值语句无效。
追加赋值 ( += ) 原变量用空格隔开的方式追加一个新值。
-
makefile 的编写
规则的三要素:目标,依赖,命令
目标:依赖条件
命令
一定要有个TAP键
-
在MakeFile中如果有多条规则的话,那么默认第一个目标就是终极目标。
-
为了防止每次修改一个就得 全部都编译,就把依赖的目标更改为.o文件。
-
工作原理:
makefile版本 -
版本一:
app:main.c add.c sub.c mul.cgcc main.c add.c sub.c mul.c -o app
- 版本二:
- 版本三:使用变量名代表一系列名字 target:目标
app: main.o add.o sub.o
gcc main.o sub.o mul.o -o app
%.o:%.c ->会在找main.o找不到的时候,自动把main填入达到%里面。
makefile中的自动变量:
$<: 规则中的第一个依赖
$@:规则中的目标
$^:规则中的所有依赖
只能在规则的命令中使用。
- 版本四:
#makefile自己维护的变量
CC=cc
# CPPFLAGS:
CPPFLAGS =
# 这里的cc其实就是gcc
5. 版本五:
- makefile给我们提供的函数都是返回值的。
- wildcard:获取指定目录下的.c文件:wildcard
- pastsubst:把指定目录下的.c 文件替换成.o。 这里模式匹配使用的是%,不是*。
- 给makefile提供函数传参,只需要将其参数与函数名用空格分离即可。但参数和参数之间使用逗号进行间隔。
- 取变量里面的内容记得要加$。
- 这样获取到的obj,就可以获取一系列函数的.o文件名字的集合。
- 版本六:Clean目标的加入
1.-rm :这个-的含义就是忽略掉当前命令执行失败的情况。
2. 查找指定目录下,指定类型的文件: src = $(wildcard ./*.c);
3. 匹配替换函数:obj = ( p a t s u b s t (patsubst %.c,%.o, (patsubst(src);
4. .PHONY:这个的意义是,这个是个伪目标,所以,即使当前文件夹中存在clean这个文件,也依然会执行clean下面的语句。
三个自动变量:
- $<: 规则中的第一个依赖
- $^:规则中的所有依赖
- $@:规则中的目标
8. C库函数
- 与位置无关的代码:
- #define NULL (void *)0 :这里的NULL其实就在
受保护的地址
。 - 为什么要弄一个虚拟地址空间:
- 虚拟地址空间,注意虚拟的含义。
9. 库函数与系统函数之间的关系
- FD:文件描述符 FD_POS:文件指针 BUFFER:buffer
2.write:做一个将用户空间拷贝到内核空间
10. open函数的使用
- 举个例子
11. read函数的使用
返回值:
- -1 :读取失败
- 0:文件读完了。
- 正数:文件读取上来的字节数。
12. readAndWrite函数的应用
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main()
{//打开一个已经存在的文件int fd = open("file.txt",O_RDONLY);if(fd==-1){perror("open");exit(1);}//创建一个新文件---写操作int fd1 = open("newfile",O_CREAT|O_WRONLY,0664);if(fd1==-1){perror("open1");exit(1);}//read filechar buf[2048]={0};int count = read(fd,buf,sizeof(buf));if(count==-1){perror("read");exit(1);}while(count){//将读出的数据写入到另一个文件中国int ret =write(fd1,buf,count);printf("write bytes %d\n",ret);count = read(fd,buf,sizeof(buf));}//close fileclose(fd);close(fd1);return 0;
}
作用:将某个文件中的内容读取到另一个文件中的内容,新创建的一个文件。
13.lseek
- 获取文件大小
- 移动文件指针
- 文件拓展
应用
#include <stdlib.h>int main()
{int fd = open("aa",O_RDWR);if(fd==-1){perror("open file");exit(1);}int ret = lseek(fd,0,SEEK_END);printf("file length=%d\n",ret);//文件拓展ret = lseek(fd,2000,SEEK_END);printf("return value:%d\n",ret);//实现文件拓展,需要再最后做一次写操作write(fd,"a",1);close(fd);return 0;
}
- 注意,在使用lseek进行拓展后,一定要额外进行一次拓展。不然,是没办法完成拓展操作的。
14. stat函数
依赖的头文件
这个的含义就是追踪和不追踪的意思。意思就是在遇到软链接的时候,是否会追踪到最底下的文件进行硕源。
stat是一个穿透的函数。
- 带l的是不穿透的。
15. access
成功就是0,不成功就返回-1。
16. truncate
17. link
unlink的应用
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
int main()
{int fd = open("tempfile",O_CREAT|O_RDWR,0664);if(fd==-1){perror("open");exit(1);}//删除临时文件fileint ret = unlink("tempfile");//write filewrite(fd,"hello\n",6);//重置文件指针lseek(fd,0,SEEK_SET);//read filechar buf[24] = {0};int len = read(fd,buf,sizeof(buf));//将读出的内容,写到屏幕上write(1,buf,len);//close fileclose(fd);return 0;
}
18. 常用命令
rename
int rename(const char*oldpath,const char* newpath);
chdir
改变进程的路径
getcwd
获取当前进程目录
rmdir
删除空目录
opendir
打开一个目录
readdir
应用
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <dirent.h>int getFileNum(char* root)
{//open dirDIR* dir = NULL;dir = opendir(root);if(dir==NULL){perror("opendir");exit(1);}//遍历当前打开的目录struct dirent* ptr = NULL;char path[1024];while(ptr=readdir(dir)!=NULL){//过滤,和if((strcmp(ptr->d_name,".")==0)||(strcmp(ptr->d_name,".."==0)){continue;}if(ptr->d_type==DT_DIR){//递归 读目录sprintf(path,"%s/%s",root,ptr->d_name);total += getFileNum(path);}//如果是普通文件if(ptr->d_type==DT_REG){total++;}}closedir(dir);//一定要关掉目录return total;
}int main(int argc,char * argv[])
{if(argc<2){printf("./a.out dir\n");}int total = getFileNum(argv[1]);printf("-->z %s has file numbers%d\n",argv[1],total);return 0;
}
19. dup,dup2(复制现有的文件描述符)
dup返回的就是文件描述符中没有被占用的最小的文件描述符。
20. fcntl
改变已经打开的文件的属性
总结
这个Linux服务器开发-基础教程总结(1) 视频到这就结束了,基本上把一些Linux开发的一些基本技能都展示了一下,师傅领进门修行在个人。接下来,就得靠自己去不断的熟练这些东西。接下来,开始看(2)的,就开始接触进程的一些概念了。
参考
- C/C++高级编程系列(1)之Linux服务器开发一基础教程
Linux服务器开发-基础教程总结(1)-基础教程
目录
- 前言
- 正文
- 1. 使用tar对文件进行压缩
- 2. gcc的整个编译过程
- 3. gcc的其他一些参数:
- 4. lib静态库文件
- 5. 共享库(动态库)
- 6. GDB调试
- 7. MakeFile
- 基础知识
- 8. C库函数
- 9. 库函数与系统函数之间的关系
- 10. open函数的使用
- 11. read函数的使用
- 12. readAndWrite函数的应用
- 13.lseek
- 14. stat函数
- 15. access
- 16. truncate
- 17. link
- 18. 常用命令
- 19. dup,dup2(复制现有的文件描述符)
- 20. fcntl
- 总结
- 参考
前言
本篇文章是观看视频所做的一些笔记。
正文
1. 使用tar对文件进行压缩
tar 参数: 不使用z/j 参数 命令只能对文件或目录打包
- c——创建——压缩
- x——释放——解压缩
- v——显示提示信息——压缩解压缩 可省略
- f——指定压缩文件的名字
z-——使用gzip的方式压缩文件 .gz
j——使用 bzip2的方式压缩文件 .bz2
压缩:
tar zcvf 生成的压缩包的名字(xxxx.tar.gz)
tar jcvf 生成的压缩包的名字(xxx.tar.bz2)
2. gcc的整个编译过程
预处理->编译->汇编->链接
编译期间是最耗时的。
- 这个编译过程很简单,我用罗列的方式应该就看起来简单很多了。
首先,准备一个main.c ,我相信这个过程应该大家都是会的。然后正式开始编译:
gcc -E main.c -o main.i
gcc -S main.i -o main.s
gcc -c main.s -o main.o
gcc main.o -o main
最后直接执行这个./main即可。
看出来猫腻了吗,那个参数分别是E S c . -o 表示的是要生成的文件的名称,分别是i ,s ,o 。就这样记忆应该就可以记录下来了。
当然上面这个过程只是让你了解gcc编译的而整个过程,而实际上,你可以直接用一条指令就可以解决这样的问题了。
gcc main.c -o main
直接一条命令就可以将main.c 编译成功了。
3. gcc的其他一些参数:
-I : 指定头文件的路径
-D: 指定一个宏,相当于在文件中define 了一个宏。
-Wall :编译期间输出警告
-g:gdb调试时需要该参数
-L :后面接要依赖的库的目录
-l: 后面接具体依赖的库的名字,注意要去掉lib这个前缀。
-fPIC:就可以生成与位置无关的代码
-O(1-3):表示优化的级别 -O1 或-O2 或-O3
4. lib静态库文件
制作步骤:
- 生产对应的.o文件 —>c -o -c
- 将生成的.o文件打包 ar rcs+静态库的名字(libMytest.a)+生成的所有的.o
使用: main.c -L -l
gcc main.c -LlibPath -llibName -o app -Iinclude
发布 和使用静态库
3. 发布.a文件
4. 给.h文件
优点:
5. 由于静态库以及被打包到可执行文件中了,所以,在发布的时候就不用再发布静态库了。
6. 加载库的速度快。
缺点 :
7. 可执行文件中会变大。
8. 升级很麻烦,需要重新编译程序。
5. 共享库(动态库)
- 命令规则
lib +名字+ .so
- 制作步骤
生成与位置无关的代码(生成与位置无关的.o)
gcc -fPIC -c *.c -Iinclude
将.o打包成共享库
- 打包方式
gcc -shared -o lib名字.so *.o
- 使用方式
gcc main.c lib/libmy.so -o app
gcc main.c -LlibPath -lmytest -Iinclude -o app
- 查找依赖的库
ldd myApp
一般是先去查找环境变量
- 应用程序不能执行,动态连接器连接不到自己制作的库
- 临时设置的方法
export LD_LIARARY_PATH = ./lib
- 永久设置的方法
- 找到动态链接库的配置文件:/etc/ld.so.conf
- 在该文件中添加动态库的目录(绝对路径)
- 更新 :sudo ldconfig -v
6. GDB调试
- 注意使用gcc编译程序的时候要使用-g的选项,才会是生成的可执行文件里面有行号,才可以进行操作。
- l :显示程序
- b num: 打断点
- i: info的意思
- i b: 代表显示出断点信息
- start :让程序启动,会开始跑到断点的那个地方
- n:next就是一步一步向后走,直接就执行完函数体了
- c: 就是continue 继续跑
- s: step进入到函数体的内部
- p: printf 表示的是打印某个变量
- ptype: 显示某个变量的类型
- start和run的区别:默认情况下,run 指令会一直执行程序,直到程序执行结束。如果程序中手动设置有断点,则 run 指令会执行程序至第一个断点处. start 指令会执行程序至 main() 主函数的起始位置,即在 main() 函数的第一行语句处停止执行(该行代码尚未执行)。
- file 文件名(绝对路径): 可以通过file命令指定要进行gdb调试的文件。
- –args: 指定需要传递给程序的数据
- set args: 可以借助 set args 命令指定目标调试程序启动所需要的数据
- run® 数据:可以使用run 或者start启动目标程序时,指定其所需要的数据。
- cd /tmp/demo :将 GDB 调试器的工作目录修改为 /tmp/demo
- path /temp/demo :某些场景中,目标调试程序的执行还需要临时修改 PATH 环境变量,此时就可以借助 path 指令
- run >a.txt: 通过run > 可以将运行的程序的输出结果输出到a.txt.
- watch cond: watch 称为监控断点,cond 表示要监控的变量
- catch event:建立捕捉断点的方式很简单
- catch 库的名称:监控库的加载(使用ldd App 可以获知其运行所需加载的动态库)
- break … if cond: 在某种条件下使断点发挥其作用。
- condition bnum expression:参数 bnum 用于代指目标断点的编号;参数 expression 表示为断点添加或修改的条件表达式。用于为 bnum 编号的断点添加或修改 expression 条件表达式
- condition bnum:用于删除 bnum 编号断点的条件表达式,使其变成普通的无条件断点
- ignore bnum count: 参数 bnum 为某个断点的编号;参数 count 用于指定该断点失效的次数。仅为一个整数,它用来表示该断点失效的次数
- next,step,until :都可以控制GDB调试器每次只执行一行代码。
- step next基本相同:但当step遇到函数时,会进入到函数内部,并在函数第一行代码处停下。
- until:不带参数的 until 命令,可以使 GDB 调试器快速运行完当前的循环体,并运行至循环体外停止。注意,until 命令并非任何情况下都会发挥这个作用,只有当执行至循环体尾部(最后一行代码)时,until 命令才会发生此作用。
- until location:location只是行号。
- finish:如果是在循环体内非最后一次循环,直接finish是出不来的。可以把循环的位置的断点去掉。就可以跳出函数体了。
- set var 变量名= 赋值:设置变量的值
- display 变量名:自动打印变量值,设置追踪变量
- undisplay:取消追踪变量
- info display:获取编号
- u: 跳出循环的命令
- quit:退出gdb
7. MakeFile
基础知识
-
makefile中的shell的含义:
-
在规则中需要使用符号 本 身 的 地 方 , 需 要 书 写 两 个 连 续 的 本身的地方,需要书写两个连续的 本身的地方,需要书写两个连续的$
-
$? 表示比目标还要新的依赖文件列表
-
分号是分隔符,反斜线是换行符,反斜杠是转义字符。
-
CUR_C := $(filter %.c, ( C U R S R C ) ) : 过 滤 掉 所 有 (CUR_SRC)):过滤掉所有 (CURSRC)):过滤掉所有(CUR_SRC)里面不符合%.c的文件 “filter”函数可以用来去除一个变量中的某些字符串.
-
cat 111.txt | tr [a-z] [A-Z] > 222.txt:tr命令用于转换文本文件中的字符
-
$(strip STRINT)
函数名称:去空格函数—strip。
函数功能:去掉字串(若干单词,使用若干空字符分割) “STRINT”开头和结尾的
空字符,并将其中多个连续空字符合并为一个空字符。
返回值:无前导和结尾空字符、使用单一空格分割的多单词字符串。
函数说明:空字符包括空格、[Tab]等不可显示字符。 -
$1表示取值
-
$(foreach var text commond):
var:局部变量
text:文件列表,空格隔开,每一次取一个值赋值为变量var
commond:对var变量进行操作(一般会使用var变量,不然没意义),每次操作结果都会以空格隔开,最后返回空格隔开的列表。 -
call:call函数是唯一一个可以用来创建新的参数化的函数。 ( c a l l < e x p r e s s i o n > ; , < p a r m 1 > ; , < p a r m 2 > ; , < p a r m 3 > ; . . . ) 当 m a k e 执 行 这 个 函 数 时 , < e x p r e s s i o n > ; 参 数 中 的 变 量 , 如 (call <expression>;,<parm1>;,<parm2>;,<parm3>;...) 当make执行这个函数时,<expression>;参数中的变量,如 (call<expression>;,<parm1>;,<parm2>;,<parm3>;...)当make执行这个函数时,<expression>;参数中的变量,如(1), ( 2 ) , (2), (2),(3)等,会被参数< parm1>;,;,;依次取代。而;的返回值就是 call函数的返回值。
-
=:代表的是赋值的意思:OBJECTS=$(SOURCES:.cpp=.o):代表的是将SOURCES 中的.o都代替成.cpp。
-
wildcard取所有目录下的.c文件。
-
四种赋值方式
简单赋值 ( := ) 编程语言中常规理解的赋值方式,只对当前语句的变量有效。
递归赋值 ( = ) 赋值语句可能影响多个变量,所有目标变量相关的其他变量都受影响。
条件赋值 ( ?= ) 如果变量未定义,则使用符号中的值定义变量。如果该变量已经赋值,则该赋值语句无效。
追加赋值 ( += ) 原变量用空格隔开的方式追加一个新值。
-
makefile 的编写
规则的三要素:目标,依赖,命令
目标:依赖条件
命令
一定要有个TAP键
-
在MakeFile中如果有多条规则的话,那么默认第一个目标就是终极目标。
-
为了防止每次修改一个就得 全部都编译,就把依赖的目标更改为.o文件。
-
工作原理:
makefile版本 -
版本一:
app:main.c add.c sub.c mul.cgcc main.c add.c sub.c mul.c -o app
- 版本二:
- 版本三:使用变量名代表一系列名字 target:目标
app: main.o add.o sub.o
gcc main.o sub.o mul.o -o app
%.o:%.c ->会在找main.o找不到的时候,自动把main填入达到%里面。
makefile中的自动变量:
$<: 规则中的第一个依赖
$@:规则中的目标
$^:规则中的所有依赖
只能在规则的命令中使用。
- 版本四:
#makefile自己维护的变量
CC=cc
# CPPFLAGS:
CPPFLAGS =
# 这里的cc其实就是gcc
5. 版本五:
- makefile给我们提供的函数都是返回值的。
- wildcard:获取指定目录下的.c文件:wildcard
- pastsubst:把指定目录下的.c 文件替换成.o。 这里模式匹配使用的是%,不是*。
- 给makefile提供函数传参,只需要将其参数与函数名用空格分离即可。但参数和参数之间使用逗号进行间隔。
- 取变量里面的内容记得要加$。
- 这样获取到的obj,就可以获取一系列函数的.o文件名字的集合。
- 版本六:Clean目标的加入
1.-rm :这个-的含义就是忽略掉当前命令执行失败的情况。
2. 查找指定目录下,指定类型的文件: src = $(wildcard ./*.c);
3. 匹配替换函数:obj = ( p a t s u b s t (patsubst %.c,%.o, (patsubst(src);
4. .PHONY:这个的意义是,这个是个伪目标,所以,即使当前文件夹中存在clean这个文件,也依然会执行clean下面的语句。
三个自动变量:
- $<: 规则中的第一个依赖
- $^:规则中的所有依赖
- $@:规则中的目标
8. C库函数
- 与位置无关的代码:
- #define NULL (void *)0 :这里的NULL其实就在
受保护的地址
。 - 为什么要弄一个虚拟地址空间:
- 虚拟地址空间,注意虚拟的含义。
9. 库函数与系统函数之间的关系
- FD:文件描述符 FD_POS:文件指针 BUFFER:buffer
2.write:做一个将用户空间拷贝到内核空间
10. open函数的使用
- 举个例子
11. read函数的使用
返回值:
- -1 :读取失败
- 0:文件读完了。
- 正数:文件读取上来的字节数。
12. readAndWrite函数的应用
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main()
{//打开一个已经存在的文件int fd = open("file.txt",O_RDONLY);if(fd==-1){perror("open");exit(1);}//创建一个新文件---写操作int fd1 = open("newfile",O_CREAT|O_WRONLY,0664);if(fd1==-1){perror("open1");exit(1);}//read filechar buf[2048]={0};int count = read(fd,buf,sizeof(buf));if(count==-1){perror("read");exit(1);}while(count){//将读出的数据写入到另一个文件中国int ret =write(fd1,buf,count);printf("write bytes %d\n",ret);count = read(fd,buf,sizeof(buf));}//close fileclose(fd);close(fd1);return 0;
}
作用:将某个文件中的内容读取到另一个文件中的内容,新创建的一个文件。
13.lseek
- 获取文件大小
- 移动文件指针
- 文件拓展
应用
#include <stdlib.h>int main()
{int fd = open("aa",O_RDWR);if(fd==-1){perror("open file");exit(1);}int ret = lseek(fd,0,SEEK_END);printf("file length=%d\n",ret);//文件拓展ret = lseek(fd,2000,SEEK_END);printf("return value:%d\n",ret);//实现文件拓展,需要再最后做一次写操作write(fd,"a",1);close(fd);return 0;
}
- 注意,在使用lseek进行拓展后,一定要额外进行一次拓展。不然,是没办法完成拓展操作的。
14. stat函数
依赖的头文件
这个的含义就是追踪和不追踪的意思。意思就是在遇到软链接的时候,是否会追踪到最底下的文件进行硕源。
stat是一个穿透的函数。
- 带l的是不穿透的。
15. access
成功就是0,不成功就返回-1。
16. truncate
17. link
unlink的应用
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
int main()
{int fd = open("tempfile",O_CREAT|O_RDWR,0664);if(fd==-1){perror("open");exit(1);}//删除临时文件fileint ret = unlink("tempfile");//write filewrite(fd,"hello\n",6);//重置文件指针lseek(fd,0,SEEK_SET);//read filechar buf[24] = {0};int len = read(fd,buf,sizeof(buf));//将读出的内容,写到屏幕上write(1,buf,len);//close fileclose(fd);return 0;
}
18. 常用命令
rename
int rename(const char*oldpath,const char* newpath);
chdir
改变进程的路径
getcwd
获取当前进程目录
rmdir
删除空目录
opendir
打开一个目录
readdir
应用
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <dirent.h>int getFileNum(char* root)
{//open dirDIR* dir = NULL;dir = opendir(root);if(dir==NULL){perror("opendir");exit(1);}//遍历当前打开的目录struct dirent* ptr = NULL;char path[1024];while(ptr=readdir(dir)!=NULL){//过滤,和if((strcmp(ptr->d_name,".")==0)||(strcmp(ptr->d_name,".."==0)){continue;}if(ptr->d_type==DT_DIR){//递归 读目录sprintf(path,"%s/%s",root,ptr->d_name);total += getFileNum(path);}//如果是普通文件if(ptr->d_type==DT_REG){total++;}}closedir(dir);//一定要关掉目录return total;
}int main(int argc,char * argv[])
{if(argc<2){printf("./a.out dir\n");}int total = getFileNum(argv[1]);printf("-->z %s has file numbers%d\n",argv[1],total);return 0;
}
19. dup,dup2(复制现有的文件描述符)
dup返回的就是文件描述符中没有被占用的最小的文件描述符。
20. fcntl
改变已经打开的文件的属性
总结
这个Linux服务器开发-基础教程总结(1) 视频到这就结束了,基本上把一些Linux开发的一些基本技能都展示了一下,师傅领进门修行在个人。接下来,就得靠自己去不断的熟练这些东西。接下来,开始看(2)的,就开始接触进程的一些概念了。
参考
- C/C++高级编程系列(1)之Linux服务器开发一基础教程