讨论完LOCAL_PATH,我们紧接着来看看LOCAL_SRC_FILES。
一、LOCAL_SRC_FILES
LOCAL_SRC_FILES := acp.c
LOCAL_SRC_FILES变量的意思见名知意,很明显是用来记录当前模块的源文件列表的一个变量。
这里是他的赋值,我们下面来看看他的使用的地方。在build/core/binary.mk中有如下的部分:
###########################################################
## C: Compile .c files to .o.
###########################################################
c_arm_sources := $(patsubst %.c.arm,%.c,$(filter %.c.arm,$(LOCAL_SRC_FILES)))
c_arm_objects := $(addprefix $(intermediates)/,$(c_arm_sources:.c=.o))
c_normal_sources := $(filter %.c,$(LOCAL_SRC_FILES))
c_normal_objects := $(addprefix $(intermediates)/,$(c_normal_sources:.c=.o))
$(c_arm_objects): PRIVATE_ARM_MODE := $(arm_objects_mode)
$(c_arm_objects): PRIVATE_ARM_CFLAGS := $(arm_objects_cflags)
$(c_normal_objects): PRIVATE_ARM_MODE := $(normal_objects_mode)
$(c_normal_objects): PRIVATE_ARM_CFLAGS := $(normal_objects_cflags)
c_objects := $(c_arm_objects) $(c_normal_objects)
ifneq ($(strip $(c_objects)),)
$(c_objects): $(intermediates)/%.o: $(TOPDIR)$(LOCAL_PATH)/%.c $(yacc_cpps) $(proto_generated_headers) $(LOCAL_ADDITIONAL_DEPENDENCIES)
$(transform-$(PRIVATE_HOST)c-to-o)
-include $(c_objects:%.o=%.P)
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的赋值:
build/core/host_java_library.mk:intermediates := $(call local-intermediates-dir)
build/core/base_rules.mk:intermediates := $(call local-intermediates-dir)
build/core/dynamic_binary.mk:guessed_intermediates := $(call local-intermediates-dir)
build/core/java.mk:intermediates := $(call local-intermediates-dir)
即,他们的都是调用local-intermediates-dir函数获取当前的intermediates的值
在build/core/definitions.mk中有local-intermediates-dir函数的定义:
# Uses LOCAL_MODULE_CLASS, LOCAL_MODULE, and LOCAL_IS_HOST_MODULE
# to determine the intermediates directory.
#
# $(1): if non-empty, force the intermediates to be COMMON
define local-intermediates-dir
$(strip \
$(if $(strip $(LOCAL_MODULE_CLASS)),, \
$(error $(LOCAL_PATH): LOCAL_MODULE_CLASS not defined before call to local-intermediates-dir)) \
$(if $(strip $(LOCAL_MODULE)),, \
$(error $(LOCAL_PATH): LOCAL_MODULE not defined before call to local-intermediates-dir)) \
$(call intermediates-dir-for,$(LOCAL_MODULE_CLASS),$(LOCAL_MODULE),$(LOCAL_IS_HOST_MODULE),$(1)) \
)
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
###########################################################
## The intermediates directory. Where object files go for
## a given target. We could technically get away without
## the "_intermediates" suffix on the directory, but it's
## nice to be able to grep for that string to find out if
## anyone's abusing the system.
###########################################################
# $(1): target class, like "APPS"
# $(2): target name, like "NotePad"
# $(3): if non-empty, this is a HOST target.
# $(4): if non-empty, force the intermediates to be COMMON
define intermediates-dir-for
$(strip \
$(eval _idfClass := $(strip $(1))) \
$(if $(_idfClass),, \
$(error $(LOCAL_PATH): Class not defined in call to intermediates-dir-for)) \
$(eval _idfName := $(strip $(2))) \
$(if $(_idfName),, \
$(error $(LOCAL_PATH): Name not defined in call to intermediates-dir-for)) \
$(eval _idfPrefix := $(if $(strip $(3)),HOST,TARGET)) \
$(if $(filter $(_idfPrefix)-$(_idfClass),$(COMMON_MODULE_CLASSES))$(4), \
$(eval _idfIntBase := $($(_idfPrefix)_OUT_COMMON_INTERMEDIATES)) \
, \
$(eval _idfIntBase := $($(_idfPrefix)_OUT_INTERMEDIATES)) \
) \
$(_idfIntBase)/$(_idfClass)/$(_idfName)_intermediates \
)
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)为空,在这里估计判断结果
应该为假,即应该执行
$(eval _idfIntBase := $($(_idfPrefix)_OUT_INTERMEDIATES))
下面我就看看这个$(HOST_OUT_INTERMEDIATES
)到底是一个什么变量。
在build/core/envsetup.mk中有明确的定义:
HOST_OUT_INTERMEDIATES := $(HOST_OUT)/obj
HOST_OUT也在本文件中定义:
HOST_OUT := $(HOST_OUT_$(HOST_BUILD_TYPE))
HOST_BUILD_TYPE默认值为release:
# the host build defaults to release, and it must be release or debug
ifeq ($(HOST_BUILD_TYPE),)
HOST_BUILD_TYPE := release
endif
因此,
HOST_OUT := $(HOST_OUT_release)
而HOST_OUT_release的定义如下:
HOST_OUT_release := $(HOST_OUT_ROOT_release)/$(HOST_OS)-$(HOST_ARCH)
HOST_OUT_ROOT_release的定义:
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的编译部分
c_objects := $(c_arm_objects) $(c_normal_objects)
ifneq ($(strip $(c_objects)),)
$(c_objects): $(intermediates)/%.o: $(TOPDIR)$(LOCAL_PATH)/%.c $(yacc_cpps) $(proto_generated_headers) $(LOCAL_ADDITIONAL_DEPENDENCIES)
$(transform-$(PRIVATE_HOST)c-to-o)
-include $(c_objects:%.o=%.P)
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)函数的具体操作,我们暂时不讲,留待后续分析
。
相关推荐
blink-led-stm8s103-makefile-master_stm32_labview_blink_源码.zip
需要替换qt-creator-opensource-src-4.4.1/src/libs/3rdparty/botan/目录下的botan.cpp与botan.h文件。 这里的资源就是需要替换的两个文件。 替换后,删除之前编译qtcreator时make过程中产生的中间文件,重新编译...
u-boot-1.1.6__Makefile.new
conan 详解 - (makefile)_files.zip
跟我一起写Makefile和Shell的主要命令,对于初学Linux开发非常有用
lcd bling using stm32 and PId
linux unix makefile 编写指南
1、将makefile中的 CROSS =/usr/local/arm/2.95.3/bin/arm-linux- CFLAGS+=-I/usr/local/src/2.4.18-rmk7/include CFLAGS+=-I/usr/local/src/2.4.18-rmk7/include/linux CFLAGS+=-I/usr/local/arm/2.95.3/arm-linux/...
Blink表演项目代码--KinectV2舞者手势姿势分类--编写Arduino代码_C++_Makefile_下载.zip
一套IM完整的UI实现方案_Objective-C_Makefile_下载.zip
Rust重写了pythonweechat-matrix脚本。_Rust_Makefile_下载.zip
uboot编译中的Makefile的解读
r16_project_ov2640_20160120不能编译uboot_验证版本parrotv1.0_20170302_1418没有外层目录.7z 开发板:SC3817。全志R16平台点亮OV2640。 切记:一定不要编译uboot。否则,你的LCD没有显示!哈哈哈……
这份文档中用到的所有程序已经被打包并压缩成一个tar.gz文件。以下是这个压缩包解压缩后的目录结构: ncurses | |----> JustForFun -- ...对于每一个示例,我都给出了这些程序调用NCURSES目录下相关文件的路径名。
Cmake 并不直接建构出最终的软件,而是产生标准的建构档(如 Unix 的 Makefile 或 Windows Visual C++ 的 projects/workspaces),然后再依一般的建构方式使用。这使得熟悉某个集成开发环境(IDE)的开发者可以用...
Bazel是一个类似于Make的编译工具,是Google为其内部软件开发的特点量身定制的工具,如今Google...Google认为直接用Makefile构建软件速度太慢,结果不可靠,所以构建了一个新的工具叫做Bazel,Bazel的规则层级更高。
Linux/unix makefile 的详细介绍,教你如何编写Makefile文件
1、修改Makefile文件的交叉编译工具为你的交叉编译工具即可: #TOOLCHAIN= arm-linux- //注释掉 TOOLCHAIN= arm-linux-gnueabihf- //修改为你的交叉编译工具 2、执行编译 make 即可在当前目录得到fastboot工具,...
open DDS的补丁包没有makefile文件集成的功能,补丁包于安装包一起解压配置环境
在src/目录下有两个子目录mpeg2enc/和mpeg2dec/,其中包含了编码器和解码器 的源代码,以及在VC下编译过的可执行程序。par/目录下给出了一组可在每秒25和30帧 的速率下进行MPEG-2和MPEG-1编码的编码器参数文件。 ...