blob: a0d829054e11ebd790eea55c4c72264885e27ccb [file] [log] [blame]
Brad Bishopc342db32019-05-15 21:57:59 -04001#
Patrick Williams92b42cb2022-09-03 06:53:57 -05002# Copyright OpenEmbedded Contributors
3#
Brad Bishopc342db32019-05-15 21:57:59 -04004# SPDX-License-Identifier: GPL-2.0-only
5#
Patrick Williamsc124f4f2015-09-15 14:41:29 -05006# This class should provide easy access to the different aspects of the
7# buildsystem such as layers, bitbake location, etc.
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08008#
9# SDK_LAYERS_EXCLUDE: Layers which will be excluded from SDK layers.
10# SDK_LAYERS_EXCLUDE_PATTERN: The simiar to SDK_LAYERS_EXCLUDE, this supports
11# python regular expression, use space as separator,
12# e.g.: ".*-downloads closed-.*"
13#
14
Patrick Williamsc124f4f2015-09-15 14:41:29 -050015import stat
16import shutil
17
18def _smart_copy(src, dest):
Brad Bishop37a0e4d2017-12-04 01:01:44 -050019 import subprocess
Patrick Williamsc124f4f2015-09-15 14:41:29 -050020 # smart_copy will choose the correct function depending on whether the
21 # source is a file or a directory.
22 mode = os.stat(src).st_mode
23 if stat.S_ISDIR(mode):
Brad Bishop37a0e4d2017-12-04 01:01:44 -050024 bb.utils.mkdirhier(dest)
Andrew Geissler95ac1b82021-03-31 14:34:31 -050025 cmd = "tar --exclude='.git' --exclude='__pycache__' --xattrs --xattrs-include='*' -chf - -C %s -p . \
Brad Bishop37a0e4d2017-12-04 01:01:44 -050026 | tar --xattrs --xattrs-include='*' -xf - -C %s" % (src, dest)
27 subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050028 else:
29 shutil.copyfile(src, dest)
30 shutil.copymode(src, dest)
31
32class BuildSystem(object):
Patrick Williamsf1e5d692016-03-30 15:21:19 -050033 def __init__(self, context, d):
Patrick Williamsc124f4f2015-09-15 14:41:29 -050034 self.d = d
Patrick Williamsf1e5d692016-03-30 15:21:19 -050035 self.context = context
Brad Bishop6e60e8b2018-02-01 10:27:11 -050036 self.layerdirs = [os.path.abspath(pth) for pth in d.getVar('BBLAYERS').split()]
37 self.layers_exclude = (d.getVar('SDK_LAYERS_EXCLUDE') or "").split()
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080038 self.layers_exclude_pattern = d.getVar('SDK_LAYERS_EXCLUDE_PATTERN')
Patrick Williamsc124f4f2015-09-15 14:41:29 -050039
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050040 def copy_bitbake_and_layers(self, destdir, workspace_name=None):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080041 import re
Patrick Williamsc124f4f2015-09-15 14:41:29 -050042 # Copy in all metadata layers + bitbake (as repositories)
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080043 copied_corebase = None
Patrick Williamsc124f4f2015-09-15 14:41:29 -050044 layers_copied = []
45 bb.utils.mkdirhier(destdir)
46 layers = list(self.layerdirs)
47
Brad Bishop6e60e8b2018-02-01 10:27:11 -050048 corebase = os.path.abspath(self.d.getVar('COREBASE'))
Patrick Williamsc124f4f2015-09-15 14:41:29 -050049 layers.append(corebase)
Brad Bishopd7bf8c12018-02-25 22:55:05 -050050 # The bitbake build system uses the meta-skeleton layer as a layout
51 # for common recipies, e.g: the recipetool script to create kernel recipies
52 # Add the meta-skeleton layer to be included as part of the eSDK installation
53 layers.append(os.path.join(corebase, 'meta-skeleton'))
Patrick Williamsc124f4f2015-09-15 14:41:29 -050054
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050055 # Exclude layers
56 for layer_exclude in self.layers_exclude:
57 if layer_exclude in layers:
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080058 bb.note('Excluded %s from sdk layers since it is in SDK_LAYERS_EXCLUDE' % layer_exclude)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050059 layers.remove(layer_exclude)
60
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080061 if self.layers_exclude_pattern:
62 layers_cp = layers[:]
63 for pattern in self.layers_exclude_pattern.split():
64 for layer in layers_cp:
65 if re.match(pattern, layer):
66 bb.note('Excluded %s from sdk layers since matched SDK_LAYERS_EXCLUDE_PATTERN' % layer)
67 layers.remove(layer)
68
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050069 workspace_newname = workspace_name
70 if workspace_newname:
71 layernames = [os.path.basename(layer) for layer in layers]
72 extranum = 0
73 while workspace_newname in layernames:
74 extranum += 1
75 workspace_newname = '%s-%d' % (workspace_name, extranum)
76
Brad Bishop6e60e8b2018-02-01 10:27:11 -050077 corebase_files = self.d.getVar('COREBASE_FILES').split()
Patrick Williamsc124f4f2015-09-15 14:41:29 -050078 corebase_files = [corebase + '/' +x for x in corebase_files]
79 # Make sure bitbake goes in
80 bitbake_dir = bb.__file__.rsplit('/', 3)[0]
81 corebase_files.append(bitbake_dir)
82
83 for layer in layers:
84 layerconf = os.path.join(layer, 'conf', 'layer.conf')
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050085 layernewname = os.path.basename(layer)
86 workspace = False
Patrick Williamsc124f4f2015-09-15 14:41:29 -050087 if os.path.exists(layerconf):
88 with open(layerconf, 'r') as f:
89 if f.readline().startswith("# ### workspace layer auto-generated by devtool ###"):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050090 if workspace_newname:
91 layernewname = workspace_newname
92 workspace = True
93 else:
94 bb.plain("NOTE: Excluding local workspace layer %s from %s" % (layer, self.context))
95 continue
Patrick Williamsc124f4f2015-09-15 14:41:29 -050096
97 # If the layer was already under corebase, leave it there
98 # since layers such as meta have issues when moved.
99 layerdestpath = destdir
100 if corebase == os.path.dirname(layer):
101 layerdestpath += '/' + os.path.basename(corebase)
Andrew Geissler9aee5002022-03-30 16:27:02 +0000102 # If the layer is located somewhere under the same parent directory
103 # as corebase we keep the layer structure.
104 elif os.path.commonpath([layer, corebase]) == os.path.dirname(corebase):
105 layer_relative = os.path.relpath(layer, os.path.dirname(corebase))
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500106 if os.path.dirname(layer_relative) != layernewname:
107 layerdestpath += '/' + os.path.dirname(layer_relative)
108
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500109 layerdestpath += '/' + layernewname
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500110
111 layer_relative = os.path.relpath(layerdestpath,
112 destdir)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500113 # Treat corebase as special since it typically will contain
114 # build directories or other custom items.
115 if corebase == layer:
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800116 copied_corebase = layer_relative
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500117 bb.utils.mkdirhier(layerdestpath)
118 for f in corebase_files:
119 f_basename = os.path.basename(f)
120 destname = os.path.join(layerdestpath, f_basename)
121 _smart_copy(f, destname)
122 else:
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800123 layers_copied.append(layer_relative)
124
Brad Bishop316dfdd2018-06-25 12:45:53 -0400125 if os.path.exists(os.path.join(layerdestpath, 'conf/layer.conf')):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500126 bb.note("Skipping layer %s, already handled" % layer)
127 else:
128 _smart_copy(layer, layerdestpath)
129
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500130 if workspace:
131 # Make some adjustments original workspace layer
132 # Drop sources (recipe tasks will be locked, so we don't need them)
133 srcdir = os.path.join(layerdestpath, 'sources')
134 if os.path.isdir(srcdir):
135 shutil.rmtree(srcdir)
136 # Drop all bbappends except the one for the image the SDK is being built for
137 # (because of externalsrc, the workspace bbappends will interfere with the
138 # locked signatures if present, and we don't need them anyway)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500139 image_bbappend = os.path.splitext(os.path.basename(self.d.getVar('FILE')))[0] + '.bbappend'
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500140 appenddir = os.path.join(layerdestpath, 'appends')
141 if os.path.isdir(appenddir):
142 for fn in os.listdir(appenddir):
143 if fn == image_bbappend:
144 continue
145 else:
146 os.remove(os.path.join(appenddir, fn))
147 # Drop README
148 readme = os.path.join(layerdestpath, 'README')
149 if os.path.exists(readme):
150 os.remove(readme)
151 # Filter out comments in layer.conf and change layer name
152 layerconf = os.path.join(layerdestpath, 'conf', 'layer.conf')
153 with open(layerconf, 'r') as f:
154 origlines = f.readlines()
155 with open(layerconf, 'w') as f:
156 for line in origlines:
157 if line.startswith('#'):
158 continue
159 line = line.replace('workspacelayer', workspace_newname)
160 f.write(line)
161
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500162 # meta-skeleton layer is added as part of the build system
163 # but not as a layer included in the build, therefore it is
164 # not reported to the function caller.
165 for layer in layers_copied:
166 if layer.endswith('/meta-skeleton'):
167 layers_copied.remove(layer)
168 break
169
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800170 return copied_corebase, layers_copied
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500171
172def generate_locked_sigs(sigfile, d):
173 bb.utils.mkdirhier(os.path.dirname(sigfile))
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500174 depd = d.getVar('BB_TASKDEPDATA', False)
Brad Bishop08902b02019-08-20 09:16:51 -0400175 tasks = ['%s:%s' % (v[2], v[1]) for v in depd.values()]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500176 bb.parse.siggen.dump_lockedsigs(sigfile, tasks)
177
Brad Bishopa34c0302019-09-23 22:34:48 -0400178def prune_lockedsigs(excluded_tasks, excluded_targets, lockedsigs, onlynative, pruned_output):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500179 with open(lockedsigs, 'r') as infile:
180 bb.utils.mkdirhier(os.path.dirname(pruned_output))
181 with open(pruned_output, 'w') as f:
182 invalue = False
183 for line in infile:
184 if invalue:
185 if line.endswith('\\\n'):
186 splitval = line.strip().split(':')
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500187 if not splitval[1] in excluded_tasks and not splitval[0] in excluded_targets:
Brad Bishopa34c0302019-09-23 22:34:48 -0400188 if onlynative:
189 if 'nativesdk' in splitval[0]:
190 f.write(line)
191 else:
192 f.write(line)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500193 else:
194 f.write(line)
195 invalue = False
196 elif line.startswith('SIGGEN_LOCKEDSIGS'):
197 invalue = True
198 f.write(line)
199
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600200def merge_lockedsigs(copy_tasks, lockedsigs_main, lockedsigs_extra, merged_output, copy_output=None):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500201 merged = {}
202 arch_order = []
203 with open(lockedsigs_main, 'r') as f:
204 invalue = None
205 for line in f:
206 if invalue:
207 if line.endswith('\\\n'):
208 merged[invalue].append(line)
209 else:
210 invalue = None
211 elif line.startswith('SIGGEN_LOCKEDSIGS_t-'):
212 invalue = line[18:].split('=', 1)[0].rstrip()
213 merged[invalue] = []
214 arch_order.append(invalue)
215
216 with open(lockedsigs_extra, 'r') as f:
217 invalue = None
218 tocopy = {}
219 for line in f:
220 if invalue:
221 if line.endswith('\\\n'):
222 if not line in merged[invalue]:
223 target, task = line.strip().split(':')[:2]
224 if not copy_tasks or task in copy_tasks:
225 tocopy[invalue].append(line)
226 merged[invalue].append(line)
227 else:
228 invalue = None
229 elif line.startswith('SIGGEN_LOCKEDSIGS_t-'):
230 invalue = line[18:].split('=', 1)[0].rstrip()
231 if not invalue in merged:
232 merged[invalue] = []
233 arch_order.append(invalue)
234 tocopy[invalue] = []
235
236 def write_sigs_file(fn, types, sigs):
237 fulltypes = []
238 bb.utils.mkdirhier(os.path.dirname(fn))
239 with open(fn, 'w') as f:
240 for typename in types:
241 lines = sigs[typename]
242 if lines:
243 f.write('SIGGEN_LOCKEDSIGS_%s = "\\\n' % typename)
244 for line in lines:
245 f.write(line)
246 f.write(' "\n')
247 fulltypes.append(typename)
248 f.write('SIGGEN_LOCKEDSIGS_TYPES = "%s"\n' % ' '.join(fulltypes))
249
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600250 if copy_output:
251 write_sigs_file(copy_output, list(tocopy.keys()), tocopy)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500252 if merged_output:
253 write_sigs_file(merged_output, arch_order, merged)
254
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600255def create_locked_sstate_cache(lockedsigs, input_sstate_cache, output_sstate_cache, d, fixedlsbstring="", filterfile=None):
256 import shutil
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500257 bb.note('Generating sstate-cache...')
258
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500259 nativelsbstring = d.getVar('NATIVELSBSTRING')
Andrew Geissler95ac1b82021-03-31 14:34:31 -0500260 bb.process.run("PYTHONDONTWRITEBYTECODE=1 gen-lockedsig-cache %s %s %s %s %s" % (lockedsigs, input_sstate_cache, output_sstate_cache, nativelsbstring, filterfile or ''))
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600261 if fixedlsbstring and nativelsbstring != fixedlsbstring:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500262 nativedir = output_sstate_cache + '/' + nativelsbstring
263 if os.path.isdir(nativedir):
264 destdir = os.path.join(output_sstate_cache, fixedlsbstring)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600265 for root, _, files in os.walk(nativedir):
266 for fn in files:
267 src = os.path.join(root, fn)
268 dest = os.path.join(destdir, os.path.relpath(src, nativedir))
269 if os.path.exists(dest):
270 # Already exists, and it'll be the same file, so just delete it
271 os.unlink(src)
272 else:
273 bb.utils.mkdirhier(os.path.dirname(dest))
274 shutil.move(src, dest)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500275
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600276def check_sstate_task_list(d, targets, filteroutfile, cmdprefix='', cwd=None, logfile=None):
277 import subprocess
278
279 bb.note('Generating sstate task list...')
280
281 if not cwd:
282 cwd = os.getcwd()
283 if logfile:
284 logparam = '-l %s' % logfile
285 else:
286 logparam = ''
Andrew Geissler95ac1b82021-03-31 14:34:31 -0500287 cmd = "%sPYTHONDONTWRITEBYTECODE=1 BB_SETSCENE_ENFORCE=1 PSEUDO_DISABLED=1 oe-check-sstate %s -s -o %s %s" % (cmdprefix, targets, filteroutfile, logparam)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600288 env = dict(d.getVar('BB_ORIGENV', False))
289 env.pop('BUILDDIR', '')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500290 env.pop('BBPATH', '')
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600291 pathitems = env['PATH'].split(':')
292 env['PATH'] = ':'.join([item for item in pathitems if not item.endswith('/bitbake/bin')])
293 bb.process.run(cmd, stderr=subprocess.STDOUT, env=env, cwd=cwd, executable='/bin/bash')