转自:http://note.qidong.name/2017/08/android-kati/
Android中的Kati
kati是Google专门为了Android而开发的一个小项目,基于Golang和C++。 目的是为了把Android中的Makefile,转换成Ninja文件。
代码位置
在Android 7.0以上的平台项目中,kati的位置是build/kati/
。 另外,平台代码也自带编译好的ckati
。
$ 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上的位置是google/kati。
git clone https://github.com/google/kati.git
编译
在Git库中,可以用make
来直接编译。 编译完成后,目录下会出现ckati
这个可执行文件。 产生ckati
后,通过执行./m2n
,可以把Makefile转换成build.ninja文件。 接下来,可以通过执行ninja
来再次编译。
在Android项目中,这个Git库自带Android.bp文件,可以作为一个模块自动跟随项目一起编译。 也可以在项目路径中,执行mm
单独编译。 编译产物主要是ckati
,会被安装到项目的out/host/linux-x86/bin/ckati
,作为编译过程中主机环境的一部分。 (这里是使用Linux来编译。如果是Windows或Darwin,产物位置会略有不同。)
使用
在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 "$@"
除了--ninja
以外,ckati
支持很多其它参数。 比如,和make
一样,可以通过-f
指定Makefile位置,通过-j
指定线程数。 另外,在kati项目的m2n
脚本中,就可以看到以下的复杂用法。
ckati --ninja --ignore_optional_include=out/%.P --ignore_dirty=out/% --use_find_emulator --detect_android_echo --detect_depfiles --gen_all_targets
然而,这些参数的具体含义,只能望文生义。 ckati
的文档十分匮乏,不仅没有像样的网站,连帮助命令都没有。 不过,从其源文件find.cc
中,还是可以看出一些端倪。
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, "--gen_all_targets")) {
gen_all_targets = true;
} else if (!strcmp(arg, "--regen")) {
// TODO: Make this default.
regen = true;
} else if (!strcmp(arg, "--regen_debug")) {
regen_debug = true;
} else if (!strcmp(arg, "--regen_ignoring_kati_binary")) {
regen_ignoring_kati_binary = true;
} else if (!strcmp(arg, "--dump_kati_stamp")) {
dump_kati_stamp = true;
regen_debug = true;
} else if (!strcmp(arg, "--detect_android_echo")) {
detect_android_echo = true;
} else if (!strcmp(arg, "--detect_depfiles")) {
detect_depfiles = true;
} else if (!strcmp(arg, "--color_warnings")) {
color_warnings = true;
} else if (!strcmp(arg, "--werror_find_emulator")) {
werror_find_emulator = true;
} else if (!strcmp(arg, "--werror_overriding_commands")) {
werror_overriding_commands = true;
} else if (ParseCommandLineOptionWithArg(
"-j", argv, &i, &num_jobs_str)) {
num_jobs = strtol(num_jobs_str, NULL, 10);
if (num_jobs <= 0) {
ERROR("Invalid -j flag: %s", num_jobs_str);
}
} else if (ParseCommandLineOptionWithArg(
"--remote_num_jobs", argv, &i, &num_jobs_str)) {
remote_num_jobs = strtol(num_jobs_str, NULL, 10);
if (remote_num_jobs <= 0) {
ERROR("Invalid -j flag: %s", num_jobs_str);
}
} else if (ParseCommandLineOptionWithArg(
"--ninja_suffix", argv, &i, &ninja_suffix)) {
} else if (ParseCommandLineOptionWithArg(
"--ninja_dir", argv, &i, &ninja_dir)) {
} else if (!strcmp(arg, "--use_find_emulator")) {
use_find_emulator = true;
} else if (ParseCommandLineOptionWithArg(
"--goma_dir", argv, &i, &goma_dir)) {
} else if (ParseCommandLineOptionWithArg(
"--ignore_optional_include",
argv, &i, &ignore_optional_include_pattern)) {
} else if (ParseCommandLineOptionWithArg(
"--ignore_dirty",
argv, &i, &ignore_dirty_pattern)) {
} else if (ParseCommandLineOptionWithArg(
"--no_ignore_dirty",
argv, &i, &no_ignore_dirty_pattern)) {
} else if (arg[0] == '-') {
ERROR("Unknown flag: %s", arg);
} else {
if (strchr(arg, '=')) {
cl_vars.push_back(arg);
} else {
should_propagate = false;
targets.push_back(Intern(arg));
}
}
总结
kati是一个基于Makefile来生成ninja.build的小项目。 它是Google专为Android而开发,用来修正Android项目创建之初的错误——使用Makefile来做一个超复杂的编译构建系统。
在编译过程中,kati负责把既有的Makefile、Android.mk,转换成Ninja文件。 在Android 7.0中,它独挑大梁。 在Android 8.0以后,它与Soong一起,成为Ninja文件的两大来源。 也许,在几个大版本后,它会与原先的Makefile、Android.mk一起,退出Android平台编译系统的大舞台。
在单独使用时,它对普通的小项目还能勉强生效。 面对复杂的、多嵌套的Makefile时,它往往无法支持,会出现各种各样的问题。 当然,也可以理解为,它只为Android而设计。
总之,不推荐在Android以外的任何项目中使用kati。