欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

android build system

程序员文章站 2024-03-18 10:25:31
...

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
$
android build system

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