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