语法

Android.mk 的必备三行

LOCAL_PATH := $(call my-dir)	# Android.mk的目录,call调用函数include $(CLEAR_VARS)			# 除了LOCAL_PATH清除所有LOCAL_XXXinclude $(BUILD_SHARED_LIBRARY)	# BUILD_XXX, 指定构建类型
# BUILD_SHARED_LIBRARY →  .so动态库
# BUILD_STATIC_LIBRARY →  .a动态库
# BUILD_EXECUTABLE → 生成elf可执行文件
# BUILD_PREBUILT → 使用预编译文件(不编译源码)编译,比如APK
# PREBUILT_SHAREED_LIBRARY →  使用预编译so文件

BUILD_EXECUTABLE 用于编译elf可执行文件,adb shell 可以直接运行;通常在 /system/bin、/vendor/bin(取决于LOCAL_MODULE_PATH);

PREBUILD_SHARED_LIBRARYBUILD_PREBUILT 区别:前者只能处理预编译的共享库,后者可以可以处理任意的预编译产物(apk、jar等等)。二者都是处理已经编译好的文件(不用自己编译)

demo:Android.mk(常见模块类型)

LOCAL_PATH := $(call my-dir)# 模块:
include $(CLEAR_VARS)
LOCAL_MODUEL := mylib		# 模块名(无扩展名)
LOCAL_SRC_FILES := mylib.c main.c	# 源文件
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include  # c头文件
LOCAL_SHARED_LIBRARIES := libfoo libbar	# 自己编译的依赖的so库(工程内的,无扩展名)
LOCAL_STATIC_LIBRARIES := libabc	# 依赖的a库(无扩展名)
LOCAL_PREBUILT_LIBS := prebuilt/libbaz.so # 外界编译好的so库(有扩展名)
LOCAL_LDLIBS := -llog -landroid # 链接时的系统库(NDK常用), liblog.so、libandroid.so
LOCAL_JAVA_LIBRARIES := libabc	# 依赖的jar包(无扩展名)
LOCAL_MODULE_SUFFIEX := .so		# 模块的扩展名
LOCAL_CFLAGS := -DDEBUG=1		# C的编译参数
LOCAL_CPPFLAGS := -std=c++11	# C++的编译参数
LOCAL_MODULE_TAGS := optional	# 是否编译选项,tests、eng、debug(lunch编译模式编译);device.mk优先级更高
LOCAL_MODULE_CLASS := SHARED_LIBRARIES # 编译模块的类型,和默认安装路径system下,lib bin app etc等
# APPS(apk)、SHARED_LIBRARIES(so)、STATIC_LIBRARIES(a)、JAVA_LIBRARIES(Java库)、ETC(放/system/etc)
LOCAL_MODULE_PATH := $(TARGET_OUT)/lib	# 安装路径 /system/bin
# $(TARGET_OUT_VENDOR)/bin → /vendor/bin
# $(TARGET_OUT_DATA)/myapp → /data/myappinclude $(BUILD_SHARED_LIBRARY)

LOCAL_LDLIBSLOCAL_SHARED_LIBRARIES 区别:前者直接-llog 传给链接器,没有建立模块依赖关系,链接器默认搜索路径(假定环境已经有了liblog.so),而且要手动确认,系统不会自动打包这个so库;后者会确保liblog先编译,建立两者的模块依赖关系,自动找到路径(多架构),由编译系统确定正确分区比如system、vendor,并且系统会自动打包so库,最好使用前者

LOCAL_MODULE_CLASSinclude $(BUILD_XXX) 区别:前者说明模块是什么类型,用于默认安装路径;后者是如何把源码做成目标(编译规则)。LOCAL_MODULE_PATH 才真正决定安装路径。

LOCAL_SHARED_LIBRARIESLOCAL_STATIC_LIBRARIES:前者在运行时才会链接此库;后者最终会被打包进此模块。

demo:Android.mk(多模块)

LOCAL_PATH := $(call my-dir)# 模块1: so库
include $(CLEAR_VARS)
LOCAL_MODULE := libfoo
LOCAL_SRC_FILES := foo.c bar.c baz.c
include $(BUILD_SHARED_LIBRARY)# 模块2: 编译为可执行文件
include $(CLEAR_VARS)
LOCAL_MODULE := foo_test
LOCAL_SRC_FILES := test.c
LOCAL_SHARED_LIBRARIES := libfoo
include $(BUILD_EXECUTABLE)

demo2: Android.mk(预编译库)

LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)
LOCAL_MODULE:= libmystuff
LOCAL_SRC_FILES := prebuilt/libmystuff.so
LOCAL_MODULE_CLASS := SHARED_LIBRARIES
LOCAL_MODULE_SUFFIX := .soinclude $(PREBUILT_SHARED_LIBRARY)	# 使用的是PREBUILT_SHARED_LIBRARY vs BUILD_SHARED_LIBRARY vs BUILD_PREBUILT

看似把libmystuff.so 编译为libmystuff.so 多次一举,实际上把libmystuff模块进入编译系统,否则其他模块引入这个库要写入绝对路径。

demo:LOCAL_LDLIBS的作用

#include <android/log.h>void foo() {__android_log_print(ANDROID_LOG_INFO, "TAG", "Hello from native");
}
// 必须要在LOCAL_SHARED_LIBRARIES := liblog,否咋找不到函数

常用函数

# 赋值
NAWE := foo
A := $(NAME).txt	# 立即赋值,A必须等于 foo.txt
B = $(NAME).txt		# $(B)使用的时候,才展开,跟随NAME变化
# :=(立即赋值) =(稍后赋值) ?=(条件赋值) +=(追加赋值)# call调用函数
LOCAL_PATH := $(call my-dir)	# Android.mk当前所在目录
LOCAL_SRC_FILES := $(wildcard *.c)	# 当前目录下所有*.c# 递归加载当前目录及子目录下的所有Android.mk
include $(call all-subdir-makefiles)
# 递归加载指定文件夹下的Android.mk
LOCAL_PATH := $(call my-dir)
include $(call all-makefiles-under,$(LOCAL_PATH))$(shell cmd)	# 执行shell命令并返回结果,eg: $(shell pwd -P)# 过滤filter,返回所有匹配的单词
$(filter text,string)	
$(filter %.c %.cpp, main.c main.o test.cpp readme.txt)	# main.c test.cpp # findstr,如果主串有就返回子串
$(findstring string,text)
$(findstring main, main.c test.cpp)		# main# foreach 是 make 内置的循环函数,Android.mk也能使用
SRC := a.c b.c c.c
$(foreach var,$(SRC),$(info hello $(var)))	# 格式 $(foreach var,list,code)
hello a.c
hello b.c
hell0 c.c# 打印信息
$(info "...........this is info........")
$(warning "...........this is warning........")# 条件编译, ifeq、ifneq
ifeq ($(TARGET_ARCH),arm)LOCAL_CFLAGS += -DARM_BUILD
else...
endififneq ($(strip $(MY_FEATURE)),)	# strip去掉所有的空格和换行LOCAL_SRC_FILES += feature.c
endif# 文本替换
STR := a/b/c
NEW := $(subst /,-,$(STR))	# a-b-c
# 取文件名
NAME := $(notdir src/main.c)	# main.c
# 取目录
DIR := $(dir src/main.c)	# src/# 调用自定义函数
my-func = $(1)-$(2)
RESULT := $(call my-func,hello,world)	# hello-world

demo:Android.mk (用于补充之前中LOCAL_XXX没有提到的)

LOCAL_CC := arm-linux-androideabi-gcc	# 指定c compiler, 很少显示指定,系统会默认 gcc/clang
LOCAL_CXX := arm-linux-androideabi-g++	# 指定c++ compiler
LOCAL_CPP_EXTENSION :=  .cc .cxx	# cpp之外的C++扩展名, 比如.cc .cxx	
LOCAL_C_INCLUDES := \			# c头文件$(LOCAL_PATH)/include \$(LOCAL_PATH)/third_party/libfoo/include# 此项目模块,会覆盖名字为CarLauncher的模块
LOCAL_OVERRIDES_PACKAGES := CarLauncher# 当模块为app时候
# 路径,/system/app(priv-app)/myapp/myapp.apk
LOCAL_PRIVILEGED_MODULE := true# 签名:PRESIGNED(保持原签名),platform(系统签名)
LOCAL_CERTIFICATE := PRESIGNED# @开头表示相对于当前Android.mk路径,指定jni的so库路径
LOCAL_PREBUILT_JNI_LIBS := \@jniLibs/armeabi-v7a/libmonochrome.so
# 不进行odex优化(dex→oat)
LOCAL_DEX_PREOPT := false# 默认路径为 /product
LOCAL_PRODUCT_MODULE := true
# 修改最终的输出名字,但是内部构建系统 模块名依然是原本的
LOCAL_BUILT_MODULE_STEM := new_name.so

tip:

build/target/product/security/platform.{pk8,x509.pem},用于签名,pk8为密钥用于加密apk,x509.pem为公钥用于验证。另外还有shared用与同一家开发的不同app签名然后apk之间的数据可以相互访问,media 也用于签名

demo:Android.mk (adair_service/Android.mk)

LOCAL_PATH := $(call my-dir)
PROJ_PATH := $(call my-dir)ifneq ($(ADAIR_SERVICE_BUILD_ANDROID), true)
ADAIR_SERVICE_BUILD_ANDROID := true$(warning "...............ADAIR_SERVICE_BUILD_ANDROID.............")
# 引用其他模块
include $(PROJ_PATH)/MainServer/Android.mk
include $(PROJ_PATH)/ParamUpdate/Android.mk
include $(PROJ_PATH)/MountAll/Android.mk
include $(PROJ_PATH)/Apk/Android.mkinclude $(PROJ_PATH)/external/can-utils/Android.mk
include $(PROJ_PATH)/external/aapt0/Android.mk
endif

其中 Apk/Android.mk:会遍历所有的子文件夹Android.mk

LOCAL_PATH := $(call my-dir)
include $(call all-makefiles-under,$(LOCAL_PATH))

实例

demo:安装WeChat的Android.mk(可以无脑复制)

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := WeChat
LOCAL_MODULE_CLASS := APPS
LOCAL_MODULE_TAGS := optional
# 可以不要
LOCAL_BUILT_MODULE_STEM := package.apk
LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX)
#LOCAL_PRIVILEGED_MODULE := true
LOCAL_CERTIFICATE := PRESIGNED
LOCAL_SRC_FILES := $(LOCAL_MODULE).apk
LOCAL_ENFORCE_USES_LIBRARIES := false
LOCAL_DEX_PREOPT := false
include $(BUILD_PREBUILT)

LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX) 其中 COMMON_ANDROID_PACKAGE_SUFFIX 已经在 build/make/core/config.mk 中定义了

demo:Apk/Goog_TTS/Android.mk

LOCAL_PATH := $(my-dir)include $(CLEAR_VARS)
LOCAL_MODULE := Goog_TTS
LOCAL_MODULE_CLASS := APPS
# 指定安装路径
LOCAL_MODULE_PATH := $(TARGET_OUT_ODM)/bundled_uninstall_back-app
LOCAL_SRC_FILES := $(LOCAL_MODULE)$(COMMON_ANDROID_PACKAGE_SUFFIX)
LOCAL_CERTIFICATE := PRESIGNED
LOCAL_DEX_PREOPT := false
LOCAL_ENFORCE_USES_LIBRARIES := false
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX)
# 指明目标架构
LOCAL_JNI_SHARED_LIBRARIES_ABI := arm
MY_LOCAL_PREBUILT_JNI_LIBS := \lib/arm/libopusV2JNI.so\lib/arm/libtts_android.so\MY_APP_LIB_PATH := $(TARGET_OUT_ODM)/bundled_uninstall_back-app/$(LOCAL_MODULE)/lib/$(LOCAL_JNI_SHARED_LIBRARIES_ABI)
# None字符串字面常量
ifneq ($(LOCAL_JNI_SHARED_LIBRARIES_ABI), None)
$(warning MY_APP_LIB_PATH=$(MY_APP_LIB_PATH))
# 模块安装结束后,执行的命令
LOCAL_POST_INSTALL_CMD := mkdir -p $(MY_APP_LIB_PATH); \$(foreach lib, $(MY_LOCAL_PREBUILT_JNI_LIBS), cp -f $(LOCAL_PATH)/$(lib) $(MY_APP_LIB_PATH)/$(notdir $(lib));)
endif
include $(BUILD_PREBUILT)

LOCAL_ENFORCE_USES_LIBRARIES:默认为true,在构建时会检查 AndroidManifest.xml 中列出的 uses-library 项,如果指定的库不存在则会构建报错或不参与构建;如果false,则不进行检查,虽然apk可能引用系统不存在的库,这些库可能由Play服务或者其他提供。

简介

Android 使用 GNU Make 语法的构建脚本,主要用于 Android NDK / AOSP(旧版) 编译系统,

Android.mk 的本质就是 Makefile,只是Google定义了一套变量和构建规范,定义了大量类似LOCAL_*的变量,不用手写gcc命令了。

Makefile 是 GUN Make 工具使用的规则文件:demo

hello: hello.c		# 目标: 依赖gcc -o hello hello.c	# 规则

CMake 本身不编译,生成构建脚本Makefile、Ninja等,然后Makefile 直接进行编译。

流程:

  • 提起编写好Android.mk 或 Android.bp
  • evensetup.sh & lunch:设置环境变量(TOP、OUT_DIR、TARGET_PRODUCT等);加载build/make/core/*.mk
  • make / mm :调用GUN make,扫描所有的Android.mk(all-subdir-makefiles)
  • build/core/*.mk 解析 LOCAL_XXX 变量,并根据最后一行include $() 产生对应编译规则makefile,makefile由kata(make-to-ninja) 生成 ninja 规则,Soong(Android.bp)也会生成ninja 规则
  • ninja 执行 C/C++编译,链接生成产物(so、apk等),最后复制到out/,并安装到目标目录上out/target/product/<device>/ 下(system vendor boot.img system.img等)

模块的 Android.mk 不会单独编译,需要被上级的Android.mk 或者 Android.bp文件引用。比如

# 递归加载当前目录及子目录下的所有Android.mk
include $(call all-subdir-makefiles)

NDK 是谷歌提供的C/C++原生开发工具包,面向的是APP层开发者,可以使用Android.mk编译JNI动态库(so) 给APK使用。可以提供性能,比如视频库、图形渲染、数学大量计算等;并且可以直接使用OpenCV、FFmpeg、libpng等开源库。

tip:foo、bar、baz 都是常用的伪变量,类似 Tom、Bob

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/918433.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/918433.shtml
英文地址,请注明出处:http://en.pswp.cn/news/918433.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

稠密检索:基于神经嵌入的高效语义搜索范式

本文由「大千AI助手」原创发布&#xff0c;专注用真话讲AI&#xff0c;回归技术本质。拒绝神话或妖魔化。搜索「大千AI助手」关注我&#xff0c;一起撕掉过度包装&#xff0c;学习真实的AI技术&#xff01; 1. 背景与定义 稠密检索&#xff08;Dense Retrieval&#xff09;是一…

AI日报0807 | GPT-5或今晚1点来袭:四大版本全曝光

关注&#xff1a;未来世界2099每日分享&#xff1a;全球最新AI资讯【应用商业技术其他】服务&#xff1a;【学习Q】【资源Q】【学习资料】【行业报告】&#xff08;无限免费下载&#xff09;应用 1、讯飞星火代码画布震撼上线&#xff1a;动嘴就能开发&#xff0c;工作效率翻倍…

认识爬虫 —— 正则表达式提取

本质是对字符串的处理&#xff0c;正则表达式描述的是一种字符串匹配的模式。简而言之&#xff0c;用具备一定特征意义的表达式对字符串进行检查&#xff0c;将符合条件的子字符串提取出来。导入模块import re一、单字符匹配match(表达式&#xff0c;匹配对象)&#xff1a;匹配…

单链表专题---暴力算法美学(1)(有视频演示)

1.1 移除链表元素 题目要求&#xff1a;给你一个链表的头节点head 和一个整数val,请你删除链表中所有满足Node.val val 的节点&#xff0c;并返回新的头节点。 思路一&#xff1a;遍历链表&#xff0c;遇到val就删除&#xff0c;pcur指向val的下一个节点&#xff0c;最后只剩…

机器学习-决策树(DecisionTree)

0 回归决策树展示 import pandas as pd import numpy as np from sklearn.tree import DecisionTreeRegressor from sklearn.metrics import root_mean_squared_error, r2_score from sklearn.model_selection import GridSearchCV,KFold from sklearn.model_selection import…

【Java Web】JDBC 连接 MySQL 实现数据库 CRUD(增删改查)详解

在 Java Web 开发中&#xff0c;与数据库交互是不可避免的&#xff0c;而 JDBC&#xff08;Java Database Connectivity&#xff09; 是 Java 官方提供的标准数据库连接接口&#xff0c;几乎所有 Java 项目中都用过它。 本文通过一个完整示例&#xff0c;带你从零实现 增&#…

HTTP 请求返回状态码和具体含义?200、400、403、404、502、503、504等

HTTP 状态码是服务器对客户端请求的响应状态标识&#xff0c;分为五大类&#xff08;以第一位数字区分&#xff09;&#xff0c;常用状态码如下&#xff1a; 1. 信息类&#xff08;1xx&#xff09;&#xff1a;请求已接收&#xff0c;继续处理 100 Continue&#xff1a;服务器已…

13-netty基础-手写rpc-消费方生成代理-05

netty系列文章&#xff1a; 01-netty基础-socket02-netty基础-java四种IO模型03-netty基础-多路复用select、poll、epoll04-netty基础-Reactor三种模型05-netty基础-ByteBuf数据结构06-netty基础-编码解码07-netty基础-自定义编解码器08-netty基础-自定义序列化和反序列化09-n…

ThreadLocal有哪些内存泄露问题,如何避免?

每个Thread都有一个ThreadLocal.ThreadLocalMap的map&#xff0c;该map的key为ThreadLocal实例&#xff0c;它为一个弱引 用&#xff0c;我们知道弱引用有利于GC回收。当ThreadLocal的key null时&#xff0c;GC就会回收这部分空间&#xff0c;但是value却不一 定能够被回收&am…

从0到1学LangChain之Agent代理:解锁大模型应用新姿势

从0到1学LangChain之Agent代理&#xff1a;解锁大模型应用新姿势 本文较长&#xff0c;建议点赞收藏&#xff0c;以免遗失。更多AI大模型开发 学习视频/籽料/面试题 都在这>>Github<< 什么是 LangChain Agent 代理 如果把大模型比作一个超级大脑&#xff0c;那么…

Spring Boot 2.6.0+ 循环依赖问题及解决方案

Spring Boot 2.6.0 循环依赖问题及解决方案 目录 背景解决方案 1. 配置文件开启循环依赖&#xff08;侵入性最低&#xff0c;临时方案&#xff09;2. Lazy 延迟注入&#xff08;侵入性低&#xff0c;推荐优先尝试&#xff09;3. 手动从容器获取&#xff08;ApplicationContex…

本地代码上传Github步骤

1.注册Github账号 2.下载git客户端 下载、安装步骤可以参考网站&#xff1a;(6 封私信 / 10 条消息) 手把手教你用git上传项目到GitHub&#xff08;图文并茂&#xff0c;这一篇就够了&#xff09;&#xff0c;相信你一定能成功&#xff01;&#xff01; - 知乎 3.在Github上…

5G NR 非地面网络 (NTN) 5G、太空和统一网络

非地面网络 5G 和太空&#xff1a;对 NTN 测试与测量的影响NTN 基站测试与测量NTN 用户设备的测试设备R&SSMW200A 矢量信号发生器R&SSMBV100B 矢量信号发生器总结5G 和太空&#xff1a;对 NTN 测试与测量的影响 5G 非地面网络 (NTN) 是无线通信向全球性星基和机载通信…

少儿编程比赛(如蓝桥杯、创意编程大赛等)的题目类型、知识点及难度总结

以下是针对主流少儿编程比赛&#xff08;如蓝桥杯、创意编程大赛等&#xff09;的题目类型、知识点及难度总结&#xff0c;结合了Scratch和C等语言的真题分析&#xff0c;帮助备赛或教学参考&#xff1a; 一、基础操作与交互题&#xff08;适合6~10岁&#xff09; 考察图形化编…

SIFThinker: Spatially-Aware Image Focus for Visual Reasoning

SIFThinker: Spatially-Aware Image Focus for Visual Reasoning Authors: Zhangquan Chen, Ruihui Zhao, Chuwei Luo, Mingze Sun, Xinlei Yu, Yangyang Kang, Ruqi Huang 相关工作总结 视觉思维链推理 最近的研究表明&#xff0c;通过上下文学习逐步推理可以显著提升大型…

学习嵌入式第二十五天

IO 1.概念 IO指input/outputLinux中一切皆文件IO的操作对象是文件 2.文件一段数据的集合文件通常存放在外存中&#xff0c;掉电后数据不丢失分类b(block&#xff0c;块设备文件) 按块扫描信息的文件。通常存储类型的设备为块设备文件。文件IOc(character&#xff0c;字符设备文…

本地部署接入 whisper + ollama qwen3:14b 总结字幕

1. 实现功能 M4-1 接入 whisper ollama qwen3:14b 总结字幕 自动下载视频元数据如果有字幕&#xff0c;只下载字幕使用 ollama 的 qwen3:14b 对字幕内容进行总结 2.运行效果 &#x1f50d; 正在提取视频元数据… &#x1f4dd; 正在下载所有可用字幕… [youtube] Extracting U…

【13-向量化-高效计算】

研究者能够扩展神经网络并构建非常大型网络的原因之一&#xff0c;就是神经网络可以被向量化&#xff0c;vectorized&#xff1b;可以非常高效地用矩阵地乘法实现。 事实上&#xff0c;并行计算硬件&#xff0c;例如GPU&#xff0c;一些CPU的功能&#xff0c;非常擅长进行非常大…

论文中PDF的公式如何提取-公式提取

Mathcheap - An AI-powered, free alternative to Mathpix Snip. 从PDF中截图公式&#xff0c;之后 ctrl V 转换成功 &#xff0c;提取成功 复制到word中&#xff0c;是这样的 这显然不是我们需要的。 可以使用Axmath 复制进去Axmath 就能正常显示公式。 之后再插入word…

用 Flink SQL 和 Paimon 打造实时数仓:深度解析与实践指南

1. 实时数仓的魅力&#xff1a;从离线到分钟级的飞跃实时数仓&#xff0c;听起来是不是有点高大上&#xff1f;其实它没那么神秘&#xff0c;但确实能让你的数据处理能力像坐上火箭一样飙升&#xff01;传统的离线数仓&#xff0c;像 Hadoop 生态的 Hive&#xff0c;动辄小时级…