关闭

Day23、环境变量、静态库和共享使用库(动态库)的创建和使用、动态加载链接

132人阅读 评论(0) 收藏 举报

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命令的使用

0
0

猜你在找
【直播】机器学习&数据挖掘7周实训--韦玮
【套餐】系统集成项目管理工程师顺利通关--徐朋
【直播】3小时掌握Docker最佳实战-徐西宁
【套餐】机器学习系列套餐(算法+实战)--唐宇迪
【直播】计算机视觉原理及实战--屈教授
【套餐】微信订阅号+服务号Java版 v2.0--翟东平
【直播】机器学习之矩阵--黄博士
【套餐】微信订阅号+服务号Java版 v2.0--翟东平
【直播】机器学习之凸优化--马博士
【套餐】Javascript 设计模式实战--曾亮
查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:11409次
    • 积分:863
    • 等级:
    • 排名:千里之外
    • 原创:79篇
    • 转载:1篇
    • 译文:0篇
    • 评论:0条