在使用NDK编译C/C++项目的过程中,免不了要编写Android.mk文件,其中最重要的就是LOCAL_SRC_FILES源文件列表.
考虑有如下源文件分布的情况:
cpp文件全部位于android项目下的jni文件夹下,结构如下 jni |---1.cpp |---2.cpp |---Android.mk |---Application.mk |---ndk_test.cpp |---src | |---core | | |---core1.cpp | | |---core2.cpp | |---src1.cpp | |---src2.cpp
按照通常的写法,在android.mk中,应该写入
LOCAL_SRC_FILES := ndk_test.cpp \ 1.cpp \ 2.cpp \ src/src1.cpp \ src/src2.cpp \ src/core/core1.cpp \ src/core/core2.cpp
繁琐不堪!
继续上面的情况为例,我可以这样写
MY_CPP_LIST := $(wildcard $(LOCAL_PATH)/*.cpp) MY_CPP_LIST += $(wildcard $(LOCAL_PATH)/src/*.cpp) MY_CPP_LIST += $(wildcard $(LOCAL_PATH)/src/core/*.cpp) LOCAL_SRC_FILES := $(MY_CPP_LIST:$(LOCAL_PATH)/%=%)
问题解决. 简单解释一下上面的几句话
这里我解释一下$(MY_CPP_LIST:$(LOCAL_PATH)/%=%)的语法含义,它的意思是对MY_CPP_LIST中每一项,应用冒号后面的规则,规则是什么呢?规则是$(LOCAL_PATH)/%=%,意思是,查找所有$(LOCAL_PATH)/开头的项,并截取后面部分
最后一句话也可以使用subst函数写成:
#替换每一项中的 "$(LOCAL_PATH)/" 为 ""(空) LOCAL_SRC_FILES := $(subst $(LOCAL_PATH)/, , $(MY_CPP_LIST))
或使用patsubst函数写成
#同模式替换,这里使用patsubst函数 LOCAL_SRC_FILES := $(patsubst $(LOCAL_PATH)/%, %, $(MY_CPP_LIST))
具体语法请参考:Functions for String Substitution and Analysis
实际使用中,可以把代码放在jni目录以外的目录里,这时只要修改wildcard函数里的相对路径就可以了,甚至也可以使用绝对路径,只要你愿意.
以上代码已经足以应付大多数情况了,不过人的懒惰是无极限的,像上面的情况我的所有源文件都在jni目录下,为什么还要把每个子目录都写一行呢,不太优雅呀,最好能写一句话把jni目录下的所有源文件都引入.
为了达到引入目录下的所有源文件,包括子目录这个目标,我在android.mk中这样写
#声明一个变量MY_CPP_PATH表示源码目录 MY_CPP_PATH := $(LOCAL_PATH)/ #获取目录下的所有文件 My_All_Files := $(shell find $(MY_CPP_PATH)/.) My_All_Files := $(My_All_Files:$(MY_CPP_PATH)/./%=$(MY_CPP_PATH)%) #从My_All_Files中再次提取所有的cpp文件,这里也可以使用filter函数 MY_CPP_LIST := $(foreach c_file,$(My_All_Files), $(wildcard $(c_file)/*.cpp) ) MY_CPP_LIST := $(MY_CPP_LIST:$(LOCAL_PATH)/%=%) LOCAL_SRC_FILES := $(MY_CPP_LIST)
通过以上几行,成功得到了jni目录包含它的子目录下的所有cpp源文件,并正确编译.实际使用中,代码不一定存放在jni目录下,修改MY_CPP_PATH就可以了,注意:MY_CPP_PATH最好使用以$(LOCAL_PATH)开头的相对目录
这种写法极大的方便了项目的开发,以前在源码目录下新建cpp源文件,新建目录都不需要再来修改android.mk文件了.
还有一个问题,上面代码里只是引入cpp文件,如果源码文件夹下还有c文件呢,怎么办?再多写几行?
这里,我直接给出代码
MY_CPP_PATH := $(LOCAL_PATH)/ My_All_Files := $(shell find $(MY_CPP_PATH)/.) My_All_Files := $(My_All_Files:$(MY_CPP_PATH)/./%=$(MY_CPP_PATH)%) MY_CPP_LIST := $(filter %.cpp %.c,$(My_All_Files)) MY_CPP_LIST := $(MY_CPP_LIST:$(LOCAL_PATH)/%=%) LOCAL_SRC_FILES := $(MY_CPP_LIST)
代码中用到了filter函数.
还不满足?如果项目的源码有多个目录放在不同的地方,而且有多个后缀,怎么办?
上代码:
MY_FILES_PATH := $(LOCAL_PATH)/ \ $(LOCAL_PATH)/../src_files/ MY_FILES_SUFFIX := %.cpp %.c %.cc My_All_Files := $(foreach src_path,$(MY_FILES_PATH), $(shell find $(src_path)/.) ) My_All_Files := $(My_All_Files:$(MY_CPP_PATH)/./%=$(MY_CPP_PATH)%) MY_CPP_LIST := $(filter $(MY_FILES_SUFFIX),$(My_All_Files)) MY_CPP_LIST := $(MY_CPP_LIST:$(LOCAL_PATH)/%=%) LOCAL_SRC_FILES := $(MY_CPP_LIST)
以上代码中,变量MY_FILES_PATH保存源文件所在目录,MY_FILES_SUFFIX保存源文件的后缀名
PS:如何debug 一个android.mk文件
有一个办法,那就是在编译过程输出android.mk文件中变量的值,就可以观察分析问题所在了,使用代码
$(warning $(LOCAL_SRC_FILES))
就可以在编译过程中从终端窗口中观察到变量LOCAL_SRC_FILES的值
VIA:Xu.blog
共有0个评论 我要评论»
网友回复/评论仅代表其个人看法,并不表明本社区同意其观点或证实其描述。
1.不欢迎无意义的回复/评论和类似“顶”、“沙发”之类没有营养的文字
如果只是想简单的表个态,请点 有用无用支持反对 等按钮
2.发言之前请再仔细看一遍文章,或许是您遗漏、误解了,理性讨论、切莫乱喷
3.严禁发布违法、违规的信息,请勿到处招贴广告、发布软文;
4.如果您发现自己的回复/评论不见了,请参考以上3条
5.不停制造违规、垃圾信息的,账户将被禁止