1 | |
---|
2 | # Copyright 2012-2016 Chris Johns (chrisj@rtems.org) |
---|
3 | # |
---|
4 | # Redistribution and use in source and binary forms, with or without |
---|
5 | # modification, are permitted provided that the following conditions are met: |
---|
6 | |
---|
7 | # 1. Redistributions of source code must retain the above copyright notice, this |
---|
8 | # list of conditions and the following disclaimer. |
---|
9 | |
---|
10 | # 2. Redistributions in binary form must reproduce the above copyright notice, |
---|
11 | # this list of conditions and the following disclaimer in the documentation |
---|
12 | # and/or other materials provided with the distribution. |
---|
13 | |
---|
14 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
---|
15 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
---|
16 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
---|
17 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE |
---|
18 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
---|
19 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
---|
20 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
---|
21 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
---|
22 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
---|
23 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
---|
24 | |
---|
25 | from __future__ import print_function |
---|
26 | |
---|
27 | # |
---|
28 | # RTEMS support for applications. |
---|
29 | # |
---|
30 | |
---|
31 | import copy |
---|
32 | import os |
---|
33 | import os.path |
---|
34 | from . import pkgconfig |
---|
35 | import re |
---|
36 | import subprocess |
---|
37 | import sys |
---|
38 | |
---|
39 | rtems_default_version = None |
---|
40 | rtems_filters = None |
---|
41 | rtems_long_commands = False |
---|
42 | |
---|
43 | windows = os.name == 'nt' or sys.platform in ['msys', 'cygwin'] |
---|
44 | |
---|
45 | def options(opt): |
---|
46 | opt.add_option('--rtems', |
---|
47 | default = None, |
---|
48 | dest = 'rtems_path', |
---|
49 | help = 'Path to an installed RTEMS (defaults to prefix).') |
---|
50 | opt.add_option('--rtems-tools', |
---|
51 | default = None, |
---|
52 | dest = 'rtems_tools', |
---|
53 | help = 'Path to RTEMS tools (defaults to path to installed RTEMS).') |
---|
54 | opt.add_option('--rtems-version', |
---|
55 | default = None, |
---|
56 | dest = 'rtems_version', |
---|
57 | help = 'RTEMS version (default is derived from prefix).') |
---|
58 | opt.add_option('--rtems-archs', |
---|
59 | default = 'all', |
---|
60 | dest = 'rtems_archs', |
---|
61 | help = 'List of RTEMS architectures to build.') |
---|
62 | opt.add_option('--rtems-bsps', |
---|
63 | default = 'all', |
---|
64 | dest = 'rtems_bsps', |
---|
65 | help = 'List of BSPs to build.') |
---|
66 | opt.add_option('--show-commands', |
---|
67 | action = 'store_true', |
---|
68 | default = False, |
---|
69 | dest = 'show_commands', |
---|
70 | help = 'Print the commands as strings.') |
---|
71 | |
---|
72 | def init(ctx, filters = None, version = None, long_commands = False, bsp_init = None): |
---|
73 | global rtems_filters |
---|
74 | global rtems_default_version |
---|
75 | global rtems_long_commands |
---|
76 | |
---|
77 | # |
---|
78 | # Set the RTEMS filter to the context. |
---|
79 | # |
---|
80 | rtems_filters = filters |
---|
81 | |
---|
82 | # |
---|
83 | # Set the default version, can be overridden. |
---|
84 | # |
---|
85 | rtems_default_version = version |
---|
86 | |
---|
87 | # |
---|
88 | # Set the long commands option. |
---|
89 | # |
---|
90 | rtems_long_commands = long_commands |
---|
91 | |
---|
92 | env = None |
---|
93 | contexts = [] |
---|
94 | try: |
---|
95 | import waflib.Options |
---|
96 | import waflib.ConfigSet |
---|
97 | |
---|
98 | # |
---|
99 | # Load the configuation set from the lock file. |
---|
100 | # |
---|
101 | env = waflib.ConfigSet.ConfigSet() |
---|
102 | env.load(waflib.Options.lockfile) |
---|
103 | |
---|
104 | # |
---|
105 | # Check the tools, architectures and bsps. |
---|
106 | # |
---|
107 | rtems_version, rtems_path, rtems_tools, archs, arch_bsps = \ |
---|
108 | check_options(ctx, |
---|
109 | env.options['prefix'], |
---|
110 | env.options['rtems_tools'], |
---|
111 | env.options['rtems_path'], |
---|
112 | env.options['rtems_version'], |
---|
113 | env.options['rtems_archs'], |
---|
114 | env.options['rtems_bsps']) |
---|
115 | |
---|
116 | # |
---|
117 | # Update the contexts for all the bsps. |
---|
118 | # |
---|
119 | from waflib.Build import BuildContext, CleanContext, \ |
---|
120 | InstallContext, UninstallContext |
---|
121 | for x in arch_bsps: |
---|
122 | for y in (BuildContext, CleanContext, InstallContext, UninstallContext): |
---|
123 | name = y.__name__.replace('Context','').lower() |
---|
124 | class context(y): |
---|
125 | cmd = name + '-' + x |
---|
126 | variant = x |
---|
127 | contexts += [context] |
---|
128 | |
---|
129 | # |
---|
130 | # Transform the command to per BSP commands. |
---|
131 | # |
---|
132 | commands = [] |
---|
133 | for cmd in waflib.Options.commands: |
---|
134 | if cmd in ['build', 'clean', 'install']: |
---|
135 | for x in arch_bsps: |
---|
136 | commands += [cmd + '-' + x] |
---|
137 | else: |
---|
138 | commands += [cmd] |
---|
139 | waflib.Options.commands = commands |
---|
140 | except: |
---|
141 | pass |
---|
142 | |
---|
143 | if bsp_init: |
---|
144 | bsp_init(ctx, env, contexts) |
---|
145 | |
---|
146 | def test_application(more = []): |
---|
147 | code = ['#include <rtems.h>'] |
---|
148 | code += more |
---|
149 | code += ['void Init(rtems_task_argument arg) { (void)arg; }'] |
---|
150 | code += ['#define CONFIGURE_APPLICATION_DOES_NOT_NEED_CLOCK_DRIVER'] |
---|
151 | code += ['#define CONFIGURE_MAXIMUM_TASKS 1'] |
---|
152 | code += ['#define CONFIGURE_RTEMS_INIT_TASKS_TABLE'] |
---|
153 | code += ['#define CONFIGURE_INIT'] |
---|
154 | code += ['#include <rtems/confdefs.h>'] |
---|
155 | return os.linesep.join(code) |
---|
156 | |
---|
157 | def configure(conf, bsp_configure = None): |
---|
158 | # |
---|
159 | # Check the environment for any flags. |
---|
160 | # |
---|
161 | for f in ['CC', 'CXX', 'AS', 'LD', 'AR', 'LINK_CC', 'LINK_CXX', |
---|
162 | 'CPPFLAGS', 'CFLAGS', 'CXXFLAGS', 'ASFLAGS', 'LINKFLAGS', 'LIB' |
---|
163 | 'WFLAGS', 'RFLAGS', 'MFLAGS', 'IFLAGS']: |
---|
164 | if f in os.environ: |
---|
165 | conf.msg('Environment variable set', f, color = 'RED') |
---|
166 | |
---|
167 | # |
---|
168 | # Handle the configurable commands options. |
---|
169 | # |
---|
170 | if conf.options.show_commands: |
---|
171 | show_commands = 'yes' |
---|
172 | else: |
---|
173 | show_commands = 'no' |
---|
174 | if rtems_long_commands and windows: |
---|
175 | long_commands = 'yes' |
---|
176 | else: |
---|
177 | long_commands = 'no' |
---|
178 | |
---|
179 | rtems_version, rtems_path, rtems_tools, archs, arch_bsps = \ |
---|
180 | check_options(conf, |
---|
181 | conf.options.prefix, |
---|
182 | conf.options.rtems_tools, |
---|
183 | conf.options.rtems_path, |
---|
184 | conf.options.rtems_version, |
---|
185 | conf.options.rtems_archs, |
---|
186 | conf.options.rtems_bsps) |
---|
187 | |
---|
188 | if rtems_tools is None: |
---|
189 | conf.fatal('RTEMS tools not found.') |
---|
190 | |
---|
191 | _log_header(conf) |
---|
192 | |
---|
193 | conf.msg('RTEMS Version', rtems_version, 'YELLOW') |
---|
194 | conf.msg('Architectures', ', '.join(archs), 'YELLOW') |
---|
195 | |
---|
196 | tools = {} |
---|
197 | env = conf.env.derive() |
---|
198 | |
---|
199 | for ab in arch_bsps: |
---|
200 | conf.setenv(ab, env) |
---|
201 | |
---|
202 | conf.msg('Board Support Package (BSP)', ab, 'YELLOW') |
---|
203 | |
---|
204 | # |
---|
205 | # Show and long commands support. |
---|
206 | # |
---|
207 | conf.env.SHOW_COMMANDS = show_commands |
---|
208 | conf.env.LONG_COMMANDS = long_commands |
---|
209 | |
---|
210 | conf.msg('Show commands', show_commands) |
---|
211 | conf.msg('Long commands', long_commands) |
---|
212 | |
---|
213 | arch = _arch_from_arch_bsp(ab) |
---|
214 | bsp = _bsp_from_arch_bsp(ab) |
---|
215 | |
---|
216 | conf.env.ARCH_BSP = '%s/%s' % (arch.split('-')[0], bsp) |
---|
217 | |
---|
218 | conf.env.RTEMS_PATH = rtems_path |
---|
219 | conf.env.RTEMS_VERSION = rtems_version |
---|
220 | conf.env.RTEMS_ARCH_BSP = ab |
---|
221 | conf.env.RTEMS_ARCH = arch.split('-')[0] |
---|
222 | conf.env.RTEMS_ARCH_RTEMS = arch |
---|
223 | conf.env.RTEMS_BSP = bsp |
---|
224 | |
---|
225 | tools = _find_tools(conf, arch, rtems_tools, tools) |
---|
226 | for t in tools[arch]: |
---|
227 | conf.env[t] = tools[arch][t] |
---|
228 | |
---|
229 | conf.load('gcc') |
---|
230 | conf.load('g++') |
---|
231 | conf.load('gas') |
---|
232 | |
---|
233 | # |
---|
234 | # Get the version of the tools being used. |
---|
235 | # |
---|
236 | rtems_cc = conf.env.CC[0] |
---|
237 | try: |
---|
238 | import waflib.Context |
---|
239 | out = conf.cmd_and_log([rtems_cc, '--version'], |
---|
240 | output = waflib.Context.STDOUT) |
---|
241 | except Exception as e: |
---|
242 | conf.fatal('CC version not found: %s' % (e.stderr)) |
---|
243 | # |
---|
244 | # First line is the version |
---|
245 | # |
---|
246 | vline = out.split('\n')[0] |
---|
247 | conf.msg('Compiler version (%s)' % (os.path.basename(rtems_cc)), |
---|
248 | ' '.join(vline.split()[2:])) |
---|
249 | |
---|
250 | flags = _load_flags(conf, ab, rtems_path) |
---|
251 | |
---|
252 | cflags = _filter_flags('cflags', flags['CFLAGS'], |
---|
253 | arch, rtems_path) |
---|
254 | ldflags = _filter_flags('ldflags', flags['LDFLAGS'], |
---|
255 | arch, rtems_path) |
---|
256 | |
---|
257 | conf.env.CFLAGS = cflags['cflags'] |
---|
258 | conf.env.CXXFLAGS = cflags['cflags'] |
---|
259 | conf.env.ASFLAGS = cflags['cflags'] |
---|
260 | conf.env.WFLAGS = cflags['warnings'] |
---|
261 | conf.env.RFLAGS = cflags['specs'] |
---|
262 | conf.env.MFLAGS = cflags['machines'] |
---|
263 | conf.env.IFLAGS = cflags['includes'] |
---|
264 | conf.env.LINKFLAGS = cflags['cflags'] + ldflags['ldflags'] |
---|
265 | conf.env.LIB = flags['LIB'] |
---|
266 | conf.env.LIBPATH = ldflags['libpath'] |
---|
267 | |
---|
268 | conf.env.RTRACE_WRAPPER_ST = '-W %s' |
---|
269 | |
---|
270 | # |
---|
271 | # Checks for various RTEMS features. |
---|
272 | # |
---|
273 | conf.check_cc(fragment = test_application(), |
---|
274 | execute = False, |
---|
275 | msg = 'Checking for a valid RTEMS BSP installation') |
---|
276 | load_cpuopts(conf) |
---|
277 | |
---|
278 | # |
---|
279 | # Add tweaks. |
---|
280 | # |
---|
281 | tweaks(conf, ab) |
---|
282 | |
---|
283 | # |
---|
284 | # If the user has supplied a BSP specific configure function |
---|
285 | # call it. |
---|
286 | # |
---|
287 | if bsp_configure: |
---|
288 | bsp_configure(conf, ab) |
---|
289 | |
---|
290 | conf.setenv('', env) |
---|
291 | |
---|
292 | conf.env.RTEMS_TOOLS = rtems_tools |
---|
293 | conf.env.ARCHS = archs |
---|
294 | conf.env.ARCH_BSPS = arch_bsps |
---|
295 | |
---|
296 | conf.env.SHOW_COMMANDS = show_commands |
---|
297 | conf.env.LONG_COMMANDS = long_commands |
---|
298 | |
---|
299 | def build(bld): |
---|
300 | if bld.env.SHOW_COMMANDS == 'yes': |
---|
301 | output_command_line() |
---|
302 | if bld.env.LONG_COMMANDS == 'yes': |
---|
303 | long_command_line() |
---|
304 | |
---|
305 | def load_cpuopts(conf): |
---|
306 | options = ['RTEMS_DEBUG', |
---|
307 | 'RTEMS_MULTIPROCESSING', |
---|
308 | 'RTEMS_NEWLIB', |
---|
309 | 'RTEMS_POSIX_API', |
---|
310 | 'RTEMS_SMP', |
---|
311 | 'RTEMS_NETWORKING'] |
---|
312 | for opt in options: |
---|
313 | enabled = check_cpuopt(conf, opt) |
---|
314 | if enabled: |
---|
315 | conf.env[opt] = 'Yes' |
---|
316 | else: |
---|
317 | conf.env[opt] = 'No' |
---|
318 | |
---|
319 | def check_cpuopt(conf, opt): |
---|
320 | code = ['#ifndef %s' % (opt)] |
---|
321 | code += [' #error %s is not defined' % (opt)] |
---|
322 | code += ['#endif'] |
---|
323 | code += ['#if %s' % (opt)] |
---|
324 | code += [' /* %s is true */' % (opt)] |
---|
325 | code += ['#else'] |
---|
326 | code += [' #error %s is false' % (opt)] |
---|
327 | code += ['#endif'] |
---|
328 | try: |
---|
329 | conf.check_cc(fragment = test_application(code), |
---|
330 | execute = False, |
---|
331 | msg = 'Checking for %s' % (opt)) |
---|
332 | except conf.errors.WafError: |
---|
333 | return False; |
---|
334 | return True |
---|
335 | |
---|
336 | def tweaks(conf, arch_bsp): |
---|
337 | # |
---|
338 | # Hack to work around NIOS2 naming. |
---|
339 | # |
---|
340 | if conf.env.RTEMS_ARCH in ['nios2']: |
---|
341 | conf.env.OBJCOPY_FLAGS = ['-O', 'elf32-littlenios2'] |
---|
342 | elif conf.env.RTEMS_ARCH in ['arm']: |
---|
343 | conf.env.OBJCOPY_FLAGS = ['-I', 'binary', '-O', 'elf32-littlearm'] |
---|
344 | else: |
---|
345 | conf.env.OBJCOPY_FLAGS = ['-O', 'elf32-' + conf.env.RTEMS_ARCH] |
---|
346 | |
---|
347 | # |
---|
348 | # Check for a i386 PC bsp. |
---|
349 | # |
---|
350 | if re.match('i386-.*-pc[3456]86', arch_bsp) is not None: |
---|
351 | conf.env.LINKFLAGS += ['-Wl,-Ttext,0x00100000'] |
---|
352 | |
---|
353 | if '-ffunction-sections' in conf.env.CFLAGS: |
---|
354 | conf.env.LINKFLAGS += ['-Wl,--gc-sections'] |
---|
355 | |
---|
356 | def check_options(ctx, prefix, rtems_tools, rtems_path, rtems_version, rtems_archs, rtems_bsps): |
---|
357 | # |
---|
358 | # Set defaults |
---|
359 | # |
---|
360 | if rtems_version is None: |
---|
361 | if rtems_default_version is None: |
---|
362 | m = re.compile('[^0-9.]*([0-9.]+)$').match(prefix) |
---|
363 | if m: |
---|
364 | rtems_version = m.group(1) |
---|
365 | else: |
---|
366 | ctx.fatal('RTEMS version cannot derived from prefix: ' + prefix) |
---|
367 | else: |
---|
368 | rtems_version = rtems_default_version |
---|
369 | if rtems_path is None: |
---|
370 | rtems_path = prefix |
---|
371 | if rtems_tools is None: |
---|
372 | rtems_tools = rtems_path |
---|
373 | |
---|
374 | # |
---|
375 | # Check the paths are valid. |
---|
376 | # |
---|
377 | if not os.path.exists(rtems_path): |
---|
378 | ctx.fatal('RTEMS path not found.') |
---|
379 | if os.path.exists(os.path.join(rtems_path, 'lib', 'pkgconfig')): |
---|
380 | rtems_config = None |
---|
381 | elif os.path.exists(os.path.join(rtems_path, 'rtems-config')): |
---|
382 | rtems_config = os.path.join(rtems_path, 'rtems-config') |
---|
383 | else: |
---|
384 | ctx.fatal('RTEMS path is not valid. No lib/pkgconfig or rtems-config found.') |
---|
385 | rtems_share_rtems_version = os.path.join(rtems_path, 'share', 'rtems' + rtems_version) |
---|
386 | if not os.path.exists(os.path.join(rtems_share_rtems_version)): |
---|
387 | ctx.fatal('RTEMS path is not valid, "%s" not found.' % (rtems_share_rtems_version)) |
---|
388 | |
---|
389 | # |
---|
390 | # We can more than one path to tools. This happens when testing different |
---|
391 | # versions. |
---|
392 | # |
---|
393 | rt = rtems_tools.split(',') |
---|
394 | tools = [] |
---|
395 | for path in rt: |
---|
396 | if not os.path.exists(path): |
---|
397 | ctx.fatal('RTEMS tools path not found: ' + path) |
---|
398 | if not os.path.exists(os.path.join(path, 'bin')): |
---|
399 | ctx.fatal('RTEMS tools path does not contain a \'bin\' directory: ' + path) |
---|
400 | tools += [os.path.join(path, 'bin')] |
---|
401 | |
---|
402 | # |
---|
403 | # Filter the tools. |
---|
404 | # |
---|
405 | tools = filter(ctx, 'tools', tools) |
---|
406 | |
---|
407 | # |
---|
408 | # Match the archs requested against the ones found. If the user |
---|
409 | # wants all (default) set all used. |
---|
410 | # |
---|
411 | if rtems_archs == 'all': |
---|
412 | archs = _find_installed_archs(rtems_config, rtems_path, rtems_version) |
---|
413 | else: |
---|
414 | archs = _check_archs(rtems_config, rtems_archs, rtems_path, rtems_version) |
---|
415 | |
---|
416 | # |
---|
417 | # Filter the architectures. |
---|
418 | # |
---|
419 | archs = filter(ctx, 'archs', archs) |
---|
420 | |
---|
421 | # |
---|
422 | # We some. |
---|
423 | # |
---|
424 | if len(archs) == 0: |
---|
425 | ctx.fatal('Could not find any architectures') |
---|
426 | |
---|
427 | # |
---|
428 | # Get the list of valid BSPs. This process filters the architectures |
---|
429 | # to those referenced by the BSPs. |
---|
430 | # |
---|
431 | if rtems_bsps == 'all': |
---|
432 | arch_bsps = _find_installed_arch_bsps(rtems_config, rtems_path, archs, rtems_version) |
---|
433 | else: |
---|
434 | arch_bsps = _check_arch_bsps(rtems_bsps, rtems_config, rtems_path, archs, rtems_version) |
---|
435 | |
---|
436 | if len(arch_bsps) == 0: |
---|
437 | ctx.fatal('No valid arch/bsps found') |
---|
438 | |
---|
439 | # |
---|
440 | # Filter the bsps. |
---|
441 | # |
---|
442 | arch_bsps = filter(ctx, 'bsps', arch_bsps) |
---|
443 | |
---|
444 | return rtems_version, rtems_path, tools, archs, arch_bsps |
---|
445 | |
---|
446 | def check_env(ctx, var): |
---|
447 | if var in ctx.env and len(ctx.env[var]) != 0: |
---|
448 | return True |
---|
449 | return False |
---|
450 | |
---|
451 | def check(ctx, option): |
---|
452 | if option in ctx.env: |
---|
453 | return ctx.env[option] == 'Yes' |
---|
454 | return False |
---|
455 | |
---|
456 | def check_debug(ctx): |
---|
457 | return check(ctx, 'RTEMS_DEBUG') |
---|
458 | |
---|
459 | def check_multiprocessing(ctx): |
---|
460 | return check(ctx, 'RTEMS_MULTIPROCESSING') |
---|
461 | |
---|
462 | def check_newlib(ctx): |
---|
463 | return check(ctx, 'RTEMS_NEWLIB') |
---|
464 | |
---|
465 | def check_posix(ctx): |
---|
466 | return check(ctx, 'RTEMS_POSIX_API') |
---|
467 | |
---|
468 | def check_smp(ctx): |
---|
469 | return check(ctx, 'RTEMS_SMP') |
---|
470 | |
---|
471 | def check_networking(ctx): |
---|
472 | return check(ctx, 'RTEMS_NETWORKING') |
---|
473 | |
---|
474 | def arch(arch_bsp): |
---|
475 | """ Given an arch/bsp return the architecture.""" |
---|
476 | return _arch_from_arch_bsp(arch_bsp).split('-')[0] |
---|
477 | |
---|
478 | def bsp(arch_bsp): |
---|
479 | """ Given an arch/bsp return the BSP.""" |
---|
480 | return _bsp_from_arch_bsp(arch_bsp) |
---|
481 | |
---|
482 | def arch_bsps(ctx): |
---|
483 | """ Return the list of arch/bsps we are building.""" |
---|
484 | return ctx.env.ARCH_BSPS |
---|
485 | |
---|
486 | def arch_bsp_env(ctx, arch_bsp): |
---|
487 | return ctx.env_of_name(arch_bsp).derive() |
---|
488 | |
---|
489 | def filter(ctx, filter, items): |
---|
490 | if rtems_filters is None: |
---|
491 | return items |
---|
492 | if type(rtems_filters) is not dict: |
---|
493 | ctx.fatal("Invalid RTEMS filter type, " \ |
---|
494 | "ie { 'tools': { 'in': [], 'out': [] }, 'arch': {}, 'bsps': {} }") |
---|
495 | if filter not in rtems_filters: |
---|
496 | return items |
---|
497 | items_in = [] |
---|
498 | items_out = [] |
---|
499 | if 'in' in rtems_filters[filter]: |
---|
500 | items_in = copy.copy(rtems_filters[filter]['in']) |
---|
501 | if 'out' in rtems_filters[filter]: |
---|
502 | items_out = copy.copy(rtems_filters[filter]['out']) |
---|
503 | filtered_items = [] |
---|
504 | for i in items: |
---|
505 | item = i |
---|
506 | ab = '%s/%s' % (arch(item), bsp(item)) |
---|
507 | for inre in items_in: |
---|
508 | if re.compile(inre).match(ab): |
---|
509 | items_in.remove(inre) |
---|
510 | filtered_items += [item] |
---|
511 | item = None |
---|
512 | break |
---|
513 | if item is not None: |
---|
514 | for outre in items_out: |
---|
515 | if re.compile(outre).match(ab): |
---|
516 | item = None |
---|
517 | break |
---|
518 | if item is not None: |
---|
519 | filtered_items += [item] |
---|
520 | if len(items_in) != 0: |
---|
521 | ctx.fatal('Following %s not found: %s' % (filter, ', '.join(items_in))) |
---|
522 | return sorted(filtered_items) |
---|
523 | |
---|
524 | def arch_rtems_version(version, arch): |
---|
525 | """ Return the RTEMS architecture path, ie sparc-rtems4.11.""" |
---|
526 | return '%s-rtems%s' % (arch, version) |
---|
527 | |
---|
528 | def arch_bsp_path(version, arch_bsp): |
---|
529 | """ Return the BSP path.""" |
---|
530 | return '%s/%s' % (arch_rtems_version(version, arch(arch_bsp)), bsp(arch_bsp)) |
---|
531 | |
---|
532 | def arch_bsp_include_path(version, arch_bsp): |
---|
533 | """ Return the BSP include path.""" |
---|
534 | return '%s/lib/include' % (arch_bsp_path(version, arch_bsp)) |
---|
535 | |
---|
536 | def arch_bsp_lib_path(version, arch_bsp): |
---|
537 | """ Return the BSP library path. """ |
---|
538 | return '%s/lib' % (arch_bsp_path(version, arch_bsp)) |
---|
539 | |
---|
540 | def library_path(library, cc, cflags): |
---|
541 | cmd = cc + cflags + ['-print-file-name=%s' % library] |
---|
542 | a = subprocess.check_output(cmd) |
---|
543 | lib = os.path.abspath(a.strip()) |
---|
544 | if os.path.exists(lib): |
---|
545 | return os.path.dirname(lib) |
---|
546 | return None |
---|
547 | |
---|
548 | def root_filesystem(bld, name, files, tar, obj): |
---|
549 | tar_rule = 'tar -cf ${TGT} --format=ustar -C ../.. $(echo "${SRC}" | sed -e \'s/\.\.\/\.\.\///g\')' |
---|
550 | if windows: |
---|
551 | tar_rule = 'sh -c "%s"' % (tar_rule) |
---|
552 | bld(name = name + '_tar', |
---|
553 | target = tar, |
---|
554 | source = files, |
---|
555 | rule = tar_rule) |
---|
556 | bld.objects(name = name, |
---|
557 | target = obj, |
---|
558 | source = tar, |
---|
559 | rule = '${OBJCOPY} -I binary -B ${RTEMS_ARCH} ${OBJCOPY_FLAGS} ${SRC} ${TGT}') |
---|
560 | |
---|
561 | def clone_tasks(bld): |
---|
562 | if bld.cmd == 'build': |
---|
563 | for obj in bld.all_task_gen[:]: |
---|
564 | for x in arch_bsp: |
---|
565 | cloned_obj = obj.clone(x) |
---|
566 | kind = Options.options.build_kind |
---|
567 | if kind.find(x) < 0: |
---|
568 | cloned_obj.posted = True |
---|
569 | obj.posted = True |
---|
570 | |
---|
571 | # |
---|
572 | # From the demos. Use this to get the command to cut+paste to play. |
---|
573 | # |
---|
574 | def output_command_line(): |
---|
575 | # first, display strings, people like them |
---|
576 | from waflib import Utils, Logs |
---|
577 | from waflib.Context import Context |
---|
578 | def exec_command(self, cmd, **kw): |
---|
579 | subprocess = Utils.subprocess |
---|
580 | kw['shell'] = isinstance(cmd, str) |
---|
581 | if isinstance(cmd, str): |
---|
582 | Logs.info('%s' % cmd) |
---|
583 | else: |
---|
584 | cmdstr = ' '.join(cmd) |
---|
585 | Logs.info('(%d) %s' % (len(cmdstr), cmdstr)) # here is the change |
---|
586 | if not isinstance(kw['cwd'], str): |
---|
587 | kw['cwd'] = str(kw['cwd']) |
---|
588 | Logs.debug('runner_env: kw=%s' % kw) |
---|
589 | try: |
---|
590 | if self.logger: |
---|
591 | self.logger.info(cmd) |
---|
592 | kw['stdout'] = kw['stderr'] = subprocess.PIPE |
---|
593 | p = subprocess.Popen(cmd, **kw) |
---|
594 | (out, err) = p.communicate() |
---|
595 | if out: |
---|
596 | self.logger.debug('out: %s' % out.decode(sys.stdout.encoding or 'iso8859-1')) |
---|
597 | if err: |
---|
598 | self.logger.error('err: %s' % err.decode(sys.stdout.encoding or 'iso8859-1')) |
---|
599 | return p.returncode |
---|
600 | else: |
---|
601 | p = subprocess.Popen(cmd, **kw) |
---|
602 | return p.wait() |
---|
603 | except OSError: |
---|
604 | return -1 |
---|
605 | Context.exec_command = exec_command |
---|
606 | |
---|
607 | # Change the outputs for tasks too |
---|
608 | from waflib.Task import Task |
---|
609 | def display(self): |
---|
610 | return '' # no output on empty strings |
---|
611 | |
---|
612 | Task.__str__ = display |
---|
613 | |
---|
614 | # |
---|
615 | # From the extras. Use this to support long command lines. |
---|
616 | # |
---|
617 | def long_command_line(): |
---|
618 | def exec_command(self, cmd, **kw): |
---|
619 | # workaround for command line length limit: |
---|
620 | # http://support.microsoft.com/kb/830473 |
---|
621 | import tempfile |
---|
622 | tmp = None |
---|
623 | try: |
---|
624 | if not isinstance(cmd, str) and len(str(cmd)) > 8192: |
---|
625 | (fd, tmp) = tempfile.mkstemp(dir=self.generator.bld.bldnode.abspath()) |
---|
626 | flat = ['"%s"' % x.replace('\\', '\\\\').replace('"', '\\"') for x in cmd[1:]] |
---|
627 | try: |
---|
628 | os.write(fd, ' '.join(flat).encode()) |
---|
629 | finally: |
---|
630 | if tmp: |
---|
631 | os.close(fd) |
---|
632 | # Line may be very long: |
---|
633 | # Logs.debug('runner:' + ' '.join(flat)) |
---|
634 | cmd = [cmd[0], '@' + tmp] |
---|
635 | ret = super(self.__class__, self).exec_command(cmd, **kw) |
---|
636 | finally: |
---|
637 | if tmp: |
---|
638 | os.remove(tmp) |
---|
639 | return ret |
---|
640 | for k in 'c cxx cprogram cxxprogram cshlib cxxshlib cstlib cxxstlib'.split(): |
---|
641 | cls = Task.classes.get(k) |
---|
642 | if cls: |
---|
643 | derived_class = type(k, (cls,), {}) |
---|
644 | derived_class.exec_command = exec_command |
---|
645 | if hasattr(cls, 'hcode'): |
---|
646 | derived_class.hcode = cls.hcode |
---|
647 | |
---|
648 | def _find_tools(conf, arch, paths, tools): |
---|
649 | if arch not in tools: |
---|
650 | arch_tools = {} |
---|
651 | arch_tools['CC'] = conf.find_program([arch + '-gcc'], path_list = paths) |
---|
652 | arch_tools['CXX'] = conf.find_program([arch + '-g++'], path_list = paths) |
---|
653 | arch_tools['LINK_CC'] = arch_tools['CC'] |
---|
654 | arch_tools['LINK_CXX'] = arch_tools['CXX'] |
---|
655 | arch_tools['AS'] = conf.find_program([arch + '-gcc'], path_list = paths) |
---|
656 | arch_tools['LD'] = conf.find_program([arch + '-ld'], path_list = paths) |
---|
657 | arch_tools['AR'] = conf.find_program([arch + '-ar'], path_list = paths) |
---|
658 | arch_tools['NM'] = conf.find_program([arch + '-nm'], path_list = paths) |
---|
659 | arch_tools['OBJDUMP'] = conf.find_program([arch + '-objdump'], path_list = paths) |
---|
660 | arch_tools['OBJCOPY'] = conf.find_program([arch + '-objcopy'], path_list = paths) |
---|
661 | arch_tools['READELF'] = conf.find_program([arch + '-readelf'], path_list = paths) |
---|
662 | arch_tools['STRIP'] = conf.find_program([arch + '-strip'], path_list = paths) |
---|
663 | arch_tools['RTEMS_LD'] = conf.find_program(['rtems-ld'], path_list = paths, |
---|
664 | mandatory = False) |
---|
665 | arch_tools['RTEMS_TLD'] = conf.find_program(['rtems-tld'], path_list = paths, |
---|
666 | mandatory = False) |
---|
667 | arch_tools['RTEMS_BIN2C'] = conf.find_program(['rtems-bin2c'], path_list = paths, |
---|
668 | mandatory = False) |
---|
669 | arch_tools['TAR'] = conf.find_program(['tar'], mandatory = False) |
---|
670 | tools[arch] = arch_tools |
---|
671 | return tools |
---|
672 | |
---|
673 | def _find_installed_archs(config, path, version): |
---|
674 | archs = [] |
---|
675 | if config is None: |
---|
676 | for d in os.listdir(path): |
---|
677 | if d.endswith('-rtems' + version): |
---|
678 | archs += [d] |
---|
679 | else: |
---|
680 | a = subprocess.check_output([config, '--list-format', '"%(arch)s"']) |
---|
681 | a = a[:-1].replace('"', '') |
---|
682 | archs = set(a.split()) |
---|
683 | archs = ['%s-rtems%s' % (x, version) for x in archs] |
---|
684 | archs.sort() |
---|
685 | return archs |
---|
686 | |
---|
687 | def _check_archs(config, req, path, version): |
---|
688 | installed = _find_installed_archs(config, path, version) |
---|
689 | archs = [] |
---|
690 | for a in req.split(','): |
---|
691 | arch = a + '-rtems' + version |
---|
692 | if arch in installed: |
---|
693 | archs += [arch] |
---|
694 | archs.sort() |
---|
695 | return archs |
---|
696 | |
---|
697 | def _find_installed_arch_bsps(config, path, archs, version): |
---|
698 | arch_bsps = [] |
---|
699 | if config is None: |
---|
700 | for f in os.listdir(_pkgconfig_path(path)): |
---|
701 | if f.endswith('.pc'): |
---|
702 | if _arch_from_arch_bsp(f[:-3]) in archs: |
---|
703 | arch_bsps += [f[:-3]] |
---|
704 | else: |
---|
705 | ab = subprocess.check_output([config, '--list-format']) |
---|
706 | ab = ab[:-1].replace('"', '') |
---|
707 | ab = ab.replace('/', '-rtems%s-' % (version)) |
---|
708 | arch_bsps = [x for x in set(ab.split())] |
---|
709 | arch_bsps.sort() |
---|
710 | return arch_bsps |
---|
711 | |
---|
712 | def _check_arch_bsps(req, config, path, archs, version): |
---|
713 | archs_bsps = [] |
---|
714 | for ab in req.split(','): |
---|
715 | abl = ab.split('/') |
---|
716 | if len(abl) != 2: |
---|
717 | return [] |
---|
718 | found = False |
---|
719 | for arch in archs: |
---|
720 | a = '%s-rtems%s' % (abl[0], version) |
---|
721 | if a == arch: |
---|
722 | found = True |
---|
723 | break |
---|
724 | if not found: |
---|
725 | return [] |
---|
726 | archs_bsps += ['%s-%s' % (a, abl[1])] |
---|
727 | if len(archs_bsps) == 0: |
---|
728 | return [] |
---|
729 | installed = _find_installed_arch_bsps(config, path, archs, version) |
---|
730 | bsps = [] |
---|
731 | for b in archs_bsps: |
---|
732 | if b in installed: |
---|
733 | bsps += [b] |
---|
734 | bsps.sort() |
---|
735 | return bsps |
---|
736 | |
---|
737 | def _arch_from_arch_bsp(arch_bsp): |
---|
738 | return '-'.join(arch_bsp.split('-')[:2]) |
---|
739 | |
---|
740 | def _bsp_from_arch_bsp(arch_bsp): |
---|
741 | return '-'.join(arch_bsp.split('-')[2:]) |
---|
742 | |
---|
743 | def _pkgconfig_path(path): |
---|
744 | return os.path.join(path, 'lib', 'pkgconfig') |
---|
745 | |
---|
746 | def _load_flags(conf, arch_bsp, path): |
---|
747 | if not os.path.exists(path): |
---|
748 | ctx.fatal('RTEMS path not found.') |
---|
749 | if os.path.exists(_pkgconfig_path(path)): |
---|
750 | pc = os.path.join(_pkgconfig_path(path), arch_bsp + '.pc') |
---|
751 | conf.to_log('Opening and load pkgconfig: ' + pc) |
---|
752 | pkg = pkgconfig.package(pc) |
---|
753 | config = None |
---|
754 | elif os.path.exists(os.path.join(path, 'rtems-config')): |
---|
755 | config = os.path.join(path, 'rtems-config') |
---|
756 | pkg = None |
---|
757 | flags = {} |
---|
758 | _log_header(conf) |
---|
759 | flags['CFLAGS'] = _load_flags_set('CFLAGS', arch_bsp, conf, config, pkg) |
---|
760 | flags['LDFLAGS'] = _load_flags_set('LDFLAGS', arch_bsp, conf, config, pkg) |
---|
761 | flags['LIB'] = _load_flags_set('LIB', arch_bsp, conf, config, pkg) |
---|
762 | return flags |
---|
763 | |
---|
764 | def _load_flags_set(flags, arch_bsp, conf, config, pkg): |
---|
765 | conf.to_log('%s ->' % flags) |
---|
766 | if pkg is not None: |
---|
767 | flagstr = '' |
---|
768 | try: |
---|
769 | flagstr = pkg.get(flags) |
---|
770 | except pkgconfig.error as e: |
---|
771 | conf.to_log('pkconfig warning: ' + e.msg) |
---|
772 | conf.to_log(' ' + flagstr) |
---|
773 | else: |
---|
774 | flags_map = { 'CFLAGS': '--cflags', |
---|
775 | 'LDFLAGS': '--ldflags', |
---|
776 | 'LIB': '--libs' } |
---|
777 | ab = arch_bsp.split('-') |
---|
778 | #conf.check_cfg(path = config, |
---|
779 | # package = '', |
---|
780 | # uselib_store = 'rtems', |
---|
781 | # args = '--bsp %s/%s %s' % (ab[0], ab[2], flags_map[flags])) |
---|
782 | #print conf.env |
---|
783 | #print '%r' % conf |
---|
784 | #flagstr = '-l -c' |
---|
785 | flagstr = subprocess.check_output([config, '--bsp', '%s/%s' % (ab[0], ab[2]), flags_map[flags]]) |
---|
786 | #print flags, ">>>>", flagstr |
---|
787 | if flags == 'CFLAGS': |
---|
788 | flagstr += ' -DWAF_BUILD=1' |
---|
789 | if flags == 'LIB': |
---|
790 | flagstr = 'rtemscpu rtemsbsp c rtemscpu rtemsbsp' |
---|
791 | return flagstr.split() |
---|
792 | |
---|
793 | def _filter_flags(label, flags, arch, rtems_path): |
---|
794 | |
---|
795 | flag_groups = \ |
---|
796 | [ { 'key': 'warnings', 'path': False, 'flags': { '-W': 1 }, 'cflags': False, 'lflags': False }, |
---|
797 | { 'key': 'includes', 'path': True, 'flags': { '-I': 1, '-isystem': 2, '-sysroot': 2 } }, |
---|
798 | { 'key': 'libpath', 'path': True, 'flags': { '-L': 1 } }, |
---|
799 | { 'key': 'machines', 'path': True, 'flags': { '-O': 1, '-m': 1, '-f': 1, '-G':1, '-E':1 } }, |
---|
800 | { 'key': 'specs', 'path': True, 'flags': { '-q': 1, '-B': 2, '--specs': 2 } } ] |
---|
801 | |
---|
802 | flags = _strip_cflags(flags) |
---|
803 | |
---|
804 | _flags = { label: [] } |
---|
805 | for fg in flag_groups: |
---|
806 | _flags[fg['key']] = [] |
---|
807 | |
---|
808 | iflags = iter(flags) |
---|
809 | for opt in iflags: |
---|
810 | in_label = True |
---|
811 | opts = [] |
---|
812 | for fg in flag_groups: |
---|
813 | key = fg['key'] |
---|
814 | for flag in fg['flags']: |
---|
815 | if opt.startswith(flag): |
---|
816 | opt_count = fg['flags'][flag] |
---|
817 | if opt_count > 1: |
---|
818 | if opt != flag: |
---|
819 | opt_count -= 1 |
---|
820 | if fg['path'] and arch in opt: |
---|
821 | opt = '%s%s/%s' % (flag, rtems_path, |
---|
822 | opt[opt.find(arch):]) |
---|
823 | opts += [opt] |
---|
824 | for c in range(1, opt_count): |
---|
825 | opt = next(iflags) |
---|
826 | if fg['path'] and arch in opt: |
---|
827 | opt = '%s%s/%s' % (f, rtems_path, |
---|
828 | opt[opt.find(arch):]) |
---|
829 | opts += [opt] |
---|
830 | _flags[key] += opts |
---|
831 | if label in fg and not fg[label]: |
---|
832 | in_label = False |
---|
833 | break |
---|
834 | if in_label: |
---|
835 | _flags[label] += opts |
---|
836 | return _flags |
---|
837 | |
---|
838 | def _strip_cflags(cflags): |
---|
839 | _cflags = [] |
---|
840 | for o in cflags: |
---|
841 | if o.startswith('-O'): |
---|
842 | pass |
---|
843 | elif o.startswith('-g'): |
---|
844 | pass |
---|
845 | else: |
---|
846 | _cflags += [o] |
---|
847 | return _cflags |
---|
848 | |
---|
849 | def _log_header(conf): |
---|
850 | conf.to_log('-----------------------------------------') |
---|
851 | |
---|
852 | from waflib import Task |
---|
853 | from waflib import TaskGen |
---|
854 | from waflib import Utils |
---|
855 | from waflib import Node |
---|
856 | from waflib.Tools.ccroot import link_task, USELIB_VARS |
---|
857 | |
---|
858 | USELIB_VARS['rap'] = set(['RTEMS_LINKFLAGS']) |
---|
859 | USELIB_VARS['rtrace'] = set(['RTRACE_FLAGS', 'RTRACE_CFG', 'RTRACE_WRAPPER', 'RTRACE_LINKCMDS']) |
---|
860 | |
---|
861 | class rap(link_task): |
---|
862 | "Link object files into a RTEMS application" |
---|
863 | run_str = '${RTEMS_LD} ${RTEMS_LINKFLAGS} --cc ${CC} ${SRC} -o ${TGT[0].abspath()} ${STLIB_MARKER} ${STLIBPATH_ST:STLIBPATH} ${STLIB_ST:STLIB} ${LIBPATH_ST:LIBPATH} ${LIB_ST:LIB}' |
---|
864 | ext_out = ['.rap'] |
---|
865 | vars = ['RTEMS_LINKFLAGS', 'LINKDEPS'] |
---|
866 | inst_to = '${BINDIR}' |
---|
867 | |
---|
868 | class rtrace(link_task): |
---|
869 | "Link object files into a RTEMS trace application" |
---|
870 | run_str = '${RTEMS_TLD} ${RTACE_FLAGS} ${RTRACE_WRAPPER_ST:RTRACE_WRAPPER} -C ${RTRACE_CFG} -r ${RTEMS_PATH} -B ${ARCH_BSP} -c ${CC} -l ${CC} -- ${SRC} ${LINKFLAGS} ${RTRACE_LINKFLAGS} -o ${TGT[0].abspath()} ${STLIB_MARKER} ${STLIBPATH_ST:STLIBPATH} ${STLIB_ST:STLIB} ${LIBPATH_ST:LIBPATH} ${LIB_ST:LIB}' |
---|
871 | ext_out = ['.texe'] |
---|
872 | vars = ['RTRACE_FLAGS', 'RTRACE_CFG', 'RTRACE_WRAPER', 'RTRACE_LINKFLAGS', 'LINKDEPS'] |
---|
873 | inst_to = '${BINDIR}' |
---|
874 | color = 'PINK' |
---|