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