精华内容
下载资源
问答
  • android.mk
    千次阅读
    2022-04-24 15:41:02

    前言:

                 在工作,我们利用Android studio开发apk是非常方便的,当我们要把工程代码放在android

    源码中编译的时候,需要我们自己编写Andorid.mk 文件。以下内容是对Android.mk文件中的代码

    解释说明。

    Android.mk 编写:

    #每个Android.mk文件必须以定义LOCAL_PATH为开始。它用于在开发tree中查找源文件

    LOCAL_PATH := $(call my-dir)

    常用的一些 函数

    $(call my-dir)    #获取当前文件夹的路径。
     
    $(call all-java-files-under, <src>)    #获取指定目录下的所有java文件。
     
    $(call all-c-files-under, <src>)    #获取指定目录下的所有c文件。
     
    $(call all-Iaidl-files-under, <src>)    #获取指定目录下的所有AIDL文件。
     
    $(call all-makefiles-under, <folder>)    #获取指定目录下的所有Make文件。
     
    $(call intermediates-dir-for, <class>, <app_name>, <host or target>, <common?>)    #获取Build输入的目标文件夹路径。
     
    $(call first-makefiles-under,$(LOCAL_PATH))    #在LOCAL_PATH的所有子目录中查找.mk文件,不包括当前目录

    #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_TAGS :=  user eng tests optional

    user: 指该模块只在user版本下才编译

    eng: 指该模块只在eng版本下才编译

    tests: 指该模块只在tests版本下才编译

    optional:指该模块在所有版本下都编译

    
    LOCAL_MODULE_TAGS := optional

    #LOCAL_SRC_FILES变量必须包含将要打包如模块的C/C++ , java源码。

    LOCAL_SRC_FILES := $(call all-java-files-under, app/src/main/java)

    #编译AndriodManifest.xml

    LOCAL_MANIFEST_FILE := app/src/main/AndroidManifest.xml


    # 编译的系统资源文件

    LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/app/src/main/res


    # 编译asset资源文件,必须要单独写出来,不然在工程中无法访问到asset路径下的资源文件

    LOCAL_ASSET_DIR := $(LOCAL_PATH)/app/src/main/assets


    #指定APP应用名称

    LOCAL_PACKAGE_NAME := MyTestApp

    #在指定分区中安装此模块

         一般有  system    system_ext     product     vendor     odm       分区     

    #模块编译输出分区
    
    #system :主要包含 Android 框架, google 官方实现
    
        #Android.mk 默认就是输出到 system 分区,不用指定
        #Android.bp 默认就是输出到 system 分区,不用指定
    
    #system_ext: android11 新划分区
    
    #vendor :SoC芯片商分区(系统级核心厂商,如高通), 为他们提供一些核心功能和服务,由 soc 实现
    
        #Android.mk LOCAL_VENDOR_MODULE := true
        #Android.bp vendor: true
    
    #odm :设备制造商分区(如华为、小米),为他们的传感器或外围设备提供一些核心功能和服务
    
        #Android.mk LOCAL_ODM_MODULE := true
        #Android.bp device_specific: true
    
    #product :产品机型分区
    
        #Android.mk LOCAL_PRODUCT_MODULE := true
        #Android.bp product_specific
    
    #安装到product分区
    LOCAL_PRODUCT_MODULE := true   

    #LOCAL_PRIVILEGED_MODULE := true对于Android系统应用LOCAL_PRIVILEGED_MODULE 决定了app在编译后,放在ROM分区中的 app  或者 priv-app位置

    LOCAL_PRIVILEGED_MODULE := true
    
    #如果配置为false 则编译到设备中的路径为  (system or product or vendor/app)
    #如果配置为true  则编译到设备中的路径为  (system or product or vendor/priv-app)

    #使用sdk的hide的api來编译, Android P 之后,Android.mk 必须定义 LOCAL_SDK_VERSION 和 LOCAL_PRIVATE_PLATFORM_APIS 变量中的一个, 这两种是或的关系,只需要定义一个

    #如果需要使用系统隐藏 API编译 则需要定义:
    LOCAL_PRIVATE_PLATFORM_APIS := true
    
    
    #如果不需要使用系统隐藏API编译,则需要定义:
    LOCAL_SDK_VERSION := current
    
    
    #注意,两个是 if --else 的定义原则,根据实际情况选择
    
    

    LOCAL_MODULE_CLASS   指定模块的类型,可不用定义,可以选择不定义

    有如下几种:
    
    编译 apk 文件 ,最后生成的文件路径一般放在 /system/app目录下
    LOCAL_MODULE_CLASS := APPS
    
    编译 jar 包   
    LOCAL_MODULE_CLASS := JAVA_LIBRAYIES
    
    定义动态库文件  最后生成的文件路径放置在/sysem/lib目录下
    LOCAL_MODULE_CLASS := SHARED_LIBRAYIES
    
    编译可执行文件  最后生成的文件路径放置放在system/bin下
    LOCAL_MODULE_CLASS := EXECUTABLES
    
    编译配置文件  最后生成的文件路径放置在 /system/etc/目录下
    LOCAL_MODULE_CLASS := ETC

     #aapt 是编译和打包资源的工具。而aapt2是在aapt上做了优化

    LOCAL_USE_AAPT2 := true   

    #指定依赖的共享java类库,这个是编译时依赖,最终不会打包到apk中

    LOCAL_JAVA_LIBRARIES := javax.obex telephony-common services.net    

    #指定依赖的静态java类库,最终会打包到apk里面。

     使用多个引用的时候,写法如下:

    LOCAL_STATIC_JAVA_LIBRARIES := \
     com.android.vcard \
     bluetooth.cc\ 
     services.net \
    libprotobuf-java-lite \ 

    #指定依赖的模块。指定模块运行所依赖的模块(模块安装时将会同步安装它所依赖的模块)

    LOCAL_REQUIRED_MODULES := libjni_pinyin_test

    #混淆配置,默认为full obfuscation,全代码混淆,disabled不开启

    #不需要使用代码混淆的工具进行代码混淆
    LOCAL_PROGUARD_ENABLED := disabled 
    
    #默认为: 使用将该工程代码全部混淆
    LOCAL_PROGUARD_ENABLE := full

    # LOCAL_CERTIFICATE 用于设置不同的签名方式

            LOCAL_CERTIFICATE := PRESIGNED,打包apk时,沿用apk中原来的签名

    用于设置不同的签名方式build/target/product/security目录中有四组默认签名供Android.mk在编译APK使用:

            1、testkey:普通APK,默认情况下使用。

            2、platform:该APK完成一些系统的核心功能。经过对系统中存在的文件夹的访问测试,这种方式编译出来的APK所在进程的UID为system。

            3、shared:该APK需要和home/contacts进程共享数据。

            4、media:该APK是media/download系统中的一环。

    应用程序的Android.mk中有一个LOCAL_CERTIFICATE字段,由它指定用哪个key签名,未指定的默认用testkey.

    LOCAL_CERTIFICATE :                    #使用平台文件签名
    (1)platform签名: 
    AndroidManifest.xml的manifest节点中添加 android:sharedUserId=”android.uid.system”, 
    Android.mk中增加  LOCAL_CERTIFICATE := platform 
    (2)shared签名: 
    AndroidManifest.xml的manifest节点中增加android:sharedUserId=”android.uid.shared”, 
    Android.mk中增加LOCAL_CERTIFICATE := shared 
    (3)media签名: 
    AndroidManifest.xml的manifest节点中增加 android:sharedUserId=”android.media”, 
    Android.mk中增加 LOCAL_CERTIFICATE := media 

    Settings.apk就是platform级别的签名,系统级应用都应该使用这个签名

    LOCAL_CERTIFICATE := platform

    #声明要调用android包,会打包到apk中,调用多个时,写法如下:

    LOCAL_STATIC_ANDROID_LIBRARIES := \
    androidx.appcompat_appcompat \
    com.google.android.material_material \
    androidx-constraintlayout_constraintlayout \
    lottie-2.8.0   //lottie 第三方aar

    #aapt是Android的打包工具,

    1、–auto-add-overlay意思是当不同文件夹有相同的资源id时,只将第一个资源合并打包进来,
    2、–extra-packages android.support.v7.appcompat,意思是将extra-package包后边的文件包引入到当前代码框架中,就像给当前代码导入一个jar包,但是这里不限jar、library等等,这样引入编译之后就能合并在一起使用

    LOCAL_AAPT_FLAGS := \
    --auto-add-overlay \
    --extra-packages com.airbnb.lottie  //lottie 第三方aar的包名

    #编译APK

    include $(BUILD_PACKAGE)


    延伸定义

    BUILD_HOST_STATIC_LIBRARY 编译静态库(适用与主机)
    BUILD_HOST_SHARED_LIBRARY 编译动态库(适用与主机)
    BUILD_HOST_EXECUTABLE 编译可执行程序(适用与主机)
    BUILD_HOST_PREBUILT 预编译(适用与主机)
    BUILD_HOST_JAVA_LIBRARY 编译java包(适用与主机)
    BUILD_JAVA_LIBRARY 编译java包
    BUILD_STATIC_JAVA_LIBRARY 编译java静态包


    BUILD_STATIC_LIBRARY 编译静态库
    BUILD_SHARED_LIBRARY 编译动态库

    官方解释是这样:
    1、 LOCAL_STATIC_JAVA_LIBRARIES-静态库是在连接阶段直接拷贝到代码 中使用的,BUILD_STATIC_JAVA_LIBRARY指定生成静态库。编译出来的静态库(这里指jar包)里每个java文件对应的class文件都单独存在,可以直接导入Eclipse等IDE使用,
    2、LOCAL_JAVA_LIBRARIES -而共享库是由加载器加载到内存,在运行时使用的。而编译出来的共享库(jar包),内部是Android字节码Dex格式的文件,一般无法导入Eclipse等IDE使用。Android.mk中由BUILD _ JAVA _ LIBRARY指定生成共享库
    
    
    静态库和动态库本质上没有区别,可能就是说静态库是编译时期就把jar包中的代码整合到项目中了,动态库就是说在程序运行期,把jar包加载到内存中,每次使用再继续重新加载到内存


    BUILD_EXECUTABLE 编译可执行程序
    BUILD_PACKAGE 编译apk  ---- 需要有源码文件的app模块
    BUILD_PREBUILT 预编译(针对单个预编译文件)  
    BUILD_MULTI_PREBUILT 预编译(针对多个预编译文件)
     

    #Android.mk 文件结尾,make文件最后一句话

    include $(call all-makefiles-under,$(LOCAL_PATH))

    更多相关内容
  • 3.Android.mkAndroid.bp中引用Android的第三方(jar、aar、so)、Androidx的类库等的使用方法 4.Android.mkAndroid.bp编译生成Apk、静态库、动态库、可执行文件等的使用方法 5.Android系统定制有源码App或无源码...
  • Android的妈咪谷歌当然也考虑到了,从Android.mk切换到Android,mk需要一定的时间,从而为我们精心开发了一个工具androidmk,但是这个工具不是很完善,对于一些Android.mk中的宏开关就无从处理了。本篇今天就带领大伙...
  • Android开发之Android.mk模板的实例详解 关于Android NDK开发的文章已经比较多了,我的博客中也分享了很多NDK开发相关经验和技巧,今天简单写了一个 Android.mk 的示例模板,供初学者参考。  本模板主要给大家示例 ...
  • 主要介绍了Android.mk引入第三方jar包和so库文件的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
  • Android.mk

    2016-02-26 18:31:02
    android编译系统的makefile文件Android.mk写法如下 (1) Android.mk文件首先需要指定LOCAL_PATH变量,用于查找源文件。由于一般情况下 Android.mk和需要编译的源文件在同一目录下,宏函数“my-dir”右编译系统提供的...
  • android studio 配置gradle 使用android.mk进行编译jni,简单的jni调用,使用android.mk进行编译,注意事项:app下的gradle,以及编译生成的 .h文件,复制修改为 .cpp时,里面的文件的宏逻辑,最好去掉这个宏(#...
  • 浅析Android.mk

    2021-01-04 02:23:01
    Android.mk简介: Android.mk文件用来告知NDK Build 系统关于Source的信息。 Android.mk将是GNU Makefile的一部分,且将被Build System解析一次或多次。 所以,请尽量少的在Android.mk中声明变量,也不要假定任何...
  • 有个编译好的第三方apk,合入到系统中,在packages\apps目录创建文件夹wukong,将第三方wukong.apk拷贝到wukong文件夹下,并在wukong文件夹创建Android.mk
  • Android.mk文件添加调试打印信息 前言    你是否有过这么一个需求,就是Android的编译环境是由无数个Android.mk文件和其它类型mk文件组成的,为了方便调试你有时候是否想打印某些的变量。那么本篇文章就是带领...
  • 生成android.mk文件

    2015-10-09 11:00:53
    自动生成android.mk文件,方便,快捷
  • Android.mk 转换为 Android.bp

    千次阅读 2021-10-27 15:11:48
    Android.mk文件是GNU Makefile的一小部分,它用来对Android程序进行编译。因为所有的编译文件都在同一个 GNU MAKE 执行环境中进行执行,而Android.mk中所有的变量都是全局的。 Soong是 Android 的构建系统,旨在替代...

    Android.mk文件是GNU Makefile的一小部分,它用来对Android程序进行编译。因为所有的编译文件都在同一个 GNU MAKE 执行环境中进行执行,而Android.mk中所有的变量都是全局的。

    Soong是 Android 的构建系统,旨在替代旧的 make-based build system ,Soong读Android.bp文件,它们以类似 Bazel 的语法定义模块。Soong 本身是在 Blueprint 之上用 Go 编写的框架,反过来使用 Ninja作为后端。 Ninja 旨在提高效率,尤其是对于增量构建。

    因为Android是个大项目,搬家到Soong/Android.bp需要一些时间。在过渡期间,两种格式都支持,Soong为Android.bp , 和 Kati为 Android.mk .标准构建将同时运行两者。 Android.mk 中的模块文件可以依赖于 Android.bp 中的模块文件,但不是其他方式。

    Android.bp的重要区别是缺乏显式的 if 语句来提高性能。而Android.mk文件可以包含 ifeq检查任意环境变量,Android.bp格式只允许区分预定义的情况,例如处理器架构或调试/发布版本 ( reference )。自定义大小写区别必须在 Go ( reference ) 中单独定义。

    因设计差异,Android.mk自动转换至 Android.bp不可行,尽管有一个名为 androidmk 的工具可以简单翻译Android.mk文件(例如没有 if 语句)到 Android.bp ,有一些androidmk 工具无法转换的语句,可以学习bp的命令。

    androidmk工具使用方法

    1. cd out/soong/host/linux-x86/bin/androidmk
    2. androidmk [flags] <inputFile>
    
    注:androidmk parses <inputFile> as an Android.mk file and attempts to output an analogous Android.bp file (to standard out)
    

    android.mk与android.bp变量对应关系

    build/soong/androidmk/androidmk/android.go

    func init() {
    	addStandardProperties(bpparser.StringType,
    		map[string]string{
    			"LOCAL_MODULE":                  "name",
    			"LOCAL_CXX_STL":                 "stl",
    			"LOCAL_MULTILIB":                "compile_multilib",
    			"LOCAL_ARM_MODE_HACK":           "instruction_set",
    			"LOCAL_SDK_VERSION":             "sdk_version",
    			"LOCAL_MIN_SDK_VERSION":         "min_sdk_version",
    			"LOCAL_NDK_STL_VARIANT":         "stl",
    			"LOCAL_JAR_MANIFEST":            "manifest",
    			"LOCAL_CERTIFICATE":             "certificate",
    			"LOCAL_PACKAGE_NAME":            "name",
    			"LOCAL_MODULE_RELATIVE_PATH":    "relative_install_path",
    			"LOCAL_PROTOC_OPTIMIZE_TYPE":    "proto.type",
    			"LOCAL_MODULE_OWNER":            "owner",
    			"LOCAL_RENDERSCRIPT_TARGET_API": "renderscript.target_api",
    			"LOCAL_NOTICE_FILE":             "notice",
    			"LOCAL_JAVA_LANGUAGE_VERSION":   "java_version",
    			"LOCAL_INSTRUMENTATION_FOR":     "instrumentation_for",
    			"LOCAL_MANIFEST_FILE":           "manifest",
    
    			"LOCAL_DEX_PREOPT_PROFILE_CLASS_LISTING": "dex_preopt.profile",
    			"LOCAL_TEST_CONFIG":                      "test_config",
    		})
    	addStandardProperties(bpparser.ListType,
    		map[string]string{
    			"LOCAL_SRC_FILES":                     "srcs",
    			"LOCAL_SRC_FILES_EXCLUDE":             "exclude_srcs",
    			"LOCAL_HEADER_LIBRARIES":              "header_libs",
    			"LOCAL_SHARED_LIBRARIES":              "shared_libs",
    			"LOCAL_STATIC_LIBRARIES":              "static_libs",
    			"LOCAL_WHOLE_STATIC_LIBRARIES":        "whole_static_libs",
    			"LOCAL_SYSTEM_SHARED_LIBRARIES":       "system_shared_libs",
    			"LOCAL_ASFLAGS":                       "asflags",
    			"LOCAL_CLANG_ASFLAGS":                 "clang_asflags",
    			"LOCAL_COMPATIBILITY_SUPPORT_FILES":   "data",
    			"LOCAL_CONLYFLAGS":                    "conlyflags",
    			"LOCAL_CPPFLAGS":                      "cppflags",
    			"LOCAL_REQUIRED_MODULES":              "required",
    			"LOCAL_HOST_REQUIRED_MODULES":         "host_required",
    			"LOCAL_TARGET_REQUIRED_MODULES":       "target_required",
    			"LOCAL_OVERRIDES_MODULES":             "overrides",
    			"LOCAL_LDLIBS":                        "host_ldlibs",
    			"LOCAL_CLANG_CFLAGS":                  "clang_cflags",
    			"LOCAL_YACCFLAGS":                     "yacc.flags",
    			"LOCAL_SANITIZE_RECOVER":              "sanitize.recover",
    			"LOCAL_LOGTAGS_FILES":                 "logtags",
    			"LOCAL_EXPORT_HEADER_LIBRARY_HEADERS": "export_header_lib_headers",
    			"LOCAL_EXPORT_SHARED_LIBRARY_HEADERS": "export_shared_lib_headers",
    			"LOCAL_EXPORT_STATIC_LIBRARY_HEADERS": "export_static_lib_headers",
    			"LOCAL_INIT_RC":                       "init_rc",
    			"LOCAL_VINTF_FRAGMENTS":               "vintf_fragments",
    			"LOCAL_TIDY_FLAGS":                    "tidy_flags",
    			// TODO: This is comma-separated, not space-separated
    			"LOCAL_TIDY_CHECKS":           "tidy_checks",
    			"LOCAL_RENDERSCRIPT_INCLUDES": "renderscript.include_dirs",
    			"LOCAL_RENDERSCRIPT_FLAGS":    "renderscript.flags",
    
    			"LOCAL_JAVA_RESOURCE_DIRS":    "java_resource_dirs",
    			"LOCAL_JAVA_RESOURCE_FILES":   "java_resources",
    			"LOCAL_JAVACFLAGS":            "javacflags",
    			"LOCAL_ERROR_PRONE_FLAGS":     "errorprone.javacflags",
    			"LOCAL_DX_FLAGS":              "dxflags",
    			"LOCAL_JAVA_LIBRARIES":        "libs",
    			"LOCAL_STATIC_JAVA_LIBRARIES": "static_libs",
    			"LOCAL_JNI_SHARED_LIBRARIES":  "jni_libs",
    			"LOCAL_AAPT_FLAGS":            "aaptflags",
    			"LOCAL_PACKAGE_SPLITS":        "package_splits",
    			"LOCAL_COMPATIBILITY_SUITE":   "test_suites",
    			"LOCAL_OVERRIDES_PACKAGES":    "overrides",
    
    			"LOCAL_ANNOTATION_PROCESSORS": "plugins",
    
    			"LOCAL_PROGUARD_FLAGS":      "optimize.proguard_flags",
    			"LOCAL_PROGUARD_FLAG_FILES": "optimize.proguard_flags_files",
    
    			// These will be rewritten to libs/static_libs by bpfix, after their presence is used to convert
    			// java_library_static to android_library.
    			"LOCAL_SHARED_ANDROID_LIBRARIES": "android_libs",
    			"LOCAL_STATIC_ANDROID_LIBRARIES": "android_static_libs",
    			"LOCAL_ADDITIONAL_CERTIFICATES":  "additional_certificates",
    
    			// Jacoco filters:
    			"LOCAL_JACK_COVERAGE_INCLUDE_FILTER": "jacoco.include_filter",
    			"LOCAL_JACK_COVERAGE_EXCLUDE_FILTER": "jacoco.exclude_filter",
    
    			"LOCAL_FULL_LIBS_MANIFEST_FILES": "additional_manifests",
    		})
    
    	addStandardProperties(bpparser.BoolType,
    		map[string]string{
    			// Bool properties
    			"LOCAL_IS_HOST_MODULE":             "host",
    			"LOCAL_CLANG":                      "clang",
    			"LOCAL_FORCE_STATIC_EXECUTABLE":    "static_executable",
    			"LOCAL_NATIVE_COVERAGE":            "native_coverage",
    			"LOCAL_NO_CRT":                     "nocrt",
    			"LOCAL_ALLOW_UNDEFINED_SYMBOLS":    "allow_undefined_symbols",
    			"LOCAL_RTTI_FLAG":                  "rtti",
    			"LOCAL_PACK_MODULE_RELOCATIONS":    "pack_relocations",
    			"LOCAL_TIDY":                       "tidy",
    			"LOCAL_USE_CLANG_LLD":              "use_clang_lld",
    			"LOCAL_PROPRIETARY_MODULE":         "proprietary",
    			"LOCAL_VENDOR_MODULE":              "vendor",
    			"LOCAL_ODM_MODULE":                 "device_specific",
    			"LOCAL_PRODUCT_MODULE":             "product_specific",
    			"LOCAL_SYSTEM_EXT_MODULE":          "system_ext_specific",
    			"LOCAL_EXPORT_PACKAGE_RESOURCES":   "export_package_resources",
    			"LOCAL_PRIVILEGED_MODULE":          "privileged",
    			"LOCAL_AAPT_INCLUDE_ALL_RESOURCES": "aapt_include_all_resources",
    			"LOCAL_DONT_MERGE_MANIFESTS":       "dont_merge_manifests",
    			"LOCAL_USE_EMBEDDED_NATIVE_LIBS":   "use_embedded_native_libs",
    			"LOCAL_USE_EMBEDDED_DEX":           "use_embedded_dex",
    
    			"LOCAL_DEX_PREOPT":                  "dex_preopt.enabled",
    			"LOCAL_DEX_PREOPT_APP_IMAGE":        "dex_preopt.app_image",
    			"LOCAL_DEX_PREOPT_GENERATE_PROFILE": "dex_preopt.profile_guided",
    
    			"LOCAL_PRIVATE_PLATFORM_APIS": "platform_apis",
    			"LOCAL_JETIFIER_ENABLED":      "jetifier",
    		})
    }
    
    展开全文
  • 该脚本支持根据APK自动生成Android.mk和解压缩库,方便APK预制,支持armeabi,armeabi-v7a,arm64-v8a
  • Android.mk语法详解

    千次阅读 2021-12-26 19:08:44
    目前 Android 工程可以通过 mk、或者 cmake 的形式构建 NDK 工程,较新的 Android 工程一般采用的是 .cmake 构建 NDK 源码,而相对创建时间久的工程则大多数采用的是 .mk 的形式构建。文章主要是通过解析 Android ...

    前言

    目前 Android 工程可以通过 .mk、或者 .cmake 的形式构建 NDK 工程,较新的 Android 工程一般采用的是 .cmake 构建 NDK 源码,而相对创建时间久的工程则大多数采用的是 .mk 的形式构建。下文主要是通过解析 Android 源码里的 docs 文档来深入了解 .mk 语法,其中会对原文里面一些描述通过实际工程加以描述。(原文以及演示的工程的链接将会在文章末尾给出)

    MK 语法概述

    一个 Android.mk 文件是用来描述 Android 的工程源码如何被构建系统所构建。进一步来说:

    • Android.mk 文件是一种会被构建系统解析一次或多次以上的 GUN Makefile 片段。.mk 语法允许构建工程的 module 源文件,每个 module 可以在 Android.mk 中被声明为下面的其中一种库:

      • 静态库(a static library)
      • 动态库(a shared library)

      只有动态库会被拷贝进项目工程,而静态库则是产生动态库的中间产物。在项目工程中,可以定义一个或多个 moduleAndroid.mk 文件中,或者可以使用同一份源码(.c / .cpp)在多个 module 内。

    • 构建系统会自动地为 .mk 工程处理细节问题。例如,我们不需要在 Android.mk 文件中列出源码的头文件,或者定义生成库的需要使用到的中间文件,NDK 构建工程会自动地为我们完成这些细节任务。同时新版本的 NDK toolchain / platform 支持向下兼容 Android.mk 语法。

    NDK工程image-20211219210440455

    对上图的解析说明:

    • src 文件中包含着 Java 源文件、jni 目录。jni 目录下包含着 .cpp / .mk ;

    • jni/Android.mk 描述如何把 hello_mk.cpp 等文件构建成一个动态库,其内容如下:

      LOCAL_PATH := $(call my-dir)
      include $(CLEAR_VARS)
      
      LOCAL_MODULE := hello_mk
      LOCAL_SRC_FILES := hello_mk.cpp
      
      include $(BUILD_SHARED_LIBRARY)
      

      在工程 app 下的 build.gradle 文件下对 Android.mk / Appplication.mk 文件位置的声明一般有两种方式:
      方式一:

      android {
          ...
          task ndkBuild(type:Exec,description:'NDK Project'){
              commandLine "C:\\Users\\iroot\\AppData\\Local\\Android\\Sdk\\ndk\\16.1.4479499\\ndk-build.cmd",//配置ndk的路径
                  'NDK_PROJECT_PATH=build/intermediates/ndk',       // ndk默认的生成so的文件路径
                  'NDK_LIBS_OUT=src/main/jniLibs',                  // 配置的我们想要生成的so文件所在的位置
                  'APP_BUILD_SCRIPT=src/main/jni/Android.mk',       // 指定项目的 Android.mk 所在位置
                  'NDK_APPLOCATION_MK=src/main/jni/Application.mk'  // 指定项目的 Applicaiton.mk 所在位置
          }
      
          tasks.withType(JavaCompile){   //使用ndkBuild
              compileTask ->compileTask.dependsOn ndkBuild
          }
      }
      

      方式二:(方式二需要工程的 setting.gradle 文件配合声明 NDK 的所在位置)

      android {
          ...
          defaultConfig {
              ...
              externalNativeBuild {
                  ndkBuild {
                      arguments 'NDK_APPLICATION_MK:=src/main/jni/Application.mk'
                      cFlags ''
                      cppFlags ''
                      abiFilters 'arm64-v8a, armeabi-v7a, x86, x86_64'
                  }
              }
          }
      
          externalNativeBuild {
              ndkBuild {
                  path 'src/main/jni/Android.mk'
              }
          }
      }
      

    MK 语法详解(一)

    LOCAL_PATH := $(call my-dir)
    

    解析:每个 Android.mk 文件必须在文件头部最开始处定义 LOCAL_PATH 变量,该变量用来获取工程中的文件节点。在上述工程图中,通过构建系统提供的函数 my-dir 获取 Android.mk 当前的所在的目录节点。

    include $(CLEAR_VARS)
    

    解析:CLEAR_VARS 变量是构建系统提供,同时指向一个特殊的 GNU Makefile,主要是用来清除如 LOCAL_XXX 所定义的变量(e.g. LOCAL_MODULE, LOCAL_SRC_FILES, LOCAL_STATIC_LIBRARIES, etc...)、以及 LOCAL_PATH 环境中的异常(CLEAR_VARS 可简单理解为初始化环境)。include $(CLEAR_VARS) 声明是必须的,因为 Android.mk 在第一次被解析的时候,变量被初始化为为知的值(这里个人理解为类似 C 中的数据定义未初始化,被其值被系统赋值为垃圾值)。

    LOCAL_MODULE := hello_mk
    

    解析:LOCAL_MODULE 变量是用来声明需要被生成的 module 名称。该定义的名称在整个工程中必须是唯一的,同时在构建的时候,系统会自动为该 module 名称补全前缀、以及后缀。也就是说,上文定义的动态库名称 hello_mk 最后被补全为 libhello_mk.so。当然,如果我们使用 LOCAL_MODULE := libhello_mk 声明的时候,系统则不会为其添加前缀。

    LOCAL_SRC_FILES := hello-jni.c
    

    解析:变量 LOCAL_SRC_FILES 是用来定义将要生成的目标动态库所需要的源码文件列表,如 c 或者 c++ 文件。但我们不要把头文件或者被 include 的文件也定义到该变量列表中,因为这些构建系统已经自动地帮我们完成这些任务。

    include $(BUILD_SHARED_LIBRARY)
    

    解析:变量 BUILD_SHARED_LIBRARY 被定义后,GNU Makefile 脚本就会负责把 include $(BUILD_SHARED_LIBRARY) 往上定义的如 LOCAL_XXX 变量都收集起来,直到离 include $(BUILD_SHARED_LIBRARY) 最近的定义的 include $(CLEAR_VARS) 为止。可简单理解为 [include $(CLEAR_VARS) ... include $(BUILD_SHARED_LIBRARY)] 之间的 LOCAL_XXX 的变量将决定如何生成一个动态库。当然,BUILD_STATIC_LIBRARY 变量是用来声明定义生成静态库。

    自定义变量

    构建系统会提供一系列的 .mk 变量供我们使用,当然我们也可以在我们工程需要的时候自定义某些变量。但需要注意不能与构建系统保留的变量名发生冲突:

    • LOCAL_ 开头的变量名;(如 LOCAL_MODULE
    • PRIVATE_NDK_APP_ 开头的变量名;(这些开头的变量名称被用以系统内部)
    • lower-case 名称;(用以系统内部,如 my-dir

    如果我们需要自定义变量,官方推荐我们使用 MY_ 前缀开头的变量,避免与系统变量发生冲突。例子如下:

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

    MK 语法详解(二)

    在上文我们了解了 CLEAR_VARSBUILD_SHARED_LIBRARYBUILD_STATIC_LIBRARY 这几个变量。构建系统还提供了其他种类的变量供我们在 mk 文件中使用,下面我们来一一认识了解它们吧。

    NDK提供的变量

    PREBUILT_SHARED_LIBRARY

    该变量用来指定一个需要被依赖进工程的动态库。与 BUILD_SHARED_LIBRARYBUILD_STATIC_LIBRARY 不同的是,该变量对应的 LOCAL_SRC_FILES 必须被初始化为一个需要被纳入到工程的动态库路径,而不是源码文件。NDK Prebuilt library support 参考资料

    使用方式 (这里不做解析,感兴趣可以查看提供的 NDK Prebuilt library support 参考资料):

    include $(CLEAR_VARS)
    LOCAL_MODULE := foo-prebuilt
    LOCAL_SRC_FILES := libfoo.so
    LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include  #导出libfoo.so的头文件
    include $(PREBUILT_SHARED_LIBRARY)
    
    include $(CLEAR_VARS)
    LOCAL_MODULE := foo-user
    LOCAL_SRC_FILES := foo-user.c
    LOCAL_SHARED_LIBRARY := foo-prebuilt
    include $(BUILD_SHARED_LIBRARY)
    

    PREBUILT_STATIC_LIBRARY

    作用和 PREBUILT_SHARED_LIBRARY 类似,只是该初始化的为静态库路径。

    TARGET_ARCH

    指定程序运行的目标 CPU 架构指令集的名称;

    TARGET_PLATFORM

    指定 Android.mk 文件将被哪一个 Android 版本解析。例如,'android-3' 对应于 Android 1.5 系统镜像。

    TARGET_ARCH_ABI

    目标 CPU+ABI 被 Android.mk 解析。

    部分举例:

    armeabi => when targetting ARMv5TE or higher CPUs
    armeabi-v7a => when targetting ARMv7 or higher CPUs
    x86 => when targetting x86 CPUs

    同时 armeabi-v7a 系统可以兼容 armeabi 二进制文件。

    代码例子:

    include $(CLEAR_VARS)
    LOCAL_MODULE := foo-prebuilt
    LOCAL_SRC_FILES := $(TARGET_ARCH_ABI)/libfoo.so
    LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
    include $(PREBUILT_SHARED_LIBRARY)
    

    同时假设上述代码目录结构如下:

    Android.mk --> the file above

    armeabi/libfoo.so --> the armeabi prebuilt shared library

    armeabi-v7a/libfoo.so --> the armeabi-v7a prebuilt shared library

    include/foo.h --> the exported header file

    TARGET_ABI

    TARGET_PLATFORMTARGET_ARCH_ABI 变量类似,变量 TARGET_ABI 在我们需要测试某一块真机的系统镜像的时候会非常有用。默认值为 android-3-armeabi。(升级 Android NDK 1.6_r1,将会默认使用 android-3-arm

    函数宏

    接下来将要描述的是 GUN Make 函数宏(function macros),函数宏返回的是文本信息(可以理解为字符串),使用的格式如:$(call &lt;function&gt;)

    my-dir

    在上文我们提到构建系统提供的函数 my-dir :返回最近导入的 Makefile 的路径,在 NDK 中一般为 Android.mk 当前的目录节点路径。这里我们再展开解析该函数在使用中需要注意的点。

    $(call my-dir) 变量获取的是最新导入的 Makefile 路径,也就意味着,当 include 新的文件路径进来以后,$(call my-dir) 返回的是该新的文件路径。如下源码一:

    源码一

    LOCAL_PATH := $(call my-dir)
    ... declare one module
    include $(LOCAL_PATH)/foo/Android.mk
    LOCAL_PATH := $(call my-dir)
    ... declare another module
    

    例子一存在二次调用 $(call my-dir) ,第二次调用返回的将是 $(LOCAL_PATH)/foo 而不是 $PATH。因此,比较好的写法做法是把将要新增的 Android.mk 文件放在文件末尾,如下源码二:

    源码二

    LOCAL_PATH := $(call my-dir)
    ... declare one module
    LOCAL_PATH := $(call my-dir)
    ... declare another module
    # extra includes at the end of the Android.mk
    include $(LOCAL_PATH)/foo/Android.mk
    

    但源码二给出形式还不是最好的,如当最后需要 include 多个 Android.mk 呢?最好的写法是把第一次获取到的 $(call my-dir) 获取到的值预先保存在另一个变量:

    源码三

    MY_LOCAL_PATH := $(call my-dir)
    LOCAL_PATH := $(MY_LOCAL_PATH)
    ... declare one module
    include $(LOCAL_PATH)/foo/Android.mk
    LOCAL_PATH := $(MY_LOCAL_PATH)
    ... declare another module
    

    all-subdir-makefiles

    该变量返回当前包含 Android.mkmy-dir 路径,以及子目录中含有 Android.mk 的路径。例如:

    sources/foo/Android.mk
    sources/foo/lib1/Android.mk
    sources/foo/lib2/Android.mk
    

    如果在 sources/foo/Android.mk 文件中含有 include $(call all-subdir-makefiles) ,则将会自动地 include 文件 sources/foo/lib1/Android.mksources/foo/lib2/Android.mk 。默认地,NDK 只会遍历查找 sources/*/Android.mk 格式地目录下的 Android.mk

    this-makefile

    返回当前的 Makefile 文件所在文件夹的路径。

    parent-makefile

    返回当前 Makefile 文件位于相对文件树节点的父 Makefile 路径。

    grand-parent-makefile

    import-module

    该函数允许我们通过 module 的名字导入另一个 module,同时自动地导入该 moduleAndroid.mk 文件。但该 module 需要在 NDK_MODULE_PATH 该变量中声明。代码如下例子:

    $(call import-module,&lt;name&gt;)
    

    Module描述变量

    接下来解析的变量是用来描述我们的 module 将要如何被构建系统所构建。

    LOCAL_PATH

    该变量被赋值为当前文件的路径。我们必须把它定义在 Android.mk 文件中开头的地方。同时该变量是不会被 $(CLEAR_VARS) 函数所清除,所以我们需要为每个需要的 Android.mk 定义路径(如在单一个 Android.mk 文件中导入多个 module)。写法如下:

    LOCAL_PATH := $(call my-dir)
    

    LOCAL_MODULE

    用来声明我们 module 的名称。声明的 module 的名称必须在该工程内是唯一的,该名称不可以包含任何的空格,同时需要声明在任何的 $(BUILD_XXXX) 变量前。该 module 的名称默认是生成文件的名称,如 module 的名称为 foo,则生成的静态库的文件名为 libfoo.a,或者生成静态库的文件名为 linfoo.so

    LOCAL_MODULE_FILENAME

    这是个可选的变量,用来重载 LOCAL_MODULE 定义的名称。写法如下:

    LOCAL_MODULE := foo-version-1
    LOCAL_MODULE_FILENAME := libfoo
    

    需要注意的是,我们不可以把路径名或者文件的后缀名称定义在 LOCAL_MODULE_FILENAME

    LOCAL_SRC_FILES

    该变量用来声明构建生成目标文件(静态 / 动态 / 可执行文件)所需要的源文件(C / C++),只有定义在该变量的源文件才会被编译进目标文件,同时构建系统会自动地为源码文件处理头文件导入这些细节操作。

    因为源码文件的路径已经在声明 LOCAL_PATH 的时候已经导入进环境,因此我们只需要补充源码文件具体的目录位置即可。写法如下:

    LOCAL_SRC_FILES := foo.c \
                       toto/bar.c
    

    LOCAL_CPP_EXTENSION

    该变量用来声明 C++ 的文件扩展后缀名称。我们可以更改默认的后缀(.cpp)名称声明。例子如下:

    LOCAL_CPP_EXTENSION := .cxx
    

    LOCAL_C_INCLUDES

    相对于 NDK 的根目录路径,该变量定义编译源码时会被追加到导入搜索路径。如下例子:

    LOCAL_C_INCLUDES := sources/foo
    

    或者:

    LOCAL_C_INCLUDES := $(LOCAL_PATH)/../foo
    

    LOCAL_C_INCLUDES 生效的时机是在 LOCAL_CFLAGS / LOCAL_CPPFLAGS 变量之前。同时,LOCAL_C_INCLUDES 路径在进行 native 层的调试的时候会被使用到。

    LOCAL_CFLAGS

    该变量声明的值会在构建 CC++ 源码文件的时候给编译器设置编译参数,是一个可选的变量。这对于指定宏定义或者编译选项是非常有帮助的。

    同时官方推荐不要尝试去调整优化选项、或者调试等级在我们的 Android.mk 文件,这些会通过 Application.mk 指定相关的信息为我们自动地处理,同时让 NDK 在调试的时候为我们生成有用的调试信息。

    android-ndk-1.5_r1 的 NDK 版本,相对应的 LOCAL_CFLAGS 定义只针对 C 文件起效,而 C++ 则需要通过设置 LOCAL_CPPFLAGS 变量指定。

    通过 LOCAL_CFLAGS 也可以像 LOCAL_C_INCLUDES 指定导入的源码文件路径,但推荐使用 LOCAL_C_INCLUDES 变量,因为后者会在 native 层调试的时候也需要使用到。

    LOCAL_CXXFLAGS

    LOCAL_CXXFLAGS 变量是 LOCAL_CPPFLAGS 的别名。但该变量可能在新的 NDK 版本中不再被支持。

    LOCAL_CPPFLAGS

    该变量会被拼接在 LOCAL_CFLAGS 变量之后,同时只对 C++ 源文件生效。

    LOCAL_STATIC_LIBRARIES

    LOCAL_STATIC_LIBRARIES 变量将被被链接进 module 里面的静态库列表,而这些静态库是通过 BUILD_STATIC_LIBRARY 定义构建的。

    LOCAL_SHARED_LIBRARIES

    作用与 LOCAL_STATIC_LIBRARIES 相同,只是定义的是动态库列表。

    LOCAL_LDLIBS

    LOCAL_LDLIBS 用于指定系统库通过 -l 前缀,指定的系统库将在编译的时候加载进我们目标 module。例如:

    LOCAL_LDLIBS := -lz
    

    通过指定 -lz 参数,编译器会加载 /system/lib/libz.so 进我们目标生成的 module。(参考 docs/STABLE-APIS.html

    LOCAL_ALLOW_UNDEFINED_SYMBOLS

    在编译生成动态库的时候,构建系统回去检测源码中是否存在 undefined symbol 的错误,这一行为有利于帮助我们提前发现代码中的 Bug。但实际中,我们总会遇到某些原因让我们不得不关闭该检测行为,当 LOCAL_ALLOW_UNDEFINED_SYMBOLS := true 会关闭对 undefined symbol 的检查。但带来的风险是在加载动态库时会使得程序发生崩溃。

    LOCAL_ARM_MODE

    默认条件下,ARM 目标二进制文件将会在 thumb 模式下生成,同时在该模式下生成的每条指令都是 16 位的。我们可以通过该变量指定在 arm 模式下生成我们的目标文件,也就是说此时的目标文件的指令宽是 32 位的。写法如下:

    LOCAL_ARM_MODE := arm
    

    在生成指定的目标文件的过程中,我们还可以通过指定某个源码文件按照我们需要的方式构建,如:

    LOCAL_SRC_FILES := foo.c bar.c.arm
    

    通过在源码文件名称后面后添加 .arm 可以指定在编译的时候,该文件以 arm 模式构建。

    同时,在 Application.mk 文件通过 APP_OPTIM := debug 定义的方式同样可以生成 ARM 目标二进制文件。在官方文档中指出这是因为由于工具链调试器在处理 thumb 指令有 bug

    LOCAL_ARM_NEON

    当该变量被设为 true 的时允许我们使用 ARM Advanced SIMD (又名 NEON)、以及 GCC 内敛函数在我们的 CC++ 代码中、同时允许 NEON 汇编出现在汇编文件中。

    我们只允许指定 ARMv7 汇编指令集在对应架构 armeabi-v7a ABI 中。但并非所有的基于 ARMv7 架构的 CPU 都支持 NEON 扩展指令集,这需要我们执行运行检测才可以发现是否 NEON 指令可以安全运行。如 LOCAL_ARM_MODE 可以在运行时指定特定文件可以支持 arm 模式进行编译,LOCAL_ARM_NEON 指令同样也可以通过指定某特定的文件追加 .neon 后缀,来支持 NEON 扩展指令集。写法如下:

    LOCAL_SRC_FILES = foo.c.neon \
    				  bar.c \
    				  zoo.c.arm.neon
    

    在上面的例子中,foo.c 文件将以 thumb+neon 模式编译、bar.c 文件将以 thumb 模式编译、zoo.c 将以 arm + neon 模式编译。需要注意的是,如果某个文件同时需要以 armneon 模式编译,那么 .neon 后缀必须跟在 .arm 后面。

    LOCAL_DISABLE_NO_EXECUTE

    Android NDK r4 版本新增对 NX bit 的安全特性的支持。该特性被默认支持,我们可以通过该变量设置 LOCAL_DISABLE_NO_EXECUTE := true 来关闭该特性。

    关于 NX 特性可以参考:

    • http://en.wikipedia.org/wiki/NX_bit
    • http://www.gentoo.org/proj/en/hardened/gnu-stack.xml

    LOCAL_EXPORT_CFLAGS

    LOCAL_EXPORT_CFLAGS 定义了一组 C / C++ 编译器参数,当其他模块以LOCAL_STATIC_LIBRARIES / LOCAL_SHARED_LIBRARIES 方式引用该模块时,就会将该组值加入到 LOCAL_CFLAGS,从而传递给编译器。如下例子:

    代码片段一:

    include $(CLEAR_VARS)
    LOCAL_MODULE := foo
    LOCAL_SRC_FILES := foo/foo.c
    LOCAL_EXPORT_CFLAGS := -DFOO=1
    include $(BUILD_STATIC_LIBRARY)
    

    代码片段二:

    include $(CLEAR_VARS)
    LOCAL_MODULE := bar
    LOCAL_SRC_FILES := bar.c
    LOCAL_CFLAGS := -DBAR=2
    LOCAL_STATIC_LIBRARIES := foo
    include $(BUILD_SHARED_LIBRARY)
    

    在代码片段一种,我们通过 foo/foo.c 构建目标静态库 foo,同时 LOCAL_EXPORT_CFLAGS := -DFOO=1。在代码片段二中,我们通过 bar.c 构建动态库 bar,这时候 -DFOO=1 -DBAR=2 会传递给编译器以用来构建动态库 bar

    LOCAL_EXPORT_CFLAGS 定义的 flags 是可以被继承的。假设 zoo 依赖 bar,而 bar 依赖 foo,那么 zoo 也会继承来自 foo 中导出的 flags。在上述代码片段中,定义的 LOCAL_EXPORT_CFLAGS 对于构建本模块是不生效的,如上述例子中,构建 foo 时声明的 LOCAL_EXPORT_CFLAGS := -DFOO=1 不会传给编译器。

    LOCAL_EXPORT_CPPFLAGS

    作用和 LOCAL_EXPORT_CFLAGS 相同,但作用于 C++ 文件。

    LOCAL_EXPORT_C_INCLUDES

    作用和 LOCAL_EXPORT_CFLAGS 相同,但只是针对 C 导入的路径。当 bar.c 需要 foo 模块提供的头文件的时候,该定义会很有帮助。

    LOCAL_EXPORT_LDLIBS

    LOCAL_EXPORT_CFLAGS 相同,但针对的是链接器 flags。由于 Unix 的链接器工作的方式,导入的链接器 flags 将会被追加到我们 moduleLOCAL_LDLIBS 变量处。

    include $(CLEAR_VARS)
    LOCAL_MODULE := foo
    LOCAL_SRC_FILES := foo/foo.c
    LOCAL_EXPORT_LDLIBS := -llog
    include $(BUILD_STATIC_LIBRARY)
    
    include $(CLEAR_VARS)
    LOCAL_MODULE := bar
    LOCAL_SRC_FILES := bar.c
    LOCAL_STATIC_LIBRARIES := foo
    include $(BUILD_SHARED_LIBRARY)
    

    在上述例子中,foo 是静态库,并且依赖系统库。同时 LOCAL_EXPORT_LDLIBS 定义用于导出依赖。当在编译器构建 bar 的时候,将会把 -llog (表示依赖系统的 日志库)构建进动态库中。

    参考资料

    后言

    Android 原生开发随着 Flutter 的到来,前景开始变得不那么明朗。Android 原生可以实现一般功能,在 Flutter 同样也可以实现,同时 Flutter 一份代码可以实现跨平台运行。可能 Flutter 并不是最终跨平台的最终实现方案,但在一定程度上也给 Android 原生开发带来不小的冲击。

    但随着目前 5G 时代的来临、以及人们普遍开始越来越重视应用安全,如应用隐私安全等。音视频领域、移动安全领域方兴未艾,尤其移动安全领域比较难找到相关的参考学习资料、学习路线,而笔者正深耘 Android 移动安全领域,希望在这学习 Android 移动安全的路上有你一起长风破浪。

    展开全文
  • Android.mk的用法

    千次阅读 2021-06-08 11:14:24
    (1)Android.mk是什么?Android.mkAndroid提供的一种makefile文件。Android.mk其实是把真正的Makefile包装起来,做成了一个对使用者来说很简单的东西。你可以在每一个Android.mk file中定义一个或多个模块。每个...

    (1)Android.mk是什么?

    Android.mk是Android提供的一种makefile文件。Android.mk其实是把真正的Makefile包装起来,做成了一个对使用者来说很简单的东西。

    你可以在每一个Android.mk file中定义一个或多个模块。每个模块属下列类型之一:

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

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

    3)  C\C++应用程序,可执行的C\C++应用程序

    4)C\C++静态库,编译生成C\C++静态库,并打包成.a文件

    5)C\C++共享库, 编译生成共享库(动态链接库),并打包成.so, 有且只有共享库才能被安装/复制到您的应用软件(APK)包中。

    使用它来编译程序时,不管是动态库、可执行的二进制文件,还是Jar库、APK包,只要沿着一个简单的思路来做三大步就可以了:清除旧变量,设置新变量,调用编译函数。

    (2)举例子

    (一)BUILD_SHARED_LIBRARY——动态库

    chris/superuser/su.cchris/superuser/Android.mk相应的Android.mk文件会像下面这样:

    LOCAL_PATH := $(call my-dir)

    include $(CLEAR_VARS)

    LOCAL_MODULE

    := su

    LOCAL_SRC_FILES := su.c

    include $(BUILD_SHARED_LIBRARY)

    1,

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

    2,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, 等等...) 。这是必要的,因为所有的编译控制文件都在同一个GNU MAKE执行环境中,所有的变量都是全局的

    3,LOCAL_MODULE := su,LOCAL_MODULE变量必须定义,以标识你在Android.mk文件中描述的每个模块。名称必须是唯一的。注意编译系统会自动产生合适的前缀和后缀,换句话说,一个被命名为'foo'的共享库模块,将会生成'libfoo.so'文件

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

    5,LOCAL_C_INCLUDES:可选变量,表示头文件的搜索路径。默认的头文件的搜索路径是LOCAL_PATH目录。示例:LOCAL_C_INCLUDES := sources/foo或LOCAL_C_INCLUDES := $(LOCAL_PATH)/../foo

    6,LOCAL_STATIC_LIBRARIES: 表示该模块需要使用哪些静态库,以便在编译时进行链接。

    7,LOCAL_SHARED_LIBRARIES:  表示模块在运行时要依赖的共享库(动态库),在链接时就需要,以便在生成文件时嵌入其相应的信息

    8,include $(call all-subdir-makefiles):返回一个位于当前'my-dir'路径的子目录中的所有Android.mk的列表。

    (二)BUILD_EXECUTABLE——二进制文件

    LOCAL_PATH := $(call my-dir)

    include $(CLEAR_VARS)

    LOCAL_SRC_FILES:= su.c

    LOCAL_MODULE:= su

    #LOCAL_C_INCLUDES :=

    #LOCAL_STATIC_LIBRARIES :=

    #LOCAL_SHARED_LIBRARIES :=

    include $(BUILD_EXECUTABLE)

    (三) BUILD_STATIC_LIBRARY——静态库

    LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_SRC_FILES:= /helloworld.cLOCAL_MODULE:= libtest_static#LOCAL_C_INCLUDES :=#LOCAL_STATIC_LIBRARIES :=#LOCAL_SHARED_LIBRARIES :=include $(BUILD_STATIC_LIBRARY)

    BUILD_STATIC_LIBRARY表示编译一个静态库.a文件。静态库不会复制到的APK包中,但是能够用于编译共享库

    补充:include $(BUILD_PACKAGE)则是编译出一个apk,include $(BUILD_STATIC_JAVA_LIBRARY)则是编译出jar包

    (a)以上三者的生成结果分别在

    out/target/product/generic/obj/EXECUTABLE

    out/target/product/generic/obj/STATIC_LIBRARY

    out/target/product/generic/obj/SHARED_LIBRARY

    (b)每个模块的目标文件夹分别为:

    可执行程序:XXX_intermediates

    静态库:      XXX_static_intermediates

    动态库:      XXX_shared_intermediates

    (c)在Android.mk文件中,还可以指定最后的目标安装路径,用LOCAL_MODULE_PATH和LOCAL_UNSTRIPPED_PATH来指定。不同的文件系统路径用以下的宏进行选择:

    TARGET_ROOT_OUT:表示根文件系统out/target/product/xxxxx/root。

    TARGET_OUT:表示system文件系统out/target/product/xxxx/system。

    TARGET_OUT_DATA:表示data文件系统out/target/product/xxxx/data。

    TARGET_OUT_SHARED_LIBRARIES:表示out/target/product/xxxx/system/lib

    TARGET_OUT_APPS:表示out/target/product/xxxx/system/app

    ANDROID_PRODUCT_OUT:out/target/product/xxxx/

    TARGET_OUT_JAVA_LIBRARIES:out/target/product/xxxx/system/framework

    例如:LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/src

    (3)相关的编译指令

    android源码目录下的build/envsetup.sh文件,描述编译的命令

    - m:       Makes from the top of the tree.

    - mm:      Builds all of the modules in the current directory.

    - mmm:     Builds all of the modules in the supplied directories.

    所以要想使用这些命令,首先需要在android源码根目录执行build/envsetup.sh 脚本设置环境。

    m:编译所有的模块

    mm:编译当前目录下的模块,当前目录下要有Android.mk文件

    mmm:编译指定路径下的模块,指定路径下要有Android.mk文件

    下面举个例子说明,假设我要编译android下的\hardware\libhardware_legacy\power模块,当前目录为源码根目录,方法如下:

    1、. build/envsetup.sh

    2、mmm hardware/libhardware_legacy/power/

    或者 :

    1、. build/envsetup.sh

    2、cd hardware/libhardware_legacy/power/

    3、mm

    实际开发中,并不需要每次都编译所有源代码,只需要编译自己修改的模块即可。Android的编译系统提供了强大的机制支持单独模块的编译,而且十分简单。Android提供三种方式用于编译单独模块:

    make 模块名

    mm (来自于envsetup.sh脚本中注册的函数)

    mmm (来自于envsetup.sh脚本中注册的函数)

    1.make 模块名

    这种方法适合第一次编译,会把依赖模块一并编译。它需要在全部源代码中找到编译模块的Android.mk文件,并检查依赖模块是否有修改,因此编译时间较长。使用这种方法,我们只需要搜索源码目录下的Android.mk文件,找到模块名,然后指定给make即可。

    对于应用层程序,需要查看Android.mk文件的LOCAL_PACKAGE_NAME变量

    例如,要编译Phone应用程序的源码,先查看Phone的Android.mk文件

    ……(省略部分内容)

    LOCAL_PATH:= $(call my-dir)

    include $(CLEAR_VARS)

    LOCAL_MODULE:=com.android.phone.common

    ……(省略部分内容)

    LOCAL_PACKAGE_NAME:=Phone

    ……(省略部分内容)

    得到编译参数后,在终端中运行如下命令便可单独编译Phone模块及其依赖模块:allong@android:~/android/.../***(Android.mk所在目录下编译)$

    make Phone

    2.mmm命令

    该命令是envsetup.sh中注册的函数,用于在源码根目录编译指定模块,参数为模块的相对路径。只能在第一次编译后使用。比如要编译Phone部分源码,需要在终端中执行以下命令:

    allong@android:~/android/jellybean$mmm packages/apps/phone

    3.mm命令

    该命令也是envsetup.sh中注册的函数,用于在模块根目录编译这个模块。只能在第一次编译后使用。例如要编译Phone部分源码,需要在终端中执行以下命令

    注意 mmm和mm命令必须在执行“.build/envsetup.sh”之后才能使用,并且只编译发生变化的文件。

    (4)Android 手工编译C程序的整个过程

    1,先将你要编译的C代码模块 放入已经编译好的android源码目录下

    b66f8e19b8ba2d98da13b844f98e3102.png

    efdb6438aa0d2ecdb8f155faceab9cf3.png

    有些头文件是android源码目录的,可能要在Android.mk中包含进来

    62db97d959589f768c9831c9f8c75b5d.png

    4ca9cebfe6356ad9c5a097d0dbee316b.png

    2,初始化环境(每次编译模块前都要进行初始化环境!在这里耽误了一天时间才知道)

    ade5a1b917e818696299415c4da1abb6.png

    5fe71010fa3115fad62ee7afea716a8b.png

    初始化之后进入你要编译的C模块目录,进行编译,编译成功会有提示

    fa0e7e001e1b0e40a100b7f1c6c0360b.png

    886fa666caa452c44328c3fd966b62f1.png

    3,因为我编译的目标文件为include $(BUILD_EXECUTABLE),编译成功后默认路径为out/target/product/shamu/obj/EXECUTABLES/su(这里是相应的模块名称)_intermediates/su(相应的模块名称),在路径下可找到你的编译结果

    8ac358476a20353aacb6167ae32792ee.png

    展开全文
  • Android.mkAndroid.bp

    2022-01-28 17:45:28
    $ out/soong/host/linux-x86/bin/androidmk Android.mk > Android.bp 编译不同类型的模块 编译成 Native 动态库 Android.mk include $(BUILD_SHARED_LIBRARY) Android.bp cc_library_shared { ...... } ...
  • android.mk

    2014-01-23 16:26:12
    cocos2d-x到android平台的android.mk正确设置,以及实现class中 文件一起编译。
  • 可以参考build\soong\androidmk\androidmk进行查找 "LOCAL_32_BIT_ONLY": local32BitOnly, "LOCAL_AIDL_INCLUDES": localAidlIncludes, "LOCAL_ASSET_DIR": localizePathList("asset_dirs"), "LOCAL_C_INCLUDES...
  • Android.mk生成工具

    热门讨论 2013-01-30 20:10:16
    根据源代码生成Android.mk 和Applicatin.mk
  • 制作了一个全平台通用的Android.mk文件。(MK文件是很容易出错的东西,调试需要花费很长的时间)。需要的同学可以借鉴一下。 使用它了make写法,全平台通用。 LOCAL_C_INCLUDES、LOCAL_SRC_FILES使用技巧。
  • 关于Android平台Android.mk的说明及使用,MTK官方文档,解锁密码是6962843490
  • 源码链接 添加个cpp文件后要Refresh Linked C++ Projects 用gradle-ndk-build: import org.apache.tools.ant.taskdefs.condition...android { compileSdkVersion versionCompiler buildToolsVer...
  • 概述Android.mk这个文件可以放在Android的某一个目录下,就可以使用mm或者其他一些命令来对它进行编译。Android.mk的作用对于 C/C++ 来说,可以编译二进制的可执行文件、静态库、动态库;对于 Java 来说,可以编译...
  • 通过Kati将Android.mk转换成ninja格式的文件,通过Blueprint+ Soong将Android.bp转换成ninja格式的文件,通过androidmk将将Android.mk转换成Android.bp,但针对没有分支、循环等流程控制的Android.mk才有效 ...
  • 匿名用户1级2016-02-02 回答Android.mk文件用来告知NDK Build 系统关于Source的信息。 Android.mk将是GNU Makefile的一部分,且将被Build System解析一次或多次。所以,请尽量少的在Android.mk中声明变量,也不要...
  • Android源码里边提供了快捷直接Android.mk转换成Android.bp的工具:androidmk 二、androidmk的源码和位置 首先让我们从androidmk的框架和源码如下来说起,我们知道Android的最新编译系统的文件架构如下: xxx@...
  • Android.mk 使用详解

    2021-06-03 16:34:07
    和你一起终身学习,这里是程序员Android经典好文推荐,通过阅读本文,您将收获以下知识点:一、Android.mk 简介二、Android.mk 的基本格式三、Android.mk 深入学习一四、 Android.mk 深入学习二五、 Android.mk 深入...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 77,931
精华内容 31,172
关键字:

android.mk

友情链接: hd44780-i2c-master.zip