Linux入门3
程序的编译与调试
编译连接过程
计算机的五大部件
运算器 控制器 存储器 输入设备 输出设备
指令,二进制的机器指令,程序由一条条的指令构成
机器指令 汇编助记符 高级语言
0110 add a+b
1010 mov a=b
预编译
删除注释,替换宏定义,将include 文件加入展开,代码量会急剧增加
gcc -E main.c -o main.i
编译
将高级语言转换为汇编助记符(即汇编语言), 会进行语法的检测,代码会急剧减少,
gcc -S main.i -o main.s
汇编
从汇编助记符翻译成机器(二进制)指令,Linux平台的可执行程序格式为ELF
gcc -c main.s -o main.o
链接
链接一些库函数,因为main.o 是一个模块
gcc main.o -o main
可以一步完成,但是如果有的.c程序没有主函数,就不能一步生成可执行程序,可以先生成-o 编译成二进制文件
gcc -o main main.c
可以用命令将源文件生成.o二进制文件
gcc -c add.c -o add.o
后面可以省略
gcc -c add.c
makefile和make
安装make
如果没有安装make,安装make
sudo apt install make
Makefile文件里面的内容
all : main
main : main.o add.o max.o
gcc -o main main.o add.o max.o
main.o : main.c
gcc -c main.c
add.o : add.c
gcc -c add.c
max.o : max.c
gcc -c max.c
clean :
rm -rf main *.o
rm -rf main *.o 删除main和后缀是.o的文件
使用
直接make 就执行了Makefile文件里面的命令,除了clean
make clean 就可以清除 rm -rf main *.o
gdb调试
生成具有调试信息的main,该程序是dubag版本,不加-g 就是release版本,gdb调试的是可执行程序
生成可以调试的可执行文件
gcc -o main main.c add.c max.c -g
gcc -g -o test test.c
常用调试命令
查看代码 l list
加断点 b break
查看断点信息 info break
查看函数堆栈 bt
运行 r run
查看变量的值 p print
单步执行 n next
一直执行,直到遇见断点 c continue
进入函数 s
跳出函数 f finish
停止调试q quit
进入帮助手册 help
查看以该字符开头的所有命令 按两次tab
bt 显示函数调用栈
多进程中,跟踪子进程:set follow-fork-mode child 默认跟踪父进程 可以改成子进程
多线程中,
查看进程堆栈 pstack+pid
用gdb调试多进程程序
1.单独调试子进程 用attach 4183 将子进程4183附加2.到gdb调试器
2.使用调试器选项:set follow-fork-mode child 默认跟踪父进程 可以改成子进程
用gdb调试多线程程序
A 查看线程信息 info threads 有*就是当前线程
B 切换到指定线程 thread id
set scheduler-locking [off]on|step]。调试多线程程序时,默认除了被调试的线程在执行外,其他线程也在继续执行,但有的时候我们希望只让被调试的线程运行。这可以通过这个命令来实现。该命令设置schedulcr-locking 的值: off表示不锁定任何线程,即所有线程都可以继续执行,这是默认值;on表示只有当前被调试的线程会继续执行;step表示在单步执行的时候,只有当前线程会执行。
Linux 系统上的库文件生成与使用
库文件定义
库是一组预先编译好的方法的集合。Linux系统存储的库的位置一般在:/lib 和 /usr/lib。
在 64 位的系统上有些库也可能被存储在/usr/lib64 下。库的头文件一般会被存储在
/usr/include 下或其子目录下。
库有两种,一种是静态库,其命令规则为 libxxx.a,一种是共享库,其命令规则为 libxxx.so
静态库的生成与使用
静态库的生成
其中“foo.h”中是函数的声明,“add.c”和“max.c”是函数的定义
第一步:先将需要生成库文件的所有“.c“文件编译成“.o”文件
gcc -c add.c
gcc -c max.c
第二步:使用 ar 命令将第一步编译的所有”.o”文件生成静态库
ar crv libfoo.a add.o max.o
◼ c 是创建库
◼ r 是将方法添加到库中
◼ v 显示过程
静态库的使用
gcc -o main main.c -L. -lfoo
◼ -L 指定库的存储路径
◼ -l 指定库的名称(不需要前面的‘lib’和扩展名‘.a’)
可以将静态库放到指定的目录下,就不需要用来-L.指定位置,但是,-lfoo必不可少
因为静态库是链接的时候就放在了可执行程序里,所以,将库删除,上次生成的可执行程序照样可以运行
如果将foo.h制动到
mv foo.h /usr/include
引用的时候可以include<foo.h>,否则用inlcude “foo.h”
动态库的生成与使用
动态库的生成
其中“foo.h”中是函数的声明,“add.c”和“max.c”是函数的定义
第一步:先将需要生成库文件的所有“.c“文件编译成“.o”文件
gcc -c add.c
gcc -c max.c
第二步:使用 gcc 命令将第一步编译的所有”.o”文件生成共享库
gcc -shared -fPIC -o libfoo.so add.o max.o
动态库的使用
因为系统默认只会去存储库的标准位置(/lib 或/usr/lib )加载,而不会在当前位置寻找。所以将库拷贝到/usr/lib 下,再执行程序,就可以成功。
cp libfoo.so /usr/lib
gcc -o main main.c -L. -lfoo
这里也可以不用写指定位置,-L.指定位置,但是,-lfoo必不可少
gcc -o main main.c -lfoo
可以通过 ldd 命令查看可执行程序使用了哪些共享库
也可以通过设置环 境变量来指定加载库的路径
打印该变量的值
echo $LD_LIBRARY_PATH
设置环境变量
LD_LIBRARY_PATH=.
export LD_LIBRARY_PATH
总结一下,就是对于动态库,要么将动态库放在标准路径下,要么设置环境变量(一般用作测试)
静态库和共享库的区别
静态库在链接时将用到的方法包含到最终生成的可执行程序中,而共享库不包含,只做标记,在运行程序时,才动态加载。