Vi编辑器: :%s# pnew # p_node # g 批量处理
工作经验:自己写的库文件,工作时直接链接!!
今天内容:
一、 环境变量
什么是环境变量?
操作系统为程序运行提供的环境参数,即环境变量
env 列出系统提供的环境变量
UID=1000 :环境变量的名字=环境变量的值(注:=号的两边不允许出现空格!)
echo 字符串 :将字符串显示到屏幕上
echo $环境变量的名字 :显示环境变量的内容
变量的名字=值 :给变量赋值
export 变量名 :将普通变量导出为环境变量
export 环境变量的名字 =值
PATH 环境变量
echo $PATH
PATH环境变量的内容是由路径组成的,路径之间使用:分隔
PATH环境变量的功能是什么?
答:当我们在bash中输入一个shell命令的时候,首先在PATH指定的第一个路径下查找有没有这个可执行文件(每一个命令都是可执行文件)。
a) 如果有,执行这个文件,执行完毕就结束。
b) 如果没有,就到下一个路径中查找,如果找到就执行a,找不到继续找。
c) 若在所有路径中都没有找到,就报错(command not found)
/bin Linux基本命令
/usr/bin Linux基本命令
(
操作:
tarena@tarena-virtual-machine:~$env
…….
PATH=/usr/lib/lightdm/lightdm:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/home/tarena/workdir/toolchains/opt/S5PV210-crosstools/4.4.6/bin
DESKTOP_SESSION=ubuntu-2d
QT_IM_MODULE=xim
PWD=/home/tarena
XMODIFIERS=@im=ibus
GNOME_KEYRING_PID=2151
………..
tarena@tarena-virtual-machine:~$echo $PATH
/usr/lib/lightdm/lightdm:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/home/tarena/workdir/toolchains/opt/S5PV210-crosstools/4.4.6/bin
……….
)
exportPATH=$PATH:. 在原来环境变量PATH的基础上增加当前路径,注意:=两边不能有空格。这个导出的环境变量只在当前bash和bash的子进程中起作用,退出当前bash(即重启),就失效。
(
tarena@tarena-virtual-machine:~/day22$./a.out
tang zi hao
tarena@tarena-virtual-machine:~/day22$a.out
tang zi hao
)
cd 回到当前用户的工作主目录
cd ~ 回到当前用户的工作主目录。~代表用户的工作主目录
day22$cd
~$
.bashrc 文件,当用户登陆的时候,执行.bashrc程序。这个程序是一个bash脚本程序。这个脚本的功能就是为当前用户初始化一些环境变量
在cd 主目录里ls –a ,打开 vi .bashrc
在文件的最后,添加 export PATH=$path:.
存盘退出
source .bashrc使PATH环境变量生效
PS1 环境变量的作用,提示符显示的内容
export PS1=’\W\$’
当前路径的最后一个文件夹的名字
tarena@tarena-virtual-machine:~/day22$export PS1='\W\$'
day22$
也可以永久使用,vi .bashrc,在最后一行输入export PS1='\W\$' ,
输入source .bashrc使PATH环境变量生效
二、 静态库的创建和使用
举例:
tmath.h 头文件
1 #ifndef T_MATH_H
2 #define T_MATH_H
3 int add(int,int);
4 int sub(int,int);
5 int mul(int,int);
6 int div(int,int);
7 #endif
tmath.c 加减函数
1 #include<tmath.h>
2 int add(int x,int y){
3 return x+y;
4 }
5 int sub(int x,int y){
6 return x-y;
7 }
mmath.c 乘除函数
1 #include<tmath.h>
2 int mul(int x,int y){
3 return x*y;
4 }
5 int div(int x,int y){
6 return x/y;
7 }
tmath.c 测试程序
1 #include<stdio.h>
2 #include<tmath.h>
3 int main(void){
4 int x=8,y=2;
5 printf("%d+%d=%d",x,y,add(x,y));
6 printf("%d-%d=%d",x,y,sub(x,y));
7 printf("%d*%d=%d",x,y,mul(x,y));
8 printf("%d/%d=%d",x,y,div(x,y));
9 return 0;
10 }
制作静态库文件
静态库文件的命名:libtmath.a lib+库名+.a
第一步:将.c文件编译为目标文件
gcc –c tmath .c
gcc –c mmath .c
第二步:将.o文件打包到静态库文件里(压缩)
ar–r libtmath.a tmath.o mmath.o
-L路径库文件所在的路径
-l库名
使用静态库:
gcctest.c –L. –ltmath –o tang 生成tang可执行文件
必须掌握:
1)查看: nm libtmath.a
day22$nm libtmath.a
tmath.o:
00000000 T add
0000000d T sub
mmath.o:
0000000c T div
00000000 T mul
day22$
2)把libtmath.a 库文件做得和系统一样
第一步:需要将使用头文件的双引号改为<>
第二步:需要将头文件放到系统目录下
gcc –v tmath.c 找到头文件库 /usr/include
sudo mv tmath.h /usr/include
第三步:需要将源文件重新编译一下
gcc –c tmath.c
gcc –c tmath.c
第四步:
将libtmath.a文件放到/usr/lib或者lib下
sudo mv libtmath.a /usr/lib
第五步:gcc test.c–ltmath –o tang
去看lib里的源码!!看各种函数的实现!
补充:
在vi编辑器中,在正常模式下输入G,指标到最后一行
ar操作: man ar 用时自己查
-t 列出库文件里的目标文件
-r 压缩
-x 解压
-q 将目标文件追加到库文件里
day22$ar -t libtmath.a
tmath.o
mmath.o
三、 动态库(共享库)的创建和使用
动态库的命名:
lib+库名+ . so .so代表动态库
动态库的制作和使用:
第一步:
gcc –fPIC –ctmath.c -fPIC的意思是相对位置,与位置无关
gcc –fPIC –cmmath.c
第二步:
gcc –shared –olibtmath.so tmath.o mmath.o
第三步:使用动态库编译源文件
gcc test.c –L. –ltmath–o tang
第四步:
tang 执行文件
错误信息
Error whileloading shared libraries: libtmath.so:cannot open shared object file:No suchfile or directory.
查找错误的工具:
ldd tang
解决上述错误的方法:
a)将libtmath.so 拷贝到 /usr/lib或者lib
/usr/lib 和 /lib 这些目录既是编译器搜索路径,也是加载器的搜索路径
sudo mvlibtmath.so /usr/lib
gcc test.c –ltmath–o tang
b)
LD__LIBRARY_PATH这是一个环境变量,这个环境变量用来告诉加载器加载路径
exportLD_LIBRARY_PATH=$LD_LIBRARY_PATH:.
解决问题后生成可执行文件tang , nm tang 看函数执行在什么时候。
补充:
如果静态库和动态库库名相同,编译的时候,系统默认的是动态库。如果想指定按照静态库编译,加选项–static
gcc –statictest.c –ltmath –o tang
day22$nm ttang
080484b0 T_start
U add
0804a024 bcompleted.6159
0804a01c Wdata_start
U div
0804a028 bdtor_idx.6161
08048540 tframe_dummy
08048564 T main
U mul
U printf@@GLIBC_2.0
U sub
此时,加减乘除函数和printf一样,都是在执行时动态加载的
案例: 360软件杀毒
病毒库更新即 更新动态库的内容
gcc test.c –ltmath–o tang
可执行文件不再发生变化,更新动态库的内容
:
将mul函数的结构改为y*x+y;
重新制作动态库
day22$gcc -fPIC-c mmath.c
day22$gcc -fPIC-c tmath.c
day22$gcc-shared -o libtmath.so tmath.o mmath.o
day22$sudo mvlibtmath.so /usr/lib 将新建的动态库覆盖掉原来的动态库
day22$ttang 不用重新生成ttang , 直接运行就可以。
8+2=10 8-2=6 8*2=24 8/2=4day22$
四、 动态加载链接
加载动态库的时候,编译的程序中有函数的占位符
等到程序执行的时候,将相应的内容加载到内存,然后链接
(选择性加载,动态库里有加减乘除,选择乘函数进行加载)
动态加载:在程序执行的时候,根据程序的需要,自己编写代码加载动态库的某个或部分函数,不需要在可执行程序中有占位符
man 3 dlopen
#include <dlfcn.h>
void *dlopen(const char *filename, int flag);
函数的功能:加载filename指定的动态库文件
每个参数的意义:
filename : 要加载的动态库的名字
flag: RTLD_LAZY 延迟加载 RTLD_NOW 立即加载
返回值:一个句柄。如果错误,返回NULL
char *dlerror(void);
功能:用于返回最近执行dlopendlsym dlclose 的错误
NULL 表示没错
void *dlsym(void *handle, const char *symbol);
功能:返回符号(函数)加载到内存里的地址
参数的介绍: handle:dlopen函数返回的句柄
symbol:是动态库里的符号。符号包含函数的名字和全局变量或者静态变量
返回值:返回值如果是空,错误。如果返回值非空,一定要将其转化为相应的函数类型
int dlclose(void *handle);
功能:让动态加载的库文件引用计数减1。
参数:是dlopen函数的返回句柄
Link with -ldl.
代码参见: dynamic
1#include<stdio.h>
2#include<dlfcn.h>
3 //定义类型。func_t是指针类型,对指针类型指向的地址进行访问的时候,遵循这类函
数的访问方式
4 //函数指针,定义的函数地址,返回值是函数的地址
5 typedef int(*func_t)(int,int);
6 int main(){
7 int var_x=8,var_y=2;
8 void*handle=dlopen("libtmath.so",RTLD_NOW);
9 //获取动态库家在到内存以后,得到函数的地址
10 void *p=dlsym(handle,"mul");//p里存放的是内存中mul函数的地址
11 //将地址强制转换
12 func_t mymath=(func_t)p;
13 printf("%d*%d=%d\n",var_x,var_y,\ // \是换行续写符
14 mymath(var_x,var_y));
15 dlclose(handle);
16 return 0;
17 }
day22$gcc dynamic.c
/tmp/ccJFAwPX.o: In function `main':
dynamic.c:(.text+0x29): undefined reference to `dlopen'
dynamic.c:(.text+0x42): undefined reference to `dlsym'
dynamic.c:(.text+0x90): undefined reference to `dlclose'
collect2: ld 返回 1
改错方法:
gcc dynamic.c –ldl
day22$gcc dynamic.c –ldl 生成可执行文件a.out
day22$./a.out
8*2=16
将改错函数加入:作用 如果找不到库文件,会提示错误
1 #include<stdio.h>
2 #include<dlfcn.h>
3 //定义类型。func_t是指针类型,对指针类型指向的地址进行访问的时候,遵循这类函
数的访问方式
4 //函数指针,定义的函数地址,返回值是函数的地址
5 typedef int (*func_t)(int,int);
6 int main(){
7 int var_x=8,var_y=2;
8 void *handle=dlopen("libtmath.so",RTLD_NOW);
9 if(NULL==handle){
10 printf("%s\n",dlerror()); //如果找不到库文件,提示返回错误
11 return 1;
12 }
13 //获取动态库家在到内存以后,得到函数的地址
14 void *p=dlsym(handle,"mul");//p里存放的是内存中mul函数的地址
15 if(NULL==p){
16 printf("%s\n",dlerror());
17 return 1;
18 }
19 //将地址强制转换
20 func_t mymath=(func_t)p;
21 printf("%d*%d=%d\n",var_x,var_y,\
22 mymath(var_x,var_y));
23 dlclose(handle);
24 return 0;
25 }
如果把libtmath.so 写错,即找不到库文件,则:
day22$a.out
libtath.so: cannot openshared object file: No such file or directory
在windows中动态库的后缀名为 .dll结尾
作业:
精通:将写过的链表做成自己的动态库 人生转折点!!!
补齐ar命令的使用