---
title: GNU开发环境基础
date: 2023-05-01 10:22:27
tags:
---
使用静态链接库(.a文件)
1) 首先使用 gcc 命令把源文件编译为目标文件,也即.o文件:gcc -c 源文件列表
2) 然后使用 ar 命令将.o文件打包成静态链接库,具体格式为:
ar rcs + 静态库文件的名字 + 目标文件列表
ar 是 Linux 的一个备份压缩命令,它可以将多个文件打包成一个备份文件(也叫归档文件),也可以从备份文件中提取成员文件。
ar 命令最常见的用法是将目标文件打包为静态链接库。
对参数的说明:
参数 r 用来替换库中已有的目标文件,或者加入新的目标文件。
参数 c 表示创建一个库。不管库否存在,都将创建。
参数 s 用来创建目标文件索引,这在创建较大的库时能提高速度。、
例如,下面的写法表示将目标文件 a.o、b.o 和 c.o 打包成一个静态库文件 libdemo.a: ar rcs libdemo.a a.o b.o c.o
创建动态库(.so)、
首先,生成目标文件,此时要加编译器选项-fpic
g++ -fPIC -c DynamicMath.cpp
-fPIC 创建与地址无关的编译程序(pic,position independent code),是为了能够在多个应用程序间共享。
- 然后,生成动态库,此时要加链接器选项-shared
g++ -shared -o libdynmath.so DynamicMath.o
上面两个步骤可以合并为一个命令:
g++ -fPIC -shared -o libdynmath.so DynamicMath.cpp
完成上述步骤引用动态链接库生成可执行文件运行会报错,因为找不到动态链接库
在执行的时候还需要定位共享库文件
如何让系统能够找到它:
- 如果安装在/lib或者/usr/lib下,那么ld默认能够找到,无需其他操作。
- 如果安装在其他目录,需要将其添加到/etc/ld.so.cache文件中,步骤如下:
-- 编辑/etc/ld.so.conf文件,加入库文件所在目录的路径
-- 运行ldconfig ,该命令会重建/etc/ld.so.cache文件
编译时的警告选项
-w 忽略所有
-Wall 发出所有gcc提供的有用警告
gdb调试基础指令
生成可调试程序 gcc a.c -o a.out -g
进入调试模式 gdb a.out
list或者l,显示代码,list 行号 显示某行代码
b 行号 ,设置断点
run 或者 r运行程序到断点位置
s 进入函数内部
n 执行下一行
注意系统函数只能执行n,不能进入
until 12 命令,它将让程序继续运行,直到执行到第12行为止。
p i 查看i变量的值
cintinue 执行断点后续指令
quit 退出
finish 结束当前函数调用
set args a b c 设置main函数参数
run 参数1 参数2...设置main参数并运行
info b 查看断点信息
b 行数 if i=5;设置条件断点,满足条件才停止在断点
ptype 查看变量类型
bt 列出当前程序正在存活的栈帧
frame根据栈帧编号切换栈帧
display 设置跟踪变量
undisplay 取消设置跟踪变量
默认情况下,run 指令会一直执行程序,直到执行结束。如果程序中手动设置有断点,则 run 指令会执行程序至第一个断点处;
start 指令会执行程序至 main() 主函数的起始位置,即在 main() 函数的第一行语句处停止执行(该行代码尚未执行)。
stat和lstat
stat会穿透符号链接 lstat不会穿透
创建软链接
具体用法:ln -s 源文件 链接文件
创建test_chk目录 的软链接
ln -s test_chk test_chk_ln
硬链接: ln ** **,没有参数-s, 它会在你选定的位置上生成一个和源文件大小相同的文件
readlink 读取符号链接文件本身
打开目录opendir
关闭目录closedir
读目录readdir
dup和dup2
int dup(int oldfd)
oldfd:已有文件描述符
返回值:新文件描述符
将标准输出重定向到描述符指向的文件
dup2(fd1,STDOUT_FILENO);
fcntl实现输入输出重定向
//返回一个>=3的文件描述符,指向fd1指向的文件
int newfd = fcntl(fd1,F_DUPFD,3);
lseek
off_t lseek(int fd, off_t offset, int whence);
whence:用于定义参数 offset 偏移量对应的参考值
fork创建子进程
创建子进程,父子进程各自,父进程返回子进程pid,子进程返回0
getpid()返回当前进程pid,getppid()返回父进程pid
父子进程读时共享写时复制
父子进程不同之处 id,返回值,各自父进程,进程创建时间,闹钟,未决信号集
父子进程共享文件描述符,mmap映射区
使用gdb调试的时候只能跟踪一个进程,默认跟踪父进程
set follow-fork-mode child命令设置gdb在fork之后跟踪子进程
set follow-fork-mode parent命令设置gdb在fork之后跟踪父进程
注意在fork函数调用前设置才有效
孤儿进程
父进程先于子进程终止,子进程沦为孤儿进程,会被init进程领养
僵尸进程
子进程终止,父进程尚未对子进程进行回收,在此期间子进程沦为僵尸进程,kill对其无效
ps ajx命令 可以查看父进程pid
exec函数族 成功无返回值,失败返回-1
execlp
加载一个进程,借助path环境变量
execl
加载一个进程,通过路径+程序名加载
如execlp("ls","ls","-l",NULL);
execl("./a.c","a.c",aa,bb,NULL);
wait
作用1阻塞等待子进程退出2清理子进程残留在内核的pcb资源3传出参数,得到子进程结束状态
wait(NULL);//不需要知道子进程结束原因
wait(&status);//回收子进程并得到结束状态,status是int型变量
WEXITSTATUS(status)得到子进程结束时return的值
if(WIFEXITED(status))为真说明子进程正常终止
调用一次wait或者waitpid只能回收一个子进程
waitpid:指定某一个进程进行回收
pid_t waitpid(pid_pid,in* status,int optains)
pid:指定回收的进程号
>0:待回收的子进程pid
-1:任意子进程
0:同组子进程
status:传出回收进程的状态
options:WNOHANG指定回收方式为非阻态
return:
>0:成功返回子进程pid
0:函数调用时,参3指定可WNOHANG,并且子进程没有结束
-1:失败,errno
进程间通信
管道:内核借助环形队列机制,使用内核缓冲区实现
特质:1伪文件,不占用内存2管道数据只能一次读取3数据在管道中,只能单向流动
局限性:数据不可反复读,只血缘进程间可用
pipe函数:创建并打开管道,
int pipe(int fd【2】),0读1写
兄弟进程通信需要先关闭父进程读端和写端