零.从HelloWorld.cpp说起

下面是一个最简单的C++程序,我们通过它来引入我们今天要讲解的Android编译系统

/*************************************************************************
@File Name : HelloWorld.cpp
@Author : SangYu
@Email : sangyu.code@gmail.com
@Description : Test for g++
************************************************************************/
#include <iostream>
int main(){
std::cout<<"Hello World!"<<std::endl;
return 0;
}

g++编译指令:g++ -o main HelloWorld.cpp

Android 编译系统初探_android

这里我们只有一个 cpp 文件,只需要一条命令即可编译出我们的可执行文件 main.exe

一.Make 与 Makefile

在大型项目开发过程中,我们会有不只一个 module,同时有数以万计的 cpp 文件,它们的编译组织(先编译谁,后编译谁,编译的库依赖哪些静态库,动态库......)这些问题我们就不能够再通过一条条命令来解决。Make 应运而生,帮助我们组织整个大型项目的编译过程,更重要地,能够识别出哪部分需要重新编译,并重新进行编译,并不需要重新编译整体项目。

The make utility automatically determines which pieces of a large program need to be recompiled, and issues commands to recompile them.

make 官网:​www.gnu.org/software/ma…

Makefile---描述了整个程序是如何编译链接的,Make 的工作依赖于 MakeFile 的规则。

原书中的 Makefile 例子:

edit : main.o kbd.o command.o display.o \
insert.o search.o files.o utils.o
cc -o edit main.o kbd.o command.o display.o \
insert.o search.o files.o utils.o
main.o : main.c defs.h
cc -c main.c
kbd.o : kbd.c defs.h command.h
cc -c kbd.c
command.o : command.c defs.h command.h
cc -c command.c
display.o : display.c defs.h buffer.h
cc -c display.c
insert.o : insert.c defs.h buffer.h
cc -c insert.c
search.o : search.c defs.h buffer.h
cc -c search.c
files.o : files.c defs.h buffer.h command.h
cc -c files.c
utils.o : utils.c defs.h
cc -c utils.c
clean :
rm edit main.o kbd.o command.o display.o \
insert.o search.o files.o utils.o

一个简单的例子:

#ifndef _ADD_HEAD_
#define _ADD_HEAD_
int AddInt(int num1, int num2);
#endif
#include <iostream>
#include "Add.h"
int AddInt(int num1, int num2)
{
return num1 + num2;
}

int main()
{
int num1,num2;
std::cout<<"Entry two number:";
std::cin>>num1>>num2;
std::cout<<"num1+num2:"<<num1<<"+"<<num2<<"="<<AddInt(num1,num2)<<std::endl;
return 0;
}
exe_name=main
program_name=Add
objects_name=$(program_name).o
$(exe_name):$(objects_name)
g++ -o $(exe_name) $(objects_name)
$(program_name).o:$(program_name).h

.PHONY: clean
clean:
-rm $(exe_name) $(objects_name)

Android 编译系统初探_g++_02

二.Android 编译系统

1.​Android Make Build System​---Android.mk

Android 基于 Make 做的 Android.mk,目前大部分 HAL 层代码和 JNI 代码都是使用该种方式进行的编译 Android.mk 的相关语法与关键字:​developer.android.com/ndk/guides/…

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE := libxmlrpc++
LOCAL_MODULE_HOST_OS := linux

LOCAL_RTTI_FLAG := -frtti
LOCAL_CPPFLAGS := -Wall -Werror -fexceptions
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/src

LOCAL_SRC_FILES := $(call \
all-cpp-files-under,src)
include $(BUILD_SHARED_LIBRARY)

Android.mk 方式的缺陷:

The Make build system is widely supported and used, but at Android's scale became slow, error prone, unscalable, and difficult to test. The ​Soong build system provides the flexibility required for Android builds.

编译变慢/易错的/无法扩展/难以测试

2.Soong build system---Android.bp

Soong 构建系统​是在 Android 7.0 (Nougat) 中引入的,旨在取代 Make。它利用 Kati​ GNU Make 克隆工具和 Ninja

根据设计,​​Android.bp​​ 文件很简单。它们不包含任何条件语句,也不包含控制流语句;所有复杂问题都由用 Go 编写的构建逻辑处理。

cc_library_shared {
name: “libxmlrpc++”,

rtti: true,
cppflags: [
“-Wall”,
“-Werror”,
“-fexceptions”,
],

export_include_dirs: [“src”],
srcs: [“src/**/*.cpp”],

target: {
darwin: {
enabled: false,
},
},
}

https://source.android.google.cn/compatibility/tests/development/blueprints

(1).Ninja

Ninja

  • Ninja 的输入文件被设计为由更高级的构建系统生成。
  • Ninja 被设计为尽可能快地运行构建, 其他构建系统基于高级语言,而 Ninja 基于汇编。

Ninja 基于汇编,专注于速度,不支持分支、循环等流程控制,也不支持逻辑运算,但它允许以其它语言如来维护这些复杂的编译流程和逻辑。例如,我们可以采用 Makefile, go, python 等等来维护编译的流程和逻辑。

(2).Blueprint

Blueprint

Blueprint 是 ninja 构建文件的生成器。android 编译系统 soong 集成了 Blueprint,Blueprint 可将我们编写的 android.bp 解析生成一个 ninja 构建文件。我们在编译一个模块时,只需要将这个模块的 android.bp 文件配置好,编译系统会自动为这个模块生成 ninja 清单,最终使用 ninja 来调用 gcc、clang、java、dex、aapt2 等等命令来构建模块。

(3).kati

简单地说,kati 就是一个转换工具,它可以将 Makefile 和.mk 文件转换为 ninja。

(4).Soong

Soong集成了 Ninja, 而 Ninja 专注于速度,没有条件或流程控制语句,也不支持逻辑运算。但它允许以其它语言如来维护这些复杂的编译流程和逻辑。例如,我们可以继续采用 makefile, 或者采用 go 语言来维护编译流程和逻辑。上面已经提到了 Ninja,Blueprint, kati 等等好几种工具,为了完整、快速的构建一个 android 系统,就需要一个“管家”来协调这些工具。例如,将.bp 转换成 ninja 时使用 Blueprint, 将 Makefile 转换成 ninja 时使用 kati。这个选择转换工具、选择解析框架、解析维护构建逻辑的“管家”就是 soong。

(5).androidmk

androidmk 可以将 android.mk 转换成 android.bp。

(6).bpfmt

用于格式化 Android.bp 文件的工具 bpfmt,类似于 gofmt。

Android.bp 的规范格式包括:

  • 4 个空格缩进。
  • 多元素列表的每个元素后的换行符。
  • 在 lists 和 maps 的结尾处始终包含一个逗号。

(7).ninja,Blueprint,kati,androidmk 与 Soong 的关系和作用

  • kati 可以将 Android.mk 文件转换成 ninja 文件。
  • androidmk 可以将 Android.mk 文件转换成 Android.bp 文件
  • Blueprint 可以将 Android.bp 文件转换成 ninja 文件。
  • Blueprint,kati,androidmk 由 Soong 调用和协调,一起合作完成 android 源码的构建。

Android 编译系统初探_g++_03