blob: f5687e589973f3585808ef4aa1112420ab34bbca [file] [log] [blame]
Patrick Williams92b42cb2022-09-03 06:53:57 -05001#
2# Copyright OpenEmbedded Contributors
3#
4# SPDX-License-Identifier: MIT
5#
6
7# Extensible SDK
8
9inherit populate_sdk_base
10
11# Used to override TOOLCHAIN_HOST_TASK in the eSDK case
12TOOLCHAIN_HOST_TASK_ESDK = " \
13 meta-environment-extsdk-${MACHINE} \
14 "
15
16SDK_RELOCATE_AFTER_INSTALL:task-populate-sdk-ext = "0"
17
18SDK_EXT = ""
19SDK_EXT:task-populate-sdk-ext = "-ext"
20
21# Options are full or minimal
22SDK_EXT_TYPE ?= "full"
23SDK_INCLUDE_PKGDATA ?= "0"
24SDK_INCLUDE_TOOLCHAIN ?= "${@'1' if d.getVar('SDK_EXT_TYPE') == 'full' else '0'}"
25SDK_INCLUDE_NATIVESDK ?= "0"
26SDK_INCLUDE_BUILDTOOLS ?= '1'
27
28SDK_RECRDEP_TASKS ?= ""
29SDK_CUSTOM_TEMPLATECONF ?= "0"
30
31ESDK_LOCALCONF_ALLOW ?= ""
32ESDK_LOCALCONF_REMOVE ?= "CONF_VERSION \
33 BB_NUMBER_THREADS \
34 BB_NUMBER_PARSE_THREADS \
35 PARALLEL_MAKE \
36 PRSERV_HOST \
37 SSTATE_MIRRORS \
38 DL_DIR \
39 SSTATE_DIR \
40 TMPDIR \
41 BB_SERVER_TIMEOUT \
42 "
43ESDK_CLASS_INHERIT_DISABLE ?= "buildhistory icecc"
44SDK_UPDATE_URL ?= ""
45
46SDK_TARGETS ?= "${PN}"
47
48def get_sdk_install_targets(d, images_only=False):
49 sdk_install_targets = ''
50 if images_only or d.getVar('SDK_EXT_TYPE') != 'minimal':
51 sdk_install_targets = d.getVar('SDK_TARGETS')
52
53 depd = d.getVar('BB_TASKDEPDATA', False)
54 tasklist = bb.build.tasksbetween('do_image_complete', 'do_build', d)
55 tasklist.remove('do_build')
56 for v in depd.values():
57 if v[1] in tasklist:
58 if v[0] not in sdk_install_targets:
59 sdk_install_targets += ' {}'.format(v[0])
60
61 if not images_only:
62 if d.getVar('SDK_INCLUDE_PKGDATA') == '1':
63 sdk_install_targets += ' meta-world-pkgdata:do_allpackagedata'
64 if d.getVar('SDK_INCLUDE_TOOLCHAIN') == '1':
65 sdk_install_targets += ' meta-extsdk-toolchain:do_populate_sysroot'
66
67 return sdk_install_targets
68
69get_sdk_install_targets[vardepsexclude] = "BB_TASKDEPDATA"
70
71OE_INIT_ENV_SCRIPT ?= "oe-init-build-env"
72
73# The files from COREBASE that you want preserved in the COREBASE copied
74# into the sdk. This allows someone to have their own setup scripts in
75# COREBASE be preserved as well as untracked files.
76COREBASE_FILES ?= " \
77 oe-init-build-env \
78 scripts \
79 LICENSE \
80 .templateconf \
81"
82
83SDK_DIR:task-populate-sdk-ext = "${WORKDIR}/sdk-ext"
84B:task-populate-sdk-ext = "${SDK_DIR}"
85TOOLCHAINEXT_OUTPUTNAME ?= "${SDK_NAME}-toolchain-ext-${SDK_VERSION}"
86TOOLCHAIN_OUTPUTNAME:task-populate-sdk-ext = "${TOOLCHAINEXT_OUTPUTNAME}"
87
88SDK_EXT_TARGET_MANIFEST = "${SDK_DEPLOY}/${TOOLCHAINEXT_OUTPUTNAME}.target.manifest"
89SDK_EXT_HOST_MANIFEST = "${SDK_DEPLOY}/${TOOLCHAINEXT_OUTPUTNAME}.host.manifest"
90
91python write_target_sdk_ext_manifest () {
92 from oe.sdk import get_extra_sdkinfo
93 sstate_dir = d.expand('${SDK_OUTPUT}/${SDKPATH}/sstate-cache')
94 extra_info = get_extra_sdkinfo(sstate_dir)
95
96 target = d.getVar('TARGET_SYS')
97 target_multimach = d.getVar('MULTIMACH_TARGET_SYS')
98 real_target_multimach = d.getVar('REAL_MULTIMACH_TARGET_SYS')
99
100 pkgs = {}
101 os.makedirs(os.path.dirname(d.getVar('SDK_EXT_TARGET_MANIFEST')), exist_ok=True)
102 with open(d.getVar('SDK_EXT_TARGET_MANIFEST'), 'w') as f:
103 for fn in extra_info['filesizes']:
104 info = fn.split(':')
105 if info[2] in (target, target_multimach, real_target_multimach) \
106 or info[5] == 'allarch':
107 if not info[1] in pkgs:
108 f.write("%s %s %s\n" % (info[1], info[2], info[3]))
109 pkgs[info[1]] = {}
110}
111python write_host_sdk_ext_manifest () {
112 from oe.sdk import get_extra_sdkinfo
113 sstate_dir = d.expand('${SDK_OUTPUT}/${SDKPATH}/sstate-cache')
114 extra_info = get_extra_sdkinfo(sstate_dir)
115 host = d.getVar('BUILD_SYS')
116 with open(d.getVar('SDK_EXT_HOST_MANIFEST'), 'w') as f:
117 for fn in extra_info['filesizes']:
118 info = fn.split(':')
119 if info[2] == host:
120 f.write("%s %s %s\n" % (info[1], info[2], info[3]))
121}
122
Andrew Geissler5082cc72023-09-11 08:41:39 -0400123SDK_POSTPROCESS_COMMAND:append:task-populate-sdk-ext = " write_target_sdk_ext_manifest write_host_sdk_ext_manifest"
Patrick Williams92b42cb2022-09-03 06:53:57 -0500124
125SDK_TITLE:task-populate-sdk-ext = "${@d.getVar('DISTRO_NAME') or d.getVar('DISTRO')} Extensible SDK"
126
127def clean_esdk_builddir(d, sdkbasepath):
128 """Clean up traces of the fake build for create_filtered_tasklist()"""
129 import shutil
130 cleanpaths = ['cache', 'tmp']
131 for pth in cleanpaths:
132 fullpth = os.path.join(sdkbasepath, pth)
133 if os.path.isdir(fullpth):
134 shutil.rmtree(fullpth)
135 elif os.path.isfile(fullpth):
136 os.remove(fullpth)
137
138def create_filtered_tasklist(d, sdkbasepath, tasklistfile, conf_initpath):
139 """
140 Create a filtered list of tasks. Also double-checks that the build system
141 within the SDK basically works and required sstate artifacts are available.
142 """
143 import tempfile
144 import shutil
145 import oe.copy_buildsystem
146
147 # Create a temporary build directory that we can pass to the env setup script
148 shutil.copyfile(sdkbasepath + '/conf/local.conf', sdkbasepath + '/conf/local.conf.bak')
149 try:
150 with open(sdkbasepath + '/conf/local.conf', 'a') as f:
151 # Force the use of sstate from the build system
152 f.write('\nSSTATE_DIR:forcevariable = "%s"\n' % d.getVar('SSTATE_DIR'))
153 f.write('SSTATE_MIRRORS:forcevariable = "file://universal/(.*) file://universal-4.9/\\1 file://universal-4.9/(.*) file://universal-4.8/\\1"\n')
154 # Ensure TMPDIR is the default so that clean_esdk_builddir() can delete it
155 f.write('TMPDIR:forcevariable = "${TOPDIR}/tmp"\n')
156 f.write('TCLIBCAPPEND:forcevariable = ""\n')
157 # Drop uninative if the build isn't using it (or else NATIVELSBSTRING will
158 # be different and we won't be able to find our native sstate)
159 if not bb.data.inherits_class('uninative', d):
160 f.write('INHERIT:remove = "uninative"\n')
161
162 # Unfortunately the default SDKPATH (or even a custom value) may contain characters that bitbake
163 # will not allow in its COREBASE path, so we need to rename the directory temporarily
164 temp_sdkbasepath = d.getVar('SDK_OUTPUT') + '/tmp-renamed-sdk'
165 # Delete any existing temp dir
166 try:
167 shutil.rmtree(temp_sdkbasepath)
168 except FileNotFoundError:
169 pass
170 bb.utils.rename(sdkbasepath, temp_sdkbasepath)
171 cmdprefix = '. %s .; ' % conf_initpath
172 logfile = d.getVar('WORKDIR') + '/tasklist_bb_log.txt'
173 try:
174 oe.copy_buildsystem.check_sstate_task_list(d, get_sdk_install_targets(d), tasklistfile, cmdprefix=cmdprefix, cwd=temp_sdkbasepath, logfile=logfile)
175 except bb.process.ExecutionError as e:
176 msg = 'Failed to generate filtered task list for extensible SDK:\n%s' % e.stdout.rstrip()
177 if 'attempted to execute unexpectedly and should have been setscened' in e.stdout:
178 msg += '\n----------\n\nNOTE: "attempted to execute unexpectedly and should have been setscened" errors indicate this may be caused by missing sstate artifacts that were likely produced in earlier builds, but have been subsequently deleted for some reason.\n'
179 bb.fatal(msg)
180 bb.utils.rename(temp_sdkbasepath, sdkbasepath)
181 # Clean out residue of running bitbake, which check_sstate_task_list()
182 # will effectively do
183 clean_esdk_builddir(d, sdkbasepath)
184 finally:
185 localconf = sdkbasepath + '/conf/local.conf'
186 if os.path.exists(localconf + '.bak'):
187 os.replace(localconf + '.bak', localconf)
188
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600189def copy_bitbake_and_layers(d, baseoutpath, derivative):
Patrick Williams92b42cb2022-09-03 06:53:57 -0500190 oe_init_env_script = d.getVar('OE_INIT_ENV_SCRIPT')
191
192 conf_bbpath = ''
193 conf_initpath = ''
194 core_meta_subdir = ''
195
196 # Copy in all metadata layers + bitbake (as repositories)
197 buildsystem = oe.copy_buildsystem.BuildSystem('extensible SDK', d)
Patrick Williams92b42cb2022-09-03 06:53:57 -0500198
Patrick Williams92b42cb2022-09-03 06:53:57 -0500199 if derivative:
200 workspace_name = 'orig-workspace'
201 else:
202 workspace_name = None
203
204 corebase, sdkbblayers = buildsystem.copy_bitbake_and_layers(baseoutpath + '/layers', workspace_name)
205 conf_bbpath = os.path.join('layers', corebase, 'bitbake')
206
207 for path in os.listdir(baseoutpath + '/layers'):
208 relpath = os.path.join('layers', path, oe_init_env_script)
209 if os.path.exists(os.path.join(baseoutpath, relpath)):
210 conf_initpath = relpath
211
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600212 relpath = os.path.join('layers', path, 'scripts', 'esdk-tools', 'devtool')
Patrick Williams92b42cb2022-09-03 06:53:57 -0500213 if os.path.exists(os.path.join(baseoutpath, relpath)):
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600214 esdk_tools_path = os.path.dirname(relpath)
Patrick Williams92b42cb2022-09-03 06:53:57 -0500215
216 relpath = os.path.join('layers', path, 'meta')
217 if os.path.exists(os.path.join(baseoutpath, relpath, 'lib', 'oe')):
218 core_meta_subdir = relpath
219
220 d.setVar('oe_init_build_env_path', conf_initpath)
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600221 d.setVar('esdk_tools_path', esdk_tools_path)
Patrick Williams92b42cb2022-09-03 06:53:57 -0500222
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600223 return (conf_initpath, conf_bbpath, core_meta_subdir, sdkbblayers)
224
225def write_devtool_config(d, baseoutpath, conf_bbpath, conf_initpath, core_meta_subdir):
Patrick Williams92b42cb2022-09-03 06:53:57 -0500226 # Write out config file for devtool
227 import configparser
Patrick Williams7784c422022-11-17 07:29:11 -0600228 config = configparser.ConfigParser()
Patrick Williams92b42cb2022-09-03 06:53:57 -0500229 config.add_section('General')
230 config.set('General', 'bitbake_subdir', conf_bbpath)
231 config.set('General', 'init_path', conf_initpath)
232 config.set('General', 'core_meta_subdir', core_meta_subdir)
233 config.add_section('SDK')
234 config.set('SDK', 'sdk_targets', d.getVar('SDK_TARGETS'))
235 updateurl = d.getVar('SDK_UPDATE_URL')
236 if updateurl:
237 config.set('SDK', 'updateserver', updateurl)
238 bb.utils.mkdirhier(os.path.join(baseoutpath, 'conf'))
239 with open(os.path.join(baseoutpath, 'conf', 'devtool.conf'), 'w') as f:
240 config.write(f)
241
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600242def write_unlocked_sigs(d, baseoutpath):
Patrick Williams92b42cb2022-09-03 06:53:57 -0500243 unlockedsigs = os.path.join(baseoutpath, 'conf', 'unlocked-sigs.inc')
244 with open(unlockedsigs, 'w') as f:
245 pass
246
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600247def write_bblayers_conf(d, baseoutpath, sdkbblayers):
Patrick Williams92b42cb2022-09-03 06:53:57 -0500248 # Create a layer for new recipes / appends
249 bbpath = d.getVar('BBPATH')
250 env = os.environ.copy()
251 env['PYTHONDONTWRITEBYTECODE'] = '1'
Andrew Geissler517393d2023-01-13 08:55:19 -0600252 bb.process.run(['devtool', '--bbpath', bbpath, '--basepath', baseoutpath, 'create-workspace', '--layerseries', d.getVar("LAYERSERIES_CORENAMES"), '--create-only', os.path.join(baseoutpath, 'workspace')], env=env)
Patrick Williams92b42cb2022-09-03 06:53:57 -0500253
254 # Create bblayers.conf
255 bb.utils.mkdirhier(baseoutpath + '/conf')
256 with open(baseoutpath + '/conf/bblayers.conf', 'w') as f:
257 f.write('# WARNING: this configuration has been automatically generated and in\n')
258 f.write('# most cases should not be edited. If you need more flexibility than\n')
259 f.write('# this configuration provides, it is strongly suggested that you set\n')
260 f.write('# up a proper instance of the full build system and use that instead.\n\n')
261
262 # LCONF_VERSION may not be set, for example when using meta-poky
263 # so don't error if it isn't found
264 lconf_version = d.getVar('LCONF_VERSION', False)
265 if lconf_version is not None:
266 f.write('LCONF_VERSION = "%s"\n\n' % lconf_version)
267
268 f.write('BBPATH = "$' + '{TOPDIR}"\n')
269 f.write('SDKBASEMETAPATH = "$' + '{TOPDIR}"\n')
270 f.write('BBLAYERS := " \\\n')
271 for layerrelpath in sdkbblayers:
272 f.write(' $' + '{SDKBASEMETAPATH}/layers/%s \\\n' % layerrelpath)
273 f.write(' $' + '{SDKBASEMETAPATH}/workspace \\\n')
274 f.write(' "\n')
275
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600276def copy_uninative(d, baseoutpath):
277 import shutil
278
Patrick Williams92b42cb2022-09-03 06:53:57 -0500279 # Copy uninative tarball
280 # For now this is where uninative.bbclass expects the tarball
281 if bb.data.inherits_class('uninative', d):
282 uninative_file = d.expand('${UNINATIVE_DLDIR}/' + d.getVarFlag("UNINATIVE_CHECKSUM", d.getVar("BUILD_ARCH")) + '/${UNINATIVE_TARBALL}')
283 uninative_checksum = bb.utils.sha256_file(uninative_file)
284 uninative_outdir = '%s/downloads/uninative/%s' % (baseoutpath, uninative_checksum)
285 bb.utils.mkdirhier(uninative_outdir)
286 shutil.copy(uninative_file, uninative_outdir)
287
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600288 return uninative_checksum
289
290def write_local_conf(d, baseoutpath, derivative, core_meta_subdir, uninative_checksum):
291 #check if custome templateconf path is set
292 use_custom_templateconf = d.getVar('SDK_CUSTOM_TEMPLATECONF')
293
Patrick Williams92b42cb2022-09-03 06:53:57 -0500294 env_passthrough = (d.getVar('BB_ENV_PASSTHROUGH_ADDITIONS') or '').split()
295 env_passthrough_values = {}
296
297 # Create local.conf
298 builddir = d.getVar('TOPDIR')
299 if derivative and os.path.exists(builddir + '/conf/site.conf'):
300 shutil.copyfile(builddir + '/conf/site.conf', baseoutpath + '/conf/site.conf')
301 if derivative and os.path.exists(builddir + '/conf/auto.conf'):
302 shutil.copyfile(builddir + '/conf/auto.conf', baseoutpath + '/conf/auto.conf')
303 if derivative:
304 shutil.copyfile(builddir + '/conf/local.conf', baseoutpath + '/conf/local.conf')
305 else:
306 local_conf_allowed = (d.getVar('ESDK_LOCALCONF_ALLOW') or '').split()
307 local_conf_remove = (d.getVar('ESDK_LOCALCONF_REMOVE') or '').split()
308 def handle_var(varname, origvalue, op, newlines):
309 if varname in local_conf_remove or (origvalue.strip().startswith('/') and not varname in local_conf_allowed):
310 newlines.append('# Removed original setting of %s\n' % varname)
311 return None, op, 0, True
312 else:
313 if varname in env_passthrough:
314 env_passthrough_values[varname] = origvalue
315 return origvalue, op, 0, True
316 varlist = ['[^#=+ ]*']
317 oldlines = []
318 if os.path.exists(builddir + '/conf/site.conf'):
319 with open(builddir + '/conf/site.conf', 'r') as f:
320 oldlines += f.readlines()
321 if os.path.exists(builddir + '/conf/auto.conf'):
322 with open(builddir + '/conf/auto.conf', 'r') as f:
323 oldlines += f.readlines()
324 if os.path.exists(builddir + '/conf/local.conf'):
325 with open(builddir + '/conf/local.conf', 'r') as f:
326 oldlines += f.readlines()
327 (updated, newlines) = bb.utils.edit_metadata(oldlines, varlist, handle_var)
328
329 with open(baseoutpath + '/conf/local.conf', 'w') as f:
330 f.write('# WARNING: this configuration has been automatically generated and in\n')
331 f.write('# most cases should not be edited. If you need more flexibility than\n')
332 f.write('# this configuration provides, it is strongly suggested that you set\n')
333 f.write('# up a proper instance of the full build system and use that instead.\n\n')
334 for line in newlines:
335 if line.strip() and not line.startswith('#'):
336 f.write(line)
337 # Write a newline just in case there's none at the end of the original
338 f.write('\n')
339
340 f.write('TMPDIR = "${TOPDIR}/tmp"\n')
341 f.write('TCLIBCAPPEND = ""\n')
342 f.write('DL_DIR = "${TOPDIR}/downloads"\n')
343
344 if bb.data.inherits_class('uninative', d):
345 f.write('INHERIT += "%s"\n' % 'uninative')
346 f.write('UNINATIVE_CHECKSUM[%s] = "%s"\n\n' % (d.getVar('BUILD_ARCH'), uninative_checksum))
347 f.write('CONF_VERSION = "%s"\n\n' % d.getVar('CONF_VERSION', False))
348
349 # Some classes are not suitable for SDK, remove them from INHERIT
350 f.write('INHERIT:remove = "%s"\n' % d.getVar('ESDK_CLASS_INHERIT_DISABLE', False))
351
352 # Bypass the default connectivity check if any
353 f.write('CONNECTIVITY_CHECK_URIS = ""\n\n')
354
355 # This warning will come out if reverse dependencies for a task
356 # don't have sstate as well as the task itself. We already know
357 # this will be the case for the extensible sdk, so turn off the
358 # warning.
359 f.write('SIGGEN_LOCKEDSIGS_SSTATE_EXISTS_CHECK = "none"\n\n')
360
361 # Warn if the sigs in the locked-signature file don't match
362 # the sig computed from the metadata.
363 f.write('SIGGEN_LOCKEDSIGS_TASKSIG_CHECK = "warn"\n\n')
364
365 # We want to be able to set this without a full reparse
366 f.write('BB_HASHCONFIG_IGNORE_VARS:append = " SIGGEN_UNLOCKED_RECIPES"\n\n')
367
368 # Set up which tasks are ignored for run on install
369 f.write('BB_SETSCENE_ENFORCE_IGNORE_TASKS = "%:* *:do_shared_workdir *:do_rm_work wic-tools:* *:do_addto_recipe_sysroot"\n\n')
370
371 # Hide the config information from bitbake output (since it's fixed within the SDK)
372 f.write('BUILDCFG_HEADER = ""\n\n')
373
374 # Write METADATA_REVISION
Patrick Williams8e7b46e2023-05-01 14:19:06 -0500375 # Needs distro override so it can override the value set in the bbclass code (later than local.conf)
376 f.write('METADATA_REVISION:%s = "%s"\n\n' % (d.getVar('DISTRO'), d.getVar('METADATA_REVISION')))
Patrick Williams92b42cb2022-09-03 06:53:57 -0500377
378 f.write('# Provide a flag to indicate we are in the EXT_SDK Context\n')
379 f.write('WITHIN_EXT_SDK = "1"\n\n')
380
381 # Map gcc-dependent uninative sstate cache for installer usage
382 f.write('SSTATE_MIRRORS += " file://universal/(.*) file://universal-4.9/\\1 file://universal-4.9/(.*) file://universal-4.8/\\1"\n\n')
383
384 if d.getVar("PRSERV_HOST"):
385 # Override this, we now include PR data, so it should only point ot the local database
386 f.write('PRSERV_HOST = "localhost:0"\n\n')
387
388 # Allow additional config through sdk-extra.conf
389 fn = bb.cookerdata.findConfigFile('sdk-extra.conf', d)
390 if fn:
391 with open(fn, 'r') as xf:
392 for line in xf:
393 f.write(line)
394
395 # If you define a sdk_extraconf() function then it can contain additional config
396 # (Though this is awkward; sdk-extra.conf should probably be used instead)
397 extraconf = (d.getVar('sdk_extraconf') or '').strip()
398 if extraconf:
399 # Strip off any leading / trailing spaces
400 for line in extraconf.splitlines():
401 f.write(line.strip() + '\n')
402
403 f.write('require conf/locked-sigs.inc\n')
404 f.write('require conf/unlocked-sigs.inc\n')
405
406 # Copy multiple configurations if they exist in the users config directory
407 if d.getVar('BBMULTICONFIG') is not None:
408 bb.utils.mkdirhier(os.path.join(baseoutpath, 'conf', 'multiconfig'))
409 for mc in d.getVar('BBMULTICONFIG').split():
410 dest_stub = "/conf/multiconfig/%s.conf" % (mc,)
411 if os.path.exists(builddir + dest_stub):
412 shutil.copyfile(builddir + dest_stub, baseoutpath + dest_stub)
413
414 cachedir = os.path.join(baseoutpath, 'cache')
415 bb.utils.mkdirhier(cachedir)
416 bb.parse.siggen.copy_unitaskhashes(cachedir)
417
418 # If PR Service is in use, we need to export this as well
419 bb.note('Do we have a pr database?')
420 if d.getVar("PRSERV_HOST"):
421 bb.note('Writing PR database...')
422 # Based on the code in classes/prexport.bbclass
423 import oe.prservice
424 #dump meta info of tables
425 localdata = d.createCopy()
426 localdata.setVar('PRSERV_DUMPOPT_COL', "1")
427 localdata.setVar('PRSERV_DUMPDIR', os.path.join(baseoutpath, 'conf'))
428 localdata.setVar('PRSERV_DUMPFILE', '${PRSERV_DUMPDIR}/prserv.inc')
429
430 bb.note('PR Database write to %s' % (localdata.getVar('PRSERV_DUMPFILE')))
431
432 retval = oe.prservice.prserv_dump_db(localdata)
433 if not retval:
434 bb.error("prexport_handler: export failed!")
435 return
436 (metainfo, datainfo) = retval
437 oe.prservice.prserv_export_tofile(localdata, metainfo, datainfo, True)
438
439 # Use templateconf.cfg file from builddir if exists
440 if os.path.exists(builddir + '/conf/templateconf.cfg') and use_custom_templateconf == '1':
441 shutil.copyfile(builddir + '/conf/templateconf.cfg', baseoutpath + '/conf/templateconf.cfg')
442 else:
443 # Write a templateconf.cfg
444 with open(baseoutpath + '/conf/templateconf.cfg', 'w') as f:
445 f.write('meta/conf/templates/default\n')
446 os.makedirs(os.path.join(baseoutpath, core_meta_subdir, 'conf/templates/default'), exist_ok=True)
447
448 # Ensure any variables set from the external environment (by way of
449 # BB_ENV_PASSTHROUGH_ADDITIONS) are set in the SDK's configuration
450 extralines = []
451 for name, value in env_passthrough_values.items():
452 actualvalue = d.getVar(name) or ''
453 if value != actualvalue:
454 extralines.append('%s = "%s"\n' % (name, actualvalue))
455 if extralines:
456 with open(baseoutpath + '/conf/local.conf', 'a') as f:
457 f.write('\n')
458 f.write('# Extra settings from environment:\n')
459 for line in extralines:
460 f.write(line)
461 f.write('\n')
462
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600463def prepare_locked_cache(d, baseoutpath, derivative, conf_initpath):
464 import shutil
465
Patrick Williams92b42cb2022-09-03 06:53:57 -0500466 # Filter the locked signatures file to just the sstate tasks we are interested in
467 excluded_targets = get_sdk_install_targets(d, images_only=True)
468 sigfile = d.getVar('WORKDIR') + '/locked-sigs.inc'
469 lockedsigs_pruned = baseoutpath + '/conf/locked-sigs.inc'
470 #nativesdk-only sigfile to merge into locked-sigs.inc
471 sdk_include_nativesdk = (d.getVar("SDK_INCLUDE_NATIVESDK") == '1')
472 nativesigfile = d.getVar('WORKDIR') + '/locked-sigs_nativesdk.inc'
473 nativesigfile_pruned = d.getVar('WORKDIR') + '/locked-sigs_nativesdk_pruned.inc'
474
475 if sdk_include_nativesdk:
476 oe.copy_buildsystem.prune_lockedsigs([],
477 excluded_targets.split(),
478 nativesigfile,
479 True,
480 nativesigfile_pruned)
481
482 oe.copy_buildsystem.merge_lockedsigs([],
483 sigfile,
484 nativesigfile_pruned,
485 sigfile)
486
487 oe.copy_buildsystem.prune_lockedsigs([],
488 excluded_targets.split(),
489 sigfile,
490 False,
491 lockedsigs_pruned)
492
493 sstate_out = baseoutpath + '/sstate-cache'
494 bb.utils.remove(sstate_out, True)
495
496 # uninative.bbclass sets NATIVELSBSTRING to 'universal%s' % oe.utils.host_gcc_version(d)
Patrick Williams03514f12024-04-05 07:04:11 -0500497 fixedlsbstring = "universal%s" % oe.utils.host_gcc_version(d) if bb.data.inherits_class('uninative', d) else ""
Patrick Williams92b42cb2022-09-03 06:53:57 -0500498
499 sdk_include_toolchain = (d.getVar('SDK_INCLUDE_TOOLCHAIN') == '1')
500 sdk_ext_type = d.getVar('SDK_EXT_TYPE')
501 if (sdk_ext_type != 'minimal' or sdk_include_toolchain or derivative) and not sdk_include_nativesdk:
502 # Create the filtered task list used to generate the sstate cache shipped with the SDK
503 tasklistfn = d.getVar('WORKDIR') + '/tasklist.txt'
504 create_filtered_tasklist(d, baseoutpath, tasklistfn, conf_initpath)
505 else:
506 tasklistfn = None
507
Patrick Williams92b42cb2022-09-03 06:53:57 -0500508 cachedir = os.path.join(baseoutpath, 'cache')
509 bb.utils.mkdirhier(cachedir)
510 bb.parse.siggen.copy_unitaskhashes(cachedir)
511
512 # Add packagedata if enabled
513 if d.getVar('SDK_INCLUDE_PKGDATA') == '1':
514 lockedsigs_base = d.getVar('WORKDIR') + '/locked-sigs-base.inc'
515 lockedsigs_copy = d.getVar('WORKDIR') + '/locked-sigs-copy.inc'
516 shutil.move(lockedsigs_pruned, lockedsigs_base)
517 oe.copy_buildsystem.merge_lockedsigs(['do_packagedata'],
518 lockedsigs_base,
519 d.getVar('STAGING_DIR_HOST') + '/world-pkgdata/locked-sigs-pkgdata.inc',
520 lockedsigs_pruned,
521 lockedsigs_copy)
522
523 if sdk_include_toolchain:
524 lockedsigs_base = d.getVar('WORKDIR') + '/locked-sigs-base2.inc'
525 lockedsigs_toolchain = d.expand("${STAGING_DIR}/${TUNE_PKGARCH}/meta-extsdk-toolchain/locked-sigs/locked-sigs-extsdk-toolchain.inc")
526 shutil.move(lockedsigs_pruned, lockedsigs_base)
527 oe.copy_buildsystem.merge_lockedsigs([],
528 lockedsigs_base,
529 lockedsigs_toolchain,
530 lockedsigs_pruned)
531 oe.copy_buildsystem.create_locked_sstate_cache(lockedsigs_toolchain,
532 d.getVar('SSTATE_DIR'),
533 sstate_out, d,
534 fixedlsbstring,
535 filterfile=tasklistfn)
536
537 if sdk_ext_type == 'minimal':
538 if derivative:
539 # Assume the user is not going to set up an additional sstate
540 # mirror, thus we need to copy the additional artifacts (from
541 # workspace recipes) into the derivative SDK
542 lockedsigs_orig = d.getVar('TOPDIR') + '/conf/locked-sigs.inc'
543 if os.path.exists(lockedsigs_orig):
544 lockedsigs_extra = d.getVar('WORKDIR') + '/locked-sigs-extra.inc'
545 oe.copy_buildsystem.merge_lockedsigs(None,
546 lockedsigs_orig,
547 lockedsigs_pruned,
548 None,
549 lockedsigs_extra)
550 oe.copy_buildsystem.create_locked_sstate_cache(lockedsigs_extra,
551 d.getVar('SSTATE_DIR'),
552 sstate_out, d,
553 fixedlsbstring,
554 filterfile=tasklistfn)
555 else:
556 oe.copy_buildsystem.create_locked_sstate_cache(lockedsigs_pruned,
557 d.getVar('SSTATE_DIR'),
558 sstate_out, d,
559 fixedlsbstring,
560 filterfile=tasklistfn)
561
562 # We don't need sstate do_package files
563 for root, dirs, files in os.walk(sstate_out):
564 for name in files:
565 if name.endswith("_package.tar.zst"):
566 f = os.path.join(root, name)
567 os.remove(f)
568
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600569def write_manifest(d, baseoutpath):
570 import glob
571
Patrick Williams92b42cb2022-09-03 06:53:57 -0500572 # Write manifest file
573 # Note: at the moment we cannot include the env setup script here to keep
574 # it updated, since it gets modified during SDK installation (see
575 # sdk_ext_postinst() below) thus the checksum we take here would always
576 # be different.
577 manifest_file_list = ['conf/*']
578 if d.getVar('BBMULTICONFIG') is not None:
579 manifest_file_list.append('conf/multiconfig/*')
580
581 esdk_manifest_excludes = (d.getVar('ESDK_MANIFEST_EXCLUDES') or '').split()
582 esdk_manifest_excludes_list = []
583 for exclude_item in esdk_manifest_excludes:
584 esdk_manifest_excludes_list += glob.glob(os.path.join(baseoutpath, exclude_item))
585 manifest_file = os.path.join(baseoutpath, 'conf', 'sdk-conf-manifest')
586 with open(manifest_file, 'w') as f:
587 for item in manifest_file_list:
588 for fn in glob.glob(os.path.join(baseoutpath, item)):
589 if fn == manifest_file or os.path.isdir(fn):
590 continue
591 if fn in esdk_manifest_excludes_list:
592 continue
593 chksum = bb.utils.sha256_file(fn)
594 f.write('%s\t%s\n' % (chksum, os.path.relpath(fn, baseoutpath)))
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600595
596
597python copy_buildsystem () {
598 import oe.copy_buildsystem
599
600 baseoutpath = d.getVar('SDK_OUTPUT') + '/' + d.getVar('SDKPATH')
601
602 # Determine if we're building a derivative extensible SDK (from devtool build-sdk)
603 derivative = (d.getVar('SDK_DERIVATIVE') or '') == '1'
604
605 conf_initpath, conf_bbpath, core_meta_subdir, sdkbblayers = copy_bitbake_and_layers(d, baseoutpath, derivative)
606
607 write_devtool_config(d, baseoutpath, conf_bbpath, conf_initpath, core_meta_subdir)
608
609 write_unlocked_sigs(d, baseoutpath)
610
611 write_bblayers_conf(d, baseoutpath, sdkbblayers)
612
613 uninative_checksum = copy_uninative(d, baseoutpath)
614
615 write_local_conf(d, baseoutpath, derivative, core_meta_subdir, uninative_checksum)
616
617 prepare_locked_cache(d, baseoutpath, derivative, conf_initpath)
618
619 write_manifest(d, baseoutpath)
620
Patrick Williams92b42cb2022-09-03 06:53:57 -0500621}
622
623def get_current_buildtools(d):
624 """Get the file name of the current buildtools installer"""
625 import glob
626 btfiles = glob.glob(os.path.join(d.getVar('SDK_DEPLOY'), '*-buildtools-nativesdk-standalone-*.sh'))
627 btfiles.sort(key=os.path.getctime)
628 return os.path.basename(btfiles[-1])
629
630def get_sdk_required_utilities(buildtools_fn, d):
631 """Find required utilities that aren't provided by the buildtools"""
632 sanity_required_utilities = (d.getVar('SANITY_REQUIRED_UTILITIES') or '').split()
633 sanity_required_utilities.append(d.expand('${BUILD_PREFIX}gcc'))
634 sanity_required_utilities.append(d.expand('${BUILD_PREFIX}g++'))
635 if buildtools_fn:
636 buildtools_installer = os.path.join(d.getVar('SDK_DEPLOY'), buildtools_fn)
637 filelist, _ = bb.process.run('%s -l' % buildtools_installer)
638 else:
639 buildtools_installer = None
640 filelist = ""
641 localdata = bb.data.createCopy(d)
642 localdata.setVar('SDKPATH', '.')
643 sdkpathnative = localdata.getVar('SDKPATHNATIVE')
644 sdkbindirs = [localdata.getVar('bindir_nativesdk'),
645 localdata.getVar('sbindir_nativesdk'),
646 localdata.getVar('base_bindir_nativesdk'),
647 localdata.getVar('base_sbindir_nativesdk')]
648 for line in filelist.splitlines():
649 splitline = line.split()
650 if len(splitline) > 5:
651 fn = splitline[5]
652 if not fn.startswith('./'):
653 fn = './%s' % fn
654 if fn.startswith(sdkpathnative):
655 relpth = '/' + os.path.relpath(fn, sdkpathnative)
656 for bindir in sdkbindirs:
657 if relpth.startswith(bindir):
658 relpth = os.path.relpath(relpth, bindir)
659 if relpth in sanity_required_utilities:
660 sanity_required_utilities.remove(relpth)
661 break
662 return ' '.join(sanity_required_utilities)
663
664install_tools() {
Patrick Williams92b42cb2022-09-03 06:53:57 -0500665 touch ${SDK_OUTPUT}/${SDKPATH}/.devtoolbase
666
667 # find latest buildtools-tarball and install it
668 if [ -n "${SDK_BUILDTOOLS_INSTALLER}" ]; then
669 install ${SDK_DEPLOY}/${SDK_BUILDTOOLS_INSTALLER} ${SDK_OUTPUT}/${SDKPATH}
670 fi
671
672 install -m 0644 ${COREBASE}/meta/files/ext-sdk-prepare.py ${SDK_OUTPUT}/${SDKPATH}
673}
674do_populate_sdk_ext[file-checksums] += "${COREBASE}/meta/files/ext-sdk-prepare.py:True"
675
676sdk_ext_preinst() {
677 # Since bitbake won't run as root it doesn't make sense to try and install
678 # the extensible sdk as root.
679 if [ "`id -u`" = "0" ]; then
680 echo "ERROR: The extensible sdk cannot be installed as root."
681 exit 1
682 fi
683 if ! command -v locale > /dev/null; then
684 echo "ERROR: The installer requires the locale command, please install it first"
685 exit 1
686 fi
687 # Check setting of LC_ALL set above
688 canonicalised_locale=`echo $LC_ALL | sed 's/UTF-8/utf8/'`
689 if ! locale -a | grep -q $canonicalised_locale ; then
690 echo "ERROR: the installer requires the $LC_ALL locale to be installed (but not selected), please install it first"
691 exit 1
692 fi
693 # The relocation script used by buildtools installer requires python
694 if ! command -v python3 > /dev/null; then
695 echo "ERROR: The installer requires python3, please install it first"
696 exit 1
697 fi
698 missing_utils=""
699 for util in ${SDK_REQUIRED_UTILITIES}; do
700 if ! command -v $util > /dev/null; then
701 missing_utils="$missing_utils $util"
702 fi
703 done
704 if [ -n "$missing_utils" ] ; then
705 echo "ERROR: the SDK requires the following missing utilities, please install them: $missing_utils"
706 exit 1
707 fi
708 SDK_EXTENSIBLE="1"
709 if [ "$publish" = "1" ] && [ "${SDK_EXT_TYPE}" = "minimal" ] ; then
710 EXTRA_TAR_OPTIONS="$EXTRA_TAR_OPTIONS --exclude=sstate-cache"
711 fi
712}
713SDK_PRE_INSTALL_COMMAND:task-populate-sdk-ext = "${sdk_ext_preinst}"
714
715# FIXME this preparation should be done as part of the SDK construction
716sdk_ext_postinst() {
717 printf "\nExtracting buildtools...\n"
718 cd $target_sdk_dir
719 env_setup_script="$target_sdk_dir/environment-setup-${REAL_MULTIMACH_TARGET_SYS}"
720 if [ -n "${SDK_BUILDTOOLS_INSTALLER}" ]; then
721 printf "buildtools\ny" | ./${SDK_BUILDTOOLS_INSTALLER} > buildtools.log || { printf 'ERROR: buildtools installation failed:\n' ; cat buildtools.log ; echo "printf 'ERROR: this SDK was not fully installed and needs reinstalling\n'" >> $env_setup_script ; exit 1 ; }
722
723 # Delete the buildtools tar file since it won't be used again
724 rm -f ./${SDK_BUILDTOOLS_INSTALLER}
725 # We don't need the log either since it succeeded
726 rm -f buildtools.log
727
728 # Make sure when the user sets up the environment, they also get
729 # the buildtools-tarball tools in their path.
730 echo "# Save and reset OECORE_NATIVE_SYSROOT as buildtools may change it" >> $env_setup_script
731 echo "SAVED=\"\$OECORE_NATIVE_SYSROOT\"" >> $env_setup_script
732 echo ". $target_sdk_dir/buildtools/environment-setup*" >> $env_setup_script
733 echo "OECORE_NATIVE_SYSROOT=\"\$SAVED\"" >> $env_setup_script
734 fi
735
736 # Allow bitbake environment setup to be ran as part of this sdk.
737 echo "export OE_SKIP_SDK_CHECK=1" >> $env_setup_script
738 # Work around runqemu not knowing how to get this information within the eSDK
739 echo "export DEPLOY_DIR_IMAGE=$target_sdk_dir/tmp/${@os.path.relpath(d.getVar('DEPLOY_DIR_IMAGE'), d.getVar('TMPDIR'))}" >> $env_setup_script
740
741 # A bit of another hack, but we need this in the path only for devtool
742 # so put it at the end of $PATH.
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600743 echo "export PATH=\"$target_sdk_dir/${esdk_tools_path}:\$PATH\"" >> $env_setup_script
Patrick Williams92b42cb2022-09-03 06:53:57 -0500744
745 echo "printf 'SDK environment now set up; additionally you may now run devtool to perform development tasks.\nRun devtool --help for further details.\n'" >> $env_setup_script
746
747 # Warn if trying to use external bitbake and the ext SDK together
748 echo "(which bitbake > /dev/null 2>&1 && echo 'WARNING: attempting to use the extensible SDK in an environment set up to run bitbake - this may lead to unexpected results. Please source this script in a new shell session instead.') || true" >> $env_setup_script
749
750 if [ "$prepare_buildsystem" != "no" -a -n "${SDK_BUILDTOOLS_INSTALLER}" ]; then
751 printf "Preparing build system...\n"
752 # dash which is /bin/sh on Ubuntu will not preserve the
753 # current working directory when first ran, nor will it set $1 when
754 # sourcing a script. That is why this has to look so ugly.
755 LOGFILE="$target_sdk_dir/preparing_build_system.log"
Andrew Geissler028142b2023-05-05 11:29:21 -0500756 sh -c ". buildtools/environment-setup* > $LOGFILE 2>&1 && cd $target_sdk_dir/`dirname ${oe_init_build_env_path}` && set $target_sdk_dir && . $target_sdk_dir/${oe_init_build_env_path} $target_sdk_dir >> $LOGFILE 2>&1 && python3 $target_sdk_dir/ext-sdk-prepare.py $LOGFILE '${SDK_INSTALL_TARGETS}'" || { echo "printf 'ERROR: this SDK was not fully installed and needs reinstalling\n'" >> $env_setup_script ; exit 1 ; }
Patrick Williams92b42cb2022-09-03 06:53:57 -0500757 fi
758 if [ -e $target_sdk_dir/ext-sdk-prepare.py ]; then
759 rm $target_sdk_dir/ext-sdk-prepare.py
760 fi
761 echo done
762}
763
764SDK_POST_INSTALL_COMMAND:task-populate-sdk-ext = "${sdk_ext_postinst}"
765
Andrew Geissler5082cc72023-09-11 08:41:39 -0400766SDK_POSTPROCESS_COMMAND:prepend:task-populate-sdk-ext = "copy_buildsystem install_tools "
Patrick Williams92b42cb2022-09-03 06:53:57 -0500767
768SDK_INSTALL_TARGETS = ""
769fakeroot python do_populate_sdk_ext() {
770 # FIXME hopefully we can remove this restriction at some point, but uninative
771 # currently forces this upon us
772 if d.getVar('SDK_ARCH') != d.getVar('BUILD_ARCH'):
773 bb.fatal('The extensible SDK can currently only be built for the same architecture as the machine being built on - SDK_ARCH is set to %s (likely via setting SDKMACHINE) which is different from the architecture of the build machine (%s). Unable to continue.' % (d.getVar('SDK_ARCH'), d.getVar('BUILD_ARCH')))
774
775 # FIXME hopefully we can remove this restriction at some point, but the eSDK
776 # can only be built for the primary (default) multiconfig
777 if d.getVar('BB_CURRENT_MC') != 'default':
778 bb.fatal('The extensible SDK can currently only be built for the default multiconfig. Currently trying to build for %s.' % d.getVar('BB_CURRENT_MC'))
779
780 # eSDK dependencies don't use the traditional variables and things don't work properly if they are set
781 d.setVar("TOOLCHAIN_HOST_TASK", "${TOOLCHAIN_HOST_TASK_ESDK}")
782 d.setVar("TOOLCHAIN_TARGET_TASK", "")
783
784 d.setVar('SDK_INSTALL_TARGETS', get_sdk_install_targets(d))
785 if d.getVar('SDK_INCLUDE_BUILDTOOLS') == '1':
786 buildtools_fn = get_current_buildtools(d)
787 else:
788 buildtools_fn = None
789 d.setVar('SDK_REQUIRED_UTILITIES', get_sdk_required_utilities(buildtools_fn, d))
790 d.setVar('SDK_BUILDTOOLS_INSTALLER', buildtools_fn)
791 d.setVar('SDKDEPLOYDIR', '${SDKEXTDEPLOYDIR}')
792 # ESDKs have a libc from the buildtools so ensure we don't ship linguas twice
793 d.delVar('SDKIMAGE_LINGUAS')
794 if d.getVar("SDK_INCLUDE_NATIVESDK") == '1':
795 generate_nativesdk_lockedsigs(d)
796 populate_sdk_common(d)
797}
798
799def generate_nativesdk_lockedsigs(d):
800 import oe.copy_buildsystem
801 sigfile = d.getVar('WORKDIR') + '/locked-sigs_nativesdk.inc'
802 oe.copy_buildsystem.generate_locked_sigs(sigfile, d)
803
804def get_ext_sdk_depends(d):
805 # Note: the deps varflag is a list not a string, so we need to specify expand=False
806 deps = d.getVarFlag('do_image_complete', 'deps', False)
807 pn = d.getVar('PN')
808 deplist = ['%s:%s' % (pn, dep) for dep in deps]
809 tasklist = bb.build.tasksbetween('do_image_complete', 'do_build', d)
810 tasklist.append('do_rootfs')
811 for task in tasklist:
812 deplist.extend((d.getVarFlag(task, 'depends') or '').split())
813 return ' '.join(deplist)
814
815python do_sdk_depends() {
816 # We have to do this separately in its own task so we avoid recursing into
817 # dependencies we don't need to (e.g. buildtools-tarball) and bringing those
818 # into the SDK's sstate-cache
819 import oe.copy_buildsystem
820 sigfile = d.getVar('WORKDIR') + '/locked-sigs.inc'
821 oe.copy_buildsystem.generate_locked_sigs(sigfile, d)
822}
823addtask sdk_depends
824
825do_sdk_depends[dirs] = "${WORKDIR}"
826do_sdk_depends[depends] = "${@get_ext_sdk_depends(d)} meta-extsdk-toolchain:do_populate_sysroot"
827do_sdk_depends[recrdeptask] = "${@d.getVarFlag('do_populate_sdk', 'recrdeptask', False)}"
828do_sdk_depends[recrdeptask] += "do_populate_lic do_package_qa do_populate_sysroot do_deploy ${SDK_RECRDEP_TASKS}"
829do_sdk_depends[rdepends] = "${@' '.join([x + ':do_package_write_${IMAGE_PKGTYPE} ' + x + ':do_packagedata' for x in d.getVar('TOOLCHAIN_HOST_TASK_ESDK').split()])}"
830
831do_populate_sdk_ext[dirs] = "${@d.getVarFlag('do_populate_sdk', 'dirs', False)}"
832
833do_populate_sdk_ext[depends] = "${@d.getVarFlag('do_populate_sdk', 'depends', False)} \
834 ${@'buildtools-tarball:do_populate_sdk' if d.getVar('SDK_INCLUDE_BUILDTOOLS') == '1' else ''} \
835 ${@'meta-world-pkgdata:do_collect_packagedata' if d.getVar('SDK_INCLUDE_PKGDATA') == '1' else ''} \
836 ${@'meta-extsdk-toolchain:do_locked_sigs' if d.getVar('SDK_INCLUDE_TOOLCHAIN') == '1' else ''}"
837
838# We must avoid depending on do_build here if rm_work.bbclass is active,
839# because otherwise do_rm_work may run before do_populate_sdk_ext itself.
840# We can't mark do_populate_sdk_ext and do_sdk_depends as having to
841# run before do_rm_work, because then they would also run as part
842# of normal builds.
843do_populate_sdk_ext[rdepends] += "${@' '.join([x + ':' + (d.getVar('RM_WORK_BUILD_WITHOUT') or 'do_build') for x in d.getVar('SDK_TARGETS').split()])}"
844
845# Make sure code changes can result in rebuild
846do_populate_sdk_ext[vardeps] += "copy_buildsystem \
847 sdk_ext_postinst"
848
849# Since any change in the metadata of any layer should cause a rebuild of the
850# sdk(since the layers are put in the sdk) set the task to nostamp so it
851# always runs.
852do_populate_sdk_ext[nostamp] = "1"
853
854SDKEXTDEPLOYDIR = "${WORKDIR}/deploy-${PN}-populate-sdk-ext"
855
856SSTATETASKS += "do_populate_sdk_ext"
857SSTATE_SKIP_CREATION:task-populate-sdk-ext = '1'
858do_populate_sdk_ext[cleandirs] = "${SDKEXTDEPLOYDIR}"
859do_populate_sdk_ext[sstate-inputdirs] = "${SDKEXTDEPLOYDIR}"
860do_populate_sdk_ext[sstate-outputdirs] = "${SDK_DEPLOY}"
861do_populate_sdk_ext[stamp-extra-info] = "${MACHINE_ARCH}"
862
863addtask populate_sdk_ext after do_sdk_depends