ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Shell 编程与文件 IO 实战:从 Makefile 到静态/动态库(srvA)

Shell 编程与文件 IO 实战:从 Makefile 到静态/动态库(srvA) Shell 编程与文件 IO 实战从 Makefile 到静态/动态库srvA本篇基于 srvAphase1/phase2真实实操。你将看到一个多文件 C 工程如何用 Makefile 管理依赖与增量编译、静态库和动态库到底有什么区别用ldd眼见为实、以及一个自己写的迷你 Shell 如何借用forkexecvp调用外部命令。1. 实验环境Linux ecs-bee4-c6af-0001 6.8.0-106-generic #106-Ubuntu SMP x86_64 gcc (Ubuntu 13.3.0) / make (GNU Make)阶段一聚焦 Linux 常用命令与 Shell 脚本阶段二聚焦系统调用级文件操作与库的制作。2. Makefile 多文件工程管理依赖追踪真有效学生成绩管理程序stu_mgr由io.c / list.c / main.c / sort.c四个源文件组成头文件统一放include/。Makefile 关键点用-MMD -MP自动生成.d依赖文件让改了某个头文件就重编相关 .c成为可能。编译过程$cd/root/lab/phase1/stu_mgrmakemkdir-pbuild gcc-Wall-Wextra-O2-Iinclude-MMD-MP-csrc/io.c-obuild/io.o gcc-Wall-Wextra-O2-Iinclude-MMD-MP-csrc/list.c-obuild/list.o gcc-Wall-Wextra-O2-Iinclude-MMD-MP-csrc/main.c-obuild/main.o gcc-Wall-Wextra-O2-Iinclude-MMD-MP-csrc/sort.c-obuild/sort.o gcc build/io.o build/list.o build/main.o build/sort.o-ostu_mgr链接完成: stu_mgr注编译出现一条-Wstringop-truncation警告strncpy拷贝 31 字节这是刻意保留的示警教材不影响功能。运行后按总分排名、按数学排名、班级统计一应俱全成功加载 10 名学生 按总分排名 名次 姓名 语文 数学 英语 总分 1 孙悦 90 88 94 272 2 李娜 92 78 96 266 ... 班级人数 : 10 语文平均分 : 82.3 数学平均分 : 83.4 英语平均分 : 82.5 总分最高 : 孙悦 (272) 总分最低 : 杨帆 (197)验证增量编译与依赖追踪——改动头文件include/slist.h再make$touchinclude/slist.hmakegcc-Wall-Wextra-O2-Iinclude-MMD-MP-csrc/io.c-obuild/io.o gcc-Wall-Wextra-O2-Iinclude-MMD-MP-csrc/list.c-obuild/list.o gcc-Wall-Wextra-O2-Iinclude-MMD-MP-csrc/main.c-obuild/main.o gcc-Wall-Wextra-O2-Iinclude-MMD-MP-csrc/sort.c-obuild/sort.o gcc build/io.o build/list.o build/main.o build/sort.o-ostu_mgr链接完成: stu_mgr --- 修改头文件后全部重编, 依赖追踪生效 ---第二次make没有任何改动$makemake: Nothing to bedoneforall.--- 第二次make无需重编, 增量编译生效 ---这就是 Makefile 依赖追踪的价值只重编受影响的文件没改过的直接跳过。3. 静态库 vs 动态库眼见为实libcalc同时提供静态库libcalc.a和动态库libcalc.so。先确认静态库里有哪些符号$ ar t libcalc.a calc_basic.o calc_adv.o $ nm libcalc.a|grepcalc_ 0000000000000000 T calc_add 0000000000000010 T calc_sub calc_adv.o: 0000000000000010 T calc_div 0000000000000000 T calc_mul静态链接把libcalc.so挪走强制gcc只能找到.a链接出的test_static把库代码直接编进可执行文件$mvlibcalc.so dynamic/gcc-Wall-otest_static test_calc.c -L.-lcalc./test_static 库版本: libcalc1.0.012.53.215.7012.5*3.240.0012.5/3.23.9112.5/00.00[libcalc]除数为0, 返回0$ ldd test_static|grepcalc||echoldd 未找到 libcalc —— 库代码已静态链入可执行文件ldd 未找到 libcalc —— 库代码已静态链入可执行文件 $ nm test_static|grepcalc_|head-400000000000012c0 T calc_add 00000000000012f0 T calc_div...动态链接用-Wl,-rpath指定运行时库路径链接.so$ gcc-Wall-otest_dynamic test_calc.c-Ldynamic-lcalc-Wl,-rpath,$PWD/dynamic./test_dynamic 库版本: libcalc1.0.012.53.215.70... $ ldd test_dynamic|grepcalc libcalc.so/root/lab/phase2/libcalc/dynamic/libcalc.so(0x00007b46f365e000)$ readelf-dtest_dynamic|grep-ENEEDED|RPATH|RUNPATH0x0000000000000001(NEEDED)Shared library:[libcalc.so]0x0000000000000001(NEEDED)Shared library:[libc.so.6]0x000000000000001d(RUNPATH)Library runpath:[/root/lab/phase2/libcalc/dynamic]一句话总结静态库把代码焊死进可执行文件ldd看不到依赖动态库在运行时才去RUNPATH找.so——前者体积大但可独立运行后者体积小但部署时要带上库。4. 迷你 Shell用forkexecvp调外部命令minishell自己实现了内建命令ls/cp/cd/exitls基于opendir/readdir/lstatcp支持-r递归其它命令交给forkexecvp交给操作系统执行。myshlstestdir 权限 用户 组 大小 修改时间 文件名 drwxr-xr-x root root4096sub -rw-r--r-- root root7a.txt 共4个条目 myshcptestdir/a.txt copied.txt myshcp-rtestdir testdir_copy 创建目录: testdir_copy/sub 拷贝文件: testdir/sub/b.txt -testdir_copy/sub/b.txt 拷贝文件: testdir/a.txt -testdir_copy/a.txt用diff -r验证递归拷贝结果完全一致$diff-rtestdir testdir_copyechodiff: 完全一致diff: 完全一致调用外部命令echo时minishell 通过fork出子进程、execvp加载/bin/echomysh echo 这是通过 forkexecvp 执行的外部命令 这是通过 forkexecvp 执行的外部命令这正是 Linux Shell 的根本机制内建命令自己处理外部命令统统fork子进程去exec。5. 小结Makefile 的-MMD -MP依赖追踪是大型 C 工程避免全量重编的关键静态库 编进本体、独立但臃肿动态库 运行时加载、省空间但要带库一个能forkexecvp的 Shell本质上就是内建命令 进程创建的组合。下一篇进入 srvB进程、线程与各种 IPC重点看不加锁的共享内存为何会丢数据。
返回列表