android makefile

Android.mk 用法

Android.mk 文件向系统描述源代码如何编译。该文件是GUN MakeFile的一小部分,会被编译系统解析一次或多次。可以在每一个Android.mk中定义一个或多个模块。每个模块属于下列类型之一。

  1. APK程序,一般的Andrid程序,编译打包生成apk文件

  2. JAVA库,java类库,编译打包生成jar文件

  3. C/C++应用程序,可执行的C/C++应用程序

  4. C/C++静态库,编译生成C/C++静态库,打包生成.a文件。

  5. C/C++共享库,编译生成共享库(动态链接库),并打包成.so文件。有且只有共享库才能被安装到apk中。

举例

//packages/apps/SoundRecorder/Android.mk
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := SoundRecorder
LOCAL_PRIVILEGED_MODULE := true
include $(BUILD_PACKAGE)

说明

  • LOCAL_PATH:= $(call my-dir)

一个Android.mk 文件必需定义好LOCAL_PATH变量。用于在开发树中查找源文件。宏函数 ‘my-dir’ 由编译系统提供,用于返回当前路径,即Android.mk所在目录

  • include $(CLEAR_VARS)

CLEAR_VARS由编译系统提供((可以在 android 安装目录下的/build/core/config.mk 文件看到其定义,为 CLEAR_VARS:= $(BUILD_SYSTEM)/clear_vars.mk)),指定让GNU MAKEFILE为你清除许多LOCAL_XXX变量(例如 LOCAL_MODULE, LOCAL_SRC_FILES, LOCAL_STATIC_LIBRARIES, 等等…),除LOCAL_PATH 。这是必要的,因为所有的编译控制文件都在同一个GNU MAKE执行环境中,所有的变量都是全局的。

  • LOCAL_MODULE_TAGS := optional

LOCAL_MODULE_TAGS := user eng tests optional user: 指该模块只在user版本下才编译eng: 指该模块只在eng版本下才编译tests: 指该模块只在tests版本下才编译optional:指该模块在所有版本下都编译默认,optional。

  • LOCAL_SRC_FILES := $(call all-subdir-java-files)

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

  • LOCAL_PACKAGE_NAME := SoundRecorder

package的名字

  • LOCAL_PRIVILEGED_MODULE := true

声明app需要放在/system/priv-app下

  • include $(BUILD_PACKAGE)

编译一个apk程序

mk文件

Android.mk文件用来告知NDK Build 系统关于Source的信息。 Android.mk将是GNU Makefile的一部分,且将被Build System解析一次或多次。 所以,请尽量少的在Android.mk中声明变量,也不要假定任何东西不会在解析过程中定义。

Android.mk文件语法允许我们将Source打包成一个"modules". modules可以是:静态库、 动态库

只有动态库可以被 install/copy到应用程序包(APK). 静态库则可以被链接入动态库。可以在一个Android.mk中定义一个或多个modules. 也可以将同一份source 加进多个modules.

Build System帮我们处理了很多细节而不需要我们再关心。例如:你不需要在Android.mk中列出头文件和外部依赖文件。

NDK Build System自动帮我们提供这些信息。这也意味着,当用户升级NDK后,你将可以受益于新的toolchain/platform而不必再去修改Android.mk.

Android.mk语法

每个Android.mk文件必须以定义LOCAL_PATH为开始。它用于在开发tree中查找源文件。宏my-dir 则由Build System提供。返回包含Android.mk的目录路径。 LOCAL_PATH:= $(call my-dir)

CLEAR_VARS 变量由Build System提供。并指向一个指定的GNU Makefile,由它负责清理很多LOCAL_xxx. #例如:LOCAL_MODULE, LOCAL_SRC_FILES, LOCAL_STATIC_LIBRARIES等等。但不清理LOCAL_PATH. #这个清理动作是必须的,因为所有的编译控制文件由同一个GNU Make解析和执行,其变量是全局的。所以清理后才能避免相互影响。 include $(CLEAR_VARS)

LOCAL_MODULE模块必须定义,以表示Android.mk中的每一个模块。名字必须唯一且不包含空格。 #Build System会自动添加适当的前缀和后缀。例如,foo,要产生动态库,则生成libfoo.so. 但请注意:如果模块名被定为:libfoo.则生成libfoo.so. 不再加前缀。 LOCAL_MODULE := hello-jni

LOCAL_SRC_FILES变量必须包含将要打包如模块的C/C++ 源码。 #不必列出头文件,build System 会自动帮我们找出依赖文件。 #缺省的C++源码的扩展名为.cpp. 也可以修改,通过LOCAL_CPP_EXTENSION。 LOCAL_SRC_FILES := hello-jni.c

#BUILD_SHARED_LIBRARY:是Build System提供的一个变量,指向一个GNU Makefile Script。 #它负责收集自从上次调用 include $(CLEAR_VARS) 后的所有LOCAL_XXX信息。并决定编译为什么。 #BUILD_STATIC_LIBRARY:编译为静态库。 #BUILD_SHARED_LIBRARY :编译为动态库 #BUILD_EXECUTABLE:编译为Native C可执行程序
include $(BUILD_SHARED_LIBRARY)

#NDK Build System变量: #NDK Build System 保留以下变量名: #以LOCAL_ 为开头的 #以PRIVATE_ ,NDK_ 或者APP_ 开头的名字。 #小写字母名字:如my-dir

NDK提供的变量 #CLEAR_VARS:指向一个编译脚本。必须在新模块前包含之。 include $(CLEAR_VARS) #BUILD_STATIC_LIBRARY:与前面类似,它也指向一个编译脚本,收集自从上次调用 include $(CLEAR_VARS) 后的所有LOCAL_XXX信息。 #并决定如何将你列出的Source编译成一个静态库。 静态库不能够加入到Project 或者APK中。但它可以用来生成动态库。 #LOCAL_STATIC_LIBRARIES and LOCAL_WHOLE_STATIC_LIBRARIES将描述之。
include $(BUILD_STATIC_LIBRARY) #BUILD_EXECUTABLE:它也指向一个编译脚本,收集自从上次调用 include $(CLEAR_VARS) 后的所有LOCAL_XXX信息。并决定如何将你列出的Source编译成一个可执行Native程序。 include $(BUILD_EXECUTABLE)

others

LOCAL_MODULE := helloworld,LOCAL_MODULE变量必须定义,以标识你在Android.mk文件中描述的每个模块。名称必须是唯一的。注意编译系统会 自动产生合适的前缀和后缀,换句话说,一个被命名为’foo’的共享库模块,将会生成’libfoo.so’文件(也可以直接已libxxx命名好)。 此处虽没用到其他常用的还有: 5,LOCAL_C_INCLUDES:可选变量,表示头文件的搜索路径。默认的头文件的搜索路径是LOCAL_PATH目录。示例:LOCAL_C_INCLUDES := sources/foo或LOCAL_C_INCLUDES := $(LOCAL_PATH)/…/foo 6,TARGET_ARCH:目标 CPU平台的名字;TARGET_PLATFORM:Android.mk 解析的时候,目标 Android 平台的名字;TARGET_ARCH_ABI:暂时只支持两个 value,armeabi 和 armeabi-v7a 7,LOCAL_STATIC_LIBRARIES: 表示该模块需要使用哪些静态库,以便在编译时进行链接。 8,LOCAL_SHARED_LIBRARIES: 表示模块在运行时要依赖的共享库(动态库),在链接时就需要,以便在生成文件时嵌入其相应的信息。 9,LOCAL_LDLIBS: 编译模块时要使用的附加的链接器选项。 10,LOCAL_ARM_MODE: 默认情况下, arm目标二进制会以 thumb 的形式生成(16 位),你可以通过设置这个变量为 arm如果你希望你的 module 是以 32 位指令的形式11,LOCAL_CFLAGS: 可选的编译器选项,在编译 C 代码文件的时候使用 12,include $(call all-subdir-makefiles):返回一个位于当前’my-dir’路径的子目录中的所有Android.mk的列表。

Android.mk的用法和基础 && m、mm、mmm编译命令
Android MakeFfile文件讲解
Android build system & Android.mk 规范
Android Makefile 笔记
理解 Android Build 系统
android.mk语法详解

简单例子 Package

LOCAL_PATH := $(call my-dir)#每个Android.mk 文件必须定义LOCAL_PATH为开始,用于在tree中查找源文件。#宏my-dir 由Build System提供,返回包含Android.mk 的目录名字
include $(CLEAR_VARS)#CLEAR_VARS 由Build System提供,指向一个GUN Makefile,负责清理LOCAL_xxx。#如LOCAL_MODULE, LOCAL_SRC_FILES, LOCAL_STATIC_LIBRARIES,等等,但是不清理LOCAL_PATH#这个是必须的,因为所有的编译控制文件由同一个GUN Make解析和执行。其变量是全局的,清理能够避免相互影响。
LOCAL_MODULE_TAGS := optional#进行编译的版本 #user 只在user版本下编译,user版本,adb 默认是关闭的,为了提高速度dex是打开的。#eng只在eng版本下编译,工程版本,debug版,adb默认打开,且设置向导是可选的。#tests只在test版本下编译#optional只在user版本下编译 ##取值范围debug eng tests optional samples shell_ash shell_mksh。注意不能取值user,如果要预装,则应定义core.mk。
LOCAL_PACKAGE_NAME := GaeiImage #package 的名字,这个名字在脚本中标识这个apk或package
LOCAL_SRC_FILES := $(call all-java-files, src) #如果要包含的是java源码的话,可以调用all-java-files-under得到。(这种形式来包含local_path目录下的所有java文件)#当涉及到C/C++时,LOCAL_SRC_FILES变量就必须包含将要编译打包进模块中的C或C++源代码文件。注意,在这里你可以不用列出头文件和包含文件,因为编译系统将会自动为你找出依赖型的文件;仅仅列出直接传递给编译器的源代码文件就好。#all-java-files-under宏的定义是在build/core/definitions.mk中#
LOCAL_CERTIFICATE := platform #是文件的签名文件的文件名,
include $(BUILD_PACKAGE)#编译成apk#用来编译生成package/app下的app##其他方式,共四种,必须以其中一种结束#include $(BUILD_STATIC_LIBRARY) 表示编译成静态库#include $(BUILD_SHARED_LIBRARY) 表示编译成动态库#include $(BUILD_EXECUTABLE) 表示编译成可执行程序

常用属性

  • all-makefiles-under

include ( c a l l a l l − m a k e f i l e s − u n d e r , (call all-makefiles-under, (callallmakefilesunder,(LOCAL_PATH))#加载当前目录下的所有makefile文件

all-makefiles-under会返回一个位于当前’my-dir’路径的子目录中的所有Android.mk的列表。#all-makefiles-under宏的定义是在build/core/definitions.mk中

mk常用语法

打印信息

$(warning xxxxx)或者$(error xxxxx)

输出变量方式为:$(warning  $(XXX))
如果是$(error xxxxx)将会停止编译

subst函数

subst是一个替换函数,这个函数有三个参数,第一个参数是被替换字串,第二个参数是替换字串,第三个参数是替换操作作用的字串。 把 c 中的 a 替换成 b

subst $(a),$(b),$(c)
  • 替换函数
comma:= ,
empty:=    
space:= $(empty) $(empty)
foo:=a b c

bar:= $(subst $(space),$(comma),$(foo)) 

这个函数也就是把 ( f o o ) 中的空格替换成逗号,所以 (foo)中的空格替换成逗号,所以 (foo)中的空格替换成逗号,所以(bar)的值是 “a,b,c”

  • 字符串替换
$(subst ee,EE,feet on the street)

feet on the street中的 ee替换成EE,返回结果是 fEEt on the strEEt

推断文件是否存在,若存在则复制该文件到某个文件夹

$(shell test -f [文件] && echo yes) #的值假设是yes, 则文件存在,然后进行shell cp 动作
HAVE_TEST_CUST_FILE := $(shell test -f vendor/huaqin/resource/$(HQ_PROJECT)_$(HQ_CLIENT)/$(LOCAL_PATH)/DroidSansFallback.ttf && echo yes)
ifeq ($(HAVE_TEST_CUST_FILE),yes)
  $(shell cp -f vendor/huaqin/resource/$(HQ_PROJECT)_$(HQ_CLIENT)/$(LOCAL_PATH)/DroidSansFallback.ttf $(PRODUCT_OUT)/system/fonts/DroidSansFallback.ttf)
endif

配置多个AndroidManifest.xml

ifeq ($(TARGET_BUILD_VARIANT), eng)
  LOCAL_MANIFEST_FILE := ex_manifest/AndroidManifest.xml
else
  LOCAL_MANIFEST_FILE := AndroidManifest.xml
endif

运行错误

  • Makefile missing separator
Makefile missing separator

解决:

​ 在Makefile文件中,命令必须以【tab】键开始
​ makefile里不要乱用TAB,只有命令所在的行才能且只能以TAB开头!

  • commands commence before first target

    commands commence before first target
    

    Makefile可能是以命令行开始:以[Tab]字符开始,但不是一个合法的命令行(例如,一个变量的赋值)。命令行必须和规则一一对应。
    第二种的错误的原因可能是一行的第一个非空字符为分号,make会认为此处遗漏了规则的“target: prerequisite”部分。


Android 的编译环境

一、android 的build系统

android build系统可以分成三大块:

  • build/core 目录下,系统的框架和核心

  • device 目录,具体产品的配置文件

  • android.mk 各个模块的编译文件

android 5.0 的build 系统开始支持64位系统。

android build 系统核心

build/core 目录下有几十个mk 文件以及一些shell脚本和perl脚本,构成了android build系统的基础和框架。编译命令有以下三个。

. build/envsetup.sh 建立android 编译环境

lunch 打印菜单让用户选择需要编译的模块。

make 编译系统

envsetup.sh 文件的作用
结尾会在device和vendor目录下搜索所有vendorsetup.sh文件的内容。device/lge/hammerhead下存在。

android 的编译命令

lunchlunch<product_name>-<build_variant> 指定当前编译的产品。
tapas
croot
m编译整个源码,但是不用将当前目录切换到源码的根目录。
mm编译当前目录下的所有模块,但是不编译它们的依赖模块。
mmm编译指定目录下的所有模块,但是不编译它们的依赖模块
mma编译当前目录下的所有模块,同时编译它们的依赖模块。
mmma编译指定目录下的所有模块,同时编译它们的依赖模块。
cgrep对系统所有的C/C++文件执行grep命令。
ggrep对系统所有的本地的Gradle 文件执行grep命令。
jgrep对系统所有Java 文件执行grep文件。
resgrep对系统所有xml目录下的 XML文件执行grep命令。
sgrep对系统中所有源文件执行grep命令。
godir

lunch命令的功能

执行完lunch命令后,系统会打印出当前配置所生成的环境变量。这些环境变量将会影响编译过程。

PLATFORM_VERSION_CODENAME=REL 平台版本名称,通常是AOSP(android open source project)
PLATFORM_VERSION=6.0.1 android平台版本号
TARGET_PRODUCT=leaderphone16 所编译的产品名称
TARGET_BUILD_VARIANT=userdebug 编译的产品类型(eng、user、userdebug)
TARGET_BUILD_TYPE=release 编译的类型(release、debug)
TARGET_BUILD_APPS=  编译android系统时,这个变量的值为null。使用build系统编译单个模块时,这个变量的值是所编译模块的路径。
TARGET_ARCH=arm64 编译目标的cpu架构
TARGET_ARCH_VARIANT=armv8-a 编译目标的cpu架构版本
TARGET_CPU_VARIANT=kryo 编译目标的cpu代号
TARGET_2ND_ARCH=arm 编译目标的第二cpu架构
TARGET_2ND_ARCH_VARIANT=armv7-a-neon 编译目标的第二cpu架构版本
TARGET_2ND_CPU_VARIANT=cortex-a53 编译目标的第二
HOST_ARCH=x86_64 编译平台的架构
HOST_OS=linux 编译平台使用的操作系统
HOST_OS_EXTRA=Linux-4.2.0-42-generic-x86_64-with-Ubuntu-14.04-trusty 编译平台操作系统的一些额外信息,包括内核版本号、产品名称、代号等
HOST_BUILD_TYPE=release 
BUILD_ID=MMB29M Build_id的值会出现在编译的版本信息中,可以利用这个环境变量来定义公司特有的标识
OUT_DIR=out 指定编译结果的输出目录
  • 修改 BUILD_ID的值

make BUILD_ID = “Android L”

  • make命令会调用build/目录下的Makefile文件

他的内容如下 include build/core/main.mk

  • Makefile文件

Makefile文件主要有三种内容构成:变量定义,函数定义、目标依赖规则。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值