• OpenWrt KernelPackage分析


    一. 前言

            KernelPackage是OpenWrt用来编译内核模块的函数,其实KernelPackage后面会调用BuildPackage,这里会一块将BuildPackage也顺便分析,本文以gpio-button-hotplug驱动模块为例,讲解整个编译过程。

            gpio-button-hotplug驱动编译命令如下:

    make package/kernel/gpio-button-hotplug/compile V=s

    二. 编译过程分析

    1. 编译命令运行分析

            由前面的文章介绍了subdir的作用后,我们可以知道,subdir会将make package/kernel/gpio-button-hotplug/compile V=s命令转换为如下命令:

    make -C package/kernel/gpio-button-hotplug compile

            make会去到package/kernel/gpio-button-hotplug下找Makfile,并且找其中的compile目标运行,gpio-button-hotplug的Makefile如下:

    1. include $(TOPDIR)/rules.mk
    2. include $(INCLUDE_DIR)/kernel.mk
    3. PKG_NAME:=gpio-button-hotplug
    4. PKG_RELEASE:=3
    5. PKG_LICENSE:=GPL-2.0
    6. include $(INCLUDE_DIR)/package.mk
    7. define KernelPackage/gpio-button-hotplug
    8. ......
    9. endef
    10. ......
    11. MAKE_OPTS:= $(KERNEL_MAKE_FLAGS) M="$(PKG_BUILD_DIR)"
    12. define Build/Compile
    13. $(MAKE) -C "$(LINUX_DIR)" $(MAKE_OPTS) modules
    14. endef
    15. $(eval $(call KernelPackage,gpio-button-hotplug))

            可以看到,这里会调用到KernelPackage,KernelPackage内容如下:

    1. include/kernel.mk:
    2. define KernelPackage
    3. NAME:=$(1)
    4. $(eval $(call Package/Default))
    5. $(eval $(call KernelPackage/Defaults))
    6. $(eval $(call KernelPackage/$(1)))
    7. $(eval $(call KernelPackage/$(1)/$(BOARD)))
    8. $(eval $(call KernelPackage/$(1)/$(BOARD)/$(if $(SUBTARGET),$(SUBTARGET),generic)))
    9. define Package/kmod-$(1)
    10. TITLE:=$(TITLE)
    11. SECTION:=kernel
    12. CATEGORY:=Kernel modules
    13. DESCRIPTION:=$(DESCRIPTION)
    14. EXTRA_DEPENDS:=kernel (=$(LINUX_VERSION)-$(LINUX_RELEASE)-$(LINUX_VERMAGIC))
    15. VERSION:=$(LINUX_VERSION)$(if $(PKG_VERSION),+$(PKG_VERSION))-$(if $(PKG_RELEASE),$(PKG_RELEASE),$(LINUX_RELEASE))
    16. PKGFLAGS:=$(PKGFLAGS)
    17. $(call KernelPackage/$(1))
    18. $(call KernelPackage/$(1)/$(BOARD))
    19. $(call KernelPackage/$(1)/$(BOARD)/$(if $(SUBTARGET),$(SUBTARGET),generic))
    20. endef
    21. ifdef KernelPackage/$(1)/conffiles
    22. define Package/kmod-$(1)/conffiles
    23. $(call KernelPackage/$(1)/conffiles)
    24. endef
    25. endif
    26. ifdef KernelPackage/$(1)/description
    27. define Package/kmod-$(1)/description
    28. $(call KernelPackage/$(1)/description)
    29. endef
    30. endif
    31. ifdef KernelPackage/$(1)/config
    32. define Package/kmod-$(1)/config
    33. $(call KernelPackage/$(1)/config)
    34. endef
    35. endif
    36. $(call KernelPackage/depends)
    37. $(call KernelPackage/hooks)
    38. ifneq ($(if $(filter-out %=y %=n %=m,$(KCONFIG)),$(filter m y,$(foreach c,$(filter-out %=y %=n %=m,$(KCONFIG)),$($(c)))),.),)
    39. define Package/kmod-$(1)/install
    40. @for mod in $$(call version_filter,$$(FILES)); do \
    41. if grep -q "$$$$$$$${mod##$(LINUX_DIR)/}" "$(LINUX_DIR)/modules.builtin"; then \
    42. echo "<<2>>" \
    43. echo "NOTICE: module '$$$$$$$$mod' is built-in."; \
    44. elif [ -e $$$$$$$$mod ]; then \
    45. echo "<<3>> $$$$$$$$mod" ; \
    46. mkdir -p $$(1)/$(MODULES_SUBDIR) ; \
    47. $(CP) -L $$$$$$$$mod $$(1)/$(MODULES_SUBDIR)/ ; \
    48. else \
    49. echo "ERROR: module '$$$$$$$$mod' is missing." >&2; \
    50. exit 1; \
    51. fi; \
    52. done;
    53. $(call ModuleAutoLoad,$(1),$$(1),$(filter-out 0-,$(word 1,$(AUTOLOAD))-),$(filter-out 0,$(word 2,$(AUTOLOAD))),$(sort $(wordlist 3,99,$(AUTOLOAD))))
    54. $(call KernelPackage/$(1)/install,$$(1))
    55. endef
    56. $(if $(CONFIG_PACKAGE_kmod-$(1)),
    57. else
    58. compile: $(1)-disabled
    59. $(1)-disabled:
    60. @echo "WARNING: kmod-$(1) is not available in the kernel config - generating empty package" >&2
    61. define Package/kmod-$(1)/install
    62. echo "<<1>>"
    63. true
    64. endef
    65. )
    66. endif
    67. $$(eval $$(call BuildPackage,kmod-$(1)))
    68. $$(IPKG_kmod-$(1)): $$(wildcard $$(call version_filter,$$(FILES)))
    69. endef

            细节先不分析,先找compile目标,可以看到KernelPackage下没有compile目标,原因如下:

    ifneq ($(if $(filter-out %=y %=n %=m,$(KCONFIG)),$(filter m y,$(foreach c,$(filter-out %=y %=n %=m,$(KCONFIG)),$($(c)))),.),)

            如上代码KCONFIG变量(package/kernel/linux/modules/*.mk才有定义)为空,所以以上表达式可以写为ifneq (.,),结果为真,执行上面的分支,上面分支没有compile目标。

            此时,就要到BuildPackage里面寻找了。BuildPackage代码如下:

    1. define BuildPackage
    2. $(eval $(Package/Default))
    3. $(eval $(Package/$(1)))
    4. ifdef DESCRIPTION
    5. $$(error DESCRIPTION:= is obsolete, use Package/PKG_NAME/description)
    6. endif
    7. ifndef Package/$(1)/description
    8. define Package/$(1)/description
    9. $(TITLE)
    10. endef
    11. endif
    12. BUILD_PACKAGES += $(1)
    13. $(STAMP_PREPARED): $$(if $(QUILT)$(DUMP),,$(call find_library_dependencies,$(1)))
    14. $(foreach FIELD, TITLE CATEGORY SECTION VERSION,
    15. ifeq ($($(FIELD)),)
    16. $$(error Package/$(1) is missing the $(FIELD) field)
    17. endif
    18. )
    19. $(if $(DUMP), \
    20. $(if $(CHECK),,$(Dumpinfo/Package)), \
    21. $(foreach target, \
    22. $(if $(Package/$(1)/targets),$(Package/$(1)/targets), \
    23. $(if $(PKG_TARGETS),$(PKG_TARGETS), ipkg) \
    24. ), $(BuildTarget/$(target)) \
    25. ) \
    26. )
    27. $(if $(PKG_HOST_ONLY),,$(call Build/DefaultTargets,$(1)))
    28. endef

            这里也没有compile目标。我们分析里面如下代码:

    $(if $(DUMP), \
        $(if $(CHECK),,$(Dumpinfo/Package)), \
        $(foreach target, \
          $(if $(Package/$(1)/targets),$(Package/$(1)/targets), \
            $(if $(PKG_TARGETS),$(PKG_TARGETS), ipkg) \
          ), $(BuildTarget/$(target)) \
        ) \
      )

            以上代码不难分析,结果为$(BuildTarget/ipkg)。接下来分析BuildTarget/ipkg,代码如下:

    1. define BuildTarget/ipkg
    2. ABIV_$(1):=$(call FormatABISuffix,$(1),$(ABI_VERSION))
    3. PDIR_$(1):=$(call FeedPackageDir,$(1))
    4. IPKG_$(1):=$$(PDIR_$(1))/$(1)$$(ABIV_$(1))_$(VERSION)_$(PKGARCH).ipk
    5. IDIR_$(1):=$(PKG_BUILD_DIR)/ipkg-$(PKGARCH)/$(1)
    6. KEEP_$(1):=$(strip $(call Package/$(1)/conffiles))
    7. ifeq ($(BUILD_VARIANT),$$(if $$(VARIANT),$$(VARIANT),$(BUILD_VARIANT)))
    8. do_install=
    9. ifdef Package/$(1)/install
    10. do_install=yes
    11. endif
    12. ifdef Package/$(1)/install-overlay
    13. do_install=yes
    14. endif
    15. ifdef do_install
    16. ifneq ($(CONFIG_PACKAGE_$(1))$(DEVELOPER),)
    17. IPKGS += $(1)
    18. $(_pkg_target)compile: $$(IPKG_$(1)) $(PKG_INFO_DIR)/$(1).provides $(PKG_BUILD_DIR)/.pkgdir/$(1).installed
    19. prepare-package-install: $$(IPKG_$(1))
    20. compile: $(STAGING_DIR_ROOT)/stamp/.$(1)_installed
    21. else
    22. $(if $(CONFIG_PACKAGE_$(1)),$$(info WARNING: skipping $(1) -- package not selected))
    23. endif
    24. .PHONY: $(PKG_INSTALL_STAMP).$(1)
    25. ifeq ($(CONFIG_PACKAGE_$(1)),y)
    26. compile: $(PKG_INSTALL_STAMP).$(1)
    27. endif
    28. $(PKG_INSTALL_STAMP).$(1): prepare-package-install
    29. echo "$(1)" >> $(PKG_INSTALL_STAMP)
    30. else
    31. $(if $(CONFIG_PACKAGE_$(1)),$$(warning WARNING: skipping $(1) -- package has no install section))
    32. endif
    33. endif
    34. DEPENDS:=$(call PKG_FIXUP_DEPENDS,$(1),$(DEPENDS))
    35. IDEPEND_$(1):=$$(call filter_deps,$$(DEPENDS))
    36. IDEPEND += $$(patsubst %,$(1):%,$$(IDEPEND_$(1)))
    37. $(FixupDependencies)
    38. $(FixupReverseDependencies)
    39. $(eval $(call BuildIPKGVariable,$(1),conffiles))
    40. $(eval $(call BuildIPKGVariable,$(1),preinst,,1))
    41. $(eval $(call BuildIPKGVariable,$(1),postinst,-pkg,1))
    42. $(eval $(call BuildIPKGVariable,$(1),prerm,-pkg,1))
    43. $(eval $(call BuildIPKGVariable,$(1),postrm,,1))
    44. $(PKG_BUILD_DIR)/.pkgdir/$(1).installed : export PATH=$$(TARGET_PATH_PKG)
    45. $(PKG_BUILD_DIR)/.pkgdir/$(1).installed: $(STAMP_BUILT)
    46. rm -rf $$@ $(PKG_BUILD_DIR)/.pkgdir/$(1)
    47. mkdir -p $(PKG_BUILD_DIR)/.pkgdir/$(1)
    48. $(call Package/$(1)/install,$(PKG_BUILD_DIR)/.pkgdir/$(1))
    49. $(call Package/$(1)/install_lib,$(PKG_BUILD_DIR)/.pkgdir/$(1))
    50. touch $$@
    51. $(STAGING_DIR_ROOT)/stamp/.$(1)_installed: $(PKG_BUILD_DIR)/.pkgdir/$(1).installed
    52. mkdir -p $(STAGING_DIR_ROOT)/stamp
    53. $(if $(ABI_VERSION),echo '$(ABI_VERSION)' | cmp -s - $(PKG_INFO_DIR)/$(1).version || { \
    54. echo '$(ABI_VERSION)' > $(PKG_INFO_DIR)/$(1).version; \
    55. $(foreach pkg,$(filter-out $(1),$(PROVIDES)), \
    56. cp $(PKG_INFO_DIR)/$(1).version $(PKG_INFO_DIR)/$(pkg).version; \
    57. ) \
    58. } )
    59. $(call locked,$(CP) $(PKG_BUILD_DIR)/.pkgdir/$(1)/. $(STAGING_DIR_ROOT)/,root-copy)
    60. touch $$@
    61. Package/$(1)/DEPENDS := $$(call mergelist,$$(foreach dep,$$(filter-out @%,$$(IDEPEND_$(1))),$$(dep)$$(call GetABISuffix,$$(dep))))
    62. ifneq ($$(EXTRA_DEPENDS),)
    63. Package/$(1)/DEPENDS := $$(EXTRA_DEPENDS)$$(if $$(Package/$(1)/DEPENDS),$$(comma) $$(Package/$(1)/DEPENDS))
    64. endif
    65. $(_define) Package/$(1)/CONTROL
    66. Package: $(1)$$(ABIV_$(1))
    67. Version: $(VERSION)
    68. $$(call addfield,Depends,$$(Package/$(1)/DEPENDS)
    69. )$$(call addfield,Conflicts,$$(call mergelist,$(CONFLICTS))
    70. )$$(call addfield,Provides,$$(call mergelist,$$(filter-out $(1)$$(ABIV_$(1)),$(PROVIDES)$$(if $$(ABIV_$(1)), $(1) $(foreach provide,$(PROVIDES),$(provide)$$(ABIV_$(1))))))
    71. )$$(call addfield,Alternatives,$$(call mergelist,$(ALTERNATIVES))
    72. )$$(call addfield,Source,$(SOURCE)
    73. )$$(call addfield,SourceName,$(1)
    74. )$$(call addfield,License,$(LICENSE)
    75. )$$(call addfield,LicenseFiles,$(LICENSE_FILES)
    76. )$$(call addfield,Section,$(SECTION)
    77. )$$(call addfield,Require-User,$(USERID)
    78. )$$(call addfield,SourceDateEpoch,$(PKG_SOURCE_DATE_EPOCH)
    79. )$$(if $$(ABIV_$(1)),ABIVersion: $$(ABIV_$(1))
    80. )$(if $(PKG_CPE_ID),CPE-ID: $(PKG_CPE_ID)
    81. )$(if $(filter hold,$(PKG_FLAGS)),Status: unknown hold not-installed
    82. )$(if $(filter essential,$(PKG_FLAGS)),Essential: yes
    83. )$(if $(MAINTAINER),Maintainer: $(MAINTAINER)
    84. )Architecture: $(PKGARCH)
    85. Installed-Size: 0
    86. $(_endef)
    87. $$(IPKG_$(1)) : export CONTROL=$$(Package/$(1)/CONTROL)
    88. $$(IPKG_$(1)) : export DESCRIPTION=$$(Package/$(1)/description)
    89. $$(IPKG_$(1)) : export PATH=$$(TARGET_PATH_PKG)
    90. $$(IPKG_$(1)) : export PKG_SOURCE_DATE_EPOCH:=$(PKG_SOURCE_DATE_EPOCH)
    91. $(PKG_INFO_DIR)/$(1).provides $$(IPKG_$(1)): $(STAMP_BUILT) $(INCLUDE_DIR)/package-ipkg.mk
    92. @rm -rf $$(IDIR_$(1)); \
    93. $$(call remove_ipkg_files,$(1),$$(call opkg_package_files,$(call gen_ipkg_wildcard,$(1))))
    94. mkdir -p $(PACKAGE_DIR) $$(IDIR_$(1))/CONTROL $(PKG_INFO_DIR)
    95. $(call Package/$(1)/install,$$(IDIR_$(1)))
    96. $(if $(Package/$(1)/install-overlay),mkdir -p $(PACKAGE_DIR) $$(IDIR_$(1))/rootfs-overlay)
    97. $(call Package/$(1)/install-overlay,$$(IDIR_$(1))/rootfs-overlay)
    98. -find $$(IDIR_$(1)) -name 'CVS' -o -name '.svn' -o -name '.#*' -o -name '*~'| $(XARGS) rm -rf
    99. @( \
    100. find $$(IDIR_$(1)) -name lib\*.so\* -or -name \*.ko | awk -F/ '{ print $$$$NF }'; \
    101. for file in $$(patsubst %,$(PKG_INFO_DIR)/%.provides,$$(IDEPEND_$(1))); do \
    102. if [ -f "$$$$file" ]; then \
    103. cat $$$$file; \
    104. fi; \
    105. done; $(Package/$(1)/extra_provides) \
    106. ) | sort -u > $(PKG_INFO_DIR)/$(1).provides
    107. $(if $(PROVIDES),@for pkg in $(filter-out $(1),$(PROVIDES)); do cp $(PKG_INFO_DIR)/$(1).provides $(PKG_INFO_DIR)/$$$$pkg.provides; done)
    108. $(CheckDependencies)
    109. $(RSTRIP) $$(IDIR_$(1))
    110. ifneq ($$(CONFIG_IPK_FILES_CHECKSUMS),)
    111. (cd $$(IDIR_$(1)); \
    112. ( \
    113. find . -type f \! -path ./CONTROL/\* -exec mkhash sha256 -n \{\} \; 2> /dev/null | \
    114. sed 's|\([[:blank:]]\)\./| \1/|' > $$(IDIR_$(1))/CONTROL/files-sha256sum \
    115. ) || true \
    116. )
    117. endif
    118. (cd $$(IDIR_$(1))/CONTROL; \
    119. ( \
    120. echo "$$$$CONTROL"; \
    121. printf "Description: "; echo "$$$$DESCRIPTION" | sed -e 's,^[[:space:]]*, ,g'; \
    122. ) > control; \
    123. chmod 644 control; \
    124. ( \
    125. echo "#!/bin/sh"; \
    126. echo "[ \"\$$$${IPKG_NO_SCRIPT}\" = \"1\" ] && exit 0"; \
    127. echo "[ -s "\$$$${IPKG_INSTROOT}/lib/functions.sh" ] || exit 0"; \
    128. echo ". \$$$${IPKG_INSTROOT}/lib/functions.sh"; \
    129. echo "default_postinst \$$$$0 \$$$$@"; \
    130. ) > postinst; \
    131. ( \
    132. echo "#!/bin/sh"; \
    133. echo "[ -s "\$$$${IPKG_INSTROOT}/lib/functions.sh" ] || exit 0"; \
    134. echo ". \$$$${IPKG_INSTROOT}/lib/functions.sh"; \
    135. echo "default_prerm \$$$$0 \$$$$@"; \
    136. ) > prerm; \
    137. chmod 0755 postinst prerm; \
    138. $($(1)_COMMANDS) \
    139. )
    140. ifneq ($$(KEEP_$(1)),)
    141. @( \
    142. keepfiles=""; \
    143. for x in $$(KEEP_$(1)); do \
    144. [ -f "$$(IDIR_$(1))/$$$$x" ] || keepfiles="$$$${keepfiles:+$$$$keepfiles }$$$$x"; \
    145. done; \
    146. [ -z "$$$$keepfiles" ] || { \
    147. mkdir -p $$(IDIR_$(1))/lib/upgrade/keep.d; \
    148. for x in $$$$keepfiles; do echo $$$$x >> $$(IDIR_$(1))/lib/upgrade/keep.d/$(1); done; \
    149. }; \
    150. )
    151. endif
    152. $(INSTALL_DIR) $$(PDIR_$(1))
    153. $(FAKEROOT) $(SCRIPT_DIR)/ipkg-build -m "$(FILE_MODES)" $$(IDIR_$(1)) $$(PDIR_$(1))
    154. @[ -f $$(IPKG_$(1)) ]
    155. $(1)-clean:
    156. $$(call remove_ipkg_files,$(1),$$(call opkg_package_files,$(call gen_ipkg_wildcard,$(1))))
    157. clean: $(1)-clean
    158. endef

            里面一段一段分析,如下:

    ifeq ($(BUILD_VARIANT),

    (if" role="presentation" style="text-align: center; position: relative;">(if
    (VARIANT),$$(VARIANT),$(BUILD_VARIANT)))
        do_install=
        ifdef Package/$(1)/install
          do_install=yes
        endif
        ifdef Package/$(1)/install-overlay
          do_install=yes
        endif
        ifdef do_install
          ifneq ($(CONFIG_PACKAGE_$(1))$(DEVELOPER),)
            IPKGS += $(1)
            $(_pkg_target)compile:
    (IPKG$(1))$(PKGINFODIR)/$(1).provides$(PKGBUILDDIR)/.pkgdir/$(1).installedpreparepackageinstall:" role="presentation" style="position: relative;">(IPKG$(1))$(PKGINFODIR)/$(1).provides$(PKGBUILDDIR)/.pkgdir/$(1).installedpreparepackageinstall:
    (IPKG_$(1))
            compile: $(STAGING_DIR_ROOT)/stamp/.$(1)_installed
          else
            $(if $(CONFIG_PACKAGE_$(1)),$$(info WARNING: skipping $(1) -- package not selected))
          endif

          .PHONY: $(PKG_INSTALL_STAMP).$(1)
          ifeq ($(CONFIG_PACKAGE_$(1)),y)
            compile: $(PKG_INSTALL_STAMP).$(1)
          endif
          $(PKG_INSTALL_STAMP).$(1): prepare-package-install
            echo "$(1)" >> $(PKG_INSTALL_STAMP)
        else
          $(if $(CONFIG_PACKAGE_$(1)),$$(warning WARNING: skipping $(1) -- package has no install section))
        endif
        endif

            由于BUILD_VARIANT和VARIANT都未定义,都为空,自然相等,所以条件成立。

    由于Package/$(1)/install定义在include/kernel.mk中,如下:

    1. include/kernel.mk:
    2. define Package/kmod-$(1)/install
    3. @for mod in $$(call version_filter,$$(FILES)); do \
    4. if grep -q "$$$$$$$${mod##$(LINUX_DIR)/}" "$(LINUX_DIR)/modules.builtin"; then \
    5. echo "NOTICE: module '$$$$$$$$mod' is built-in."; \
    6. elif [ -e $$$$$$$$mod ]; then \
    7. mkdir -p $$(1)/$(MODULES_SUBDIR) ; \
    8. $(CP) -L $$$$$$$$mod $$(1)/$(MODULES_SUBDIR)/ ; \
    9. else \
    10. echo "ERROR: module '$$$$$$$$mod' is missing." >&2; \
    11. exit 1; \
    12. fi; \
    13. done;
    14. $(call ModuleAutoLoad,$(1),$$(1),$(filter-out 0-,$(word 1,$(AUTOLOAD))-),$(filter-out 0,$(word 2,$(AUTOLOAD))),$(sort $(wordlist 3,99,$(AUTOLOAD))))
    15. $(call KernelPackage/$(1)/install,$$(1))
    16. endef

            所以do_install变量的值是yes。以上的结果可以通过$(warning $(Package/$(1)/install))打印出来证实。

            由于,do_install=yes,此时,可以找到compile目标了,这里有两个compile目标,两个compile目标会依次运行,compile目标和为什么这么运行的例子如下:

    1. include/package-ipkg.mk:
    2. compile: $(STAGING_DIR_ROOT)/stamp/.$(1)_installed
    3. ......
    4. compile: $(PKG_INSTALL_STAMP).$(1)
    5. example:
    6. act1:
    7. @echo act1;
    8. act2:
    9. @echo act2;
    10. compile: act1
    11. compile: act2
    12. all: compile
    13. @echo all
    14. result:
    15. act1
    16. act2
    17. all
    2. 先来分析第一个compile目标

     $(STAGING_DIR_ROOT)/stamp/.$(1)_installed依赖于$(PKG_BUILD_DIR)/.pkgdir/$(1).installed,实现如下:

    1. include/package-ipkg.mk:
    2. $(STAGING_DIR_ROOT)/stamp/.$(1)_installed: $(PKG_BUILD_DIR)/.pkgdir/$(1).installed
    3. mkdir -p $(STAGING_DIR_ROOT)/stamp
    4. $(if $(ABI_VERSION),echo '$(ABI_VERSION)' | cmp -s - $(PKG_INFO_DIR)/$(1).version || { \
    5. echo '$(ABI_VERSION)' > $(PKG_INFO_DIR)/$(1).version; \
    6. $(foreach pkg,$(filter-out $(1),$(PROVIDES)), \
    7. cp $(PKG_INFO_DIR)/$(1).version $(PKG_INFO_DIR)/$(pkg).version; \
    8. ) \
    9. } )
    10. $(call locked,$(CP) $(PKG_BUILD_DIR)/.pkgdir/$(1)/. $(STAGING_DIR_ROOT)/,root-copy)
    11. touch $$@

            $(PKG_BUILD_DIR)/.pkgdir/$(1).installed依赖于STAMP_BUILT,实现如下:

    1. include/package-ipkg.mk:
    2. $(PKG_BUILD_DIR)/.pkgdir/$(1).installed: $(STAMP_BUILT)
    3. rm -rf $$@ $(PKG_BUILD_DIR)/.pkgdir/$(1)
    4. mkdir -p $(PKG_BUILD_DIR)/.pkgdir/$(1)
    5. $(call Package/$(1)/install,$(PKG_BUILD_DIR)/.pkgdir/$(1))
    6. $(call Package/$(1)/install_lib,$(PKG_BUILD_DIR)/.pkgdir/$(1))
    7. touch $$@

            STAMP_BUILT定义在Build/CoreTargets,Build/CoreTargets实现如下:

    1. include/package.mk:
    2. define Build/CoreTargets
    3. STAMP_PREPARED:=$$(STAMP_PREPARED)
    4. STAMP_CONFIGURED:=$$(STAMP_CONFIGURED)
    5. $(if $(QUILT),$(Build/Quilt))
    6. $(call Build/Autoclean)
    7. $(call DefaultTargets)
    8. $(DL_DIR)/$(FILE): FORCE
    9. download:
    10. $(foreach hook,$(Hooks/Download),
    11. $(call $(hook))$(sep)
    12. )
    13. $(STAMP_PREPARED) : export PATH=$$(TARGET_PATH_PKG)
    14. $(STAMP_PREPARED): $(STAMP_PREPARED_DEPENDS)
    15. @-rm -rf $(PKG_BUILD_DIR)
    16. @mkdir -p $(PKG_BUILD_DIR)
    17. touch $$@_check
    18. $(foreach hook,$(Hooks/Prepare/Pre),$(call $(hook))$(sep))
    19. $(Build/Prepare)
    20. $(foreach hook,$(Hooks/Prepare/Post),$(call $(hook))$(sep))
    21. touch $$@
    22. $(call Build/Exports,$(STAMP_CONFIGURED))
    23. $(STAMP_CONFIGURED): $(STAMP_PREPARED) $(STAMP_CONFIGURED_DEPENDS)
    24. rm -f $(STAMP_CONFIGURED_WILDCARD)
    25. $(CleanStaging)
    26. $(foreach hook,$(Hooks/Configure/Pre),$(call $(hook))$(sep))
    27. $(Build/Configure)
    28. $(foreach hook,$(Hooks/Configure/Post),$(call $(hook))$(sep))
    29. touch $$@
    30. $(call Build/Exports,$(STAMP_BUILT))
    31. $(STAMP_BUILT): $(STAMP_CONFIGURED) $(STAMP_BUILT_DEPENDS)
    32. rm -f $$@
    33. touch $$@_check
    34. $(foreach hook,$(Hooks/Compile/Pre),$(call $(hook))$(sep))
    35. $(Build/Compile)
    36. $(foreach hook,$(Hooks/Compile/Post),$(call $(hook))$(sep))
    37. $(Build/Install)
    38. $(foreach hook,$(Hooks/Install/Post),$(call $(hook))$(sep))
    39. touch $$@
    40. $(STAMP_INSTALLED) : export PATH=$$(TARGET_PATH_PKG)
    41. $(STAMP_INSTALLED): $(STAMP_BUILT)
    42. rm -rf $(TMP_DIR)/stage-$(PKG_DIR_NAME)
    43. mkdir -p $(TMP_DIR)/stage-$(PKG_DIR_NAME)/host $(STAGING_DIR)/packages
    44. $(foreach hook,$(Hooks/InstallDev/Pre),\
    45. $(call $(hook),$(TMP_DIR)/stage-$(PKG_DIR_NAME),$(TMP_DIR)/stage-$(PKG_DIR_NAME)/host)$(sep)\
    46. )
    47. $(call Build/InstallDev,$(TMP_DIR)/stage-$(PKG_DIR_NAME),$(TMP_DIR)/stage-$(PKG_DIR_NAME)/host)
    48. $(foreach hook,$(Hooks/InstallDev/Post),\
    49. $(call $(hook),$(TMP_DIR)/stage-$(PKG_DIR_NAME),$(TMP_DIR)/stage-$(PKG_DIR_NAME)/host)$(sep)\
    50. )
    51. if [ -f $(STAGING_DIR)/packages/$(STAGING_FILES_LIST) ]; then \
    52. $(SCRIPT_DIR)/clean-package.sh \
    53. "$(STAGING_DIR)/packages/$(STAGING_FILES_LIST)" \
    54. "$(STAGING_DIR)"; \
    55. fi
    56. if [ -d $(TMP_DIR)/stage-$(PKG_DIR_NAME) ]; then \
    57. (cd $(TMP_DIR)/stage-$(PKG_DIR_NAME); find ./ > $(TMP_DIR)/stage-$(PKG_DIR_NAME).files); \
    58. $(call locked, \
    59. mv $(TMP_DIR)/stage-$(PKG_DIR_NAME).files $(STAGING_DIR)/packages/$(STAGING_FILES_LIST) && \
    60. $(CP) $(TMP_DIR)/stage-$(PKG_DIR_NAME)/* $(STAGING_DIR)/; \
    61. ,staging-dir); \
    62. fi
    63. rm -rf $(TMP_DIR)/stage-$(PKG_DIR_NAME)
    64. touch $$@
    65. ifdef Build/InstallDev
    66. $(_pkg_target)compile: $(STAMP_INSTALLED)
    67. endif
    68. $(_pkg_target)prepare: $(STAMP_PREPARED)
    69. $(_pkg_target)configure: $(STAMP_CONFIGURED)
    70. $(_pkg_target)dist: $(STAMP_CONFIGURED)
    71. $(_pkg_target)distcheck: $(STAMP_CONFIGURED)
    72. ifneq ($(CONFIG_AUTOREMOVE),)
    73. compile:
    74. -touch -r $(PKG_BUILD_DIR)/.built $(PKG_BUILD_DIR)/.autoremove 2>/dev/null >/dev/null
    75. $(FIND) $(PKG_BUILD_DIR) -mindepth 1 -maxdepth 1 -not '(' -type f -and -name '.*' -and -size 0 ')' -and -not -name '.pkgdir' | \
    76. $(XARGS) rm -rf
    77. endif
    78. endef
    79. define Build/DefaultTargets
    80. $(if $(USE_SOURCE_DIR)$(USE_GIT_TREE)$(USE_GIT_SRC_CHECKOUT),,$(if $(strip $(PKG_SOURCE_URL)),$(call Download,default)))
    81. $(if $(DUMP),,$(Build/CoreTargets))
    82. define Build/DefaultTargets
    83. endef
    84. endef
    85. define BuildPackage
    86. ......
    87. $(if $(PKG_HOST_ONLY),,$(call Build/DefaultTargets,$(1)))
    88. endef

    其中

    $(STAMP_BUILT): $(STAMP_CONFIGURED) $(STAMP_BUILT_DEPENDS)
        rm -f

    @touch" role="presentation" style="text-align: center; position: relative;">@touch
    @_check
        $(foreach hook,$(Hooks/Compile/Pre),$(call $(hook))$(sep))
        $(Build/Compile)
        $(foreach hook,$(Hooks/Compile/Post),$(call $(hook))$(sep))
        $(Build/Install)
        $(foreach hook,$(Hooks/Install/Post),$(call $(hook))$(sep))
        touch $$@

            STAMP_BUILT依赖于STAMP_CONFIGURED和STAMP_BUILT_DEPENDS,STAMP_CONFIGURED实现如下:

    $(STAMP_CONFIGURED): $(STAMP_PREPARED) $(STAMP_CONFIGURED_DEPENDS)
        rm -f $(STAMP_CONFIGURED_WILDCARD)
        $(CleanStaging)
        $(foreach hook,$(Hooks/Configure/Pre),$(call $(hook))$(sep))
        $(Build/Configure)
        $(foreach hook,$(Hooks/Configure/Post),$(call $(hook))$(sep))
        touch $$@

            STAMP_CONFIGURED依赖于STAMP_PREPARED,STAMP_PREPARED实现如下:

    (STAMP_PREPARED) : export PATH=

    (TARGETPATHPKG)$(STAMPPREPARED):$(STAMPPREPAREDDEPENDS)@rmrf$(PKGBUILDDIR)@mkdirp$(PKGBUILDDIR)touch" role="presentation" style="position: relative;">(TARGETPATHPKG)$(STAMPPREPARED):$(STAMPPREPAREDDEPENDS)@rmrf$(PKGBUILDDIR)@mkdirp$(PKGBUILDDIR)touch
    @_check
        $(foreach hook,$(Hooks/Prepare/Pre),$(call $(hook))$(sep))
        $(Build/Prepare)
        $(foreach hook,$(Hooks/Prepare/Post),$(call $(hook))$(sep))
        touch $$@

            经过这几个步骤,kmod-*.ipkg的代码就编译好了。步骤分别是BUild/Prepare,CleanStaging,Build/Configure,Build/Compile和Build/Install。

            在之后,执行如下代码

    1. include/package-ipkg.mk:
    2. $(PKG_BUILD_DIR)/.pkgdir/$(1).installed : export PATH=$$(TARGET_PATH_PKG)
    3. $(PKG_BUILD_DIR)/.pkgdir/$(1).installed: $(STAMP_BUILT)
    4. rm -rf $$@ $(PKG_BUILD_DIR)/.pkgdir/$(1)
    5. mkdir -p $(PKG_BUILD_DIR)/.pkgdir/$(1)
    6. $(call Package/$(1)/install,$(PKG_BUILD_DIR)/.pkgdir/$(1))
    7. $(call Package/$(1)/install_lib,$(PKG_BUILD_DIR)/.pkgdir/$(1))
    8. touch $$@

           实际运行代码:

    1. rm -rf /root/mt7981/openwrt/build_dir/target-aarch64_cortex-a53_musl/linux-mediatek_mt7981/gpio-button-hotplug/.pkgdir/kmod-gpio-button-hotplug.installed /root/mt7981/openwrt/build_dir/target-aarch64_cortex-a53_musl/linux-mediatek_mt7981/gpio-button-hotplug/.pkgdir/kmod-gpio-button-hotplug
    2. mkdir -p /root/mt7981/openwrt/build_dir/target-aarch64_cortex-a53_musl/linux-mediatek_mt7981/gpio-button-hotplug/.pkgdir/kmod-gpio-button-hotplug
    3. mkdir -p /root/mt7981/openwrt/build_dir/target-aarch64_cortex-a53_musl/linux-mediatek_mt7981/gpio-button-hotplug/.pkgdir/kmod-gpio-button-hotplug/etc/modules.d; ( echo "gpio-button-hotplug"; ) > /root/mt7981/openwrt/build_dir/target-aarch64_cortex-a53_musl/linux-mediatek_mt7981/gpio-button-hotplug/.pkgdir/kmod-gpio-button-hotplug/etc/modules.d/30-gpio-button-hotplug; mkdir -p /root/mt7981/openwrt/build_dir/target-aarch64_cortex-a53_musl/linux-mediatek_mt7981/gpio-button-hotplug/.pkgdir/kmod-gpio-button-hotplug/etc/modules-boot.d; ln -sf ../modules.d/30-gpio-button-hotplug /root/mt7981/openwrt/build_dir/target-aarch64_cortex-a53_musl/linux-mediatek_mt7981/gpio-button-hotplug/.pkgdir/kmod-gpio-button-hotplug/etc/modules-boot.d/;
    4. touch /root/mt7981/openwrt/build_dir/target-aarch64_cortex-a53_musl/linux-mediatek_mt7981/gpio-button-hotplug/.pkgdir/kmod-gpio-button-hotplug.installed

            创建build_dir/target-aarch64_cortex-a53_musl/linux-mediatek_mt7981/gpio-button-hotplug/.pkgdir/kmod-gpio-button-hotplug.installed文件。

    1. $(STAGING_DIR_ROOT)/stamp/.$(1)_installed: $(PKG_BUILD_DIR)/.pkgdir/$(1).installed
    2. mkdir -p $(STAGING_DIR_ROOT)/stamp
    3. $(if $(ABI_VERSION),echo '$(ABI_VERSION)' | cmp -s - $(PKG_INFO_DIR)/$(1).version || { \
    4. echo '$(ABI_VERSION)' > $(PKG_INFO_DIR)/$(1).version; \
    5. $(foreach pkg,$(filter-out $(1),$(PROVIDES)), \
    6. cp $(PKG_INFO_DIR)/$(1).version $(PKG_INFO_DIR)/$(pkg).version; \
    7. ) \
    8. } )
    9. $(call locked,$(CP) $(PKG_BUILD_DIR)/.pkgdir/$(1)/. $(STAGING_DIR_ROOT)/,root-copy)
    10. touch $$@

             执行如下:

    mkdir -p /root/mt7981/openwrt/staging_dir/target-aarch64_cortex-a53_musl/root-mediatek/stamp
    SHELL= flock /root/mt7981/openwrt/tmp/.root-copy.flock -c 'cp -fpR /root/mt7981/openwrt/build_dir/target-aarch64_cortex-a53_musl/linux-mediatek_mt7981/gpio-button-hotplug/.pkgdir/kmod-gpio-button-hotplug/. /root/mt7981/openwrt/staging_dir/target-aarch64_cortex-a53_musl/root-mediatek/'
    touch /root/mt7981/openwrt/staging_dir/target-aarch64_cortex-a53_musl/root-mediatek/stamp/.kmod-gpio-button-hotplug_installed

            至此,第一个compile目标就分析完成了,接下来第二个compile主要是生成ipkg包。

    3. 第二个compile分析

            第二个compile代码如下:

    1. include/package-ipkg.mk:
    2. compile: $(PKG_INSTALL_STAMP).$(1)

            $(PKG_INSTALL_STAMP).$(1)依赖于prepare-package-install,prepare-package-install代码如下:

    1. include/package-ipkg.mk:
    2. prepare-package-install: $$(IPKG_$(1))

            $$(IPKG_$(1))的定义如下:

    1. include/package-ipkg.mk:
    2. $$(IPKG_$(1)) : export CONTROL=$$(Package/$(1)/CONTROL)
    3. $$(IPKG_$(1)) : export DESCRIPTION=$$(Package/$(1)/description)
    4. $$(IPKG_$(1)) : export PATH=$$(TARGET_PATH_PKG)
    5. $$(IPKG_$(1)) : export PKG_SOURCE_DATE_EPOCH:=$(PKG_SOURCE_DATE_EPOCH)
    6. $(PKG_INFO_DIR)/$(1).provides $$(IPKG_$(1)): $(STAMP_BUILT) $(INCLUDE_DIR)/package-ipkg.mk
    7. @rm -rf $$(IDIR_$(1)); \
    8. $$(call remove_ipkg_files,$(1),$$(call opkg_package_files,$(call gen_ipkg_wildcard,$(1))))
    9. mkdir -p $(PACKAGE_DIR) $$(IDIR_$(1))/CONTROL $(PKG_INFO_DIR)
    10. $(call Package/$(1)/install,$$(IDIR_$(1)))
    11. $(if $(Package/$(1)/install-overlay),mkdir -p $(PACKAGE_DIR) $$(IDIR_$(1))/rootfs-overlay)
    12. $(call Package/$(1)/install-overlay,$$(IDIR_$(1))/rootfs-overlay)
    13. -find $$(IDIR_$(1)) -name 'CVS' -o -name '.svn' -o -name '.#*' -o -name '*~'| $(XARGS) rm -rf
    14. @( \
    15. find $$(IDIR_$(1)) -name lib\*.so\* -or -name \*.ko | awk -F/ '{ print $$$$NF }'; \
    16. for file in $$(patsubst %,$(PKG_INFO_DIR)/%.provides,$$(IDEPEND_$(1))); do \
    17. if [ -f "$$$$file" ]; then \
    18. cat $$$$file; \
    19. fi; \
    20. done; $(Package/$(1)/extra_provides) \
    21. ) | sort -u > $(PKG_INFO_DIR)/$(1).provides
    22. $(if $(PROVIDES),@for pkg in $(filter-out $(1),$(PROVIDES)); do cp $(PKG_INFO_DIR)/$(1).provides $(PKG_INFO_DIR)/$$$$pkg.provides; done)
    23. $(CheckDependencies)
    24. $(RSTRIP) $$(IDIR_$(1))
    25. ifneq ($$(CONFIG_IPK_FILES_CHECKSUMS),)
    26. (cd $$(IDIR_$(1)); \
    27. ( \
    28. find . -type f \! -path ./CONTROL/\* -exec mkhash sha256 -n \{\} \; 2> /dev/null | \
    29. sed 's|\([[:blank:]]\)\./| \1/|' > $$(IDIR_$(1))/CONTROL/files-sha256sum \
    30. ) || true \
    31. )
    32. endif
    33. (cd $$(IDIR_$(1))/CONTROL; \
    34. ( \
    35. echo "$$$$CONTROL"; \
    36. printf "Description: "; echo "$$$$DESCRIPTION" | sed -e 's,^[[:space:]]*, ,g'; \
    37. ) > control; \
    38. chmod 644 control; \
    39. ( \
    40. echo "#!/bin/sh"; \
    41. echo "[ \"\$$$${IPKG_NO_SCRIPT}\" = \"1\" ] && exit 0"; \
    42. echo "[ -s "\$$$${IPKG_INSTROOT}/lib/functions.sh" ] || exit 0"; \
    43. echo ". \$$$${IPKG_INSTROOT}/lib/functions.sh"; \
    44. echo "default_postinst \$$$$0 \$$$$@"; \
    45. ) > postinst; \
    46. ( \
    47. echo "#!/bin/sh"; \
    48. echo "[ -s "\$$$${IPKG_INSTROOT}/lib/functions.sh" ] || exit 0"; \
    49. echo ". \$$$${IPKG_INSTROOT}/lib/functions.sh"; \
    50. echo "default_prerm \$$$$0 \$$$$@"; \
    51. ) > prerm; \
    52. chmod 0755 postinst prerm; \
    53. $($(1)_COMMANDS) \
    54. )
    55. ifneq ($$(KEEP_$(1)),)
    56. @( \
    57. keepfiles=""; \
    58. for x in $$(KEEP_$(1)); do \
    59. [ -f "$$(IDIR_$(1))/$$$$x" ] || keepfiles="$$$${keepfiles:+$$$$keepfiles }$$$$x"; \
    60. done; \
    61. [ -z "$$$$keepfiles" ] || { \
    62. mkdir -p $$(IDIR_$(1))/lib/upgrade/keep.d; \
    63. for x in $$$$keepfiles; do echo $$$$x >> $$(IDIR_$(1))/lib/upgrade/keep.d/$(1); done; \
    64. }; \
    65. )
    66. endif
    67. $(INSTALL_DIR) $$(PDIR_$(1))
    68. $(FAKEROOT) $(SCRIPT_DIR)/ipkg-build -m "$(FILE_MODES)" $$(IDIR_$(1)) $$(PDIR_$(1))
    69. @[ -f $$(IPKG_$(1)) ]

            逐行代码分析,

    1. @rm -rf $$(IDIR_$(1)); \
    2. $$(call remove_ipkg_files,$(1),$$(call opkg_package_files,$(call gen_ipkg_wildcard,$(1))))

            这句指令实际执行命令如下:

    rm -rf /root/mt7981/openwrt/build_dir/target-aarch64_cortex-a53_musl/linux-mediatek_mt7981/gpio-button-hotplug/ipkg-aarch64_cortex-a53/kmod-gpio-button-hotplug; 

             删除ipkg目录。

    mkdir -p $(PACKAGE_DIR) $$(IDIR_$(1))/CONTROL $(PKG_INFO_DIR)

            实际执行命令如下:

    mkdir -p /root/mt7981/openwrt/bin/targets/mediatek/mt7981/packages /root/mt7981/openwrt/build_dir/target-aarch64_cortex-a53_musl/linux-mediatek_mt7981/gpio-button-hotplug/ipkg-aarch64_cortex-a53/kmod-gpio-button-hotplug/CONTROL /root/mt7981/openwrt/staging_dir/target-aarch64_cortex-a53_musl/pkginfo

            新建ipkg以及其下面的目录。

    $(call Package/$(1)/install,$$(IDIR_$(1)))

            实际执行命令如下:

    mkdir -p /root/mt7981/openwrt/build_dir/target-aarch64_cortex-a53_musl/linux-mediatek_mt7981/gpio-button-hotplug/ipkg-aarch64_cortex-a53/kmod-gpio-button-hotplug/etc/modules.d; ( echo "gpio-button-hotplug"; ) > /root/mt7981/openwrt/build_dir/target-aarch64_cortex-a53_musl/linux-mediatek_mt7981/gpio-button-hotplug/ipkg-aarch64_cortex-a53/kmod-gpio-button-hotplug/etc/modules.d/30-gpio-button-hotplug;  mkdir -p /root/mt7981/openwrt/build_dir/target-aarch64_cortex-a53_musl/linux-mediatek_mt7981/gpio-button-hotplug/ipkg-aarch64_cortex-a53/kmod-gpio-button-hotplug/etc/modules-boot.d; ln -sf ../modules.d/30-gpio-button-hotplug /root/mt7981/openwrt/build_dir/target-aarch64_cortex-a53_musl/linux-mediatek_mt7981/gpio-button-hotplug/ipkg-aarch64_cortex-a53/kmod-gpio-button-hotplug/etc/modules-boot.d/;

            其上面的命令都在include/kernel.mk的Package/kmod-$(1)/install中的ModuleAutoLoad实现的。

    1. -find $$(IDIR_$(1)) -name 'CVS' -o -name '.svn' -o -name '.#*' -o -name '*~'| $(XARGS) rm -rf
    2. @( \
    3. find $$(IDIR_$(1)) -name lib\*.so\* -or -name \*.ko | awk -F/ '{ print $$$$NF }'; \
    4. for file in $$(patsubst %,$(PKG_INFO_DIR)/%.provides,$$(IDEPEND_$(1))); do \
    5. if [ -f "$$$$file" ]; then \
    6. cat $$$$file; \
    7. fi; \
    8. done; $(Package/$(1)/extra_provides) \
    9. ) | sort -u > $(PKG_INFO_DIR)/$(1).provides

            实际执行命令如下:

    find /root/mt7981/openwrt/build_dir/target-aarch64_cortex-a53_musl/linux-mediatek_mt7981/gpio-button-hotplug/ipkg-aarch64_cortex-a53/kmod-gpio-button-hotplug -name 'CVS' -o -name '.svn' -o -name '.#*' -o -name '*~'| xargs -r rm -rf

            删除掉ipkg目录下一些无关的文件。

    $(RSTRIP) $$(IDIR_$(1))

            实际执行命令如下:

    export CROSS="aarch64-openwrt-linux-musl-"  NO_RENAME=1 ; NM="aarch64-openwrt-linux-musl-nm" STRIP="/root/mt7981/openwrt/staging_dir/host/bin/sstrip -z" STRIP_KMOD="/root/mt7981/openwrt/scripts/strip-kmod.sh" PATCHELF="/root/mt7981/openwrt/staging_dir/host/bin/patchelf" /root/mt7981/openwrt/scripts/rstrip.sh /root/mt7981/openwrt/build_dir/target-aarch64_cortex-a53_musl/linux-mediatek_mt7981/gpio-button-hotplug/ipkg-aarch64_cortex-a53/kmod-gpio-button-hotplug
    rstrip.sh: /root/mt7981/openwrt/build_dir/target-aarch64_cortex-a53_musl/linux-mediatek_mt7981/gpio-button-hotplug/ipkg-aarch64_cortex-a53/kmod-gpio-button-hotplug/lib/modules/5.4.203/gpio-button-hotplug.ko: relocatable

            去掉ipkg中文件的符号表。

    1. (cd $$(IDIR_$(1))/CONTROL; \
    2. ( \
    3. echo "$$$$CONTROL"; \
    4. printf "Description: "; echo "$$$$DESCRIPTION" | sed -e 's,^[[:space:]]*, ,g'; \
    5. ) > control; \
    6. chmod 644 control; \
    7. ( \
    8. echo "#!/bin/sh"; \
    9. echo "[ \"\$$$${IPKG_NO_SCRIPT}\" = \"1\" ] && exit 0"; \
    10. echo "[ -s "\$$$${IPKG_INSTROOT}/lib/functions.sh" ] || exit 0"; \
    11. echo ". \$$$${IPKG_INSTROOT}/lib/functions.sh"; \
    12. echo "default_postinst \$$$$0 \$$$$@"; \
    13. ) > postinst; \
    14. ( \
    15. echo "#!/bin/sh"; \
    16. echo "[ -s "\$$$${IPKG_INSTROOT}/lib/functions.sh" ] || exit 0"; \
    17. echo ". \$$$${IPKG_INSTROOT}/lib/functions.sh"; \
    18. echo "default_prerm \$$$$0 \$$$$@"; \
    19. ) > prerm; \
    20. chmod 0755 postinst prerm; \
    21. $($(1)_COMMANDS) \
    22. )

            实际执行命令如下:

    (cd /root/mt7981/openwrt/build_dir/target-aarch64_cortex-a53_musl/linux-mediatek_mt7981/gpio-button-hotplug/ipkg-aarch64_cortex-a53/kmod-gpio-button-hotplug/CONTROL; ( echo "$CONTROL"; printf "Description: "; echo "$DESCRIPTION" | sed -e 's,^[[:space:]]*, ,g'; ) > control; chmod 644 control; ( echo "#!/bin/sh"; echo "[ \"\${IPKG_NO_SCRIPT}\" = \"1\" ] && exit 0"; echo "[ -s "\${IPKG_INSTROOT}/lib/functions.sh" ] || exit 0"; echo ". \${IPKG_INSTROOT}/lib/functions.sh"; echo "default_postinst \$0 \$@"; ) > postinst; ( echo "#!/bin/sh"; echo "[ -s "\${IPKG_INSTROOT}/lib/functions.sh" ] || exit 0"; echo ". \${IPKG_INSTROOT}/lib/functions.sh"; echo "default_prerm \$0 \$@"; ) > prerm; chmod 0755 postinst prerm;  )

            生成ipkg下的control,postinst和prerm文件。

    $(INSTALL_DIR) $$(PDIR_$(1))

            实际执行命令如下:

    install -d -m0755 /root/mt7981/openwrt/bin/targets/mediatek/mt7981/packages

            创建bin下的packages目录。

    $(FAKEROOT) $(SCRIPT_DIR)/ipkg-build -m "$(FILE_MODES)" $$(IDIR_$(1)) $$(PDIR_$(1))

             实际执行命令如下:

    /root/mt7981/openwrt/staging_dir/host/bin/fakeroot /root/mt7981/openwrt/scripts/ipkg-build -m "" /root/mt7981/openwrt/build_dir/target-aarch64_cortex-a53_musl/linux-mediatek_mt7981/gpio-button-hotplug/ipkg-aarch64_cortex-a53/kmod-gpio-button-hotplug /root/mt7981/openwrt/bin/targets/mediatek/mt7981/packages
    Packaged contents of /root/mt7981/openwrt/build_dir/target-aarch64_cortex-a53_musl/linux-mediatek_mt7981/gpio-button-hotplug/ipkg-aarch64_cortex-a53/kmod-gpio-button-hotplug into /root/mt7981/openwrt/bin/targets/mediatek/mt7981/packages/kmod-gpio-button-hotplug_5.4.203-3_aarch64_cortex-a53.ipk

            调用ipkg-build命令生成ipkg文件。

    echo "$(1)" >> $(PKG_INSTALL_STAMP)

            实际执行命令如下:

    echo "kmod-gpio-button-hotplug" >> /root/mt7981/openwrt/staging_dir/target-aarch64_cortex-a53_musl/pkginfo/gpio-button-hotplug.default.install

    三. 总结

    1. kmod的ipkg和普通的应用程序的ipkg相同点

            毫无疑问,它们都必须包含ipkg的基本元素,符合ipkg的规范,有CONTROL目录,CONTROL目录下有对应的control,postinst和prerm文件,还有其他的目录,例如内核驱动有etc和lib目录,应用程序有usr目录等等。

            它们都要调用include/package.mk中的BuildPackage,再调用到include/package-ipkg.mk的BuildTarget/ipkg,BuildPackage的子功能定义编译ipkg源代码的一整套流程,Prepare,Configure,Compile和Install步骤,虽然两者区别是其中一个一些步骤会省略(Build/xxx为空),例如,kmod就不需要Configure。

    2. kmod的ipkg和普通的应用程序的ipkg不同点

            编译kmod和普通应用的代码方式不一样。这个就体现在Build/Compile中,kmod的Makefile需要在自己的Makefile中定义这个宏,表示如何编译kmod,而应用代码Build/Compile是不推荐自定义的。

            安装的方式不一样。kmod需要etc/modules.d/这样的目录,而应用程序不需要,在kmod的安装中,include/package-ipkg.mk中$(call Package/$(1)/install,$$(IDIR_$(1)))会调用到include/kernel.mk中的Package/kmod-$(1)/install,而如果再有需要,由于KernelPackage/$(1)/install定义在Package/kmod-$(1)/install,kmod的Makefile可以自定义KernelPackage/$(1)/install,做一些特殊处理。但是普通应用程序要在自己的Makefile中定义Package/$(1)/install,做一些自己需要的操作。

  • 相关阅读:
    Pulsar 社区周报 | No.2024-06-07 | Apache Pulsar 新分支 3.3 版本发布
    【Java】认识类和对象
    【数据结构初阶】复杂链表复制+带头双向循环链表+缓存级知识
    Docker 容器编排
    C++入门(上)
    冥想第九百七十八天
    贪吃蛇小游戏
    美团三面:让你怀疑人生的Spring Boot夺命连环40问
    重量级ORM框架--持久化框架Hibernate【JPA注解开发】
    这么分页,小心有坑
  • 原文地址:https://blog.csdn.net/to_be_better_wen/article/details/132918659