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