android build system
1、gcc编译参数详解
1)-E
指示编译器对输入文件进行预处理,并将结果输出到标准输出(控制台)。预处理包括头文件的包含、宏定义的扩展、条件编译的选择等。
2)-D和-U
-D在命令行定义宏,作用等同于在代码中进程宏定义;-U用于取消宏定义。
例如–DDEBUG=1 <=>#define DEBUG 1
#include <stdio.h>
int main()
{
printf("hello world!\n");
#ifdef DEBUG
printf("hello debug!\n");
#endif
return 0;
}
不带—D进行编译的输出结果
aaa@qq.com_hxiong_com /cygdrive/e/project/cygwin_project/c_project/debug
$ gcc -o main main.c
aaa@qq.com_hxiong_com /cygdrive/e/project/cygwin_project/c_project/debug
$ ./main
hello world!
aaa@qq.com_hxiong_com /cygdrive/e/project/cygwin_project/c_project/debug
$
带—D进行编译的输出结果
aaa@qq.com_hxiong_com /cygdrive/e/project/cygwin_project/c_project/debug
$ gcc -DDEBUG=1 -o main main.c
aaa@qq.com_hxiong_com /cygdrive/e/project/cygwin_project/c_project/debug
$ ./main
hello world!
hello debug!
aaa@qq.com_hxiong_com /cygdrive/e/project/cygwin_project/c_project/debug
$
3)-S
指示编译器产生汇编代码文件后停止,汇编代码缺省的文件后缀名是.s
例如gcc –S main.c
会生成main.s文件,内容如下
.file "main.c"
.def __main; .scl 2; .type 32; .endef
.section .rdata,"dr"
.LC0:
.ascii "hello world!\0"
.text
.globl main
.def main; .scl 2; .type 32; .endef
.seh_proc main
main:
pushq %rbp
.seh_pushreg %rbp
movq %rsp, %rbp
.seh_setframe %rbp, 0
subq $32, %rsp
.seh_stackalloc 32
.seh_endprologue
call __main
leaq .LC0(%rip), %rcx
call puts
movl $0, %eax
addq $32, %rsp
popq %rbp
ret
.seh_endproc
.ident "GCC: (GNU) 4.9.3"
.def puts; .scl 2; .type 32; .endef
4)-c
指示编译器只编译源文件,但不进行连接,生成的文件为.o,这是可以重定向的目标程序。
5)-o
指示编译器为生成的可执行文件指定文件名,也就是设置可执行文件的文件名
6)-g
指示编译器产生可以被gnu调试工具进行调试的程序。
7)-l
用来指定程序要连接的库,例如 gcc –lc 实际上是链接libc.so库,也就是去掉了库前面的lib和后面的.so。
8)-L
指定连接的库文件所在的目录,例如gcc –L/usr/lib –lc就是链接/usr/lib目录下的libc.so库。
9)-include和-I
-include指定要包含的头文件,-I用于指定头文件所在的目录。
10)-Wl
WL后面的参数会传给链接程序
11)-shared
生成共享目标文件,通常用于编译动态库文件。2、编译可执行程序
我们以cameraserve为例,Android.mk指定了编译的规则
frameworks\av\camera\cameraserver\Android.mk
# LOCAL_PATH重新赋值为当前的路径
LOCAL_PATH:= $(call my-dir)
# 清除之前设置的LOCAL_XXX变量,除了LOCAL_PATH
include $(CLEAR_VARS)
# 设置需要需要编译的源文件
LOCAL_SRC_FILES:= \
main_cameraserver.cpp
# 设置需要链接的动态库
LOCAL_SHARED_LIBRARIES := \
libcameraservice \
libcutils \
libutils \
libbinder \
libcamera_client
# 设置编译出来的目标文件名
LOCAL_MODULE:= cameraserver
LOCAL_32_BIT_ONLY := true
# gcc编译参数的设置
LOCAL_CFLAGS += -Wall -Wextra -Werror -Wno-unused-parameter
# 设置rc文件
LOCAL_INIT_RC := cameraserver.rc
# 指定要编译成可执行程序文件
include $(BUILD_EXECUTABLE)
BUILD_EXECUTABLE定义在
build\core\config.mk
…
CLEAR_VARS:= $(BUILD_SYSTEM)/clear_vars.mk
BUILD_HOST_STATIC_LIBRARY:= $(BUILD_SYSTEM)/host_static_library.mk
BUILD_HOST_SHARED_LIBRARY:= $(BUILD_SYSTEM)/host_shared_library.mk
BUILD_STATIC_LIBRARY:= $(BUILD_SYSTEM)/static_library.mk
BUILD_SHARED_LIBRARY:= $(BUILD_SYSTEM)/shared_library.mk
BUILD_EXECUTABLE:= $(BUILD_SYSTEM)/executable.mk
BUILD_HOST_EXECUTABLE:= $(BUILD_SYSTEM)/host_executable.mk
BUILD_PACKAGE:= $(BUILD_SYSTEM)/package.mk
…
所以include $(BUILD_EXECUTABLE) 实际上是 include build/core/executable.mk
我们继续看executable.mk 做了什么事
差不多是做了一大堆的设置和检查工作,最后include executable_internal.mk
build\core\executable.mk
…
# check if non-preferred arch is supported
include $(BUILD_SYSTEM)/module_arch_supported.mk
ifeq ($(my_module_arch_supported),true)
# non-preferred arch is supported
OVERRIDE_BUILT_MODULE_PATH :=
LOCAL_BUILT_MODULE :=
LOCAL_INSTALLED_MODULE :=
LOCAL_INTERMEDIATE_TARGETS :=
include $(BUILD_SYSTEM)/executable_internal.mk
endif
…
我们继续往下看executable_internal.mk 做了什么事
build\core\executable_internal.mk
…
ifeq ($(LOCAL_FORCE_STATIC_EXECUTABLE),true) #这里表示编译静态可执行程序
$(linked_module): $(my_target_crtbegin_static_o) $(all_objects) $(all_libraries) $(my_target_crtend_o)
$(transform-o-to-static-executable)
$(PRIVATE_POST_LINK_CMD)
else #否则编译动态可执行程序,需要连接动态库
$(linked_module): $(my_target_crtbegin_dynamic_o) $(all_objects) $(all_libraries) $(my_target_crtend_o)
$(transform-o-to-executable)
$(PRIVATE_POST_LINK_CMD)
endif
…
$(linked_module):针对cameraserver 是 out/target/product/$(project)/arm/EXECUTABLES/cameraserver_intermediates/LINKED/cameraserver
$( my_target_crtbegin_dynamic_o):是 out/target/product/$(project)/arm/lib/ crtbegin_dynamic.o
$(all_objects):是out/target/product/$(project)/arm/EXECUTABLES/cameraserver_intermediates/main_cameraserver.o。
$(all_libraries):是out/target/product/$(project)/arm/lib/cameraservice.so 也就是LOCAL_SHARED_LIBRARIES引用的so,当然还包括libc.so libm.so
$(my_target_crtend_o):是out/target/product/$(project)/arm/lib/crtend_android.o
$( transform-o-to-executable) 是执行gcc编译命令的命令行。
定义在build\core\ definitions.mk
define transform-o-to-executable
@echo "target Executable: $(PRIVATE_MODULE) (aaa@qq.com)"
@mkdir -p $(dir aaa@qq.com)
$(transform-o-to-executable-inner)
endef
makefile中的define endef可以认为它就是定义了一个函数,里面的内容就是执行的命令。define transform-o-to-executable-inner
$(hide) $(PRIVATE_CXX) -pie \
-nostdlib -Bdynamic \
-Wl,-dynamic-linker,$(PRIVATE_LINKER) \
-Wl,--gc-sections \
-Wl,-z,nocopyreloc \
$(PRIVATE_TARGET_GLOBAL_LD_DIRS) \
-Wl,-rpath-link=$(PRIVATE_TARGET_OUT_INTERMEDIATE_LIBRARIES) \
$(PRIVATE_TARGET_CRTBEGIN_DYNAMIC_O) \
$(PRIVATE_ALL_OBJECTS) \
-Wl,--whole-archive \
$(call normalize-target-libraries,$(PRIVATE_ALL_WHOLE_STATIC_LIBRARIES)) \
-Wl,--no-whole-archive \
$(if $(PRIVATE_GROUP_STATIC_LIBRARIES),-Wl$(comma)--start-group) \
$(call normalize-target-libraries,$(PRIVATE_ALL_STATIC_LIBRARIES)) \
$(if $(PRIVATE_GROUP_STATIC_LIBRARIES),-Wl$(comma)--end-group) \
$(if $(filter true,$(NATIVE_COVERAGE)),$(PRIVATE_TARGET_COVERAGE_LIB)) \
$(PRIVATE_TARGET_LIBATOMIC) \
$(PRIVATE_TARGET_LIBGCC) \
$(call normalize-target-libraries,$(PRIVATE_ALL_SHARED_LIBRARIES)) \
-o aaa@qq.com \
$(PRIVATE_TARGET_GLOBAL_LDFLAGS) \
$(PRIVATE_LDFLAGS) \
$(PRIVATE_TARGET_CRTEND_O) \
$(PRIVATE_LDLIBS)
endef
transform-o-to-executable-inner里面就是gcc编译出可执行程序的命令,在知道gcc命令参数的情况下,我们把里面的参数还原出来。$(hide):这里就是一个字符@ @放在命令的前面是在执行的时候不将命令打印出来。
$(PRIVATE_CXX):这里是prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/bin/aarch64-linux-android-g++
所以$(hide) $(PRIVATE_CXX) 就是调用g++程序来进行编译,后面就都是gcc/g++的相关参数了,前面有讲一些。
-pie 加了这个参数后,程序的地址是可以变化的。
-Wl,-dynamic-linker 用于设置动态链接器
$(PRIVATE_LINKER):这里是/system/bin/linker64 (64位)$(PRIVATE_TARGET_GLOBAL_LD_DIRS):这里是-Lout/target/product/$(project)/arm/lib
$(PRIVATE_TARGET_OUT_INTERMEDIATE_LIBRARIES):这里是out/target/product/$(project)/arm/lib
$(PRIVATE_TARGET_CRTBEGIN_DYNAMIC_O):这里是out/target/product/$(project)/arm/lib/crtbegin_dynamic.o
$(PRIVATE_ALL_OBJECTS):这里是out/target/product/$(project)/arm/EXECUTABLES/cameraserver_intermediates/main_cameraserver.o
$(PRIVATE_TARGET_LIBGCC) 是prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/lib/gcc/aarch64-linux-android/4.9/libgcc.a
$(call normalize-target-libraries,$(PRIVATE_ALL_SHARED_LIBRARIES))执行的结果是得到需要连接的lib库,比如 lcameraservice lbinder lc lutils ... 也就是LOCAL_SHARED_LIBRARIES包含的库和必需的库,用空格分开。
aaa@qq.com 是out/target/product/$(project)/arm/EXECUTABLES/cameraserver_intermediates/LINKED/cameraserver
$(PRIVATE_TARGET_GLOBAL_LDFLAGS)是-WL,-z,noexecstack –WL,-z,relro –WL,-z,now –WL,…
–WL,-z,now 表示函数立刻绑定
$(PRIVATE_TARGET_CRTEND_O) 是out/target/product/$(project)/arm/lib/ crtend_android.o