2015年10月20日星期二

linux下的动态链接库和静态链接库到底是个什么鬼?(三)动态加载库 - kane_zch

本邮件内容由第三方提供,如果您不想继续收到该邮件,可 点此退订
linux下的动态链接库和静态链接库到底是个什么鬼?(三)动态加载库 - kane_zch  阅读原文»

前两天搞明白了动态链接库和静态链接库,后面终于也基本上搞懂了我之前不明白的“dlopen”是咋回事,怎么也要扒一扒。

共享库,有两种形式,第一种就是在上一篇文章中说到的“动态链接库”,而共享库的另一种形式,则被称之为“动态加载库”,也就是我刚才提到的用“dlopen”方式来玩的。动态加载库在编译的时候,应该是不需要去-l引用lib,而是在可执行程序中,可以自已决定加载库的时机。比如程序跑着跑着,突然想用libabc.so库里的一个叫abc的函数了,这时就可以用dlopen去打开这个库,然后使用dlsym去找到abc的函数指针并调用即可。

这几个以“dl”开头的函数,叫动态加载API,提供了以下这么几个接口来支持动态加载操作:

void *dlopen( const char *file, int mode );

dlopen的函数功能是打开库文件并返回文件句柄,mode参数表示重定位的时机,有RTLD_NOW和RTLD_LAZY两个值 ,这个我们后面再分析是啥意思。

void *dlsym( void *restrict handle, const char *restrict name );

dlsym函数的功能是从这个新加载的库里根据传入的函数名,找到该函数的地址

char *dlerror();

dlerror没有入参,它会返回发生的上一个错误的字符串

char *dlclose( void *handle );

dlclose关闭打开的库文件,实际上如果当前还有其他的程序引用这个库,它是不会被关闭的,多个程序共享时采用引用计数机制,当最后一个引用它的程序关闭它时才会真正的关闭。这几个函数在使用时,需要包含<dlfcn.h>头文件。

下面我依然用之前sumapp这个简单的demo程序来演示一下动态加载库的用法。

首先libsum.so生成方式不变,具体可参考上一篇文章。main.c的代码我们需要变一下,重新以dlopen的方式去引用libsum.so, 代码如下:

192:zch kane$ ls
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$ gcc -rdynamic -o sumappd demodlopen.c -ldl
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下的动态链接库和静态链接库到底是个什么鬼?(三)动态加载库,转载请注明。

多光源 MultipleLight - 那些消散不去的是寂寞  阅读原文»

使用2个Pass增加光照效果;

第一个Pass是基础光源,一般是第一个平行光;Tags{"LightMode" = "ForwardBase"}

第二个光源是增加的光源,一般是点光源;Tags{"LightMode" = "ForwardAdd"} Blend One One

混合:Blend

这里例如我们给一个模型贴一个材质,那么在某个点计算出来颜色值称为源,而该点之前累积的颜色值,叫目标。
语法
Blend SrcFactor DstFactor SrcFactor是源系数,DstFactor是目标系数
最终颜色 = (Shader计算出的点颜色值 * 源系数)+(点累积颜色 * 目标系数)
属性(往SrcFactor,DstFactor 上填的值)
one 1
zero 0
SrcColor 源的RGB值,例如(0.5,0.4,1)
SrcAlpha 源的A值, 例如0.6
DstColor 混合目标的RGB值例如(0.5,0.4,1)
DstAlpha 混合目标的A值例如0.6
OneMinusSrcColor (1,1,1) - SrcColor
OneMinusSrcAlpha 1- SrcAlpha
OneMinusDstColor (1,1,1) - DstColor
OneMinusDstAlpha 1- DstAlpha

我们在Pass中计算光源时,需要注意,是平行光还是点光源:

1 float3 lightDirection;
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 }

源代码:

1 Shader "JQM/MultipleLight"
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 };
阅读更多内容

没有评论:

发表评论