Upstream version 9.38.207.0
[platform/framework/web/crosswalk.git] / src / native_client / SConstruct
1 #! -*- python -*-
2 # Copyright (c) 2012 The Native Client Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
5
6 import atexit
7 import json
8 import os
9 import platform
10 import re
11 import subprocess
12 import sys
13 import zlib
14 sys.path.append("./common")
15 sys.path.append('../third_party')
16
17 from SCons.Errors import UserError
18 from SCons.Script import GetBuildFailures
19
20 import SCons.Warnings
21 import SCons.Util
22
23 SCons.Warnings.warningAsException()
24
25 sys.path.append("tools")
26 import command_tester
27 import test_lib
28
29 import pynacl.platform
30
31 # turning garbage collection off reduces startup time by 10%
32 import gc
33 gc.disable()
34
35 # REPORT
36 CMD_COUNTER = {}
37 ENV_COUNTER = {}
38 def PrintFinalReport():
39   """This function is run just before scons exits and dumps various reports.
40   """
41   # Note, these global declarations are not strictly necessary
42   global pre_base_env
43   global CMD_COUNTER
44   global ENV_COUNTER
45
46   if pre_base_env.Bit('target_stats'):
47     print
48     print '*' * 70
49     print 'COMMAND EXECUTION REPORT'
50     print '*' * 70
51     for k in sorted(CMD_COUNTER.keys()):
52       print "%4d %s" % (CMD_COUNTER[k], k)
53
54     print
55     print '*' * 70
56     print 'ENVIRONMENT USAGE REPORT'
57     print '*' * 70
58     for k in sorted(ENV_COUNTER.keys()):
59       print "%4d  %s" % (ENV_COUNTER[k], k)
60
61   failures = []
62   for failure in GetBuildFailures():
63     for node in Flatten(failure.node):
64       failures.append({
65           # If this wasn't a test, "GetTestName" will return raw_name.
66           'test_name': GetTestName(node),
67           'raw_name': str(node.path),
68           'errstr': failure.errstr
69       })
70
71   json_path = ARGUMENTS.get('json_build_results_output_file')
72   if json_path:
73     with open(json_path, 'w') as f:
74       json.dump(failures, f, sort_keys=True, indent=2)
75
76   if not failures:
77     return
78
79   print
80   print '*' * 70
81   print 'ERROR REPORT: %d failures' % len(failures)
82   print '*' * 70
83   print
84   for failure in failures:
85     test_name = failure['test_name']
86     if test_name != failure['raw_name']:
87       test_name = '%s (%s)' % (test_name, failure['raw_name'])
88     print "%s failed: %s\n" % (test_name, failure['errstr'])
89
90
91 def VerboseConfigInfo(env):
92   "Should we print verbose config information useful for bug reports"
93   if '--help' in sys.argv: return False
94   if env.Bit('prebuilt') or env.Bit('built_elsewhere'): return False
95   return env.Bit('sysinfo')
96
97
98 # SANITY CHECKS
99
100 # NOTE BitFromArgument(...) implicitly defines additional ACCEPTABLE_ARGUMENTS.
101 ACCEPTABLE_ARGUMENTS = set([
102     # TODO: add comments what these mean
103     # TODO: check which ones are obsolete
104     ####  ASCII SORTED ####
105     # Use a destination directory other than the default "scons-out".
106     'DESTINATION_ROOT',
107     'MODE',
108     'SILENT',
109     # Limit bandwidth of browser tester
110     'browser_tester_bw',
111     # Location to download Chromium binaries to and/or read them from.
112     'chrome_binaries_dir',
113     # used for chrome_browser_tests: path to the browser
114     'chrome_browser_path',
115     # A comma-separated list of test names to disable by excluding the
116     # tests from a test suite.  For example, 'small_tests
117     # disable_tests=run_hello_world_test' will run small_tests without
118     # including hello_world_test.  Note that if a test listed here
119     # does not exist you will not get an error or a warning.
120     'disable_tests',
121     # used for chrome_browser_tests: path to a pre-built browser plugin.
122     'force_ppapi_plugin',
123     # force emulator use by tests
124     'force_emulator',
125     # force sel_ldr use by tests
126     'force_sel_ldr',
127     # force irt image used by tests
128     'force_irt',
129     # generate_ninja=FILE enables a Ninja backend for SCons.  This writes a
130     # .ninja build file to FILE describing all of SCons' build targets.
131     'generate_ninja',
132     # Path to a JSON file for machine-readable output.
133     'json_build_results_output_file',
134     # Replacement memcheck command for overriding the DEPS-in memcheck
135     # script.  May have commas to separate separate shell args.  There
136     # is no quoting, so this implies that this mechanism will fail if
137     # the args actually need to have commas.  See
138     # http://code.google.com/p/nativeclient/issues/detail?id=3158 for
139     # the discussion of why this argument is needed.
140     'memcheck_command',
141     # If the replacement memcheck command only works for trusted code,
142     # set memcheck_trusted_only to non-zero.
143     'memcheck_trusted_only',
144     # When building with MSan, this can be set to values 0 (fastest, least
145     # useful reports) through 2 (slowest, most useful reports). Default is 1.
146     'msan_track_origins',
147     # colon-separated list of linker flags, e.g. "-lfoo:-Wl,-u,bar".
148     'nacl_linkflags',
149     # colon-separated list of pnacl bcld flags, e.g. "-lfoo:-Wl,-u,bar".
150     # Not using nacl_linkflags since that gets clobbered in some tests.
151     'pnacl_bcldflags',
152     'platform',
153     # Run tests under this tool (e.g. valgrind, tsan, strace, etc).
154     # If the tool has options, pass them after comma: 'tool,--opt1,--opt2'.
155     # NB: no way to use tools the names or the args of
156     # which contains a comma.
157     'run_under',
158     # More args for the tool.
159     'run_under_extra_args',
160     # Multiply timeout values by this number.
161     'scale_timeout',
162     # test_wrapper specifies a wrapper program such as
163     # tools/run_test_via_ssh.py, which runs tests on a remote host
164     # using rsync and SSH.  Example usage:
165     #   ./scons run_hello_world_test platform=arm force_emulator= \
166     #     test_wrapper="./tools/run_test_via_ssh.py --host=armbox --subdir=tmp"
167     'test_wrapper',
168     # Replacement tsan command for overriding the DEPS-in tsan
169     # script.  May have commas to separate separate shell args.  There
170     # is no quoting, so this implies that this mechanism will fail if
171     # the args actually need to have commas.  See
172     # http://code.google.com/p/nativeclient/issues/detail?id=3158 for
173     # the discussion of why this argument is needed.
174     'tsan_command',
175     # Run browser tests under this tool. See
176     # tools/browser_tester/browsertester/browserlauncher.py for tool names.
177     'browser_test_tool',
178     # activates buildbot-specific presets
179     'buildbot',
180     # Where to install header files for public consumption.
181     'includedir',
182     # Where to install libraries for public consumption.
183     'libdir',
184     # Where to install trusted-code binaries for public (SDK) consumption.
185     'bindir',
186     # Where a Breakpad build output directory is for optional Breakpad testing.
187     'breakpad_tools_dir',
188     # Allows overriding of the nacl newlib toolchain directory.
189     'nacl_newlib_dir',
190     # Allows override of the nacl glibc toolchain directory.
191     'nacl_glibc_dir',
192     # Allows override of the pnacl newlib toolchain directory.
193     'pnacl_newlib_dir',
194     # Allows overriding the version number in the toolchain's
195     # FEATURE_VERSION file.  This is used for PNaCl ABI compatibility
196     # testing.
197     'toolchain_feature_version',
198   ])
199
200
201 # Overly general to provide compatibility with existing build bots, etc.
202 # In the future it might be worth restricting the values that are accepted.
203 _TRUE_STRINGS = set(['1', 'true', 'yes'])
204 _FALSE_STRINGS = set(['0', 'false', 'no'])
205
206
207 # Converts a string representing a Boolean value, of some sort, into an actual
208 # Boolean value. Python's built in type coercion does not work because
209 # bool('False') == True
210 def StringValueToBoolean(value):
211   # ExpandArguments may stick non-string values in ARGUMENTS. Be accommodating.
212   if isinstance(value, bool):
213     return value
214
215   if not isinstance(value, basestring):
216     raise Exception("Expecting a string but got a %s" % repr(type(value)))
217
218   if value.lower() in _TRUE_STRINGS:
219     return True
220   elif value.lower() in _FALSE_STRINGS:
221     return False
222   else:
223     raise Exception("Cannot convert '%s' to a Boolean value" % value)
224
225
226 def GetBinaryArgumentValue(arg_name, default):
227   if not isinstance(default, bool):
228     raise Exception("Default value for '%s' must be a Boolean" % arg_name)
229   if arg_name not in ARGUMENTS:
230     return default
231   return StringValueToBoolean(ARGUMENTS[arg_name])
232
233
234 # name is the name of the bit
235 # arg_name is the name of the command-line argument, if it differs from the bit
236 def BitFromArgument(env, name, default, desc, arg_name=None):
237   # In most cases the bit name matches the argument name
238   if arg_name is None:
239     arg_name = name
240
241   DeclareBit(name, desc)
242   assert arg_name not in ACCEPTABLE_ARGUMENTS, repr(arg_name)
243   ACCEPTABLE_ARGUMENTS.add(arg_name)
244
245   if GetBinaryArgumentValue(arg_name, default):
246     env.SetBits(name)
247   else:
248     env.ClearBits(name)
249
250
251 # SetUpArgumentBits declares binary command-line arguments and converts them to
252 # bits. For example, one of the existing declarations would result in the
253 # argument "bitcode=1" causing env.Bit('bitcode') to evaluate to true.
254 # NOTE Command-line arguments are a SCons-ism that is separate from
255 # command-line options.  Options are prefixed by "-" or "--" whereas arguments
256 # are not.  The function SetBitFromOption can be used for options.
257 # NOTE This function must be called before the bits are used
258 # NOTE This function must be called after all modifications of ARGUMENTS have
259 # been performed. See: ExpandArguments
260 def SetUpArgumentBits(env):
261   BitFromArgument(env, 'bitcode', default=False,
262     desc='We are building bitcode')
263
264   BitFromArgument(env, 'translate_fast', default=False,
265     desc='When using pnacl TC (bitcode=1) use accelerated translation step')
266
267   BitFromArgument(env, 'built_elsewhere', default=False,
268     desc='The programs have already been built by another system')
269
270   BitFromArgument(env, 'skip_trusted_tests', default=False,
271     desc='Only run untrusted tests - useful for translator testing'
272       ' (also skips tests of the IRT itself')
273
274   BitFromArgument(env, 'nacl_pic', default=False,
275     desc='generate position indepent code for (P)NaCl modules')
276
277   BitFromArgument(env, 'nacl_static_link', default=not env.Bit('nacl_glibc'),
278     desc='Whether to use static linking instead of dynamic linking '
279       'for building NaCl executables during tests. '
280       'For nacl-newlib, the default is 1 (static linking). '
281       'For nacl-glibc, the default is 0 (dynamic linking).')
282
283   BitFromArgument(env, 'nacl_disable_shared', default=not env.Bit('nacl_glibc'),
284     desc='Do not build shared versions of libraries. '
285       'For nacl-newlib, the default is 1 (static libraries only). '
286       'For nacl-glibc, the default is 0 (both static and shared libraries).')
287
288   # Defaults on when --verbose is specified.
289   # --verbose sets 'brief_comstr' to False, so this looks a little strange
290   BitFromArgument(env, 'target_stats', default=not GetOption('brief_comstr'),
291     desc='Collect and display information about which commands are executed '
292       'during the build process')
293
294   BitFromArgument(env, 'werror', default=True,
295     desc='Treat warnings as errors (-Werror)')
296
297   BitFromArgument(env, 'disable_nosys_linker_warnings', default=False,
298     desc='Disable warning mechanism in src/untrusted/nosys/warning.h')
299
300   BitFromArgument(env, 'naclsdk_validate', default=True,
301     desc='Verify the presence of the SDK')
302
303   BitFromArgument(env, 'running_on_valgrind', default=False,
304     desc='Compile and test using valgrind')
305
306   BitFromArgument(env, 'enable_tmpfs_redirect_var', default=False,
307     desc='Allow redirecting tmpfs location for shared memory '
308          '(by default, /dev/shm is used)')
309
310   BitFromArgument(env, 'pp', default=False,
311     desc='Enable pretty printing')
312
313   # Defaults on when --verbose is specified
314   # --verbose sets 'brief_comstr' to False, so this looks a little strange
315   BitFromArgument(env, 'sysinfo', default=not GetOption('brief_comstr'),
316     desc='Print verbose system information')
317
318   BitFromArgument(env, 'disable_flaky_tests', default=False,
319     desc='Do not run potentially flaky tests - used on Chrome bots')
320
321   BitFromArgument(env, 'use_sandboxed_translator', default=False,
322     desc='use pnacl sandboxed translator for linking (not available for arm)')
323
324   BitFromArgument(env, 'pnacl_generate_pexe', default=env.Bit('bitcode'),
325     desc='use pnacl to generate pexes and translate in a separate step')
326
327   BitFromArgument(env, 'translate_in_build_step', default=True,
328     desc='Run translation during build phase (e.g. if do_not_run_tests=1)')
329
330   BitFromArgument(env, 'pnacl_unsandboxed', default=False,
331     desc='Translate pexe to an unsandboxed, host executable')
332
333   BitFromArgument(env, 'nonsfi_nacl', default=False,
334     desc='Use Non-SFI Mode instead of the original SFI Mode.  This uses '
335       'nonsfi_loader instead of sel_ldr, and it tells the PNaCl toolchain '
336       'to translate pexes to Non-SFI nexes.')
337
338   BitFromArgument(env, 'use_newlib_nonsfi_loader', default=True,
339     desc='Test nonsfi_loader linked against NaCl newlib instead of the one '
340       'linked against host libc. This flag makes sense only with '
341       'nonsfi_nacl=1.')
342
343   BitFromArgument(env, 'browser_headless', default=False,
344     desc='Where possible, set up a dummy display to run the browser on '
345       'when running browser tests.  On Linux, this runs the browser through '
346       'xvfb-run.  This Scons does not need to be run with an X11 display '
347       'and we do not open a browser window on the user\'s desktop.  '
348       'Unfortunately there is no equivalent on Mac OS X.')
349
350   BitFromArgument(env, 'disable_crash_dialog', default=True,
351     desc='Disable Windows\' crash dialog box, which Windows pops up when a '
352       'process exits with an unhandled fault.  Windows enables this by '
353       'default for processes launched from the command line or from the '
354       'GUI.  Our default is to disable it, because the dialog turns crashes '
355       'into hangs on Buildbot, and our test suite includes various crash '
356       'tests.')
357
358   BitFromArgument(env, 'do_not_run_tests', default=False,
359     desc='Prevents tests from running.  This lets SCons build the files needed '
360       'to run the specified test(s) without actually running them.  This '
361       'argument is a counterpart to built_elsewhere.')
362
363   BitFromArgument(env, 'no_gdb_tests', default=False,
364     desc='Prevents GDB tests from running.  If GDB is not available, you can '
365       'test everything else by specifying this flag.')
366
367   BitFromArgument(env, 'validator_ragel', default=True,
368     desc='Use the R-DFA validator instead of the original validators.')
369
370   # TODO(shcherbina): add support for other golden-based tests, not only
371   # run_x86_*_validator_testdata_tests.
372   BitFromArgument(env, 'regenerate_golden', default=False,
373     desc='When running golden-based tests, instead of comparing results '
374          'save actual output as golden data.')
375
376   BitFromArgument(env, 'x86_64_zero_based_sandbox', default=False,
377     desc='Use the zero-address-based x86-64 sandbox model instead of '
378       'the r15-based model.')
379
380   BitFromArgument(env, 'android', default=False,
381                   desc='Build for Android target')
382
383   BitFromArgument(env, 'arm_hard_float', default=True,
384                   desc='Build for hard float ARM ABI')
385
386   BitFromArgument(env, 'skip_nonstable_bitcode', default=False,
387                   desc='Skip tests involving non-stable bitcode')
388
389   #########################################################################
390   # EXPERIMENTAL
391   # This is for generating a testing library for use within private test
392   # enuminsts, where we want to compare and test different validators.
393   #
394   BitFromArgument(env, 'ncval_testing', default=False,
395     desc='EXPERIMENTAL: Compile validator code for testing within enuminsts')
396
397   # PNaCl sanity checks
398   if ((env.Bit('pnacl_generate_pexe') or env.Bit('use_sandboxed_translator'))
399       and not env.Bit('bitcode')):
400     raise UserError("pnacl_generate_pexe and use_sandboxed_translator"
401                     " don't make sense without bitcode")
402
403 def CheckArguments():
404   for key in ARGUMENTS:
405     if key not in ACCEPTABLE_ARGUMENTS:
406       raise UserError('bad argument: %s' % key)
407
408
409 # Sets a command line argument. Dies if an argument with this name is already
410 # defined.
411 def SetArgument(key, value):
412   print '    %s=%s' % (key, str(value))
413   if key in ARGUMENTS:
414     raise UserError('ERROR: %s redefined' % (key, ))
415   ARGUMENTS[key] = value
416
417 # Expands "macro" command line arguments.
418 def ExpandArguments():
419   if ARGUMENTS.get('buildbot') == 'memcheck':
420     print 'buildbot=memcheck expands to the following arguments:'
421     SetArgument('run_under',
422                 ARGUMENTS.get('memcheck_command',
423                               'src/third_party/valgrind/memcheck.sh') +
424                 ',--error-exitcode=1')
425     SetArgument('scale_timeout', 20)
426     SetArgument('running_on_valgrind', True)
427   elif ARGUMENTS.get('buildbot') == 'tsan':
428     print 'buildbot=tsan expands to the following arguments:'
429     SetArgument('run_under',
430                 ARGUMENTS.get('tsan_command',
431                               'src/third_party/valgrind/tsan.sh') +
432                 ',--nacl-untrusted,--error-exitcode=1,' +
433                 '--suppressions=src/third_party/valgrind/tests.supp')
434     SetArgument('scale_timeout', 20)
435     SetArgument('running_on_valgrind', True)
436   elif ARGUMENTS.get('buildbot') == 'tsan-trusted':
437     print 'buildbot=tsan-trusted expands to the following arguments:'
438     SetArgument('run_under',
439                 ARGUMENTS.get('tsan_command',
440                               'src/third_party/valgrind/tsan.sh') +
441                 ',--error-exitcode=1,' +
442                 '--suppressions=src/third_party/valgrind/tests.supp')
443     SetArgument('scale_timeout', 20)
444     SetArgument('running_on_valgrind', True)
445   elif ARGUMENTS.get('buildbot') == 'memcheck-browser-tests':
446     print 'buildbot=memcheck-browser-tests expands to the following arguments:'
447     SetArgument('browser_test_tool', 'memcheck')
448     SetArgument('scale_timeout', 20)
449     SetArgument('running_on_valgrind', True)
450   elif ARGUMENTS.get('buildbot') == 'tsan-browser-tests':
451     print 'buildbot=tsan-browser-tests expands to the following arguments:'
452     SetArgument('browser_test_tool', 'tsan')
453     SetArgument('scale_timeout', 20)
454     SetArgument('running_on_valgrind', True)
455   elif ARGUMENTS.get('buildbot'):
456     raise UserError('ERROR: unexpected argument buildbot="%s"' % (
457         ARGUMENTS.get('buildbot'), ))
458
459 ExpandArguments()
460
461 def GetTargetPlatform():
462   return pynacl.platform.GetArch3264(ARGUMENTS.get('platform', 'x86-32'))
463
464 def GetBuildPlatform():
465   return pynacl.platform.GetArch3264()
466
467
468 environment_list = []
469
470 # Base environment for both nacl and non-nacl variants.
471 kwargs = {}
472 if ARGUMENTS.get('DESTINATION_ROOT') is not None:
473   kwargs['DESTINATION_ROOT'] = ARGUMENTS.get('DESTINATION_ROOT')
474 pre_base_env = Environment(
475     # Use the environment that scons was run in to run scons invoked commands.
476     # This allows in things like externally provided PATH, PYTHONPATH.
477     ENV = os.environ.copy(),
478     tools = ['component_setup'],
479     # SOURCE_ROOT is one leave above the native_client directory.
480     SOURCE_ROOT = Dir('#/..').abspath,
481     # Publish dlls as final products (to staging).
482     COMPONENT_LIBRARY_PUBLISH = True,
483
484     # Use workaround in special scons version.
485     LIBS_STRICT = True,
486     LIBS_DO_SUBST = True,
487
488     # Select where to find coverage tools.
489     COVERAGE_MCOV = '../third_party/lcov/bin/mcov',
490     COVERAGE_GENHTML = '../third_party/lcov/bin/genhtml',
491     **kwargs
492 )
493
494
495 if 'generate_ninja' in ARGUMENTS:
496   import pynacl.scons_to_ninja
497   pynacl.scons_to_ninja.GenerateNinjaFile(
498       pre_base_env, dest_file=ARGUMENTS['generate_ninja'])
499
500
501 breakpad_tools_dir = ARGUMENTS.get('breakpad_tools_dir')
502 if breakpad_tools_dir is not None:
503   pre_base_env['BREAKPAD_TOOLS_DIR'] = pre_base_env.Dir(
504       os.path.abspath(breakpad_tools_dir))
505
506
507 # CLANG
508 DeclareBit('clang', 'Use clang to build trusted code')
509 pre_base_env.SetBitFromOption('clang', False)
510
511 DeclareBit('asan',
512            'Use AddressSanitizer to build trusted code (implies --clang)')
513 pre_base_env.SetBitFromOption('asan', False)
514 if pre_base_env.Bit('asan'):
515   pre_base_env.SetBits('clang')
516
517 DeclareBit('msan',
518            'Use MemorySanitizer to build trusted code (implies --clang)')
519 pre_base_env.SetBitFromOption('msan', False)
520 if pre_base_env.Bit('msan'):
521   pre_base_env.SetBits('clang')
522
523 # CODE COVERAGE
524 DeclareBit('coverage_enabled', 'The build should be instrumented to generate'
525            'coverage information')
526
527 # If the environment variable BUILDBOT_BUILDERNAME is set, we can determine
528 # if we are running in a VM by the lack of a '-bare-' (aka bare metal) in the
529 # bot name.  Otherwise if the builder name is not set, then assume real HW.
530 DeclareBit('running_on_vm', 'Returns true when environment is running in a VM')
531 builder = os.environ.get('BUILDBOT_BUILDERNAME')
532 if builder and builder.find('-bare-') == -1:
533   pre_base_env.SetBits('running_on_vm')
534 else:
535   pre_base_env.ClearBits('running_on_vm')
536
537 DeclareBit('nacl_glibc', 'Use nacl-glibc for building untrusted code')
538 pre_base_env.SetBitFromOption('nacl_glibc', False)
539
540 # This function should be called ASAP after the environment is created, but
541 # after ExpandArguments.
542 SetUpArgumentBits(pre_base_env)
543
544 # Register PrintFinalReport only after SetUpArgumentBits since it references
545 # bits that get declared in SetUpArgumentBits
546 atexit.register(PrintFinalReport)
547
548 def DisableCrashDialog():
549   if sys.platform == 'win32':
550     import win32api
551     import win32con
552     # The double call is to preserve existing flags, as discussed at
553     # http://blogs.msdn.com/oldnewthing/archive/2004/07/27/198410.aspx
554     new_flags = win32con.SEM_NOGPFAULTERRORBOX
555     existing_flags = win32api.SetErrorMode(new_flags)
556     win32api.SetErrorMode(existing_flags | new_flags)
557
558 if pre_base_env.Bit('disable_crash_dialog'):
559   DisableCrashDialog()
560
561 # We want to pull CYGWIN setup in our environment or at least set flag
562 # nodosfilewarning. It does not do anything when CYGWIN is not involved
563 # so let's do it in all cases.
564 pre_base_env['ENV']['CYGWIN'] = os.environ.get('CYGWIN', 'nodosfilewarning')
565
566 # Note: QEMU_PREFIX_HOOK may influence test runs and sb translator invocations
567 pre_base_env['ENV']['QEMU_PREFIX_HOOK'] = os.environ.get('QEMU_PREFIX_HOOK', '')
568
569 # Allow the zero-based sandbox model to run insecurely.
570 # TODO(arbenson): remove this once binutils bug is fixed (see
571 # src/trusted/service_runtime/arch/x86_64/sel_addrspace_posix_x86_64.c)
572 if pre_base_env.Bit('x86_64_zero_based_sandbox'):
573   pre_base_env['ENV']['NACL_ENABLE_INSECURE_ZERO_BASED_SANDBOX'] = 1
574
575 if pre_base_env.Bit('werror'):
576   werror_flags = ['-Werror']
577 else:
578   werror_flags = []
579
580 # Allow variadic macros
581 werror_flags = werror_flags + ['-Wno-variadic-macros']
582
583 if pre_base_env.Bit('clang'):
584   # Allow 'default' label in switch even when all enumeration cases
585   # have been covered.
586   werror_flags += ['-Wno-covered-switch-default']
587   # Allow C++11 extensions (for "override")
588   werror_flags += ['-Wno-c++11-extensions']
589
590
591 # Method to make sure -pedantic, etc, are not stripped from the
592 # default env, since occasionally an engineer will be tempted down the
593 # dark -- but wide and well-trodden -- path of expediency and stray
594 # from the path of correctness.
595
596 def EnsureRequiredBuildWarnings(env):
597   if (env.Bit('linux') or env.Bit('mac')) and not env.Bit('android'):
598     required_env_flags = set(['-pedantic', '-Wall'] + werror_flags)
599     ccflags = set(env.get('CCFLAGS'))
600
601     if not required_env_flags.issubset(ccflags):
602       raise UserError('required build flags missing: '
603                       + ' '.join(required_env_flags.difference(ccflags)))
604   else:
605     # windows get a pass for now
606     pass
607
608 pre_base_env.AddMethod(EnsureRequiredBuildWarnings)
609
610 # Expose MakeTempDir and MakeTempFile to scons scripts
611 def MakeEmptyFile(env, **kwargs):
612   fd, path = test_lib.MakeTempFile(env, **kwargs)
613   os.close(fd)
614   return path
615
616 pre_base_env.AddMethod(test_lib.MakeTempDir)
617 pre_base_env.AddMethod(MakeEmptyFile)
618
619 # Method to add target suffix to name.
620 def NaClTargetArchSuffix(env, name):
621   return name + '_' + env['TARGET_FULLARCH'].replace('-', '_')
622
623 pre_base_env.AddMethod(NaClTargetArchSuffix)
624
625
626 # Generic Test Wrapper
627
628 # Add list of Flaky or Bad tests to skip per platform.  A
629 # platform is defined as build type
630 # <BUILD_TYPE>-<SUBARCH>
631 bad_build_lists = {
632     'arm': [],
633 }
634
635 # This is a list of tests that do not yet pass when using nacl-glibc.
636 # TODO(mseaborn): Enable more of these tests!
637 nacl_glibc_skiplist = set([
638     # Struct layouts differ.
639     'run_abi_test',
640     # Syscall wrappers not implemented yet.
641     'run_sysbasic_test',
642     'run_sysbrk_test',
643     # Fails because clock() is not hooked up.
644     'run_timefuncs_test',
645     # Needs further investigation.
646     'sdk_minimal_test',
647     # This test fails with nacl-glibc: glibc reports an internal
648     # sanity check failure in free().
649     # TODO(robertm): This needs further investigation.
650     'run_ppapi_event_test',
651     'run_srpc_ro_file_test',
652     'run_ppapi_geturl_valid_test',
653     'run_ppapi_geturl_invalid_test',
654     # http://code.google.com/p/chromium/issues/detail?id=108131
655     # we would need to list all of the glibc components as
656     # web accessible resources in the extensions's manifest.json,
657     # not just the nexe and nmf file.
658     'run_ppapi_extension_mime_handler_browser_test',
659     ])
660 nacl_glibc_skiplist.update(['%s_irt' % test for test in nacl_glibc_skiplist])
661
662 # Whitelist of tests to run for Non-SFI Mode.  Note that typos here will
663 # not be caught automatically!
664 # TODO(mseaborn): Eventually we should run all of small_tests instead of
665 # this whitelist.
666 nonsfi_test_whitelist = set([
667     'run_clock_get_test',
668     'run_dup_test',
669     'run_fcntl_test',
670     'run_float_test',
671     'run_fork_test',
672     'run_getpid_test',
673     'run_hello_world_test',
674     'run_irt_futex_test',
675     'run_malloc_realloc_calloc_free_test',
676     'run_mmap_test',
677     'run_nanosleep_test',
678     'run_prctl_test',
679     'run_printf_test',
680     'run_pwrite_test',
681     'run_sigaction_test',
682     'run_signal_test',
683     'run_socket_test',
684     'run_stack_alignment_test',
685     'run_syscall_test',
686     'run_thread_test',
687     ])
688
689
690 # If a test is not in one of these suites, it will probally not be run on a
691 # regular basis.  These are the suites that will be run by the try bot or that
692 # a large number of users may run by hand.
693 MAJOR_TEST_SUITES = set([
694   'small_tests',
695   'medium_tests',
696   'large_tests',
697   # Tests using the pepper plugin, only run with chrome
698   # TODO(ncbray): migrate pepper_browser_tests to chrome_browser_tests
699   'pepper_browser_tests',
700   # Lightweight browser tests
701   'chrome_browser_tests',
702   'huge_tests',
703   'memcheck_bot_tests',
704   'tsan_bot_tests',
705   # Special testing environment for testing comparing x86 validators.
706   'ncval_testing',
707   # Environment for validator difference testing
708   'validator_diff_tests',
709   # Subset of tests enabled for Non-SFI Mode.
710   'nonsfi_tests',
711 ])
712
713 # These are the test suites we know exist, but aren't run on a regular basis.
714 # These test suites are essentially shortcuts that run a specific subset of the
715 # test cases.
716 ACCEPTABLE_TEST_SUITES = set([
717   'barebones_tests',
718   'dynamic_load_tests',
719   'eh_tests',  # Tests for C++ exception handling
720   'exception_tests',  # Tests for hardware exception handling
721   'exit_status_tests',
722   'gdb_tests',
723   'mmap_race_tests',
724   'nonpexe_tests',
725   'performance_tests',
726   'pnacl_abi_tests',
727   'sel_ldr_sled_tests',
728   'sel_ldr_tests',
729   'toolchain_tests',
730   'validator_modeling',
731   'validator_tests',
732   # Special testing of the decoder for the ARM validator.
733   'arm_decoder_tests',
734 ])
735
736 # Under --mode=nacl_irt_test we build variants of numerous tests normally
737 # built under --mode=nacl.  The test names and suite names for these
738 # variants are set (in IrtTestAddNodeToTestSuite, below) by appending _irt
739 # to the names used for the --mode=nacl version of the same tests.
740 MAJOR_TEST_SUITES |= set([name + '_irt'
741                           for name in MAJOR_TEST_SUITES])
742 ACCEPTABLE_TEST_SUITES |= set([name + '_irt'
743                                for name in ACCEPTABLE_TEST_SUITES])
744
745 # The major test suites are also acceptable names.  Suite names are checked
746 # against this set in order to catch typos.
747 ACCEPTABLE_TEST_SUITES.update(MAJOR_TEST_SUITES)
748
749
750 def ValidateTestSuiteNames(suite_name, node_name):
751   if node_name is None:
752     node_name = '<unknown>'
753
754   # Prevent a silent failiure - strings are iterable!
755   if not isinstance(suite_name, (list, tuple)):
756     raise Exception("Test suites for %s should be specified as a list, "
757       "not as a %s: %s" % (node_name, type(suite_name).__name__,
758       repr(suite_name)))
759
760   if not suite_name:
761     raise Exception("No test suites are specified for %s. Set the 'broken' "
762       "parameter on AddNodeToTestSuite in the cases where there's a known "
763       "issue and you don't want the test to run" % (node_name,))
764
765   # Make sure each test is in at least one test suite we know will run
766   major_suites = set(suite_name).intersection(MAJOR_TEST_SUITES)
767   if not major_suites:
768     raise Exception("None of the test suites %s for %s are run on a "
769     "regular basis" % (repr(suite_name), node_name))
770
771   # Make sure a wierd test suite hasn't been inadvertantly specified
772   for s in suite_name:
773     if s not in ACCEPTABLE_TEST_SUITES:
774       raise Exception("\"%s\" is not a known test suite. Either this is "
775       "a typo for %s, or it should be added to ACCEPTABLE_TEST_SUITES in "
776       "SConstruct" % (s, node_name))
777
778 BROKEN_TEST_COUNT = 0
779
780
781 def GetPlatformString(env):
782   build = env['BUILD_TYPE']
783
784   # If we are testing 'NACL' we really need the trusted info
785   if build=='nacl' and 'TRUSTED_ENV' in env:
786     trusted_env = env['TRUSTED_ENV']
787     build = trusted_env['BUILD_TYPE']
788     subarch = trusted_env['BUILD_SUBARCH']
789   else:
790     subarch = env['BUILD_SUBARCH']
791
792   # Build the test platform string
793   return build + '-' + subarch
794
795 pre_base_env.AddMethod(GetPlatformString)
796
797
798 tests_to_disable_qemu = set([
799     # These tests do not work under QEMU but do work on ARM hardware.
800     #
801     # You should use the is_broken argument in preference to adding
802     # tests to this list.
803     #
804     # TODO(dschuff) some of these tests appear to work with the new QEMU.
805     # find out which
806     # http://code.google.com/p/nativeclient/issues/detail?id=2437
807     # Note, for now these tests disable both the irt and non-irt variants
808     'run_atomic_ops_test',    # still broken with qemu 2012/06/12
809     'run_atomic_ops_nexe_test',
810     'run_egyptian_cotton_test',  # still broken with qemu 2012/06/12
811     'run_many_threads_sequential_test',
812     'run_mmap_atomicity_test',   # still broken with qemu 2012/06/12
813     # http://code.google.com/p/nativeclient/issues/detail?id=2142
814     'run_nacl_semaphore_test',
815     'run_nacl_tls_unittest',
816     # subprocess needs to also have qemu prefix, which isn't supported
817     'run_subprocess_test',
818     # The next 2 tests seem flaky on QEMU
819     'run_srpc_manifest_file_test',
820     'run_srpc_message_untrusted_test',
821     'run_thread_stack_alloc_test',
822     'run_thread_suspension_test',
823     'run_thread_test',
824     'run_dynamic_modify_test',
825     # qemu has bugs that make TestCatchingFault flaky (see
826     # http://code.google.com/p/nativeclient/issues/detail?id=3239), and
827     # we don't particularly need to measure performance under qemu.
828     'run_performance_test',
829 ])
830
831 tests_to_disable = set()
832 if ARGUMENTS.get('disable_tests', '') != '':
833   tests_to_disable.update(ARGUMENTS['disable_tests'].split(','))
834
835
836 def ShouldSkipTest(env, node_name):
837   if (env.Bit('skip_trusted_tests')
838       and (env['NACL_BUILD_FAMILY'] == 'TRUSTED'
839            or env['NACL_BUILD_FAMILY'] == 'UNTRUSTED_IRT')):
840     return True
841
842   if env.Bit('do_not_run_tests'):
843     # This hack is used for pnacl testing where we might build tests
844     # without running them on one bot and then transfer and run them on another.
845     # The skip logic only takes the first bot into account e.g. qemu
846     # restrictions, while it really should be skipping based on the second
847     # bot. By simply disabling the skipping completely we work around this.
848     return False
849
850   # There are no known-to-fail tests any more, but this code is left
851   # in so that if/when we port to a new architecture or add a test
852   # that is known to fail on some platform(s), we can continue to have
853   # a central location to disable tests from running.  NB: tests that
854   # don't *build* on some platforms need to be omitted in another way.
855
856   if node_name in tests_to_disable:
857     return True
858
859   if env.UsingEmulator():
860     if node_name in tests_to_disable_qemu:
861       return True
862     # For now also disable the irt variant
863     if node_name.endswith('_irt') and node_name[:-4] in tests_to_disable_qemu:
864       return True
865
866   # Retrieve list of tests to skip on this platform
867   skiplist = bad_build_lists.get(env.GetPlatformString(), [])
868   if node_name in skiplist:
869     return True
870
871   if env.Bit('nacl_glibc') and node_name in nacl_glibc_skiplist:
872     return True
873
874   return False
875
876 pre_base_env.AddMethod(ShouldSkipTest)
877
878
879 def AddImplicitTestSuites(suite_list, node_name):
880   if node_name in nonsfi_test_whitelist:
881     suite_list = suite_list + ['nonsfi_tests']
882   return suite_list
883
884
885 def AddNodeToTestSuite(env, node, suite_name, node_name, is_broken=False,
886                        is_flaky=False):
887   global BROKEN_TEST_COUNT
888
889   # CommandTest can return an empty list when it silently discards a test
890   if not node:
891     return
892
893   assert node_name is not None
894   test_name_regex = r'run_.*_(unit)?test.*$'
895   assert re.match(test_name_regex, node_name), (
896       'test %r does not match "run_..._test" naming convention '
897       '(precise regex is %s)' % (node_name, test_name_regex))
898
899   suite_name = AddImplicitTestSuites(suite_name, node_name)
900   ValidateTestSuiteNames(suite_name, node_name)
901
902   AlwaysBuild(node)
903
904   if is_broken or is_flaky and env.Bit('disable_flaky_tests'):
905     # Only print if --verbose is specified
906     if not GetOption('brief_comstr'):
907       print '*** BROKEN ', node_name
908     BROKEN_TEST_COUNT += 1
909     env.Alias('broken_tests', node)
910   elif env.ShouldSkipTest(node_name):
911     print '*** SKIPPING ', env.GetPlatformString(), ':', node_name
912     env.Alias('broken_tests', node)
913   else:
914     env.Alias('all_tests', node)
915
916     for s in suite_name:
917       env.Alias(s, node)
918
919   if node_name:
920     env.ComponentTestOutput(node_name, node)
921     test_name = node_name
922   else:
923     # This is rather shady, but the tests need a name without dots so they match
924     # what gtest does.
925     # TODO(ncbray) node_name should not be optional.
926     test_name = os.path.basename(str(node[0].path))
927     if test_name.endswith('.out'):
928       test_name = test_name[:-4]
929     test_name = test_name.replace('.', '_')
930   SetTestName(node, test_name)
931
932 pre_base_env.AddMethod(AddNodeToTestSuite)
933
934
935 def TestBindsFixedTcpPort(env, node):
936   # This tells Scons that tests that bind a fixed TCP port should not
937   # run concurrently, because they would interfere with each other.
938   # These tests are typically tests for NaCl's GDB debug stub.  The
939   # dummy filename used below is an arbitrary token that just has to
940   # match across the tests.
941   SideEffect(env.File('${SCONSTRUCT_DIR}/test_binds_fixed_tcp_port'), node)
942
943 pre_base_env.AddMethod(TestBindsFixedTcpPort)
944
945
946 # Convenient testing aliases
947 # NOTE: work around for scons non-determinism in the following two lines
948 Alias('sel_ldr_sled_tests', [])
949
950 Alias('small_tests', [])
951 Alias('medium_tests', [])
952 Alias('large_tests', [])
953
954 Alias('small_tests_irt', [])
955 Alias('medium_tests_irt', [])
956 Alias('large_tests_irt', [])
957
958 Alias('pepper_browser_tests', [])
959 Alias('chrome_browser_tests', [])
960
961 Alias('unit_tests', 'small_tests')
962 Alias('smoke_tests', ['small_tests', 'medium_tests'])
963
964 if pre_base_env.Bit('nacl_glibc'):
965   Alias('memcheck_bot_tests', ['small_tests'])
966   Alias('tsan_bot_tests', ['small_tests'])
967 else:
968   Alias('memcheck_bot_tests', ['small_tests', 'medium_tests', 'large_tests'])
969   Alias('tsan_bot_tests', [])
970
971
972 def Banner(text):
973   print '=' * 70
974   print text
975   print '=' * 70
976
977 pre_base_env.AddMethod(Banner)
978
979
980 # PLATFORM LOGIC
981 # Define the platforms, and use them to define the path for the
982 # scons-out directory (aka TARGET_ROOT)
983 #
984 # Various variables in the scons environment are related to this, e.g.
985 #
986 # BUILD_ARCH: (arm, mips, x86)
987 # BUILD_SUBARCH: (32, 64)
988 #
989
990 DeclareBit('build_x86_32', 'Building binaries for the x86-32 architecture',
991            exclusive_groups='build_arch')
992 DeclareBit('build_x86_64', 'Building binaries for the x86-64 architecture',
993            exclusive_groups='build_arch')
994 DeclareBit('build_mips32', 'Building binaries for the MIPS architecture',
995            exclusive_groups='build_arch')
996 DeclareBit('build_arm_arm', 'Building binaries for the ARM architecture',
997            exclusive_groups='build_arch')
998 DeclareBit('target_x86_32', 'Tools being built will process x86-32 binaries',
999            exclusive_groups='target_arch')
1000 DeclareBit('target_x86_64', 'Tools being built will process x86-36 binaries',
1001            exclusive_groups='target_arch')
1002 DeclareBit('target_mips32', 'Tools being built will process MIPS binaries',
1003            exclusive_groups='target_arch')
1004 DeclareBit('target_arm_arm', 'Tools being built will process ARM binaries',
1005            exclusive_groups='target_arch')
1006
1007 # Shorthand for either the 32 or 64 bit version of x86.
1008 DeclareBit('build_x86', 'Building binaries for the x86 architecture')
1009 DeclareBit('target_x86', 'Tools being built will process x86 binaries')
1010
1011 DeclareBit('build_arm', 'Building binaries for the arm architecture')
1012 DeclareBit('target_arm', 'Tools being built will process arm binaries')
1013
1014
1015 def MakeArchSpecificEnv(platform=None):
1016   env = pre_base_env.Clone()
1017   if platform is None:
1018     platform = GetTargetPlatform()
1019
1020   arch = pynacl.platform.GetArch(platform)
1021   if pynacl.platform.IsArch64Bit(platform):
1022     subarch = '64'
1023   else:
1024     subarch = '32'
1025
1026   env.Replace(BUILD_FULLARCH=platform)
1027   env.Replace(BUILD_ARCHITECTURE=arch)
1028   env.Replace(BUILD_SUBARCH=subarch)
1029   env.Replace(TARGET_FULLARCH=platform)
1030   env.Replace(TARGET_ARCHITECTURE=arch)
1031   env.Replace(TARGET_SUBARCH=subarch)
1032
1033   # Example: PlatformBit('build', 'x86-32') -> build_x86_32
1034   def PlatformBit(prefix, platform):
1035     return "%s_%s" % (prefix, platform.replace('-', '_'))
1036
1037   env.SetBits(PlatformBit('build', platform))
1038   env.SetBits(PlatformBit('target', platform))
1039
1040   if env.Bit('build_x86_32') or env.Bit('build_x86_64'):
1041     env.SetBits('build_x86')
1042   if env.Bit('build_arm_arm'):
1043     env.SetBits('build_arm')
1044
1045   if env.Bit('target_x86_32') or env.Bit('target_x86_64'):
1046     env.SetBits('target_x86')
1047   if env.Bit('target_arm_arm'):
1048     env.SetBits('target_arm')
1049
1050   env.Replace(BUILD_ISA_NAME=platform)
1051
1052   if env.Bit('target_mips32'):
1053     # This is a silent default on MIPS.
1054     env.SetBits('bitcode')
1055
1056   # Determine where the object files go
1057   env.Replace(BUILD_TARGET_NAME=platform)
1058   # This may be changed later; see target_variant_map, below.
1059   env.Replace(TARGET_VARIANT='')
1060   env.Replace(TARGET_ROOT=
1061       '${DESTINATION_ROOT}/${BUILD_TYPE}-${BUILD_TARGET_NAME}${TARGET_VARIANT}')
1062   return env
1063
1064
1065 # Valgrind
1066 pre_base_env.AddMethod(lambda self: ARGUMENTS.get('running_on_valgrind'),
1067                        'IsRunningUnderValgrind')
1068
1069 DeclareBit('with_leakcheck', 'Running under Valgrind leak checker')
1070
1071 def RunningUnderLeakCheck():
1072   run_under = ARGUMENTS.get('run_under')
1073   if run_under:
1074     extra_args = ARGUMENTS.get('run_under_extra_args')
1075     if extra_args:
1076       run_under += extra_args
1077     if run_under.find('leak-check=full') > 0:
1078       return True
1079   return False
1080
1081 if RunningUnderLeakCheck():
1082   pre_base_env.SetBits('with_leakcheck')
1083
1084
1085 def HasSuffix(item, suffix):
1086   if isinstance(item, str):
1087     return item.endswith(suffix)
1088   elif hasattr(item, '__getitem__'):
1089     return HasSuffix(item[0], suffix)
1090   else:
1091     return item.path.endswith(suffix)
1092
1093
1094 def StripSuffix(string, suffix):
1095   assert string.endswith(suffix)
1096   return string[:-len(suffix)]
1097
1098
1099 def DualLibrary(env, lib_name, *args, **kwargs):
1100   """Builder to build both .a and _shared.a library in one step.
1101
1102   Args:
1103     env: Environment in which we were called.
1104     lib_name: Library name.
1105     args: Positional arguments.
1106     kwargs: Keyword arguments.
1107   """
1108   static_objs = [i for i in Flatten(args[0]) if not HasSuffix(i, '.os')]
1109   shared_objs = [i for i in Flatten(args[0]) if not HasSuffix(i, '.o')]
1110   # Built static library as ususal.
1111   env.ComponentLibrary(lib_name, static_objs, **kwargs)
1112   # For coverage bots, we only want one object file since two versions would
1113   # write conflicting information to the same .gdca/.gdna files.
1114   if env.Bit('coverage_enabled'): return
1115   # Build a static library using -fPIC for the .o's.
1116   if env.Bit('linux'):
1117     env_shared = env.Clone(OBJSUFFIX='.os')
1118     env_shared.Append(CCFLAGS=['-fPIC'])
1119     # -fPIE overrides -fPIC, and shared libraries should not be linked
1120     # as executables.
1121     env_shared.FilterOut(CCFLAGS=['-fPIE'])
1122     env_shared.ComponentLibrary(lib_name + '_shared', shared_objs, **kwargs)
1123     # for arm trusted we usually build -static
1124     env_shared.FilterOut(LINKFLAGS=['-static'])
1125
1126 def DualObject(env, *args, **kwargs):
1127   """Builder to build both .o and .os in one step.
1128
1129   Args:
1130     env: Environment in which we were called.
1131     args: Positional arguments.
1132     kwargs: Keyword arguments.
1133   """
1134   # Built static library as ususal.
1135   ret = env.ComponentObject(*args, **kwargs)
1136   # For coverage bots, we only want one object file since two versions would
1137   # write conflicting information to the same .gdca/.gdna files.
1138   if env.Bit('coverage_enabled'): return ret
1139   # Build a static library using -fPIC for the .o's.
1140   if env.Bit('linux'):
1141     env_shared = env.Clone(OBJSUFFIX='.os')
1142     env_shared.Append(CCFLAGS=['-fPIC'])
1143     ret += env_shared.ComponentObject(*args, **kwargs)
1144   return ret
1145
1146
1147 def AddDualLibrary(env):
1148   env.AddMethod(DualLibrary)
1149   env.AddMethod(DualObject)
1150   # For coverage bots we only build one set of objects and we always set
1151   # '-fPIC' so we do not need a "special" library.
1152   if env.Bit('coverage_enabled'):
1153     env['SHARED_LIBS_SPECIAL'] = False
1154   else:
1155     env['SHARED_LIBS_SPECIAL'] = env.Bit('linux')
1156
1157
1158 # In prebuild mode we ignore the dependencies so that stuff does
1159 # NOT get build again
1160 # Optionally ignore the build process.
1161 DeclareBit('prebuilt', 'Disable all build steps, only support install steps')
1162 pre_base_env.SetBitFromOption('prebuilt', False)
1163
1164
1165 # HELPERS FOR TEST INVOLVING TRUSTED AND UNTRUSTED ENV
1166 def GetEmulator(env):
1167   emulator = ARGUMENTS.get('force_emulator')
1168   if emulator is None and 'TRUSTED_ENV' in env:
1169     emulator = env['TRUSTED_ENV'].get('EMULATOR')
1170   return emulator
1171
1172 pre_base_env.AddMethod(GetEmulator)
1173
1174 def UsingEmulator(env):
1175   return bool(env.GetEmulator())
1176
1177 pre_base_env.AddMethod(UsingEmulator)
1178
1179
1180 def GetValidator(env, validator):
1181   # NOTE: that the variable TRUSTED_ENV is set by ExportSpecialFamilyVars()
1182   if 'TRUSTED_ENV' not in env:
1183     return None
1184
1185   if validator is None:
1186     if env.Bit('build_arm'):
1187       validator = 'arm-ncval-core'
1188     elif env.Bit('build_mips32'):
1189       validator = 'mips-ncval-core'
1190     else:
1191       if env.Bit('validator_ragel'):
1192         validator = 'ncval_new'
1193       else:
1194         validator = 'ncval'
1195
1196   trusted_env = env['TRUSTED_ENV']
1197   return trusted_env.File('${STAGING_DIR}/${PROGPREFIX}%s${PROGSUFFIX}' %
1198                     validator)
1199
1200 pre_base_env.AddMethod(GetValidator)
1201
1202
1203 # Perform os.path.abspath rooted at the directory SConstruct resides in.
1204 def SConstructAbsPath(env, path):
1205   return os.path.normpath(os.path.join(env['MAIN_DIR'], path))
1206
1207 pre_base_env.AddMethod(SConstructAbsPath)
1208
1209
1210 def GetPlatformBuildTargetDir(env):
1211   # Currently we do not support any cross OS compiles, eventually the OS name
1212   # will probably be passed in through arguments.
1213   os_name = pynacl.platform.GetOS()
1214
1215   # Currently 32/64 share the same tool build target directory. When we have
1216   # separate toolchains for each the architectures will probably have to use
1217   # the Arch3264() variant.
1218   build_arch = pynacl.platform.GetArch(GetBuildPlatform())
1219
1220   return '%s_%s' % (os_name, build_arch)
1221
1222 pre_base_env.AddMethod(GetPlatformBuildTargetDir)
1223
1224
1225 def GetToolchainDir(env, platform_build_dir=None, toolchain_name=None,
1226                     target_arch=None, is_pnacl=None, lib_name=None):
1227   if platform_build_dir is None:
1228     platform_build_dir = env.GetPlatformBuildTargetDir()
1229
1230   if toolchain_name is None:
1231     # Fill in default arguments based on environment.
1232     if is_pnacl is None:
1233       is_pnacl = env.Bit('bitcode')
1234       if lib_name is None:
1235         if is_pnacl or not env.Bit('nacl_glibc'):
1236           lib_name = 'newlib'
1237         else:
1238           lib_name = 'glibc'
1239
1240     if target_arch is None:
1241       target_arch = pynacl.platform.GetArch(GetTargetPlatform())
1242
1243     if is_pnacl:
1244       target_env = 'pnacl'
1245     else:
1246       target_env = 'nacl_%s' % target_arch
1247
1248     # See if we have a custom toolchain directory set.
1249     if is_pnacl:
1250       toolchain_arg = 'pnacl_%s_dir' % lib_name
1251     else:
1252       toolchain_arg = 'nacl_%s_dir' % lib_name
1253
1254     custom_toolchain_dir = ARGUMENTS.get(toolchain_arg, None)
1255     if custom_toolchain_dir:
1256       return env.SConstructAbsPath(custom_toolchain_dir)
1257
1258     # Get the standard toolchain name since no directory custom was found.
1259     if is_pnacl:
1260       target_env = 'pnacl'
1261     else:
1262       target_env = 'nacl_%s' % target_arch
1263     toolchain_name = '%s_%s' % (target_env, lib_name)
1264
1265   # Get the absolute path for the platform build directory and toolchain.
1266   toolchain_sub_dir = os.path.join('toolchain',
1267                                    platform_build_dir,
1268                                    toolchain_name)
1269   return env.SConstructAbsPath(toolchain_sub_dir)
1270
1271 pre_base_env.AddMethod(GetToolchainDir)
1272
1273
1274 def GetSelLdr(env):
1275   sel_ldr = ARGUMENTS.get('force_sel_ldr')
1276   if sel_ldr:
1277     return env.File(env.SConstructAbsPath(sel_ldr))
1278
1279   # NOTE: that the variable TRUSTED_ENV is set by ExportSpecialFamilyVars()
1280   if 'TRUSTED_ENV' not in env:
1281     return None
1282
1283   trusted_env = env['TRUSTED_ENV']
1284   return trusted_env.File('${STAGING_DIR}/${PROGPREFIX}sel_ldr${PROGSUFFIX}')
1285
1286 pre_base_env.AddMethod(GetSelLdr)
1287
1288
1289 def GetSelLdrSeccomp(env):
1290   # NOTE: that the variable TRUSTED_ENV is set by ExportSpecialFamilyVars()
1291   if 'TRUSTED_ENV' not in env:
1292     return None
1293
1294   if not (env.Bit('linux') and env.Bit('build_x86_64')):
1295     return None
1296
1297   trusted_env = env['TRUSTED_ENV']
1298   return trusted_env.File('${STAGING_DIR}/${PROGPREFIX}'
1299                           'sel_ldr_seccomp${PROGSUFFIX}')
1300
1301 pre_base_env.AddMethod(GetSelLdrSeccomp)
1302
1303
1304 def SupportsSeccompBpfSandbox(env):
1305   if not (env.Bit('linux') and env.Bit('build_x86_64')):
1306     return False
1307
1308   # The gcov runtime does some extra calls (such as 'access') that
1309   # are not permitted by the policy.
1310   if env.Bit('coverage_enabled'):
1311     return False
1312
1313   # This is a lame detection if seccomp bpf filters are supported by the kernel.
1314   # We suppose that any Linux kernel v3.2+ supports it, but it is only true
1315   # for Ubuntu kernels. Seccomp BPF filters reached the mainline at 3.5,
1316   # so this check will be wrong on some relatively old non-Ubuntu Linux distros.
1317   kernel_version = map(int, platform.release().split('.', 2)[:2])
1318   return kernel_version >= [3, 2]
1319
1320 pre_base_env.AddMethod(SupportsSeccompBpfSandbox)
1321
1322
1323 def GetBootstrap(env):
1324   if env.Bit('msan'):
1325     # Bootstrap doens't currently work with MSan. However, MSan is only
1326     # available on x86_64 where we don't need bootstrap anyway.
1327     return None, None
1328   if 'TRUSTED_ENV' in env:
1329     trusted_env = env['TRUSTED_ENV']
1330     if trusted_env.Bit('linux'):
1331       template_digits = 'X' * 16
1332       return (trusted_env.File('${STAGING_DIR}/nacl_helper_bootstrap'),
1333               ['--r_debug=0x' + template_digits,
1334                '--reserved_at_zero=0x' + template_digits])
1335   return None, None
1336
1337 pre_base_env.AddMethod(GetBootstrap)
1338
1339 def AddBootstrap(env, executable, args):
1340   bootstrap, bootstrap_args = env.GetBootstrap()
1341   if bootstrap is None:
1342     return [executable] + args
1343   else:
1344     return [bootstrap, executable] + bootstrap_args + args
1345
1346 pre_base_env.AddMethod(AddBootstrap)
1347
1348
1349 def GetNonSfiLoader(env):
1350   if env.Bit('use_newlib_nonsfi_loader'):
1351     return nacl_env.GetTranslatedNexe(nacl_env.File(
1352         '${STAGING_DIR}/${PROGPREFIX}nonsfi_loader${PROGSUFFIX}'))
1353
1354   if 'TRUSTED_ENV' not in env:
1355     return None
1356   return env['TRUSTED_ENV'].File(
1357       '${STAGING_DIR}/${PROGPREFIX}nonsfi_loader${PROGSUFFIX}')
1358
1359 pre_base_env.AddMethod(GetNonSfiLoader)
1360
1361
1362 def GetIrtNexe(env, chrome_irt=False):
1363   image = ARGUMENTS.get('force_irt')
1364   if image:
1365     return env.SConstructAbsPath(image)
1366
1367   if chrome_irt:
1368     return nacl_irt_env.File('${STAGING_DIR}/irt.nexe')
1369   else:
1370     return nacl_irt_env.File('${STAGING_DIR}/irt_core.nexe')
1371
1372 pre_base_env.AddMethod(GetIrtNexe)
1373
1374 def ApplyTLSEdit(env, nexe_name, raw_nexe):
1375   # If the environment was built elsewhere, we do not need to apply tls_edit
1376   # since it only needs to be done during building.
1377   if env.Bit('built_elsewhere'):
1378     return env.File(nexe_name)
1379
1380   tls_edit_exe = env['BUILD_ENV'].File('${STAGING_DIR}/tls_edit${PROGSUFFIX}')
1381   return env.Command(
1382       nexe_name,
1383       [tls_edit_exe, raw_nexe],
1384       '${SOURCES[0]} --verbose ${SOURCES[1:]} ${TARGET}')
1385
1386 pre_base_env.AddMethod(ApplyTLSEdit)
1387
1388 def CommandValidatorTestNacl(env, name, image,
1389                              validator_flags=None,
1390                              validator=None,
1391                              size='medium',
1392                              **extra):
1393   validator = env.GetValidator(validator)
1394   if validator is None:
1395     print 'WARNING: no validator found. Skipping test %s' % name
1396     return []
1397
1398   if validator_flags is None:
1399     validator_flags = []
1400
1401   if env.Bit('pnacl_generate_pexe'):
1402     return []
1403
1404   command = [validator] + validator_flags + [image]
1405   return env.CommandTest(name, command, size, **extra)
1406
1407 pre_base_env.AddMethod(CommandValidatorTestNacl)
1408
1409
1410 def ExtractPublishedFiles(env, target_name):
1411   run_files = ['$STAGING_DIR/' + os.path.basename(published_file.path)
1412                for published_file in env.GetPublished(target_name, 'run')]
1413   nexe = '$STAGING_DIR/%s${PROGSUFFIX}' % target_name
1414   return [env.File(file) for file in run_files + [nexe]]
1415
1416 pre_base_env.AddMethod(ExtractPublishedFiles)
1417
1418
1419 # Only include the chrome side of the build if present.
1420 if os.path.exists(pre_base_env.File(
1421     '#/../ppapi/native_client/chrome_main.scons').abspath):
1422   SConscript('#/../ppapi/native_client/chrome_main.scons',
1423       exports=['pre_base_env'])
1424   enable_chrome = True
1425 else:
1426   def AddChromeFilesFromGroup(env, file_group):
1427     pass
1428   pre_base_env.AddMethod(AddChromeFilesFromGroup)
1429   enable_chrome = False
1430 DeclareBit('enable_chrome_side',
1431            'Is the chrome side present.')
1432 pre_base_env.SetBitFromOption('enable_chrome_side', enable_chrome)
1433
1434 def ProgramNameForNmf(env, basename):
1435   """ Create an architecture-specific filename that can be used in an NMF URL.
1436   """
1437   if env.Bit('pnacl_generate_pexe'):
1438     return basename
1439   else:
1440     return '%s_%s' % (basename, env.get('TARGET_FULLARCH'))
1441
1442 pre_base_env.AddMethod(ProgramNameForNmf)
1443
1444
1445 def SelUniversalTest(env,
1446                      name,
1447                      nexe,
1448                      args=None,
1449                      sel_universal_flags=None,
1450                      **kwargs):
1451   # The dynamic linker's ability to receive arguments over IPC at
1452   # startup currently requires it to reject the plugin's first
1453   # connection, but this interferes with the sel_universal-based
1454   # testing because sel_universal does not retry the connection.
1455   # TODO(mseaborn): Fix by retrying the connection or by adding an
1456   # option to ld.so to disable its argv-over-IPC feature.
1457   if env.Bit('nacl_glibc') and not env.Bit('nacl_static_link'):
1458     return []
1459
1460   # TODO(petarj): Sel_universal hangs on qemu-mips. Enable when fixed.
1461   if env.Bit('target_mips32') and env.UsingEmulator():
1462     return []
1463
1464   if sel_universal_flags is None:
1465     sel_universal_flags = []
1466
1467   # When run under qemu, sel_universal must sneak in qemu to the execv
1468   # call that spawns sel_ldr.
1469   if env.UsingEmulator():
1470     sel_universal_flags.append('--command_prefix')
1471     sel_universal_flags.append(env.GetEmulator())
1472
1473   if 'TRUSTED_ENV' not in env:
1474     return []
1475   sel_universal = env['TRUSTED_ENV'].File(
1476       '${STAGING_DIR}/${PROGPREFIX}sel_universal${PROGSUFFIX}')
1477
1478   # Point to sel_ldr using an environment variable.
1479   sel_ldr = env.GetSelLdr()
1480   if sel_ldr is None:
1481     print 'WARNING: no sel_ldr found. Skipping test %s' % name
1482     return []
1483   kwargs.setdefault('osenv', []).append('NACL_SEL_LDR=' + sel_ldr.abspath)
1484   bootstrap, _ = env.GetBootstrap()
1485   if bootstrap is not None:
1486     kwargs['osenv'].append('NACL_SEL_LDR_BOOTSTRAP=%s' % bootstrap.abspath)
1487
1488   node = CommandSelLdrTestNacl(env,
1489                                name,
1490                                nexe,
1491                                args=args,
1492                                loader=sel_universal,
1493                                sel_ldr_flags=sel_universal_flags,
1494                                skip_bootstrap=True,
1495                                **kwargs)
1496   if not env.Bit('built_elsewhere'):
1497     env.Depends(node, sel_ldr)
1498     if bootstrap is not None:
1499       env.Depends(node, bootstrap)
1500   return node
1501
1502 pre_base_env.AddMethod(SelUniversalTest)
1503
1504
1505 def MakeNaClLogOption(env, target):
1506   """ Make up a filename related to the [target], for use with NACLLOG.
1507   The file should end up in the build directory (scons-out/...).
1508   """
1509   # NOTE: to log to the source directory use file.srcnode().abspath instead.
1510   # See http://www.scons.org/wiki/File%28%29
1511   return env.File(target + '.nacllog').abspath
1512
1513 pre_base_env.AddMethod(MakeNaClLogOption)
1514
1515 def MakeVerboseExtraOptions(env, target, log_verbosity, extra):
1516   """ Generates **extra options that will give access to service runtime logs,
1517   at a given log_verbosity. Slips the options into the given extra dict. """
1518   log_file = env.MakeNaClLogOption(target)
1519   extra['log_file'] = log_file
1520   extra_env = ['NACLLOG=%s' % log_file,
1521                'NACLVERBOSITY=%d' % log_verbosity]
1522   extra['osenv'] = extra.get('osenv', []) + extra_env
1523
1524 pre_base_env.AddMethod(MakeVerboseExtraOptions)
1525
1526 def ShouldUseVerboseOptions(env, extra):
1527   """ Heuristic for setting up Verbose NACLLOG options. """
1528   return ('process_output_single' in extra or
1529           'log_golden' in extra)
1530
1531 pre_base_env.AddMethod(ShouldUseVerboseOptions)
1532
1533
1534 DeclareBit('tests_use_irt', 'Non-browser tests also load the IRT image', False)
1535
1536 # Bit to be set by individual test/nacl.scons files that need to opt out.
1537 DeclareBit('nonstable_bitcode', 'Tests use non-stable bitcode features', False)
1538
1539
1540 def GetFinalizedPexe(env, pexe):
1541   """ Prep and finalize the ABI for a given pexe if needed.
1542   """
1543   if not env.Bit('pnacl_generate_pexe') or env.Bit('nonstable_bitcode'):
1544     return pexe
1545
1546   # We can remove this once we move all CommandSelLdrTestNacl to a nacl.scons
1547   # file instead.  There are currently some canned nexe tests in build.scons.
1548   if env['NACL_BUILD_FAMILY'] == 'TRUSTED':
1549     return pexe
1550
1551   # Otherwise, finalize during the build step, since there is no finalize tool
1552   # that can run on triggered bots such as the ARM HW bots.
1553   pexe_name = pexe.abspath
1554   final_name = StripSuffix(pexe_name, '.nonfinal.pexe') + '.final.pexe'
1555   # Make sure the pexe doesn't get removed by the fake builders when
1556   # built_elsewhere=1
1557   env.Precious(pexe)
1558   node = env.Command(target=final_name, source=[pexe_name],
1559                      action=[Action('${PNACLFINALIZECOM}',
1560                                     '${PNACLFINALIZECOMSTR}')])
1561   assert len(node) == 1, node
1562   return node[0]
1563
1564 pre_base_env.AddMethod(GetFinalizedPexe)
1565
1566
1567 # Translate the given pexe.
1568 def GetTranslatedNexe(env, pexe):
1569   # First finalize the pexe.
1570   pexe = GetFinalizedPexe(env, pexe)
1571
1572   # Then check if we need to translate.
1573   # Check if we started with a pexe, so there is actually a translation step.
1574   if not env.Bit('pnacl_generate_pexe'):
1575     return pexe
1576
1577   # We can remove this once we move all CommandSelLdrTestNacl to a nacl.scons
1578   # file instead.  There are currently some canned nexe tests in build.scons.
1579   if env['NACL_BUILD_FAMILY'] == 'TRUSTED':
1580     return pexe
1581
1582   # Often there is a build step (do_not_run_tests=1) and a test step
1583   # (which is run with -j1). Normally we want to translate in the build step
1584   # so we can translate in parallel. However when we do sandboxed translation
1585   # on arm hw, we do the build step on x86 and translation on arm, so we have
1586   # to force the translation to be done in the test step. Hence,
1587   # we check the bit 'translate_in_build_step' / check if we are
1588   # in the test step.
1589   if not env.Bit('translate_in_build_step') and env.Bit('do_not_run_tests'):
1590     return pexe
1591
1592   pexe_name = pexe.abspath
1593   # Tidy up the suffix (remove the .final.pexe or .nonfinal.pexe),
1594   # depending on whether or not the pexe was finalized.
1595   suffix_to_strip = '.final.pexe'
1596   if not pexe_name.endswith(suffix_to_strip):
1597     suffix_to_strip = '.nonfinal.pexe'
1598   nexe_name = StripSuffix(pexe_name, suffix_to_strip) + '.nexe'
1599   # Make sure the pexe doesn't get removed by the fake builders when
1600   # built_elsewhere=1
1601   env.Precious(pexe)
1602   if env.Bit('nonstable_bitcode'):
1603     env.Append(TRANSLATEFLAGS=['--allow-llvm-bitcode-input'])
1604   node = env.Command(target=nexe_name, source=[pexe_name],
1605                      action=[Action('${TRANSLATECOM}', '${TRANSLATECOMSTR}')])
1606   assert len(node) == 1, node
1607   return node[0]
1608
1609 pre_base_env.AddMethod(GetTranslatedNexe)
1610
1611
1612 def CommandTestFileDumpCheck(env,
1613                              name,
1614                              target,
1615                              check_file,
1616                              objdump_flags):
1617   """Create a test that disassembles a binary (|target|) and checks for
1618   patterns in the |check_file|.  Disassembly is done using |objdump_flags|.
1619   """
1620
1621   # Do not try to run OBJDUMP if 'built_elsewhere', since that *might* mean
1622   # that a toolchain is not even present.  E.g., the arm hw buildbots do
1623   # not have the pnacl toolchain. We should be able to look for the host
1624   # ARM objdump though... a TODO(jvoung) for when there is time.
1625   if env.Bit('built_elsewhere'):
1626     return []
1627   target = env.GetTranslatedNexe(target)
1628   return env.CommandTestFileCheck(name,
1629                                   ['${OBJDUMP}', objdump_flags, target],
1630                                   check_file)
1631
1632 pre_base_env.AddMethod(CommandTestFileDumpCheck)
1633
1634
1635 def CommandTestFileCheck(env, name, cmd, check_file):
1636   """Create a test that runs a |cmd| (array of strings),
1637   which is expected to print to stdout.  The results
1638   of stdout will then be piped to the file_check.py tool which
1639   will search for the regexes specified in |check_file|. """
1640
1641   return env.CommandTest(name,
1642                          ['${PYTHON}',
1643                           env.File('${SCONSTRUCT_DIR}/tools/file_check.py'),
1644                           check_file] + cmd,
1645                          # don't run ${PYTHON} under the emulator.
1646                          direct_emulation=False)
1647
1648 pre_base_env.AddMethod(CommandTestFileCheck)
1649
1650 def CommandSelLdrTestNacl(env, name, nexe,
1651                           args = None,
1652                           log_verbosity=2,
1653                           sel_ldr_flags=None,
1654                           loader=None,
1655                           size='medium',
1656                           # True for *.nexe statically linked with glibc
1657                           glibc_static=False,
1658                           skip_bootstrap=False,
1659                           wrapper_program_prefix=None,
1660                           # e.g., [ 'python', 'time_check.py', '--' ]
1661                           **extra):
1662   # Disable all sel_ldr tests for windows under coverage.
1663   # Currently several .S files block sel_ldr from being instrumented.
1664   # See http://code.google.com/p/nativeclient/issues/detail?id=831
1665   if ('TRUSTED_ENV' in env and
1666       env['TRUSTED_ENV'].Bit('coverage_enabled') and
1667       env['TRUSTED_ENV'].Bit('windows')):
1668     return []
1669
1670   # The nexe might be a pexe that needs finalization, and translation.
1671   nexe = env.GetTranslatedNexe(nexe)
1672
1673   command = [nexe]
1674   if args is not None:
1675     command += args
1676
1677   if env.Bit('pnacl_unsandboxed') or (env.Bit('nonsfi_nacl') and
1678                                       not env.Bit('tests_use_irt')):
1679     # Run unsandboxed executable directly, without sel_ldr.
1680     return env.CommandTest(name, command, size, **extra)
1681
1682   if loader is None:
1683     if env.Bit('nonsfi_nacl'):
1684       loader = env.GetNonSfiLoader()
1685     else:
1686       loader = env.GetSelLdr()
1687     if loader is None:
1688       print 'WARNING: no sel_ldr found. Skipping test %s' % name
1689       return []
1690
1691   # Avoid problems with [] as default arguments
1692   if sel_ldr_flags is None:
1693     sel_ldr_flags = []
1694   else:
1695     # Avoid modifying original list
1696     sel_ldr_flags = list(sel_ldr_flags)
1697
1698   # Disable the validator if running a GLibC test under Valgrind.
1699   # http://code.google.com/p/nativeclient/issues/detail?id=1799
1700   if env.IsRunningUnderValgrind() and env.Bit('nacl_glibc'):
1701     sel_ldr_flags += ['-cc']
1702     # https://code.google.com/p/nativeclient/issues/detail?id=3158
1703     # We don't currently have valgrind.so for LD_PRELOAD to use.  That .so
1704     # is not used for newlib.
1705     # TODO(sehr): add valgrind.so built for NaCl.
1706     return []
1707
1708   # Skip platform qualification checks on configurations with known issues.
1709   if env.GetEmulator() or env.IsRunningUnderValgrind():
1710     sel_ldr_flags += ['-Q']
1711
1712   # Skip validation if we are using the x86-64 zero-based sandbox.
1713   # TODO(arbenson): remove this once the validator supports the x86-64
1714   # zero-based sandbox model.
1715   if env.Bit('x86_64_zero_based_sandbox'):
1716     sel_ldr_flags += ['-c']
1717
1718   # The glibc modifications only make sense for nacl_env tests.
1719   # But this function gets used by some base_env (i.e. src/trusted/...)
1720   # tests too.  Don't add the --nacl_glibc changes to the command
1721   # line for those cases.
1722   if env.Bit('nacl_glibc') and env['NACL_BUILD_FAMILY'] != 'TRUSTED':
1723     if not glibc_static and not env.Bit('nacl_static_link'):
1724       command = ['${NACL_SDK_LIB}/runnable-ld.so',
1725                  # Locally-built shared libraries come from ${LIB_DIR}
1726                  # while toolchain-provided ones come from ${NACL_SDK_LIB}.
1727                  '--library-path', '${LIB_DIR}:${NACL_SDK_LIB}'] + command
1728     # Enable file access.
1729     sel_ldr_flags += ['-a']
1730
1731   # Turn off sandbox for mac so coverage files can be written out.
1732   if ('TRUSTED_ENV' in env and
1733       env['TRUSTED_ENV'].Bit('coverage_enabled') and
1734       env.Bit('host_mac') and
1735       '-a' not in sel_ldr_flags):
1736     sel_ldr_flags += ['-a']
1737
1738   if env.Bit('tests_use_irt'):
1739     sel_ldr_flags += ['-B', nacl_env.GetIrtNexe()]
1740
1741   if skip_bootstrap:
1742     loader_cmd = [loader]
1743   else:
1744     loader_cmd = env.AddBootstrap(loader, [])
1745
1746   if env.Bit('nonsfi_nacl'):
1747     # nonsfi_loader does not accept the same flags as sel_ldr yet, so
1748     # we ignore sel_ldr_flags here.
1749     command = [loader] + command
1750   else:
1751     command = loader_cmd + sel_ldr_flags + ['--'] + command
1752
1753   if env.Bit('host_linux'):
1754     extra['using_nacl_signal_handler'] = True
1755
1756   if env.ShouldUseVerboseOptions(extra):
1757     env.MakeVerboseExtraOptions(name, log_verbosity, extra)
1758
1759   node = env.CommandTest(name, command, size, posix_path=True,
1760                          wrapper_program_prefix=wrapper_program_prefix, **extra)
1761   if env.Bit('tests_use_irt'):
1762     env.Alias('irt_tests', node)
1763   return node
1764
1765 pre_base_env.AddMethod(CommandSelLdrTestNacl)
1766
1767
1768 TEST_EXTRA_ARGS = ['stdin', 'log_file',
1769                    'stdout_golden', 'stderr_golden', 'log_golden',
1770                    'filter_regex', 'filter_inverse', 'filter_group_only',
1771                    'osenv', 'arch', 'subarch', 'exit_status', 'track_cmdtime',
1772                    'num_runs', 'process_output_single',
1773                    'process_output_combined', 'using_nacl_signal_handler',
1774                    'declares_exit_status', 'time_warning', 'time_error']
1775
1776 TEST_TIME_THRESHOLD = {
1777     'small':   2,
1778     'medium': 10,
1779     'large':  60,
1780     'huge': 1800,
1781     }
1782
1783 # Valgrind handles SIGSEGV in a way our testing tools do not expect.
1784 UNSUPPORTED_VALGRIND_EXIT_STATUS = ['trusted_sigabrt',
1785                                     'untrusted_sigill' ,
1786                                     'untrusted_segfault',
1787                                     'untrusted_sigsegv_or_equivalent',
1788                                     'trusted_segfault',
1789                                     'trusted_sigsegv_or_equivalent']
1790
1791
1792 def GetPerfEnvDescription(env):
1793   """Return a string describing architecture, library, etc. options.
1794
1795   This function attempts to gather a string that might inform why a performance
1796   change has occurred.
1797   """
1798   description_list = [env['TARGET_FULLARCH']]
1799   # Using a list to keep the order consistent.
1800   bit_to_description = [ ('bitcode', ('pnacl', 'nnacl')),
1801                          ('translate_fast', ('fast', '')),
1802                          ('nacl_glibc', ('glibc', 'newlib')),
1803                          ('nacl_static_link', ('static', 'dynamic')),
1804                          ]
1805   for (bit, (descr_yes, descr_no)) in bit_to_description:
1806     if env.Bit(bit):
1807       additional = descr_yes
1808     else:
1809       additional = descr_no
1810     if additional:
1811       description_list.append(additional)
1812   return '_'.join(description_list)
1813
1814 pre_base_env.AddMethod(GetPerfEnvDescription)
1815
1816
1817 TEST_NAME_MAP = {}
1818
1819 def GetTestName(target):
1820   key = str(target.path)
1821   return TEST_NAME_MAP.get(key, key)
1822
1823 pre_base_env['GetTestName'] = GetTestName
1824
1825
1826 def SetTestName(node, name):
1827   for target in Flatten(node):
1828     TEST_NAME_MAP[str(target.path)] = name
1829
1830
1831 def ApplyTestWrapperCommand(command_args, extra_deps):
1832   new_args = ARGUMENTS['test_wrapper'].split()
1833   for input_file in extra_deps:
1834     new_args.extend(['-F', input_file])
1835   for arg in command_args:
1836     if isinstance(arg, str):
1837       new_args.extend(['-a', arg])
1838     else:
1839       new_args.extend(['-f', arg])
1840   return new_args
1841
1842
1843 def CommandTest(env, name, command, size='small', direct_emulation=True,
1844                 extra_deps=[], posix_path=False, capture_output=True,
1845                 capture_stderr=True, wrapper_program_prefix=None,
1846                 scale_timeout=None, **extra):
1847   if not name.endswith('.out') or name.startswith('$'):
1848     raise Exception('ERROR: bad test filename for test output %r' % name)
1849
1850   if env.IsRunningUnderValgrind():
1851     skip = 'Valgrind'
1852   elif env.Bit('asan'):
1853     skip = 'AddressSanitizer'
1854   else:
1855     skip = None
1856   # Valgrind tends to break crash tests by changing the exit status.
1857   # So far, tests using declares_exit_status are crash tests.  If this
1858   # changes, we will have to find a way to make declares_exit_status
1859   # work with Valgrind.
1860   if (skip is not None and
1861       (extra.get('exit_status') in UNSUPPORTED_VALGRIND_EXIT_STATUS or
1862        bool(int(extra.get('declares_exit_status', 0))))):
1863     print 'Skipping death test "%s" under %s' % (name, skip)
1864     return []
1865
1866   if env.Bit('asan'):
1867     extra.setdefault('osenv', [])
1868     # Ensure that 'osenv' is a list.
1869     if isinstance(extra['osenv'], str):
1870       extra['osenv'] = [extra['osenv']]
1871     # ASan normally intercepts SIGSEGV and disables our SIGSEGV signal
1872     # handler, which interferes with various NaCl tests, including the
1873     # platform qualification test built into sel_ldr.  We fix this by
1874     # telling ASan not to mess with SIGSEGV.
1875     asan_options = ['handle_segv=0']
1876     if env.Bit('host_mac') and int(platform.mac_ver()[0].split('.')[1]) < 7:
1877       # MacOS 10.6 has a bug in the libsandbox system library where it
1878       # makes a memcmp call that reads off the end of a malloc'd block.
1879       # The bug appears to be harmless, but trips an ASan report.  So
1880       # tell ASan to suppress memcmp checks.
1881       asan_options.append('strict_memcmp=0')
1882     # TODO(mcgrathr): Remove this when we clean up all the crufty old
1883     # code to be leak-free.
1884     # https://code.google.com/p/nativeclient/issues/detail?id=3874
1885     asan_options.append('detect_leaks=0')
1886     # Note that the ASan runtime doesn't use : specifically as a separator.
1887     # It actually just looks for "foo=" anywhere in the string with strstr,
1888     # so any separator will do.  The most obvious choices, ' ', ',', and ';'
1889     # all cause command_tester.py to split things up and get confused.
1890     extra['osenv'].append('ASAN_OPTIONS=' + ':'.join(asan_options))
1891
1892   name = '${TARGET_ROOT}/test_results/' + name
1893   # NOTE: using the long version of 'name' helps distinguish opt vs dbg
1894   max_time = TEST_TIME_THRESHOLD[size]
1895   if 'scale_timeout' in ARGUMENTS:
1896     max_time = max_time * int(ARGUMENTS['scale_timeout'])
1897   if scale_timeout:
1898     max_time = max_time * scale_timeout
1899
1900   if env.Bit('nacl_glibc'):
1901     suite = 'nacl_glibc'
1902   else:
1903     suite = 'nacl_newlib'
1904   if env.Bit('bitcode'):
1905     suite = 'p' + suite
1906
1907   script_flags = ['--name', '%s.${GetTestName(TARGET)}' % suite,
1908                   '--time_warning', str(max_time),
1909                   '--time_error', str(10 * max_time),
1910                   ]
1911
1912   run_under = ARGUMENTS.get('run_under')
1913   if run_under:
1914     run_under_extra_args = ARGUMENTS.get('run_under_extra_args')
1915     if run_under_extra_args:
1916       run_under = run_under + ',' + run_under_extra_args
1917     script_flags.append('--run_under')
1918     script_flags.append(run_under)
1919
1920   emulator = env.GetEmulator()
1921   if emulator and direct_emulation:
1922     command = [emulator] + command
1923
1924   # test wrapper should go outside of emulators like qemu, since the
1925   # test wrapper code is not emulated.
1926   if wrapper_program_prefix is not None:
1927     command = wrapper_program_prefix + command
1928
1929   script_flags.append('--perf_env_description')
1930   script_flags.append(env.GetPerfEnvDescription())
1931
1932   # Add architecture info.
1933   extra['arch'] = env['BUILD_ARCHITECTURE']
1934   extra['subarch'] = env['BUILD_SUBARCH']
1935
1936   for flag_name, flag_value in extra.iteritems():
1937     assert flag_name in TEST_EXTRA_ARGS, repr(flag_name)
1938     if isinstance(flag_value, list):
1939       # Options to command_tester.py which are actually lists must not be
1940       # separated by whitespace. This stringifies the lists with a separator
1941       # char to satisfy command_tester.
1942       flag_value =  command_tester.StringifyList(flag_value)
1943     # do not add --flag + |flag_name| |flag_value| if
1944     # |flag_value| is false (empty).
1945     if flag_value:
1946       script_flags.append('--' + flag_name)
1947       # Make sure flag values are strings (or SCons objects) when building
1948       # up the command. Right now, this only means convert ints to strings.
1949       if isinstance(flag_value, int):
1950         flag_value = str(flag_value)
1951       script_flags.append(flag_value)
1952
1953   # Other extra flags
1954   if not capture_output:
1955     script_flags.extend(['--capture_output', '0'])
1956   if not capture_stderr:
1957     script_flags.extend(['--capture_stderr', '0'])
1958
1959   # Set command_tester.py's output filename.  We skip this when using
1960   # test_wrapper because the run_test_via_ssh.py wrapper does not have
1961   # the ability to copy result files back from the remote host.
1962   if 'test_wrapper' not in ARGUMENTS:
1963     script_flags.extend(['--output_stamp', name])
1964
1965   test_script = env.File('${SCONSTRUCT_DIR}/tools/command_tester.py')
1966   extra_deps = extra_deps + [env.File('${SCONSTRUCT_DIR}/tools/test_lib.py')]
1967   command = ['${PYTHON}', test_script] + script_flags + command
1968   if 'test_wrapper' in ARGUMENTS:
1969     command = ApplyTestWrapperCommand(command, extra_deps)
1970   return env.AutoDepsCommand(name, command,
1971                              extra_deps=extra_deps, posix_path=posix_path,
1972                              disabled=env.Bit('do_not_run_tests'))
1973
1974 pre_base_env.AddMethod(CommandTest)
1975
1976
1977 def FileSizeTest(env, name, envFile, max_size=None):
1978   """FileSizeTest() returns a scons node like the other XYZTest generators.
1979   It logs the file size of envFile in a perf-buildbot-recognizable format.
1980   Optionally, it can cause a test failure if the file is larger than max_size.
1981   """
1982   def doSizeCheck(target, source, env):
1983     filepath = source[0].abspath
1984     actual_size = os.stat(filepath).st_size
1985     command_tester.LogPerfResult(name,
1986                                  env.GetPerfEnvDescription(),
1987                                  '%.3f' % (actual_size / 1024.0),
1988                                  'KB')
1989     # Also get zipped size.
1990     nexe_file = open(filepath, 'rb')
1991     zipped_size = len(zlib.compress(nexe_file.read()))
1992     nexe_file.close()
1993     command_tester.LogPerfResult(name,
1994                                  'ZIPPED_' + env.GetPerfEnvDescription(),
1995                                  '%.3f' % (zipped_size / 1024.0),
1996                                  'KB')
1997     # Finally, do the size check.
1998     if max_size is not None and actual_size > max_size:
1999       # NOTE: this exception only triggers a failure for this particular test,
2000       # just like any other test failure.
2001       raise Exception("File %s larger than expected: expected up to %i, got %i"
2002                       % (filepath, max_size, actual_size))
2003   # If 'built_elsewhere', the file should should have already been built.
2004   # Do not try to built it and/or its pieces.
2005   if env.Bit('built_elsewhere'):
2006     env.Ignore(name, envFile)
2007   return env.Command(name, envFile, doSizeCheck)
2008
2009 pre_base_env.AddMethod(FileSizeTest)
2010
2011 def StripExecutable(env, name, exe):
2012   """StripExecutable returns a node representing the stripped version of |exe|.
2013      The stripped version will be given the basename |name|.
2014      NOTE: for now this only works with the untrusted toolchain.
2015      STRIP does not appear to be a first-class citizen in SCons and
2016      STRIP has only been set to point at the untrusted toolchain.
2017   """
2018   return env.Command(
2019       target=name,
2020       source=[exe],
2021       action=[Action('${STRIPCOM} ${SOURCES} -o ${TARGET}', '${STRIPCOMSTR}')])
2022
2023 pre_base_env.AddMethod(StripExecutable)
2024
2025
2026 # TODO(ncbray): pretty up the log output when running this builder.
2027 def DisabledCommand(target, source, env):
2028   pass
2029
2030 pre_base_env['BUILDERS']['DisabledCommand'] = Builder(action=DisabledCommand)
2031
2032
2033 def AutoDepsCommand(env, name, command, extra_deps=[], posix_path=False,
2034                     disabled=False):
2035   """AutoDepsCommand() takes a command as an array of arguments.  Each
2036   argument may either be:
2037
2038    * a string, or
2039    * a Scons file object, e.g. one created with env.File() or as the
2040      result of another build target.
2041
2042   In the second case, the file is automatically declared as a
2043   dependency of this command.
2044   """
2045   command = list(command)
2046   deps = []
2047   for index, arg in enumerate(command):
2048     if not isinstance(arg, str):
2049       if len(Flatten(arg)) != 1:
2050         # Do not allow this, because it would cause "deps" to get out
2051         # of sync with the indexes in "command".
2052         # See http://code.google.com/p/nativeclient/issues/detail?id=1086
2053         raise AssertionError('Argument to AutoDepsCommand() actually contains '
2054                              'multiple (or zero) arguments: %r' % arg)
2055       if posix_path:
2056         command[index] = '${SOURCES[%d].posix}' % len(deps)
2057       else:
2058         command[index] = '${SOURCES[%d].abspath}' % len(deps)
2059       deps.append(arg)
2060
2061   # If built_elsewhere, build commands are replaced by no-ops, so make sure
2062   # the targets don't get removed first
2063   if env.Bit('built_elsewhere'):
2064     env.Precious(deps)
2065   env.Depends(name, extra_deps)
2066
2067   if disabled:
2068     return env.DisabledCommand(name, deps)
2069   else:
2070     return env.Command(name, deps, ' '.join(command))
2071
2072
2073 pre_base_env.AddMethod(AutoDepsCommand)
2074
2075
2076 def GetPrintableCommandName(cmd):
2077   """Look at the first few elements of cmd to derive a suitable command name."""
2078   cmd_tokens = cmd.split()
2079   if "python" in cmd_tokens[0] and len(cmd_tokens) >= 2:
2080     cmd_name = cmd_tokens[1]
2081   else:
2082     cmd_name = cmd_tokens[0].split('(')[0]
2083
2084   # undo some pretty printing damage done by hammer
2085   cmd_name = cmd_name.replace('________','')
2086   # use file name part of a path
2087   return cmd_name.split('/')[-1]
2088
2089
2090 def GetPrintableEnvironmentName(env):
2091   # use file name part of a obj root path as env name
2092   return env.subst('${TARGET_ROOT}').split('/')[-1]
2093
2094 pre_base_env.AddMethod(GetPrintableEnvironmentName)
2095
2096
2097 def CustomCommandPrinter(cmd, targets, source, env):
2098   # Abuse the print hook to count the commands that are executed
2099   if env.Bit('target_stats'):
2100     cmd_name = GetPrintableCommandName(cmd)
2101     env_name = env.GetPrintableEnvironmentName()
2102     CMD_COUNTER[cmd_name] = CMD_COUNTER.get(cmd_name, 0) + 1
2103     ENV_COUNTER[env_name] = ENV_COUNTER.get(env_name, 0) + 1
2104
2105   if env.Bit('pp'):
2106     # Our pretty printer
2107     if targets:
2108       cmd_name = GetPrintableCommandName(cmd)
2109       env_name = env.GetPrintableEnvironmentName()
2110       sys.stdout.write('[%s] [%s] %s\n' % (cmd_name, env_name,
2111                                            targets[0].get_path()))
2112   else:
2113     # The SCons default (copied from print_cmd_line in Action.py)
2114     sys.stdout.write(cmd + u'\n')
2115
2116 if 'generate_ninja' not in ARGUMENTS:
2117   pre_base_env.Append(PRINT_CMD_LINE_FUNC=CustomCommandPrinter)
2118
2119
2120 def GetAbsDirArg(env, argument, target):
2121   """Fetch the named command-line argument and turn it into an absolute
2122 directory name.  If the argument is missing, raise a UserError saying
2123 that the given target requires that argument be given."""
2124   dir = ARGUMENTS.get(argument)
2125   if not dir:
2126     raise UserError('%s must be set when invoking %s' % (argument, target))
2127   return os.path.join(env.Dir('$MAIN_DIR').abspath, dir)
2128
2129 pre_base_env.AddMethod(GetAbsDirArg)
2130
2131
2132 pre_base_env.Append(
2133     CPPDEFINES = [
2134         ['NACL_BUILD_ARCH', '${BUILD_ARCHITECTURE}' ],
2135         ['NACL_BUILD_SUBARCH', '${BUILD_SUBARCH}' ],
2136         ],
2137     )
2138
2139 def MakeGTestEnv(env):
2140   # Create an environment to run unit tests using Gtest.
2141   gtest_env = env.Clone()
2142
2143   # This became necessary for the arm cross TC v4.6
2144   # but probable applies to all new gcc TCs
2145   gtest_env.Append(LINKFLAGS=['-pthread'])
2146
2147   # Define compile-time flag that communicates that we are compiling in the test
2148   # environment (rather than for the TCB).
2149   if gtest_env['NACL_BUILD_FAMILY'] == 'TRUSTED':
2150     gtest_env.Append(CCFLAGS=['-DNACL_TRUSTED_BUT_NOT_TCB'])
2151
2152   # This is necessary for unittest_main.c which includes gtest/gtest.h
2153   # The problem is that gtest.h includes other files expecting the
2154   # include path to be set.
2155   gtest_env.Prepend(CPPPATH=['${SOURCE_ROOT}/testing/gtest/include'])
2156
2157   # gtest does not compile with our stringent settings.
2158   if gtest_env.Bit('linux') or gtest_env.Bit('mac'):
2159     # "-pedantic" is because of: gtest-typed-test.h:236:46: error:
2160     # anonymous variadic macros were introduced in C99
2161     # Also, gtest does not compile successfully with "-Wundef".
2162     gtest_env.FilterOut(CCFLAGS=['-pedantic', '-Wundef'])
2163   gtest_env.FilterOut(CXXFLAGS=['-fno-rtti', '-Weffc++'])
2164
2165   # gtest is incompatible with static linking due to obscure libstdc++
2166   # linking interactions.
2167   # See http://code.google.com/p/nativeclient/issues/detail?id=1987
2168   gtest_env.FilterOut(LINKFLAGS=['-static'])
2169
2170   gtest_env.Prepend(LIBS=['gtest'])
2171   return gtest_env
2172
2173 pre_base_env.AddMethod(MakeGTestEnv)
2174
2175 def MakeUntrustedNativeEnv(env):
2176   native_env = nacl_env.Clone()
2177   if native_env.Bit('bitcode') and not native_env.Bit('target_mips32'):
2178     native_env = native_env.PNaClGetNNaClEnv()
2179   return native_env
2180
2181 pre_base_env.AddMethod(MakeUntrustedNativeEnv)
2182
2183 def MakeBaseTrustedEnv(platform=None):
2184   base_env = MakeArchSpecificEnv(platform)
2185   base_env.Append(
2186     IS_BUILD_ENV = False,
2187     BUILD_SUBTYPE = '',
2188     CPPDEFINES = [
2189       ['NACL_TARGET_ARCH', '${TARGET_ARCHITECTURE}' ],
2190       ['NACL_TARGET_SUBARCH', '${TARGET_SUBARCH}' ],
2191       ],
2192     CPPPATH = [
2193       '${SOURCE_ROOT}',
2194     ],
2195
2196     EXTRA_CFLAGS = [],
2197     EXTRA_CXXFLAGS = [],
2198     EXTRA_LIBS = [],
2199     CFLAGS = ['${EXTRA_CFLAGS}'],
2200     CXXFLAGS = ['${EXTRA_CXXFLAGS}'],
2201   )
2202   if base_env.Bit('ncval_testing'):
2203     base_env.Append(CPPDEFINES = ['NCVAL_TESTING'])
2204
2205   base_env.Append(BUILD_SCONSCRIPTS = [
2206       # KEEP THIS SORTED PLEASE
2207       'build/package_version/build.scons',
2208       'pynacl/build.scons',
2209       'src/nonsfi/irt/build.scons',
2210       'src/nonsfi/loader/build.scons',
2211       'src/shared/gio/build.scons',
2212       'src/shared/imc/build.scons',
2213       'src/shared/ldr/build.scons',
2214       'src/shared/platform/build.scons',
2215       'src/shared/serialization/build.scons',
2216       'src/shared/srpc/build.scons',
2217       'src/shared/utils/build.scons',
2218       'src/third_party/gtest/build.scons',
2219       'src/tools/validator_tools/build.scons',
2220       'src/trusted/cpu_features/build.scons',
2221       'src/trusted/debug_stub/build.scons',
2222       'src/trusted/desc/build.scons',
2223       'src/trusted/desc_cacheability/build.scons',
2224       'src/trusted/fault_injection/build.scons',
2225       'src/trusted/generic_container/build.scons',
2226       'src/trusted/gio/build.scons',
2227       'src/trusted/interval_multiset/build.scons',
2228       'src/trusted/manifest_name_service_proxy/build.scons',
2229       'src/trusted/nacl_base/build.scons',
2230       'src/trusted/nonnacl_util/build.scons',
2231       'src/trusted/perf_counter/build.scons',
2232       'src/trusted/platform_qualify/build.scons',
2233       'src/trusted/reverse_service/build.scons',
2234       'src/trusted/seccomp_bpf/build.scons',
2235       'src/trusted/sel_universal/build.scons',
2236       'src/trusted/service_runtime/build.scons',
2237       'src/trusted/simple_service/build.scons',
2238       'src/trusted/threading/build.scons',
2239       'src/trusted/validator/build.scons',
2240       'src/trusted/validator/driver/build.scons',
2241       'src/trusted/validator/x86/32/build.scons',
2242       'src/trusted/validator/x86/64/build.scons',
2243       'src/trusted/validator/x86/build.scons',
2244       'src/trusted/validator/x86/decoder/build.scons',
2245       'src/trusted/validator/x86/decoder/generator/build.scons',
2246       'src/trusted/validator/x86/ncval_reg_sfi/build.scons',
2247       'src/trusted/validator/x86/ncval_seg_sfi/build.scons',
2248       'src/trusted/validator/x86/ncval_seg_sfi/generator/build.scons',
2249       'src/trusted/validator/x86/testing/enuminsts/build.scons',
2250       'src/trusted/validator_arm/build.scons',
2251       'src/trusted/validator_ragel/build.scons',
2252       'src/trusted/validator_x86/build.scons',
2253       'src/trusted/weak_ref/build.scons',
2254       'tests/common/build.scons',
2255       'tests/lock_manager/build.scons',
2256       'tests/performance/build.scons',
2257       'tests/python_version/build.scons',
2258       'tests/sel_ldr_seccomp/build.scons',
2259       'tests/srpc_message/build.scons',
2260       'tests/tools/build.scons',
2261       'tests/unittests/shared/srpc/build.scons',
2262       'tests/unittests/shared/imc/build.scons',
2263       'tests/unittests/shared/platform/build.scons',
2264       'tests/unittests/trusted/asan/build.scons',
2265       'tests/unittests/trusted/bits/build.scons',
2266       'tests/unittests/trusted/platform_qualify/build.scons',
2267       'tests/unittests/trusted/service_runtime/build.scons',
2268       'toolchain_build/build.scons',
2269   ])
2270
2271   base_env.AddMethod(SDKInstallBin)
2272
2273   # The ARM and MIPS validators can be built for any target that doesn't use
2274   # ELFCLASS64.
2275   if not base_env.Bit('target_x86_64'):
2276     base_env.Append(
2277         BUILD_SCONSCRIPTS = [
2278           'src/trusted/validator_mips/build.scons',
2279         ])
2280
2281   base_env.AddChromeFilesFromGroup('trusted_scons_files')
2282
2283   base_env.Replace(
2284       NACL_BUILD_FAMILY = 'TRUSTED',
2285   )
2286
2287   # Add optional scons files if present in the directory tree.
2288   if os.path.exists(pre_base_env.subst('${MAIN_DIR}/supplement/build.scons')):
2289     base_env.Append(BUILD_SCONSCRIPTS=['${MAIN_DIR}/supplement/build.scons'])
2290
2291   return base_env
2292
2293
2294 # Select tests to run under coverage build.
2295 pre_base_env['COVERAGE_TARGETS'] = [
2296     'small_tests', 'medium_tests', 'large_tests',
2297     'chrome_browser_tests']
2298
2299
2300 pre_base_env.Help("""\
2301 ======================================================================
2302 Help for NaCl
2303 ======================================================================
2304
2305 Common tasks:
2306 -------------
2307
2308 * cleaning:           scons -c
2309 * building:           scons
2310 * build mandel:       scons --mode=nacl mandel.nexe
2311 * smoke test:         scons --mode=nacl,opt-linux -k pp=1 smoke_tests
2312
2313 * sel_ldr:            scons --mode=opt-linux sel_ldr
2314
2315 * build the plugin:         scons --mode=opt-linux ppNaClPlugin
2316 *      or:                  scons --mode=opt-linux src/trusted/plugin
2317
2318 Targets to build trusted code destined for the SDK:
2319 * build trusted-code tools:     scons build_bin
2320 * install trusted-code tools:   scons install_bin bindir=...
2321 * These default to opt build, or add --mode=dbg-host for debug build.
2322
2323 Targets to build untrusted code destined for the SDK:
2324 * build just libraries:         scons build_lib
2325 * install just headers:         scons install_headers includedir=...
2326 * install just libraries:       scons install_lib libdir=...
2327 * install headers and libraries:scons install includedir=... libdir=...
2328
2329 * dump system info:   scons --mode=nacl,opt-linux dummy
2330
2331 Options:
2332 --------
2333
2334 --prebuilt          Do not build things, just do install steps
2335
2336 --verbose           Full command line logging before command execution
2337
2338 pp=1                Use command line pretty printing (more concise output)
2339
2340 sysinfo=1           Verbose system info printing
2341
2342 naclsdk_validate=0  Suppress presence check of sdk
2343
2344
2345
2346 Automagically generated help:
2347 -----------------------------
2348 """)
2349
2350
2351 def SetUpClang(env):
2352   env['CLANG_DIR'] = '${SOURCE_ROOT}/third_party/llvm-build/Release+Asserts/bin'
2353   env['CLANG_OPTS'] = []
2354   if env.Bit('asan'):
2355     if not (env.Bit('host_linux') or env.Bit('host_mac')):
2356       raise UserError("ERROR: ASan is only available for Linux and Mac")
2357     env.Append(CLANG_OPTS=['-fsanitize=address',
2358                            '-gline-tables-only',
2359                            '-fno-omit-frame-pointer',
2360                            '-DADDRESS_SANITIZER'])
2361     if env.Bit('host_mac'):
2362       # The built executables will try to find this library at runtime
2363       # in the directory containing the executable itself.  In the
2364       # Chromium build, the library just gets copied into that
2365       # directory.  Here, there isn't a single directory from which
2366       # all the test binaries are run (sel_ldr is run from staging/
2367       # but other trusted test binaries are run from their respective
2368       # obj/.../ directories).  So instead just point the dynamic linker
2369       # at the right directory using an environment variable.
2370       clang_lib_dir = '${CLANG_DIR}/../lib/clang/*/lib/darwin'
2371       env['ENV']['DYLD_LIBRARY_PATH'] = ':'.join([dir.abspath for dir in
2372                                                   env.Glob(clang_lib_dir)])
2373       if 'PROPAGATE_ENV' not in env:
2374         env['PROPAGATE_ENV'] = []
2375       env['PROPAGATE_ENV'].append('DYLD_LIBRARY_PATH')
2376
2377   if env.Bit('msan'):
2378     if not env.Bit('host_linux') or not env.Bit('build_x86_64'):
2379       raise UserError('ERROR: MSan is only available for x86-64 Linux')
2380     track_origins = ARGUMENTS.get('msan_track_origins', '1')
2381     env.Append(CLANG_OPTS=['-fsanitize=memory',
2382                            '-fsanitize-memory-track-origins=%s' % track_origins,
2383                            '-gline-tables-only',
2384                            '-fno-omit-frame-pointer',
2385                            '-DMEMORY_SANITIZER'])
2386
2387   env['CC'] = '${CLANG_DIR}/clang ${CLANG_OPTS}'
2388   env['CXX'] = '${CLANG_DIR}/clang++ ${CLANG_OPTS}'
2389   # Make sure we find Clang-supplied libraries like -lprofile_rt
2390   # in the Clang build we use, rather than from the system.
2391   # The system-installed versions go with the system-installed Clang
2392   # and might not be compatible with the Clang we're running.
2393   env.Append(LIBPATH=['${CLANG_DIR}/../lib'])
2394
2395 def GenerateOptimizationLevels(env):
2396   if env.Bit('clang'):
2397     SetUpClang(env)
2398
2399   # Generate debug variant.
2400   debug_env = env.Clone(tools = ['target_debug'])
2401   debug_env['OPTIMIZATION_LEVEL'] = 'dbg'
2402   debug_env['BUILD_TYPE'] = debug_env.subst('$BUILD_TYPE')
2403   debug_env['BUILD_DESCRIPTION'] = debug_env.subst('$BUILD_DESCRIPTION')
2404   AddDualLibrary(debug_env)
2405   # Add to the list of fully described environments.
2406   environment_list.append(debug_env)
2407
2408   # Generate opt variant.
2409   opt_env = env.Clone(tools = ['target_optimized'])
2410   opt_env['OPTIMIZATION_LEVEL'] = 'opt'
2411   opt_env['BUILD_TYPE'] = opt_env.subst('$BUILD_TYPE')
2412   opt_env['BUILD_DESCRIPTION'] = opt_env.subst('$BUILD_DESCRIPTION')
2413   AddDualLibrary(opt_env)
2414   # Add to the list of fully described environments.
2415   environment_list.append(opt_env)
2416
2417   return (debug_env, opt_env)
2418
2419
2420 def SDKInstallBin(env, name, node, target=None):
2421   """Add the given node to the build_bin and install_bin targets.
2422 It will be installed under the given name with the build target appended.
2423 The optional target argument overrides the setting of what that target is."""
2424   env.Alias('build_bin', node)
2425   if 'install_bin' in COMMAND_LINE_TARGETS:
2426     dir = env.GetAbsDirArg('bindir', 'install_bin')
2427     if target is None:
2428       target = env['TARGET_FULLARCH'].replace('-', '_')
2429     file_name, file_ext = os.path.splitext(name)
2430     output_name = file_name + '_' + target + file_ext
2431     install_node = env.InstallAs(os.path.join(dir, output_name), node)
2432     env.Alias('install_bin', install_node)
2433
2434
2435 def MakeWindowsEnv(platform=None):
2436   base_env = MakeBaseTrustedEnv(platform)
2437   windows_env = base_env.Clone(
2438       BUILD_TYPE = '${OPTIMIZATION_LEVEL}-win',
2439       BUILD_TYPE_DESCRIPTION = 'Windows ${OPTIMIZATION_LEVEL} build',
2440       tools = ['target_platform_windows'],
2441       # Windows /SAFESEH linking requires either an .sxdata section be
2442       # present or that @feat.00 be defined as a local, absolute symbol
2443       # with an odd value.
2444       ASCOM = ('$ASPPCOM /E /D__ASSEMBLER__ | '
2445                '$WINASM -defsym @feat.00=1 -o $TARGET'),
2446       PDB = '${TARGET.base}.pdb',
2447       # Strict doesn't currently work for Windows since some of the system
2448       # libraries like wsock32 are magical.
2449       LIBS_STRICT = False,
2450       TARGET_ARCH='x86_64' if base_env.Bit('build_x86_64') else 'x86',
2451   )
2452
2453   windows_env.Append(
2454       CPPDEFINES = [
2455           ['NACL_WINDOWS', '1'],
2456           ['NACL_OSX', '0'],
2457           ['NACL_LINUX', '0'],
2458           ['NACL_ANDROID', '0'],
2459           ['_WIN32_WINNT', '0x0501'],
2460           ['__STDC_LIMIT_MACROS', '1'],
2461           ['NOMINMAX', '1'],
2462           # WIN32 is used by ppapi
2463           ['WIN32', '1'],
2464           # WIN32_LEAN_AND_MEAN tells windows.h to omit obsolete and rarely
2465           # used #include files. This allows use of Winsock 2.0 which otherwise
2466           # would conflict with Winsock 1.x included by windows.h.
2467           ['WIN32_LEAN_AND_MEAN', ''],
2468       ],
2469       LIBS = ['ws2_32', 'advapi32'],
2470       # TODO(bsy) remove 4355 once cross-repo
2471       # NACL_ALLOW_THIS_IN_INITIALIZER_LIST changes go in.
2472       CCFLAGS = ['/EHsc', '/WX', '/wd4355', '/wd4800'],
2473   )
2474
2475   # This linker option allows us to ensure our builds are compatible with
2476   # Chromium, which uses it.
2477   if windows_env.Bit('build_x86_32'):
2478     windows_env.Append(LINKFLAGS = "/safeseh")
2479
2480   # We use the GNU assembler (gas) on Windows so that we can use the
2481   # same .S assembly files on all platforms.  Microsoft's assembler uses
2482   # a completely different syntax for x86 code.
2483   if windows_env.Bit('build_x86_64'):
2484     # This assembler only works for x86-64 code.
2485     windows_env['WINASM'] = \
2486         windows_env.File('$SOURCE_ROOT/third_party/mingw-w64/mingw/bin/'
2487                          'x86_64-w64-mingw32-as.exe').abspath
2488   else:
2489     # This assembler only works for x86-32 code.
2490     windows_env['WINASM'] = \
2491         windows_env.File('$SOURCE_ROOT/third_party/gnu_binutils/files/'
2492                          'as').abspath
2493   return windows_env
2494
2495 (windows_debug_env,
2496  windows_optimized_env) = GenerateOptimizationLevels(MakeWindowsEnv())
2497
2498 def MakeUnixLikeEnv(platform=None):
2499   unix_like_env = MakeBaseTrustedEnv(platform)
2500   # -Wdeclaration-after-statement is desirable because MS studio does
2501   # not allow declarations after statements in a block, and since much
2502   # of our code is portable and primarily initially tested on Linux,
2503   # it'd be nice to get the build error earlier rather than later
2504   # (building and testing on Linux is faster).
2505   # TODO(nfullagar): should we consider switching to -std=c99 ?
2506   unix_like_env.Prepend(
2507     CFLAGS = [
2508         '-std=gnu99',
2509         '-Wdeclaration-after-statement',
2510         # Require defining functions as "foo(void)" rather than
2511         # "foo()" because, in C (but not C++), the latter defines a
2512         # function with unspecified arguments rather than no
2513         # arguments.
2514         '-Wstrict-prototypes',
2515         ],
2516     CCFLAGS = [
2517         # '-malign-double',
2518         '-Wall',
2519         '-pedantic',
2520         '-Wextra',
2521         '-Wno-long-long',
2522         '-Wswitch-enum',
2523         '-Wsign-compare',
2524         '-Wundef',
2525         '-fdiagnostics-show-option',
2526         '-fvisibility=hidden',
2527         '-fstack-protector',
2528         ] + werror_flags,
2529     # NOTE: pthread is only neeeded for libppNaClPlugin.so and on arm
2530     LIBS = ['pthread'],
2531     CPPDEFINES = [['__STDC_LIMIT_MACROS', '1'],
2532                   ['__STDC_FORMAT_MACROS', '1'],
2533                   ],
2534   )
2535   # Android's stlport uses __STRICT_ANSI__ to exclude "long long".
2536   # This breaks basically all C++ code that uses stlport.
2537   if not unix_like_env.Bit('android'):
2538     unix_like_env.Prepend(CXXFLAGS=['-std=c++98'])
2539
2540   if not unix_like_env.Bit('clang'):
2541     unix_like_env.Append(CCFLAGS=['--param', 'ssp-buffer-size=4'])
2542
2543   if unix_like_env.Bit('enable_tmpfs_redirect_var'):
2544     unix_like_env.Append(CPPDEFINES=[['NACL_ENABLE_TMPFS_REDIRECT_VAR', '1']])
2545   else:
2546     unix_like_env.Append(CPPDEFINES=[['NACL_ENABLE_TMPFS_REDIRECT_VAR', '0']])
2547   return unix_like_env
2548
2549
2550 def MakeMacEnv(platform=None):
2551   mac_env = MakeUnixLikeEnv(platform).Clone(
2552       BUILD_TYPE = '${OPTIMIZATION_LEVEL}-mac',
2553       BUILD_TYPE_DESCRIPTION = 'MacOS ${OPTIMIZATION_LEVEL} build',
2554       tools = ['target_platform_mac'],
2555       # TODO(bradnelson): this should really be able to live in unix_like_env
2556       #                   but can't due to what the target_platform_x module is
2557       #                   doing.
2558       LINK = '$CXX',
2559       PLUGIN_SUFFIX = '.bundle',
2560   )
2561   # On Mac, only the newer clang toolchains can parse some of the trusted
2562   # code's assembly syntax, so turn clang on by default.
2563   mac_env.SetBits('clang')
2564
2565   # This should be kept in synch with mac_deployment_target
2566   # in build/common.gypi, which in turn should be kept in synch
2567   # with chromium/src/build/common.gypi.
2568   mac_deployment_target = '10.6'
2569
2570   mac_env.Append(
2571       CCFLAGS=['-mmacosx-version-min=' + mac_deployment_target],
2572       LINKFLAGS=['-mmacosx-version-min=' + mac_deployment_target])
2573
2574   subarch_flag = '-m%s' % mac_env['BUILD_SUBARCH']
2575   mac_env.Append(
2576       CCFLAGS=[subarch_flag, '-fPIC'],
2577       ASFLAGS=[subarch_flag],
2578       LINKFLAGS=[subarch_flag, '-fPIC'],
2579       CPPDEFINES = [['NACL_WINDOWS', '0'],
2580                     ['NACL_OSX', '1'],
2581                     ['NACL_LINUX', '0'],
2582                     ['NACL_ANDROID', '0'],
2583                     # defining _DARWIN_C_SOURCE breaks 10.4
2584                     #['_DARWIN_C_SOURCE', '1'],
2585                     #['__STDC_LIMIT_MACROS', '1']
2586                     ],
2587   )
2588   return mac_env
2589
2590 (mac_debug_env, mac_optimized_env) = GenerateOptimizationLevels(MakeMacEnv())
2591
2592
2593 def which(cmd, paths=os.environ.get('PATH', '').split(os.pathsep)):
2594   for p in paths:
2595      if os.access(os.path.join(p, cmd), os.X_OK):
2596        return True
2597   return False
2598
2599
2600 def SetUpLinuxEnvArm(env):
2601   jail = env.GetToolchainDir(toolchain_name='arm_trusted')
2602   if env.Bit('arm_hard_float'):
2603     arm_abi = 'gnueabihf'
2604   else:
2605     arm_abi = 'gnueabi'
2606   if not platform.machine().startswith('arm'):
2607     # Allow emulation on non-ARM hosts.
2608     env.Replace(EMULATOR=jail + '/run_under_qemu_arm')
2609   if env.Bit('built_elsewhere'):
2610     def FakeInstall(dest, source, env):
2611       print 'Not installing', dest
2612       # Replace build commands with no-ops
2613     env.Replace(CC='true', CXX='true', LD='true',
2614                 AR='true', RANLIB='true', INSTALL=FakeInstall)
2615   else:
2616     arm_suffix = None
2617     for suffix in ['', '-4.5', '-4.6']:
2618       if which('arm-linux-%s-g++%s' % (arm_abi, suffix)):
2619         arm_suffix = suffix
2620         break
2621     if arm_suffix is None:
2622       # This doesn't bail out completely here because we cannot
2623       # tell whether scons was run with just --mode=nacl, where
2624       # none of these settings will actually be used.
2625       print 'NOTE: arm trusted TC is not installed'
2626       bad = 'ERROR-missing-arm-trusted-toolchain'
2627       env.Replace(CC=bad, CXX=bad, LD=bad)
2628       return
2629
2630     env.Replace(CC='arm-linux-%s-gcc%s' % (arm_abi, arm_suffix),
2631                 CXX='arm-linux-%s-g++%s' % (arm_abi, arm_suffix),
2632                 LD='arm-linux-%s-ld%s' % (arm_abi, arm_suffix),
2633                 ASFLAGS=[],
2634                 # The -rpath-link argument is needed on Ubuntu/Precise to
2635                 # avoid linker warnings about missing ld.linux.so.3.
2636                 # TODO(sbc): remove this once we stop supporting Precise
2637                 # as a build environment.
2638                 LINKFLAGS=['-Wl,-rpath-link=' + jail +
2639                            '/lib/arm-linux-' + arm_abi]
2640                 )
2641     # Note we let the compiler choose whether it's -marm or -mthumb by
2642     # default.  The hope is this will have the best chance of testing
2643     # the prevailing compilation mode used for Chromium et al.
2644     env.Prepend(CCFLAGS=['-march=armv7-a'])
2645
2646   # get_plugin_dirname.cc has a dependency on dladdr
2647   env.Append(LIBS=['dl'])
2648
2649 def SetUpAndroidEnv(env):
2650   env.FilterOut(CPPDEFINES=[['_LARGEFILE64_SOURCE', '1']])
2651   env.FilterOut(CPPDEFINES=[['NACL_ANDROID', '0']])
2652   env.Prepend(CPPDEFINES=[['NACL_ANDROID', '1']])
2653   android_ndk_root = os.path.join('${SOURCE_ROOT}', 'src', 'third_party',
2654                                   'android_tools', 'ndk')
2655   android_ndk_experimental_root = os.path.join('${SOURCE_ROOT}', 'src',
2656                                                'third_party', 'android_tools',
2657                                                'ndk_experimental')
2658   android_sdk_root = os.path.join('${SOURCE_ROOT}', 'src', 'third_party',
2659                                   'android_tools', 'sdk')
2660   android_sdk_version = 19
2661   android_stlport_root = os.path.join(android_ndk_root, 'sources', 'cxx-stl',
2662                                       'stlport')
2663   ndk_host_os_map = {
2664       pynacl.platform.OS_WIN : 'win',
2665       pynacl.platform.OS_MAC: 'darwin',
2666       pynacl.platform.OS_LINUX : 'linux'
2667       }
2668   host_os = ndk_host_os_map[pynacl.platform.GetOS()]
2669   android_sdk = os.path.join(android_sdk_root, 'platforms',
2670                              'android-%s' % android_sdk_version)
2671   arch_cflags = []
2672   if env.Bit('build_arm'):
2673     android_ndk_target_prefix = 'arm-linux-androideabi'
2674     android_ndk_version = '4.8'
2675     android_app_abi = 'armeabi-v7a'
2676     android_ndk_sysroot = os.path.join(android_ndk_root, 'platforms',
2677                                        'android-14', 'arch-arm')
2678     android_ndk_lib_dir = os.path.join('usr', 'lib')
2679     android_toolchain = os.path.join(android_ndk_root, 'toolchains',
2680                                      'arm-linux-androideabi-4.6', 'prebuilt',
2681                                      '%s-x86_64' % host_os, 'bin')
2682     arch_cflags += ['-march=armv7-a', '-mfloat-abi=softfp']
2683   # TODO(sehr): add other android architecture platform settings here.
2684   android_ndk_include = os.path.join(android_ndk_sysroot, 'usr', 'include')
2685   android_ndk_lib = os.path.join(android_ndk_sysroot, android_ndk_lib_dir)
2686   android_sdk_jar = os.path.join(android_sdk, 'android.jar')
2687   android_stlport_include = os.path.join(android_stlport_root, 'stlport')
2688   android_stlport_libs_dir = os.path.join(android_stlport_root, 'libs',
2689                                           android_app_abi)
2690   android_ndk_libgcc_path = os.path.join(android_toolchain, '..', 'lib', 'gcc',
2691                                          android_ndk_target_prefix,
2692                                          android_ndk_version)
2693   env.Replace(CC=os.path.join(android_toolchain,
2694                               '%s-gcc' % android_ndk_target_prefix),
2695               CXX=os.path.join(android_toolchain,
2696                               '%s-g++' % android_ndk_target_prefix),
2697               LD=os.path.join(android_toolchain,
2698                               '%s-g++' % android_ndk_target_prefix),
2699               AR=os.path.join(android_toolchain,
2700                               '%s-ar' % android_ndk_target_prefix),
2701               RANLIB=os.path.join(android_toolchain,
2702                                   '%s-ranlib' % android_ndk_target_prefix),
2703               READELF=os.path.join(android_toolchain,
2704                                    '%s-readelf' % android_ndk_target_prefix),
2705               STRIP=os.path.join(android_toolchain,
2706                                  '%s-strip' % android_ndk_target_prefix),
2707               EMULATOR=os.path.join(android_sdk_root, 'tools', 'emulator'),
2708               LIBPATH=['${LIB_DIR}',
2709                        android_ndk_lib,
2710                        android_ndk_libgcc_path,
2711                        os.path.join(android_stlport_root, 'libs',
2712                                     android_app_abi),
2713                        ],
2714               LIBS=['stlport_shared',
2715                     'gcc',
2716                     'c',
2717                     'dl',
2718                     'm',
2719                     ],
2720               )
2721   # SHLINKFLAGS should not inherit options from LINKFLAGS.
2722   env.FilterOut(SHLINKFLAGS=['$LINKFLAGS'])
2723   env.Append(CCFLAGS=['--sysroot=' + android_ndk_sysroot,
2724                       '-isystem=' + os.path.join(android_ndk_sysroot, 'usr',
2725                                                  'include'),
2726                       '-I%s' % android_stlport_include,
2727                       '-ffunction-sections',
2728                       '-g',
2729                       '-fstack-protector',
2730                       '-fno-short-enums',
2731                       '-finline-limit=64',
2732                       '-Wa,--noexecstack',
2733                       '-DANDROID',
2734                       '-D__ANDROID__',
2735                       # Due to bogus warnings on uintptr_t formats.
2736                       '-Wno-format',
2737                       ] + arch_cflags,
2738              CXXFLAGS=['-I%s' % android_stlport_include,
2739                        '-I%s' % android_ndk_include,
2740                        '-fno-exceptions',
2741                        ],
2742              LINKFLAGS=['--sysroot=' + android_ndk_sysroot,
2743                         '-nostdlib',
2744                         '-Wl,--no-undefined',
2745                         # Don't export symbols from statically linked libraries.
2746                         '-Wl,--exclude-libs=ALL',
2747                         # crtbegin_dynamic.o should be the last item in ldflags.
2748                         os.path.join(android_ndk_lib, 'crtbegin_dynamic.o'),
2749                         ],
2750              LINKCOM=' $ANDROID_EXTRA_LIBS',
2751              ANDROID_EXTRA_LIBS=os.path.join(android_ndk_lib,
2752                                              'crtend_android.o'),
2753              SHLINKFLAGS=['--sysroot=' + android_ndk_sysroot,
2754                           '-nostdlib',
2755                           # crtbegin_so.o should be the last item in ldflags.
2756                           os.path.join(android_ndk_lib, 'crtbegin_so.o'),
2757                           ],
2758              SHLINKCOM=' $ANDROID_EXTRA_SHLIBS',
2759              ANDROID_EXTRA_SHLIBS=os.path.join(android_ndk_lib,
2760                                                'crtend_so.o'),
2761              )
2762   return env
2763
2764 def SetUpLinuxEnvMips(env):
2765   jail = env.GetToolchainDir(toolchain_name='mips_trusted')
2766   if not platform.machine().startswith('mips'):
2767     # Allow emulation on non-MIPS hosts.
2768     env.Replace(EMULATOR=jail + '/run_under_qemu_mips32')
2769   if env.Bit('built_elsewhere'):
2770     def FakeInstall(dest, source, env):
2771       print 'Not installing', dest
2772       # Replace build commands with no-ops
2773     env.Replace(CC='true', CXX='true', LD='true',
2774                 AR='true', RANLIB='true', INSTALL=FakeInstall)
2775   else:
2776     tc_dir = os.path.join(jail, 'bin')
2777     if not which(os.path.join(tc_dir, 'mipsel-linux-gnu-gcc')):
2778       raise UserError("\nERRROR: "
2779           "MIPS trusted TC is not installed - try running:\n"
2780           "tools/trusted_cross_toolchains/trusted-toolchain-creator"
2781           ".mipsel.debian.sh nacl_sdk")
2782     env.Replace(CC=os.path.join(tc_dir, 'mipsel-linux-gnu-gcc'),
2783                 CXX=os.path.join(tc_dir, 'mipsel-linux-gnu-g++'),
2784                 LD=os.path.join(tc_dir, 'mipsel-linux-gnu-ld'),
2785                 ASFLAGS=[],
2786                 LIBPATH=['${LIB_DIR}',
2787                          jail + '/sysroot/usr/lib'],
2788                 LINKFLAGS=['-T',
2789                     os.path.join(jail, 'ld_script_mips_trusted')]
2790                 )
2791
2792     env.Append(LIBS=['rt', 'dl', 'pthread'],
2793                      CCFLAGS=['-march=mips32r2'])
2794
2795 # Makes a generic Linux development environment.
2796 # Linux development environments are used in two different ways.
2797 # 1) To produce trusted tools (e.g., sel_ldr), called TRUSTED_ENV
2798 # 2) To produce build tools (e.g., tls_edit), called BUILD_ENV
2799 def MakeGenericLinuxEnv(platform=None):
2800   linux_env = MakeUnixLikeEnv(platform).Clone(
2801       BUILD_TYPE = '${OPTIMIZATION_LEVEL}-linux',
2802       BUILD_TYPE_DESCRIPTION = 'Linux ${OPTIMIZATION_LEVEL} build',
2803       tools = ['target_platform_linux'],
2804       # TODO(bradnelson): this should really be able to live in unix_like_env
2805       #                   but can't due to what the target_platform_x module is
2806       #                   doing.
2807       LINK = '$CXX',
2808   )
2809
2810   # Prepend so we can disable warnings via Append
2811   linux_env.Prepend(
2812       CPPDEFINES = [['NACL_WINDOWS', '0'],
2813                     ['NACL_OSX', '0'],
2814                     ['NACL_LINUX', '1'],
2815                     ['NACL_ANDROID', '0'],
2816                     ['_BSD_SOURCE', '1'],
2817                     ['_POSIX_C_SOURCE', '199506'],
2818                     ['_XOPEN_SOURCE', '600'],
2819                     ['_GNU_SOURCE', '1'],
2820                     ['_LARGEFILE64_SOURCE', '1'],
2821                     ],
2822       LIBS = ['rt'],
2823       )
2824
2825   if linux_env.Bit('build_x86_32'):
2826     linux_env.Prepend(
2827         CCFLAGS = ['-m32'],
2828         LINKFLAGS = ['-m32'],
2829         )
2830   elif linux_env.Bit('build_x86_64'):
2831     linux_env.Prepend(
2832         CCFLAGS = ['-m64'],
2833         LINKFLAGS = ['-m64'],
2834         )
2835   elif linux_env.Bit('build_arm'):
2836     SetUpLinuxEnvArm(linux_env)
2837   elif linux_env.Bit('build_mips32'):
2838     SetUpLinuxEnvMips(linux_env)
2839   else:
2840     Banner('Strange platform: %s' % GetTargetPlatform())
2841
2842   # These are desireable options for every Linux platform:
2843   # _FORTIFY_SOURCE: general paranoia "hardening" option for library functions
2844   # -fPIE/-pie: create a position-independent executable
2845   # relro/now: "hardening" options for linking
2846   # noexecstack: ensure that the executable does not get a PT_GNU_STACK
2847   #              header that causes the kernel to set the READ_IMPLIES_EXEC
2848   #              personality flag, which disables NX page protection.
2849   linux_env.Prepend(
2850       CPPDEFINES=[['-D_FORTIFY_SOURCE', '2']],
2851       LINKFLAGS=['-pie', '-Wl,-z,relro', '-Wl,-z,now', '-Wl,-z,noexecstack'],
2852       )
2853   # The ARM toolchain has a linker that doesn't handle the code its
2854   # compiler generates under -fPIE.
2855   if linux_env.Bit('build_arm') or linux_env.Bit('build_mips32'):
2856     linux_env.Prepend(CCFLAGS=['-fPIC'])
2857     # TODO(mcgrathr): Temporarily punt _FORTIFY_SOURCE for ARM because
2858     # it causes a libc dependency newer than the old bots have installed.
2859     linux_env.FilterOut(CPPDEFINES=[['-D_FORTIFY_SOURCE', '2']])
2860   else:
2861     linux_env.Prepend(CCFLAGS=['-fPIE'])
2862
2863   # We always want to use the same flags for .S as for .c because
2864   # code-generation flags affect the predefines we might test there.
2865   linux_env.Replace(ASFLAGS=['${CCFLAGS}'])
2866
2867   return linux_env
2868
2869 # Specializes a generic Linux development environment to be a trusted
2870 # environment.
2871 def MakeTrustedLinuxEnv(platform=None):
2872   linux_env = MakeGenericLinuxEnv(platform)
2873   if linux_env.Bit('android'):
2874     SetUpAndroidEnv(linux_env)
2875   return linux_env
2876
2877 (linux_debug_env, linux_optimized_env) = \
2878     GenerateOptimizationLevels(MakeTrustedLinuxEnv())
2879
2880 # Do this before the site_scons/site_tools/naclsdk.py stuff to pass it along.
2881 pre_base_env.Append(
2882     PNACL_BCLDFLAGS = ARGUMENTS.get('pnacl_bcldflags', '').split(':'))
2883
2884
2885 # The nacl_env is used to build native_client modules
2886 # using a special tool chain which produces platform
2887 # independent binaries
2888 # NOTE: this loads stuff from: site_scons/site_tools/naclsdk.py
2889 nacl_env = MakeArchSpecificEnv()
2890 nacl_env = nacl_env.Clone(
2891     tools = ['naclsdk'],
2892     NACL_BUILD_FAMILY = 'UNTRUSTED',
2893     BUILD_TYPE = 'nacl',
2894     BUILD_TYPE_DESCRIPTION = 'NaCl module build',
2895
2896     ARFLAGS = 'rc',
2897
2898     # ${SOURCE_ROOT} for #include <ppapi/...>
2899     CPPPATH = [
2900       '${SOURCE_ROOT}',
2901     ],
2902
2903     EXTRA_CFLAGS = [],
2904     EXTRA_CXXFLAGS = [],
2905     EXTRA_LIBS = [],
2906     EXTRA_LINKFLAGS = ARGUMENTS.get('nacl_linkflags', '').split(':'),
2907
2908     # always optimize binaries
2909     CCFLAGS = ['-O2',
2910                '-g',
2911                '-fomit-frame-pointer',
2912                # This makes sure unwind/backtrace info is available for
2913                # all code locations.  Note build/untrusted.gypi uses it too.
2914                '-fasynchronous-unwind-tables',
2915                '-Wall',
2916                '-Wundef',
2917                '-fdiagnostics-show-option',
2918                '-pedantic',
2919                ] +
2920               werror_flags,
2921
2922     CFLAGS = ['-std=gnu99',
2923               ],
2924     CXXFLAGS = ['-std=gnu++98',
2925                 '-Wno-long-long',
2926                 ],
2927
2928     # This magic is copied from scons-2.0.1/engine/SCons/Defaults.py
2929     # where this pattern is used for _LIBDIRFLAGS, which produces -L
2930     # switches.  Here we are producing a -Wl,-rpath-link,DIR for each
2931     # element of LIBPATH, i.e. for each -LDIR produced.
2932     RPATH_LINK_FLAGS = '$( ${_concat(RPATHLINKPREFIX, LIBPATH, RPATHLINKSUFFIX,'
2933                        '__env__, RDirs, TARGET, SOURCE)} $)',
2934     RPATHLINKPREFIX = '-Wl,-rpath-link,',
2935     RPATHLINKSUFFIX = '',
2936
2937     LIBS = [],
2938     LINKFLAGS = ['${RPATH_LINK_FLAGS}'],
2939
2940     # These are settings for in-tree, non-browser tests to use.
2941     # They use libraries that circumvent the IRT-based implementations
2942     # in the public libraries.
2943     # Note that pthread_private is part of NONIRT_LIBS for PNaCl because
2944     # libc++ depends on it.
2945     NONIRT_LIBS = (['nacl_sys_private'] +
2946                    (['pthread_private'] if nacl_env.Bit('bitcode') else [])),
2947     PTHREAD_LIBS = ['pthread_private'],
2948     DYNCODE_LIBS = ['nacl_dyncode_private'],
2949     EXCEPTION_LIBS = ['nacl_exception_private'],
2950     LIST_MAPPINGS_LIBS = ['nacl_list_mappings_private'],
2951     )
2952
2953 def UsesAbiNote(env):
2954   """Return True if using a new-style GCC with .note.NaCl.ABI.* notes.
2955 This means there will always be an RODATA segment, even if just for the note."""
2956   return env.Bit('target_arm') and not env.Bit('bitcode')
2957
2958 nacl_env.AddMethod(UsesAbiNote)
2959
2960 def UnderWindowsCoverage(env):
2961   """Return True if using running on coverage under windows."""
2962   if 'TRUSTED_ENV' not in env:
2963     return False
2964   return env['TRUSTED_ENV'].Bit('coverage_enabled') and env.Bit('host_windows')
2965
2966 nacl_env.AddMethod(UnderWindowsCoverage)
2967
2968 def AllowNonStableBitcode(env, allow_sb_translator=False):
2969   """ This modifies the environment to allow features that aren't part
2970       of PNaCl's stable ABI.  If tests using these features should be
2971       skipped entirely, this returns False.  Otherwise, on success, it
2972       returns True.
2973   """
2974   if env.Bit('bitcode') and env.Bit('skip_nonstable_bitcode'):
2975     return False
2976   # The PNaCl sandboxed translator (for the most part) only accepts stable
2977   # bitcode, so in most cases we skip building non-stable tests.
2978   # However, there are some limited cases like debug information which
2979   # we support but do not guarantee stability. Tests targeting such cases
2980   # can opt-in to testing w/ allow_sb_translator=True.
2981   if env.Bit('use_sandboxed_translator') and not allow_sb_translator:
2982     return False
2983   # Change environment to skip finalization step.
2984   env.SetBits('nonstable_bitcode')
2985   return True
2986
2987 nacl_env.AddMethod(AllowNonStableBitcode)
2988
2989
2990 def AllowInlineAssembly(env):
2991   """ This modifies the environment to allow inline assembly in
2992       untrusted code.  If the environment cannot be modified to allow
2993       inline assembly, it returns False.  Otherwise, on success, it
2994       returns True.
2995   """
2996   if env.Bit('bitcode'):
2997     # For each architecture, we only attempt to make our inline
2998     # assembly code work with one untrusted-code toolchain.  For x86,
2999     # we target GCC, but not PNaCl/Clang, because the latter's
3000     # assembly support has various quirks that we don't want to have
3001     # to debug.  For ARM, we target PNaCl/Clang, because that is the
3002     # only current ARM toolchain.  One day, we will have an ARM GCC
3003     # toolchain, and we will no longer need to use inline assembly
3004     # with PNaCl/Clang at all.
3005     if not (env.Bit('target_arm') or env.Bit('target_mips32')):
3006       return False
3007     # Inline assembly does not work in pexes.
3008     if env.Bit('pnacl_generate_pexe'):
3009       return False
3010     env.AddBiasForPNaCl()
3011     env.PNaClForceNative()
3012   return True
3013
3014 nacl_env.AddMethod(AllowInlineAssembly)
3015
3016
3017 # TODO(mseaborn): Enable this unconditionally once the C code on the
3018 # Chromium side compiles successfully with this warning.
3019 if not enable_chrome:
3020   nacl_env.Append(CFLAGS=['-Wstrict-prototypes'])
3021
3022 # This is the address at which a user executable is expected to place its
3023 # data segment in order to be compatible with the integrated runtime (IRT)
3024 # library.  This address should not be changed lightly.
3025 irt_compatible_rodata_addr = 0x10000000
3026 # This is the address at which the IRT's own code will be located.
3027 # It must be below irt_compatible_rodata and leave enough space for
3028 # the code segment of the IRT.  It should be as close as possible to
3029 # irt_compatible_rodata so as to leave the maximum contiguous area
3030 # available for the dynamic code loading area that falls below it.
3031 # This can be adjusted as necessary for the actual size of the IRT code.
3032 irt_code_addr = irt_compatible_rodata_addr - (6 << 20) # max 6M IRT code
3033 # This is the address at which the IRT's own data will be located.  The
3034 # 32-bit sandboxes limit the address space to 1GB; the initial thread's
3035 # stack sits at the top of the address space and extends down for
3036 # NACL_DEFAULT_STACK_MAX (src/trusted/service_runtime/sel_ldr.h) below.
3037 # So this must be below there, and leave enough space for the IRT's own
3038 # data segment.  It should be as high as possible so as to leave the
3039 # maximum contiguous area available for the user's data and break below.
3040 # This can be adjusted as necessary for the actual size of the IRT data
3041 # (that is RODATA, rounded up to 64k, plus writable data).
3042 # 1G (address space) - 16M (NACL_DEFAULT_STACK_MAX) - 1MB (IRT rodata+data)
3043 irt_data_addr = (1 << 30) - (16 << 20) - (1 << 20)
3044
3045 nacl_env.Replace(
3046     IRT_DATA_REGION_START = '%#.8x' % irt_compatible_rodata_addr,
3047     # Load addresses of the IRT's code and data segments.
3048     IRT_BLOB_CODE_START = '%#.8x' % irt_code_addr,
3049     IRT_BLOB_DATA_START = '%#.8x' % irt_data_addr,
3050     )
3051
3052 def TestsUsePublicListMappingsLib(env):
3053   """Use the public list_mappings library for in-tree tests."""
3054   env.Replace(LIST_MAPPINGS_LIBS=['nacl_list_mappings'])
3055
3056 def TestsUsePublicLibs(env):
3057   """Change the environment so it uses public libraries for in-tree tests."""
3058   env.Replace(NONIRT_LIBS=['pthread'] if env.Bit('bitcode') else [],
3059               PTHREAD_LIBS=['pthread'],
3060               DYNCODE_LIBS=['nacl_dyncode', 'nacl'],
3061               EXCEPTION_LIBS=['nacl_exception', 'nacl'])
3062
3063 # glibc is incompatible with libpthread_private and libnacl_sys_private.
3064 if nacl_env.Bit('nacl_glibc'):
3065   nacl_env.Replace(NONIRT_LIBS=[],
3066                    PTHREAD_LIBS=['pthread'])
3067
3068 # These add on to those set in pre_base_env, above.
3069 nacl_env.Append(
3070     CPPDEFINES = [
3071         # This ensures that UINT32_MAX gets defined.
3072         ['__STDC_LIMIT_MACROS', '1'],
3073         # This ensures that PRId64 etc. get defined.
3074         ['__STDC_FORMAT_MACROS', '1'],
3075         # _GNU_SOURCE ensures that strtof() gets declared.
3076         ['_GNU_SOURCE', 1],
3077         # strdup, and other common stuff
3078         ['_BSD_SOURCE', '1'],
3079         ['_POSIX_C_SOURCE', '199506'],
3080         ['_XOPEN_SOURCE', '600'],
3081
3082         ['DYNAMIC_ANNOTATIONS_ENABLED', '1' ],
3083         ['DYNAMIC_ANNOTATIONS_PREFIX', 'NACL_' ],
3084
3085         ['NACL_WINDOWS', '0'],
3086         ['NACL_OSX', '0'],
3087         ['NACL_LINUX', '0'],
3088         ['NACL_ANDROID', '0'],
3089         ],
3090     )
3091
3092 def FixWindowsAssembler(env):
3093   if env.Bit('host_windows'):
3094     # NOTE: This is needed because Windows builds are case-insensitive.
3095     # Without this we use nacl-as, which doesn't handle include directives, etc.
3096     env.Replace(ASCOM='${CCCOM}')
3097
3098 FixWindowsAssembler(nacl_env)
3099
3100 # Look in the local include and lib directories before the toolchain's.
3101 nacl_env['INCLUDE_DIR'] = '${TARGET_ROOT}/include'
3102 # Remove the default $LIB_DIR element so that we prepend it without duplication.
3103 # Using PrependUnique alone would let it stay last, where we want it first.
3104 nacl_env.FilterOut(LIBPATH=['${LIB_DIR}'])
3105 nacl_env.PrependUnique(
3106     CPPPATH = ['${INCLUDE_DIR}'],
3107     LIBPATH = ['${LIB_DIR}'],
3108     )
3109
3110 if nacl_env.Bit('bitcode'):
3111   # passing -O when linking requests LTO, which does additional global
3112   # optimizations at link time
3113   nacl_env.Append(LINKFLAGS=['-O3'])
3114   if not nacl_env.Bit('nacl_glibc'):
3115     nacl_env.Append(LINKFLAGS=['-static'])
3116
3117   if nacl_env.Bit('translate_fast'):
3118     nacl_env.Append(LINKFLAGS=['-Xlinker', '-translate-fast'])
3119     nacl_env.Append(TRANSLATEFLAGS=['-translate-fast'])
3120
3121   # With pnacl's clang base/ code uses the "override" keyword.
3122   nacl_env.Append(CXXFLAGS=['-Wno-c++11-extensions'])
3123   # Allow extraneous semicolons.  (Until these are removed.)
3124   # http://code.google.com/p/nativeclient/issues/detail?id=2861
3125   nacl_env.Append(CCFLAGS=['-Wno-extra-semi'])
3126   # Allow unused private fields.  (Until these are removed.)
3127   # http://code.google.com/p/nativeclient/issues/detail?id=2861
3128   nacl_env.Append(CCFLAGS=['-Wno-unused-private-field'])
3129
3130 # We use a special environment for building the IRT image because it must
3131 # always use the newlib toolchain, regardless of --nacl_glibc.  We clone
3132 # it from nacl_env here, before too much other cruft has been added.
3133 # We do some more magic below to instantiate it the way we need it.
3134 nacl_irt_env = nacl_env.Clone(
3135     BUILD_TYPE = 'nacl_irt',
3136     BUILD_TYPE_DESCRIPTION = 'NaCl IRT build',
3137     NACL_BUILD_FAMILY = 'UNTRUSTED_IRT',
3138 )
3139
3140 # Provide access to the IRT build environment from the default environment
3141 # which is needed when compiling custom IRT for testing purposes.
3142 nacl_env['NACL_IRT_ENV'] = nacl_irt_env
3143
3144 # Since we don't build src/untrusted/pthread/nacl.scons in
3145 # nacl_irt_env, we must tell the IRT how to find the pthread.h header.
3146 nacl_irt_env.Append(CPPPATH='${MAIN_DIR}/src/untrusted/pthread')
3147
3148 # Map certain flag bits to suffices on the build output.  This needs to
3149 # happen pretty early, because it affects any concretized directory names.
3150 target_variant_map = [
3151     ('bitcode', 'pnacl'),
3152     ('translate_fast', 'fast'),
3153     ('nacl_pic', 'pic'),
3154     ('use_sandboxed_translator', 'sbtc'),
3155     ('nacl_glibc', 'glibc'),
3156     ('pnacl_generate_pexe', 'pexe'),
3157     ('nonsfi_nacl', 'nonsfi'),
3158     ]
3159 for variant_bit, variant_suffix in target_variant_map:
3160   if nacl_env.Bit(variant_bit):
3161     nacl_env['TARGET_VARIANT'] += '-' + variant_suffix
3162
3163 if nacl_env.Bit('bitcode'):
3164   nacl_env['TARGET_VARIANT'] += '-clang'
3165
3166 nacl_env.Replace(TESTRUNNER_LIBS=['testrunner'])
3167 # TODO(mseaborn): Drop this once chrome side has inlined this.
3168 nacl_env.Replace(PPAPI_LIBS=['ppapi'])
3169
3170 # TODO(mseaborn): Make nacl-glibc-based static linking work with just
3171 # "-static", without specifying a linker script.
3172 # See http://code.google.com/p/nativeclient/issues/detail?id=1298
3173 def GetLinkerScriptBaseName(env):
3174   if env.Bit('build_x86_64'):
3175     return 'elf_x86_64_nacl'
3176   else:
3177     return 'elf_i386_nacl'
3178
3179 if (nacl_env.Bit('nacl_glibc') and
3180     nacl_env.Bit('nacl_static_link')):
3181   nacl_env.Append(LINKFLAGS=['-static'])
3182   if nacl_env.Bit('target_x86'):
3183     # The "-lc" is necessary because libgcc_eh depends on libc but for
3184     # some reason nacl-gcc is not linking with "--start-group/--end-group".
3185     nacl_env.Append(LINKFLAGS=[
3186         '-T', 'ldscripts/%s.x.static' % GetLinkerScriptBaseName(nacl_env),
3187         '-lc'])
3188
3189 if nacl_env.Bit('running_on_valgrind'):
3190   nacl_env.Append(CCFLAGS = ['-g', '-Wno-overlength-strings',
3191                              '-fno-optimize-sibling-calls'],
3192                   CPPDEFINES = [['DYNAMIC_ANNOTATIONS_ENABLED', '1' ],
3193                                 ['DYNAMIC_ANNOTATIONS_PREFIX', 'NACL_' ]])
3194   # With GLibC, libvalgrind.so is preloaded at runtime.
3195   # With Newlib, it has to be linked in.
3196   if not nacl_env.Bit('nacl_glibc'):
3197     nacl_env.Append(LINKFLAGS = ['-Wl,-u,have_nacl_valgrind_interceptors'],
3198                     LIBS = ['valgrind'])
3199
3200 environment_list.append(nacl_env)
3201
3202 if not nacl_env.Bit('nacl_glibc'):
3203   # These are all specific to nacl-newlib so we do not include them
3204   # when building against nacl-glibc.  The functionality of
3205   # pthread/startup/stubs/nosys is provided by glibc.  The valgrind
3206   # code currently assumes nc_threads.
3207   nacl_env.Append(
3208       BUILD_SCONSCRIPTS = [
3209         ####  ALPHABETICALLY SORTED ####
3210         'src/untrusted/pthread/nacl.scons',
3211         'src/untrusted/stubs/nacl.scons',
3212         'src/untrusted/nosys/nacl.scons',
3213         ####  ALPHABETICALLY SORTED ####
3214       ])
3215 nacl_env.Append(
3216     BUILD_SCONSCRIPTS = [
3217     ####  ALPHABETICALLY SORTED ####
3218     'src/nonsfi/irt/build.scons',
3219     'src/nonsfi/linux/nacl.scons',
3220     'src/nonsfi/loader/build.scons',
3221     'src/shared/gio/nacl.scons',
3222     'src/shared/imc/nacl.scons',
3223     'src/shared/ldr/nacl.scons',
3224     'src/shared/platform/nacl.scons',
3225     'src/shared/srpc/nacl.scons',
3226     'src/trusted/service_runtime/nacl.scons',
3227     'src/trusted/validator/nacl.scons',
3228     'src/trusted/weak_ref/nacl.scons',
3229     'src/untrusted/crash_dump/nacl.scons',
3230     'src/untrusted/irt/nacl_headers.scons',
3231     'src/untrusted/minidump_generator/nacl.scons',
3232     'src/untrusted/nacl/nacl.scons',
3233     'src/untrusted/valgrind/nacl.scons',
3234     ####  ALPHABETICALLY SORTED ####
3235 ])
3236 nacl_env.AddChromeFilesFromGroup('untrusted_scons_files')
3237
3238 # These are tests that are worthwhile to run in IRT variant only.
3239 irt_only_tests = [
3240     #### ALPHABETICALLY SORTED ####
3241     'tests/irt/nacl.scons',
3242     'tests/irt_compatibility/nacl.scons',
3243     'tests/sbrk/nacl.scons',
3244     'tests/translator_size_limits/nacl.scons',
3245     ]
3246
3247 # These are tests that are worthwhile to run in both IRT and non-IRT variants.
3248 # The nacl_irt_test mode runs them in the IRT variants.
3249 irt_variant_tests = [
3250     #### ALPHABETICALLY SORTED ####
3251     'tests/app_lib/nacl.scons',
3252     'tests/bigalloc/nacl.scons',
3253     'tests/callingconv/nacl.scons',
3254     'tests/callingconv_ppapi/nacl.scons',
3255     'tests/callingconv_case_by_case/nacl.scons',
3256     'tests/clock/nacl.scons',
3257     'tests/common/nacl.scons',
3258     'tests/compiler_thread_suspension/nacl.scons',
3259     'tests/computed_gotos/nacl.scons',
3260     'tests/data_below_data_start/nacl.scons',
3261     'tests/data_not_executable/nacl.scons',
3262     'tests/debug_stub/nacl.scons',
3263     'tests/dup/nacl.scons',
3264     'tests/dynamic_code_loading/nacl.scons',
3265     'tests/dynamic_linking/nacl.scons',
3266     'tests/egyptian_cotton/nacl.scons',
3267     'tests/environment_variables/nacl.scons',
3268     'tests/exception_test/nacl.scons',
3269     'tests/fdopen_test/nacl.scons',
3270     'tests/fib/nacl.scons',
3271     'tests/file/nacl.scons',
3272     'tests/fixedfeaturecpu/nacl.scons',
3273     'tests/futexes/nacl.scons',
3274     'tests/gc_instrumentation/nacl.scons',
3275     'tests/gdb/nacl.scons',
3276     'tests/glibc_file64_test/nacl.scons',
3277     'tests/glibc_static_test/nacl.scons',
3278     'tests/glibc_syscall_wrappers/nacl.scons',
3279     'tests/glibc_socket_wrappers/nacl.scons',
3280     'tests/hello_world/nacl.scons',
3281     'tests/imc_shm_mmap/nacl.scons',
3282     'tests/includability/nacl.scons',
3283     'tests/infoleak/nacl.scons',
3284     'tests/libc/nacl.scons',
3285     'tests/libc_free_hello_world/nacl.scons',
3286     'tests/list_mappings/nacl.scons',
3287     'tests/longjmp/nacl.scons',
3288     'tests/loop/nacl.scons',
3289     'tests/mandel/nacl.scons',
3290     'tests/math/nacl.scons',
3291     'tests/memcheck_test/nacl.scons',
3292     'tests/mmap/nacl.scons',
3293     'tests/mmap_main_nexe/nacl.scons',
3294     'tests/mmap_prot_exec/nacl.scons',
3295     'tests/mmap_race_protect/nacl.scons',
3296     'tests/nacl_log/nacl.scons',
3297     'tests/nameservice/nacl.scons',
3298     'tests/nanosleep/nacl.scons',
3299     'tests/nonsfi/nacl.scons',
3300     'tests/noop/nacl.scons',
3301     'tests/nrd_xfer/nacl.scons',
3302     'tests/nthread_nice/nacl.scons',
3303     'tests/null/nacl.scons',
3304     'tests/nullptr/nacl.scons',
3305     'tests/pagesize/nacl.scons',
3306     'tests/performance/nacl.scons',
3307     'tests/pnacl_abi/nacl.scons',
3308     'tests/pnacl_dynamic_loading/nacl.scons',
3309     'tests/pnacl_native_objects/nacl.scons',
3310     'tests/process_create/nacl.scons',
3311     'tests/random/nacl.scons',
3312     'tests/redir/nacl.scons',
3313     'tests/rodata_not_writable/nacl.scons',
3314     'tests/run_py/nacl.scons',
3315     'tests/sel_ldr/nacl.scons',
3316     'tests/sel_ldr_seccomp/nacl.scons',
3317     'tests/sel_main_chrome/nacl.scons',
3318     'tests/signal_handler/nacl.scons',
3319     'tests/simd/nacl.scons',
3320     'tests/sleep/nacl.scons',
3321     'tests/srpc/nacl.scons',
3322     'tests/srpc_hw/nacl.scons',
3323     'tests/srpc_message/nacl.scons',
3324     'tests/stack_alignment/nacl.scons',
3325     'tests/stubout_mode/nacl.scons',
3326     'tests/subprocess/nacl.scons',
3327     'tests/sysbasic/nacl.scons',
3328     'tests/syscall_return_regs/nacl.scons',
3329     'tests/syscall_return_sandboxing/nacl.scons',
3330     'tests/syscalls/nacl.scons',
3331     'tests/thread_capture/nacl.scons',
3332     'tests/threads/nacl.scons',
3333     'tests/time/nacl.scons',
3334     'tests/tls/nacl.scons',
3335     'tests/tls_perf/nacl.scons',
3336     'tests/tls_segment_x86_32/nacl.scons',
3337     'tests/toolchain/nacl.scons',
3338     'tests/toolchain/arm/nacl.scons',
3339     'tests/toolchain/mips/nacl.scons',
3340     'tests/unittests/shared/platform/nacl.scons',
3341     'tests/untrusted_check/nacl.scons',
3342     'tests/unwind_restores_regs/nacl.scons',
3343     #### ALPHABETICALLY SORTED ####
3344     # NOTE: The following tests are really IRT-only tests, but they
3345     # are in this category so that they can generate libraries (which
3346     # works in nacl_env but not in nacl_irt_test_env) while also
3347     # adding tests to nacl_irt_test_env.
3348     'tests/inbrowser_test_runner/nacl.scons',
3349     'tests/untrusted_crash_dump/nacl.scons',
3350     'tests/untrusted_minidump/nacl.scons',
3351 ]
3352
3353 # These are tests that are NOT worthwhile to run in an IRT variant.
3354 # In some cases, that's because they are browser tests which always
3355 # use the IRT.  In others, it's because they are special-case tests
3356 # that are incompatible with having an IRT loaded.
3357 nonvariant_tests = [
3358     #### ALPHABETICALLY SORTED ####
3359     'tests/barebones/nacl.scons',
3360     'tests/chrome_extension/nacl.scons',
3361     'tests/custom_desc/nacl.scons',
3362     'tests/faulted_thread_queue/nacl.scons',
3363     'tests/gold_plugin/nacl.scons',
3364     'tests/imc_sockets/nacl.scons',
3365     'tests/minnacl/nacl.scons',
3366     'tests/multiple_sandboxes/nacl.scons',
3367     # Potential issue with running them:
3368     # http://code.google.com/p/nativeclient/issues/detail?id=2092
3369     # See also the comment in "buildbot/buildbot_standard.py"
3370     'tests/pnacl_shared_lib_test/nacl.scons',
3371     'tests/pwrite/nacl.scons',
3372     'tests/signal_handler_single_step/nacl.scons',
3373     'tests/thread_suspension/nacl.scons',
3374     'tests/trusted_crash/crash_in_syscall/nacl.scons',
3375     'tests/trusted_crash/osx_crash_filter/nacl.scons',
3376     'tests/trusted_crash/osx_crash_forwarding/nacl.scons',
3377     'tests/unittests/shared/imc/nacl.scons',
3378     'tests/unittests/shared/srpc/nacl.scons',
3379     #### ALPHABETICALLY SORTED ####
3380 ]
3381
3382 nacl_env.Append(BUILD_SCONSCRIPTS=nonvariant_tests)
3383 nacl_env.AddChromeFilesFromGroup('nonvariant_test_scons_files')
3384 nacl_env.Append(BUILD_SCONSCRIPTS=irt_variant_tests)
3385 nacl_env.AddChromeFilesFromGroup('irt_variant_test_scons_files')
3386
3387 # Defines TESTS_TO_RUN_INBROWSER.
3388 SConscript('tests/inbrowser_test_runner/selection.scons',
3389            exports=['nacl_env'])
3390
3391 # Possibly install a toolchain by downloading it
3392 # TODO: explore using a less heavy weight mechanism
3393 # NOTE: this uses stuff from: site_scons/site_tools/naclsdk.py
3394 import SCons.Script
3395
3396 SCons.Script.AddOption('--download',
3397                        dest='download',
3398                        metavar='DOWNLOAD',
3399                        default=False,
3400                        action='store_true',
3401                        help='deprecated - allow tools to download')
3402
3403 if nacl_env.GetOption('download'):
3404   print '@@@@ --download is deprecated, use gclient runhooks --force'
3405   nacl_sync_env = nacl_env.Clone()
3406   nacl_sync_env['ENV'] = os.environ
3407   nacl_sync_env.Execute('gclient runhooks --force')
3408
3409
3410 def NaClSharedLibrary(env, lib_name, *args, **kwargs):
3411   env_shared = env.Clone(COMPONENT_STATIC=False)
3412   soname = SCons.Util.adjustixes(lib_name, 'lib', '.so')
3413   env_shared.AppendUnique(SHLINKFLAGS=['-Wl,-soname,%s' % (soname)])
3414   return env_shared.ComponentLibrary(lib_name, *args, **kwargs)
3415
3416 nacl_env.AddMethod(NaClSharedLibrary)
3417
3418 def NaClSdkLibrary(env, lib_name, *args, **kwargs):
3419   n = [env.ComponentLibrary(lib_name, *args, **kwargs)]
3420   if not env.Bit('nacl_disable_shared'):
3421     n.append(env.NaClSharedLibrary(lib_name, *args, **kwargs))
3422   return n
3423
3424 nacl_env.AddMethod(NaClSdkLibrary)
3425
3426
3427 # Special environment for untrusted test binaries that use raw syscalls
3428 def RawSyscallObjects(env, sources):
3429   raw_syscall_env = env.Clone()
3430   raw_syscall_env.Append(
3431     CPPDEFINES = [
3432       ['USE_RAW_SYSCALLS', '1'],
3433       ['NACL_BUILD_ARCH', '${BUILD_ARCHITECTURE}' ],
3434       ['NACL_BUILD_SUBARCH', '${BUILD_SUBARCH}' ],
3435       ['NACL_TARGET_ARCH', '${TARGET_ARCHITECTURE}' ],
3436       ['NACL_TARGET_SUBARCH', '${TARGET_SUBARCH}' ],
3437       ],
3438   )
3439   objects = []
3440   for source_file in sources:
3441     target_name = 'raw_' + os.path.basename(source_file).rstrip('.c')
3442     object = raw_syscall_env.ComponentObject(target_name,
3443                                              source_file)
3444     objects.append(object)
3445   return objects
3446
3447 nacl_env.AddMethod(RawSyscallObjects)
3448
3449
3450 # The IRT-building environment was cloned from nacl_env, but it should
3451 # ignore the --nacl_glibc, nacl_pic=1 and bitcode=1 switches.
3452 # We have to reinstantiate the naclsdk.py magic after clearing those flags,
3453 # so it regenerates the tool paths right.
3454 # TODO(mcgrathr,bradnelson): could get cleaner if naclsdk.py got folded back in.
3455 nacl_irt_env.ClearBits('nacl_glibc')
3456 nacl_irt_env.ClearBits('nacl_pic')
3457 # We build the IRT using the nnacl TC even when the pnacl TC is used otherwise.
3458 if nacl_irt_env.Bit('target_mips32') or nacl_irt_env.Bit('target_x86_64'):
3459   nacl_irt_env.SetBits('bitcode')
3460 else:
3461   nacl_irt_env.ClearBits('bitcode')
3462 nacl_irt_env.ClearBits('pnacl_generate_pexe')
3463 nacl_irt_env.ClearBits('use_sandboxed_translator')
3464 nacl_irt_env.Tool('naclsdk')
3465 # These are unfortunately clobbered by running Tool, which
3466 # we needed to do to get the destination directory reset.
3467 # We want all the same values from nacl_env.
3468 nacl_irt_env.Replace(EXTRA_CFLAGS=nacl_env['EXTRA_CFLAGS'],
3469                      EXTRA_CXXFLAGS=nacl_env['EXTRA_CXXFLAGS'],
3470                      CCFLAGS=nacl_env['CCFLAGS'],
3471                      CFLAGS=nacl_env['CFLAGS'],
3472                      CXXFLAGS=nacl_env['CXXFLAGS'])
3473 FixWindowsAssembler(nacl_irt_env)
3474 # Make it find the libraries it builds, rather than the SDK ones.
3475 nacl_irt_env.Replace(LIBPATH='${LIB_DIR}')
3476
3477 if nacl_irt_env.Bit('bitcode'):
3478   if nacl_irt_env.Bit('target_x86_64'):
3479     nacl_irt_env.Append(CCFLAGS=['--target=x86_64-unknown-nacl'])
3480     nacl_irt_env.Append(LINKFLAGS=['--target=x86_64-unknown-nacl',
3481                                    '--pnacl-allow-translate',
3482                                    '-arch', 'x86-64'])
3483   elif nacl_irt_env.Bit('target_mips32'):
3484     # Disable the PNaCl IRT verifier since it will complain about
3485     # __executable_start symbol not being a valid external symbol.
3486     nacl_irt_env.Append(LINKFLAGS=['--pnacl-disable-abi-check'])
3487
3488 # The IRT is C only, don't link with the C++ linker so that it doesn't
3489 # start depending on the C++ standard library and (in the case of
3490 # libc++) pthread.
3491 nacl_irt_env.Replace(LINK=(nacl_irt_env['LINK'].
3492                            replace('pnacl-clang++', 'pnacl-clang')))
3493
3494 if nacl_irt_env.Bit('bitcode'):
3495   nacl_irt_env.Append(LINKFLAGS=['--pnacl-allow-native'])
3496
3497 # All IRT code must avoid direct use of the TLS ABI register, which
3498 # is reserved for user TLS.  Instead, ensure all TLS accesses use a
3499 # call to __nacl_read_tp, which the IRT code overrides to segregate
3500 # IRT-private TLS from user TLS. This only applies to mips now, on
3501 # other platforms we modify the TLS register through tls_edit as a
3502 # post process.
3503 if nacl_irt_env.Bit('target_mips32'):
3504   nacl_irt_env.Append(LINKFLAGS=['-Wt,-mtls-use-call'])
3505
3506 # TODO(mcgrathr): Clean up uses of these methods.
3507 def AddLibraryDummy(env, nodes):
3508   return nodes
3509 nacl_irt_env.AddMethod(AddLibraryDummy, 'AddLibraryToSdk')
3510
3511 def AddObjectInternal(env, nodes):
3512   return env.Replicate('${LIB_DIR}', nodes)
3513 nacl_env.AddMethod(AddObjectInternal, 'AddObjectToSdk')
3514 nacl_irt_env.AddMethod(AddObjectInternal, 'AddObjectToSdk')
3515
3516 def IrtNaClSdkLibrary(env, lib_name, *args, **kwargs):
3517   env.ComponentLibrary(lib_name, *args, **kwargs)
3518 nacl_irt_env.AddMethod(IrtNaClSdkLibrary, 'NaClSdkLibrary')
3519
3520 nacl_irt_env.AddMethod(SDKInstallBin)
3521
3522 # Populate the internal include directory when AddHeaderToSdk
3523 # is used inside nacl_env.
3524 def AddHeaderInternal(env, nodes, subdir='nacl'):
3525   dir = '${INCLUDE_DIR}'
3526   if subdir is not None:
3527     dir += '/' + subdir
3528   n = env.Replicate(dir, nodes)
3529   return n
3530
3531 nacl_irt_env.AddMethod(AddHeaderInternal, 'AddHeaderToSdk')
3532
3533 def PublishHeader(env, nodes, subdir):
3534   if ('install' in COMMAND_LINE_TARGETS or
3535       'install_headers' in COMMAND_LINE_TARGETS):
3536     dir = env.GetAbsDirArg('includedir', 'install_headers')
3537     if subdir is not None:
3538       dir += '/' + subdir
3539     n = env.Install(dir, nodes)
3540     env.Alias('install', env.Alias('install_headers', n))
3541     return n
3542
3543 def PublishLibrary(env, nodes):
3544   env.Alias('build_lib', nodes)
3545
3546   if ('install' in COMMAND_LINE_TARGETS or
3547       'install_lib' in COMMAND_LINE_TARGETS):
3548     dir = env.GetAbsDirArg('libdir', 'install_lib')
3549     n = env.Install(dir, nodes)
3550     env.Alias('install', env.Alias('install_lib', n))
3551     return n
3552
3553 def NaClAddHeader(env, nodes, subdir='nacl'):
3554   n = AddHeaderInternal(env, nodes, subdir)
3555   PublishHeader(env, n, subdir)
3556   return n
3557 nacl_env.AddMethod(NaClAddHeader, 'AddHeaderToSdk')
3558
3559 def NaClAddLibrary(env, nodes):
3560   nodes = env.Replicate('${LIB_DIR}', nodes)
3561   PublishLibrary(env, nodes)
3562   return nodes
3563 nacl_env.AddMethod(NaClAddLibrary, 'AddLibraryToSdk')
3564
3565 def NaClAddObject(env, nodes):
3566   lib_nodes = env.Replicate('${LIB_DIR}', nodes)
3567   PublishLibrary(env, lib_nodes)
3568   return lib_nodes
3569 nacl_env.AddMethod(NaClAddObject, 'AddObjectToSdk')
3570
3571 # We want to do this for nacl_env when not under --nacl_glibc,
3572 # but for nacl_irt_env whether or not under --nacl_glibc, so
3573 # we do it separately for each after making nacl_irt_env and
3574 # clearing its Bit('nacl_glibc').
3575 def AddImplicitLibs(env):
3576   implicit_libs = []
3577
3578   # Require the pnacl_irt_shim for pnacl x86-64 and arm.
3579   # Use -B to have the compiler look for the fresh libpnacl_irt_shim.a.
3580   if ( env.Bit('bitcode') and
3581        (env.Bit('target_x86_64') or env.Bit('target_arm'))
3582        and env['NACL_BUILD_FAMILY'] != 'UNTRUSTED_IRT'):
3583     # Note: without this hack ibpnacl_irt_shim.a will be deleted
3584     #       when "built_elsewhere=1"
3585     #       Since we force the build in a previous step the dependency
3586     #       is not really needed.
3587     #       Note: the "precious" mechanism did not work in this case
3588     if not env.Bit('built_elsewhere'):
3589       if env.Bit('enable_chrome_side'):
3590         implicit_libs += ['libpnacl_irt_shim.a']
3591
3592   if not env.Bit('nacl_glibc'):
3593     # These are automatically linked in by the compiler, either directly
3594     # or via the linker script that is -lc.  In the non-glibc build, we
3595     # are the ones providing these files, so we need dependencies.
3596     # The ComponentProgram method (site_scons/site_tools/component_builders.py)
3597     # adds dependencies on env['IMPLICIT_LIBS'] if that's set.
3598     if env.Bit('bitcode'):
3599       implicit_libs += ['libnacl.a']
3600     else:
3601       implicit_libs += ['crt1.o',
3602                         'libnacl.a',
3603                         'crti.o',
3604                         'crtn.o']
3605       # TODO(mcgrathr): multilib nonsense defeats -B!  figure out a better way.
3606       if GetTargetPlatform() == 'x86-32':
3607         implicit_libs.append(os.path.join('32', 'crt1.o'))
3608
3609   if implicit_libs != []:
3610     env['IMPLICIT_LIBS'] = [env.File(os.path.join('${LIB_DIR}', file))
3611                             for file in implicit_libs]
3612     # The -B<dir>/ flag is necessary to tell gcc to look for crt[1in].o there.
3613     env.Prepend(LINKFLAGS=['-B${LIB_DIR}/'])
3614
3615 AddImplicitLibs(nacl_env)
3616 AddImplicitLibs(nacl_irt_env)
3617
3618 nacl_irt_env.Append(
3619     BUILD_SCONSCRIPTS = [
3620         'src/shared/gio/nacl.scons',
3621         'src/shared/platform/nacl.scons',
3622         'src/shared/srpc/nacl.scons',
3623         'src/tools/tls_edit/build.scons',
3624         'src/untrusted/irt/nacl.scons',
3625         'src/untrusted/nacl/nacl.scons',
3626         'src/untrusted/stubs/nacl.scons',
3627         'tests/irt_private_pthread/nacl.scons',
3628     ])
3629 nacl_irt_env.AddChromeFilesFromGroup('untrusted_irt_scons_files')
3630
3631 environment_list.append(nacl_irt_env)
3632
3633 # Since browser_tests already use the IRT normally, those are fully covered
3634 # in nacl_env.  But the non_browser_tests don't use the IRT in nacl_env.
3635 # We want additional variants of those tests with the IRT, so we make
3636 # another environment and repeat them with that adjustment.
3637 nacl_irt_test_env = nacl_env.Clone(
3638     BUILD_TYPE = 'nacl_irt_test',
3639     BUILD_TYPE_DESCRIPTION = 'NaCl tests build with IRT',
3640     NACL_BUILD_FAMILY = 'UNTRUSTED_IRT_TESTS',
3641
3642     INCLUDE_DIR = nacl_env.Dir('${INCLUDE_DIR}'),
3643     LIB_DIR = nacl_env.Dir('${LIB_DIR}'),
3644     BUILD_SCONSCRIPTS = [],
3645     )
3646 nacl_irt_test_env.SetBits('tests_use_irt')
3647 if nacl_irt_test_env.Bit('enable_chrome_side'):
3648   nacl_irt_test_env.Replace(TESTRUNNER_LIBS=['testrunner_browser'])
3649
3650 nacl_irt_test_env.Append(BUILD_SCONSCRIPTS=irt_variant_tests)
3651 nacl_irt_test_env.AddChromeFilesFromGroup('irt_variant_test_scons_files')
3652 nacl_irt_test_env.Append(BUILD_SCONSCRIPTS=irt_only_tests)
3653 TestsUsePublicLibs(nacl_irt_test_env)
3654 TestsUsePublicListMappingsLib(nacl_irt_test_env)
3655
3656 # We add the following settings after creating nacl_irt_test_env because we
3657 # don't want them to be inherited by nacl_irt_test_env.
3658 if nacl_env.Bit('nonsfi_nacl'):
3659   # Not-IRT-using non-SFI code uses Linux syscalls directly.  Since this
3660   # involves using inline assembly, this requires turning off the PNaCl ABI
3661   # checker.
3662   nacl_env.SetBits('nonstable_bitcode')
3663   nacl_env.Append(LINKFLAGS=['--pnacl-disable-abi-check'])
3664   # Tell the PNaCl translator to link a Linux executable.
3665   nacl_env.Append(TRANSLATEFLAGS=['--noirt'])
3666
3667 # If a tests/.../nacl.scons file builds a library, we will just use
3668 # the one already built in nacl_env instead.
3669 def IrtTestDummyLibrary(*args, **kwargs):
3670   pass
3671 nacl_irt_test_env.AddMethod(IrtTestDummyLibrary, 'ComponentLibrary')
3672
3673 def IrtTestAddNodeToTestSuite(env, node, suite_name, node_name=None,
3674                               is_broken=False, is_flaky=False,
3675                               disable_irt_suffix=False):
3676   # The disable_irt_suffix argument is there for allowing tests
3677   # defined in nacl_irt_test_env to be part of chrome_browser_tests
3678   # (rather than part of chrome_browser_tests_irt).
3679   # TODO(mseaborn): But really, all of chrome_browser_tests should be
3680   # placed in nacl_irt_test_env rather than in nacl_env.
3681   suite_name = AddImplicitTestSuites(suite_name, node_name)
3682   if not disable_irt_suffix:
3683     if node_name is not None:
3684       node_name += '_irt'
3685     suite_name = [name + '_irt' for name in suite_name]
3686   # NOTE: This needs to be called directly to as we're overriding the
3687   #       prior version.
3688   return AddNodeToTestSuite(env, node, suite_name, node_name,
3689                             is_broken, is_flaky)
3690 nacl_irt_test_env.AddMethod(IrtTestAddNodeToTestSuite, 'AddNodeToTestSuite')
3691
3692 environment_list.append(nacl_irt_test_env)
3693
3694
3695 windows_coverage_env = windows_debug_env.Clone(
3696     tools = ['code_coverage'],
3697     BUILD_TYPE = 'coverage-win',
3698     BUILD_TYPE_DESCRIPTION = 'Windows code coverage build',
3699     # TODO(bradnelson): switch nacl to common testing process so this won't be
3700     #    needed.
3701     MANIFEST_FILE = None,
3702     COVERAGE_ANALYZER_DIR=r'..\third_party\coverage_analyzer\bin',
3703     COVERAGE_ANALYZER='$COVERAGE_ANALYZER_DIR\coverage_analyzer.exe',
3704 )
3705 # TODO(bradnelson): Switch nacl to common testing process so this won't be
3706 #                   needed. Ignoring instrumentation failure as that's easier
3707 #                   than trying to gate out the ones with asm we can't handle.
3708 windows_coverage_env['LINKCOM'] = windows_coverage_env.Action([
3709     windows_coverage_env.get('LINKCOM', []),
3710     '-$COVERAGE_VSINSTR /COVERAGE ${TARGET}'])
3711 windows_coverage_env.Append(LINKFLAGS = ['/NODEFAULTLIB:msvcrt'])
3712 AddDualLibrary(windows_coverage_env)
3713 environment_list.append(windows_coverage_env)
3714
3715 mac_coverage_env = mac_debug_env.Clone(
3716     tools = ['code_coverage'],
3717     BUILD_TYPE = 'coverage-mac',
3718     BUILD_TYPE_DESCRIPTION = 'MacOS code coverage build',
3719     # Strict doesnt't currently work for coverage because the path to gcov is
3720     # magically baked into the compiler.
3721     LIBS_STRICT = False,
3722 )
3723 AddDualLibrary(mac_coverage_env)
3724 environment_list.append(mac_coverage_env)
3725
3726 linux_coverage_env = linux_debug_env.Clone(
3727     tools = ['code_coverage'],
3728     BUILD_TYPE = 'coverage-linux',
3729     BUILD_TYPE_DESCRIPTION = 'Linux code coverage build',
3730     # Strict doesnt't currently work for coverage because the path to gcov is
3731     # magically baked into the compiler.
3732     LIBS_STRICT = False,
3733 )
3734
3735 linux_coverage_env.FilterOut(CCFLAGS=['-fPIE'])
3736 linux_coverage_env.Append(CCFLAGS=['-fPIC'])
3737
3738 linux_coverage_env['OPTIONAL_COVERAGE_LIBS'] = '$COVERAGE_LIBS'
3739 AddDualLibrary(linux_coverage_env)
3740 environment_list.append(linux_coverage_env)
3741
3742
3743 # Environment Massaging
3744 RELEVANT_CONFIG = ['NACL_BUILD_FAMILY',
3745                    'BUILD_TYPE',
3746                    'TARGET_ROOT',
3747                    'OBJ_ROOT',
3748                    'BUILD_TYPE_DESCRIPTION',
3749                    ]
3750
3751 MAYBE_RELEVANT_CONFIG = ['BUILD_OS',
3752                          'BUILD_ARCHITECTURE',
3753                          'BUILD_SUBARCH',
3754                          'TARGET_OS',
3755                          'TARGET_ARCHITECTURE',
3756                          'TARGET_SUBARCH',
3757                          ]
3758
3759 def DumpCompilerVersion(cc, env):
3760   if 'gcc' in cc:
3761     env.Execute(env.Action('set'))
3762     env.Execute(env.Action('${CC} -v -c'))
3763     env.Execute(env.Action('${CC} -print-search-dirs'))
3764     env.Execute(env.Action('${CC} -print-libgcc-file-name'))
3765   elif cc.startswith('cl'):
3766     import subprocess
3767     try:
3768       p = subprocess.Popen(env.subst('${CC} /V'),
3769                            bufsize=1000*1000,
3770                            stdout=subprocess.PIPE,
3771                            stderr=subprocess.PIPE)
3772       stdout, stderr = p.communicate()
3773       print stderr[0:stderr.find("\r")]
3774     except WindowsError:
3775       # If vcvars was not run before running SCons, we won't be able to find
3776       # the compiler at this point.  SCons has built in functions for finding
3777       # the compiler, but they haven't run yet.
3778       print 'Can not find the compiler, assuming SCons will find it later.'
3779   else:
3780     print "UNKNOWN COMPILER"
3781
3782
3783 def SanityCheckEnvironments(all_envs):
3784   # simple completeness check
3785   for env in all_envs:
3786     for tag in RELEVANT_CONFIG:
3787       assert tag in env, repr(tag)
3788       assert env[tag], repr(env[tag])
3789
3790
3791 def LinkTrustedEnv(selected_envs):
3792   # Collect build families and ensure that we have only one env per family.
3793   family_map = {}
3794   for env in selected_envs:
3795     family = env['NACL_BUILD_FAMILY']
3796     if family not in family_map:
3797       family_map[family] = env
3798     else:
3799       msg = 'You are using incompatible environments simultaneously\n'
3800       msg += '%s vs %s\n' % (env['BUILD_TYPE'],
3801                              family_map[family]['BUILD_TYPE'])
3802       msg += ('Please specfy the exact environments you require, e.g. '
3803               'MODE=dbg-host,nacl')
3804       raise Exception(msg)
3805
3806   # Set TRUSTED_ENV so that tests of untrusted code can locate sel_ldr
3807   # etc.  We set this on trusted envs too because some tests on
3808   # trusted envs run sel_ldr (e.g. using checked-in binaries).
3809   if 'TRUSTED' in family_map:
3810     for env in selected_envs:
3811       env['TRUSTED_ENV'] = family_map['TRUSTED']
3812       # Propagate some environment variables from the trusted environment,
3813       # in case some (e.g. Mac's DYLD_LIBRARY_PATH) are necessary for
3814       # running sel_ldr et al in untrusted environments' tests.
3815       for var in env['TRUSTED_ENV'].get('PROPAGATE_ENV', []):
3816         env['ENV'][var] = env['TRUSTED_ENV']['ENV'][var]
3817   if 'TRUSTED' not in family_map or 'UNTRUSTED' not in family_map:
3818     Banner('Warning: "--mode" did not specify both trusted and untrusted '
3819            'build environments.  As a result, many tests will not be run.')
3820
3821 def MakeBuildEnv():
3822   build_platform = GetBuildPlatform()
3823
3824   # Build Platform Base Function
3825   platform_func_map = {
3826       'win32' : MakeWindowsEnv,
3827       'cygwin': MakeWindowsEnv,
3828       'linux' : MakeGenericLinuxEnv,
3829       'linux2': MakeGenericLinuxEnv,
3830       'darwin': MakeMacEnv,
3831       }
3832   if sys.platform not in platform_func_map:
3833     raise UserError('Unrecognized host platform: %s', sys.platform)
3834   make_env_func = platform_func_map[sys.platform]
3835
3836   build_env = make_env_func(build_platform)
3837   build_env['IS_BUILD_ENV'] = True
3838
3839   # Building tls_edit depends on gio, platform, and validator_ragel.
3840   build_env['BUILD_SCONSCRIPTS'] = [
3841     # KEEP THIS SORTED PLEASE
3842     'src/shared/gio/build.scons',
3843     'src/shared/platform/build.scons',
3844     'src/trusted/validator_ragel/build.scons',
3845     ]
3846
3847   # The build environment is only used for intermediate steps and should
3848   # not be creating any targets. Aliases are used as means to add targets
3849   # to builds (IE, all_programs, all_libraries...etc.). Since we want to
3850   # share all of our build scripts but not define any aliases, we should
3851   # override the alias function and essentially stub it out.
3852   build_env.Alias = lambda env, target, source=[], actions=None, **kw : []
3853
3854   return build_env
3855
3856 def LinkBuildEnv(selected_envs):
3857   build_env_map = {
3858     'opt': opt_build_env,
3859     'dbg': dbg_build_env,
3860     }
3861
3862   # We need to find the optimization level in order to know which
3863   # build environment we want to use
3864   opt_level = None
3865   for env in selected_envs:
3866     if env.get('OPTIMIZATION_LEVEL', None):
3867       opt_level = env['OPTIMIZATION_LEVEL']
3868       break
3869
3870   build_env = build_env_map.get(opt_level, opt_build_env)
3871   for env in selected_envs:
3872     env['BUILD_ENV'] = build_env
3873
3874   # If the build environment is different from all the selected environments,
3875   # we will need to also append it to the selected environments so the targets
3876   # can be built.
3877   build_env_root = build_env.subst('${TARGET_ROOT}')
3878   for env in selected_envs:
3879     if build_env_root == env.subst('${TARGET_ROOT}'):
3880       break
3881   else:
3882     # Did not find a matching environment, append the build environment now.
3883     selected_envs.append(build_env)
3884
3885 def DumpEnvironmentInfo(selected_envs):
3886   if VerboseConfigInfo(pre_base_env):
3887     Banner("The following environments have been configured")
3888     for env in selected_envs:
3889       for tag in RELEVANT_CONFIG:
3890         assert tag in env, repr(tag)
3891         print "%s:  %s" % (tag, env.subst(env.get(tag)))
3892       for tag in MAYBE_RELEVANT_CONFIG:
3893         print "%s:  %s" % (tag, env.subst(env.get(tag)))
3894       cc = env.subst('${CC}')
3895       print 'CC:', cc
3896       asppcom = env.subst('${ASPPCOM}')
3897       print 'ASPPCOM:', asppcom
3898       DumpCompilerVersion(cc, env)
3899       print
3900     rev_file = 'toolchain/linux_x86_pnacl/pnacl_newlib/REV'
3901     if os.path.exists(rev_file):
3902       for line in open(rev_file).read().split('\n'):
3903         if "Revision:" in line:
3904           print "PNACL : %s" % line
3905
3906 def PnaclSetEmulatorForSandboxedTranslator(selected_envs):
3907   # Slip in emulator flags if necessary, for the sandboxed pnacl translator
3908   # on ARM, once emulator is actually known (vs in naclsdk.py, where it
3909   # is not yet known).
3910   for env in selected_envs:
3911     if (env.Bit('bitcode')
3912         and env.Bit('use_sandboxed_translator')
3913         and env.UsingEmulator()):
3914       # This must modify the LINK command itself, since LINKFLAGS may
3915       # be filtered (e.g., in barebones tests).
3916       env.Append(LINK=' --pnacl-use-emulator')
3917       env.Append(TRANSLATE=' --pnacl-use-emulator')
3918
3919
3920 # Blank out defaults.
3921 Default(None)
3922
3923 # Apply optional supplement if present in the directory tree.
3924 if os.path.exists(pre_base_env.subst('$MAIN_DIR/supplement/supplement.scons')):
3925   SConscript('supplement/supplement.scons', exports=['environment_list'])
3926
3927 # print sytem info (optionally)
3928 if VerboseConfigInfo(pre_base_env):
3929   Banner('SCONS ARGS:' + str(sys.argv))
3930   os.system(pre_base_env.subst('${PYTHON} tools/sysinfo.py'))
3931
3932 CheckArguments()
3933
3934 SanityCheckEnvironments(environment_list)
3935 selected_envs = FilterEnvironments(environment_list)
3936
3937 # If we are building NaCl, build nacl_irt too.  This works around it being
3938 # a separate mode due to the vagaries of scons when we'd really rather it
3939 # not be, while not requiring that every bot command line using --mode be
3940 # changed to list '...,nacl,nacl_irt' explicitly.
3941 if nacl_env in selected_envs:
3942   selected_envs.append(nacl_irt_env)
3943
3944 # The nacl_irt_test_env requires nacl_env to build things correctly.
3945 if nacl_irt_test_env in selected_envs and nacl_env not in selected_envs:
3946   selected_envs.append(nacl_env)
3947
3948 DumpEnvironmentInfo(selected_envs)
3949 LinkTrustedEnv(selected_envs)
3950
3951 # When building NaCl, any intermediate build tool that is used during the
3952 # build process must be built using the current build environment, not the
3953 # target. Create a build environment for this purpose and link it into
3954 # the selected environments
3955 dbg_build_env, opt_build_env = GenerateOptimizationLevels(MakeBuildEnv())
3956 LinkBuildEnv(selected_envs)
3957
3958 # This must happen after LinkTrustedEnv, since that is where TRUSTED_ENV
3959 # is finally set, and env.UsingEmulator() checks TRUSTED_ENV for the emulator.
3960 # This must also happen before BuildEnvironments.
3961 PnaclSetEmulatorForSandboxedTranslator(selected_envs)
3962
3963 BuildEnvironments(selected_envs)
3964
3965 # Change default to build everything, but not run tests.
3966 Default(['all_programs', 'all_bundles', 'all_test_programs', 'all_libraries'])
3967
3968
3969 # Sanity check whether we are ready to build nacl modules
3970 # NOTE: this uses stuff from: site_scons/site_tools/naclsdk.py
3971 if nacl_env.Bit('naclsdk_validate') and (nacl_env in selected_envs or
3972                                          nacl_irt_env in selected_envs):
3973   nacl_env.ValidateSdk()
3974
3975 if BROKEN_TEST_COUNT > 0:
3976   msg = "There are %d broken tests." % BROKEN_TEST_COUNT
3977   if GetOption('brief_comstr'):
3978     msg += " Add --verbose to the command line for more information."
3979   print msg
3980
3981 # separate warnings from actual build output
3982 Banner('B U I L D - O U T P U T:')