GNU开发环境基础

发布时间 2023-08-25 21:47:47作者: ddup123
---
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写
            兄弟进程通信需要先关闭父进程读端和写端