mk文件语法|关于android NDK开发中applicationmk文件的疑惑

|

㈠ android.mk采用的什么语法

编译系统已经替你处理了很多琐碎的事情。例如,你不需要在Android.mk文件中罗列.h头文件和显式声明生成文件之间的依赖关系。NDK编译系统会自动为你计算出来。这也意味着,当升级到新版的NDK时,不需要更改Android.mk文件就可以相互兼容。

㈡ 关于android NDK开发中application.mk文件的疑惑

介绍:Android SDK是一个允许Android应用开发人员使用C或C++源文件编译并嵌入到本机源代码中的应用程序包的一组工具。重要说明:Android NDK只能用于android 1.5以上版本1.Android NDK的目的:Android虚拟机允许你的应用程序源代码通过JNI调用在本地实现的源代码,简单的说,这就意味着:你的应用程序将声明一个或多个用’native’关键字的方法用来指明它们是通过本地代码实现的例如:native byte[] loadFile(String filePath)你必须提供包含实现这些方法的共享库(就是.so),将共享库打包到你的应用程序包apk中,这些库文件必须根据标准的Unix约定来命名为 lib<something>.so,并且是需要包含一个标准的JNI的接口,例如libFileLoader.so你的应用程序必须明确的装载这些库文件(.so文件),比如,在程序的开始装载它,只需要简单的添加几句源代码:java代码:static {System.loadLibrary(“FileLoader”);}注意:这里你不必再将前缀lib和后缀.so写入。Android NDK对于Android SDK只是个组件,它可以帮你:生成的JNI兼容的共享库可以在大于Android1.5平台的ARM CPU上运行将生成的共享库拷贝到合适的程序工程路径的位置上,以保证它们自动的添加到你的apk包中(并且签名的)在以后的版本中,我们将提供来帮助你的源代码通过远程gdb连接和尽可能多的源代码的信息。而且,Android NDK还提供:一组交叉编译链(编译器、链接器等)来生成可以在Linux,OS X和Windows(用Cygwin)运行的二进制文件一组与由Android平台提供的稳定的本地API列表的头文件它们在docs/STABLE-APIS.html中有说明重要提示:记住,在以后的更新和发布平台中,Android系统镜像中的大多数本地系统库并不是一成不变的,而是可以彻底改变,甚至删除的一个编译系统(build system)可以允许开发者写一个非常短的编译文件(build files)去描述哪个源代码需要编译,并且怎样编译。编译系统可以解决所有的toolchain/platform/CPU/ABI细节的问题。并且,较晚的NDK版本中还添加了更多的可以不用改变开发者的编译文件的情况下的toolchains,platforms,系统接口。2.Android NDK的缺点NDK并不是一个可以编写通用的源代码并且可以在Android设备上运行的方法,你的应用程序还是需要使用JAVA程序,适当的处理系统事件来避免“应用程序没有反应”的对话框或者处理Android应用程序的生命周期注意:可以适当的在源代码中写一个复杂的应用程序,用于启动/停止一个小型的“应用程序包”强烈建议很好地理解的 JNI,因为许多操作在这种环境要求的开发人员,都采取具体的行动,不一定在常典型的本机代码。这些措施包括:不能通过指针直接访问VM的对象。比如:你不能安全的得到一个指向String对象的16位char数组的循环遍历需要显示引用管理本机代码时候要保持处理JNI调用之间的VM对象NDK在Android平台仅仅提供了有限的本地API和库文件的支持的系统头文件,然而一个标准的Android系统镜像包括许多本地共享库,这些都应该被考虑在更新和发行版本的可以彻底改变的实现细节如果Android系统库没有明确的被NDK明确的支持,然后应用程序不应该依赖于它提供的,或者打破了将来在各种设备上的无线系统更新选定的系统库将逐渐被添加到稳定的NDK API中。3.NDK开发实践下面将给出一个怎样用Android NDK开发本地代码的粗略的概述(1) 把本地代码放在$PROJECT/jni/…下,比如将hello.c放到apps/hello/jni/目录下(2) 在你的NDK编译系统中在$PROJECT/jni/Android.mk来描述你的源代码(3) 可选:在$PROJECT/jni/Application.mk到你的编译系统中来详细描述你的项目,尽管你开始的话不一定需要它,但是它允许你使用更多的CPU或者覆盖编译器/链接器的标记(4) 从你的项目的目录开始通过运行”$NDK/ndk-build”来编译你的代码,或者从子目录开始(5) 最后一步可以,万一成功,剥离共享库的应用层序需要你的应用程序的项目根目录。然后你通过通常的方法来生成最终的apk。

㈢ 如何让编译器架构Android.mk动态

Android.mk文件用来告知NDK Build 系统关于Source的信息。 Android.mk将是GNU Makefile的一部分,且将被Build System解析一次或多次。所以,请尽量少的在Android.mk中声明变量,也不要假定任何东西不会在解析过程中定义。Android.mk文件语法允许我们将Source打包成一个"moles". moles可以是:静态库动态库。只有动态库可以被 install/到应用程序包(APK). 静态库则可以被链接入动态库。可以在一个Android.mk中定义一个或多个moles. 也可以将同一份source 加进多个moles.Build System帮我们处理了很多细节而不需要我们再关心。例如:你不需要在Android.mk中列出头文件和外部依赖文件。NDK Build System自动帮我们提供这些信息。这也意味着,当用户升级NDK后,你将可以受益于新的toolchain/platform而不必再去修改Android.mk.1. Android.mk语法:首先看一个最简单的Android.mk的例子:LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE := hello-jniLOCAL_SRC_FILES := hello-jni.cinclude $(BUILD_SHARED_LIBRARY)讲解如下:LOCAL_PATH := $(call my-dir)每个Android.mk文件必须以定义LOCAL_PATH为开始。它用于在开发tree中查找源文件。宏my-dir则由Build System提供。返回包含Android.mk的目录路径。include $(CLEAR_VARS)CLEAR_VARS 变量由Build System提供。并指向一个指定的GNU Makefile,由它负责清理很多LOCAL_xxx.例如:LOCAL_MODULE, LOCAL_SRC_FILES, LOCAL_STATIC_LIBRARIES等等。但不清理LOCAL_PATH.这个清理动作是必须的,因为所有的编译控制文件由同一个GNU Make解析和执行,其变量是全局的。所以清理后才能避免相互影响。LOCAL_MODULE := hello-jniLOCAL_MODULE模块必须定义,以表示Android.mk中的每一个模块。名字必须唯一且不包含空格。Build System会自动添加适当的前缀和后缀。例如,foo,要产生动态库,则生成libfoo.so. 但请注意:如果模块名被定为:libfoo.则生成libfoo.so. 不再加前缀。LOCAL_SRC_FILES := hello-jni.cLOCAL_SRC_FILES变量必须包含将要打包如模块的C/C++ 源码。不必列出头文件,build System 会自动帮我们找出依赖文件。缺省的C++源码的扩展名为.cpp. 也可以修改,通过LOCAL_CPP_EXTENSION。include $(BUILD_SHARED_LIBRARY)BUILD_SHARED_LIBRARY:是Build System提供的一个变量,指向一个GNU Makefile Script。它负责收集自从上次调用 include $(CLEAR_VARS) 后的所有LOCAL_XXX信息。并决定编译为什么。BUILD_STATIC_LIBRARY:编译为静态库。 BUILD_SHARED_LIBRARY :编译为动态库 BUILD_EXECUTABLE:编译为Native C可执行程序 2. NDK Build System变量:NDK Build System 保留以下变量名:以LOCAL_ 为开头的以PRIVATE_ ,NDK_ 或者APP_ 开头的名字。小写字母名字:如my-dir如果想要定义自己在Android.mk中使用的变量名,建议添加 MY_前缀。2.1: NDK提供的变量:此类GNU Make变量是NDK Build System在解析Android.mk之前就定义好了的。2.1.1:CLEAR_VARS:指向一个编译脚本。必须在新模块前包含之。 include $(CLEAR_VARS)2.1.2:BUILD_SHARED_LIBRARY:指向一个编译脚本,它收集自从上次调用 include $(CLEAR_VARS) 后的所有LOCAL_XXX信息。并决定如何将你列出的Source编译成一个动态库。 注意,在包含此文件前,至少应该包含:LOCAL_MODULE and LOCAL_SRC_FILES 例如: include $(BUILD_SHARED_LIBRARY) 2.1.3:BUILD_STATIC_LIBRARY:与前面类似,它也指向一个编译脚本,收集自从上次调用 include $(CLEAR_VARS) 后的所有LOCAL_XXX信息。并决定如何将你列出的Source编译成一个静态库。 静态库不能够加入到Project 或者APK中。但它可以用来生成动态库。LOCAL_STATIC_LIBRARIES and LOCAL_WHOLE_STATIC_LIBRARIES将描述之。 include $(BUILD_STATIC_LIBRARY) 2.1.4: BUILD_EXECUTABLE: 与前面类似,它也指向一个编译脚本,收集自从上次调用 include $(CLEAR_VARS) 后的所有LOCAL_XXX信息。并决定如何将你列出的Source编译成一个可执行Native程序。 include $(BUILD_EXECUTABLE) 2.1.5:PREBUILT_SHARED_LIBRARY:把这个共享库声明为 “一个” 独立的模块。指向一个build 脚本,用来指定一个预先编译好多动态库。 与BUILD_SHARED_LIBRARY and BUILD_STATIC_LIBRARY不同,此时模块的LOCAL_SRC_FILES应该被指定为一个预先编译好的动态库,而非source file. LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE := foo-prebuilt # 模块名LOCAL_SRC_FILES := libfoo.so # 模块的文件路径(相对于 LOCAL_PATH)include $(PREBUILT_SHARED_LIBRARY) # 注意这里不是 BUILD_SHARED_LIBRARY这个共享库将被拷贝到 $PROJECT/obj/local 和 $PROJECT/libs/<abi> (stripped) 主要是用在将已经编译好的第三方库使用在本Android Project中。为什么不直接将其COPY到libs/armabi目录呢?因为这样做缺陷很多。下一节再详细说明。2.1.6: PREBUILT_STATIC_LIBRARY:预先编译的静态库。 同上。2.1.7: TARGET_ARCH: 目标CPU架构名。如果为“arm” 则声称ARM兼容的指令。与CPU架构版本无关。2.1.8: TARGET_PLATFORM: 目标的名字。2.1.9:TARGET_ARCH_ABIName of the target CPU+ABI armeabi For ARMv5TE armeabi-v7a2.1.10:TARGET_ABI 2.2: NDK提供的功能宏: GNUMake 提供的功能宏,只有通过类似: $(call function) 的方式来得到其值,它将返回文本化的信息。 2.2.1: my-dir: $(call my-dir): 返回最近一次include的Makefile的路径。通常返回Android.mk所在的路径。它用来作为Android.mk的开头来定义LOCAL_PATH. LOCAL_PATH := $(call my-dir) 请注意:返回的是最近一次include的Makefile的路径。所以在Include其它Makefile后,再调用$(call my-dir)会返回其它Android.mk 所在路径。 例如: LOCAL_PATH := $(call my-dir) declare one mole include $(LOCAL_PATH)/foo/Android.mk LOCAL_PATH := $(call my-dir) declare another mole则第二次返回的LOCAL_PATH为:$PATH/foo。 而非$PATH. 2.2.2: all-subdir-makefiles:返回一个列表,包含'my-dir'中所有子目录中的Android.mk。 例如: 结构如下: sources/foo/Android.mk sources/foo/lib1/Android.mk sources/foo/lib2/Android.mk 在If sources/foo/Android.mk 中, include $(call all-subdir-makefiles) 那则自动include 了sources/foo/lib1/Android.mk and sources/foo/lib2/Android.mk。2.2.3:this-makefile: 当前Makefile的路径。 2.2.4:parent-makefile: 返回include tree中父Makefile 路径。 也就是include 当前Makefile的Makefile Path。 2.2.5:import-mole: 允许寻找并inport其它moles到本Android.mk中来。 它会从NDK_MODULE_PATH寻找指定的模块名。 $(call import-mole,<name>)2.3: 模块描述变量: 此类变量用来给Build System描述模块信息。在'include $(CLEAR_VARS)' 和 'include $(BUILD_XXXXX)'之间。必须定义此类变量。 include $(CLEAR_VARS) script用来清空这些变量。 include $(BUILD_XXXXX)收集和使用这些变量。 2.3.1: LOCAL_PATH: 这个值用来给定当前目录。必须在Android.mk的开是位置定义之。例如: LOCAL_PATH := $(call my-dir) LOCAL_PATH不会被include $(CLEAR_VARS) 清理。 2.3.2: LOCAL_MODULE: moles名。在include $(BUILD_XXXXX)之前,必须定义这个变量。此变量必须唯一且不能有空格。 通常,由此变量名决定最终生成的目标文件名。2.3.3: LOCAL_MODULE_FILENAME: 可选。用来override LOCAL_MODULE. 即允许用户重新定义最终生成的目标文件名。 LOCAL_MODULE := foo-version-1 LOCAL_MODULE_FILENAME := libfoo2.3.4:LOCAL_SRC_FILES: 为Build Moles而提供的Source 文件列表。不需要列出依赖文件。 注意:文件相对于LOCAL_PATH存放,且可以提供相对路径。 例如: LOCAL_SRC_FILES := foo.c \ toto/bar.c2.3.5: LOCAL_CPP_EXTENSION: 指出C++ 扩展名。(可选) LOCAL_CPP_EXTENSION := .cxx 从NDK R7后,可以写多个: LOCAL_CPP_EXTENSION := .cxx .cpp .cc 2.3.6:LOCAL_CPP_FEATURES: 可选。用来指定C++ features。 LOCAL_CPP_FEATURES := rtti LOCAL_CPP_FEATURES := exceptions2.3.7:LOCAL_C_INCLUDES: 一个可选的path列表。相对于NDK ROOT 目录。编译时,将会把这些目录附上。 LOCAL_C_INCLUDES := sources/foo LOCAL_C_INCLUDES := $(LOCAL_PATH)/../foo2.3.8: LOCAL_CFLAGS:一个可选的设置,在编译C/C++ source 时添加如Flags。 用来附加编译选项。 注意:不要尝试在此处修改编译的优化选项和Debug等级。它会通过您Application.mk中的信息自动指定。 也可以指定include 目录通过:LOCAL_CFLAGS += -I<path>。 这个方法比使用LOCAL_C_INCLUDES要好。因为这样也可以被ndk-debug使用。 2.3.9: LOCAL_CXXFLAGS: LOCAL_CPPFLAGS的别名。 2.3.10: LOCAL_CPPFLAGS: C++ Source 编译时添加的C Flags。这些Flags将出现在LOCAL_CFLAGS flags 的后面。 2.3.11: LOCAL_STATIC_LIBRARIES: 要链接到本模块的静态库list。(built with BUILD_STATIC_LIBRARY)2.3.12: LOCAL_SHARED_LIBRARIES: 要链接到本模块的动态库。 2.3.13:LOCAL_WHOLE_STATIC_LIBRARIES: 静态库全链接。 不同于LOCAL_STATIC_LIBRARIES,类似于使用–whole-archive 2.3.14:LOCAL_LDLIBS: linker flags。 可以用它来添加系统库。 如 -lz: LOCAL_LDLIBS := -lz 2.3.15: LOCAL_ALLOW_UNDEFINED_SYMBOLS: 2.3.16: LOCAL_ARM_MODE: 缺省模式下,ARM目标代码被编译为thumb模式。每个指令16位。如果指定此变量为:arm。 则指令为32位。 LOCAL_ARM_MODE := arm 其实也可以指定某一个或者某几个文件的ARM指令模式。 2.3.17: LOCAL_ARM_NEON: 设置为true时,会讲浮点编译成neon指令。这会极大地加快浮点运算(前提是硬件支持) 只有targeting 为 'armeabi-v7a'时才可以。 2.3.18:LOCAL_DISABLE_NO_EXECUTE: 2.3.19: LOCAL_EXPORT_CFLAGS: 定义这个变量用来记录C/C++编译器标志集合,并且会被添加到其他任何以LOCAL_STATIC_LIBRARIES和LOCAL_SHARED_LIBRARIES的模块的LOCAL_CFLAGS定义中 LOCAL_SRC_FILES := foo.c bar.c.arm 注意:此处NDK版本为NDK R7C.(不同NDK版本,ndk-build所产生的Makefile并不完全相同)

㈣ 如何自动设好 Android.mk 的 LOCAL

最简单的方式就是调用shell外部命令。首先咱们指定要搜索的源文件根目录,设为SRC_ROOT这个变量。LOCAL_C_INCLUDES变量直接就是用find <path> -type d命令去搜索根目录下的目录。LOCAL_SRC_FILES稍微复杂一些,首先咱们先用find <path> -type f得到所有的普通文件路径,再指定源代码文件名的匹配模式(例如咱用的是c++,所以咱指定了变量SRC_SUFFIX存放一般c++源代码文件的后缀名),用filter命令筛选出所有的源代码文件路径。完整的代码如下:# WARNING: Shell command is used, it is only works on a UNIX-like OS.# Replace it with Makefile rules if you want to run on Windows.SRC_SUFFIX := *.cpp *.cSRC_ROOT := $(LOCAL_PATH)/../../ClassesALL_FILES := $(shell find $(SRC_ROOT) -type f)SRC_FILES := $(filter $(subst *,%,$(SRC\_SUFFIX)),$(ALL_FILES))LOCAL_SRC_FILES := hellocpp/main.cppLOCAL_SRC_FILES += $(SRC\_FILES:$(LOCAL_PATH)/%=%)SRC_DIRS := $(shell find $(SRC_ROOT) -type d)LOCAL_C_INCLUDES := $(SRC_DIRS)

㈤ 谁知道跟我一起写 Makefile(转载)Makefile有什么

Makefile里主要包含了五个东西:显式规则、隐晦规则、变量定义、文件指示和注释。 1、显式规则。显式规则说明了,如何生成一个或多的的目标文件。这是由Makefile的书写者明显指出,要生成的文件,文件的依赖文件,生成的命令。 2、隐晦规则。由于我们的make有自动推导的功能,所以隐晦的规则可以让我们比较粗糙地简略地书写Makefile,这是由make所支持的。 3、变量的定义。在Makefile中我们要定义一系列的变量,变量一般都是字符串,这个有点你C语言中的宏,当Makefile被执行时,其中的变量都会被扩展到相应的引用位置上。 4、文件指示。其包括了三个部分,一个是在一个Makefile中引用另一个Makefile,就像C语言中的include一样;另一个是指根据某些情况指定Makefile中的有效部分,就像C语言中的预编译#if一样;还有就是定义一个多行的命令。有关这一部分的内容,我会在后续的部分中讲述。 5、注释。Makefile中只有行注释,和UNIX的Shell脚本一样,其注释是用“#”字符,这个就像C/C++中的“//”一样。如果你要在你的Makefile中使用“#”字符,可以用反斜框进行转义,如:“\#”。 最后,还值得一提的是,在Makefile中的命令,必须要以[Tab]键开始。 二、Makefile的文件名 默认的情况下,make命令会在当前目录下按顺序找寻文件名为“GNUmakefile”、“makefile”、“Makefile”的文件,找到了解释这个文件。在这三个文件名中,最好使用“Makefile”这个文件名,因为,这个文件名第一个字符为大写,这样有一种显目的感觉。最好不要用“GNUmakefile”,这个文件是GNU的make识别的。有另外一些make只对全小写的“makefile”文件名敏感,但是基本上来说,大多数的make都支持“makefile”和“Makefile”这两种默认文件名。 当然,你可以使用别的文件名来书写Makefile,比如:“Make.Linux”,“Make.Solaris”,“Make.AIX”等,如果要指定特定的Makefile,你可以使用make的“-f”和“–file”参数,如:make -f Make.Linux或make –file Make.AIX。 三、引用其它的Makefile 在Makefile使用include关键字可以把别的Makefile包含进来,这很像C语言的#include,被包含的文件会原模原样的放在当前文件的包含位置。include的语法是: include ; filename可以是当前操作系统Shell的文件模式(可以保含路径和通配符) 在include前面可以有一些空字符,但是绝不能是[Tab]键开始。include和;可以用一个或多个空格隔开。举个例子,你有这样几个Makefile:a.mk、b.mk、c.mk,还有一个文件叫foo.make,以及一个变量$(bar),其包含了e.mk和f.mk,那么,下面的语句: include foo.make *.mk $(bar) 等价于: include foo.make a.mk b.mk c.mk e.mk f.mk make命令开始时,会把找寻include所指出的其它Makefile,并把其内容安置在当前的位置。就好像C/C++的#include指令一样。如果文件都没有指定绝对路径或是相对路径的话,make会在当前目录下首先寻找,如果当前目录下没有找到,那么,make还会在下面的几个目录下找: 1、如果make执行时,有“-I”或“–include-dir”参数,那么make就会在这个参数所指定的目录下去寻找。 2、如果目录;/include(一般是:/usr/local/bin或/usr/include)存在的话,make也会去找。 如果有文件没有找到的话,make会生成一条警告信息,但不会马上出现致命错误。它会继续载入其它的文件,一旦完成makefile的读取,make会再重试这些没有找到,或是不能读取的文件,如果还是不行,make才会出现一条致命信息。如果你想让make不理那些无法读取的文件,而继续执行,你可以在include前加一个减号“-”。如: -include ; 其表示,无论include过程中出现什么错误,都不要报错继续执行。和其它版本make兼容的相关命令是sinclude,其作用和这一个是一样的。 四、环境变量 MAKEFILES 如果你的当前环境中定义了环境变量MAKEFILES,那么,make会把这个变量中的值做一个类似于include的动作。这个变量中的值是其它的Makefile,用空格分隔。只是,它和include不同的是,从这个环境变中引入的Makefile的“目标”不会起作用,如果环境变量中定义的文件发现错误,make也会不理。 但是在这里我还是建议不要使用这个环境变量,因为只要这个变量一被定义,那么当你使用make时,所有的Makefile都会受到它的影响,这绝不是你想看到的。在这里提这个事,只是为了告诉大家,也许有时候你的Makefile出现了怪事,那么你可以看看当前环境中有没有定义这个变量。 五、make的工作方式 GNU的make工作时的执行步骤入下:(想来其它的make也是类似) 1、读入所有的Makefile。 2、读入被include的其它Makefile。 3、初始化文件中的变量。 4、推导隐晦规则,并分析所有规则。 5、为所有的目标文件创建依赖关系链。 6、根据依赖关系,决定哪些目标要重新生成。 7、执行生成命令。 1-5步为第一个阶段,6-7为第二个阶段。第一个阶段中,如果定义的变量被使用了,那么,make会把其展开在使用的位置。但make并不会完全马上展开,make使用的是拖延战术,如果变量出现在依赖关系的规则中,那么仅当这条依赖被决定要使用了,变量才会在其内部展开。 当然,这个工作方式你不一定要清楚,但是知道这个方式你也会对make更为熟悉。有了这个基础,后续部分也就容易看懂了。 gunguymadman 回复于:2004-09-16 12:19:56书写规则 ———— 规则包含两个部分,一个是依赖关系,一个是生成目标的方法。 在Makefile中,规则的顺序是很重要的,因为,Makefile中只应该有一个最终目标,其它的目标都是被这个目标所连带出来的,所以一定要让make知道你的最终目标是什么。一般来说,定义在Makefile中的目标可能会有很多,但是第一条规则中的目标将被确立为最终的目标。如果第一条规则中的目标有很多个,那么,第一个目标会成为最终的目标。make所完成的也就是这个目标。 好了,还是让我们来看一看如何书写规则。

㈥ 请教MK文件语法LOCAL_CFLAGS的用法

LOCAL_CFLAGS-D,增加全局宏定义。LOCAL_CFLAGS := -DUSE_JSC相当于在所有源文件中增加一个#define USE_JSCLOCAL_CFLAGS := -DUSE_COPY_BIT=1相当于在所有源文件中增加一个#define USE_COPY_BIT 1

㈦ 如何自动设好 Android.mk 的 LOCAL

用Cocos2d-x开发Android游戏时,需要在Android.mk文件中,为LOCAL_SRC_FILES变量指定要编译的源代码,以及为LOCAL_C_INCLUDES变量指定头文件。当项目文件越来越多时,这种手动修改很浪费时间。好在Android.mk其实就是一个makefile,可以借助makefile语法来自动完成这部分工作。使用外部命令最简单的方式就是调用shell外部命令。首先自己指定要搜索的源文件根目录,设为SRC_ROOT这个变量。LOCAL_C_INCLUDES变量直接就是用find <path> -type d命令去搜索根目录下的目录。LOCAL_SRC_FILES稍微复杂一些,首先自己先用find <path> -type f得到所有的普通文件路径,再指定源代码文件名的匹配模式(例如用的是c++,所以指定了变量SRC_SUFFIX存放一般c++源代码文件的后缀名),用filter命令筛选出所有的源代码文件路径。完整的代码如下:# WARNING: Shell command is used, it is only works on a UNIX-like OS.# Replace it with Makefile rules if you want to run on Windows.SRC_SUFFIX := *.cpp *.cSRC_ROOT := $(LOCAL_PATH)/../../ClassesALL_FILES := $(shell find $(SRC_ROOT) -type f)SRC_FILES := $(filter $(subst *,%,$(SRC\_SUFFIX)),$(ALL_FILES))LOCAL_SRC_FILES := hellocpp/main.cppLOCAL_SRC_FILES += $(SRC\_FILES:$(LOCAL_PATH)/%=%)SRC_DIRS := $(shell find $(SRC_ROOT) -type d)LOCAL_C_INCLUDES := $(SRC_DIRS)使用纯Makefile语法使用外部命令是最简单实用的解决方案,但正如上面的代码注释所提及的,这种方式只能在Unix系统上才能用,对于需要跨平台适用的情况,还是需要采用纯Makefile语法才行。知道,Makefile的wildcard命令可以部分实现类似find的功能,例如找到当前目录下的.c文件可以用$(wildcard *.c),可惜wildcard毕竟不够强大,该命令的结果并不包含子目录以下的.c文件。想要实现这一功能,可以借用StackOverflow上大神用纯Makefile语法写的递归wildcard:# recursive wildcardrwildcard = $(foreach d,$(wildcard $1\*),$(call rwildcard,$d/,$2) $(filter $(subst *,%,$2),$d)))该rwildcard命令传入两个参数,第一个参数$1是目录,第二个参数$2是匹配模式。该命令首先用$(wildcard $1*)得到目录下的所有文件和一级子目录,再遍历一遍:对于当前$d变量是目录的情况,对$d/目录递归调用rwildcard;对于$d是普通文件的情况,递归调用会因为$(wildcard $d/*)找不到匹配而终止,接下来便调用filter函数对$2的模式进行筛选。完整的代码如下:SRC_SUFFIX := *.cpp *.cSRC_ROOT := $(LOCAL_PATH)/../../Classes# recursive wildcardrwildcard = $(foreach d,$(wildcard $1\*),$(call rwildcard,$d/,$2) $(filter $(subst *,%,$2),$d)))SRC_FILES := $(call rwildcard,$(SRC_ROOT)/,$(SRC_SUFFIX))LOCAL_SRC_FILES := hellocpp/main.cppLOCAL_SRC_FILES += $(SRC\_FILES:$(LOCAL_PATH)/%=%)筛除不需要编译的源代码文件上面介绍的方法有一个适用的前提,那就是$SRC_ROOT下每个源代码文件都需要被编译。而有时候这个条件并不成立,像本渣所在项目中就用到了一些外部库,这些库的源代码是不用被编译的(例如设为ASIO_HEADER_ONLY的Asio库)。这个时候就需要把这部分源代码排除在LOCAL_SRC_FILES之外。第一种方法:filter-out第一种方法是用Makefile的filter-out命令:# ASIO library is set as ASIO_HEADER_ONLY, so it will be excluded from source codeEXCLUDE_SRC_FILES := $(SRC_ROOT)/3rdParty/Asio/asio/impl/%.cppEXCLUDE := $(filter $(EXCLUDE_SRC_FILES),$(SRC_FILES))SRC_FILES := $(filter-out $(EXCLUDE_SRC_FILES),$(SRC_FILES))这种方式虽然可行,但是filter-out无法用于多级目录的模式匹配,所以这种方法暴露了太多关于外部库源代码路径的细节。有没有可能指定要排除的库名或关键字,再根据这个信息去筛除匹配的源代码文件呢?第二种方法:改进rwildcard第二种方式是在rwildcard中加入一个判断用于筛除:如果当前的目录/文件名匹配到所要筛除的关键字,则什么都不做;否则就继续递归调用和执行filter命令。# ASIO library is set as ASIO_HEADER_ONLY, so it will be excludedEXCLUDE_LIB := Asio# recursive wildcardrwildcard = $(foreach d,$(wildcard $1\*),$(if $(findstring $(EXCLUDE_LIB),$d),,$(call rwildcard,$d/,$2) $(filter $(subst *,%,$2),$d)))SRC_FILES := $(call rwildcard,$(SRC_ROOT)/,$(SRC_SUFFIX))这种方式是好一些了,而且直接在递归wildcard搜索时就进行了排除,不过rwildcard变得更复杂了,可读性不佳。第三种方法:FILTER_OUT_PATTERN最后的方法也来自于StackOverflow大神用纯Makefile语法改造过的filter-out,不过本质上和第二种方法的实现是类似的,这里就不详细解释了:# ASIO library is set as ASIO_HEADER_ONLY, so it will be excluded from source codeEXCLUDE_SRC_PATTERN := asioFILTER_OUT_PATTERN = $(foreach v,$(2),$(if $(findstring $(1),$(v)),,$(v)))SRC_FILES := $(call FILTER\_OUT\_PATTERN,$(EXCLUDE_SRC_PATTERN),$(SRC_FILES))

㈧ Android.mk语法问题

这个遍历文件路径和文件类型

㈨ shell脚本提取文档中的一个多位数,加一,返回

digit就是数字的意思,望文生义,[[:digit:]] 表示数字类,匹配一位数字。

grep的-E选项表示使用扩展的正则表达式,-o表示仅提取正则匹配的内容,而不是返回整行内容。

awk 'BEGIN{FS="=";OFS="="} NR==267{$3+=1;print}'data.mk 也可以,awk相当于一门小型语言,里面的语法类似C语法,支持直接做运算,还有一些内置函数。所以如果在文本处理的同时涉及运算的话,用awk可以一站式解决,更为方便。

方法很多,下面这样也行:

#!/bin/bashnum=`sed-nr'267s/.*=([0-9]+).*/1/p'data.mk`echo$((num+1))

其中,-r选项等同于grep的-E选项。

[0-9]和[[:digit:]]是等价的,都表示数字类。只不过[[:digit:]]是符合POSIX标准的用法,更为标准和通用。

这就可以返回并打印结果到控制台了。要写入文件的话,用重定向。


赞 (0)