前两天搞明白了动态链接库和静态链接库,后面终于也基本上搞懂了我之前不明白的“dlopen”是咋回事,怎么也要扒一扒。
共享库,有两种形式,第一种就是在上一篇文章中说到的“动态链接库”,而共享库的另一种形式,则被称之为“动态加载库”,也就是我刚才提到的用“dlopen”方式来玩的。动态加载库在编译的时候,应该是不需要去-l引用lib,而是在可执行程序中,可以自已决定加载库的时机。比如程序跑着跑着,突然想用libabc.so库里的一个叫abc的函数了,这时就可以用dlopen去打开这个库,然后使用dlsym去找到abc的函数指针并调用即可。
这几个以“dl”开头的函数,叫动态加载API,提供了以下这么几个接口来支持动态加载操作:
dlopen的函数功能是打开库文件并返回文件句柄,mode参数表示重定位的时机,有RTLD_NOW和RTLD_LAZY两个值 ,这个我们后面再分析是啥意思。
dlsym函数的功能是从这个新加载的库里根据传入的函数名,找到该函数的地址
dlerror没有入参,它会返回发生的上一个错误的字符串
dlclose关闭打开的库文件,实际上如果当前还有其他的程序引用这个库,它是不会被关闭的,多个程序共享时采用引用计数机制,当最后一个引用它的程序关闭它时才会真正的关闭。这几个函数在使用时,需要包含<dlfcn.h>头文件。
下面我依然用之前sumapp这个简单的demo程序来演示一下动态加载库的用法。
首先libsum.so生成方式不变,具体可参考上一篇文章。main.c的代码我们需要变一下,重新以dlopen的方式去引用libsum.so, 代码如下:
demodlopen.c main.c sum.h sumappd
libsum.so sum.c sum.o
192:zch kane$
192:zch kane$
192:zch kane$
192:zch kane$ more demodlopen.c
#include<stdio.h>
#include<dlfcn.h>
int main(void)
{
int iNum1 = 1;
int iNum2 = 2;
void * pHandle = NULL;
int (*pFunc)(int, int) = NULL;
char * pcError;
int iRet = 0;
pHandle = dlopen("libsum.so", RTLD_LAZY);
if (NULL == pHandle)
{
printf("Open libsum.so failed!, error message is %s\r\n.", dlerror());
return 0;
}
pFunc = dlsym(pHandle, "Sum");
if (NULL == pFunc)
{
printf("Find function Sum failed!, error message is %s\r\n.", dlerror());
return 0;
}
iRet = (*pFunc)(iNum1, iNum2);
printf("iRet = %d\r\n", iRet);
dlclose(pHandle);
return 0;
}
192:zch kane$
编译demodlopen.c,执行sumappd
192:zch kane$./sumappd
iRet = 3
编译时-rdynamic用来通知链接器将所有符号添加到动态符号表中(目的是能够通过使用 dlopen
来实现向后跟踪)。-ldl
表明一定要将 dllib
链接于该程序。
总结:动态链接库在加载时机是进程启动,而动态加载库则由程序自行决定加载时机。看了下网上有一些同学也不太明白到底什么时候适合用动态链接库,什么时候适合用动态加载库。我说一下我在工作中遇到的一个场景就是用的动态加载。由于我们做的是基于linux的嵌入式软件平台,需要同时支持多款产品,而有些特性或者说业务,在某款产品上可能不支持,以达到产品差异化的目的。比如业务A在运行时可能会用到libabc.so, 但是 libabc.so在某款产品上可能会被裁减掉,因此对于这种情况,在编译版本及写代码的时候,就得用动态加载这种方式。因为如果你用动态链接的方式,而libabc.so刚好在这款产品上被裁掉了,会导致业务A的进程启动失败(动态链接在进程启动的时候去加载动态库失败)。
更加深入的文章,请参考http://www.ibm.com/developerworks/cn/linux/l-dynamic-libraries/index.html
本文链接:linux下的动态链接库和静态链接库到底是个什么鬼?(三)动态加载库,转载请注明。
使用2个Pass增加光照效果;
第一个Pass是基础光源,一般是第一个平行光;Tags{"LightMode" = "ForwardBase"}
第二个光源是增加的光源,一般是点光源;Tags{"LightMode" = "ForwardAdd"} Blend One One
混合:Blend
我们在Pass中计算光源时,需要注意,是平行光还是点光源:
2 float atten;
3
4 if(_WorldSpaceLightPos0.w==0.0)//平行光
5 {
6 atten = 1.0;
7 lightDirection = normalize(_WorldSpaceLightPos0.xyz);
8 }
9 else
10 {
11 float3 fragmentToLightSource = _WorldSpaceLightPos0.xyz -i.posWorld.xyz;
12 float distance = length(fragmentToLightSource);
13 atten = 1.0/distance;
14 lightDirection = normalize(fragmentToLightSource);
15 }
源代码:
2 {
3 Properties
4 {
5 _Color("Color", color) = (1.0,1.0,1.0,1.0)
6 _SpecColor("Specular Color", color) = (1.0,1.0,1.0,1.0)
7 _Shininess("Shininess",float) = 10
8 _RimColor("Rim Coloe Color", color) = (1.0,1.0,1.0,1.0)
9 _RimPower("Rim Power",Range(0.1,10.0)) = 3.0
10
11 }
12 SubShader{
13 Pass{
14
15 Tags { "LightMode" = "ForwardBase"}
16
17 CGPROGRAM
18 #pragma vertex vert
19 #pragma fragment frag
20
21 //使用自定义变量
22 uniform float4 _Color;
23 uniform float4 _SpecColor;
24 uniform float4 _RimColor;
25 uniform float _Shininess;
26 uniform float _RimPower;
27
28 //使用Unity定义的变量
29 uniform float4 _LightColor0;
30
31 struct vertexInput{
32 float4 vertex:POSITION;
33 float3 normal:NORMAL;
34 };
35
36 struct vertexOutput{
37 float4 pos:SV_POSITION;
38 float4 posWorld:TEXCOORD0;
39 float3 normalDir:TEXCOORD1;
40 };
阅读更多内容
没有评论:
发表评论