blob: 7cb784cf8c4c5dfc1e3429ad778f1b37f52cc1a9 [file] [log] [blame]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001# This class should provide easy access to the different aspects of the
2# buildsystem such as layers, bitbake location, etc.
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08003#
4# SDK_LAYERS_EXCLUDE: Layers which will be excluded from SDK layers.
5# SDK_LAYERS_EXCLUDE_PATTERN: The simiar to SDK_LAYERS_EXCLUDE, this supports
6# python regular expression, use space as separator,
7# e.g.: ".*-downloads closed-.*"
8#
9
Patrick Williamsc124f4f2015-09-15 14:41:29 -050010import stat
11import shutil
12
13def _smart_copy(src, dest):
Brad Bishop37a0e4d2017-12-04 01:01:44 -050014 import subprocess
Patrick Williamsc124f4f2015-09-15 14:41:29 -050015 # smart_copy will choose the correct function depending on whether the
16 # source is a file or a directory.
17 mode = os.stat(src).st_mode
18 if stat.S_ISDIR(mode):
Brad Bishop37a0e4d2017-12-04 01:01:44 -050019 bb.utils.mkdirhier(dest)
20 cmd = "tar --exclude='.git' --xattrs --xattrs-include='*' -chf - -C %s -p . \
21 | tar --xattrs --xattrs-include='*' -xf - -C %s" % (src, dest)
22 subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050023 else:
24 shutil.copyfile(src, dest)
25 shutil.copymode(src, dest)
26
27class BuildSystem(object):
Patrick Williamsf1e5d692016-03-30 15:21:19 -050028 def __init__(self, context, d):
Patrick Williamsc124f4f2015-09-15 14:41:29 -050029 self.d = d
Patrick Williamsf1e5d692016-03-30 15:21:19 -050030 self.context = context
Brad Bishop6e60e8b2018-02-01 10:27:11 -050031 self.layerdirs = [os.path.abspath(pth) for pth in d.getVar('BBLAYERS').split()]
32 self.layers_exclude = (d.getVar('SDK_LAYERS_EXCLUDE') or "").split()
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080033 self.layers_exclude_pattern = d.getVar('SDK_LAYERS_EXCLUDE_PATTERN')
Patrick Williamsc124f4f2015-09-15 14:41:29 -050034
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050035 def copy_bitbake_and_layers(self, destdir, workspace_name=None):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080036 import re
Patrick Williamsc124f4f2015-09-15 14:41:29 -050037 # Copy in all metadata layers + bitbake (as repositories)
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080038 copied_corebase = None
Patrick Williamsc124f4f2015-09-15 14:41:29 -050039 layers_copied = []
40 bb.utils.mkdirhier(destdir)
41 layers = list(self.layerdirs)
42
Brad Bishop6e60e8b2018-02-01 10:27:11 -050043 corebase = os.path.abspath(self.d.getVar('COREBASE'))
Patrick Williamsc124f4f2015-09-15 14:41:29 -050044 layers.append(corebase)
Brad Bishopd7bf8c12018-02-25 22:55:05 -050045 # The bitbake build system uses the meta-skeleton layer as a layout
46 # for common recipies, e.g: the recipetool script to create kernel recipies
47 # Add the meta-skeleton layer to be included as part of the eSDK installation
48 layers.append(os.path.join(corebase, 'meta-skeleton'))
Patrick Williamsc124f4f2015-09-15 14:41:29 -050049
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050050 # Exclude layers
51 for layer_exclude in self.layers_exclude:
52 if layer_exclude in layers:
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080053 bb.note('Excluded %s from sdk layers since it is in SDK_LAYERS_EXCLUDE' % layer_exclude)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050054 layers.remove(layer_exclude)
55
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080056 if self.layers_exclude_pattern:
57 layers_cp = layers[:]
58 for pattern in self.layers_exclude_pattern.split():
59 for layer in layers_cp:
60 if re.match(pattern, layer):
61 bb.note('Excluded %s from sdk layers since matched SDK_LAYERS_EXCLUDE_PATTERN' % layer)
62 layers.remove(layer)
63
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050064 workspace_newname = workspace_name
65 if workspace_newname:
66 layernames = [os.path.basename(layer) for layer in layers]
67 extranum = 0
68 while workspace_newname in layernames:
69 extranum += 1
70 workspace_newname = '%s-%d' % (workspace_name, extranum)
71
Brad Bishop6e60e8b2018-02-01 10:27:11 -050072 corebase_files = self.d.getVar('COREBASE_FILES').split()
Patrick Williamsc124f4f2015-09-15 14:41:29 -050073 corebase_files = [corebase + '/' +x for x in corebase_files]
74 # Make sure bitbake goes in
75 bitbake_dir = bb.__file__.rsplit('/', 3)[0]
76 corebase_files.append(bitbake_dir)
77
78 for layer in layers:
79 layerconf = os.path.join(layer, 'conf', 'layer.conf')
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050080 layernewname = os.path.basename(layer)
81 workspace = False
Patrick Williamsc124f4f2015-09-15 14:41:29 -050082 if os.path.exists(layerconf):
83 with open(layerconf, 'r') as f:
84 if f.readline().startswith("# ### workspace layer auto-generated by devtool ###"):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050085 if workspace_newname:
86 layernewname = workspace_newname
87 workspace = True
88 else:
89 bb.plain("NOTE: Excluding local workspace layer %s from %s" % (layer, self.context))
90 continue
Patrick Williamsc124f4f2015-09-15 14:41:29 -050091
92 # If the layer was already under corebase, leave it there
93 # since layers such as meta have issues when moved.
94 layerdestpath = destdir
95 if corebase == os.path.dirname(layer):
96 layerdestpath += '/' + os.path.basename(corebase)
Brad Bishopd7bf8c12018-02-25 22:55:05 -050097 else:
98 layer_relative = os.path.basename(corebase) + '/' + os.path.relpath(layer, corebase)
99 if os.path.dirname(layer_relative) != layernewname:
100 layerdestpath += '/' + os.path.dirname(layer_relative)
101
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500102 layerdestpath += '/' + layernewname
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500103
104 layer_relative = os.path.relpath(layerdestpath,
105 destdir)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500106 # Treat corebase as special since it typically will contain
107 # build directories or other custom items.
108 if corebase == layer:
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800109 copied_corebase = layer_relative
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500110 bb.utils.mkdirhier(layerdestpath)
111 for f in corebase_files:
112 f_basename = os.path.basename(f)
113 destname = os.path.join(layerdestpath, f_basename)
114 _smart_copy(f, destname)
115 else:
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800116 layers_copied.append(layer_relative)
117
Brad Bishop316dfdd2018-06-25 12:45:53 -0400118 if os.path.exists(os.path.join(layerdestpath, 'conf/layer.conf')):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500119 bb.note("Skipping layer %s, already handled" % layer)
120 else:
121 _smart_copy(layer, layerdestpath)
122
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500123 if workspace:
124 # Make some adjustments original workspace layer
125 # Drop sources (recipe tasks will be locked, so we don't need them)
126 srcdir = os.path.join(layerdestpath, 'sources')
127 if os.path.isdir(srcdir):
128 shutil.rmtree(srcdir)
129 # Drop all bbappends except the one for the image the SDK is being built for
130 # (because of externalsrc, the workspace bbappends will interfere with the
131 # locked signatures if present, and we don't need them anyway)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500132 image_bbappend = os.path.splitext(os.path.basename(self.d.getVar('FILE')))[0] + '.bbappend'
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500133 appenddir = os.path.join(layerdestpath, 'appends')
134 if os.path.isdir(appenddir):
135 for fn in os.listdir(appenddir):
136 if fn == image_bbappend:
137 continue
138 else:
139 os.remove(os.path.join(appenddir, fn))
140 # Drop README
141 readme = os.path.join(layerdestpath, 'README')
142 if os.path.exists(readme):
143 os.remove(readme)
144 # Filter out comments in layer.conf and change layer name
145 layerconf = os.path.join(layerdestpath, 'conf', 'layer.conf')
146 with open(layerconf, 'r') as f:
147 origlines = f.readlines()
148 with open(layerconf, 'w') as f:
149 for line in origlines:
150 if line.startswith('#'):
151 continue
152 line = line.replace('workspacelayer', workspace_newname)
153 f.write(line)
154
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500155 # meta-skeleton layer is added as part of the build system
156 # but not as a layer included in the build, therefore it is
157 # not reported to the function caller.
158 for layer in layers_copied:
159 if layer.endswith('/meta-skeleton'):
160 layers_copied.remove(layer)
161 break
162
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800163 return copied_corebase, layers_copied
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500164
165def generate_locked_sigs(sigfile, d):
166 bb.utils.mkdirhier(os.path.dirname(sigfile))
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500167 depd = d.getVar('BB_TASKDEPDATA', False)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600168 tasks = ['%s.%s' % (v[2], v[1]) for v in depd.values()]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500169 bb.parse.siggen.dump_lockedsigs(sigfile, tasks)
170
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500171def prune_lockedsigs(excluded_tasks, excluded_targets, lockedsigs, pruned_output):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500172 with open(lockedsigs, 'r') as infile:
173 bb.utils.mkdirhier(os.path.dirname(pruned_output))
174 with open(pruned_output, 'w') as f:
175 invalue = False
176 for line in infile:
177 if invalue:
178 if line.endswith('\\\n'):
179 splitval = line.strip().split(':')
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500180 if not splitval[1] in excluded_tasks and not splitval[0] in excluded_targets:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500181 f.write(line)
182 else:
183 f.write(line)
184 invalue = False
185 elif line.startswith('SIGGEN_LOCKEDSIGS'):
186 invalue = True
187 f.write(line)
188
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600189def merge_lockedsigs(copy_tasks, lockedsigs_main, lockedsigs_extra, merged_output, copy_output=None):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500190 merged = {}
191 arch_order = []
192 with open(lockedsigs_main, 'r') as f:
193 invalue = None
194 for line in f:
195 if invalue:
196 if line.endswith('\\\n'):
197 merged[invalue].append(line)
198 else:
199 invalue = None
200 elif line.startswith('SIGGEN_LOCKEDSIGS_t-'):
201 invalue = line[18:].split('=', 1)[0].rstrip()
202 merged[invalue] = []
203 arch_order.append(invalue)
204
205 with open(lockedsigs_extra, 'r') as f:
206 invalue = None
207 tocopy = {}
208 for line in f:
209 if invalue:
210 if line.endswith('\\\n'):
211 if not line in merged[invalue]:
212 target, task = line.strip().split(':')[:2]
213 if not copy_tasks or task in copy_tasks:
214 tocopy[invalue].append(line)
215 merged[invalue].append(line)
216 else:
217 invalue = None
218 elif line.startswith('SIGGEN_LOCKEDSIGS_t-'):
219 invalue = line[18:].split('=', 1)[0].rstrip()
220 if not invalue in merged:
221 merged[invalue] = []
222 arch_order.append(invalue)
223 tocopy[invalue] = []
224
225 def write_sigs_file(fn, types, sigs):
226 fulltypes = []
227 bb.utils.mkdirhier(os.path.dirname(fn))
228 with open(fn, 'w') as f:
229 for typename in types:
230 lines = sigs[typename]
231 if lines:
232 f.write('SIGGEN_LOCKEDSIGS_%s = "\\\n' % typename)
233 for line in lines:
234 f.write(line)
235 f.write(' "\n')
236 fulltypes.append(typename)
237 f.write('SIGGEN_LOCKEDSIGS_TYPES = "%s"\n' % ' '.join(fulltypes))
238
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600239 if copy_output:
240 write_sigs_file(copy_output, list(tocopy.keys()), tocopy)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500241 if merged_output:
242 write_sigs_file(merged_output, arch_order, merged)
243
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600244def create_locked_sstate_cache(lockedsigs, input_sstate_cache, output_sstate_cache, d, fixedlsbstring="", filterfile=None):
245 import shutil
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500246 bb.note('Generating sstate-cache...')
247
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500248 nativelsbstring = d.getVar('NATIVELSBSTRING')
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600249 bb.process.run("gen-lockedsig-cache %s %s %s %s %s" % (lockedsigs, input_sstate_cache, output_sstate_cache, nativelsbstring, filterfile or ''))
250 if fixedlsbstring and nativelsbstring != fixedlsbstring:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500251 nativedir = output_sstate_cache + '/' + nativelsbstring
252 if os.path.isdir(nativedir):
253 destdir = os.path.join(output_sstate_cache, fixedlsbstring)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600254 for root, _, files in os.walk(nativedir):
255 for fn in files:
256 src = os.path.join(root, fn)
257 dest = os.path.join(destdir, os.path.relpath(src, nativedir))
258 if os.path.exists(dest):
259 # Already exists, and it'll be the same file, so just delete it
260 os.unlink(src)
261 else:
262 bb.utils.mkdirhier(os.path.dirname(dest))
263 shutil.move(src, dest)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500264
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600265def check_sstate_task_list(d, targets, filteroutfile, cmdprefix='', cwd=None, logfile=None):
266 import subprocess
267
268 bb.note('Generating sstate task list...')
269
270 if not cwd:
271 cwd = os.getcwd()
272 if logfile:
273 logparam = '-l %s' % logfile
274 else:
275 logparam = ''
276 cmd = "%sBB_SETSCENE_ENFORCE=1 PSEUDO_DISABLED=1 oe-check-sstate %s -s -o %s %s" % (cmdprefix, targets, filteroutfile, logparam)
277 env = dict(d.getVar('BB_ORIGENV', False))
278 env.pop('BUILDDIR', '')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500279 env.pop('BBPATH', '')
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600280 pathitems = env['PATH'].split(':')
281 env['PATH'] = ':'.join([item for item in pathitems if not item.endswith('/bitbake/bin')])
282 bb.process.run(cmd, stderr=subprocess.STDOUT, env=env, cwd=cwd, executable='/bin/bash')