mirror of
https://github.com/openwrt/openwrt.git
synced 2026-10-12 06:57:57 +04:00
The rootfs is installed from scratch on every build: apk add, then the post-install and init scripts of every package, one after the other. This takes about 1.5 s, even if no package changed. Build a key from the package index, which holds a hash of every package, the install list, .config, SOURCE_DATE_EPOCH, the files overlay, apk, tar, gzip and the Makefiles that create the rootfs. Save a copy of the rootfs with the key, and restore it from the copy if the key did not change. Later build steps modify the rootfs, so it is always restored from the copy and never reused in place. prepare_rootfs runs tar and gzip over the apk script archive, so the key holds those two host tools as well. With mklibs it also runs rstrip.sh, which the key then holds too. The install list now holds the base-files, libc and kernel versions too, so that the key can use it. Only the APK path uses the cache. The copy costs disk: the build directory carries the root filesystem twice, once as root and root.orig and once in the cache. Signed-off-by: John Crispin <john@phrozen.org>
256 lines
9.3 KiB
Makefile
256 lines
9.3 KiB
Makefile
#
|
|
# Copyright (C) 2006-2010 OpenWrt.org
|
|
#
|
|
# This is free software, licensed under the GNU General Public License v2.
|
|
# See /LICENSE for more information.
|
|
#
|
|
|
|
curdir:=package
|
|
|
|
include $(INCLUDE_DIR)/feeds.mk
|
|
include $(INCLUDE_DIR)/rootfs.mk
|
|
|
|
-include $(TMP_DIR)/.packagedeps
|
|
package-y += kernel/linux
|
|
$(curdir)/autoremove:=1
|
|
$(curdir)/builddirs:=$(sort $(package-) $(package-y) $(package-m))
|
|
$(curdir)/builddirs-default:=. $(sort $(package-y) $(package-m))
|
|
$(curdir)/builddirs-prereq:=. $(sort $(prereq-y) $(prereq-m))
|
|
ifdef CHECK_ALL
|
|
$(curdir)/builddirs-check:=$($(curdir)/builddirs)
|
|
$(curdir)/builddirs-download:=$($(curdir)/builddirs)
|
|
endif
|
|
ifneq ($(IGNORE_ERRORS),)
|
|
package-y-filter := $(package-y)
|
|
package-m-filter := $(filter-out $(package-y),$(package-m))
|
|
package-n-filter := $(filter-out $(package-y) $(package-m),$(package-))
|
|
package-ignore-errors := $(filter n m y,$(IGNORE_ERRORS))
|
|
package-ignore-errors := $(if $(package-ignore-errors),$(package-ignore-errors),n m)
|
|
package-ignore-subdirs := $(sort $(foreach m,$(package-ignore-errors),$(package-$(m)-filter)))
|
|
$(curdir)/builddirs-ignore-download := $(package-ignore-subdirs)
|
|
$(curdir)/builddirs-ignore-compile := $(package-ignore-subdirs)
|
|
$(curdir)/builddirs-ignore-host-download := $(package-ignore-subdirs)
|
|
$(curdir)/builddirs-ignore-host-compile := $(package-ignore-subdirs)
|
|
endif
|
|
|
|
PACKAGE_INSTALL_FILES:= \
|
|
$(foreach pkg,$(sort $(package-y)), \
|
|
$(foreach variant, \
|
|
$(if $(strip $(package/$(pkg)/variants)), \
|
|
$(package/$(pkg)/variants), \
|
|
$(if $(package/$(pkg)/default-variant), \
|
|
$(package/$(pkg)/default-variant), \
|
|
default \
|
|
) \
|
|
), \
|
|
$(PKG_INFO_DIR)/$(lastword $(subst /,$(space),$(pkg))).$(variant).install \
|
|
) \
|
|
)
|
|
|
|
$(curdir)/cleanup: $(TMP_DIR)/.build
|
|
rm -rf $(STAGING_DIR_ROOT)
|
|
|
|
PACKAGE_EXT:=$(if $(CONFIG_USE_APK),apk,ipk)
|
|
PACKAGE_INDEX_FILE:=$(PACKAGE_DIR_ALL)/$(if $(CONFIG_USE_APK),packages.adb,Packages)
|
|
PACKAGE_MERGE_LIST:=$(PACKAGE_DIR_ALL).list
|
|
|
|
define package_merge_links
|
|
rm -rf $(PACKAGE_DIR_ALL); \
|
|
mkdir -p $(PACKAGE_DIR_ALL); \
|
|
$(foreach pdir,$(PACKAGE_SUBDIRS), \
|
|
$(if $(wildcard $(pdir)/*.$(PACKAGE_EXT)), \
|
|
ln -s $(pdir)/*.$(PACKAGE_EXT) $(PACKAGE_DIR_ALL) || true;))
|
|
endef
|
|
|
|
$(curdir)/merge:
|
|
mkdir -p $(dir $(PACKAGE_MERGE_LIST))
|
|
find $(PACKAGE_SUBDIRS) -maxdepth 1 -name '*.$(PACKAGE_EXT)' \
|
|
-printf '%p %s %T@\n' 2>/dev/null | LC_ALL=C sort > $(PACKAGE_MERGE_LIST).new
|
|
if cmp -s $(PACKAGE_MERGE_LIST).new $(PACKAGE_MERGE_LIST) && \
|
|
[ -f $(PACKAGE_INDEX_FILE) ]; then \
|
|
rm -f $(PACKAGE_MERGE_LIST).new; \
|
|
else \
|
|
$(package_merge_links) \
|
|
mv $(PACKAGE_MERGE_LIST).new $(PACKAGE_MERGE_LIST); \
|
|
fi
|
|
|
|
$(BUILD_KEY_APK_SEC):
|
|
$(STAGING_DIR_HOST)/bin/openssl ecparam -name prime256v1 -genkey -noout -out $(BUILD_KEY_APK_SEC)
|
|
|
|
$(BUILD_KEY_APK_PUB): $(BUILD_KEY_APK_SEC)
|
|
$(STAGING_DIR_HOST)/bin/openssl ec -in $(BUILD_KEY_APK_SEC) -pubout > $(BUILD_KEY_APK_PUB)
|
|
|
|
$(curdir)/merge-index: $(curdir)/merge
|
|
ifneq ($(CONFIG_USE_APK),)
|
|
[ -f $(PACKAGE_INDEX_FILE) ] || \
|
|
(cd $(PACKAGE_DIR_ALL) && $(STAGING_DIR_HOST)/bin/apk mkndx \
|
|
--root $(TOPDIR) \
|
|
--keys-dir $(TOPDIR) \
|
|
--allow-untrusted \
|
|
$(if $(CONFIG_SIGNED_PACKAGES),--sign $(BUILD_KEY_APK_SEC),) \
|
|
--output packages.adb \
|
|
*.apk; \
|
|
)
|
|
else
|
|
[ -f $(PACKAGE_INDEX_FILE) ] || \
|
|
(cd $(PACKAGE_DIR_ALL) && $(SCRIPT_DIR)/ipkg-make-index.sh . 2>&1 > Packages; )
|
|
endif
|
|
|
|
ifndef SDK
|
|
$(curdir)//compile = $(STAGING_DIR)/.prepared $(BIN_DIR)
|
|
ifneq ($(CONFIG_USE_APK),)
|
|
$(curdir)//compile += $(curdir)/system/apk/host/compile $(BUILD_KEY_APK_SEC) $(BUILD_KEY_APK_PUB)
|
|
else
|
|
$(curdir)/compile: $(curdir)/system/opkg/host/compile
|
|
endif
|
|
else
|
|
ifneq ($(CONFIG_USE_APK),)
|
|
$(curdir)//compile += $(BUILD_KEY_APK_SEC) $(BUILD_KEY_APK_PUB)
|
|
endif
|
|
endif
|
|
|
|
# The rootfs is a function of the package index, which holds a hash of every
|
|
# package, and of the inputs below. Installing it takes a few seconds, so
|
|
# keep a copy and restore it if none of them changed. Later build steps
|
|
# modify the rootfs, so it is always restored from the copy.
|
|
ROOTFS_CACHE:=$(TARGET_ROOTFS_DIR)/rootfs-cache-$(BOARD)
|
|
|
|
define rootfs_cache_key
|
|
$(shell ( \
|
|
echo '$(subst ','\'',$(1))'; \
|
|
echo $(SOURCE_DATE_EPOCH); \
|
|
cat $(PACKAGE_DIR_ALL)/packages.adb $(TOPDIR)/.config $(STAGING_DIR_HOST)/bin/apk \
|
|
$(STAGING_DIR_HOST)/bin/tar $(STAGING_DIR_HOST)/bin/gzip \
|
|
$(if $(CONFIG_USE_MKLIBS),$(SCRIPT_DIR)/rstrip.sh) \
|
|
$(INCLUDE_DIR)/rootfs.mk $(TOPDIR)/package/Makefile; \
|
|
[ ! -d $(TOPDIR)/files ] || ( cd $(TOPDIR)/files && \
|
|
find . -printf '%p %y %m %l\n' | LC_ALL=C sort && \
|
|
find . -type f -print0 | LC_ALL=C sort -z | xargs -0 -r cat ); \
|
|
) | $(MKHASH) sha256)
|
|
endef
|
|
|
|
define rootfs_cache_restore
|
|
cp -a $(ROOTFS_CACHE)/root $(TARGET_DIR)
|
|
cp -a $(ROOTFS_CACHE)/root.orig $(TARGET_DIR_ORIG)
|
|
endef
|
|
|
|
APK_INSTALL_ARGS = \
|
|
$(foreach pkg,$(shell cat $(PACKAGE_INSTALL_FILES) 2>/dev/null),$(pkg)$(call GetABISuffix,$(pkg))) \
|
|
base-files=$(shell cat $(STAGING_DIR)/base-files.version) \
|
|
libc=$(shell cat $(STAGING_DIR)/libc.version) \
|
|
kernel=$(subst -rc,_rc,$(shell cat $(STAGING_DIR)/kernel.version))
|
|
|
|
define apk_install_rootfs
|
|
mkdir -p $(TARGET_DIR)/tmp
|
|
$(file >$(TMP_DIR)/apk_install_list,$(APK_INSTALL_ARGS))
|
|
$(call apk,$(TARGET_DIR)) add --no-cache --initdb --no-scripts --arch $(ARCH_PACKAGES) \
|
|
--repositories-file /dev/null --repository file://$(PACKAGE_DIR_ALL)/packages.adb \
|
|
$(if $(CONFIG_SIGNED_PACKAGES),,--allow-untrusted) \
|
|
$$(cat $(TMP_DIR)/apk_install_list)
|
|
rm -rf $(TARGET_DIR)/run
|
|
$(CP) $(TARGET_DIR) $(TARGET_DIR_ORIG)
|
|
$(call prepare_rootfs,$(TARGET_DIR),$(TOPDIR)/files)
|
|
rm -rf $(ROOTFS_CACHE)
|
|
mkdir -p $(ROOTFS_CACHE)
|
|
cp -a $(TARGET_DIR) $(ROOTFS_CACHE)/root
|
|
cp -a $(TARGET_DIR_ORIG) $(ROOTFS_CACHE)/root.orig
|
|
echo $(ROOTFS_KEY) > $(ROOTFS_CACHE)/key
|
|
endef
|
|
|
|
$(curdir)/install: $(TMP_DIR)/.build $(curdir)/merge $(curdir)/merge-index
|
|
- find $(STAGING_DIR_ROOT) -type d | $(XARGS) chmod 0755
|
|
rm -rf $(TARGET_DIR) $(TARGET_DIR_ORIG)
|
|
ifneq ($(CONFIG_USE_APK),)
|
|
$(eval ROOTFS_KEY:=$(call rootfs_cache_key,$(APK_INSTALL_ARGS)))
|
|
$(if $(filter $(ROOTFS_KEY),$(shell cat $(ROOTFS_CACHE)/key 2>/dev/null)),$(rootfs_cache_restore),$(apk_install_rootfs))
|
|
else
|
|
mkdir -p $(TARGET_DIR)/tmp
|
|
$(file >$(TMP_DIR)/opkg_install_list,\
|
|
$(call opkg_package_files,\
|
|
$(foreach pkg,$(shell cat $(PACKAGE_INSTALL_FILES) 2>/dev/null),$(pkg)$(call GetABISuffix,$(pkg)))))
|
|
$(call opkg,$(TARGET_DIR)) install $$(cat $(TMP_DIR)/opkg_install_list)
|
|
@for file in $(PACKAGE_INSTALL_FILES); do \
|
|
[ -s $$file.flags ] || continue; \
|
|
for flag in `cat $$file.flags`; do \
|
|
$(call opkg,$(TARGET_DIR)) flag $$flag `cat $$file`; \
|
|
done; \
|
|
done || true
|
|
$(CP) $(TARGET_DIR) $(TARGET_DIR_ORIG)
|
|
$(call prepare_rootfs,$(TARGET_DIR),$(TOPDIR)/files)
|
|
endif
|
|
|
|
$(curdir)/index: FORCE
|
|
@echo Generating package index...
|
|
ifneq ($(CONFIG_USE_APK),)
|
|
@for d in $(PACKAGE_SUBDIRS); do \
|
|
set -e; \
|
|
mkdir -p $$d; \
|
|
cd $$d || continue; \
|
|
ls *.apk >/dev/null 2>&1 || continue; \
|
|
if [ -f packages.adb ] && [ -f index.json ] && \
|
|
[ -z "$$(find . -maxdepth 1 \( -name '*.apk' -o -type d \) \
|
|
-newer index.json -print -quit 2>/dev/null)" ]; then \
|
|
continue; \
|
|
fi; \
|
|
$(STAGING_DIR_HOST)/bin/apk mkndx \
|
|
--root $(TOPDIR) \
|
|
--keys-dir $(TOPDIR) \
|
|
--allow-untrusted \
|
|
$(if $(CONFIG_SIGNED_PACKAGES),--sign $(BUILD_KEY_APK_SEC),) \
|
|
--output packages.adb \
|
|
*.apk; \
|
|
$(STAGING_DIR_HOST)/bin/apk adbdump --format json packages.adb | \
|
|
$(SCRIPT_DIR)/make-index-json.py -f apk -a "$(ARCH_PACKAGES)" - > index.json; \
|
|
done
|
|
ifdef CONFIG_JSON_CYCLONEDX_SBOM
|
|
@echo Creating CycloneDX package SBOMs...
|
|
@for d in $(PACKAGE_SUBDIRS); do \
|
|
[ -d $$d ] && \
|
|
cd $$d || continue; \
|
|
[ -f packages.adb ] || continue; \
|
|
$(STAGING_DIR_HOST)/bin/apk adbdump --format json packages.adb | \
|
|
$(SCRIPT_DIR)/make-sbom.py - -f apk > Packages.bom.cdx.json || true; \
|
|
done
|
|
endif
|
|
else
|
|
@for d in $(PACKAGE_SUBDIRS); do ( \
|
|
mkdir -p $$d; \
|
|
cd $$d || continue; \
|
|
$(SCRIPT_DIR)/ipkg-make-index.sh . 2>&1 > Packages.manifest; \
|
|
grep -vE '^(Maintainer|LicenseFiles|Source|SourceName|Require|SourceDateEpoch)' Packages.manifest > Packages; \
|
|
case "$$(((64 + $$(stat -L -c%s Packages)) % 128))" in 110|111) \
|
|
$(call ERROR_MESSAGE,WARNING: Applying padding in $$d/Packages to workaround usign SHA-512 bug!); \
|
|
{ echo ""; echo ""; } >> Packages;; \
|
|
esac; \
|
|
$(SCRIPT_DIR)/make-index-json.py -f opkg -a "$(ARCH_PACKAGES)" Packages > index.json; \
|
|
gzip -9nc Packages > Packages.gz; \
|
|
); done
|
|
ifdef CONFIG_SIGNED_PACKAGES
|
|
@echo Signing package index...
|
|
@for d in $(PACKAGE_SUBDIRS); do ( \
|
|
[ -d $$d ] && \
|
|
cd $$d || continue; \
|
|
$(STAGING_DIR_HOST)/bin/usign -S -m Packages -s $(BUILD_KEY); \
|
|
); done
|
|
endif
|
|
ifdef CONFIG_JSON_CYCLONEDX_SBOM
|
|
@echo Creating CycloneDX package SBOMs...
|
|
@for d in $(PACKAGE_SUBDIRS); do ( \
|
|
[ -d $$d ] && \
|
|
cd $$d || continue; \
|
|
$(SCRIPT_DIR)/package-metadata.pl pkgcyclonedxsbom Packages.manifest > Packages.bom.cdx.json || true; \
|
|
); done
|
|
endif
|
|
endif
|
|
$(call sha256sums,$(OUTPUT_DIR)/packages/$(ARCH_PACKAGES),1)
|
|
|
|
$(curdir)/flags-install:= -j1
|
|
|
|
$(eval $(call stampfile,$(curdir),package,prereq,.config))
|
|
$(eval $(call stampfile,$(curdir),package,cleanup,.config $(TMP_DIR)/.packageinfo))
|
|
$(eval $(call stampfile,$(curdir),package,compile,$(TMP_DIR)/.build))
|
|
$(eval $(call stampfile,$(curdir),package,install,$(TMP_DIR)/.build))
|
|
$(eval $(call stampfile,$(curdir),package,check,$(TMP_DIR)/.build))
|
|
|
|
$(eval $(call subdir,$(curdir)))
|