xref: /OK3568_Linux_fs/yocto/poky/meta/classes/image.bbclass (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun
2*4882a593SmuzhiyunIMAGE_CLASSES ??= ""
3*4882a593Smuzhiyun
4*4882a593Smuzhiyun# rootfs bootstrap install
5*4882a593Smuzhiyun# warning -  image-container resets this
6*4882a593SmuzhiyunROOTFS_BOOTSTRAP_INSTALL = "run-postinsts"
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun# Handle inherits of any of the image classes we need
9*4882a593SmuzhiyunIMGCLASSES = "rootfs_${IMAGE_PKGTYPE} image_types ${IMAGE_CLASSES}"
10*4882a593Smuzhiyun# Only Linux SDKs support populate_sdk_ext, fall back to populate_sdk_base
11*4882a593Smuzhiyun# in the non-Linux SDK_OS case, such as mingw32
12*4882a593SmuzhiyunIMGCLASSES += "${@['populate_sdk_base', 'populate_sdk_ext']['linux' in d.getVar("SDK_OS")]}"
13*4882a593SmuzhiyunIMGCLASSES += "${@bb.utils.contains_any('IMAGE_FSTYPES', 'live iso hddimg', 'image-live', '', d)}"
14*4882a593SmuzhiyunIMGCLASSES += "${@bb.utils.contains('IMAGE_FSTYPES', 'container', 'image-container', '', d)}"
15*4882a593SmuzhiyunIMGCLASSES += "image_types_wic"
16*4882a593SmuzhiyunIMGCLASSES += "rootfs-postcommands"
17*4882a593SmuzhiyunIMGCLASSES += "image-postinst-intercepts"
18*4882a593SmuzhiyunIMGCLASSES += "overlayfs-etc"
19*4882a593Smuzhiyuninherit ${IMGCLASSES}
20*4882a593Smuzhiyun
21*4882a593SmuzhiyunTOOLCHAIN_TARGET_TASK += "${PACKAGE_INSTALL}"
22*4882a593SmuzhiyunTOOLCHAIN_TARGET_TASK_ATTEMPTONLY += "${PACKAGE_INSTALL_ATTEMPTONLY}"
23*4882a593SmuzhiyunPOPULATE_SDK_POST_TARGET_COMMAND += "rootfs_sysroot_relativelinks; "
24*4882a593Smuzhiyun
25*4882a593SmuzhiyunLICENSE ?= "MIT"
26*4882a593SmuzhiyunPACKAGES = ""
27*4882a593SmuzhiyunDEPENDS += "${@' '.join(["%s-qemuwrapper-cross" % m for m in d.getVar("MULTILIB_VARIANTS").split()])} qemuwrapper-cross depmodwrapper-cross cross-localedef-native"
28*4882a593SmuzhiyunRDEPENDS += "${PACKAGE_INSTALL} ${LINGUAS_INSTALL} ${IMAGE_INSTALL_DEBUGFS}"
29*4882a593SmuzhiyunRRECOMMENDS += "${PACKAGE_INSTALL_ATTEMPTONLY}"
30*4882a593SmuzhiyunPATH:prepend = "${@":".join(all_multilib_tune_values(d, 'STAGING_BINDIR_CROSS').split())}:"
31*4882a593Smuzhiyun
32*4882a593SmuzhiyunINHIBIT_DEFAULT_DEPS = "1"
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun# IMAGE_FEATURES may contain any available package group
35*4882a593SmuzhiyunIMAGE_FEATURES ?= ""
36*4882a593SmuzhiyunIMAGE_FEATURES[type] = "list"
37*4882a593SmuzhiyunIMAGE_FEATURES[validitems] += "debug-tweaks read-only-rootfs read-only-rootfs-delayed-postinsts stateless-rootfs empty-root-password allow-empty-password allow-root-login post-install-logging overlayfs-etc"
38*4882a593Smuzhiyun
39*4882a593Smuzhiyun# Generate companion debugfs?
40*4882a593SmuzhiyunIMAGE_GEN_DEBUGFS ?= "0"
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun# These packages will be installed as additional into debug rootfs
43*4882a593SmuzhiyunIMAGE_INSTALL_DEBUGFS ?= ""
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun# These packages will be removed from a read-only rootfs after all other
46*4882a593Smuzhiyun# packages have been installed
47*4882a593SmuzhiyunROOTFS_RO_UNNEEDED ??= "update-rc.d base-passwd shadow ${VIRTUAL-RUNTIME_update-alternatives} ${ROOTFS_BOOTSTRAP_INSTALL}"
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun# packages to install from features
50*4882a593SmuzhiyunFEATURE_INSTALL = "${@' '.join(oe.packagegroup.required_packages(oe.data.typed_value('IMAGE_FEATURES', d), d))}"
51*4882a593SmuzhiyunFEATURE_INSTALL[vardepvalue] = "${FEATURE_INSTALL}"
52*4882a593SmuzhiyunFEATURE_INSTALL_OPTIONAL = "${@' '.join(oe.packagegroup.optional_packages(oe.data.typed_value('IMAGE_FEATURES', d), d))}"
53*4882a593SmuzhiyunFEATURE_INSTALL_OPTIONAL[vardepvalue] = "${FEATURE_INSTALL_OPTIONAL}"
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun# Define some very basic feature package groups
56*4882a593SmuzhiyunFEATURE_PACKAGES_package-management = "${ROOTFS_PKGMANAGE}"
57*4882a593SmuzhiyunSPLASH ?= "${@bb.utils.contains("MACHINE_FEATURES", "screen", "psplash", "", d)}"
58*4882a593SmuzhiyunFEATURE_PACKAGES_splash = "${SPLASH}"
59*4882a593Smuzhiyun
60*4882a593SmuzhiyunIMAGE_INSTALL_COMPLEMENTARY = '${@complementary_globs("IMAGE_FEATURES", d)}'
61*4882a593Smuzhiyun
62*4882a593Smuzhiyundef check_image_features(d):
63*4882a593Smuzhiyun    valid_features = (d.getVarFlag('IMAGE_FEATURES', 'validitems') or "").split()
64*4882a593Smuzhiyun    valid_features += d.getVarFlags('COMPLEMENTARY_GLOB').keys()
65*4882a593Smuzhiyun    for var in d:
66*4882a593Smuzhiyun       if var.startswith("FEATURE_PACKAGES_"):
67*4882a593Smuzhiyun           valid_features.append(var[17:])
68*4882a593Smuzhiyun    valid_features.sort()
69*4882a593Smuzhiyun
70*4882a593Smuzhiyun    features = set(oe.data.typed_value('IMAGE_FEATURES', d))
71*4882a593Smuzhiyun    for feature in features:
72*4882a593Smuzhiyun        if feature not in valid_features:
73*4882a593Smuzhiyun            if bb.utils.contains('EXTRA_IMAGE_FEATURES', feature, True, False, d):
74*4882a593Smuzhiyun                raise bb.parse.SkipRecipe("'%s' in IMAGE_FEATURES (added via EXTRA_IMAGE_FEATURES) is not a valid image feature. Valid features: %s" % (feature, ' '.join(valid_features)))
75*4882a593Smuzhiyun            else:
76*4882a593Smuzhiyun                raise bb.parse.SkipRecipe("'%s' in IMAGE_FEATURES is not a valid image feature. Valid features: %s" % (feature, ' '.join(valid_features)))
77*4882a593Smuzhiyun
78*4882a593SmuzhiyunIMAGE_INSTALL ?= ""
79*4882a593SmuzhiyunIMAGE_INSTALL[type] = "list"
80*4882a593Smuzhiyunexport PACKAGE_INSTALL ?= "${IMAGE_INSTALL} ${ROOTFS_BOOTSTRAP_INSTALL} ${FEATURE_INSTALL}"
81*4882a593SmuzhiyunPACKAGE_INSTALL_ATTEMPTONLY ?= "${FEATURE_INSTALL_OPTIONAL}"
82*4882a593Smuzhiyun
83*4882a593SmuzhiyunIMGDEPLOYDIR = "${WORKDIR}/deploy-${PN}-image-complete"
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun# Images are generally built explicitly, do not need to be part of world.
86*4882a593SmuzhiyunEXCLUDE_FROM_WORLD = "1"
87*4882a593Smuzhiyun
88*4882a593SmuzhiyunUSE_DEVFS ?= "1"
89*4882a593SmuzhiyunUSE_DEPMOD ?= "1"
90*4882a593Smuzhiyun
91*4882a593SmuzhiyunPID = "${@os.getpid()}"
92*4882a593Smuzhiyun
93*4882a593SmuzhiyunPACKAGE_ARCH = "${MACHINE_ARCH}"
94*4882a593Smuzhiyun
95*4882a593SmuzhiyunLDCONFIGDEPEND ?= "ldconfig-native:do_populate_sysroot"
96*4882a593SmuzhiyunLDCONFIGDEPEND:libc-musl = ""
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun# This is needed to have depmod data in PKGDATA_DIR,
99*4882a593Smuzhiyun# but if you're building small initramfs image
100*4882a593Smuzhiyun# e.g. to include it in your kernel, you probably
101*4882a593Smuzhiyun# don't want this dependency, which is causing dependency loop
102*4882a593SmuzhiyunKERNELDEPMODDEPEND ?= "virtual/kernel:do_packagedata"
103*4882a593Smuzhiyun
104*4882a593Smuzhiyundo_rootfs[depends] += " \
105*4882a593Smuzhiyun    makedevs-native:do_populate_sysroot virtual/fakeroot-native:do_populate_sysroot ${LDCONFIGDEPEND} \
106*4882a593Smuzhiyun    virtual/update-alternatives-native:do_populate_sysroot update-rc.d-native:do_populate_sysroot \
107*4882a593Smuzhiyun    ${KERNELDEPMODDEPEND} \
108*4882a593Smuzhiyun"
109*4882a593Smuzhiyundo_rootfs[recrdeptask] += "do_packagedata"
110*4882a593Smuzhiyun
111*4882a593Smuzhiyundef rootfs_command_variables(d):
112*4882a593Smuzhiyun    return ['ROOTFS_POSTPROCESS_COMMAND','ROOTFS_PREPROCESS_COMMAND','ROOTFS_POSTINSTALL_COMMAND','ROOTFS_POSTUNINSTALL_COMMAND','OPKG_PREPROCESS_COMMANDS','OPKG_POSTPROCESS_COMMANDS','IMAGE_POSTPROCESS_COMMAND',
113*4882a593Smuzhiyun            'IMAGE_PREPROCESS_COMMAND','RPM_PREPROCESS_COMMANDS','RPM_POSTPROCESS_COMMANDS','DEB_PREPROCESS_COMMANDS','DEB_POSTPROCESS_COMMANDS']
114*4882a593Smuzhiyun
115*4882a593Smuzhiyunpython () {
116*4882a593Smuzhiyun    variables = rootfs_command_variables(d)
117*4882a593Smuzhiyun    for var in variables:
118*4882a593Smuzhiyun        if d.getVar(var, False):
119*4882a593Smuzhiyun            d.setVarFlag(var, 'func', '1')
120*4882a593Smuzhiyun}
121*4882a593Smuzhiyun
122*4882a593Smuzhiyundef rootfs_variables(d):
123*4882a593Smuzhiyun    from oe.rootfs import variable_depends
124*4882a593Smuzhiyun    variables = ['IMAGE_DEVICE_TABLE','IMAGE_DEVICE_TABLES','BUILD_IMAGES_FROM_FEEDS','IMAGE_TYPES_MASKED','IMAGE_ROOTFS_ALIGNMENT','IMAGE_OVERHEAD_FACTOR','IMAGE_ROOTFS_SIZE','IMAGE_ROOTFS_EXTRA_SPACE',
125*4882a593Smuzhiyun                 'IMAGE_ROOTFS_MAXSIZE','IMAGE_NAME','IMAGE_LINK_NAME','IMAGE_MANIFEST','DEPLOY_DIR_IMAGE','IMAGE_FSTYPES','IMAGE_INSTALL_COMPLEMENTARY','IMAGE_LINGUAS', 'IMAGE_LINGUAS_COMPLEMENTARY', 'IMAGE_LOCALES_ARCHIVE',
126*4882a593Smuzhiyun                 'MULTILIBRE_ALLOW_REP','MULTILIB_TEMP_ROOTFS','MULTILIB_VARIANTS','MULTILIBS','ALL_MULTILIB_PACKAGE_ARCHS','MULTILIB_GLOBAL_VARIANTS','BAD_RECOMMENDATIONS','NO_RECOMMENDATIONS',
127*4882a593Smuzhiyun                 'PACKAGE_ARCHS','PACKAGE_CLASSES','TARGET_VENDOR','TARGET_ARCH','TARGET_OS','OVERRIDES','BBEXTENDVARIANT','FEED_DEPLOYDIR_BASE_URI','INTERCEPT_DIR','USE_DEVFS',
128*4882a593Smuzhiyun                 'CONVERSIONTYPES', 'IMAGE_GEN_DEBUGFS', 'ROOTFS_RO_UNNEEDED', 'IMGDEPLOYDIR', 'PACKAGE_EXCLUDE_COMPLEMENTARY', 'REPRODUCIBLE_TIMESTAMP_ROOTFS', 'IMAGE_INSTALL_DEBUGFS']
129*4882a593Smuzhiyun    variables.extend(rootfs_command_variables(d))
130*4882a593Smuzhiyun    variables.extend(variable_depends(d))
131*4882a593Smuzhiyun    return " ".join(variables)
132*4882a593Smuzhiyun
133*4882a593Smuzhiyundo_rootfs[vardeps] += "${@rootfs_variables(d)}"
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun# This is needed to have kernel image in DEPLOY_DIR.
136*4882a593Smuzhiyun# This follows many common usecases and user expectations.
137*4882a593Smuzhiyun# But if you are building an image which doesn't need the kernel image at all,
138*4882a593Smuzhiyun# you can unset this variable manually.
139*4882a593SmuzhiyunKERNEL_DEPLOY_DEPEND ?= "virtual/kernel:do_deploy"
140*4882a593Smuzhiyundo_build[depends] += "${KERNEL_DEPLOY_DEPEND}"
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun
143*4882a593Smuzhiyunpython () {
144*4882a593Smuzhiyun    def extraimage_getdepends(task):
145*4882a593Smuzhiyun        deps = ""
146*4882a593Smuzhiyun        for dep in (d.getVar('EXTRA_IMAGEDEPENDS') or "").split():
147*4882a593Smuzhiyun            if ":" in dep:
148*4882a593Smuzhiyun                deps += " %s " % (dep)
149*4882a593Smuzhiyun            else:
150*4882a593Smuzhiyun                deps += " %s:%s" % (dep, task)
151*4882a593Smuzhiyun        return deps
152*4882a593Smuzhiyun
153*4882a593Smuzhiyun    d.appendVarFlag('do_image_complete', 'depends', extraimage_getdepends('do_populate_sysroot'))
154*4882a593Smuzhiyun
155*4882a593Smuzhiyun    deps = " " + imagetypes_getdepends(d)
156*4882a593Smuzhiyun    d.appendVarFlag('do_rootfs', 'depends', deps)
157*4882a593Smuzhiyun
158*4882a593Smuzhiyun    #process IMAGE_FEATURES, we must do this before runtime_mapping_rename
159*4882a593Smuzhiyun    #Check for replaces image features
160*4882a593Smuzhiyun    features = set(oe.data.typed_value('IMAGE_FEATURES', d))
161*4882a593Smuzhiyun    remain_features = features.copy()
162*4882a593Smuzhiyun    for feature in features:
163*4882a593Smuzhiyun        replaces = set((d.getVar("IMAGE_FEATURES_REPLACES_%s" % feature) or "").split())
164*4882a593Smuzhiyun        remain_features -= replaces
165*4882a593Smuzhiyun
166*4882a593Smuzhiyun    #Check for conflict image features
167*4882a593Smuzhiyun    for feature in remain_features:
168*4882a593Smuzhiyun        conflicts = set((d.getVar("IMAGE_FEATURES_CONFLICTS_%s" % feature) or "").split())
169*4882a593Smuzhiyun        temp = conflicts & remain_features
170*4882a593Smuzhiyun        if temp:
171*4882a593Smuzhiyun            bb.fatal("%s contains conflicting IMAGE_FEATURES %s %s" % (d.getVar('PN'), feature, ' '.join(list(temp))))
172*4882a593Smuzhiyun
173*4882a593Smuzhiyun    d.setVar('IMAGE_FEATURES', ' '.join(sorted(list(remain_features))))
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun    check_image_features(d)
176*4882a593Smuzhiyun}
177*4882a593Smuzhiyun
178*4882a593SmuzhiyunIMAGE_POSTPROCESS_COMMAND ?= ""
179*4882a593Smuzhiyun
180*4882a593SmuzhiyunIMAGE_LINGUAS ??= ""
181*4882a593Smuzhiyun
182*4882a593SmuzhiyunLINGUAS_INSTALL ?= "${@" ".join(map(lambda s: "locale-base-%s" % s, d.getVar('IMAGE_LINGUAS').split()))}"
183*4882a593Smuzhiyun
184*4882a593Smuzhiyun# per default create a locale archive
185*4882a593SmuzhiyunIMAGE_LOCALES_ARCHIVE ?= '1'
186*4882a593Smuzhiyun
187*4882a593Smuzhiyun# Prefer image, but use the fallback files for lookups if the image ones
188*4882a593Smuzhiyun# aren't yet available.
189*4882a593SmuzhiyunPSEUDO_PASSWD = "${IMAGE_ROOTFS}:${STAGING_DIR_NATIVE}"
190*4882a593Smuzhiyun
191*4882a593SmuzhiyunPSEUDO_IGNORE_PATHS .= ",${WORKDIR}/intercept_scripts,${WORKDIR}/oe-rootfs-repo,${WORKDIR}/sstate-build-image_complete"
192*4882a593Smuzhiyun
193*4882a593SmuzhiyunPACKAGE_EXCLUDE ??= ""
194*4882a593SmuzhiyunPACKAGE_EXCLUDE[type] = "list"
195*4882a593Smuzhiyun
196*4882a593Smuzhiyunfakeroot python do_rootfs () {
197*4882a593Smuzhiyun    from oe.rootfs import create_rootfs
198*4882a593Smuzhiyun    from oe.manifest import create_manifest
199*4882a593Smuzhiyun    import logging
200*4882a593Smuzhiyun
201*4882a593Smuzhiyun    logger = d.getVar('BB_TASK_LOGGER', False)
202*4882a593Smuzhiyun    if logger:
203*4882a593Smuzhiyun        logcatcher = bb.utils.LogCatcher()
204*4882a593Smuzhiyun        logger.addHandler(logcatcher)
205*4882a593Smuzhiyun    else:
206*4882a593Smuzhiyun        logcatcher = None
207*4882a593Smuzhiyun
208*4882a593Smuzhiyun    # NOTE: if you add, remove or significantly refactor the stages of this
209*4882a593Smuzhiyun    # process then you should recalculate the weightings here. This is quite
210*4882a593Smuzhiyun    # easy to do - just change the MultiStageProgressReporter line temporarily
211*4882a593Smuzhiyun    # to pass debug=True as the last parameter and you'll get a printout of
212*4882a593Smuzhiyun    # the weightings as well as a map to the lines where next_stage() was
213*4882a593Smuzhiyun    # called. Of course this isn't critical, but it helps to keep the progress
214*4882a593Smuzhiyun    # reporting accurate.
215*4882a593Smuzhiyun    stage_weights = [1, 203, 354, 186, 65, 4228, 1, 353, 49, 330, 382, 23, 1]
216*4882a593Smuzhiyun    progress_reporter = bb.progress.MultiStageProgressReporter(d, stage_weights)
217*4882a593Smuzhiyun    progress_reporter.next_stage()
218*4882a593Smuzhiyun
219*4882a593Smuzhiyun    # Handle package exclusions
220*4882a593Smuzhiyun    excl_pkgs = d.getVar("PACKAGE_EXCLUDE").split()
221*4882a593Smuzhiyun    inst_pkgs = d.getVar("PACKAGE_INSTALL").split()
222*4882a593Smuzhiyun    inst_attempt_pkgs = d.getVar("PACKAGE_INSTALL_ATTEMPTONLY").split()
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun    d.setVar('PACKAGE_INSTALL_ORIG', ' '.join(inst_pkgs))
225*4882a593Smuzhiyun    d.setVar('PACKAGE_INSTALL_ATTEMPTONLY', ' '.join(inst_attempt_pkgs))
226*4882a593Smuzhiyun
227*4882a593Smuzhiyun    for pkg in excl_pkgs:
228*4882a593Smuzhiyun        if pkg in inst_pkgs:
229*4882a593Smuzhiyun            bb.warn("Package %s, set to be excluded, is in %s PACKAGE_INSTALL (%s).  It will be removed from the list." % (pkg, d.getVar('PN'), inst_pkgs))
230*4882a593Smuzhiyun            inst_pkgs.remove(pkg)
231*4882a593Smuzhiyun
232*4882a593Smuzhiyun        if pkg in inst_attempt_pkgs:
233*4882a593Smuzhiyun            bb.warn("Package %s, set to be excluded, is in %s PACKAGE_INSTALL_ATTEMPTONLY (%s).  It will be removed from the list." % (pkg, d.getVar('PN'), inst_pkgs))
234*4882a593Smuzhiyun            inst_attempt_pkgs.remove(pkg)
235*4882a593Smuzhiyun
236*4882a593Smuzhiyun    d.setVar("PACKAGE_INSTALL", ' '.join(inst_pkgs))
237*4882a593Smuzhiyun    d.setVar("PACKAGE_INSTALL_ATTEMPTONLY", ' '.join(inst_attempt_pkgs))
238*4882a593Smuzhiyun
239*4882a593Smuzhiyun    # Ensure we handle package name remapping
240*4882a593Smuzhiyun    # We have to delay the runtime_mapping_rename until just before rootfs runs
241*4882a593Smuzhiyun    # otherwise, the multilib renaming could step in and squash any fixups that
242*4882a593Smuzhiyun    # may have occurred.
243*4882a593Smuzhiyun    pn = d.getVar('PN')
244*4882a593Smuzhiyun    runtime_mapping_rename("PACKAGE_INSTALL", pn, d)
245*4882a593Smuzhiyun    runtime_mapping_rename("PACKAGE_INSTALL_ATTEMPTONLY", pn, d)
246*4882a593Smuzhiyun    runtime_mapping_rename("BAD_RECOMMENDATIONS", pn, d)
247*4882a593Smuzhiyun
248*4882a593Smuzhiyun    # Generate the initial manifest
249*4882a593Smuzhiyun    create_manifest(d)
250*4882a593Smuzhiyun
251*4882a593Smuzhiyun    progress_reporter.next_stage()
252*4882a593Smuzhiyun
253*4882a593Smuzhiyun    # generate rootfs
254*4882a593Smuzhiyun    d.setVarFlag('REPRODUCIBLE_TIMESTAMP_ROOTFS', 'export', '1')
255*4882a593Smuzhiyun    create_rootfs(d, progress_reporter=progress_reporter, logcatcher=logcatcher)
256*4882a593Smuzhiyun
257*4882a593Smuzhiyun    progress_reporter.finish()
258*4882a593Smuzhiyun}
259*4882a593Smuzhiyundo_rootfs[dirs] = "${TOPDIR}"
260*4882a593Smuzhiyundo_rootfs[cleandirs] += "${IMAGE_ROOTFS} ${IMGDEPLOYDIR} ${S}"
261*4882a593Smuzhiyundo_rootfs[file-checksums] += "${POSTINST_INTERCEPT_CHECKSUMS}"
262*4882a593Smuzhiyunaddtask rootfs after do_prepare_recipe_sysroot
263*4882a593Smuzhiyun
264*4882a593Smuzhiyunfakeroot python do_image () {
265*4882a593Smuzhiyun    from oe.utils import execute_pre_post_process
266*4882a593Smuzhiyun
267*4882a593Smuzhiyun    d.setVarFlag('REPRODUCIBLE_TIMESTAMP_ROOTFS', 'export', '1')
268*4882a593Smuzhiyun    pre_process_cmds = d.getVar("IMAGE_PREPROCESS_COMMAND")
269*4882a593Smuzhiyun
270*4882a593Smuzhiyun    execute_pre_post_process(d, pre_process_cmds)
271*4882a593Smuzhiyun}
272*4882a593Smuzhiyundo_image[dirs] = "${TOPDIR}"
273*4882a593Smuzhiyunaddtask do_image after do_rootfs
274*4882a593Smuzhiyun
275*4882a593Smuzhiyunfakeroot python do_image_complete () {
276*4882a593Smuzhiyun    from oe.utils import execute_pre_post_process
277*4882a593Smuzhiyun
278*4882a593Smuzhiyun    post_process_cmds = d.getVar("IMAGE_POSTPROCESS_COMMAND")
279*4882a593Smuzhiyun
280*4882a593Smuzhiyun    execute_pre_post_process(d, post_process_cmds)
281*4882a593Smuzhiyun}
282*4882a593Smuzhiyundo_image_complete[dirs] = "${TOPDIR}"
283*4882a593SmuzhiyunSSTATETASKS += "do_image_complete"
284*4882a593SmuzhiyunSSTATE_SKIP_CREATION:task-image-complete = '1'
285*4882a593Smuzhiyundo_image_complete[sstate-inputdirs] = "${IMGDEPLOYDIR}"
286*4882a593Smuzhiyundo_image_complete[sstate-outputdirs] = "${DEPLOY_DIR_IMAGE}"
287*4882a593Smuzhiyundo_image_complete[stamp-extra-info] = "${MACHINE_ARCH}"
288*4882a593Smuzhiyunaddtask do_image_complete after do_image before do_build
289*4882a593Smuzhiyunpython do_image_complete_setscene () {
290*4882a593Smuzhiyun    sstate_setscene(d)
291*4882a593Smuzhiyun}
292*4882a593Smuzhiyunaddtask do_image_complete_setscene
293*4882a593Smuzhiyun
294*4882a593Smuzhiyun# Add image-level QA/sanity checks to IMAGE_QA_COMMANDS
295*4882a593Smuzhiyun#
296*4882a593Smuzhiyun# IMAGE_QA_COMMANDS += " \
297*4882a593Smuzhiyun#     image_check_everything_ok \
298*4882a593Smuzhiyun# "
299*4882a593Smuzhiyun# This task runs all functions in IMAGE_QA_COMMANDS after the rootfs
300*4882a593Smuzhiyun# construction has completed in order to validate the resulting image.
301*4882a593Smuzhiyun#
302*4882a593Smuzhiyun# The functions should use ${IMAGE_ROOTFS} to find the unpacked rootfs
303*4882a593Smuzhiyun# directory, which if QA passes will be the basis for the images.
304*4882a593Smuzhiyunfakeroot python do_image_qa () {
305*4882a593Smuzhiyun    from oe.utils import ImageQAFailed
306*4882a593Smuzhiyun
307*4882a593Smuzhiyun    qa_cmds = (d.getVar('IMAGE_QA_COMMANDS') or '').split()
308*4882a593Smuzhiyun    qamsg = ""
309*4882a593Smuzhiyun
310*4882a593Smuzhiyun    for cmd in qa_cmds:
311*4882a593Smuzhiyun        try:
312*4882a593Smuzhiyun            bb.build.exec_func(cmd, d)
313*4882a593Smuzhiyun        except oe.utils.ImageQAFailed as e:
314*4882a593Smuzhiyun            qamsg = qamsg + '\tImage QA function %s failed: %s\n' % (e.name, e.description)
315*4882a593Smuzhiyun        except Exception as e:
316*4882a593Smuzhiyun            qamsg = qamsg + '\tImage QA function %s failed: %s\n' % (cmd, e)
317*4882a593Smuzhiyun
318*4882a593Smuzhiyun    if qamsg:
319*4882a593Smuzhiyun        imgname = d.getVar('IMAGE_NAME')
320*4882a593Smuzhiyun        bb.fatal("QA errors found whilst validating image: %s\n%s" % (imgname, qamsg))
321*4882a593Smuzhiyun}
322*4882a593Smuzhiyunaddtask do_image_qa after do_rootfs before do_image
323*4882a593Smuzhiyun
324*4882a593SmuzhiyunSSTATETASKS += "do_image_qa"
325*4882a593SmuzhiyunSSTATE_SKIP_CREATION:task-image-qa = '1'
326*4882a593Smuzhiyundo_image_qa[sstate-inputdirs] = ""
327*4882a593Smuzhiyundo_image_qa[sstate-outputdirs] = ""
328*4882a593Smuzhiyunpython do_image_qa_setscene () {
329*4882a593Smuzhiyun    sstate_setscene(d)
330*4882a593Smuzhiyun}
331*4882a593Smuzhiyunaddtask do_image_qa_setscene
332*4882a593Smuzhiyun
333*4882a593Smuzhiyundef setup_debugfs_variables(d):
334*4882a593Smuzhiyun    d.appendVar('IMAGE_ROOTFS', '-dbg')
335*4882a593Smuzhiyun    if d.getVar('IMAGE_LINK_NAME'):
336*4882a593Smuzhiyun        d.appendVar('IMAGE_LINK_NAME', '-dbg')
337*4882a593Smuzhiyun    d.appendVar('IMAGE_NAME','-dbg')
338*4882a593Smuzhiyun    d.setVar('IMAGE_BUILDING_DEBUGFS', 'true')
339*4882a593Smuzhiyun    debugfs_image_fstypes = d.getVar('IMAGE_FSTYPES_DEBUGFS')
340*4882a593Smuzhiyun    if debugfs_image_fstypes:
341*4882a593Smuzhiyun        d.setVar('IMAGE_FSTYPES', debugfs_image_fstypes)
342*4882a593Smuzhiyun
343*4882a593Smuzhiyunpython setup_debugfs () {
344*4882a593Smuzhiyun    setup_debugfs_variables(d)
345*4882a593Smuzhiyun}
346*4882a593Smuzhiyun
347*4882a593Smuzhiyunpython () {
348*4882a593Smuzhiyun    vardeps = set()
349*4882a593Smuzhiyun    # We allow CONVERSIONTYPES to have duplicates. That avoids breaking
350*4882a593Smuzhiyun    # derived distros when OE-core or some other layer independently adds
351*4882a593Smuzhiyun    # the same type. There is still only one command for each type, but
352*4882a593Smuzhiyun    # presumably the commands will do the same when the type is the same,
353*4882a593Smuzhiyun    # even when added in different places.
354*4882a593Smuzhiyun    #
355*4882a593Smuzhiyun    # Without de-duplication, gen_conversion_cmds() below
356*4882a593Smuzhiyun    # would create the same compression command multiple times.
357*4882a593Smuzhiyun    ctypes = set(d.getVar('CONVERSIONTYPES').split())
358*4882a593Smuzhiyun    old_overrides = d.getVar('OVERRIDES', False)
359*4882a593Smuzhiyun
360*4882a593Smuzhiyun    def _image_base_type(type):
361*4882a593Smuzhiyun        basetype = type
362*4882a593Smuzhiyun        for ctype in ctypes:
363*4882a593Smuzhiyun            if type.endswith("." + ctype):
364*4882a593Smuzhiyun                basetype = type[:-len("." + ctype)]
365*4882a593Smuzhiyun                break
366*4882a593Smuzhiyun
367*4882a593Smuzhiyun        if basetype != type:
368*4882a593Smuzhiyun            # New base type itself might be generated by a conversion command.
369*4882a593Smuzhiyun            basetype = _image_base_type(basetype)
370*4882a593Smuzhiyun
371*4882a593Smuzhiyun        return basetype
372*4882a593Smuzhiyun
373*4882a593Smuzhiyun    basetypes = {}
374*4882a593Smuzhiyun    alltypes = d.getVar('IMAGE_FSTYPES').split()
375*4882a593Smuzhiyun    typedeps = {}
376*4882a593Smuzhiyun
377*4882a593Smuzhiyun    if d.getVar('IMAGE_GEN_DEBUGFS') == "1":
378*4882a593Smuzhiyun        debugfs_fstypes = d.getVar('IMAGE_FSTYPES_DEBUGFS').split()
379*4882a593Smuzhiyun        for t in debugfs_fstypes:
380*4882a593Smuzhiyun            alltypes.append("debugfs_" + t)
381*4882a593Smuzhiyun
382*4882a593Smuzhiyun    def _add_type(t):
383*4882a593Smuzhiyun        baset = _image_base_type(t)
384*4882a593Smuzhiyun        input_t = t
385*4882a593Smuzhiyun        if baset not in basetypes:
386*4882a593Smuzhiyun            basetypes[baset]= []
387*4882a593Smuzhiyun        if t not in basetypes[baset]:
388*4882a593Smuzhiyun            basetypes[baset].append(t)
389*4882a593Smuzhiyun        debug = ""
390*4882a593Smuzhiyun        if t.startswith("debugfs_"):
391*4882a593Smuzhiyun            t = t[8:]
392*4882a593Smuzhiyun            debug = "debugfs_"
393*4882a593Smuzhiyun        deps = (d.getVar('IMAGE_TYPEDEP:' + t) or "").split()
394*4882a593Smuzhiyun        vardeps.add('IMAGE_TYPEDEP:' + t)
395*4882a593Smuzhiyun        if baset not in typedeps:
396*4882a593Smuzhiyun            typedeps[baset] = set()
397*4882a593Smuzhiyun        deps = [debug + dep for dep in deps]
398*4882a593Smuzhiyun        for dep in deps:
399*4882a593Smuzhiyun            if dep not in alltypes:
400*4882a593Smuzhiyun                alltypes.append(dep)
401*4882a593Smuzhiyun            _add_type(dep)
402*4882a593Smuzhiyun            basedep = _image_base_type(dep)
403*4882a593Smuzhiyun            typedeps[baset].add(basedep)
404*4882a593Smuzhiyun
405*4882a593Smuzhiyun        if baset != input_t:
406*4882a593Smuzhiyun            _add_type(baset)
407*4882a593Smuzhiyun
408*4882a593Smuzhiyun    for t in alltypes[:]:
409*4882a593Smuzhiyun        _add_type(t)
410*4882a593Smuzhiyun
411*4882a593Smuzhiyun    d.appendVarFlag('do_image', 'vardeps', ' '.join(vardeps))
412*4882a593Smuzhiyun
413*4882a593Smuzhiyun    maskedtypes = (d.getVar('IMAGE_TYPES_MASKED') or "").split()
414*4882a593Smuzhiyun    maskedtypes = [dbg + t for t in maskedtypes for dbg in ("", "debugfs_")]
415*4882a593Smuzhiyun
416*4882a593Smuzhiyun    for t in basetypes:
417*4882a593Smuzhiyun        vardeps = set()
418*4882a593Smuzhiyun        cmds = []
419*4882a593Smuzhiyun        subimages = []
420*4882a593Smuzhiyun        realt = t
421*4882a593Smuzhiyun
422*4882a593Smuzhiyun        if t in maskedtypes:
423*4882a593Smuzhiyun            continue
424*4882a593Smuzhiyun
425*4882a593Smuzhiyun        localdata = bb.data.createCopy(d)
426*4882a593Smuzhiyun        debug = ""
427*4882a593Smuzhiyun        if t.startswith("debugfs_"):
428*4882a593Smuzhiyun            setup_debugfs_variables(localdata)
429*4882a593Smuzhiyun            debug = "setup_debugfs "
430*4882a593Smuzhiyun            realt = t[8:]
431*4882a593Smuzhiyun        localdata.setVar('OVERRIDES', '%s:%s' % (realt, old_overrides))
432*4882a593Smuzhiyun        localdata.setVar('type', realt)
433*4882a593Smuzhiyun        # Delete DATETIME so we don't expand any references to it now
434*4882a593Smuzhiyun        # This means the task's hash can be stable rather than having hardcoded
435*4882a593Smuzhiyun        # date/time values. It will get expanded at execution time.
436*4882a593Smuzhiyun        # Similarly TMPDIR since otherwise we see QA stamp comparision problems
437*4882a593Smuzhiyun        # Expand PV else it can trigger get_srcrev which can fail due to these variables being unset
438*4882a593Smuzhiyun        localdata.setVar('PV', d.getVar('PV'))
439*4882a593Smuzhiyun        localdata.delVar('DATETIME')
440*4882a593Smuzhiyun        localdata.delVar('DATE')
441*4882a593Smuzhiyun        localdata.delVar('TMPDIR')
442*4882a593Smuzhiyun        localdata.delVar('IMAGE_VERSION_SUFFIX')
443*4882a593Smuzhiyun        vardepsexclude = (d.getVarFlag('IMAGE_CMD:' + realt, 'vardepsexclude') or '').split()
444*4882a593Smuzhiyun        for dep in vardepsexclude:
445*4882a593Smuzhiyun            localdata.delVar(dep)
446*4882a593Smuzhiyun
447*4882a593Smuzhiyun        image_cmd = localdata.getVar("IMAGE_CMD")
448*4882a593Smuzhiyun        vardeps.add('IMAGE_CMD:' + realt)
449*4882a593Smuzhiyun        if image_cmd:
450*4882a593Smuzhiyun            cmds.append("\t" + image_cmd)
451*4882a593Smuzhiyun        else:
452*4882a593Smuzhiyun            bb.fatal("No IMAGE_CMD defined for IMAGE_FSTYPES entry '%s' - possibly invalid type name or missing support class" % t)
453*4882a593Smuzhiyun        cmds.append(localdata.expand("\tcd ${IMGDEPLOYDIR}"))
454*4882a593Smuzhiyun
455*4882a593Smuzhiyun        # Since a copy of IMAGE_CMD:xxx will be inlined within do_image_xxx,
456*4882a593Smuzhiyun        # prevent a redundant copy of IMAGE_CMD:xxx being emitted as a function.
457*4882a593Smuzhiyun        d.delVarFlag('IMAGE_CMD:' + realt, 'func')
458*4882a593Smuzhiyun
459*4882a593Smuzhiyun        rm_tmp_images = set()
460*4882a593Smuzhiyun        def gen_conversion_cmds(bt):
461*4882a593Smuzhiyun            for ctype in sorted(ctypes):
462*4882a593Smuzhiyun                if bt.endswith("." + ctype):
463*4882a593Smuzhiyun                    type = bt[0:-len(ctype) - 1]
464*4882a593Smuzhiyun                    if type.startswith("debugfs_"):
465*4882a593Smuzhiyun                        type = type[8:]
466*4882a593Smuzhiyun                    # Create input image first.
467*4882a593Smuzhiyun                    gen_conversion_cmds(type)
468*4882a593Smuzhiyun                    localdata.setVar('type', type)
469*4882a593Smuzhiyun                    cmd = "\t" + localdata.getVar("CONVERSION_CMD:" + ctype)
470*4882a593Smuzhiyun                    if cmd not in cmds:
471*4882a593Smuzhiyun                        cmds.append(cmd)
472*4882a593Smuzhiyun                    vardeps.add('CONVERSION_CMD:' + ctype)
473*4882a593Smuzhiyun                    subimage = type + "." + ctype
474*4882a593Smuzhiyun                    if subimage not in subimages:
475*4882a593Smuzhiyun                        subimages.append(subimage)
476*4882a593Smuzhiyun                    if type not in alltypes:
477*4882a593Smuzhiyun                        rm_tmp_images.add(localdata.expand("${IMAGE_NAME}${IMAGE_NAME_SUFFIX}.${type}"))
478*4882a593Smuzhiyun
479*4882a593Smuzhiyun        for bt in basetypes[t]:
480*4882a593Smuzhiyun            gen_conversion_cmds(bt)
481*4882a593Smuzhiyun
482*4882a593Smuzhiyun        localdata.setVar('type', realt)
483*4882a593Smuzhiyun        if t not in alltypes:
484*4882a593Smuzhiyun            rm_tmp_images.add(localdata.expand("${IMAGE_NAME}${IMAGE_NAME_SUFFIX}.${type}"))
485*4882a593Smuzhiyun        else:
486*4882a593Smuzhiyun            subimages.append(realt)
487*4882a593Smuzhiyun
488*4882a593Smuzhiyun        # Clean up after applying all conversion commands. Some of them might
489*4882a593Smuzhiyun        # use the same input, therefore we cannot delete sooner without applying
490*4882a593Smuzhiyun        # some complex dependency analysis.
491*4882a593Smuzhiyun        for image in sorted(rm_tmp_images):
492*4882a593Smuzhiyun            cmds.append("\trm " + image)
493*4882a593Smuzhiyun
494*4882a593Smuzhiyun        after = 'do_image'
495*4882a593Smuzhiyun        for dep in typedeps[t]:
496*4882a593Smuzhiyun            after += ' do_image_%s' % dep.replace("-", "_").replace(".", "_")
497*4882a593Smuzhiyun
498*4882a593Smuzhiyun        task = "do_image_%s" % t.replace("-", "_").replace(".", "_")
499*4882a593Smuzhiyun
500*4882a593Smuzhiyun        d.setVar(task, '\n'.join(cmds))
501*4882a593Smuzhiyun        d.setVarFlag(task, 'func', '1')
502*4882a593Smuzhiyun        d.setVarFlag(task, 'fakeroot', '1')
503*4882a593Smuzhiyun
504*4882a593Smuzhiyun        d.appendVarFlag(task, 'prefuncs', ' ' + debug + ' set_image_size')
505*4882a593Smuzhiyun        d.prependVarFlag(task, 'postfuncs', 'create_symlinks ')
506*4882a593Smuzhiyun        d.appendVarFlag(task, 'subimages', ' ' + ' '.join(subimages))
507*4882a593Smuzhiyun        d.appendVarFlag(task, 'vardeps', ' ' + ' '.join(vardeps))
508*4882a593Smuzhiyun        d.appendVarFlag(task, 'vardepsexclude', ' DATETIME DATE ' + ' '.join(vardepsexclude))
509*4882a593Smuzhiyun
510*4882a593Smuzhiyun        bb.debug(2, "Adding task %s before %s, after %s" % (task, 'do_image_complete', after))
511*4882a593Smuzhiyun        bb.build.addtask(task, 'do_image_complete', after, d)
512*4882a593Smuzhiyun}
513*4882a593Smuzhiyun
514*4882a593Smuzhiyun#
515*4882a593Smuzhiyun# Compute the rootfs size
516*4882a593Smuzhiyun#
517*4882a593Smuzhiyundef get_rootfs_size(d):
518*4882a593Smuzhiyun    import subprocess, oe.utils
519*4882a593Smuzhiyun
520*4882a593Smuzhiyun    rootfs_alignment = int(d.getVar('IMAGE_ROOTFS_ALIGNMENT'))
521*4882a593Smuzhiyun    overhead_factor = float(d.getVar('IMAGE_OVERHEAD_FACTOR'))
522*4882a593Smuzhiyun    rootfs_req_size = int(d.getVar('IMAGE_ROOTFS_SIZE'))
523*4882a593Smuzhiyun    rootfs_extra_space = eval(d.getVar('IMAGE_ROOTFS_EXTRA_SPACE'))
524*4882a593Smuzhiyun    rootfs_maxsize = d.getVar('IMAGE_ROOTFS_MAXSIZE')
525*4882a593Smuzhiyun    image_fstypes = d.getVar('IMAGE_FSTYPES') or ''
526*4882a593Smuzhiyun    initramfs_fstypes = d.getVar('INITRAMFS_FSTYPES') or ''
527*4882a593Smuzhiyun    initramfs_maxsize = d.getVar('INITRAMFS_MAXSIZE')
528*4882a593Smuzhiyun
529*4882a593Smuzhiyun    size_kb = oe.utils.directory_size(d.getVar("IMAGE_ROOTFS")) / 1024
530*4882a593Smuzhiyun
531*4882a593Smuzhiyun    base_size = size_kb * overhead_factor
532*4882a593Smuzhiyun    bb.debug(1, '%f = %d * %f' % (base_size, size_kb, overhead_factor))
533*4882a593Smuzhiyun    base_size2 = max(base_size, rootfs_req_size) + rootfs_extra_space
534*4882a593Smuzhiyun    bb.debug(1, '%f = max(%f, %d)[%f] + %d' % (base_size2, base_size, rootfs_req_size, max(base_size, rootfs_req_size), rootfs_extra_space))
535*4882a593Smuzhiyun
536*4882a593Smuzhiyun    base_size = base_size2
537*4882a593Smuzhiyun    if base_size != int(base_size):
538*4882a593Smuzhiyun        base_size = int(base_size + 1)
539*4882a593Smuzhiyun    else:
540*4882a593Smuzhiyun        base_size = int(base_size)
541*4882a593Smuzhiyun    bb.debug(1, '%f = int(%f)' % (base_size, base_size2))
542*4882a593Smuzhiyun
543*4882a593Smuzhiyun    base_size_saved = base_size
544*4882a593Smuzhiyun    base_size += rootfs_alignment - 1
545*4882a593Smuzhiyun    base_size -= base_size % rootfs_alignment
546*4882a593Smuzhiyun    bb.debug(1, '%d = aligned(%d)' % (base_size, base_size_saved))
547*4882a593Smuzhiyun
548*4882a593Smuzhiyun    # Do not check image size of the debugfs image. This is not supposed
549*4882a593Smuzhiyun    # to be deployed, etc. so it doesn't make sense to limit the size
550*4882a593Smuzhiyun    # of the debug.
551*4882a593Smuzhiyun    if (d.getVar('IMAGE_BUILDING_DEBUGFS') or "") == "true":
552*4882a593Smuzhiyun        bb.debug(1, 'returning debugfs size %d' % (base_size))
553*4882a593Smuzhiyun        return base_size
554*4882a593Smuzhiyun
555*4882a593Smuzhiyun    # Check the rootfs size against IMAGE_ROOTFS_MAXSIZE (if set)
556*4882a593Smuzhiyun    if rootfs_maxsize:
557*4882a593Smuzhiyun        rootfs_maxsize_int = int(rootfs_maxsize)
558*4882a593Smuzhiyun        if base_size > rootfs_maxsize_int:
559*4882a593Smuzhiyun            bb.fatal("The rootfs size %d(K) exceeds IMAGE_ROOTFS_MAXSIZE: %d(K)" % \
560*4882a593Smuzhiyun                (base_size, rootfs_maxsize_int))
561*4882a593Smuzhiyun
562*4882a593Smuzhiyun    # Check the initramfs size against INITRAMFS_MAXSIZE (if set)
563*4882a593Smuzhiyun    if image_fstypes == initramfs_fstypes != ''  and initramfs_maxsize:
564*4882a593Smuzhiyun        initramfs_maxsize_int = int(initramfs_maxsize)
565*4882a593Smuzhiyun        if base_size > initramfs_maxsize_int:
566*4882a593Smuzhiyun            bb.error("The initramfs size %d(K) exceeds INITRAMFS_MAXSIZE: %d(K)" % \
567*4882a593Smuzhiyun                (base_size, initramfs_maxsize_int))
568*4882a593Smuzhiyun            bb.error("You can set INITRAMFS_MAXSIZE a larger value. Usually, it should")
569*4882a593Smuzhiyun            bb.fatal("be less than 1/2 of ram size, or you may fail to boot it.\n")
570*4882a593Smuzhiyun
571*4882a593Smuzhiyun    bb.debug(1, 'returning %d' % (base_size))
572*4882a593Smuzhiyun    return base_size
573*4882a593Smuzhiyun
574*4882a593Smuzhiyunpython set_image_size () {
575*4882a593Smuzhiyun        rootfs_size = get_rootfs_size(d)
576*4882a593Smuzhiyun        d.setVar('ROOTFS_SIZE', str(rootfs_size))
577*4882a593Smuzhiyun        d.setVarFlag('ROOTFS_SIZE', 'export', '1')
578*4882a593Smuzhiyun}
579*4882a593Smuzhiyun
580*4882a593Smuzhiyun#
581*4882a593Smuzhiyun# Create symlinks to the newly created image
582*4882a593Smuzhiyun#
583*4882a593Smuzhiyunpython create_symlinks() {
584*4882a593Smuzhiyun
585*4882a593Smuzhiyun    deploy_dir = d.getVar('IMGDEPLOYDIR')
586*4882a593Smuzhiyun    img_name = d.getVar('IMAGE_NAME')
587*4882a593Smuzhiyun    link_name = d.getVar('IMAGE_LINK_NAME')
588*4882a593Smuzhiyun    manifest_name = d.getVar('IMAGE_MANIFEST')
589*4882a593Smuzhiyun    taskname = d.getVar("BB_CURRENTTASK")
590*4882a593Smuzhiyun    subimages = (d.getVarFlag("do_" + taskname, 'subimages', False) or "").split()
591*4882a593Smuzhiyun    imgsuffix = d.getVarFlag("do_" + taskname, 'imgsuffix') or d.expand("${IMAGE_NAME_SUFFIX}.")
592*4882a593Smuzhiyun
593*4882a593Smuzhiyun    if not link_name:
594*4882a593Smuzhiyun        return
595*4882a593Smuzhiyun    for type in subimages:
596*4882a593Smuzhiyun        dst = os.path.join(deploy_dir, link_name + "." + type)
597*4882a593Smuzhiyun        src = img_name + imgsuffix + type
598*4882a593Smuzhiyun        if os.path.exists(os.path.join(deploy_dir, src)):
599*4882a593Smuzhiyun            bb.note("Creating symlink: %s -> %s" % (dst, src))
600*4882a593Smuzhiyun            if os.path.islink(dst):
601*4882a593Smuzhiyun                os.remove(dst)
602*4882a593Smuzhiyun            os.symlink(src, dst)
603*4882a593Smuzhiyun        else:
604*4882a593Smuzhiyun            bb.note("Skipping symlink, source does not exist: %s -> %s" % (dst, src))
605*4882a593Smuzhiyun}
606*4882a593Smuzhiyun
607*4882a593SmuzhiyunMULTILIBRE_ALLOW_REP =. "${base_bindir}|${base_sbindir}|${bindir}|${sbindir}|${libexecdir}|${sysconfdir}|${nonarch_base_libdir}/udev|/lib/modules/[^/]*/modules.*|"
608*4882a593SmuzhiyunMULTILIB_CHECK_FILE = "${WORKDIR}/multilib_check.py"
609*4882a593SmuzhiyunMULTILIB_TEMP_ROOTFS = "${WORKDIR}/multilib"
610*4882a593Smuzhiyun
611*4882a593Smuzhiyundo_fetch[noexec] = "1"
612*4882a593Smuzhiyundo_unpack[noexec] = "1"
613*4882a593Smuzhiyundo_patch[noexec] = "1"
614*4882a593Smuzhiyundo_configure[noexec] = "1"
615*4882a593Smuzhiyundo_compile[noexec] = "1"
616*4882a593Smuzhiyundo_install[noexec] = "1"
617*4882a593Smuzhiyundeltask do_populate_lic
618*4882a593Smuzhiyundeltask do_populate_sysroot
619*4882a593Smuzhiyundo_package[noexec] = "1"
620*4882a593Smuzhiyundeltask do_package_qa
621*4882a593Smuzhiyundeltask do_packagedata
622*4882a593Smuzhiyundeltask do_package_write_ipk
623*4882a593Smuzhiyundeltask do_package_write_deb
624*4882a593Smuzhiyundeltask do_package_write_rpm
625*4882a593Smuzhiyun
626*4882a593Smuzhiyun# Prepare the root links to point to the /usr counterparts.
627*4882a593Smuzhiyuncreate_merged_usr_symlinks() {
628*4882a593Smuzhiyun    root="$1"
629*4882a593Smuzhiyun    install -d $root${base_bindir} $root${base_sbindir} $root${base_libdir}
630*4882a593Smuzhiyun    ln -rs $root${base_bindir} $root/bin
631*4882a593Smuzhiyun    ln -rs $root${base_sbindir} $root/sbin
632*4882a593Smuzhiyun    ln -rs $root${base_libdir} $root/${baselib}
633*4882a593Smuzhiyun
634*4882a593Smuzhiyun    if [ "${nonarch_base_libdir}" != "${base_libdir}" ]; then
635*4882a593Smuzhiyun       install -d $root${nonarch_base_libdir}
636*4882a593Smuzhiyun       ln -rs $root${nonarch_base_libdir} $root/lib
637*4882a593Smuzhiyun    fi
638*4882a593Smuzhiyun
639*4882a593Smuzhiyun    # create base links for multilibs
640*4882a593Smuzhiyun    multi_libdirs="${@d.getVar('MULTILIB_VARIANTS')}"
641*4882a593Smuzhiyun    for d in $multi_libdirs; do
642*4882a593Smuzhiyun        install -d $root${exec_prefix}/$d
643*4882a593Smuzhiyun        ln -rs $root${exec_prefix}/$d $root/$d
644*4882a593Smuzhiyun    done
645*4882a593Smuzhiyun}
646*4882a593Smuzhiyun
647*4882a593Smuzhiyuncreate_merged_usr_symlinks_rootfs() {
648*4882a593Smuzhiyun    create_merged_usr_symlinks ${IMAGE_ROOTFS}
649*4882a593Smuzhiyun}
650*4882a593Smuzhiyun
651*4882a593Smuzhiyuncreate_merged_usr_symlinks_sdk() {
652*4882a593Smuzhiyun    create_merged_usr_symlinks ${SDK_OUTPUT}${SDKTARGETSYSROOT}
653*4882a593Smuzhiyun}
654*4882a593Smuzhiyun
655*4882a593SmuzhiyunROOTFS_PREPROCESS_COMMAND += "${@bb.utils.contains('DISTRO_FEATURES', 'usrmerge', 'create_merged_usr_symlinks_rootfs; ', '',d)}"
656*4882a593SmuzhiyunPOPULATE_SDK_PRE_TARGET_COMMAND += "${@bb.utils.contains('DISTRO_FEATURES', 'usrmerge', 'create_merged_usr_symlinks_sdk; ', '',d)}"
657*4882a593Smuzhiyun
658*4882a593Smuzhiyunreproducible_final_image_task () {
659*4882a593Smuzhiyun    if [ "$REPRODUCIBLE_TIMESTAMP_ROOTFS" = "" ]; then
660*4882a593Smuzhiyun        REPRODUCIBLE_TIMESTAMP_ROOTFS=`git -C "${COREBASE}" log -1 --pretty=%ct 2>/dev/null` || true
661*4882a593Smuzhiyun        if [ "$REPRODUCIBLE_TIMESTAMP_ROOTFS" = "" ]; then
662*4882a593Smuzhiyun            REPRODUCIBLE_TIMESTAMP_ROOTFS=`stat -c%Y ${@bb.utils.which(d.getVar("BBPATH"), "conf/bitbake.conf")}`
663*4882a593Smuzhiyun        fi
664*4882a593Smuzhiyun    fi
665*4882a593Smuzhiyun    # Set mtime of all files to a reproducible value
666*4882a593Smuzhiyun    bbnote "reproducible_final_image_task: mtime set to $REPRODUCIBLE_TIMESTAMP_ROOTFS"
667*4882a593Smuzhiyun    find  ${IMAGE_ROOTFS} -print0 | xargs -0 touch -h  --date=@$REPRODUCIBLE_TIMESTAMP_ROOTFS
668*4882a593Smuzhiyun}
669*4882a593Smuzhiyun
670*4882a593Smuzhiyunsystemd_preset_all () {
671*4882a593Smuzhiyun    if [ -e ${IMAGE_ROOTFS}${root_prefix}/lib/systemd/systemd ]; then
672*4882a593Smuzhiyun	systemctl --root="${IMAGE_ROOTFS}" --preset-mode=enable-only preset-all
673*4882a593Smuzhiyun    fi
674*4882a593Smuzhiyun}
675*4882a593Smuzhiyun
676*4882a593SmuzhiyunIMAGE_PREPROCESS_COMMAND:append = " ${@ 'systemd_preset_all;' if bb.utils.contains('DISTRO_FEATURES', 'systemd', True, False, d) and not bb.utils.contains('IMAGE_FEATURES', 'stateless-rootfs', True, False, d) else ''} reproducible_final_image_task; "
677*4882a593Smuzhiyun
678*4882a593SmuzhiyunCVE_PRODUCT = ""
679