现在的位置: 首页 > 综合 > 正文

深入浅出Android makefile(3)–LOCAL_SRC_FILES

2013年11月23日 ⁄ 综合 ⁄ 共 7328字 ⁄ 字号 评论关闭

讨论完LOCAL_PATH,我们紧接着来看看LOCAL_SRC_FILES。


一、LOCAL_SRC_FILES
Makefile代码  收藏代码
  1. LOCAL_SRC_FILES := acp.c  

LOCAL_SRC_FILES变量的意思见名知意,很明显是用来记录当前模块的源文件列表的一个变量。


这里是他的赋值,我们下面来看看他的使用的地方。在build/core/binary.mk中有如下的部分:
Makefile代码  收藏代码
  1. ###########################################################  
  2. ## C: Compile .c files to .o.  
  3. ###########################################################  
  4.   
  5. c_arm_sources    := $(patsubst %.c.arm,%.c,$(filter %.c.arm,$(LOCAL_SRC_FILES)))  
  6. c_arm_objects    := $(addprefix $(intermediates)/,$(c_arm_sources:.c=.o))  
  7.   
  8. c_normal_sources := $(filter %.c,$(LOCAL_SRC_FILES))  
  9. c_normal_objects := $(addprefix $(intermediates)/,$(c_normal_sources:.c=.o))  
  10.   
  11. $(c_arm_objects):    PRIVATE_ARM_MODE := $(arm_objects_mode)  
  12. $(c_arm_objects):    PRIVATE_ARM_CFLAGS := $(arm_objects_cflags)  
  13. $(c_normal_objects): PRIVATE_ARM_MODE := $(normal_objects_mode)  
  14. $(c_normal_objects): PRIVATE_ARM_CFLAGS := $(normal_objects_cflags)  
  15.   
  16. c_objects        := $(c_arm_objects) $(c_normal_objects)  
  17.   
  18. ifneq ($(strip $(c_objects)),)  
  19. $(c_objects): $(intermediates)/%.o: $(TOPDIR)$(LOCAL_PATH)/%.c $(yacc_cpps) $(proto_generated_headers) $(LOCAL_ADDITIONAL_DEPENDENCIES)  
  20.      $(transform-$(PRIVATE_HOST)c-to-o)  
  21. -include $(c_objects:%.o=%.P)  
  22. endif  

 

分析上面的代码,
1. 我们首先从LOCAL_SRC_FILES中得到所有的C文件
     c_normal_sources value acp.c
2. 定义一个变量,c_normal_objects,用来表示生成的.o文件的路径
     c_normal_objects value out/host/linux-x86/obj/EXECUTABLES/acp_intermediates/acp.o
其中,$(c_normal_sources:.c=.o)会返回acp.o,那么c_normal_objects的关键就是$(intermediates)变量

二、intermediates
通过查找,我们可以发现在以下地方有intermediates的赋值:
Makefile代码  收藏代码
  1. build/core/host_java_library.mk:intermediates := $(call local-intermediates-dir)  
  2. build/core/base_rules.mk:intermediates := $(call local-intermediates-dir)  
  3. build/core/dynamic_binary.mk:guessed_intermediates := $(call local-intermediates-dir)  
  4. build/core/java.mk:intermediates := $(call local-intermediates-dir)  
即,他们的都是调用local-intermediates-dir函数获取当前的intermediates的值

在build/core/definitions.mk中有local-intermediates-dir函数的定义:
Makefile代码  收藏代码
  1. # Uses LOCAL_MODULE_CLASS, LOCAL_MODULE, and LOCAL_IS_HOST_MODULE  
  2. # to determine the intermediates directory.  
  3. #  
  4. # $(1): if non-empty, force the intermediates to be COMMON  
  5. define local-intermediates-dir  
  6. $(strip \  
  7.     $(if $(strip $(LOCAL_MODULE_CLASS)),, \  
  8.         $(error $(LOCAL_PATH): LOCAL_MODULE_CLASS not defined before call to local-intermediates-dir)) \  
  9.     $(if $(strip $(LOCAL_MODULE)),, \  
  10.         $(error $(LOCAL_PATH): LOCAL_MODULE not defined before call to local-intermediates-dir)) \  
  11.     $(call intermediates-dir-for,$(LOCAL_MODULE_CLASS),$(LOCAL_MODULE),$(LOCAL_IS_HOST_MODULE),$(1)) \  
  12. )  
  13. endef  
根据注释,我们知道 local-intermediates-dir的定义会依赖于LOCAL_MODULE_CLASS, LOCAL_MODULE, 和 LOCAL_IS_HOST_MODULE这三个变量的值。
我们先通过添加打印的方式,得到如下三个变量的值:
LOCAL_MODULE_CLASS value EXECUTABLES
LOCAL_MODULE value acp
LOCAL_IS_HOST_MODULE value true
其中,LOCAL_MODULE 的值是acp,这个肯定的是没问题的,因为在acp模块的Android.mk文件中有明确的定义:LOCAL_MODULE := acp
那LOCAL_MODULE_CLASS 为什么是EXECUTABLES呢?我们这里先猜一下,估计是和最后一句include $(BUILD_HOST_EXECUTABLE )有关,
同样,LOCAL_IS_HOST_MODULE 为true,估计也是和include $(BUILD_HOST _EXECUTABLE)有关了。

我们还是先回到 local-intermediates-dir函数中,其中前两个判断是判断是否定义LOCAL_MODULE_CLASS和LOCAL_MODULE,如果未空,则直接报错,这里也就说明了在每一个编译模块中(即include $(CLEAR_VARS)和include $(BUILD_XXX)之间)必须定义LOCAL_MODULE的值。

因此,如果LOCAL_MODULE_CLASS和LOCAL_MODULE都不为空时,则执行intermediates-dir-for这个函数,$(LOCAL_MODULE_CLASS),$(LOCAL_MODULE),$(LOCAL_IS_HOST_MODULE)还有 local-intermediates-dir函数的第一个参数 $(1)会作为参数传给intermediates-dir-for函数。根据上面intermediates的赋值部分的代码,我们知道调用local-intermediates-dir函数时没有传递任何参数,因此此时的$(1)即为空,传给intermediates-dir-for函数的也就只有上述的3个参数。

三、 intermediates-dir-for
下面我们来看intermediates-dir-for
Makefile代码  收藏代码
  1. ###########################################################  
  2. ## The intermediates directory.  Where object files go for  
  3. ## a given target.  We could technically get away without  
  4. ## the "_intermediates" suffix on the directory, but it's  
  5. ## nice to be able to grep for that string to find out if  
  6. ## anyone's abusing the system.  
  7. ###########################################################  
  8.   
  9. # $(1): target class, like "APPS"  
  10. # $(2): target name, like "NotePad"  
  11. # $(3): if non-empty, this is a HOST target.  
  12. # $(4): if non-empty, force the intermediates to be COMMON  
  13. define intermediates-dir-for  
  14. $(strip \  
  15.     $(eval _idfClass := $(strip $(1))) \  
  16.     $(if $(_idfClass),, \  
  17.         $(error $(LOCAL_PATH): Class not defined in call to intermediates-dir-for)) \  
  18.     $(eval _idfName := $(strip $(2))) \  
  19.     $(if $(_idfName),, \  
  20.         $(error $(LOCAL_PATH): Name not defined in call to intermediates-dir-for)) \  
  21.     $(eval _idfPrefix := $(if $(strip $(3)),HOST,TARGET)) \  
  22.     $(if $(filter $(_idfPrefix)-$(_idfClass),$(COMMON_MODULE_CLASSES))$(4), \  
  23.         $(eval _idfIntBase := $($(_idfPrefix)_OUT_COMMON_INTERMEDIATES)) \  
  24.       , \  
  25.         $(eval _idfIntBase := $($(_idfPrefix)_OUT_INTERMEDIATES)) \  
  26.      ) \  
  27.     $(_idfIntBase)/$(_idfClass)/$(_idfName)_intermediates \  
  28. )  
  29. endef  
根据注释,我们可以知道$(1),$(2),$(3),$(4)这4个参数的意义。
而以下三行则是使用$(1),$(2),$(3)来定义三个临时变量:_idfClass,_idfName 和_idfPrefix 
$(eval _idfClass := $(strip $(1))) 
$(eval _idfName := $(strip $(2)))
$(eval _idfPrefix := $(if $(strip $(3)),HOST,TARGET))
在本例中这三个临时变量的值则为:EXECUTABLES、acp和HOST

下面关键的一个临时变量是_idfIntBase ,我们发现无论$(if $(filter $(_idfPrefix)-$(_idfClass),$(COMMON_MODULE_CLASSES))$(4)是真还是假,
_idfIntBase 的值不是$(HOST_OUT_COMMON_INTERMEDIATES)就是$(HOST_OUT_INTERMEDIATES),因为上面调用时$(4)为空,在这里估计判断结果 应该为假,即应该执行

Makefile代码  收藏代码
  1. $(eval _idfIntBase := $($(_idfPrefix)_OUT_INTERMEDIATES))  
下面我就看看这个$(HOST_OUT_INTERMEDIATES )到底是一个什么变量。
在build/core/envsetup.mk中有明确的定义:
Makefile代码  收藏代码
  1. HOST_OUT_INTERMEDIATES := $(HOST_OUT)/obj   
HOST_OUT也在本文件中定义:
Makefile代码  收藏代码
  1. HOST_OUT := $(HOST_OUT_$(HOST_BUILD_TYPE))   
HOST_BUILD_TYPE默认值为release:
Makefile代码  收藏代码
  1. # the host build defaults to release, and it must be release or debug  
  2. ifeq ($(HOST_BUILD_TYPE),)  
  3. HOST_BUILD_TYPE := release  
  4. endif   
因此,
Makefile代码  收藏代码
  1. HOST_OUT := $(HOST_OUT_release)  

而HOST_OUT_release的定义如下:

Makefile代码  收藏代码
  1. HOST_OUT_release := $(HOST_OUT_ROOT_release)/$(HOST_OS)-$(HOST_ARCH)  
HOST_OUT_ROOT_release的定义:
Makefile代码  收藏代码
  1. HOST_OUT_ROOT_release := $(OUT_DIR)/host   
在Linux上编译,因此HOST_OS := linux ,而我们的机器采用的是Intel Xeon X3440 CPU,即x86架构,因此HOST_ARCH:= x86

经过上述分析,
$(HOST_OUT_INTERMEDIATES ) =out/host/linux-x86/obj
intermediates-dir-for 函数返回out/host/linux-x86/ob/EXECUTABLES/acp_intermediates
local-intermediates-dir 函数返回out/host/linux-x86/ob/EXECUTABLES/acp_intermediates
intermediates 变量的值为out/host/linux-x86/ob/EXECUTABLES/acp_intermediates
c_normal_objects 变量的值为out/host/linux-x86/obj/EXECUTABLES/acp_intermediates/acp.o

四、c_objects
下面我们回到LOCAL_SRC_FILES的编译部分
Makefile代码  收藏代码
  1.  c_objects        := $(c_arm_objects) $(c_normal_objects)  
  2.   
  3. ifneq ($(strip $(c_objects)),)  
  4. $(c_objects): $(intermediates)/%.o: $(TOPDIR)$(LOCAL_PATH)/%.c $(yacc_cpps) $(proto_generated_headers) $(LOCAL_ADDITIONAL_DEPENDENCIES)  
  5.      $(transform-$(PRIVATE_HOST)c-to-o)  
  6. -include $(c_objects:%.o=%.P)  
  7. endif   
其中c_arm_objects为空,c_normal_objects 的值为out/host/linux-x86/obj/EXECUTABLES/acp_intermediates/acp.o
所以c_objects 的值也为out/host/linux-x86/obj/EXECUTABLES/acp_intermediates/acp.o
执行c_objects目标时,依赖$(intermediates)/%.o、 $(TOPDIR)$(LOCAL_PATH)/%.c、$(yacc_cpps) 、$(proto_generated_headers)和$(LOCAL_ADDITIONAL_DEPENDENCIES)
执行如下操作: $(transform-$(PRIVATE_HOST)c-to-o)
$(transform-$(PRIVATE_HOST)c-to-o)函数的具体操作,我们暂时不讲,留待后续分析 。

抱歉!评论已关闭.