对linux编译模块make -C path_to_kernel_src M=`pwd` modules的理解

本文深入探讨了M=`pwd`在Linux内核模块编译过程中的具体作用及其背后的实现机制,解释了KBUILD_EXTMOD变量如何帮助指定模块路径。

    这篇文章侧重点在M=`pwd`的个人理解,不足之处希望大神斧正,谢谢。

    一直以为M=`pwd`是make的参数,可是这个参数也写的够简单。最近重看<跟我写makefile>时,发现常有这样的makefile内容

# Use 'make V=1' to see the full commands
ifdef V
ifeq ("$(origin V)", "command line")
KBUILD_VERBOSE = $(V)
endif
endif
    出于好奇,make时顺手输入make V=1,接下来就是被整屛的编译信息包围。在makefile中,ifdef/endif用于判断变量是否定义,而origin函数则告诉make,这个变量是来自命令行输入还是文件中定义。那么,整句话被理解为:如果定义了变量V,并且V来自于命令行,那么编译时将输出详细信息。

    由此,想到编译模块时,也会传入M=`pwd`,虽然网上清一色的解释,这是指定模块路径的参数,但总觉得有失严谨(当然,这篇文章也未必严谨)。百度了诺干页,终于整理出了我想要的答案:

    在内核makefile中有如下一段(网摘,暂未考证,不过可信度很高)

# Use make M=dir to specify directory of external module to build
# Old syntax make ... SUBDIRS=$PWD is still supported
# Setting the environment variable KBUILD_EXTMOD take precedence
ifdef SUBDIRS
KBUILD_EXTMOD ?= $(SUBDIRS)
endif

ifeq ("$(origin M)", "command line")
KBUILD_EXTMOD := $(M)
endif
    从这段内容理解如果make传入的命令行变量存在且是M,那么,变量KBUILD_EXTMOD变为变量M的值,即`pwd`。

    从变量名可推知,这极有可能是编译外部模块相关的变量,以此为字眼继续搜索。网上有人列举编译内核时涉及的环境变量时提到

KBUILD_EXTMOD:当编译外部模块时设置内核源码查找路径,目录可以用以下几种方式指定
 1、在命令行用M=path
 2、环境变量KBUILD_EXTMOD
 3、环境变量SUBDIRS
 用M=path会覆盖其它两种情况
    从这至少可以确定,我的猜测还算靠谱,但是还是没有找到如何将代码编译成模块。那就继续搜索,最终在一篇名为< Linux Kbuild工作原理详细分析(以DVSDK生成PowerVR显卡模块为例)>文章中找到相关线索。

    按作者原文,编译模块分2个阶段(其实这个在ldd上也提到,反正我一直不理解):step 1:编译生成mod.o文件;step 2:好像涉及到模块链接和生成sym信息。2.6以后的内核编译完模块后都会为模块链接生成符号信息,其中涉及到Makefile.modpost,关于这个的作用可以参考存在依赖关系的内核模块的编译问题 。看过这篇文章,再结合kbuild在根目录下寻找目标modules的代码:

PHONY += modules
modules: $(vmlinux-dirs) $(if $(KBUILD_BUILTIN),vmlinux)
	$(Q)$(AWK) '!x[$$0]++' $(vmlinux-dirs:%=$(objtree)/%/modules.order) > 

$(objtree)/modules.order
	@$(kecho) '  Building modules, stage 2.';
	$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost
	$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.fwinst obj=firmware __fw_modbuild
最后第二句是make -f Makefile.modpost,用这种非标准名字的makefile文件执行代码编译,而scripts/Makefile.modpost中这句

include $(if $(wildcard $(KBUILD_EXTMOD)/Kbuild), \
             $(KBUILD_EXTMOD)/Kbuild, $(KBUILD_EXTMOD)/Makefile)
意思是如果在KBUILD_EXTMOD路径下找到Kbuild就include $(KBUILD_EXTMOD)/Kbuild,否则include $(KBUILD_EXTMOD)/Makefile。这个路径正好包括我们自己的代码路径,因此,模块顺利的被编译链接。





    

TARGET := mpp FW_SRC := mpp_proc.c FW_SRC += vb_proc.c log_proc.c sys_proc.c mpp_proc_common.c \ vi_proc.c vpss_proc.c venc_proc.c vdec_proc.c \ ai_proc.c ao_proc.c aenc_proc.c adec_proc.c \ vgs_proc.c cpm_proc.c region_proc.c media_mm_proc.c ifeq ($(ENABLE_MPP_TRACE),1) FW_SRC += trace_proc.c endif ifneq ($(findstring $(TARGET_CHIPSERIES), TX5335AX TX5368AX TX5339AX),) # $(info ----- proc TARGET_CHIPSERIES 52) # ccflags-y += -DCVE_PROC_BUILD # ccflags-y += -DDMA_PROC_BUILD FW_SRC += cve_proc.c FW_SRC += dma_proc.c else ifneq ($(findstring $(TARGET_CHIPSERIES), TX5336EX TX5256EX),) # $(info ------ proc TARGET_CHIPSERIES 53) # ccflags-y += -DAMR_PROC_BUILD # ccflags-y += -DCVE_PROC_BUILD # ccflags-y += -DDMA_PROC_BUILD # ccflags-y += -DBIS_PROC_BUILD ccflags-y += -DDX5336 -DVO_PROC_BUILD -DGDC_PROC_BUILD FW_SRC += cve_proc.c FW_SRC += bis_proc.c FW_SRC += gdc_proc.c FW_SRC += dma_proc.c FW_SRC += vo_proc.c else ifneq ($(findstring $(TARGET_CHIPSERIES), TX5215BX ),) # ccflags-y += -DAMR_PROC_BUILD # ccflags-y += -DCVE_PROC_BUILD # ccflags-y += -DDMA_PROC_BUILD # ccflags-y += -DDMA_PROC_BUILD ccflags-y += -DDX5215 -DVO_PROC_BUILD FW_SRC += cve_proc.c FW_SRC += dma_proc.c FW_SRC += vo_proc.c else ifneq ($(findstring $(TARGET_CHIPSERIES), TX5239BX TX5239CX),) # $(info ------ proc TARGET_CHIPSERIES 56) # ccflags-y += -DAMR_PROC_BUILD # ccflags-y += -DCVE_PROC_BUILD # ccflags-y += -DDMA_PROC_BUILD ccflags-y += -DTX5239 FW_SRC += cve_proc.c FW_SRC += dma_proc.c else ifneq ($(findstring $(TARGET_CHIPSERIES), TX5112DX),) # $(info ------ proc TARGET_CHIPSERIES 57) # ccflags-y += -DAMR_PROC_BUILD # ccflags-y += -DDMA_PROC_BUILD ccflags-y += -DDX5112 FW_SRC += cve_proc.c FW_SRC += dma_proc.c else ifneq ($(findstring $(TARGET_CHIPSERIES), TX5239DX),) # $(info ------ proc TARGET_CHIPSERIES 57) # ccflags-y += -DAMR_PROC_BUILD # ccflags-y += -DDMA_PROC_BUILD ccflags-y += -DTX5239 FW_SRC += cve_proc.c FW_SRC += dma_proc.c else ifneq ($(findstring $(TARGET_CHIPSERIES), TX5110FPGA TX5110FX),) # $(info ------ proc TARGET_CHIPSERIES 57B) # ccflags-y += -DAMR_PROC_BUILD # ccflags-y += -DDMA_PROC_BUILD ccflags-y += -DDX5110 FW_SRC += cve_proc.c FW_SRC += dma_proc.c endif FW_SRC_OBJ := $(FW_SRC:.c=.o) obj-m := $(TARGET).o $(TARGET)-y += $(FW_SRC_OBJ) ccflags-y += -fdebug-prefix-map=$(CURDIR)=. PWD := $(shell pwd) ccflags-y += -I$(PWD)/../libs/mpp/common/mpp_sys/inc \ -I$(PWD)/../libs/mpp/common/include/ \ -I$(PWD)/../libs/mpp/include/ \ -I$(PWD)/../libs/drv/audio/codec/ts_codec/ ccflags-y += -DUSE_MPP_HEADER -Wno-error=unused-variable ifeq ($(ENABLE_MPP_TRACE),1) ccflags-y += -DENABLE_MPP_TRACE endif modules: @echo "TARGET_CHIPSERIES:$(TARGET_CHIPSERIES)" @echo "ENABLE_MPP_TRACE:$(ENABLE_MPP_TRACE)" $(MAKE) -C $(TARGET_KERNEL_DIR) M=$(PWD) modules clear: @rm -f *.o *.cmd *.mod.c @rm -rf *~ core .depend .tmp_versions Module.symvers modules.order -f @rm -f .*ko.cmd .*.o.cmd .*.o.d @rm -f *.unsigned clean: @rm -f $(TARGET).ko @make -C $(TARGET_KERNEL_DIR) M=$(PWD) clean 同一套代码,该模块编译的ko在不同路径下为啥会不一样,以上是makefile脚本,
08-15
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值