Android 編譯介紹

来源:https://www.cnblogs.com/zhiqinlin/archive/2023/09/13/17700115.html
-Advertisement-
Play Games

Android的源碼非常的龐大,編譯Android系統往往會占用我們很長的時間,我們需要瞭解下Android的編譯規則,以期能提高我們的開發效率。。。 ...


一、需求

        Android的源碼非常的龐大,編譯Android系統往往會占用我們很長的時間,我們需要瞭解下Android的編譯規則,以期能提高我們的開發效率,達到程式員按時下班的偉大理想。

二、環境

  1. 平臺:QCM2290
  2. 版本:Android 11
  3. 編譯伺服器: 64G + 32核

三、相關概念

3.1 Treble架構

        由於Android各個層級之間的耦合性大,Android系統更新成本高,導致Android系統版本雖然已經釋放了很久,但是市面上Android的系統依然存在滯後、碎片化的情況。Android 8.0 重新設計了 Android 操作系統框架(名為“Treble”的項目),以便讓製造商能夠以更低的成本更輕鬆、更快速地將設備更新到新版 Android 系統。
        Android 7.x 及更早版本中沒有正式的供應商介面。當設備製造上升級Android系統時,需要移植大量的代碼。因為Framework與供應商代碼打包在一個鏡像中,所以必須整體升級。

        Android 8.0 及更高版本提供了一個穩定的新供應商介面。設備製造商訪問的是 Android 代碼中特定於硬體的部分,而不會依賴供應商的私有介面。並且供應商會使用獨立的vendor分區。這樣,設備製造商在更新 Android 操作系統框架,只需要單獨升級system分區。同時穩定的供應商介面會保證相容性。         Treble的目標是將供應商實現(大部分有晶元製造商編寫特定設備軟體和底層軟體)與Android操作系統框架分隔開來,這通過供應商介面來實現。為了確保供應商實現的向前相容性,供應商介面會由供應商測試套件 (VTS) 進行驗證,該套件類似於相容性測試套件 (CTS)。您可以使用 VTS 在舊版 Android 架構和當前 Android 架構中自動執行 HAL 和操作系統內核測試。

3.2 Soong

        Soong 構建系統是在 Android 7.0 (Nougat) 中引入的,旨在取代 Make。它利用 Kati GNU Make 克隆工具和 Ninja 構建系統組件來加速 Android 的構建。

        Soong是由Go語言寫的一個項目,從Android 7.0開始,在prebuilts/go/目錄下新增了Go語言所需的運行環境,Soong在編譯時使用,解析Android.bp,將之轉化為Ninja文件,完成Android的選擇編譯,解析配置工作等。故Soong相當於Makefile編譯系統的核心,即build/make/core下麵的內容。

3.3 Blueprint

        Blueprint由Go語言編寫,是生成、解析Android.bp的工具,是Soong的一部分。Soong則是專為Android編譯而設計的工具,Blueprint只是解析文件的形式,而Soong則解釋內容的含義。

3.4 KATI

        kati是Google專門為了Android而開發的一個小項目,基於Golang和C++。目的是為了把Android中的Makefile,轉換成Ninja文件。
        在最新的Android R(11)中,Google已經移除了/build/kati目錄,只保留了一個預先編譯出來的可執行文件:prebuilts/build-tools/linux-x86/bin/ckati,這意味著Google在逐漸從編譯系統中移除kati,預計1-2個Android大版本,.mk文件全部都切換成.bp文件後,kati將會正式退出Android歷史舞臺。
        kati是go語言寫的,而ckati是c++寫的。kati官方文檔對它的描述是:kati is an experimental GNU make clone。也就是說,kati是對等make命令的。只不過kati並不執行具體的編譯工作,而是生成ninja文件。kati剛開始是使用Golang編寫的,但是後來驗證下來發現編譯速度不行,於是改成C++編寫,所以現在存在兩個版本:kati、ckati。

3.5 Ninja

        Ninja 是Google的一名程式員推出的註重速度的構建工具。一般在Unix/Linux上的程式通過make/makefile來構建編譯,而Ninja通過將編譯任務並行組織,大大提高了構建速度。
        Ninja是一個致力於速度的小型編譯系統(類似於Make),如果把其他編譯系統比做高級語言的話,Ninja就是彙編語言。通常使用Kati或soong把makefile轉換成Ninja files,然後用Ninja編譯。
        ninja核心是由C/C++編寫的,同時有一部分輔助功能由python和shell實現。由於其開源性,所以可以利用ninja的開源代碼進行各種個性化的編譯定製。

3.5 Makefile

        Makefile是一個文本文件,是GNU make程式在執行的時候預設讀取的配置文件。其關係到了整個工程的編譯規則。一個工程中的源文件按類型、功能、模塊分別放在若幹個目錄中,makefile定義了一系列規則來指定,哪些文件需要先編譯,哪些文件需要後編譯,哪些文件需要重新編譯,甚至於進行更複雜的功能操作。
        其好處在於:寫好makefile之後,只需要一個“make”命令,整個工程就能完全自動編譯,極大地提高了軟體開發的效率。

四、高通編譯

        我司高通項目的編譯,有一個痛點,就是編譯的時間太久,即便是remake一個工程都要占用小半天的時間,不僅自身調試效率低,還頻繁占用伺服器編譯資源。故我們有必要瞭解下,高通的編譯腳本的邏輯。

4.1 編譯指令

以下為我司編譯常用指令:

平臺 編譯指令 備註
QCM2290 ./build.sh dist -j32 全編譯,並打包
QCM2290 source build/envsetup.sh
lunch qssi-userdebug
./build.sh dist -j32 --qssi_only
單獨編譯,qssi模塊
QCM2290 source build/envsetup.sh
lunch bengal-userdebug
./build.sh dist -j32 --target_only
單獨編譯,target模塊
QCM2290 source build/envsetup.sh
lunch bengal-userdebug
./build.sh dist -j32 --merge_only
打包操作,打包ota zip and super.img
QCM2290 source build/envsetup.sh
lunch bengal-userdebug
./build.sh -j32 --merge_only
打包操作,打包super.img

4.2 編譯腳本

(1)qssi模塊,qcom single system image,就類似system分區,編譯生成路徑:out\target\product\qssi
(2)target模塊,就類似vendor分區,編譯生成路徑:out\target\product\bengal
(3)AndroidQ以前只用lunch自己項目的target就可以進行編譯了,現在隨著Treble架構的強制推行,system和vendor要強制解耦了。

@android/build.sh
function build_qssi_only () {//編譯qssi
    command "source build/envsetup.sh"
    command "$QTI_BUILDTOOLS_DIR/build/kheaders-dep-scanner.sh"
    command "lunch ${TARGET_QSSI}-${TARGET_BUILD_VARIANT}"
    command "make $QSSI_ARGS"
}

function build_target_only () {//編譯target
    command "source build/envsetup.sh"
    command "$QTI_BUILDTOOLS_DIR/build/kheaders-dep-scanner.sh"
    command "lunch ${TARGET}-${TARGET_BUILD_VARIANT}"
    QSSI_ARGS="$QSSI_ARGS SKIP_ABI_CHECKS=$SKIP_ABI_CHECKS"
    command "make $QSSI_ARGS"
    command "run_qiifa"
}

function merge_only () {//打包
    # DIST/OTA specific operations:
    if [ "$DIST_ENABLED" = true ]; then
        generate_ota_zip
    fi
    # Handle dynamic partition case and generate images
    if [ "$BOARD_DYNAMIC_PARTITION_ENABLE" = true ]; then
        generate_dynamic_partition_images
    fi
}

function full_build () {//全編譯
    build_qssi_only
    build_target_only
    # Copy Qssi system|product.img to target folder so that all images can be picked up from one folder
    command "cp $QSSI_OUT/system.img $OUT/"
    if [ -f  $QSSI_OUT/product.img ]; then
        command "cp $QSSI_OUT/product.img $OUT/"
    fi
    if [ -f  $QSSI_OUT/system_ext.img ]; then
        command "cp $QSSI_OUT/system_ext.img $OUT/"
    fi
    merge_only
}

ps:編譯時,根據需要,編譯對應的target模塊或者qssi模塊,儘量避免全編。

五、Android-Make指令

        從高通的編譯腳本來看,其最終是調用make指令,來實現Android的編譯。那麼問題來了,這個make指令實現在哪裡呢?具體做了什麼事情呢?

5.1 Android編譯指令

        Android項目的編譯,不同的ODM廠商會根據自身的編譯規則,定製不同的編譯腳本、打包腳本,但是歸根到底,都是基於如下命令進行客制化:

source build/envsetup.sh //step 1.初始化編譯環境
lunch xxx //step 2.選擇編譯目標
make -j8 //step 3.執行編譯
make snod //step 4.打包生成鏡像

5.2 初始化編譯環境

envsetup.sh腳本:主要是定義了make、mm、lunch、cgrep等相關函數,為Android系統的編譯提供支持。

@LINUX\android\build\envsetup.sh
...
function mmm()
(
    call_hook ${FUNCNAME[0]} $@
    if [ $? -ne 0 ]; then
        return 1
    fi

    _trigger_build "modules-in-dirs-no-deps" "$@"
)
...
function make()
{
    _wrap_build $(get_make_command "$@") "$@"
}
...

常用指令:

5.3 選擇編譯目標

lunch命令:主要作用是根據用戶輸入或者選擇的產品名來設置與具體產品相關的環境變數。

lunch 24後,生成的編譯環境變數信息:

5.4 執行編譯

make命令:主要用來編譯Android系統,生成對應的編譯文件。其中,Android10及之後,通過soong構建系統執行編譯。

5.4.1 編譯流程圖

5.4.2 shell腳本部分

step 1. make指令入口

@LINUX\android\build\envsetup.sh
function make()
{
    _wrap_build $(get_make_command "$@") "$@"
}

step 2. 獲取構建方式(以前通過make構建,後續更換成soong方式),通過判斷soong_ui.bash文件是否存在,來決定系統構建方式。

@LINUX\android\build\envsetup.sh
function get_make_command()
{
    if [ -f build/soong/soong_ui.bash ]; then
        # Always use the real make if -C is passed in
        for arg in "$@"; do
            if [[ $arg == -C* ]]; then
                echo command make
                return
            fi
        done
        echo build/soong/soong_ui.bash --make-mode
    else
        echo command make
    fi
}

step 3. 執行構建指令,並列印構建時間、構建結果

@LINUX\android\build\envsetup.sh
function _wrap_build()
{
    ...
    local start_time=$(date +"%s")
    "$@" //執行構建指令
    local ret=$?
    local end_time=$(date +"%s")
    local tdiff=$(($end_time-$start_time))
    local hours=$(($tdiff / 3600 ))
    local mins=$((($tdiff % 3600) / 60))
    local secs=$(($tdiff % 60))
    local ncolors=$(tput colors 2>/dev/null)
    ...
    echo
    if [ $ret -eq 0 ] ; then
        echo -n "${color_success}#### build completed successfully " //列印構建成功結果
    else
        echo -n "${color_failed}#### failed to build some targets " //列印構建失敗結果
    fi
    if [ $hours -gt 0 ] ; then
        printf "(%02g:%02g:%02g (hh:mm:ss))" $hours $mins $secs //列印構建時間
    ...
    return $ret
}

構建指令如下:

高通平臺指令:
build/soong/soong_ui.bash --make-mode dist -j32 ENABLE_AB=true SYSTEMEXT_SEPARATE_PARTITION_ENABLE=true BOARD_DYNAMIC_PARTITION_ENABLE=true ENABLE_VIRTUAL_AB=false SHIPPING_API_LEVEL=29

5.4.3 goLang腳本部分

5.4.3.1 執行soong_ui.bash腳本

soong_ui.bash腳本主要做了兩件事:

  1. 根據"android/soong/cmd/soong_ui/"內容,生成soong_ui的go可執行程式,生成路徑:out\soong_ui
  2. 執行soong_ui程式,進入soong_ui世界
@build\soong\soong_ui.bash
...
# Save the current PWD for use in soong_ui
export ORIGINAL_PWD=${PWD}
export TOP=$(gettop)
source ${TOP}/build/soong/scripts/microfactory.bash

soong_build_go soong_ui android/soong/cmd/soong_ui//構建soong_ui執行程式

cd ${TOP}
exec "$(getoutdir)/soong_ui" "$@"//執行soong_ui程式,啟動構建

5.4.3.2 soong入口

        soong_ui是個go程式,至此進入soong構建系統的世界。

@android\build\soong\cmd\soong_ui\main.go
func main() {
    ...
	c, args := getCommand(os.Args)
	...
	f := build.NewSourceFinder(buildCtx, config)
	defer f.Shutdown()
	build.FindSources(buildCtx, config, f)//遍歷整個項目,記錄所有的mk、bp等文件
	c.run(buildCtx, config, args, logsDir)//啟動構建
}

5.4.3.3 soong構建系統

        soong構建系統最核心的步驟。其主要通過將bp、mk文件,解析成ninja文件,再通過ninja去實現系統構建任務。

@android\build\soong\ui\build\build.go
func Build(ctx Context, config Config, what int) {
    ...
    runSoong(ctx, config)//step 1.處理bp文件
    ...
    runKatiBuild(ctx, config)//step 2.處理mk文件
    ...
    createCombinedBuildNinjaFile(ctx, config)//step 3.整合ninja文件
    ...
    runNinja(ctx, config)//step 4.構建
    ...
}

step 1. runSoong
runSoong 對工具進行編譯,先編譯出blueprint等編譯工具, 再把*.bp 編譯成 out/soong/build.ninja。

@android\build\soong\ui\build\soong.go
func runSoong(ctx Context, config Config) {
    ...
    ctx.BeginTrace(metrics.RunSoong, "blueprint bootstrap")//1.主要用於生成out/soong/.minibootstrap目錄相關文件
    ...
    ctx.BeginTrace(metrics.RunSoong, "environment check")//2.初始環境檢查
    ...
    ctx.BeginTrace(metrics.RunSoong, "minibp")//3.創建minibp可執行程式
    ...
    ctx.BeginTrace(metrics.RunSoong, "bpglob")//4.創建bpglob可執行程式
    ...
    ninja("minibootstrap", ".minibootstrap/build.ninja")//5.主要用於生成out/soong/.bootstrap/build.ninja文件
    ninja("bootstrap", ".bootstrap/build.ninja")//6.生成out/soong/build.ninja
}

(1)創建 out/soong/.minibootstrap/目錄併在這個目錄下創建一系列文件,包括out/soong/.minibootstrap/build.ninja這個文件。該路徑下的內容,會參與到bootstrap階段的構建;
(2)檢查soong構建的環境、工具是否存在&正常;
(3)通過microfactory生成out/soong/.minibootstrap/minibp可執行程式,會參與到bootstrap階段的構建;
(4)通過microfactory生成out/soong/.minibootstrap/bpglob可執行程式,會參與到bootstrap階段的構建;
(5)通過步驟三編譯生成的minibp程式,生成out/soong/.bootstrap/build.ninja文件,該文件會參與到bootstrap階段的構建,可參考verbose.log列印的日誌:

@android\out\verbose.log
[1/1] out/soong/.minibootstrap/minibp -t -l out/.module_paths/Android.bp.list -b out/soong -n out -d out/soong/.bootstrap/build.ninja.d -globFile out/soong/.minibootstrap/build-globs.ninja -o out/soong/.bootstrap/build.ninja Android.bp

(6)bootstrap表示從無到有創建Soong,該階段會先生成bootstrap相關的工具程式:./out/soong/.bootstrap/bin/*,再使用編譯生成的soong_build程式,生成out/soong/build.ninja文件。用於後續參與Ninja編譯構建工作,可參考verbose.log列印的日誌:

@android\out\verbose.log
[2/2] out/soong/.bootstrap/bin/soong_build -t -l out/.module_paths/Android.bp.list -b out/soong -n out -d out/soong/build.ninja.d -globFile out/soong/.bootstrap/build-globs.ninja -o out/soong/build.ninja Android.bp

out/soong/build.ninja文件羅列了項目上所有的bp模塊編譯規則,及其相關依賴模塊、SDK、簽名信息、臨時文件等(文件很大,約3.53G,慎重打開)。如下為該文件部分內容:

(7)該階段在編譯時,控制台列印的log如下:

step 2. runKatiBuild
        runKatiBuild, 載入 build/make/core/main.mk, 搜集所有的Android.mk文件生成out/build-xxx.ninja文件

@android\build\soong\ui\build\kati.go
func runKatiBuild(ctx Context, config Config) {
    ctx.BeginTrace(metrics.RunKati, "kati build")
    ...
    args := []string{
        "--writable", config.OutDir() + "/",
        "-f", "build/make/core/main.mk",
    }
    ...
    runKati(ctx, config, katiBuildSuffix, args, func(env *Environment) {})//執行ckati指令,構建mk
    ...
}

(1)參考soong.log的日誌,runKati函數最終會引用cKati指令,載入main.mk文件,生成ninja文件,其指令如下:

@android\out\soong.log
2023/09/08 10:47:50.479597 build/soong/ui/build/exec.go:60: prebuilts/build-tools/linux-x86/bin/ckati [prebuilts/build-tools/linux-x86/bin/ckati --ninja --ninja_dir=out --ninja_suffix=-qssi --no_ninja_prelude --regen --ignore_optional_include=out/%.P --detect_android_echo --color_warnings --gen_all_targets --use_find_emulator --werror_find_emulator --no_builtin_rules --werror_suffix_rules --warn_real_to_phony --warn_phony_looks_real --werror_real_to_phony --werror_phony_looks_real --werror_writable --top_level_phony --kati_stats --writable out/ 
-f build/make/core/main.mk --werror_implicit_rules SOONG_MAKEVARS_MK=out/soong/make_vars-qssi.mk SOONG_ANDROID_MK=out/soong/Android-qssi.mk TARGET_DEVICE_DIR=device/qcom/qssi KATI_PACKAGE_MK_DIR=out/target/product/qssi/obj/CONFIG/kati_packaging]

(2)build/make/core/main.mk又是何方神聖?從main.mk開始,將通過include命令將其所有需要的.mk文件包含進來,最終在記憶體中形成一個包括所有編譯腳本的集合,這個相當於一個巨大Makefile文件。網上有個圖,可以很好的描述其關係,如下:

文件 說明
build/make/core/main.mk Build的主控文件,主要作用是包含其他mk,以及定義幾個最重要的編譯目標,同時檢查編譯工具的版本,例如gcc、clang、java等
build/make/core/config.mk Build的配置文件,主要是區分各個產品的配置,並將這些編譯器參數引入產品配置 BoardConfig.mk,同時也配置了一些編譯器的路徑等
build/make/core/clang/config.mk clang編譯的配置文件
build/make/core/definitions.mk 最重要的 Make 文件之一,在其中定義了大量的函數。這些函數都是 Build 系統的其他文件將用到的。例如:my-dir,all-subdir-makefiles,find-subdir-files,sign-package 等,關於這些函數的說明請參見每個函數的代碼註釋。
build/make/core/dex_preopt.mk 定義了dex優化相關的路徑和參數
build/make/core/pdk_config.mk 編譯pdk的配置文件
build/make/core/Makefile 系統最終編譯完成所需要的各種目標和規則
build/make/core/envsetup.mk 包含進product_config.mk文件並且根據其內容設置編譯產品所需要的環境變數,並檢查合法性,指定輸出路徑等
build/make/core/combo/select.mk 根據當前編譯器的平臺選擇平臺相關的 Make 文件
build/make/core/ninja_config.mk 解析makefile的的列表,傳給kati,配置傳給ninja和kati的目標
build/make/core/soong_config.mk 配置soong的環境變數,建立go變數和mk變數的json映射關係,讓go變數可以獲取到mk中定義的變數值

(3)如上關係圖所示,mk文件索引的幾乎都是config.mk之類的配置文件,那我們編譯模塊對應的Android.mk又在哪個位置被引入呢?在5.4.3.2節,在soong啟動時,我們便會去搜索項目中所有的Android.mk文件,並記錄於out/.module_paths/Android.mk.list文件。在main.mk裡面,便可以根據這個文件,將所有的內容include進來。因此,在該項目下定義的任一Android.mk都可以被引用。

@android/build/make/core/main.mk
...
subdir_makefiles := $(SOONG_ANDROID_MK) $(file <$(OUT_DIR)/.module_paths/Android.mk.list) $(SOONG_OUT_DIR)/late-$(TARGET_PRODUCT).mk
subdir_makefiles_total := $(words int $(subdir_makefiles) post finish)
.KATI_READONLY := subdir_makefiles_total
//遍歷相關mk文件
$(foreach mk,$(subdir_makefiles),$(info [$(call inc_and_print,subdir_makefiles_inc)/$(subdir_makefiles_total)] including $(mk) ...)$(eval include $(mk)))
...

(4)main.mk載入完成後,最終生成out/build-xxx.ninja文件,用於後續參與Ninja編譯構建工作。out/build-xxx.ninja文件羅列了項目上所有的mk模塊編譯規則,及其相關依賴模塊、SDK、簽名信息、臨時文件等(qssi模塊和target模塊,約1G+1.08G,文件較大,慎重打開)。
(5)該階段在編譯時,控制台列印的log如下:

step 3. createCombinedBuildNinjaFile
        為了方便統一管理,Soong將out/soong/build.ninja文件 、out/build-*.ninja文件和out/build-*-package.ninja文件, 合成為out/combined-*.ninja文件,由該文件記錄所有待執行ninja文件。

@android\build\soong\ui\build\build.go

var combinedBuildNinjaTemplate = template.Must(template.New("combined").Parse(`
builddir = {{.OutDir}}
{{if .UseRemoteBuild }}pool local_pool
 depth = {{.Parallel}}
{{end -}}
pool highmem_pool
 depth = {{.HighmemParallel}}
build _kati_always_build_: phony
{{if .HasKatiSuffix}}subninja {{.KatiBuildNinjaFile}}//追加文件out/build-*.ninja
subninja {{.KatiPackageNinjaFile}}//追加文件out/build-*-package.ninja
{{end -}}
subninja {{.SoongNinjaFile}}//追加文件out/soong/build.ninja
`))

func createCombinedBuildNinjaFile(ctx Context, config Config) {
    ...
    file, err := os.Create(config.CombinedNinjaFile())//創建combined-*.ninja文件
    ...
    if err := combinedBuildNinjaTemplate.Execute(file, config); //執行合併動作
    ...
}

out/combined-qssi.ninja文件,如下:

step 4. runNinja
        runNinja,運行Ninja命令, 解析combined-*.ninja,執行編譯過程

@android\build\soong\ui\build\ninja.go
func runNinja(ctx Context, config Config) {
    ...
    executable := config.PrebuiltBuildTool("ninja")//獲取ninja指令
    args := []string{
        "-d", "keepdepfile",
        "-d", "keeprsp",
        "--frontend_file", fifo,
    }
    ...
    args = append(args, "-f", config.CombinedNinjaFile())//配置組合的ninja文件
    args = append(args,
        "-w", "dupbuild=err",
        "-w", "missingdepfile=err"
    cmd := Command(ctx, config, "ninja", executable, args...)//初始化ninja指令參數
    ...
    ctx.Status.Status("Starting ninja...")
    cmd.RunAndStreamOrFatal()//執行ninja指令
}

(1)參考soong.log的日誌,runNinja函數最終會引用ninja指令,載入out/combined-*.ninja文件,執行最終的編譯,其指令如下:

@android\out\soong.log
2023/09/12 14:13:05.709769 build/soong/ui/build/exec.go:60: prebuilts/build-tools/linux-x86/bin/ninja [prebuilts/build-tools/linux-x86/bin/ninja -d keepdepfile -d keeprsp --frontend_file out/.ninja_fifo droid -j 34 -f out/combined-bengal.ninja -w dupbuild=err -w missingdepfile=err]

(2)該階段在編譯時,控制台列印的log如下:

5.4.3.4 soong編譯創建文件

文件 備註
android/out/soong.log soong模塊列印內容
android/out/verbose.log 控制台編譯日誌
android/out/dumpvars-verbose.log lunch的log信息
android/out/.ninja_log ninja模塊編譯log
android/out/soong_ui go可執行程式,執行soong編譯
android/out/.module_paths/ 遍歷整個項目,記錄所有的mk、bp等文件
android/out/soong/build.ninja 項目上所有bp模塊的編譯規則
android/out/build-*.ninja 項目上所有mk模塊的編譯規則
android/out/combined-*.ninja 項目上所有模塊的編譯規則組合
android/out/soong/host/linux-x86/bin/androidmk mk文件轉bp文件的指令

六、編譯小竅門

6.1 模塊編譯速度優化

        隨著Android版本的更迭,尤其是Androd10和Android11以上源碼的編譯,單編模塊的時間也特別慢,每次都需要小半個小時甚至更長,因為每次單編都會重新載入所有mk文件,再生成ninja編譯,此過程很慢,實際編譯過程很快。
(1)如下指令是AOSP的快編指令,用於快速編譯單個模塊:

./prebuilts/build-tools/linux-x86/bin/ninja -f out/combined-bengal.ninja SnapdragonCamera -j32
格式 描述
./prebuilts/build-tools/linux-x86/bin/ninja 指定了要使用的構建工具,即Ninja構建系統。該指令通過在AOSP預構建工具鏈目錄下找到Ninja可執行文件進行調用。
out/combined-aosp_arm-eng.ninja 指定了Ninja構建系統要使用的構建文件的路徑和名稱。在AOSP編譯過程中,生成的構建文件會存儲在out目錄中,且命名通常包含目標設備的相關信息。
SnapdragonCamera 指定了要構建的目標模塊或子模塊的名稱。
-j32 指定了併發構建的線程數。-j32表示同時使用32個線程進行構建,以加快構建速度。

其他常用的指令,如:

#編譯Settings
./prebuilts/build-tools/linux-x86/bin/ninja -f out/combined-bengal.ninja Settings -j32
#編譯selinux
./prebuilts/build-tools/linux-x86/bin/ninja -f out/combined-bengal.ninja selinux_policy -j32
#編譯Framework
./prebuilts/build-tools/linux-x86/bin/ninja -f out/combined-bengal.ninja frameworks -j32
#全編譯
./prebuilts/build-tools/linux-x86/bin/ninja -f out/combined-bengal.ninja -j32 2>&1 |tee ninja_build.log

(2)ninja與mm指令對比,查看編譯速度(工程已經編譯過,刪除SnapdragonCamera目錄,比較編譯完成時間)

指令 編譯時間 (mm:ss) 編譯時間 (mm:ss) 編譯時間 (mm:ss)
mm SnapdragonCamera 05:58 05:37 04:25
./prebuilts/build-tools/linux-x86/bin/ninja -f out/combined-bengal.ninja SnapdragonCamera -j32 00:05 00:04 00:04

6.2 Android.mk轉換為Android.bp

        Android.bp的出現就是為了替換Android.mk文件。bp跟mk文件不同,它是純粹的配置,沒有分支、迴圈等流程式控制制,不能做算數邏輯運算。如果需要控制邏輯,那麼只能通過Go語言編寫。舊的mk可以轉換為bp,Soong會編譯生成一個androidmk命令,用於將Android.mk文件轉換為Android.bp文件。
(1)生成androidmk文件
確認out/soong/host/linux-x86/bin/目錄下是否存在androidmk文件,如不存在androidmk文件,使用如下命令生成:

source build/envsetup.sh
m -j blueprint_tools

(2)通過androidmk執行轉化動作

cd out/soong/host/linux-x86/bin/
androidmk android.mk > android.bp

(3)轉換前的android.mk
預置應用到vendor分區

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := TCP_UDP
LOCAL_MODULE_CLASS := APPS
LOCAL_CERTIFICATE := PRESIGNED
LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR)
LOCAL_SRC_FILES := app/TCP_UDP.apk
include $(BUILD_PREBUILT)

(4)轉換後的android.bp
轉化對應的規則,可參考:build/soong/androidmk/androidmk/android.go

android_app_import {

    name: "TCP_UDP",

    local_module_path: {
        var: "TARGET_OUT_VENDOR",
    },
    apk: "app/TCP_UDP.apk",
    presigned: true,
}

七、小結

  1. Android的Treble架構;
  2. Soong構建流程;
  3. Out路徑下關於構建生成的臨時文件、日誌;
  4. Blueprint、Kati、Ninja模塊的作用;

八、參考資料

Treble架構:
https://segmentfault.com/a/1190000021550665?sort=newest

Android-Make指令:
https://blog.csdn.net/yiranfeng/article/details/109084082
https://blog.csdn.net/yiranfeng/article/details/109148537
https://zhuanlan.zhihu.com/p/342303212
https://zhuanlan.zhihu.com/p/342817768
https://blog.csdn.net/m0_37624402/article/details/91409900

編譯優化:
https://blog.csdn.net/lontano_0406/article/details/131162119
http://wed.xjx100.cn/news/268761.html?action=onClick
https://blog.csdn.net/weixin_36389889/article/details/128469488


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 先執行 free -h 查看現在的swap分配情況 執行 swapon -s 查看swap的分區文件 執行 swapoff /dev/dm-1 取消已經掛上的swap文件 現在擴充swap到4G,並將swap文件掛到/vm_memory/swapfile上 先創建/vm_memory/swapfil ...
  • 1、背景描述 出於安全考慮,需要禁止使用root用戶通過ssh遠程登錄Linux 禁用root用戶遠程登錄後,需要提供一個許可權用戶用於ssh遠程登錄 2、創建擁有sudo許可權的用戶 2.1、創建一個普通用戶rain useradd命令用於創建一個用戶, 選項 -m 表示創建用戶的主目錄, -c 表示 ...
  • 1. 索引 1.1. 鍵(key) 1.2. 存儲引擎用於快速找到記錄的一種數據結構 1.3. 當表中的數據量越來越大時,索引對性能的影響愈發重要 1.4. 在數據量較小且負載較低時,缺少合適的索引對性能的影響可能還不明顯 1.5. 索引優化是對查詢性能優化最有效的手段 1.6. 索引能夠輕易將查詢 ...
  • 本文分享自華為雲社區《GaussDB(DWS)鎖問題全解》,作者: yd_211043076。 一、gaussdb有哪些鎖 1、常規鎖:常規鎖主要用於業務訪問資料庫對象的加鎖,保護併發操作的對象,保持數據一致性;常見的常規鎖有表鎖(relation)和行鎖(tuple)。 表鎖:當對錶進行DDL、D ...
  • Apache SeaTunnel是一個非常易於使用的、超高性能的分散式數據集成平臺,支持海量數據的實時同步。每天可穩定高效同步數百億數據,已被近百家企業投入生產使用。 現在的版本不支持通過jtds的方式鏈接sqlserver,我們來自己寫代碼來實現它,並把代碼提交給apache seatunnel。 ...
  • 通過 API 對外提供數據服務是大部分企業中比較常見的數據應用方式,對於 API 平臺管理者、開發者和調用者來說,API 的調用性能、安全性和穩定性是在平臺選型時最需要考慮的三個因素。 袋鼠雲API開發及管理平臺【數棧-數據服務 DataAPI】通過多種手段標準化管控服務,可完成從 API 創建、發 ...
  • 業務挑戰與痛點 隨著互聯網技術的發展、雲計算技術的成熟、人工智慧技術的興起和數字化經濟的崛起,數據已成為企業的核心資產。在金融行業中,數字化已成為了支撐各類業務場景的核心力量,包括個人理財、企業融資、股票交易、保險理賠、貸款服務、支付結算、投資咨詢、資產管理等等。然而,在基於大數據分析與處理技術的業 ...
  • 起因 在GreatSQL社區上有一位用戶提出了“手工構建MGR碰到的次節點一直處於recovering狀態”,經過排查後,發現了是因為新密碼驗證插件caching_sha2_password導致的從節點一直無法連接主節點,帖子地址:(https://greatsql.cn/thread-420-2- ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...