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