-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathSConstruct
2438 lines (2043 loc) · 84.3 KB
/
SConstruct
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
# -*- python -*-
# Copyright 2008 The Native Client Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can
# be found in the LICENSE file.
import atexit
import glob
import os
import stat
import subprocess
import sys
sys.path.append("./common")
from SCons.Errors import UserError
from SCons.Script import GetBuildFailures
import SCons.Warnings
SCons.Warnings.warningAsException()
# NOTE: Underlay for src/third_party_mod/gtest
# TODO: try to eliminate this hack
Dir('src/third_party_mod/gtest').addRepository(
Dir('#/../testing/gtest'))
Dir('tests/ppapi_tests').addRepository(Dir('#/../ppapi/tests'))
# ----------------------------------------------------------
# REPORT
# ----------------------------------------------------------
def PrintFinalReport():
"""This function is run just before scons exits and dumps various reports.
"""
# Note, these global declarations are not strictly necessary
global pre_base_env
global CMD_COUNTER
global ENV_COUNTER
if pre_base_env.Bit('target_stats'):
print
print '*' * 70
print 'COMMAND EXECUTION REPORT'
print '*' * 70
for k in sorted(CMD_COUNTER.keys()):
print "%4d %s" % (CMD_COUNTER[k], k)
print
print '*' * 70
print 'ENVIRONMENT USAGE REPORT'
print '*' * 70
for k in sorted(ENV_COUNTER.keys()):
print "%4d %s" % (ENV_COUNTER[k], k)
failures = GetBuildFailures()
if not failures:
return
print
print '*' * 70
print 'ERROR REPORT: %d failures' % len(failures)
print '*' * 70
print
for f in failures:
print "%s failed: %s\n" % (f.node, f.errstr)
atexit.register(PrintFinalReport)
def VerboseConfigInfo(env):
"Should we print verbose config information useful for bug reports"
if '--help' in sys.argv: return False
if env.Bit('prebuilt') or env.Bit('built_elsewhere'): return False
return env.Bit('sysinfo')
# ----------------------------------------------------------
# SANITY CHECKS
# ----------------------------------------------------------
# NOTE BitFromArgument(...) implicitly defines additional ACCEPTABLE_ARGUMENTS.
ACCEPTABLE_ARGUMENTS = set([
# TODO: add comments what these mean
# TODO: check which ones are obsolete
#### ASCII SORTED ####
# Use a destination directory other than the default "scons-out".
'DESTINATION_ROOT',
'DOXYGEN',
'MODE',
'SILENT',
# set build platform
'buildplatform',
# used for browser_tests
'chrome_browser_path',
# where should we store extrasdk libraries
'extra_sdk_lib_destination',
# where should we store extrasdk headers
'extra_sdk_include_destination',
# force emulator use by tests
'force_emulator',
# force sel_ldr use by tests
'force_sel_ldr',
# colon-separated list of compiler flags, e.g. "-g:-Wall".
'nacl_ccflags',
# colon-separated list of linker flags, e.g. "-lfoo:-Wl,-u,bar".
'nacl_linkflags',
# colon-separated list of pnacl bcld flags, e.g. "-lfoo:-Wl,-u,bar".
# Not using nacl_linkflags since that gets clobbered in some tests.
'pnacl_bcldflags',
'naclsdk_mode',
# set both targetplatform and buildplatform
'platform',
# Run tests under this tool (e.g. valgrind, tsan, strace, etc).
# If the tool has options, pass them after comma: 'tool,--opt1,--opt2'.
# NB: no way to use tools the names or the args of
# which contains a comma.
'run_under',
# More args for the tool.
'run_under_extra_args',
# Multiply timeout values by this number.
'scale_timeout',
# enable use of SDL
'sdl',
# set target platform
'targetplatform',
# activates buildbot-specific presets
'buildbot',
])
# Overly general to provide compatibility with existing build bots, etc.
# In the future it might be worth restricting the values that are accepted.
_TRUE_STRINGS = set(['1', 'true', 'yes'])
_FALSE_STRINGS = set(['0', 'false', 'no'])
# Converts a string representing a Boolean value, of some sort, into an actual
# Boolean value. Python's built in type coercion does not work because
# bool('False') == True
def StringValueToBoolean(value):
# ExpandArguments may stick non-string values in ARGUMENTS. Be accommodating.
if isinstance(value, bool):
return value
if not isinstance(value, basestring):
raise Exception("Expecting a string but got a %s" % repr(type(value)))
if value.lower() in _TRUE_STRINGS:
return True
elif value.lower() in _FALSE_STRINGS:
return False
else:
raise Exception("Cannot convert '%s' to a Boolean value" % value)
def GetBinaryArgumentValue(arg_name, default):
if not isinstance(default, bool):
raise Exception("Default value for '%s' must be a Boolean" % arg_name)
if arg_name not in ARGUMENTS:
return default
return StringValueToBoolean(ARGUMENTS[arg_name])
# name is the name of the bit
# arg_name is the name of the command-line argument, if it differs from the bit
def BitFromArgument(env, name, default, desc, arg_name=None):
# In most cases the bit name matches the argument name
if arg_name is None:
arg_name = name
DeclareBit(name, desc)
assert arg_name not in ACCEPTABLE_ARGUMENTS, arg_name
ACCEPTABLE_ARGUMENTS.add(arg_name)
if GetBinaryArgumentValue(arg_name, default):
env.SetBits(name)
else:
env.ClearBits(name)
# SetUpArgumentBits declares binary command-line arguments and converts them to
# bits. For example, one of the existing declarations would result in the
# argument "bitcode=1" causing env.Bit('bitcode') to evaluate to true.
# NOTE Command-line arguments are a SCons-ism that is separate from
# command-line options. Options are prefixed by "-" or "--" whereas arguments
# are not. The function SetBitFromOption can be used for options.
# NOTE This function must be called before the bits are used
# NOTE This function must be called after all modifications of ARGUMENTS have
# been performed. See: ExpandArguments
def SetUpArgumentBits(env):
BitFromArgument(env, 'bitcode', default=False,
desc="We are building bitcode")
BitFromArgument(env, 'built_elsewhere', default=False,
desc="The programs have already been built by another system")
BitFromArgument(env, 'nacl_pic', default=False,
desc="generate position indepent code for (P)NaCl modules")
# Defaults on when --verbose is specified.
# --verbose sets 'brief_comstr' to False, so this looks a little strange
BitFromArgument(env, 'target_stats', default=not GetOption('brief_comstr'),
desc="Collect and display information about which commands are executed "
"during the build process")
BitFromArgument(env, 'werror', default=True,
desc="Treat warnings as errors (-Werror)")
BitFromArgument(env, 'disable_nosys_linker_warnings', default=False,
desc="Disable warning mechanism in src/untrusted/nosys/warning.h")
BitFromArgument(env, 'naclsdk_validate', default=True,
desc="Verify the presence of the SDK")
BitFromArgument(env, 'nocpp', default=False,
desc="Skip the compilation of C++ code")
BitFromArgument(env, 'running_on_valgrind', default=False,
desc="Compile and test using valgrind")
BitFromArgument(env, 'build_vim', default=False,
desc="Build vim")
BitFromArgument(env, 'build_av_apps', default=True,
desc="Build multi media apps")
# This argument allows -lcrypt to be disabled, which
# makes it easier to build x86-32 NaCl on x86-64 Ubuntu Linux,
# where there is no -dev package for the 32-bit libcrypto
BitFromArgument(env, 'use_libcrypto', default=True,
desc="Use libcrypto")
BitFromArgument(env, 'pp', default=False,
desc="Enable pretty printing")
BitFromArgument(env, 'dangerous_debug_disable_inner_sandbox',
default=False, desc="Make sel_ldr less strict")
# By default SCons does not use the system's environment variables when
# executing commands, to help isolate the build process.
BitFromArgument(env, 'use_environ', arg_name='USE_ENVIRON',
default=False, desc="Expose existing environment variables to the build")
# Defaults on when --verbose is specified
# --verbose sets 'brief_comstr' to False, so this looks a little strange
BitFromArgument(env, 'sysinfo', default=not GetOption('brief_comstr'),
desc="Print verbose system information")
def CheckArguments():
for key in ARGUMENTS:
if key not in ACCEPTABLE_ARGUMENTS:
print 'ERROR'
print 'ERROR bad argument: %s' % key
print 'ERROR'
sys.exit(-1)
# Sets a command line argument. Dies if an argument with this name is already
# defined.
def SetArgument(key, value):
print ' %s=%s' % (key, str(value))
if key in ARGUMENTS:
print 'ERROR: %s redefined' % (key, )
sys.exit(-1)
else:
ARGUMENTS[key] = value
# Expands "macro" command line arguments.
def ExpandArguments():
if ARGUMENTS.get('buildbot') == 'memcheck':
print 'buildbot=memcheck expands to the following arguments:'
SetArgument('run_under',
'src/third_party/valgrind/memcheck.sh,' +
'--error-exitcode=1')
SetArgument('scale_timeout', 20)
SetArgument('running_on_valgrind', True)
elif ARGUMENTS.get('buildbot') == 'tsan':
print 'buildbot=tsan expands to the following arguments:'
SetArgument('run_under',
'src/third_party/valgrind/tsan.sh,' +
'--nacl-untrusted,--error-exitcode=1')
SetArgument('scale_timeout', 20)
SetArgument('running_on_valgrind', True)
elif ARGUMENTS.get('buildbot') == 'tsan-trusted':
print 'buildbot=tsan-trusted expands to the following arguments:'
SetArgument('run_under',
'src/third_party/valgrind/tsan.sh,' +
'--error-exitcode=1')
SetArgument('scale_timeout', 20)
SetArgument('running_on_valgrind', True)
elif ARGUMENTS.get('buildbot'):
print 'ERROR: unexpected argument buildbot="%s"' % (
ARGUMENTS.get('buildbot'), )
sys.exit(-1)
#-----------------------------------------------------------
ExpandArguments()
# ----------------------------------------------------------
environment_list = []
# ----------------------------------------------------------
# Base environment for both nacl and non-nacl variants.
kwargs = {}
if ARGUMENTS.get('DESTINATION_ROOT') is not None:
kwargs['DESTINATION_ROOT'] = ARGUMENTS.get('DESTINATION_ROOT')
pre_base_env = Environment(
tools = ['component_setup'],
# SOURCE_ROOT is one leave above the native_client directory.
SOURCE_ROOT = Dir('#/..').abspath,
# Publish dlls as final products (to staging).
COMPONENT_LIBRARY_PUBLISH = True,
# Use workaround in special scons version.
LIBS_STRICT = True,
LIBS_DO_SUBST = True,
# Select where to find coverage tools.
COVERAGE_MCOV = '../third_party/lcov/bin/mcov',
COVERAGE_GENHTML = '../third_party/lcov/bin/genhtml',
**kwargs
)
# This function should be called ASAP after the environment is created, but
# after ExpandArguments.
SetUpArgumentBits(pre_base_env)
# Scons normally wants to scrub the environment. However, sometimes
# we want to allow PATH and other variables through so that Scons
# scripts can find nacl-gcc without needing a Scons-specific argument.
if pre_base_env.Bit('use_environ'):
pre_base_env['ENV'] = os.environ.copy()
# We want to pull CYGWIN setup in our environment or at least set flag
# nodosfilewarning. It does not do anything when CYGWIN is not involved
# so let's do it in all cases.
pre_base_env['ENV']['CYGWIN'] = os.environ.get('CYGWIN', 'nodosfilewarning')
if pre_base_env.Bit('werror'):
werror_flags = ['-Werror']
else:
werror_flags = []
# ----------------------------------------------------------
# Method to make sure -pedantic, etc, are not stripped from the
# default env, since occasionally an engineer will be tempted down the
# dark -- but wide and well-trodden -- path of expediency and stray
# from the path of correctness.
def EnsureRequiredBuildWarnings(env):
if env.Bit('linux') or env.Bit('mac'):
required_env_flags = set(['-pedantic', '-Wall'] + werror_flags)
ccflags = set(env.get('CCFLAGS'))
if not required_env_flags.issubset(ccflags):
raise UserError('required build flags missing: '
+ ' '.join(required_env_flags.difference(ccflags)))
else:
# windows get a pass for now
pass
pre_base_env.AddMethod(EnsureRequiredBuildWarnings)
# ----------------------------------------------------------
# Generic Test Wrapper
# ----------------------------------------------------------
# Add list of Flaky or Bad tests to skip per platform. A
# platform is defined as build type
# <BUILD_TYPE>-<SUBARCH>
bad_build_lists = dict()
bad_build_lists['opt-win-64'] = ['run_srpc_basic_test',
'run_srpc_bad_service_test',
'run_fake_browser_ppapi_test',
'run_ppapi_plugin_unittest']
bad_build_lists['dbg-win-64'] = ['run_srpc_basic_test',
'run_srpc_bad_service_test',
'run_fake_browser_ppapi_test',
'run_ppapi_plugin_unittest']
# This is a list of tests that do not yet pass when using nacl-glibc.
# TODO(mseaborn): Enable more of these tests!
nacl_glibc_skiplist = [
# This test assumes it can allocate address ranges from the
# dynamic code area itself. However, this does not work when
# ld.so assumes it can do the same. To fix this, ld.so will need
# an interface, like mmap() or brk(), for reserving space in the
# dynamic code area.
'run_dynamic_load_test',
# This uses a canned binary that is compiled w/ newlib. A
# glibc version might be useful.
'run_fuzz_nullptr_test',
# This tests the absence of "-s" but that is no good because
# we currently force that option on.
'run_stubout_mode_test',
# Struct layouts differ.
'run_abi_test',
# Syscall wrappers not implemented yet.
'run_sysbasic_test',
'run_sysbrk_test',
# Fails because clock() is not hooked up.
'run_timefuncs_test',
# Needs further investigation.
'sdk_minimal_test',
# TODO(elijahtaylor) add apropriate syscall hooks for glibc
'run_gc_instrumentation_test',
# The tests below just run ncval. ncval does not pass on
# dynamically-linked executables because, to reduce executable
# size, the code segment is not page-aligned, and ncval rejects
# such executables. See
# http://code.google.com/p/nativeclient/issues/detail?id=1183
'run_earth',
'run_life',
'run_mandel_nav',
'run_whole_archive_test',
# run_srpc_sysv_shm_test fails because:
# 1) it uses fstat(), while we only have an fstat64() wrapper;
# 2) the test needs an explicit fflush(stdout) call because the
# process is killed without exit() being called.
'run_srpc_sysv_shm_test',
]
# If a test is not in one of these suites, it will probally not be run on a
# regular basis. These are the suites that will be run by the try bot or that
# a large number of users may run by hand.
MAJOR_TEST_SUITES = set([
'small_tests',
'medium_tests',
'large_tests',
'small_tests_arm_hw_only',
'large_tests_arm_hw_only',
'browser_tests',
'huge_tests',
# Adding a test to broken_tests means the test will not be run unless
# explicitly requested by name. Broken tests cannot belong to any other test
# suite and are not added to all_tests
'broken_tests',
])
# These are the test suites we know exist, but aren't run on a regular basis.
# These test suites are essentially shortcuts that run a specific subset of the
# test cases.
ACCEPTABLE_TEST_SUITES = set([
'validator_tests',
'validator_modeling',
'sel_ldr_tests',
'sel_ldr_sled_tests',
'barebones_tests',
'tsan_bot_tests',
'toolchain_tests',
'pnacl_abi_tests',
])
# The major test suites are also acceptable names. Suite names are checked
# against this set in order to catch typos.
ACCEPTABLE_TEST_SUITES.update(MAJOR_TEST_SUITES)
def ValidateTestSuiteNames(suite_name, node_name):
if node_name is None:
node_name = '<unknown>'
# Prevent a silent failiure - strings are iterable!
if not isinstance(suite_name, (list, tuple)):
raise Exception("Test suites for %s should be specified as a list, "
"not as a %s: %s" % (node_name, type(suite_name).__name__,
repr(suite_name)))
if not suite_name:
raise Exception("No test suites are specified for %s. Put the test in "
"'broken_tests' if there's a known issue and you don't want it to "
"run" % (node_name,))
if 'broken_tests' in suite_name and len(suite_name) != 1:
raise Exception("'broken_tests' is a special test suite - if you're "
"adding a test to it, that test (%s) should not be in any other "
"suite" % (node_name,))
# Make sure each test is in at least one test suite we know will run
# 'broken_tests' is where you put tests you deliberately do not want to run
major_suites = set(suite_name).intersection(MAJOR_TEST_SUITES)
if not major_suites:
raise Exception("None of the test suites %s for %s are run on a "
"regular basis" % (repr(suite_name), node_name))
# Make sure a wierd test suite hasn't been inadvertantly specified
for s in suite_name:
if s not in ACCEPTABLE_TEST_SUITES:
raise Exception("\"%s\" is not a known test suite. Either this is "
"a typo for %s, or it should be added to ACCEPTABLE_TEST_SUITES in "
"SConstruct" % (s, node_name))
def IsBrokenTest(suite_name):
return len(suite_name) == 1 and 'broken_tests' == suite_name[0]
def AddNodeToTestSuite(env, node, suite_name, node_name=None):
build = env['BUILD_TYPE']
# If we are testing 'NACL' we really need the trusted info
if build=='nacl' and 'TRUSTED_ENV' in env:
trusted_env = env['TRUSTED_ENV']
build = trusted_env['BUILD_TYPE']
subarch = trusted_env['BUILD_SUBARCH']
else:
subarch = env['BUILD_SUBARCH']
# Build the test platform string
platform = build + '-' + subarch
if not node:
return
# There are no known-to-fail tests any more, but this code is left
# in so that if/when we port to a new architecture or add a test
# that is known to fail on some platform(s), we can continue to have
# a central location to disable tests from running. NB: tests that
# don't *build* on some platforms need to be omitted in another way.
# Retrieve list of tests to skip on this platform
skiplist = bad_build_lists.get(platform,[])
if env.Bit('nacl_glibc'):
skiplist = skiplist + nacl_glibc_skiplist
if node_name in skiplist:
print '*** SKIPPING ', platform, ':', node_name
return
ValidateTestSuiteNames(suite_name, node_name)
AlwaysBuild(node)
if not IsBrokenTest(suite_name):
env.Alias('all_tests', node)
for s in suite_name:
env.Alias(s, node)
if node_name:
env.ComponentTestOutput(node_name, node)
pre_base_env.AddMethod(AddNodeToTestSuite)
# ----------------------------------------------------------
# Convenient testing aliases
# NOTE: work around for scons non-determinism in the following two lines
Alias('sel_ldr_sled_tests', [])
Alias('small_tests', [])
Alias('medium_tests', [])
Alias('large_tests', [])
Alias('browser_tests', [])
Alias('unit_tests', 'small_tests')
Alias('smoke_tests', ['small_tests', 'medium_tests'])
Alias('memcheck_bot_tests', ['small_tests', 'medium_tests', 'large_tests'])
Alias('tsan_bot_tests', [])
# ----------------------------------------------------------
def Banner(text):
print '=' * 70
print text
print '=' * 70
pre_base_env.AddMethod(Banner)
# ----------------------------------------------------------
# PLATFORM LOGIC
# ----------------------------------------------------------
# Define the build and target platforms, and use them to define the path
# for the scons-out directory (aka TARGET_ROOT)
#.
# We have "build" and "target" platforms for the non nacl environments
# which govern service runtime, validator, etc.
#
# "build" means the platform the code is running on
# "target" means the platform the validator is checking for.
# Typically they are the same but testing it useful to have flexibility.
#
# Various variables in the scons environment are related to this, e.g.
#
# BUILD_ARCH: (arm, x86)
# BUILD_SUBARCH: (32, 64)
#
# The settings can be controlled using scons command line variables:
#
#
# buildplatform=: controls the build platform
# targetplatform=: controls the target platform
# platform=: controls both
#
# This dictionary is used to translate from a platform name to a
# (arch, subarch) pair
AVAILABLE_PLATFORMS = {
'x86-32' : { 'arch' : 'x86' , 'subarch' : '32' },
'x86-64' : { 'arch' : 'x86' , 'subarch' : '64' },
'arm' : { 'arch' : 'arm' , 'subarch' : '32' }
}
# Look up the platform name from the command line arguments,
# defaulting to 'platform' if needed.
def GetPlatform(name):
platform = ARGUMENTS.get(name)
if platform is None:
return ARGUMENTS.get('platform', 'x86-32')
elif ARGUMENTS.get('platform') is None:
return platform
else:
Banner("Can't specify both %s and %s on the command line"
% ('platform', name))
assert 0
# Decode platform into list [ ARCHITECTURE , EXEC_MODE ].
def DecodePlatform(platform):
if platform in AVAILABLE_PLATFORMS:
return AVAILABLE_PLATFORMS[platform]
Banner("Unrecognized platform: %s" % ( platform ))
assert 0
BUILD_NAME = GetPlatform('buildplatform')
pre_base_env.Replace(BUILD_FULLARCH=BUILD_NAME)
pre_base_env.Replace(BUILD_ARCHITECTURE=DecodePlatform(BUILD_NAME)['arch'])
pre_base_env.Replace(BUILD_SUBARCH=DecodePlatform(BUILD_NAME)['subarch'])
TARGET_NAME = GetPlatform('targetplatform')
pre_base_env.Replace(TARGET_FULLARCH=TARGET_NAME)
pre_base_env.Replace(TARGET_ARCHITECTURE=DecodePlatform(TARGET_NAME)['arch'])
pre_base_env.Replace(TARGET_SUBARCH=DecodePlatform(TARGET_NAME)['subarch'])
DeclareBit('build_x86_32', 'Building binaries for the x86-32 architecture',
exclusive_groups='build_arch')
DeclareBit('build_x86_64', 'Building binaries for the x86-64 architecture',
exclusive_groups='build_arch')
DeclareBit('build_arm', 'Building binaries for the ARM architecture',
exclusive_groups='build_arch')
DeclareBit('target_x86_32', 'Tools being built will process x86-32 binaries',
exclusive_groups='target_arch')
DeclareBit('target_x86_64', 'Tools being built will process x86-36 binaries',
exclusive_groups='target_arch')
DeclareBit('target_arm', 'Tools being built will process ARM binaries',
exclusive_groups='target_arch')
# Shorthand for either the 32 or 64 bit version of x86.
DeclareBit('build_x86', 'Building binaries for the x86 architecture')
DeclareBit('target_x86', 'Tools being built will process x86 binaries')
# Example: PlatformBit('build', 'x86-32') -> build_x86_32
def PlatformBit(prefix, platform):
return "%s_%s" % (prefix, platform.replace('-', '_'))
pre_base_env.SetBits(PlatformBit('build', BUILD_NAME))
pre_base_env.SetBits(PlatformBit('target', TARGET_NAME))
if pre_base_env.Bit('build_x86_32') or pre_base_env.Bit('build_x86_64'):
pre_base_env.SetBits('build_x86')
if pre_base_env.Bit('target_x86_32') or pre_base_env.Bit('target_x86_64'):
pre_base_env.SetBits('target_x86')
pre_base_env.Replace(BUILD_ISA_NAME=GetPlatform('buildplatform'))
if TARGET_NAME == 'arm' and not pre_base_env.Bit('bitcode'):
# This has always been a silent default on ARM.
pre_base_env.SetBits('bitcode')
# Determine where the object files go
if BUILD_NAME == TARGET_NAME:
TARGET_ROOT = '${DESTINATION_ROOT}/${BUILD_TYPE}-%s' % TARGET_NAME
else:
TARGET_ROOT = '${DESTINATION_ROOT}/${BUILD_TYPE}-%s-to-%s' % (BUILD_NAME,
TARGET_NAME)
pre_base_env.Replace(TARGET_ROOT=TARGET_ROOT)
# TODO(robertm): eliminate this for the trust env
def FixupArmEnvironment():
""" Glean settings by invoking setup scripts and capturing environment."""
nacl_dir = Dir('#/').abspath
p = subprocess.Popen([
'/bin/bash', '-c',
'source ' + nacl_dir +
'/tools/llvm/setup_arm_trusted_toolchain.sh && ' +
sys.executable + " -c 'import os ; print os.environ'"],
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(stdout, stderr) = p.communicate()
assert p.returncode == 0, stderr
arm_env = eval(stdout)
for key, value in arm_env.iteritems():
if key.startswith('NACL_') or key.startswith('ARM_'):
os.environ[key] = value
# Source setup bash scripts and glean the settings.
if (pre_base_env.Bit('target_arm') and
not pre_base_env.Bit('built_elsewhere') and
ARGUMENTS.get('naclsdk_mode') != 'manual'):
FixupArmEnvironment()
# Valgrind
pre_base_env.AddMethod(lambda self: ARGUMENTS.get('running_on_valgrind'),
'IsRunningUnderValgrind')
# This method indicates that the binaries we are building will validate code
# for an architecture different than the one the binaries will run on.
# NOTE Currently (2010/11/17) this is 'x86' vs. 'arm', and x86-32 vs. x86-64
# is not considered to be a cross-tools build.
def CrossToolsBuild(env):
return env['BUILD_ARCHITECTURE'] != env['TARGET_ARCHITECTURE']
pre_base_env.AddMethod(CrossToolsBuild, 'CrossToolsBuild')
# ----------------------------------------------------------
# PLUGIN PREREQUISITES
# ----------------------------------------------------------
PREREQUISITES = pre_base_env.Alias('plugin_prerequisites', [])
def GetPluginPrerequsites():
# the first source is the banner. drop it
return PREREQUISITES[0].sources[1:]
# this is a horrible hack printing all the dependencies
# dynamically accumulated for PREREQUISITES via AddPluginPrerequisite
def PluginPrerequisiteInfo(target, source, env):
Banner("Pluging Prerequisites")
deps = [dep.abspath for dep in GetPluginPrerequsites()]
print "abbreviated list: ", str([os.path.basename(d) for d in deps])
print "full list:"
for dep in deps:
print dep
return None
banner = pre_base_env.Command('plugin_prerequisites_banner', [],
PluginPrerequisiteInfo)
pre_base_env.Alias('plugin_prerequisites', banner)
def AddPluginPrerequisite(env, nodes):
env.Alias('plugin_prerequisites', nodes)
return n
pre_base_env.AddMethod(AddPluginPrerequisite)
# NOTE: PROGRAMFILES is only used for windows
# SILENT is used to turn of user ack
INSTALL_COMMAND = ['${PYTHON}',
'${SCONSTRUCT_DIR}/tools/firefoxinstall.py',
'SILENT="%s"' % ARGUMENTS.get('SILENT', ''),
'"PROGRAMFILES=%s"' % os.getenv('PROGRAMFILES', ''),
]
n = pre_base_env.Alias(target='firefox_install_restore',
source=[],
action=' '.join(INSTALL_COMMAND + ['MODE=RESTORE']))
AlwaysBuild(n)
n = pre_base_env.Alias(target='firefox_install_backup',
source=[],
action=' '.join(INSTALL_COMMAND + ['MODE=BACKUP']))
AlwaysBuild(n)
# ----------------------------------------------------------
def HasSuffix(item, suffix):
if isinstance(item, str):
return item.endswith(suffix)
elif hasattr(item, '__getitem__'):
return HasSuffix(item[0], suffix)
else:
return item.path.endswith(suffix)
def DualLibrary(env, lib_name, *args, **kwargs):
"""Builder to build both .a and _shared.a library in one step.
Args:
env: Environment in which we were called.
lib_name: Library name.
args: Positional arguments.
kwargs: Keyword arguments.
"""
static_objs = [i for i in Flatten(args[0]) if not HasSuffix(i, '.os')]
shared_objs = [i for i in Flatten(args[0]) if not HasSuffix(i, '.o')]
# Built static library as ususal.
env.ComponentLibrary(lib_name, static_objs, **kwargs)
# Build a static library using -fPIC for the .o's.
if env.Bit('target_x86_64') and env.Bit('linux'):
env_shared = env.Clone(OBJSUFFIX='.os')
env_shared.Append(CCFLAGS=['-fPIC'])
env_shared.ComponentLibrary(lib_name + '_shared', shared_objs, **kwargs)
def DualObject(env, *args, **kwargs):
"""Builder to build both .o and .os in one step.
Args:
env: Environment in which we were called.
args: Positional arguments.
kwargs: Keyword arguments.
"""
# Built static library as ususal.
ret = env.ComponentObject(*args, **kwargs)
# Build a static library using -fPIC for the .o's.
if env.Bit('target_x86_64') and env.Bit('linux'):
env_shared = env.Clone(OBJSUFFIX='.os')
env_shared.Append(CCFLAGS=['-fPIC'])
ret += env_shared.ComponentObject(*args, **kwargs)
return ret
def AddDualLibrary(env):
env.AddMethod(DualLibrary)
env.AddMethod(DualObject)
env['SHARED_LIBS_SPECIAL'] = env.Bit('target_x86_64') and env.Bit('linux')
def InstallPlugin(target, source, env):
Banner('Pluging Installation')
# NOTE: sandbox settings are ignored for non-linux systems
# TODO: we may want to enable this for more linux platforms
if pre_base_env.Bit('build_x86_32'):
sb = 'USE_SANDBOX=1'
else:
sb = 'USE_SANDBOX=0'
deps = [dep.abspath for dep in GetPluginPrerequsites()]
command = env.subst(' '.join(INSTALL_COMMAND + ['MODE=INSTALL', sb] + deps))
return os.system(command)
DeclareBit('nacl_glibc', 'Use nacl-glibc for building untrusted code')
pre_base_env.SetBitFromOption('nacl_glibc', False)
# In prebuild mode we ignore the dependencies so that stuff does
# NOT get build again
# Optionally ignore the build process.
DeclareBit('prebuilt', 'Disable all build steps, only support install steps')
pre_base_env.SetBitFromOption('prebuilt', False)
# Disable tests/platform quals that would fail on vmware + hardy + 64 as
# currently run on some of the buildbots.
DeclareBit('disable_hardy64_vmware_failures',
'Disable tests/platform quals that would fail on '
'vmware + hardy + 64 as currently run on some of the buildbots.')
pre_base_env.SetBitFromOption('disable_hardy64_vmware_failures', False)
if pre_base_env.Bit('disable_hardy64_vmware_failures'):
print 'Running with --disable_hardy64_vmware_failures'
if pre_base_env.Bit('prebuilt') or pre_base_env.Bit('built_elsewhere'):
n = pre_base_env.Command('firefox_install_command',
[],
InstallPlugin)
else:
n = pre_base_env.Command('firefox_install_command',
PREREQUISITES,
InstallPlugin)
n = pre_base_env.Alias('firefox_install', n)
AlwaysBuild(n)
# ----------------------------------------------------------
# HELPERS FOR TEST INVOLVING TRUSTED AND UNTRUSTED ENV
# ----------------------------------------------------------
def GetEmulator(env):
emulator = ARGUMENTS.get('force_emulator')
if emulator is None:
emulator = env.get('EMULATOR', '')
return emulator
def GetValidator(env, validator):
# NOTE: that the variable TRUSTED_ENV is set by ExportSpecialFamilyVars()
if 'TRUSTED_ENV' not in env:
return None
if validator is None:
if env.Bit('build_arm'):
validator = 'arm-ncval-core'
else:
validator = 'ncval'
trusted_env = env['TRUSTED_ENV']
return trusted_env.File('${STAGING_DIR}/${PROGPREFIX}%s${PROGSUFFIX}' %
validator)
def GetSelLdr(env, loader='sel_ldr'):
sel_ldr = ARGUMENTS.get('force_sel_ldr')
if sel_ldr:
return sel_ldr
# NOTE: that the variable TRUSTED_ENV is set by ExportSpecialFamilyVars()
if 'TRUSTED_ENV' not in env:
return None
trusted_env = env['TRUSTED_ENV']
sel_ldr = trusted_env.File('${STAGING_DIR}/${PROGPREFIX}%s${PROGSUFFIX}' %
loader)
return sel_ldr
def CommandValidatorTestNacl(env, name, image,
validator_flags=None,
validator=None,
size='medium',
**extra):
validator = GetValidator(env, validator)
if validator is None:
print 'WARNING: no validator found. Skipping test %s' % name
return []
if validator_flags is None:
validator_flags = []
command = [validator] + validator_flags + [image]
return CommandTest(env, name, command, size, **extra)
pre_base_env.AddMethod(CommandValidatorTestNacl)
# ----------------------------------------------------------
EXTRA_ENV = [('XAUTHORITY', None),
('HOME', None),
('DISPLAY', None),
('SSH_TTY', None),
('KRB5CCNAME', None),
]
SELENIUM_TEST_SCRIPT = '${SCONSTRUCT_DIR}/tools/selenium_tester.py'
def BrowserTester(env,
target,
url,
files,
browser,
log_verbosity=2,
args=[]):
# NOTE: hack to enable chrome testing - only works with Linux so far
if ARGUMENTS.get('chrome_browser_path'):
browser = env.subst('"*googlechrome '
'${SOURCE_ROOT}/native_client/tools/'
'google-chrome-wrapper.py"')
# this env affects the behavior of google-chrome-wrapper.py
env['ENV']['CHROME_BROWSER_EXE'] = ARGUMENTS.get('chrome_browser_path')
deps = [SELENIUM_TEST_SCRIPT] + files
command = ['${SOURCES[0].abspath}', '--url', url, '--browser', browser]
for i in range(len(files)):
command.append('--file')
command.append('${SOURCES[%d].abspath}' % (i + 1))
# NOTE: additional hack to enable chrome testing
# use a more recent version of the selenium server
if ARGUMENTS.get('chrome_browser_path'):
command.append('--selenium_jar')
command.append(env.subst('${SOURCE_ROOT}/third_party/selenium/'
'selenium-server-2.0a1/'
'selenium-server-standalone.jar'))
# NOTE: setting the PYTHONPATH is currently not necessary as the test
# script sets its own path
# env['ENV']['PYTHONPATH'] = ???
# NOTE: since most of the demos use X11 we need to make sure
# some env vars are set for tag, val in extra_env:
for tag, val in EXTRA_ENV:
if val is None:
if os.getenv(tag) is not None:
env['ENV'][tag] = os.getenv(tag)
# TODO(robertm): explain why this is necessary
env['ENV']['NACL_DISABLE_SECURITY_FOR_SELENIUM_TEST'] = '1'
node = env.Command(target, deps, ' '.join(command))
# If we are testing build output captured from elsewhere,
# ignore build dependencies.
if env.Bit('built_elsewhere'):
env.Ignore(node, deps)
return node
pre_base_env.AddMethod(BrowserTester)
# ----------------------------------------------------------
def DemoSelLdrNacl(env,
target,
nexe,
log_verbosity=2,
sel_ldr_flags=['-d'],
args=[]):
sel_ldr = GetSelLdr(env);
if not sel_ldr:
print 'WARNING: no sel_ldr found. Skipping test %s' % target
return []