android build system

本文详细介绍了GCC编译器的各种参数及其使用场景,包括预处理、宏定义、生成汇编代码、仅编译源文件等功能。并通过Android项目的实例,展示了如何通过Makefile配置完成可执行程序的构建过程。

1、gcc编译参数详解

 

1)-E

指示编译器对输入文件进行预处理,并将结果输出到标准输出(控制台)。预处理包括头文件的包含、宏定义的扩展、条件编译的选择等。

2)-D和-U

-D在命令行定义宏,作用等同于在代码中进程宏定义;-U用于取消宏定义。

例如–DDEBUG=1   <=>#define DEBUG 1


 
  1. #include <stdio.h>

  2. int main()

  3. {

  4. printf("hello world!\n");

  5. #ifdef DEBUG

  6. printf("hello debug!\n");

  7. #endif

  8. return 0;

  9. }

不带—D进行编译的输出结果

hxiong@www_hxiong_com /cygdrive/e/project/cygwin_project/c_project/debug
$ gcc -o main main.c
hxiong@www_hxiong_com /cygdrive/e/project/cygwin_project/c_project/debug
$ ./main
hello world!

hxiong@www_hxiong_com /cygdrive/e/project/cygwin_project/c_project/debug
$

带—D进行编译的输出结果

 

hxiong@www_hxiong_com /cygdrive/e/project/cygwin_project/c_project/debug
$ gcc -DDEBUG=1 -o main main.c
hxiong@www_hxiong_com /cygdrive/e/project/cygwin_project/c_project/debug
$ ./main
hello world!
hello debug!

hxiong@www_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


 
  1. # LOCAL_PATH重新赋值为当前的路径

  2. LOCAL_PATH:= $(call my-dir)

  3. # 清除之前设置的LOCAL_XXX变量,除了LOCAL_PATH

  4. include $(CLEAR_VARS)

  5. # 设置需要需要编译的源文件

  6. LOCAL_SRC_FILES:= \

  7. main_cameraserver.cpp

  8. # 设置需要链接的动态库

  9. LOCAL_SHARED_LIBRARIES := \

  10. libcameraservice \

  11. libcutils \

  12. libutils \

  13. libbinder \

  14. libcamera_client

  15. # 设置编译出来的目标文件名

  16. LOCAL_MODULE:= cameraserver

  17. LOCAL_32_BIT_ONLY := true

  18. # gcc编译参数的设置

  19. LOCAL_CFLAGS += -Wall -Wextra -Werror -Wno-unused-parameter

  20. # 设置rc文件

  21. LOCAL_INIT_RC := cameraserver.rc

  22. # 指定要编译成可执行程序文件

  23. include $(BUILD_EXECUTABLE)

 

BUILD_EXECUTABLE定义在

build\core\config.mk


 
  1. CLEAR_VARS:= $(BUILD_SYSTEM)/clear_vars.mk

  2. BUILD_HOST_STATIC_LIBRARY:= $(BUILD_SYSTEM)/host_static_library.mk

  3. BUILD_HOST_SHARED_LIBRARY:= $(BUILD_SYSTEM)/host_shared_library.mk

  4. BUILD_STATIC_LIBRARY:= $(BUILD_SYSTEM)/static_library.mk

  5. BUILD_SHARED_LIBRARY:= $(BUILD_SYSTEM)/shared_library.mk

  6. BUILD_EXECUTABLE:= $(BUILD_SYSTEM)/executable.mk

  7. BUILD_HOST_EXECUTABLE:= $(BUILD_SYSTEM)/host_executable.mk

  8. BUILD_PACKAGE:= $(BUILD_SYSTEM)/package.mk

所以include $(BUILD_EXECUTABLE) 实际上是 include build/core/executable.mk

 

我们继续看executable.mk 做了什么事

差不多是做了一大堆的设置和检查工作,最后include executable_internal.mk

build\core\executable.mk


 
  1. # check if non-preferred arch is supported

  2. include $(BUILD_SYSTEM)/module_arch_supported.mk

  3. ifeq ($(my_module_arch_supported),true)

  4. # non-preferred arch is supported

  5. OVERRIDE_BUILT_MODULE_PATH :=

  6. LOCAL_BUILT_MODULE :=

  7. LOCAL_INSTALLED_MODULE :=

  8. LOCAL_INTERMEDIATE_TARGETS :=

  9. include $(BUILD_SYSTEM)/executable_internal.mk

  10. endif

我们继续往下看executable_internal.mk 做了什么事

build\core\executable_internal.mk


 
  1. ifeq ($(LOCAL_FORCE_STATIC_EXECUTABLE),true) #这里表示编译静态可执行程序

  2. $(linked_module): $(my_target_crtbegin_static_o) $(all_objects) $(all_libraries) $(my_target_crtend_o)

  3. $(transform-o-to-static-executable)

  4. $(PRIVATE_POST_LINK_CMD)

  5. else #否则编译动态可执行程序,需要连接动态库

  6. $(linked_module): $(my_target_crtbegin_dynamic_o) $(all_objects) $(all_libraries) $(my_target_crtend_o)

  7. $(transform-o-to-executable)

  8. $(PRIVATE_POST_LINK_CMD)

  9. 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


 
  1. define transform-o-to-executable

  2. @echo "target Executable: $(PRIVATE_MODULE) ($@)"

  3. @mkdir -p $(dir $@)

  4. $(transform-o-to-executable-inner)

  5. endef

makefile中的define endef可以认为它就是定义了一个函数,里面的内容就是执行的命令。
 


 
  1. define transform-o-to-executable-inner

  2. $(hide) $(PRIVATE_CXX) -pie \

  3. -nostdlib -Bdynamic \

  4. -Wl,-dynamic-linker,$(PRIVATE_LINKER) \

  5. -Wl,--gc-sections \

  6. -Wl,-z,nocopyreloc \

  7. $(PRIVATE_TARGET_GLOBAL_LD_DIRS) \

  8. -Wl,-rpath-link=$(PRIVATE_TARGET_OUT_INTERMEDIATE_LIBRARIES) \

  9. $(PRIVATE_TARGET_CRTBEGIN_DYNAMIC_O) \

  10. $(PRIVATE_ALL_OBJECTS) \

  11. -Wl,--whole-archive \

  12. $(call normalize-target-libraries,$(PRIVATE_ALL_WHOLE_STATIC_LIBRARIES)) \

  13. -Wl,--no-whole-archive \

  14. $(if $(PRIVATE_GROUP_STATIC_LIBRARIES),-Wl$(comma)--start-group) \

  15. $(call normalize-target-libraries,$(PRIVATE_ALL_STATIC_LIBRARIES)) \

  16. $(if $(PRIVATE_GROUP_STATIC_LIBRARIES),-Wl$(comma)--end-group) \

  17. $(if $(filter true,$(NATIVE_COVERAGE)),$(PRIVATE_TARGET_COVERAGE_LIB)) \

  18. $(PRIVATE_TARGET_LIBATOMIC) \

  19. $(PRIVATE_TARGET_LIBGCC) \

  20. $(call normalize-target-libraries,$(PRIVATE_ALL_SHARED_LIBRARIES)) \

  21. -o $@ \

  22. $(PRIVATE_TARGET_GLOBAL_LDFLAGS) \

  23. $(PRIVATE_LDFLAGS) \

  24. $(PRIVATE_TARGET_CRTEND_O) \

  25. $(PRIVATE_LDLIBS)

  26. 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包含的库和必需的库,用空格分开。

$@ 是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

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值