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