shell 基本指令
echo <> 将 <> 中的内容输出到屏幕
$? 上一次命令执行的结果
man 帮助的使用:
man command
man 1 command 和上面的一样
man 2 系统调用
man 3 库函数
PRINTF(3) 表示man 3 可以查看这个函数
程序编译的流程
1.预处理
gcc -E hello.c -o hello.i
2. 编译 将预处理后的文件翻译为汇编文件
gcc -S hello.i -o hello.s
3. 汇编 将汇编语言翻译为机器语言
gcc -c hello.s -o hello.o
4. 将目标文件和运行是文件或者函数库链接形成可执行文件
gcc hello.o -o hello
- 编译的基本单位是什么?
编译的基本单位是源程序
nm 二进制文件名
可以查看二进制文件中的符号表
什么是符号?
一个二进制符号表中包含 函数的名字 全局变量的名字 静态局部变量的名字
T 表示 在此文件中定义了该函数
U表示 在此文件中没有定义该函数
链接
链接分为动态链接和静态链接
静态链接就是将各个二进制文件(.o文件) 链接在一起,发生在生成可执行文件的时候
nm t_add.o
00000000 T t_add
0000000d T t_sub
nm t_mul.o
0000000c T t_div
00000000 T t_mul
这些地址是相对地址,相对于自己模块的地址
nm a.out
生成的符号表的地址是绝对地址
file main.o
他的属性有 relocatable 表示可以重定位
file a.out
他的属性是 可执行的
静态库的制作,使用
根据链接方式的不同分为静态库和动态库(共享库)
命名规则:
lib库名.a 静态库的名字
lib库名.so 动态库的名字
- 将需要打包到静态库的源文件编译编译成为目标文件
gcc -c t_add.c t_mul.c
之后会生成t_add.o t_mul.o - 将第一步中生成的目标文件打包到静态库文件中
ar -r libp_math.a *.o
会生成 libp_math.a
libp_math.a 这是静态库文件 静态库名字是 p_math - 用静态库链接生成可执行文件
gcc -c main.c -o main.o
gcc main.o -L. -lp_math
注意: 其中
-L路径 告诉连接器到指定的路径下找需要的静态库文件
-l库名 指定使用到的静态库的库名
静态库在链接时,用到的才会被连接到可执行文件中,不用的不会链接到可执行文件中。
三 环境变量
什么是环境变量
进程是程序运行的实例。
程序执行过程中(进程中),需要访问计算机的资源,每台计算机资源存放的位置和配置都不同。
每个进程都有自己的环境变量列表。
所有的应用进程构成了一棵树。进程树
pstree(1) 查看系统的进程树
进程间的关系 父子关系 兄弟关系
环境变量可以被子进程继承。
以bash 进程为例,讲解环境变量的操作。
- 查看bash进程的环境列表
env(1)
环境变量的格式
name=val 注意: =两边不允许出现空格
$name 可以取出环境变量的名字
echo $name
grep 字符串 文件名
修改环境变量的值
name=value 如果环境变量name存在,使用value得知替换name环境变量原来的值。
如果环境变量name不存在,将创建一个自定义变量。
环境变量和自定义变量
环境变量可以被子进程继承的,但是自定义变量不可以被子进程继承。
如果将自定义变量转换为环境变量?
export name
删除环境变量
unset name
exit 退出当前子进程
PS1 自定义变量
这个变量表示bash 进程的提示符
如果希望bash 进程前面显示的仅仅是当前文件夹,则修改PS1
PS1="\W$"
bash 本身就是一个进程,当bash这个进程启动以后,会执行一个bash 脚本文件 ~/.bashrc
用户可以在这个脚本文件中设置bash 进程的环境变量。
PATH 是一个环境变量
echo $PATH
/home/book/bin:/home/book/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/work/tools/gcc-3.4.5-glibc-2.3.6/bin:/snap/bin
对PATH 环境变量的注释:
1.冒号会分割多个路径
2. bash 输入一条指令的时候,会在这些路径下找可执行程序,如果能够找到,则执行这个程序,如果找不到,会报错。
修改PATH 环境变量:
如果想要在a.out 目录下直接执行 a.out 程序
例如 原来 ./a.out 现在 a.out
则 有如下的修改方法: 在环境变量PATH 中加入当前路径即可
PATH= $PATH:.
仅仅是在当前bash 下可以使用 a.out
如果想要在任意的路径下使用a.out
则需要修改 vim .bashrc
将 PATH=$PATH:. 加入 .bashrc 文件即可。
动态库的制作和使用
lib库名.so
- 将所有要打包的动态库的源文件编译为目标文件(与位置无关的目标文件?)
gcc -c -fPIC t*.c 将所有t 开头 的.c 文件打包生成与位置无关的.o 文件 - 将第一步中生成的目标文件打包成为动态库
gcc -shared -o libt_math.so *.o - 使用动态库链接生成可执行文件
gcc main.c -L. -lt_math
注意: 这一步使用的是静态连接器,当识别为动态库时,只是check 一下其中有没有需要的函数 没有则会报错。
然后执行./a.out 会有error :
显示 libt_math.so cant open 找不到这个文件
产生这个error 的原因是动态连接器到不到文件
处理方法
ldd a.out : 查看 a.out 在执行时,需要依赖那些动态库
普通的c 程序依赖的库如下
linux-vdso.so.1 => (0x00007ffd769f4000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fee7137b000)
/lib64/ld-linux-x86-64.so.2 (0x00007fee71745000)
libt_math.so =》 not found
表示动态链接器无法找到这个动态库
告知动态连接器这个库文件的位置:
1.export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.
冒号分隔符分隔多条路径
2. 动态连接器默认的搜索路径是 /lib 或者是 /usr/lib
#include <> " " 的区别
<> 去系统的指定路径下寻找,找不到会报错
“ ” 在当前路径下找,找不到去系统指定路径下找,再找不到,报错
系统指定路径是什么?
gcc -E hello.c -o hello.i -v
显示预处理的过程
#include “…” search starts here:
#include <…> search starts here:
/usr/lib/gcc/x86_64-linux-gnu/5/include
/usr/local/include
/usr/lib/gcc/x86_64-linux-gnu/5/include-fixed
/usr/include/x86_64-linux-gnu
/usr/include
End of search list.
- gcc -E hello.c -Ilib -o hello.i -v
-I路径 将路径添加到文件包含时,系统指定的路径中。 - 将 头文件移动到 系统的搜索路径下 比如 /usr/include 或者/usr/local/include
链接过程进一步分析
- gcc hello.o -o hello -v 显示链接的过程
会有很多的.o 文件,这些文件是函数在运行时的链接文件 - nm /usr/lib/gcc/x86_64-linux-gnu/5/…/…/…/x86_64-linux-gnu/crt1.o 查看这个.o 函数的符号表,可以看到 main 函数也是一个需要链接的 .o 函数,而T_start 才是一个函数执行时真正的入口地址
其他的.o 文件也都是系统提供的,被称为运行时文件(运行时环境)
nm /usr/lib/gcc/x86_64-linux-gnu/5/…/…/…/x86_64-linux-gnu/crt1.o
0000000000000000 D __data_start 0000000000000000 W data_start
0000000000000000 R _IO_stdin_used
U __libc_csu_fini
U __libc_csu_init
U __libc_start_main
U main
0000000000000000 T _start