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