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.
6 """NaCl SDK tool SCons."""
22 'tooldir': 'arm-nacl',
30 'tooldir': 'i686-nacl',
31 'other_libdir': 'lib32',
34 'ld_flag': ' -melf_i386_nacl',
37 'tooldir': 'x86_64-nacl',
38 'other_libdir': 'lib64',
41 'ld_flag': ' -melf_x86_64_nacl',
46 def _StubOutEnvToolsForBuiltElsewhere(env):
47 """Stub out all tools so that they point to 'true'.
49 Some machines have their code built by another machine, they'll therefore
50 run 'true' instead of running the usual build tools.
53 env: The SCons environment in question.
55 assert(env.Bit('built_elsewhere'))
56 env.Replace(CC='true', CXX='true', LINK='true', AR='true',
57 RANLIB='true', AS='true', ASPP='true', LD='true',
58 STRIP='true', PNACLOPT='true', PNACLFINALIZE='true')
61 def _SetEnvForNativeSdk(env, sdk_path):
62 """Initialize environment according to target architecture."""
64 bin_path = os.path.join(sdk_path, 'bin')
65 # NOTE: attempts to eliminate this PATH setting and use
66 # absolute path have been futile
67 env.PrependENVPath('PATH', bin_path)
70 tool_map = NACL_TOOL_MAP[env['TARGET_ARCHITECTURE']]
71 subarch_spec = tool_map[env['TARGET_SUBARCH']]
72 tooldir = subarch_spec['tooldir']
73 # We need to pass it extra options for the subarch we are building.
74 as_mode_flag = subarch_spec['as_flag']
75 cc_mode_flag = subarch_spec['cc_flag']
76 ld_mode_flag = subarch_spec['ld_flag']
77 if os.path.exists(os.path.join(sdk_path, tooldir)):
78 # The tooldir for the build target exists.
79 # The tools there do the right thing without special options.
81 libdir = os.path.join(tooldir, 'lib')
83 # We're building for a target for which there is no matching tooldir.
84 # For example, for x86-32 when only <sdk_path>/x86_64-nacl/ exists.
85 # Find a tooldir for a different subarch that does exist.
86 others_map = tool_map.copy()
87 del others_map[env['TARGET_SUBARCH']]
88 for subarch, tool_spec in others_map.iteritems():
89 tooldir = tool_spec['tooldir']
90 if os.path.exists(os.path.join(sdk_path, tooldir)):
91 # OK, this is the other subarch to use as tooldir.
93 # The lib directory may have an alternate name, i.e.
94 # 'lib32' in the x86_64-nacl tooldir.
95 libdir = os.path.join(tooldir, subarch_spec.get('other_libdir', 'lib'))
98 if tool_prefix is None:
99 raise Exception("Cannot find a toolchain for %s in %s" %
100 (env['TARGET_FULLARCH'], sdk_path))
102 env.Replace(# Replace header and lib paths.
103 # where to put nacl extra sdk headers
104 # TODO(robertm): switch to using the mechanism that
105 # passes arguments to scons
106 NACL_SDK_INCLUDE='%s/%s/include' % (sdk_path, tool_prefix),
107 # where to find/put nacl generic extra sdk libraries
108 NACL_SDK_LIB='%s/%s' % (sdk_path, libdir),
109 # Replace the normal unix tools with the NaCl ones.
110 CC=os.path.join(bin_path, '%s-gcc' % tool_prefix),
111 CXX=os.path.join(bin_path, '%s-g++' % tool_prefix),
112 AR=os.path.join(bin_path, '%s-ar' % tool_prefix),
113 AS=os.path.join(bin_path, '%s-as' % tool_prefix),
114 ASPP=os.path.join(bin_path, '%s-gcc' % tool_prefix),
115 GDB=os.path.join(bin_path, '%s-gdb' % tool_prefix),
116 # NOTE: use g++ for linking so we can handle C AND C++.
117 LINK=os.path.join(bin_path, '%s-g++' % tool_prefix),
118 # Grrr... and sometimes we really need ld.
119 LD=os.path.join(bin_path, '%s-ld' % tool_prefix) + ld_mode_flag,
120 RANLIB=os.path.join(bin_path, '%s-ranlib' % tool_prefix),
121 NM=os.path.join(bin_path, '%s-nm' % tool_prefix),
122 OBJDUMP=os.path.join(bin_path, '%s-objdump' % tool_prefix),
123 STRIP=os.path.join(bin_path, '%s-strip' % tool_prefix),
124 ADDR2LINE=os.path.join(bin_path, '%s-addr2line' % tool_prefix),
125 BASE_LINKFLAGS=[cc_mode_flag],
126 BASE_CFLAGS=[cc_mode_flag],
127 BASE_CXXFLAGS=[cc_mode_flag],
128 BASE_ASFLAGS=[as_mode_flag],
129 BASE_ASPPFLAGS=[cc_mode_flag],
130 CFLAGS=['-std=gnu99'],
134 '-Wno-variadic-macros',
137 '-fno-stack-protector',
138 '-fdiagnostics-show-option',
145 # NaClSdk environment seems to be inherited from the host environment.
146 # On Linux host, this probably makes sense. On Windows and Mac, this
147 # introduces nothing except problems.
148 # For now, simply override the environment settings as in
149 # <scons>/engine/SCons/Platform/posix.py
150 env.Replace(LIBPREFIX='lib',
152 SHLIBPREFIX='$LIBPREFIX',
154 LIBPREFIXES=['$LIBPREFIX'],
155 LIBSUFFIXES=['$LIBSUFFIX', '$SHLIBSUFFIX'],
157 # Force -fPIC when compiling for shared libraries.
158 env.AppendUnique(SHCCFLAGS=['-fPIC'],
161 def _SetEnvForPnacl(env, root):
162 # All the PNaCl tools require Python to be in the PATH.
163 arch = env['TARGET_FULLARCH']
164 assert arch in ['arm', 'mips32', 'x86-32', 'x86-64']
166 if env.Bit('pnacl_unsandboxed'):
167 if env.Bit('host_linux'):
168 arch = '%s-linux' % arch
169 elif env.Bit('host_mac'):
170 arch = '%s-mac' % arch
171 if env.Bit('nonsfi_nacl'):
173 arch_flag = ' -arch %s' % arch
174 if env.Bit('pnacl_generate_pexe'):
177 ld_arch_flag = arch_flag
179 llc_mtriple_flag = ''
180 if env.Bit('minsfi'):
182 if env.Bit('build_x86_32'):
184 elif env.Bit('build_x86_64'):
187 if env.Bit('host_linux'):
188 llc_mtriple_flag = ' -mtriple=%s-linux-gnu' % llc_cpu
189 elif env.Bit('host_mac'):
190 llc_mtriple_flag = ' -mtriple=%s-apple-darwin' % llc_cpu
192 translator_root = os.path.join(os.path.dirname(root), 'pnacl_translator')
194 binprefix = os.path.join(root, 'bin', 'pnacl-')
196 if env.Bit('host_windows'):
199 pnacl_ar = binprefix + 'ar' + binext
200 pnacl_as = binprefix + 'as' + binext
201 pnacl_nm = binprefix + 'nm' + binext
202 pnacl_ranlib = binprefix + 'ranlib' + binext
203 # Use the standalone sandboxed translator in sbtc mode
204 if env.Bit('use_sandboxed_translator'):
205 pnacl_translate = os.path.join(translator_root, 'bin',
206 'pnacl-translate' + binext)
208 pnacl_translate = binprefix + 'translate' + binext
210 pnacl_cc = binprefix + 'clang' + binext
211 pnacl_cxx = binprefix + 'clang++' + binext
213 pnacl_ld = binprefix + 'ld' + binext
214 pnacl_disass = binprefix + 'dis' + binext
215 pnacl_finalize = binprefix + 'finalize' + binext
216 pnacl_opt = binprefix + 'opt' + binext
217 pnacl_strip = binprefix + 'strip' + binext
218 pnacl_llc = binprefix + 'llc' + binext
220 # NOTE: XXX_flags start with space for easy concatenation
221 # The flags generated here get baked into the commands (CC, CXX, LINK)
222 # instead of CFLAGS etc to keep them from getting blown away by some
223 # tests. Don't add flags here unless they always need to be preserved.
225 pnacl_cc_flags = ' -std=gnu99'
226 pnacl_ld_flags = ' ' + ' '.join(env['PNACL_BCLDFLAGS'])
227 pnacl_translate_flags = ''
230 if env.Bit('nacl_pic'):
231 pnacl_cc_flags += ' -fPIC'
232 pnacl_cxx_flags += ' -fPIC'
233 # NOTE: this is a special hack for the pnacl backend which
234 # does more than linking
235 pnacl_ld_flags += ' -fPIC'
236 pnacl_translate_flags += ' -fPIC'
238 if env.Bit('minsfi'):
239 pnacl_llc_flags += ' -relocation-model=pic -filetype=obj'
240 pnacl_ld_flags += ' -nostdlib -Wl,-r -L' + os.path.join(root, 'usr', 'lib')
242 if env.Bit('use_sandboxed_translator'):
243 sb_flags = ' --pnacl-sb'
244 pnacl_ld_flags += sb_flags
245 pnacl_translate_flags += sb_flags
247 if env.Bit('x86_64_zero_based_sandbox'):
248 pnacl_translate_flags += ' -sfi-zero-based-sandbox'
250 env.Replace(# Replace header and lib paths.
251 NACL_SDK_INCLUDE=os.path.join(root, 'le32-nacl', 'include'),
252 NACL_SDK_LIB=os.path.join(root, 'le32-nacl', 'lib'),
253 # Remove arch-specific flags (if any)
259 # Replace the normal unix tools with the PNaCl ones.
260 CC=pnacl_cc + pnacl_cc_flags,
261 CXX=pnacl_cxx + pnacl_cxx_flags,
262 ASPP=pnacl_cc + pnacl_cc_flags,
267 LINK=pnacl_cxx + ld_arch_flag + pnacl_ld_flags,
268 # Although we are currently forced to produce native output
269 # for LINK, we are free to produce bitcode for SHLINK
270 # (SharedLibrary linking) because scons doesn't do anything
271 # with shared libraries except use them with the toolchain.
272 SHLINK=pnacl_cxx + ld_arch_flag + pnacl_ld_flags,
275 AS=pnacl_as + ld_arch_flag,
278 OBJDUMP=pnacl_disass,
280 TRANSLATE=pnacl_translate + arch_flag + pnacl_translate_flags,
281 PNACLFINALIZE=pnacl_finalize,
283 LLC=pnacl_llc + llc_mtriple_flag + pnacl_llc_flags,
286 if env.Bit('built_elsewhere'):
287 def FakeInstall(dest, source, env):
288 print 'Not installing', dest
289 _StubOutEnvToolsForBuiltElsewhere(env)
290 env.Replace(INSTALL=FakeInstall)
291 if env.Bit('translate_in_build_step'):
292 env.Replace(TRANSLATE='true')
293 env.Replace(PNACLFINALIZE='true')
296 def PNaClForceNative(env):
297 assert(env.Bit('bitcode'))
298 if env.Bit('pnacl_generate_pexe'):
299 env.Replace(CC='NO-NATIVE-CC-INVOCATION-ALLOWED',
300 CXX='NO-NATIVE-CXX-INVOCATION-ALLOWED')
303 env.Replace(OBJSUFFIX='.o',
305 arch_flag = ' -arch ${TARGET_FULLARCH}'
306 cc_flags = ' --pnacl-allow-native --pnacl-allow-translate'
307 env.Append(CC=arch_flag + cc_flags,
308 CXX=arch_flag + cc_flags,
309 ASPP=arch_flag + cc_flags,
310 LINK=cc_flags) # Already has -arch
311 env['LD'] = 'NO-NATIVE-LD-INVOCATION-ALLOWED'
312 env['SHLINK'] = '${LINK}'
313 if env.Bit('built_elsewhere'):
314 _StubOutEnvToolsForBuiltElsewhere(env)
316 # Get an environment for nacl-gcc when in PNaCl mode.
317 def PNaClGetNNaClEnv(env):
318 assert(env.Bit('bitcode'))
319 assert(not env.Bit('target_mips32'))
321 # This is kind of a hack. We clone the environment,
322 # clear the bitcode bit, and then reload naclsdk.py
323 native_env = env.Clone()
324 native_env.ClearBits('bitcode')
325 if env.Bit('built_elsewhere'):
326 _StubOutEnvToolsForBuiltElsewhere(env)
328 native_env = native_env.Clone(tools=['naclsdk'])
329 if native_env.Bit('pnacl_generate_pexe'):
330 native_env.Replace(CC='NO-NATIVE-CC-INVOCATION-ALLOWED',
331 CXX='NO-NATIVE-CXX-INVOCATION-ALLOWED')
333 # These are unfortunately clobbered by running Tool.
334 native_env.Replace(EXTRA_CFLAGS=env['EXTRA_CFLAGS'],
335 EXTRA_CXXFLAGS=env['EXTRA_CXXFLAGS'],
336 CCFLAGS=env['CCFLAGS'],
337 CFLAGS=env['CFLAGS'],
338 CXXFLAGS=env['CXXFLAGS'])
342 # This adds architecture specific defines for the target architecture.
343 # These are normally omitted by PNaCl.
344 # For example: __i686__, __arm__, __mips__, __x86_64__
345 def AddBiasForPNaCl(env, temporarily_allow=True):
346 assert(env.Bit('bitcode'))
347 # re: the temporarily_allow flag -- that is for:
348 # BUG= http://code.google.com/p/nativeclient/issues/detail?id=1248
349 if env.Bit('pnacl_generate_pexe') and not temporarily_allow:
350 env.Replace(CC='NO-NATIVE-CC-INVOCATION-ALLOWED',
351 CXX='NO-NATIVE-CXX-INVOCATION-ALLOWED')
354 if env.Bit('target_arm'):
355 env.AppendUnique(CCFLAGS=['--pnacl-arm-bias'],
356 ASPPFLAGS=['--pnacl-arm-bias'])
357 elif env.Bit('target_x86_32'):
358 env.AppendUnique(CCFLAGS=['--pnacl-i686-bias'],
359 ASPPFLAGS=['--pnacl-i686-bias'])
360 elif env.Bit('target_x86_64'):
361 env.AppendUnique(CCFLAGS=['--pnacl-x86_64-bias'],
362 ASPPFLAGS=['--pnacl-x86_64-bias'])
363 elif env.Bit('target_mips32'):
364 env.AppendUnique(CCFLAGS=['--pnacl-mips-bias'],
365 ASPPFLAGS=['--pnacl-mips-bias'])
367 raise Exception("Unknown architecture!")
370 def ValidateSdk(env):
371 checkables = ['${NACL_SDK_INCLUDE}/stdio.h']
373 if os.path.exists(env.subst(c)):
375 # Windows build does not use cygwin and so can not see nacl subdirectory
376 # if it's cygwin's symlink - check for /include instead...
377 if os.path.exists(re.sub(r'(nacl64|nacl)/include/([^/]*)$',
381 # TODO(pasko): remove the legacy header presence test below.
382 if os.path.exists(re.sub(r'nacl/include/([^/]*)$',
383 r'nacl64/include/\1',
386 message = env.subst('''
387 ERROR: NativeClient toolchain does not seem present!,
391 NACL_SDK_INCLUDE=${NACL_SDK_INCLUDE}
392 NACL_SDK_LIB=${NACL_SDK_LIB}
401 Run: gclient runhooks --force or build the SDK yourself.
403 sys.stderr.write(message + "\n\n")
407 def ScanLinkerScript(node, env, libpath):
408 """SCons scanner for linker script files.
409 This handles trivial linker scripts like those used for libc.so and libppapi.a.
410 These scripts just indicate more input files to be linked in, so we want
411 to produce dependencies on them.
413 A typical such linker script looks like:
416 INPUT ( foo.a libbar.a libbaz.a )
421 Use the shared library, but some functions are only in
422 the static library, so try that secondarily. */
423 OUTPUT_FORMAT(elf64-x86-64)
424 GROUP ( /lib/libc.so.6 /usr/lib/libc_nonshared.a
425 AS_NEEDED ( /lib/ld-linux-x86-64.so.2 ) )
427 contents = node.get_text_contents()
428 if contents.startswith('!<arch>\n') or contents.startswith('\177ELF'):
429 # An archive or ELF file is not a linker script.
432 comment_pattern = re.compile(r'/\*.*?\*/', re.DOTALL | re.MULTILINE)
433 def remove_comments(text):
434 return re.sub(comment_pattern, '', text)
436 tokens = remove_comments(contents).split()
440 if token.startswith('OUTPUT_FORMAT('):
442 elif token == 'OUTPUT_FORMAT':
443 # Swallow the next three tokens: '(', 'xyz', ')'
445 elif token in ['(', ')', 'INPUT', 'GROUP', 'AS_NEEDED']:
450 # Find those items in the library path, ignoring ones we fail to find.
451 found = [SCons.Node.FS.find_file(lib, libpath) for lib in libs]
452 return [lib for lib in found if lib is not None]
454 # This is a modified copy of the class TempFileMunge in
455 # third_party/scons-2.0.1/engine/SCons/Platform/__init__.py.
456 # It differs in using quote_for_at_file (below) in place of
457 # SCons.Subst.quote_spaces.
458 class NaClTempFileMunge(object):
459 """A callable class. You can set an Environment variable to this,
460 then call it with a string argument, then it will perform temporary
461 file substitution on it. This is used to circumvent the long command
465 env["TEMPFILE"] = TempFileMunge
466 env["LINKCOM"] = "${TEMPFILE('$LINK $TARGET $SOURCES')}"
468 By default, the name of the temporary file used begins with a
469 prefix of '@'. This may be configred for other tool chains by
470 setting '$TEMPFILEPREFIX'.
472 env["TEMPFILEPREFIX"] = '-@' # diab compiler
473 env["TEMPFILEPREFIX"] = '-via' # arm tool chain
475 def __init__(self, cmd):
478 def __call__(self, target, source, env, for_signature):
480 # If we're being called for signature calculation, it's
481 # because we're being called by the string expansion in
482 # Subst.py, which has the logic to strip any $( $) that
483 # may be in the command line we squirreled away. So we
484 # just return the raw command line and let the upper
485 # string substitution layers do their thing.
488 # Now we're actually being called because someone is actually
489 # going to try to execute the command, so we have to do our
491 cmd = env.subst_list(self.cmd, SCons.Subst.SUBST_CMD, target, source)[0]
493 maxline = int(env.subst('$MAXLINELENGTH'))
500 if length <= maxline:
503 # We do a normpath because mktemp() has what appears to be
504 # a bug in Windows that will use a forward slash as a path
505 # delimiter. Windows's link mistakes that for a command line
508 # We use the .lnk suffix for the benefit of the Phar Lap
509 # linkloc linker, which likes to append an .lnk suffix if
511 (fd, tmp) = tempfile.mkstemp('.lnk', text=True)
512 native_tmp = SCons.Util.get_native_path(os.path.normpath(tmp))
514 if env['SHELL'] and env['SHELL'] == 'sh':
515 # The sh shell will try to escape the backslashes in the
516 # path, so unescape them.
517 native_tmp = native_tmp.replace('\\', r'\\\\')
518 # In Cygwin, we want to use rm to delete the temporary
519 # file, because del does not exist in the sh shell.
520 rm = env.Detect('rm') or 'del'
522 # Don't use 'rm' if the shell is not sh, because rm won't
523 # work with the Windows shells (cmd.exe or command.com) or
524 # Windows path names.
527 prefix = env.subst('$TEMPFILEPREFIX')
531 # The @file is sometimes handled by a GNU tool itself, using
532 # the libiberty/argv.c code, and sometimes handled implicitly
533 # by Cygwin before the tool's own main even sees it. These
534 # two treat the contents differently, so there is no single
535 # perfect way to quote. The libiberty @file code uses a very
536 # regular scheme: a \ in any context is always swallowed and
537 # quotes the next character, whatever it is; '...' or "..."
538 # quote whitespace in ... and the outer quotes are swallowed.
539 # The Cygwin @file code uses a vaguely similar scheme, but its
540 # treatment of \ is much less consistent: a \ outside a quoted
541 # string is never stripped, and a \ inside a quoted string is
542 # only stripped when it quoted something (Cygwin's definition
543 # of "something" here is nontrivial). In our uses the only
544 # appearances of \ we expect are in Windows-style file names.
545 # Fortunately, an extra doubling of \\ that doesn't get
546 # stripped is harmless in the middle of a file name.
547 def quote_for_at_file(s):
549 if ' ' in s or '\t' in s:
550 return '"' + re.sub('([ \t"])', r'\\\1', s) + '"'
551 return s.replace('\\', '\\\\')
553 args = list(map(quote_for_at_file, cmd[1:]))
554 os.write(fd, " ".join(args) + "\n")
556 # XXX Using the SCons.Action.print_actions value directly
557 # like this is bogus, but expedient. This class should
558 # really be rewritten as an Action that defines the
559 # __call__() and strfunction() methods and lets the
560 # normal action-execution logic handle whether or not to
561 # print/execute the action. The problem, though, is all
562 # of that is decided before we execute this method as
563 # part of expanding the $TEMPFILE construction variable.
564 # Consequently, refactoring this will have to wait until
565 # we get more flexible with allowing Actions to exist
566 # independently and get strung together arbitrarily like
567 # Ant tasks. In the meantime, it's going to be more
568 # user-friendly to not let obsession with architectural
569 # purity get in the way of just being helpful, so we'll
570 # reach into SCons.Action directly.
571 if SCons.Action.print_actions:
572 print("Using tempfile "+native_tmp+" for command line:\n"+
573 str(cmd[0]) + " " + " ".join(args))
574 return [ cmd[0], prefix + native_tmp + '\n' + rm, native_tmp ]
577 """SCons entry point for this tool.
580 env: The SCons environment in question.
582 NOTE: SCons requires the use of this name, which fails lint.
585 # make these methods to the top level scons file
586 env.AddMethod(ValidateSdk)
587 env.AddMethod(AddBiasForPNaCl)
588 env.AddMethod(PNaClForceNative)
589 env.AddMethod(PNaClGetNNaClEnv)
591 # Invoke the various unix tools that the NativeClient SDK resembles.
598 if env.Bit('pnacl_generate_pexe'):
599 suffix = '.nonfinal.pexe'
604 COMPONENT_LINKFLAGS=[''],
605 COMPONENT_LIBRARY_LINK_SUFFIXES=['.pso', '.so', '.a'],
607 COMPONENT_LIBRARY_DEBUG_SUFFIXES=[],
609 # adding BASE_ AND EXTRA_ flags to common command lines
610 # The suggested usage pattern is:
611 # BASE_XXXFLAGS can only be set in this file
612 # EXTRA_XXXFLAGS can only be set in a ComponentXXX call
613 # NOTE: we also have EXTRA_LIBS which is handles separately in
614 # site_scons/site_tools/component_builders.py
615 # NOTE: the command lines were gleaned from:
616 # * ../third_party/scons-2.0.1/engine/SCons/Tool/cc.py
617 # * ../third_party/scons-2.0.1/engine/SCons/Tool/c++.py
619 CCCOM='$CC $BASE_CFLAGS $CFLAGS $EXTRA_CFLAGS ' +
620 '$CCFLAGS $_CCCOMCOM -c -o $TARGET $SOURCES',
621 SHCCCOM='$SHCC $BASE_CFLAGS $SHCFLAGS $EXTRA_CFLAGS ' +
622 '$SHCCFLAGS $_CCCOMCOM -c -o $TARGET $SOURCES',
624 CXXCOM='$CXX $BASE_CXXFLAGS $CXXFLAGS $EXTRA_CXXFLAGS ' +
625 '$CCFLAGS $_CCCOMCOM -c -o $TARGET $SOURCES',
626 SHCXXCOM='$SHCXX $BASE_CXXFLAGS $SHCXXFLAGS $EXTRA_CXXFLAGS ' +
627 '$SHCCFLAGS $_CCCOMCOM -c -o $TARGET $SOURCES',
629 LINKCOM='$LINK $BASE_LINKFLAGS $LINKFLAGS $EXTRA_LINKFLAGS ' +
630 '$SOURCES $_LIBDIRFLAGS $_LIBFLAGS -o $TARGET',
631 SHLINKCOM='$SHLINK $BASE_LINKFLAGS $SHLINKFLAGS $EXTRA_LINKFLAGS ' +
632 '$SOURCES $_LIBDIRFLAGS $_LIBFLAGS -o $TARGET',
634 ASCOM='$AS $BASE_ASFLAGS $ASFLAGS $EXTRA_ASFLAGS -o $TARGET $SOURCES',
635 ASPPCOM='$ASPP $BASE_ASPPFLAGS $ASPPFLAGS $EXTRA_ASPPFLAGS ' +
636 '$CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS -c -o $TARGET $SOURCES',
638 # Strip doesn't seem to be a first-class citizen in SCons country,
639 # so we have to add these *COM, *COMSTR manually.
640 # Note: it appears we cannot add this in component_setup.py
641 STRIPFLAGS=['--strip-all'],
642 STRIPCOM='${STRIP} ${STRIPFLAGS}',
643 TRANSLATECOM='${TRANSLATE} ${TRANSLATEFLAGS} ${SOURCES} -o ${TARGET}',
644 PNACLFINALIZEFLAGS=[],
645 PNACLFINALIZECOM='${PNACLFINALIZE} ${PNACLFINALIZEFLAGS} ' +
646 '${SOURCES} -o ${TARGET}',
649 # Windows has a small limit on the command line size. The linking and AR
650 # commands can get quite large. So bring in the SCons machinery to put
651 # most of a command line into a temporary file and pass it with
652 # @filename, which works with gcc.
653 if env['PLATFORM'] in ['win32', 'cygwin']:
654 env['TEMPFILE'] = NaClTempFileMunge
655 for com in ['LINKCOM', 'SHLINKCOM', 'ARCOM']:
656 env[com] = "${TEMPFILE('%s')}" % env[com]
658 # Get root of the SDK.
659 root = env.GetToolchainDir()
661 # if bitcode=1 use pnacl toolchain
662 if env.Bit('bitcode'):
663 _SetEnvForPnacl(env, root)
665 # Get GDB from the nacl-gcc toolchain even when using PNaCl.
666 # TODO(mseaborn): We really want the nacl-gdb binary to be in a
667 # separate tarball from the nacl-gcc toolchain, then this step
668 # will not be necessary.
669 # See http://code.google.com/p/nativeclient/issues/detail?id=2773
670 if env.Bit('target_x86'):
671 temp_env = env.Clone()
672 temp_env.ClearBits('bitcode')
673 temp_root = temp_env.GetToolchainDir()
674 _SetEnvForNativeSdk(temp_env, temp_root)
675 env.Replace(GDB=temp_env['GDB'])
676 elif env.Bit('built_elsewhere'):
677 _StubOutEnvToolsForBuiltElsewhere(env)
679 _SetEnvForNativeSdk(env, root)
681 env.Prepend(LIBPATH='${NACL_SDK_LIB}')
683 # Install our scanner for (potential) linker scripts.
684 # It applies to "source" files ending in .a or .so.
685 # Dependency files it produces are to be found in ${LIBPATH}.
686 # It is applied recursively to those dependencies in case
687 # some of them are linker scripts too.
688 ldscript_scanner = SCons.Scanner.Base(
689 function=ScanLinkerScript,
690 skeys=['.a', '.so', '.pso'],
691 path_function=SCons.Scanner.FindPathDirs('LIBPATH'),
694 env.Append(SCANNERS=ldscript_scanner)
696 # Scons tests can check this version number to decide whether to
697 # enable tests for toolchain bug fixes or new features. See
698 # description in pnacl/build.sh.
699 if 'toolchain_feature_version' in SCons.Script.ARGUMENTS:
700 version = int(SCons.Script.ARGUMENTS['toolchain_feature_version'])
702 version_file = os.path.join(root, 'FEATURE_VERSION')
703 # There is no pnacl_newlib toolchain on ARM, only a pnacl_translator, so
704 # use that if necessary. Otherwise use it if we are doing sandboxed
706 if not os.path.exists(version_file) or env.Bit('use_sandboxed_translator'):
707 version_file = os.path.join(os.path.dirname(root), 'pnacl_translator',
709 if os.path.exists(version_file):
710 with open(version_file, 'r') as fh:
711 version = int(fh.read())
714 env.Replace(TOOLCHAIN_FEATURE_VERSION=version)