利用android_ndk以及OpenGLES开发动态壁纸


本文是一个android动态壁纸的例子,利用android_ndk调用底层的C++代码,使用OpenGLES来绘制动态壁纸。仅作参考。
首先是定义我们自己的Renderer类,FireWallpaperRenderer实现了GLWallpaperService.Renderer接口(GLWallpaperService的代码在《android利用OpenGLES开发动态壁纸用到的GLWallpaperService类》的那篇博客里):
[java] view plaincopyprint?
import java.io.IOException;  
import java.io.InputStream;  
  
import javax.microedition.khronos.egl.EGLConfig;  
import javax.microedition.khronos.opengles.GL10;  
import android.content.Context;  
import android.graphics.Bitmap;  
import android.graphics.BitmapFactory;  
import android.opengl.GLUtils;  
import android.util.Log;  
  
public class FireWallpaperRenderer implements GLWallpaperService.Renderer {  
    //用于纹理映射的绑定,并把绑定后的地址传递给C++代码,供其调用  
    private int[] texture = new int[2];  
    //用于加载Bitmap的context  
    private Context mContext;  
      
    //FireWallpaperRenderer构造函数,用来初始化mContext  
    public FireWallpaperRenderer(Context context){  
        mContext = context;  
    }  
      
    /** 
     * 渲染场景的代码,这里我们是通过调用底层C++的代码来实现的, 
     * 这样能得到更好地运行速度 
     * */  
    @Override  
    public void onDrawFrame(GL10 gl) {  
        //调用本地onDrawFrame方法  
        FireNativeMethod.onDrawFrame(gl);  
    }  
      
      
    /** 
     * 处理屏幕尺寸发生变化时的代码, 
     * 用来重新设置场景的大小和其他一些属性, 
     * 也是通过调用底层C++代码来实现 
     * */  
    @Override  
    public void onSurfaceChanged(GL10 gl, int width, int height) {  
        //调用本地onSurfaceChanged方法  
        FireNativeMethod.onSurfaceChanged(gl, width, height);  
    }  
  
    /** 
     * 初始化OpenGL场景, 
     * 用来设置场景的一些属性, 
     * 也是通过调用底层C++代码来实现 
     * */  
    @Override  
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {  
        //用来绑定Bitmap纹理  
        bindTexture(gl, mContext);  
        //调用本地setTexture方法,把纹理绑定的地址传递给C++代码,以供其调用  
        FireNativeMethod.setTexture(texture);  
        //调用本地onSurfaceCreated方法  
        FireNativeMethod.onSurfaceCreated(gl, config);  
  
    }  
      
    /** 
     * 用来绑定Bitmap纹理的代码, 
     * 因为暂时没有找到在C++代码中绑定Bitmap纹理的方法, 
     * 所以暂且在java层绑定Bitmap纹理 
     * */  
  
    private void bindTexture(GL10 gl, Context context) {  
        //生成纹理  
        gl.glGenTextures(2, texture, 0);  
        //加载Bitmap  
        Bitmap bitmap = loadBitmap(context, R.drawable.floor);  
        if (bitmap != null) {  
            Log.i("firewallpaperrenderer", "bind the floor texture");  
            //如果bitmap加载成功,则生成此bitmap的纹理映射  
            gl.glBindTexture(GL10.GL_TEXTURE_2D, texture[0]);  
            //设置纹理映射的属性  
            gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER,  
                    GL10.GL_NEAREST);  
            gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER,  
                    GL10.GL_NEAREST);  
            //生成纹理映射  
            GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);  
            //释放bitmap资源  
            bitmap.recycle();  
        }  
        bitmap = loadBitmap(context, R.drawable.fire);  
        if (bitmap != null) {  
            //同上  
            Log.i("firewallpaperrenderer", "bind the fire texture");  
            gl.glBindTexture(GL10.GL_TEXTURE_2D, texture[1]);  
            gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER,  
                    GL10.GL_NEAREST);  
            gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER,  
                    GL10.GL_NEAREST);  
            GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);  
            bitmap.recycle();  
        }  
  
    }  
  
    /** 
     * 加载Bitmap的方法, 
     * 用来从res中加载Bitmap资源 
     * */  
    private Bitmap loadBitmap(Context context, int resourceId) {  
        InputStream is = context.getResources().openRawResource(resourceId);  
        Bitmap bitmap = null;  
        try {  
  
            // 利用BitmapFactory生成Bitmap  
            bitmap = BitmapFactory.decodeStream(is);  
        } finally {  
            try {  
  
                // 关闭流  
                is.close();  
                is = null;  
            } catch (IOException e) {  
                e.printStackTrace();  
            }  
  
        }  
        return bitmap;  
  
    }  
  
}  
然后定义我们的WallpaperService,FireWallpaperService继承自GLWallpaperService:
[java] view plaincopyprint?
public class FireWallpaperService extends GLWallpaperService {  
    //定义FireWallpaperRenderer实例  
    private FireWallpaperRenderer mRenderer;  
      
      
    public Engine onCreateEngine() {  
        if (mRenderer == null) {  
            mRenderer = new FireWallpaperRenderer(this);  
        }  
        return new FireWallpaperEngine();  
    }  
  
    class FireWallpaperEngine extends GLWallpaperService.GLEngine {  
  
        public FireWallpaperEngine() {  
            //设置Renderer和RendererMode  
            setRenderer(mRenderer);  
            setRenderMode(RENDERMODE_CONTINUOUSLY);  
        }  
  
    }  
  
}  
完成后编辑Manifest.xml文件,如下:
[html] view plaincopyprint?
application android:icon="@drawable/icon" android:label="@string/app_name">  
        <service android:name=".FireWallpaperService" android:label="@string/firewallpaper"  
            android:permission="android.permission.BIND_WALLPAPER">  
            <intent-filter>  
                <action android:name="android.service.wallpaper.WallpaperService" />  
            </intent-filter>  
            <meta-data android:name="android.service.wallpaper"  
                android:resource="@xml/wallpaper" />  
        </service>  
  
    </application>  


Manifest.xml文件中,FireWallpaperService使用到的wallpaper文件
(<meta-dataandroid:name="android.service.wallpaper"android:resource="@xml/wallpaper" />)在res/xml目录下定义,内容如下:
[html] view plaincopyprint?
<span style="color:#000000;"><?xml version="1.0" encoding="utf-8"?>  
<wallpaper xmlns:android="http://schemas.android.com/apk/res/android"  
    android:description="@string/description" android:thumbnail="@drawable/firelivewallpaper" /></span>  


然后是我们的本地方法类——FireNativeMethod:
[java] view plaincopyprint?
import javax.microedition.khronos.egl.EGLConfig;  
import javax.microedition.khronos.opengles.GL10;  
  
public class FireNativeMethod {  
    //加载本地库文件  
    static{  
        System.loadLibrary("fire_native_method");  
    }  
      
    //渲染场景本地方法  
    public static native void onDrawFrame(GL10 gl);  
    //处理屏幕尺寸变化本地方法  
    public static native void onSurfaceChanged(GL10 gl, int width, int height);  
    //初始化OpenGL场景本地方法  
    public static native void onSurfaceCreated(GL10 gl, EGLConfig config);  
    //传递纹理映射地址本地方法  
    public static native void setTexture(int [] textureString);  
  
}  


之后就是我们的本地C++代码部分了。
首先我们要定义和篝火粒子属性设置相关的类的头文件(Fire.h):
[cpp] view plaincopyprint?
#ifndef _FIRE  
#define _FIRE  
#include <GLES2/gl2.h>  
#include <GLES2/gl2ext.h>  
#include <GLES/gl.h>  
#include <stdlib.h>  
#include <math.h>  
//声明用来调用纹理映射的数组  
extern GLuint *texture;  
/** 
 * Fire类 
 * */  
class Fire  
{  
public:  
    Fire(void);  
    ~Fire(void);  
    void InitFire();   //初始化篝火粒子  
    //下面两个方法用来设置篝火粒子的属性值,以供渲染篝火粒子所用  
    void PrepareFire();  
    void ActivateFireParticles();  
    void RenderFire();  //渲染篝火粒子  
  
    // 粒子结构体  
  
    struct PARTICLE {  
  
        float X,Y,Z; // 当前位置  
        float sX,sY,sZ; // 当前移动速度  
        float tX,tY,tZ; // 目标移动速度  
        float R,B,G; // 粒子颜色  
        float Size; // 粒子大小  
        bool Active; // 粒子是否可见  
        int Age; // 粒子的生命值  
        int MaxAge; // 粒子消失前的最大生命值  
  
    };  
  
    //粒子结构体数组  
    PARTICLE * FireParticles;  
  
    //粒子个数  
    int FireParticleCount;  
  
    //每帧活动粒子数  
    int ActivateFirePerFrame;  
  
};  
#endif  


然后是其相关的C++文件(Fire.cpp):
[cpp] view plaincopyprint?
#include "Fire.h"  
  
//初始化纹理数组  
GLuint *texture = 0;  
Fire::Fire(void) {  
}  
  
  
/** 
 * 释放粒子结构体数组 
 * */  
Fire::~Fire(void) {  
    delete[] FireParticles;  
    FireParticles = 0;  
}  
  
/** 
 * 初始化粒子 
 * */  
void Fire::InitFire() {  
  
    int p;  
  
    //粒子的个数  
    FireParticleCount = 500;  
  
  
    //每帧粒子个数  
    ActivateFirePerFrame = 40;  
  
    //初始化粒子结构体数组  
    FireParticles = new PARTICLE[FireParticleCount];  
  
    //初始粒子不可见  
    for (p = 0; p < FireParticleCount; p++) {  
  
        FireParticles[p].Active = false;  
  
    }  
}  
  
void Fire::PrepareFire() {  
  
    int p;  
  
    for (p = 0; p < FireParticleCount; p++) {  
  
        // 调整粒子的速度  
        FireParticles[p].sX += (FireParticles[p].tX - FireParticles[p].sX)  
                / 10.0f;  
        FireParticles[p].sY += (FireParticles[p].tY - FireParticles[p].sY)  
                / 20.0f;  
        FireParticles[p].sZ += (FireParticles[p].tZ - FireParticles[p].sZ)  
                / 10.0f;  
        // 通过新的速度调整粒子的位置  
        FireParticles[p].X += FireParticles[p].sX;  
        FireParticles[p].Y += FireParticles[p].sY;  
        FireParticles[p].Z += FireParticles[p].sZ;  
  
        // 调整粒子尺寸  
        FireParticles[p].Size -= 0.002f;  
        if (FireParticles[p].Size < 0.0f) {  
            FireParticles[p].Active = false;  
        }  
  
        // 调整粒子颜色  
        FireParticles[p].R -= 0.01f;  
        FireParticles[p].G -= 0.03f;  
  
        if (FireParticles[p].R < 0.1f)  
            FireParticles[p].R = 0.1f;  
        if (FireParticles[p].G < 0.1f)  
            FireParticles[p].G = 0.0f;  
  
        // 最后检查粒子的生命值,如果生命值大于最大生命值,设置粒子不可见  
        FireParticles[p].Age++;  
        if (FireParticles[p].Age > FireParticles[p].MaxAge) {  
            FireParticles[p].Active = false;  
        }  
  
    }  
  
}  
  
void Fire::ActivateFireParticles() {  
  
    int p;  
  
    for (p = 0; p < FireParticleCount; p++) {  
  
        if (!FireParticles[p].Active) {  
  
            // 设置粒子的起始位置  
            FireParticles[p].X = (((float) ((rand() % 50) + 1)) / 100.0f)  
                    - 0.25f;  
            FireParticles[p].Y = 0.0f;  
            FireParticles[p].Z = (((float) ((rand() % 50) + 1)) / 100.0f)  
                    - 0.25f;  
  
            // 设置粒子的目标速度  
            FireParticles[p].tX = 0.0f;  
            FireParticles[p].tY = 0.01f;  
            FireParticles[p].tZ = 0.0f;  
  
            // 生成粒子随机速度  
            FireParticles[p].sX = (((float) ((rand() % 30) + 1)) / 1000.0f)  
                    - 0.015f;  
            FireParticles[p].sY = (((float) ((rand() % 50) + 1)) / 1000.0f);  
            FireParticles[p].sZ = (((float) ((rand() % 30) + 1)) / 1000.0f)  
                    - 0.015f;  
  
            //设置粒子可见  
            FireParticles[p].Active = true;  
            // 设置粒子的生命值为0  
            FireParticles[p].Age = 0;  
            // 设置粒子的最大生命值为300  
            FireParticles[p].MaxAge = 300;  
  
            // 设置粒子颜色  
            FireParticles[p].R = 0.7f;  
            FireParticles[p].G = 0.6f;  
            FireParticles[p].B = 0.0f;  
  
            // 设置粒子尺寸  
            FireParticles[p].Size = (((float) ((rand() % 15))) / 100.0f);  
  
            return;  
        }  
    }  
}  
  
void Fire::RenderFire() {  
  
    for (int i = 0; i < ActivateFirePerFrame; i++) {  
        ActivateFireParticles();  
    }  
  
    PrepareFire();  
  
    int p;  
  
    GLfloat fogColor[4] = { 0.0f, 0.0f, 0.0f, 0.5f };  
  
    glFogx(GL_FOG_MODE, GL_LINEAR); // 设置雾模式  
    glFogfv(GL_FOG_COLOR, fogColor); // 设置雾颜色  
    glFogf(GL_FOG_DENSITY, 0.35f); // 设置雾密度  
    glHint(GL_FOG_HINT, GL_DONT_CARE); // Fog Hint Value  
    glFogf(GL_FOG_START, 1.0f); // 设置雾的开始深度  
    glFogf(GL_FOG_END, 2.0f); // 设置雾的结束深度  
    glEnable(GL_FOG); // 启用雾模式  
  
  
    GLfloat LightAmbient[] = { 0.5f, 0.5f, 0.5f, 1.0f };  
    GLfloat LightDiffuse[] = { 1.0f, 1.0f, 1.0f, 1.0f };  
    GLfloat LightPosition[] = { 0.0f, 0.1f, 0.0f, 1.0f };  
  
    glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient);  
    glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse);  
    glLightfv(GL_LIGHT1, GL_POSITION, LightPosition);  
    glEnable(GL_LIGHT1);  
    glEnable(GL_LIGHTING);  
  
    /** 
     * 开始渲染地面 
     * */  
    //启用纹理,并绑定地面纹理,禁用混合  
    glEnable(GL_TEXTURE_2D);  
    glBindTexture(GL_TEXTURE_2D, texture[0]);  
    glDisable(GL_BLEND);  
  
    //设置颜色  
    glColor4f(1.0f, 1.0f, 1.0f, 1.0f);  
  
    //法线向量  
    float normals[] = { 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f,  
            0.0f, 1.0f, 0.0f };  
    //纹理坐标  
    float texCoords[] = { 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f };  
    //顶点坐标  
    float vertecies[] = { 0.0f, 0.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 0.0f,  
            -0.5f, 0.5f, 0.0f, -0.5f };  
    //绘制地面  
    for (int y = 0; y < 20; y++) {  
        for (int x = 0; x < 20; x++) {  
            glPushMatrix();  
            glTranslatef(-5.0f, 0.0f, 5.0f);  
            glTranslatef((float) x / 2, 0.0f, -(float) y / 2);  
            glEnableClientState(GL_VERTEX_ARRAY);  
            glEnableClientState(GL_TEXTURE_COORD_ARRAY);  
            glEnableClientState(GL_NORMAL_ARRAY);  
            glVertexPointer(3, GL_FLOAT, 0, vertecies);  
            glTexCoordPointer(2, GL_FLOAT, 0, texCoords);  
            glNormalPointer(GL_FLOAT, 0, normals);  
            glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);  
            glDisableClientState(GL_VERTEX_ARRAY);  
            glDisableClientState(GL_TEXTURE_COORD_ARRAY);  
            glDisableClientState(GL_NORMAL_ARRAY);  
            glPopMatrix();  
        }  
    }  
  
    //禁用光照和雾模式  
    glDisable(GL_LIGHTING);  
    glDisable(GL_FOG);  
    /** 
     * 渲染地面结束 
     * */  
  
    /** 
     * 开始渲染篝火 
     * */  
    // 启用纹理,绑定我们的粒子纹理  
    glEnable(GL_TEXTURE_2D);  
    glBindTexture(GL_TEXTURE_2D, texture[1]);  
  
    // 禁用深度测试  
    glDisable(GL_DEPTH_TEST);  
  
    // 启用混合  
    glEnable(GL_BLEND);  
    glBlendFunc(GL_SRC_ALPHA, GL_ONE);  
  
    //绘制我们的篝火  
    for (p = 0; p < FireParticleCount; p++) {  
  
        if (FireParticles[p].Active) {  
            glColor4f(FireParticles[p].R, FireParticles[p].G,  
                    FireParticles[p].B, 1.0f);  
  
            glPushMatrix();  
  
            glTranslatef(FireParticles[p].X, FireParticles[p].Y,  
                    FireParticles[p].Z);  
            glNormal3f(0.0f, 0.0f, 1.0f);  
            float vertecies[] = { -FireParticles[p].Size,  
                    -FireParticles[p].Size, 0.0f, FireParticles[p].Size,  
                    -FireParticles[p].Size, 0.0f, -FireParticles[p].Size,  
                    FireParticles[p].Size, 0.0f, FireParticles[p].Size,  
                    FireParticles[p].Size, 0.0f };  
            glEnableClientState(GL_VERTEX_ARRAY);  
            glEnableClientState(GL_TEXTURE_COORD_ARRAY);  
            glVertexPointer(3, GL_FLOAT, 0, vertecies);  
            glTexCoordPointer(2, GL_FLOAT, 0, texCoords);  
            glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);  
            glDisableClientState(GL_VERTEX_ARRAY);  
            glDisableClientState(GL_TEXTURE_COORD_ARRAY);  
  
            glPopMatrix();  
        }  
    }  
  
    /** 
     * 渲染篝火结束 
     * */  
    //重新启用深度测试  
    glEnable(GL_DEPTH_TEST);  
  
}  


接着是我们处理OpenGL初始化、设置和渲染的方法的头文件——Stdx.h:
[cpp] view plaincopyprint?
#ifndef _STDX  
#define _STDX  
#include "Fire.h"  
//初始化OpenGL场景  
extern void InitGL();  
//处理屏幕尺寸变化  
extern void SizeChanged(int width ,int height);  
//渲染场景  
extern void RendererGL();  
//计算场景透视  
extern void gluPerspective(double fovy, double aspect, double zNear,  
        double zFar);  
#endif  


 
然后是其相关的C++文件——main.cpp:
[cpp] view plaincopyprint?
#include "Stdx.h"  
Fire Fire;  //Fire实例  
float aspectRatio;   //用于透视计算  
void InitGL() {  
    glShadeModel(GL_SMOOTH);   // 启用平滑模式  
    glClearColor(0.0f, 0.0f, 0.0f, 0.5f);   // 设置黑色背景  
    glClearDepthf(1.0f);    // 设置深度缓存  
    glEnable(GL_DEPTH_TEST);   // 启用深度测试  
    glDepthFunc(GL_LEQUAL);   // 深度测试类型  
    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);   // 获得良好的透视效果  
    Fire.InitFire();   //初始化粒子  
}  
  
void SizeChanged(int width ,int height) {  
    glViewport(0, 0, width, height);  //重设窗口大小  
    glMatrixMode(GL_PROJECTION);  //启用投影矩阵  
    glLoadIdentity();     //重置投影矩阵  
    aspectRatio = float(width) / float(height);  //获得屏幕宽、高比  
    gluPerspective(45.0, aspectRatio, 0.1, 100.0);  //计算透视  
    glMatrixMode(GL_MODELVIEW);  //启用模型视图矩阵  
    glLoadIdentity();   //重置模型视图矩阵  
}  
  
void RendererGL() {  
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);   // 首先清除颜色和深度缓存  
    glLoadIdentity();   // 重设模型视图矩阵  
    glTranslatef(0.0f, -0.5f, -2.2f);  //移动场景  
    Fire.RenderFire(); //渲染篝火  
  
  
}  
  
void gluPerspective(double fovy, double aspect, double zNear, double zFar) {  
    glMatrixMode(GL_PROJECTION);   //启用投影矩阵  
    glLoadIdentity();   //重置投影矩阵  
  
    //计算透视  
    double xmin, xmax, ymin, ymax;  
    ymax = zNear * tan(fovy * M_PI / 360.0);  
    ymin = -ymax;  
    xmin = ymin * aspect;  
    xmax = ymax * aspect;  
  
    //设置透视  
    glFrustumf(xmin, xmax, ymin, ymax, zNear, zFar);  
    glMatrixMode(GL_MODELVIEW);  //启用模型视图矩阵  
    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);    // 获得良好的透视效果  
}  


之后我们需要把我们的本地方法类——FireNativeMethod利用javah命令生成正确的头文件,然后在其对应的C++文件(com_ygc_FireNativeMethod.cpp)中定义头文件中的方法,在其方法中调用相应的本地代码实现其功能:
[cpp] view plaincopyprint?
#include "com_ygc_FireNativeMethod.h"  
#include "Stdx.h"  
/* 
 * 调用RendererGL方法渲染场景 
 */  
JNIEXPORT void JNICALL Java_com_ygc_FireNativeMethod_onDrawFrame  
  (JNIEnv *env, jclass cls, jobject obj){  
    RendererGL();  
}  
  
/* 
 * 调用SizeChanged调整场景 
 */  
JNIEXPORT void JNICALL Java_com_ygc_FireNativeMethod_onSurfaceChanged  
  (JNIEnv *env, jclass cls, jobject obj, jint width, jint height){  
    SizeChanged(width,height);  
}  
  
/* 
 * 调用InitGL初始化场景 
 */  
JNIEXPORT void JNICALL Java_com_ygc_FireNativeMethod_onSurfaceCreated  
  (JNIEnv *env, jclass cls, jobject obj1, jobject obj2){  
    InitGL();  
}  
/* 
 * 获得纹理绑定地址 
 */  
JNIEXPORT void JNICALL Java_com_ygc_FireNativeMethod_setTexture  
  (JNIEnv *env, jclass cls, jintArray tex){  
    texture = (GLuint *)env->GetIntArrayElements(tex,0);  
  
}  


 
最后是我们的Android.mk文件:
[plain] view plaincopyprint?
# Copyright (C) 2009 The Android Open Source Project  
#  
# Licensed under the Apache License, Version 2.0 (the "License");  
# you may not use this file except in compliance with the License.  
# You may obtain a copy of the License at  
#  
#      http://www.apache.org/licenses/LICENSE-2.0  
#  
# Unless required by applicable law or agreed to in writing, software  
# distributed under the License is distributed on an "AS IS" BASIS,  
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  
# See the License for the specific language governing permissions and  
# limitations under the License.  
#  
LOCAL_PATH := $(call my-dir)  
  
include $(CLEAR_VARS)  
  
LOCAL_MODULE    := fire_native_method  
LOCAL_SRC_FILES := com_ygc_FireNativeMethod.cpp Fire.cpp main.cpp  
LOCAL_LDLIBS    :=-L$(SYSROOT)/usr/lib -lGLESv2  
LOCAL_LDLIBS    +=-L$(SYSROOT)/usr/lib -lGLESv1_CM  
LOCAL_LDLIBS    += -L$(SYSROOT)/usr/lib -llog  
  
include $(BUILD_SHARED_LIBRARY)  


转自 http://blog.csdn.net/ygc87/article/details/6779347
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值