Android.mk教程

語法

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;動輒小時級…