暴力枚举之分数拆分

暴力枚举之分数拆分

一个很简单的分数拆分题:

已知正整数k,找到所有的正整数,x>=y,使得1/k=1/x+1/y
这道题要先求得x或y的值区间:

∵ x >= y  
∴ 1/x <= 1/y  
又∵ 1/k = 1/x + 1/y
∴ 1/k <= 2/y
∴ y<=2k
∵ 1/k = 1/x + 1/y
∴ x=k*y/(y-k)
又∵ x>=1,y>=1
∴ y>k
∴ k<y<=2k

分析完之后上代码:

void fraction_split(){

	int k;
	scanf("%d",&k);

	int y;
	for(y=k+1;y<=2*k;y++){
		int x;
		if(x=(k*y)%(y-k)==0){
			x=(k*y)/(y-k);
			printf("1/%d=1/%d +1/%d\n",k,x,y);

		}
		

	}

根据深度优先算法(DFS)和标记数组求全排列

根据深度优先算法(DFS)和标记数组求全排列

问题描述:

输入正整数n,输出所有形如abcd/efg = n的表达式,其中a~g恰好为数字1~7的一个排列

输入格式

首先是一个整数t,代表测试数据的组数,每组测试数据包括一个整数n,且1<=n<=100

输出格式

输出全部满足要求的结果(任意顺序),如果没有满足要求的,输出”NULL”

解答

对输入的7个数字进行全排列,再对排列后的数字进行4、3的拆分并对其取模,若能整除且结果等于输入,则输出答案。此题的关键在于如何去遍历数字的全排列,在这里我用DFS遍历。


#include<stdio.h>
#include<stdlib.h>
#define GET_ARRAY_LEN(array,len){len = (sizeof(array) / sizeof(array[0]));}
int visit[10]={0};
int numbers[7]={1,2,3,4,5,6,7};
int result[7]={0};
int lengths=6;
int input;
int is_find=0;

 
void dfs(int depth){
     
    int i;
    for(i=0;i<7;i++){
        if(visit[i]==0){
            visit[i]=1;
             
            result[depth]=numbers[i];
 
            if(depth==lengths){
 
                int before=result[0]*1000+result[1]*100+result[2]*10+result[3]*1;
                int after=result[4]*100+result[5]*10+result[6]*1;
 
                if(before%after==0){
                    if(before/after==input){
                        printf("%d/%d=%d\n",before,after,input);
                        is_find=1;
                    }
                }
 
            }else{
                dfs(depth+1);
            }
            visit[i]=0;
        }
    } 
}

 
int main(void){
     
    int loop;
    scanf("%d",&loop);
    int m;
    for(m=0;m<loop;m++){
        scanf("%d",&input);
        is_find=0;
        dfs(0);
        if(is_find==0)
            printf("NULL\n");
    }
}

拷贝带随机指针的链表

拷贝带随机指针的链表

此题关键在于深层拷贝,尤其要注意随机指针的拷贝问题。
代码如下:


class Solution {
public:
    RandomListNode *copyRandomList(RandomListNode *head) {
	
		if(head==NULL){
			return NULL;
		}

		RandomListNode * copyNode;
		RandomListNode * cur=head;
        
		while(cur!=NULL){
			copyNode= new RandomListNode(cur->label);
			copyNode->next=cur->next;
			cur->next=copyNode;
			cur=copyNode->next;
		}

		cur=head;

		while(cur!=NULL){
			if(cur->random!=NULL){
				cur->next->random=cur->random->next;
			}
			cur=cur->next->next;
		}
		cur=head;
		RandomListNode *phead= new RandomListNode(0);
		RandomListNode* new_list=phead;
		while(cur!=NULL){
			phead->next=cur->next;
			cur->next=cur->next->next;
			phead=phead->next;
			cur=cur->next;
		}
		return new_list->next;
    }
};

Android JNI和NDK学习(5)--JNI分析API

Java类型和本地类型对应

在如下情况下,需要在本地方法中应用java对象的引用,就会用到类型之间的转换:

  1. java方法里面将参数传入本地方法;
  2. 在本地方法里面创建java对象;
  3. 在本地方法里面return结果给java程序。

Java基本类型

像booleans、integers、floats等从Java程序中传到本地方法中的原始类型可以直接使用,下面是java中的原始类型和本地方法中的类型的对应:

Java 类型本地类型说明

boolean jboolean 无符号,8 位  
byte jbyte 无符号,8 位  
char jchar 无符号,16 位    
short jshort 有符号,16 位  
int jint 有符号,32 位  
long jlong 有符号,64 位  
float jfloat 32 位  
double jdouble 64 位  
void void N/A  

也就是说如果我在方法中传进去了一个boolean的参数的话,那么我在本地方法中就有jboolean类型与之对应。同理,如果在本地方法中return一个jint的话,那么在java中就返回一个int类型。

为了使用方便,特提供以下定义。

#define JNI_FALSE 0
#define JNI_TRUE 1

jsize 整数类型用于描述主要指数和大小:
typedef jint jsize;

Java String类型

在java中,使用的字符串String对象是Unicode码,即每个字符不论是中文还是英文或是符号,一个字符总是占用两个字节。
在c/c++本地代码中创建java的String对象
.java通过JNI接口可以将java的字符串转换到c/c++中的宽字符串(wchar_t *),或是传回一个UTF-8的字符串(char *)到c/c++。反过来,c/c++可以通过一个宽字符串,或是一个UTF-8编码的字符串来创建一个java端的String对象。

GetStringChars/GetStringUTFChars

.这两个函数用来取得与某个jstring对象相关的java字符串。分别可以取得UTF-16编码的宽字符串(jchar)跟UTF-8编码的字符串(char)。

Const jchar* GetStringChars(jstring str, jboolean* copied)
Const char* GetStringUTFChars(jstring str, jboolean* copied)

第一个参数传入一个指向java中的String对象的jstring变量
第二个参数传入的是一个jboolean的指针。
这两个函数分别都会有两个不同的动作: 第一个参数:
1. 开新内存,然后把java中的String拷贝到这个内存中,然后返回这个内存地址的指针。
2. 直接返回指向java中string的内存的指针,这个时候千万不要改变这个内存的内容,这将破坏String在java中始终是常量这个原则。 第二个参数:
是用来标示是否对java的string对象进行了拷贝的。
如果传入的这个jboolean指针不是null,则他会给该指针指向的内存传入JNI_TRUE或JNI_FALSE标示是否进行了拷贝。
传入null标示不关心是否拷贝字符串,它就不会给jboolean*指向的内存赋值。
使用这两个函数取得的字符串,在不使用的时候,要使用ReleaseStringChars/ReleaseStringUTFChars来释放拷贝的内存,或是释放对java的String对象的引用。

ReleaseStringChars(jstring jstr, const jchar* str);
ReleaseStringUTFChars(jstring jstr, const char* str);

第一个参数指定一个jstring变量,即是要释放的本地字符串的来源。
第二个参数就是要释放的本地字符串

访问类对象的属性

env 为 JNIEnv,obj的类型为jobject

JAVA_FieldAccessTest_accessField(JNIEnv *env,jobject obj){
 
 	jfieldID fid;
 	jclass cls = (*env)->GetObjectClass(env, obj);
 	//类FieldAccessTest中有个String类型的属性s
 
 	//获取要访问的属性的id
 	fid = (*env)->GetFieldID(evn,cls,"s","Ljava/lang/String;");
	//读取属性值
	jstring jstr = (*env)->GetObjectField(env,obj,fid);
	char* str  = (*evn)->GetStringUTFChars(env,jstr,NULL);
   
 //释放资源
   	(*env)->ReleaseStringUTFChars(env,jstr,str);

	//现在反过来,改变调用该本地方法的java对象的属性值
	jstr = (*env)->NewStringUTF(env,"88888");
 (*env)->SetObjectField(env,obj,fid,jstr);

}

总结:

1. jfieldID fid = (*env)->GetFieldID(env,对象所属的类的jclass,
    	    属性名,
        	属性对应的属性描述符号);
2. (*env)->GetObjectField(env,对象,属性id);

访问静态属性:

假如有个类如下:

class StaticFielcTest {
   	private static int si;
   	private native void accessField();
 	}

那么实现为:

JNIEXPORT void JNICALL
Java_StaticFieldTest_accessField(JNIEnv *env, jobject obj)
{
   	jfieldID fid;   /* store the field ID */
   	jint si;
   	jclass cls = (*env)->GetObjectClass(env, obj);   //获取类class
   	fid = (*env)->GetStaticFieldID(env, cls, "si", "I");  //获取静态属性id
   	si = (*env)->GetStaticIntField(env, cls, fid);   //读去属性的值
  	(*env)->SetStaticIntField(env, cls, fid, 200);  //设置静态属性的值
   	}

访问实例方法

假如有个这样的类:

class MethodCall {
   	private native void nativeMethod();
   	private void callback() {
       	System.out.println("In Java CallBack");
   	}
   	public static void main(String args[]) {
       	MethodCall c = new MethodCall();
       	c.nativeMethod();
} static {
       	System.loadLibrary("InstanceMethodCall");
   	}
}

jni实现:

JNIEXPORT void JNICALL
   	Java_MethodCall_nativeMethod(JNIEnv *env, jobject obj)
   	{
   	//1.拿到class
   	jclass cls = (*env)->GetObjectClass(env, obj);                         
   	//2.拿到方法id
   	jmethodID mid = (*env)->GetMethodID(env, cls, "callback", "()V");           
    	//3.根据obj,和方法id 调用方法
  	(*env)->CallVoidMethod(env, obj, mid);   
   	}

根据方法的返回值来决定调用哪个方法:
CallMethod 如果返回int 那么最后一步就调用 `(*env)->CallIntMethod(env,obj,mid)`;

最后那个参数 “()V” 是方法描述符:

(I)V   带一个int 类型的参数,返回值类型为void
()D     没有参数,返回double   //注意!!没有参数并不是  (V)D

方法public static void main(String[] args) 对应的方法描的符为:

([Ljava/lang/String;)V

访问静态方法

jclass cls = (*env)->GetObjectClass(env, obj);
jmethodID mid =
    	   (*env)->GetStaticMethodID(env, cls, "callback", "()V");
(*env)->CallStaticVoidMethod(env, cls, mid);    //注意,这里跟访问实例方法的区别是 第二个参数不是obj,而是cls

Android JNI和NDK学习(4)--编译与预编译

打包so文件

在apk里打包进.so文件的方法

  1. 是在Android.mk文件里增加
    LOCAL_JNI_SHARED_LIBRARIES := libxxx
    这样在编译的时候,NDK自动会把这个libxxx打包进apk;
    放在youapk/lib/目录下。

  2. 是在应用的目录下手工建
    libs/armeabi
    目录,然后把libxxx.so拷贝到这个目录下,
    这样NDK就会自动把这个libxxx.so打包进apk,位置还是在
    放在yourapk/lib/目录下。

在代码里,使用 System.loadLibrary("xxx");
就可以加载这个动态库了。
这里要注意,参数只写xxx就可以了,不需要写libxxx,也不需要写libxxx.so。

还有一点要说明,System.loadLibrary这个函数会在如下路径搜索libxxx.so文件:

      /system/lib
      /data/data/you apk package/lib

但,如果libxxx.so还依赖其它.so文件,比如libyyy.so,则System.loadLibrary只会
在/system/lib目录下去找,如果没找到,它不会自动到/data/data/you apk package/lib
下去找
,这个时候就会报动态库没找到的错;
解决方法是在load libxxx.so之前,先load libyyy.so,如下:

      System.loadLibrary("yyy");  
      System.loadLibrary("xxx");  

声明一个预编译库的模块

对于Android编译工具而言,每个预编译库必须声明为一个独立的模块。这里举一个例子,假设 libfoo.so 文件与 Android.mk 位于同一个目录:

      LOCAL_PATH := $(call my-dir)  
      include $(CLEAR_VARS)  
      LOCAL_MODULE := foo-prebuilt  
      LOCAL_SRC_FILES := libfoo.so  
      include $(PREBUILT_SHARED_LIBRARY)  

按以下步骤声明这样一个模块:

  1. 给该模块取一个名字(这里是 foo-prebuilt)。这个名字不需要与预编译库自身的名字相同。
  2. 将 LOCAL_SRC_FILES 指定为你要提供的共享库的路径。通常,该路径是相对于 LOCAL_PATH 的路径。注意:必须保证共享库ABI的兼容性。
  3. 如果你的库是共享库,则包含 PREBUILT_SHARED_LIBRARY 而不是 BUILD_SHARED_LIBRARY;如果是静态库,则包含 PREBUILT_STATIC_LIBRARY。
    预编译模块不需要编译。该预编译模块会被拷贝到 $PROJECT/obj/local 下面,还会被拷贝到 $PROJECT/libs/ 下面(这里的库被strip过)。

在其他模块中引用这个预编译库

在依赖该预编译库的模块对应的Android.mk中,将预编译库的名字(前面取的)加入到 LOCAL_STATIC_LIBRARIES 或 LOCAL_SHARED_LIBRARIES 声明中。例如,一个使用上面libfoo.so的简单例子如下:

      include $(CLEAR_VARS)  
      LOCAL_MODULE := foo-user  
      LOCAL_SRC_FILES := foo-user.c  
      LOCAL_SHARED_LIBRARIES := foo-prebuilt  
      include $(BUILD_SHARED_LIBRARY)  

Android JNI和NDK学习(3)--Android.mk分析

参数解析

以刚才的Android.mk为例.

# 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    := hello-jni
LOCAL_SRC_FILES := hello-jni.c

include $(BUILD_SHARED_LIBRARY)

LOCAL_PATH := $(call my-dir)

一个Android.mk 文件首先必须定义好LOCAL_PATH变量。它用于在开发树中查找源文件。在这个例子中,宏函数’my-dir’,由编译系统提供,用于返回当前路径(即包含Android.mk file文件的目录)。

include $( CLEAR_VARS)

CLEAR_VARS由编译系统提供,指定让GNU MAKEFILE为你清除许多LOCAL_XXX变量(例如 LOCAL_MODULE, LOCAL_SRC_FILES, LOCAL_STATIC_LIBRARIES, 等等…),
除LOCAL_PATH 。这是必要的,因为所有的编译控制文件都在同一个GNU MAKE执行环境中,所有的变量都是全局的。

LOCAL_MODULE := hello-jni

编译的目标对象,LOCAL_MODULE变量必须定义,以标识你在Android.mk文件中描述的每个模块。名称必须是唯一的,而且不包含任何空格。

注意:编译系统会自动产生合适的前缀和后缀,换句话说,一个被命名为’hello-jni’的共享库模块,将会生成’libhello-jni.so’文件。

重要注意事项:

如果你把库命名为‘libhello-jni’,编译系统将不会添加任何的lib前缀,也会生成 ‘libhello-jni.so’,这是为了支持来源于Android平台的源代码的Android.mk文件,如果你确实需要这么做的话。

LOCAL_SRC_FILES := hello-jni.c

LOCAL_SRC_FILES变量必须包含将要编译打包进模块中的C或C++源代码文件。注意,你不用在这里列出头文件和包含文件,因为编译系统将会自动为你找出依赖型的文件;仅仅列出直接传递给编译器的源代码文件就好。

注意,默认的C++源码文件的扩展名是’.cpp’. 指定一个不同的扩展名也是可能的,只要定义LOCAL_DEFAULT_CPP_EXTENSION变量,不要忘记开始的小圆点(也就是’.cxx’,而不是’cxx’)

include $(BUILD_SHARED_LIBRARY)

BUILD_SHARED_LIBRARY表示编译生成共享库,是编译系统提供的变量,指向一个GNU Makefile脚本,负责收集自从上次调用’include $(CLEAR_VARS)’以来,定义在LOCAL_XXX变量中的所有信息,并且决定编译什么,如何正确地去做。还有 BUILD_STATIC_LIBRARY变量表示生成静态库:lib$(LOCAL_MODULE).a, BUILD_EXECUTABLE 表示生成可执行文件。

在这里详细叙述一下Android.mk语法规范

Android.mk文件的用途

一个android子项目中会存在一个或多个Android.mk文件
**1、单一的Android.mk文件 **
直接参考NDK的sample目录下的hello-jni项目,在这个项目中只有一个Android.mk文件
**2、多个Android.mk文件 **
如果需要编译的模块比较多,我们可能会将对应的模块放置在相应的目录中,
这样,我们可以在每个目录中定义对应的Android.mk文件(类似于上面的写法),
最后,在根目录放置一个Android.mk文件,内容如下:

include $(call all-subdir-makefiles) 

只需要这一行就可以了,它的作用就是包含所有子目录中的Android.mk文件
**3、多个模块共用一个Android.mk **
这个文件允许你将源文件组织成模块,这个模块中含有:
-静态库(.a文件)
-动态库(.so文件)
只有共享库才能被安装/复制到您的应用软件(APK)包中 include $(BUILD_STATIC_LIBRARY),编译出的是静态库 include $(BUILD_SHARED_LIBRARY),编译出的是动态库

自定义变量

以下是在 Android.mk中依赖或定义的变量列表,可以定义其他变量为自己使用,但是NDK编译系统保留下列变量名:
-以 LOCAL_开头的名字(例如 LOCAL_MODULE)
-以 PRIVATE, NDK 或 APP_开头的名字(内部使用)
-小写名字(内部使用,例如‘my-dir’)
如果为了方便在 Android.mk 中定义自己的变量,建议使用 MY_前缀,一个小例子:

MY_SOURCES := foo1.c 
ifneq ($(MY_CONFIG_BAR),) 
MY_SOURCES += bar.c 
endif 
LOCAL_SRC_FILES += $(MY_SOURCES) 

注意:‘:=’是赋值的意思;’+=’是追加的意思;‘$’表示引用某变量的值。

GNU Make系统变量

这些 GNU Make变量在你的 Android.mk 文件解析之前,就由编译系统定义好了。注意在某些情况下,NDK可能分析 Android.mk 几次,每一次某些变量的定义会有不同。

  1. CLEAR_VALS
    指向一个编译脚本,几乎所有未定义的 LOCAL_XXX 变量都在”Module-description”节中列出。必须在开始一个新模块之前包含这个脚本:include$(CLEAR_VARS),用于重置除LOCAL_PATH变量外的,所有LOCAL_XXX系列变量

  2. BUILD_SHARED_LIBRARY:
    指向编译脚本,根据所有的在 LOCAL_XXX 变量把列出的源代码文件编译成一个共享库。
    注意,必须至少在包含这个文件之前定义 LOCAL_MODULE 和 LOCAL_SRC_FILES。

  3. BUILD_STATIC_LIBRARY:
    一个 BUILD_SHARED_LIBRARY 变量用于编译一个静态库。静态库不会复制到的APK包中,但是能够用于编译共享库。
    示例:include $(BUILD_STATIC_LIBRARY)
    注意,这将会生成一个名为 lib$(LOCAL_MODULE).a 的文件
  4. TARGET_ARCH: 目标 CPU平台的名字
  5. TARGET_PLATFORM: Android.mk 解析的时候,目标 Android 平台的名字.详情可考/development/ndk/docs/stable- apis.txt.
    android-3 -> Official Android 1.5 system images
    android-4 -> Official Android 1.6 system images
    android-5 -> Official Android 2.0 system images
  6. TARGET_ARCH_ABI: 暂时只支持两个 value,armeabi 和 armeabi-v7a。。
  7. TARGET_ABI: 目标平台和 ABI 的组合,

模块描述变量

下面的变量用于向编译系统描述你的模块。应该定义在’include $(CLEAR_VARS)’和’include $(BUILD_XXXXX)’之间。$(CLEAR_VARS)是一个脚本,清除所有这些变量。

  1. LOCAL_PATH: 这个变量用于给出当前文件的路径。
    必须在 Android.mk 的开头定义,可以这样使用:LOCAL_PATH := $(call my-dir)
    如当前目录下有个文件夹名称 src,则可以这样写 $(call src),那么就会得到 src 目录的完整路径
    这个变量不会被$(CLEAR_VARS)清除,因此每个 Android.mk 只需要定义一次(即使在一个文件中定义了几个模块的情况下)。
  2. LOCAL_MODULE: 这是模块的名字,它必须是唯一的,而且不能包含空格。
    必须在包含任一的$(BUILD_XXXX)脚本之前定义它。模块的名字决定了生成文件的名字。
  3. LOCAL_SRC_FILES: 这是要编译的源代码文件列表。
    只要列出要传递给编译器的文件,因为编译系统自动计算依赖。注意源代码文件名称都是相对于 LOCAL_PATH的,你可以使用路径部分,例如:
    LOCAL_SRC_FILES := foo.c toto/bar.c\
    Hello.c
    文件之间可以用空格或Tab键进行分割,换行请用”"
    如果是追加源代码文件的话,请用LOCAL_SRC_FILES +=
    注意:可以LOCAL_SRC_FILES := $(call all-subdir-java-files)这种形式来包含local_path目录下的所有java文件。
  4. LOCAL_C_INCLUDES: 可选变量,表示头文件的搜索路径。
    默认的头文件的搜索路径是LOCAL_PATH目录。
  5. LOCAL_STATIC_LIBRARIES: 表示该模块需要使用哪些静态库,以便在编译时进行链接。
  6. LOCAL_SHARED_LIBRARIES: 表示模块在运行时要依赖的共享库(动态库),在链接时就需要,以便在生成文件时嵌入其相应的信息。
    注意:它不会附加列出的模块到编译图,也就是仍然需要在Application.mk 中把它们添加到程序要求的模块中。
  7. LOCAL_LDLIBS: 编译模块时要使用的附加的链接器选项。这对于使用‘-l’前缀传递指定库的名字是有用的。
    例如,LOCAL_LDLIBS := -lz表示告诉链接器生成的模块要在加载时刻链接到/system/lib/libz.so
    可查看 docs/STABLE-APIS.TXT 获取使用 NDK发行版能链接到的开放的系统库列表。
  8. LOCAL_MODULE_PATH 和 LOCAL_UNSTRIPPED_PATH
    在 Android.mk 文件中, 还可以用LOCAL_MODULE_PATH 和LOCAL_UNSTRIPPED_PATH指定最后的目标安装路径.
    不同的文件系统路径用以下的宏进行选择:
    TARGET_ROOT_OUT:表示根文件系统。
    TARGET_OUT:表示 system文件系统。
    TARGET_OUT_DATA:表示 data文件系统。
    用法如:LOCAL_MODULE_PATH :=$(TARGET_ROOT_OUT)
    至于LOCAL_MODULE_PATH 和LOCAL_UNSTRIPPED_PATH的区别,暂时还不清楚。
  9. LOCAL_JNI_SHARED_LIBRARIES:定义了要包含的so库文件的名字,如果程序没有采用jni,不需要
    LOCAL_JNI_SHARED_LIBRARIES := libxxx 这样在编译的时候,NDK自动会把这个libxxx打包进apk; 放在youapk/lib/目录下

NDK提供的函数宏

GNU Make函数宏,必须通过使用’$(call )’来调用,返回值是文本化的信息。

  1. my-dir:返回当前 Android.mk 所在的目录的路径,相对于 NDK 编译系统的顶层。这是有用的,在 Android.mk 文件的开头如此定义:
    LOCAL_PATH := $(call my-dir)
  2. all-subdir-makefiles: 返回一个位于当前’my-dir’路径的子目录中的所有Android.mk的列表。
    例如,某一子项目的目录层次如下:
    src/foo/Android.mk
    src/foo/lib1/Android.mk
    src/foo/lib2/Android.mk
    如果 src/foo/Android.mk 包含一行:
    include $(call all-subdir-makefiles)
    那么它就会自动包含 src/foo/lib1/Android.mk 和 src/foo/lib2/Android.mk。
    这项功能用于向编译系统提供深层次嵌套的代码目录层次。
    注意,在默认情况下,NDK 将会只搜索在 src/*/Android.mk 中的文件。
  3. this-makefile: 返回当前Makefile 的路径(即这个函数调用的地方)
  4. parent-makefile: 返回调用树中父 Makefile 路径。即包含当前Makefile的Makefile 路径。
  5. grand-parent-makefile:返回调用树中父Makefile的父Makefile的路径
    ###Android.mk示例

    #编译静态库
    LOCAL_PATH := $(call my-dir)
    include $(CLEAR_VARS)
    LOCAL_MODULE = libhellos
    LOCAL_CFLAGS = $(L_CFLAGS)
    LOCAL_SRC_FILES = hellos.c
    LOCAL_C_INCLUDES = $(INCLUDES)
    LOCAL_SHARED_LIBRARIES := libcutils
    LOCAL_COPY_HEADERS_TO := libhellos
    LOCAL_COPY_HEADERS := hellos.h
    include $(BUILD_STATIC_LIBRARY)

    #编译动态库
    LOCAL_PATH := $(call my-dir)
    include $(CLEAR_VARS)
    LOCAL_MODULE = libhellod
    LOCAL_CFLAGS = $(L_CFLAGS)
    LOCAL_SRC_FILES = hellod.c
    LOCAL_C_INCLUDES = $(INCLUDES)
    LOCAL_SHARED_LIBRARIES := libcutils
    LOCAL_COPY_HEADERS_TO := libhellod
    LOCAL_COPY_HEADERS := hellod.h
    include $(BUILD_SHARED_LIBRARY)