Android中Kati简介

1. 介绍

kati is an experimental GNU make clone. The main goal of this tool is to speed-up incremental build of Android.

Currently, kati does not offer a faster build by itself. It instead converts your Makefile to a ninja file.

Kati 是为了提高Android 编译速度而产生的实验性的GNU make 克隆的工具。本身没有提供快速编译,而是将Makefile 文件转换为Ninja 文件,再通过Ninja 进行编译提速。

Currently, kati's main mode is --ninja mode. Instead of executing build commands by itself, kati generates build.ninja file andninja actually runs commands. 

目前,Kati的主要模式是--ninja模式。 Kati自己不用执行build命令,而是生成build.ninja文件,而ninja实际上运行命令。

Kati 最开始在Go 中实现的,期初开发者认为Go 可以获取足够的性能,但是最终却是使得Kati 的Go 版本变慢了。所以后来Kati 用C++重写实现。观看现在Kati 实现的代码,其中除了C++ 实现,还要部分的Go 和sh,这应该是考虑之后的最好性能。

2. 整体架构

  • 解析器(Parser)
  • 评估器(Evaluator)
  • 依赖构建器(Dependency builder)
  • 执行器(Executor)
  • Ninja生成器(Ninja generator)

Kati 由上面几部分组成。

A Makefile has some statements which consist of zero or more expressions. There are two parsers and two evaluators - one for statements and the other for expressions.

其中两个解析器和两个评估期,一个针对Makefile中的语句,一个针对Makefile中的表达式。

评估器输出构建规则(build rules)和变量表(variable table)的列表。依赖构建器从构建规则列表中创建依赖图(dependency graph)。注意这一步不使用变量表。
然后将使用执行器或Ninja生成器。无论哪种方式,Kati再次为命令行运行其评估器。该变量表再次用于此步骤。

3. 代码位置

从目前来看(Android N、O、P)代码目录在:

build/kati/

另外,Android 也再带编译好的kati 文件:

$ find prebuilts/ -name ckati
prebuilts/build-tools/linux-x86/asan/bin/ckati
prebuilts/build-tools/linux-x86/bin/ckati
prebuilts/build-tools/darwin-x86/bin/ckati

github的source code路径为:

https://github.com/google/kati

可以通过下面命令获取source code:

git clone https://github.com/google/kati.git

4. 编译

在Android项目中,这个Git库自带Android.bp文件,可以作为一个模块自动跟随项目一起编译。 也可以在项目路径中,执行mm单独编译。 编译产物主要是ckati,会被安装到项目的out/host/linux-x86/bin/ckati,作为编译过程中主机环境的一部分。

下面是Android.bp 中节选的部分规则:

cc_binary_host {                                                                                       
    name: "ckati",                                                                                     
    defaults: ["ckati_defaults"],                                                                      
    srcs: ["main.cc"],                                                                                 
    whole_static_libs: ["libckati"],                                                                   
}                                                                                                      
                                                                                                       
cc_binary_host {                                                                                       
    name: "ckati_stamp_dump",                                                                          
    defaults: ["ckati_defaults"],                                                                      
    srcs: ["regen_dump.cc"],                                                                           
    static_libs: ["libckati"],                                                                         
} 

在Android也预置了ckati,在项目编译的时候会直接使用这里的ckati,详细看prebuilts/build-tools/build-prebuilts.sh,下面节选部分内容:

if [ -n ${build_soong} ]; then                                                                         
    # ckati and makeparallel (Soong)                                                                   
    SOONG_OUT=${OUT_DIR}/soong                                                                         
    SOONG_HOST_OUT=${OUT_DIR}/soong/host/${OS}-x86                                                     
    rm -rf ${SOONG_OUT}                                                                                
    mkdir -p ${SOONG_OUT}                                                                              
    cat > ${SOONG_OUT}/soong.variables << EOF                                                          
{                                                                                                      
    "Allow_missing_dependencies": true,                                                                
    "HostArch":"x86_64",                                                                               
    "HostSecondaryArch":"x86"                                                                          
}                                                                                                      
EOF

5. 用法

在Android项目中,ckati会在编译过程中,自动被使用,无需操心。

单独使用时,在包含Makefile的目录下,执行ckati,效果与make基本相同。 执行ckati --ninja,可以根据Makefile生成build.ninja文件,并且附带env.sh和ninja.sh。 通过env.sh来配置环境,通过执行./ninja.sh来启动Ninja、使用build.ninja编译。 生成的ninja.sh文件,主要内容如下。

. ./env.sh
exec ninja -f ./build.ninja "$@"

上面也提到,目前kati 使用都是带--ninja,其他的参数可以根据code 获取到,首先当然是main 函数:

int main(int argc, char* argv[]) {
  if (argc >= 2 && !strcmp(argv[1], "--realpath")) {
    HandleRealpath(argc - 2, argv + 2);
    return 0;
  }
  Init();
  string orig_args;
  for (int i = 0; i < argc; i++) {
    if (i)
      orig_args += ' ';
    orig_args += argv[i];
  }
  g_flags.Parse(argc, argv);
  ...
  ...
  Quit();
  return r;
}

g_glags 的Parse 就是解析命令行,来看下g_flags:

extern Flags g_flags;

从这个看应该是Flags 类了,没错,就在这里:

void Flags::Parse(int argc, char** argv) {
  subkati_args.push_back(argv[0]);
  num_jobs = num_cpus = sysconf(_SC_NPROCESSORS_ONLN);
  const char* num_jobs_str;
  const char* writable_str;

  if (const char* makeflags = getenv("MAKEFLAGS")) {
    for (StringPiece tok : WordScanner(makeflags)) {
      if (!HasPrefix(tok, "-") && tok.find('=') != string::npos)
        cl_vars.push_back(tok);
    }
  }

  for (int i = 1; i < argc; i++) {
    const char* arg = argv[i];
    bool should_propagate = true;
    int pi = i;
    if (!strcmp(arg, "-f")) {
      makefile = argv[++i];
      should_propagate = false;
    } else if (!strcmp(arg, "-c")) {
      is_syntax_check_only = true;
    } else if (!strcmp(arg, "-i")) {
      is_dry_run = true;
    } else if (!strcmp(arg, "-s")) {
      is_silent_mode = true;
    } else if (!strcmp(arg, "-d")) {
      enable_debug = true;
    } else if (!strcmp(arg, "--kati_stats")) {
      enable_stat_logs = true;
    } else if (!strcmp(arg, "--warn")) {
      enable_kati_warnings = true;
    } else if (!strcmp(arg, "--ninja")) {
      generate_ninja = true;
    } else if (!strcmp(arg, "--empty_ninja_file")) {
      generate_empty_ninja = true;
    } else if (!strcmp(arg, "--gen_all_targets")) {
      gen_all_targets = true;

    ...
    ...

    }

    if (should_propagate) {
      for (; pi <= i; pi++) {
        subkati_args.push_back(argv[pi]);
      }
    }
  }
}

6. 总结

Kati 可以看成一个小工具,主要是Android 中将Makefile 文件转换为另一个中编译模式——Ninja,而Ninja 也是Android 为了编译能够更加快速。后面也出现了Blueprint 替代了现在的Makefile,都是为了编译的快速、简便。以后Android 中也有可能不在需要Makefile,也一起期待吧!

附:

由于时间有限,个人也不是负责编译模块,所以,深入研究的比较少,有时间了定会详细剖析一下source code。

 

 

参考:

GitHub - google/kati: An experimental GNU make clone

其他文章:

Android 中Ninja 简介

理解 Android Build 系统

Android中的Android.bp、Blueprint 和Soong简介

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

私房菜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值