Android O 編譯探析

根目錄下的Makefile

include build/core/main.mk

build/core/main.mk

host_prebuilts := linux-x86

.PHONY: run_soong_ui
run_soong_ui:
    +@prebuilts/build-tools/$(host_prebuilts)/bin/makeparallel --ninja build/soong/soong_ui.bash --make-mode $(MAKECMDGOALS)

.PHONY: $(MAKECMDGOALS)
$(sort $(MAKECMDGOALS)) : run_soong_ui
    @#empty

MAKECMDGOALS

  • The targets given to make on the command line. Setting this variable has no effect on the operation of make.

根據(jù)build/envsetup.sh,MAKECMDGOALS會(huì)被mm/mmm/mma/mmma設(shè)置,結(jié)構(gòu)大致是MODULES-IN-$DIR, 執(zhí)行make/m時(shí)為空

prebuilts/build-tools/linux-x86/bin/makeparallel

file prebuilts/build-tools/linux-x86/bin/makeparallel

prebuilts/build-tools/linux-x86/bin/makeparallel: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.24, stripped

源代碼位置 build/make/tools/makeparallel,是用C++編寫的,可以自行執(zhí)行make編譯

makeparallel.cpp
int main(int argc, char* argv[]) {
    解析參數(shù)
    pid = fork();
  if (pid < 0) {
    error(errno, errno, "fork failed");
  } else if (pid == 0) {
    // child
    unsetenv("MAKEFLAGS");
    unsetenv("MAKELEVEL");

    // make 3.81 sets the stack ulimit to unlimited, which may cause problems
    // for child processes
    struct rlimit rlim{};
    if (getrlimit(RLIMIT_STACK, &rlim) == 0 && rlim.rlim_cur == RLIM_INFINITY) {
      rlim.rlim_cur = 8*1024*1024;
      setrlimit(RLIMIT_STACK, &rlim);
    }

    // 執(zhí)行 build/soong/soong_ui.bash --make-mode XXX
    int ret = execvp(path, args.data());
    if (ret < 0) {
      error(errno, errno, "exec %s failed", path);
    }
    abort();
  }
  // 父進(jìn)程等待子進(jìn)程退出
}

build/soong/soong_ui.bash

...
run_go "$@"

核心是執(zhí)行函數(shù)run_go

function run_go
{
    # Increment when microfactory changes enough that it cannot rebuild itself.
    # For example, if we use a new command line argument that doesn't work on older versions.
    local mf_version=2

    local mf_src="${TOP}/build/soong/cmd/microfactory"

    local out_dir="${OUT_DIR-}"
    if [ -z "${out_dir}" ]; then
        if [ "${OUT_DIR_COMMON_BASE-}" ]; then
            out_dir="${OUT_DIR_COMMON_BASE}/$(basename ${TOP})"
        else
            out_dir="${TOP}/out"
        fi
    fi

    local mf_bin="${out_dir}/microfactory_$(uname)"
    local mf_version_file="${out_dir}/.microfactory_$(uname)_version"
    local soong_ui_bin="${out_dir}/soong_ui"
    local from_src=1

    if [ -f "${mf_bin}" ] && [ -f "${mf_version_file}" ]; then
        if [ "${mf_version}" -eq "$(cat "${mf_version_file}")" ]; then
            from_src=0
        fi
    fi

    // 第一次直接運(yùn)行g(shù)o文件并生成可執(zhí)行文件microfactory_Linux,之后直接執(zhí)行microfactory_Linux
    local mf_cmd
    if [ $from_src -eq 1 ]; then
        mf_cmd="${GOROOT}/bin/go run ${mf_src}/microfactory.go"
    else
        mf_cmd="${mf_bin}"
    fi

   // 為了生成soong_ui
    ${mf_cmd} -s "${mf_src}" -b "${mf_bin}" \
            -pkg-path "android/soong=${TOP}/build/soong" -trimpath "${TOP}/build/soong" \
            -o "${soong_ui_bin}" android/soong/cmd/soong_ui

    if [ $from_src -eq 1 ]; then
        echo "${mf_version}" >"${mf_version_file}"
    fi

 // 執(zhí)行soong_ui
    exec "${out_dir}/soong_ui" "$@"
}

build/soong/cmd/microfactory/microfactory.go

省略

build/soong/cmd/soong_ui/main.go

func main() {
      ......
      build.Build(buildCtx, config, build.BuildAll)
}

build/soong/ui/build/build.go

const (
    BuildNone          = iota
    BuildProductConfig = 1 << iota
    BuildSoong         = 1 << iota
    BuildKati          = 1 << iota
    BuildNinja         = 1 << iota
    BuildAll           = BuildProductConfig | BuildSoong | BuildKati | BuildNinja
)

func Build(ctx Context, config Config, what int)
根據(jù)之前what值決定執(zhí)行哪些操作,根據(jù)上面的代碼,可以看到調(diào)用的是build.BuildAll
下面看一下每項(xiàng)操作具體做了哪些工作

  • BuildProductConfig
>runMakeProductConfig(ctx, config)

build/soong/ui/build/make.go
核心操作是執(zhí)行了make -f build/core/config.mk剩胁,解析命令執(zhí)行結(jié)果獲得變量/值的集合,同步環(huán)境變>量。為config設(shè)置KATI_GOALS扒最、NINJA_GOALS,其實(shí)就是之前的MAKECMDGOALS旭从。

  • BuildSoong
runSoongBootstrap(ctx, config)
runSoong(ctx, config)
  • runSoongBootstrap
    核心邏輯是執(zhí)行build/soong/bootstrap.bash
  • build/soong/bootstrap.bash
    輸出模板build/soong/soong.bootstrap.inout/soong/.soong.bootstrap,執(zhí)行build/blueprint/bootstrap.bash,建立軟鏈接out/soong/soong指向build/soong/soong.bash
$ cat out/soong/.soong.bootstrap 
BUILDDIR="out/soong"
SRCDIR_FROM_BUILDDIR="../.."
PREBUILTOS="linux-x86"
  • build/blueprint/bootstrap.bash
    輸出模板build/soong/build.ninja.inout/soong/.minibootstrap/build.ninja,變量存儲(chǔ)到out/soong/.blueprint.bootstrap
$ cat out/soong/.blueprint.bootstrap
BOOTSTRAP="./bootstrap.bash"
BOOTSTRAP_MANIFEST="./build/soong/build.ninja.in"
  • runSoong
    執(zhí)行out/soong/soong(build/soong/soong.bash)
  • build/soong/soong.bash
BUILDDIR=out/soong NINJA="prebuilts/build-tools/linux-x86/bin/ninja" build/blueprint/blueprint.bash $@
  • build/blueprint/blueprint.bash
# Build minibp and the primary build.ninja
"${NINJA}" -w dupbuild=err -f "${BUILDDIR}/.minibootstrap/build.ninja"

# Build the primary builder and the main build.ninja
"${NINJA}" -w dupbuild=err -f "${BUILDDIR}/.bootstrap/build.ninja"

# SKIP_NINJA can be used by wrappers that wish to run ninja themselves.
if [ -z "$SKIP_NINJA" ]; then
   "${NINJA}" -w dupbuild=err -f "${BUILDDIR}/build.ninja" "$@"
else
   exit 0
fi
  • BuildKati
runKati(ctx, config)
    • build/soong/ui/build/kati.go
      runKati 核心是執(zhí)行ckati命令。ckati的源碼位于build/kati下敷待,通過make執(zhí)行
// 生成KatiSuffix间涵,后面會(huì)需要
genKatiSuffix(ctx, config)
executable := "prebuilts/build-tools/" + config.HostPrebuiltTag() + "/bin/ckati"
args := []string{
        "--ninja",
        "--ninja_dir=" + config.OutDir(),
        "--ninja_suffix=" + config.KatiSuffix(),
        "--regen",
        "--ignore_optional_include=" + filepath.Join(config.OutDir(), "%.P"),
        "--detect_android_echo",
        "--color_warnings",
        "--gen_all_targets",
        "-f", "build/core/main.mk",
    }
    • build/kati/main.cc

??跟蹤main函數(shù),先進(jìn)行Init()榜揖,初始化了一些東西勾哩,先不care。把參數(shù)做個(gè)備份保存到orig_args(不知道什么意圖)举哟。把參數(shù)拿去解析(flags.cc)思劳,解析完存放結(jié)構(gòu)體Flags中。
??FindFirstMakefie尋找第一個(gè)makefile妨猩,上面已經(jīng)通過-f指定了makefile潜叛,未指定則順序?qū)ふ耶?dāng)前目錄下的GNUmakefile、makefile壶硅、Makefile威兜。
??然后進(jìn)入Run函數(shù)。根據(jù)之前參數(shù)需要生成Ninja文件庐椒。NeedsRegen判斷是否需要重新生成ninja文件椒舵。函數(shù)IsMissingOutputs判斷GetNinjaFilename/GetNinjaShellScriptFilename是否存在,涉及到config.ninja_suffix约谈,也就是KatiSuffix上面已備注逮栅。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市窗宇,隨后出現(xiàn)的幾起案子措伐,更是在濱河造成了極大的恐慌,老刑警劉巖军俊,帶你破解...
    沈念sama閱讀 217,542評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件侥加,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡粪躬,警方通過查閱死者的電腦和手機(jī)担败,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來镰官,“玉大人提前,你說我怎么就攤上這事∮具耄” “怎么了狈网?”我有些...
    開封第一講書人閱讀 163,912評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我拓哺,道長(zhǎng)勇垛,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,449評(píng)論 1 293
  • 正文 為了忘掉前任士鸥,我火速辦了婚禮闲孤,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘烤礁。我一直安慰自己讼积,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,500評(píng)論 6 392
  • 文/花漫 我一把揭開白布脚仔。 她就那樣靜靜地躺著币砂,像睡著了一般。 火紅的嫁衣襯著肌膚如雪玻侥。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,370評(píng)論 1 302
  • 那天亿蒸,我揣著相機(jī)與錄音凑兰,去河邊找鬼。 笑死边锁,一個(gè)胖子當(dāng)著我的面吹牛姑食,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播茅坛,決...
    沈念sama閱讀 40,193評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼音半,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了贡蓖?” 一聲冷哼從身側(cè)響起曹鸠,我...
    開封第一講書人閱讀 39,074評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎斥铺,沒想到半個(gè)月后彻桃,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,505評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡晾蜘,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,722評(píng)論 3 335
  • 正文 我和宋清朗相戀三年邻眷,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片剔交。...
    茶點(diǎn)故事閱讀 39,841評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡肆饶,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出岖常,到底是詐尸還是另有隱情驯镊,我是刑警寧澤,帶...
    沈念sama閱讀 35,569評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站阿宅,受9級(jí)特大地震影響候衍,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜洒放,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,168評(píng)論 3 328
  • 文/蒙蒙 一蛉鹿、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧往湿,春花似錦妖异、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至绒窑,卻和暖如春棕孙,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背些膨。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工蟀俊, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人订雾。 一個(gè)月前我還...
    沈念sama閱讀 47,962評(píng)論 2 370
  • 正文 我出身青樓肢预,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親洼哎。 傳聞我的和親對(duì)象是個(gè)殘疾皇子烫映,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,781評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容