Upstream version 6.35.121.0
[platform/framework/web/crosswalk.git] / src / native_client / toolchain_build / toolchain_build_pnacl.py
1 #!/usr/bin/python
2 # Copyright (c) 2013 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 """Recipes for PNaCl toolchain packages.
7
8    Recipes consist of specially-structured dictionaries, with keys for package
9    name, type, commands to execute, etc. The structure is documented in the
10    PackageBuilder docstring in toolchain_main.py.
11
12    The real entry plumbing and CLI flags are also in toolchain_main.py.
13 """
14
15 import base64
16 import fnmatch
17 import logging
18 import os
19 import re
20 import shutil
21 import stat
22 import subprocess
23 import sys
24 import zipfile
25
26 sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
27 import pynacl.gsd_storage
28 import pynacl.platform
29 import pynacl.repo_tools
30
31 import command
32 import pnacl_commands
33 import pnacl_targetlibs
34 import toolchain_main
35
36 SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
37 NACL_DIR = os.path.dirname(SCRIPT_DIR)
38 # Use the argparse from third_party to ensure it's the same on all platorms
39 python_lib_dir = os.path.join(os.path.dirname(NACL_DIR), 'third_party',
40                               'python_libs', 'argparse')
41 sys.path.insert(0, python_lib_dir)
42 import argparse
43
44 # Scons tests can check this version number to decide whether to enable tests
45 # for toolchain bug fixes or new features.  This allows tests to be enabled on
46 # the toolchain buildbots/trybots before the new toolchain version is rolled
47 # into TOOL_REVISIONS (i.e. before the tests would pass on the main NaCl
48 # buildbots/trybots).  If you are adding a test that depends on a toolchain
49 # change, you can increment this version number manually.
50 FEATURE_VERSION = 4
51
52 # For backward compatibility, these key names match the directory names
53 # previously used with gclient
54 GIT_REPOS = {
55     'binutils': 'nacl-binutils.git',
56     'clang': 'pnacl-clang.git',
57     'llvm': 'pnacl-llvm.git',
58     'gcc': 'pnacl-gcc.git',
59     'libcxx': 'pnacl-libcxx.git',
60     'libcxxabi': 'pnacl-libcxxabi.git',
61     'nacl-newlib': 'nacl-newlib.git',
62     'llvm-test-suite': 'pnacl-llvm-testsuite.git',
63     'compiler-rt': 'pnacl-compiler-rt.git',
64     }
65
66 GIT_BASE_URL = 'https://chromium.googlesource.com/native_client/'
67 GIT_DEPS_FILE = os.path.join(NACL_DIR, 'pnacl', 'COMPONENT_REVISIONS')
68
69 # TODO(dschuff): Some of this cygwin/mingw logic duplicates stuff in command.py
70 # and the mechanism for switching between cygwin and mingw is bad.
71 # Path to the hermetic cygwin
72 BUILD_CROSS_MINGW = False
73 CYGWIN_PATH = os.path.join(NACL_DIR, 'cygwin')
74 # Path to the mingw cross-compiler libs on Ubuntu
75 CROSS_MINGW_LIBPATH = '/usr/lib/gcc/i686-w64-mingw32/4.6'
76 # Path and version of the native mingw compiler to be installed on Windows hosts
77 MINGW_PATH = os.path.join(NACL_DIR, 'mingw32')
78 MINGW_VERSION = 'i686-w64-mingw32-4.8.1'
79
80 ALL_ARCHES = ('x86-32', 'x86-64', 'arm', 'mips32', 'x86-32-nonsfi')
81 # MIPS32 doesn't use biased bitcode, and nonsfi targets don't need it.
82 BITCODE_BIASES = tuple(bias for bias in ('portable', 'x86-32', 'x86-64', 'arm'))
83
84 MAKE_DESTDIR_CMD = ['make', 'DESTDIR=%(abs_output)s']
85
86 def TripleIsWindows(t):
87   return fnmatch.fnmatch(t, '*-mingw32*') or fnmatch.fnmatch(t, '*cygwin*')
88
89
90 def CompilersForHost(host):
91   compiler = {
92       # For now we only do native builds for linux and mac
93       'i686-linux': ('gcc', 'g++'), # treat 32-bit linux like a native build
94       'x86_64-linux': ('gcc', 'g++'),
95       # TODO(dschuff): switch to clang on mac
96       'x86_64-apple-darwin': ('gcc', 'g++'),
97       # Windows build should work for native and cross
98       'i686-w64-mingw32': ('i686-w64-mingw32-gcc', 'i686-w64-mingw32-g++'),
99       # TODO: add arm-hosted support
100   }
101   return compiler[host]
102
103
104 def ConfigureHostArchFlags(host):
105   configure_args = []
106   extra_cc_args = []
107
108   native = pynacl.platform.PlatformTriple()
109   is_cross = host != native
110   if is_cross:
111     if (pynacl.platform.IsLinux64() and
112         fnmatch.fnmatch(host, '*-linux*')):
113       # 64 bit linux can build 32 bit linux binaries while still being a native
114       # build for our purposes. But it's not what config.guess will yield, so
115       # use --build to force it and make sure things build correctly.
116       configure_args.append('--build=' + host)
117       extra_cc_args = ['-m32']
118     else:
119       configure_args.append('--host=' + host)
120
121   extra_cxx_args = list(extra_cc_args)
122
123   cc, cxx = CompilersForHost(host)
124
125   if is_cross:
126     # LLVM's linux->mingw cross build needs this
127     configure_args.append('CC_FOR_BUILD=gcc')
128
129   configure_args.append('CC=' + ' '.join([cc] + extra_cc_args))
130   configure_args.append('CXX=' + ' '.join([cxx] + extra_cxx_args))
131
132   if TripleIsWindows(host):
133     # The i18n support brings in runtime dependencies on MinGW DLLs
134     # that we don't want to have to distribute alongside our binaries.
135     # So just disable it, and compiler messages will always be in US English.
136     configure_args.append('--disable-nls')
137     if not command.Runnable.use_cygwin:
138       configure_args.extend(['LDFLAGS=-L%(abs_libdl)s',
139                              'CFLAGS=-isystem %(abs_libdl)s',
140                              'CXXFLAGS=-isystem %(abs_libdl)s'])
141   return configure_args
142
143
144 def CmakeHostArchFlags(host, options):
145   cmake_flags = []
146   if options.clang:
147     cc ='%(abs_top_srcdir)s/../third_party/llvm-build/Release+Asserts/bin/clang'
148     cxx = cc + '++'
149   else:
150     cc, cxx = CompilersForHost(host)
151   cmake_flags.extend(['-DCMAKE_C_COMPILER='+cc, '-DCMAKE_CXX_COMPILER='+cxx])
152
153   if pynacl.platform.IsLinux64() and pynacl.platform.PlatformTriple() != host:
154     # Currently the only supported "cross" build is 64-bit Linux to 32-bit
155     # Linux. Enable it, and disable libxml because Ubuntu doesn't have a
156     # 32-bit libxml build.
157     cmake_flags.extend(['-DLLVM_BUILD_32_BITS=ON',
158                         '-DLLVM_ENABLE_LIBXML=OFF'])
159
160   if options.sanitize:
161     cmake_flags.extend(['-DCMAKE_%s_FLAGS=-fsanitize=%s' % (c, options.sanitize)
162                         for c in ('C', 'CXX')])
163     cmake_flags.append('-DCMAKE_EXE_LINKER_FLAGS=-fsanitize=%s' %
164                        options.sanitize)
165   return cmake_flags
166
167
168 def MakeCommand(host):
169   make_command = ['make']
170   if (not pynacl.platform.IsWindows() or
171       command.Runnable.use_cygwin):
172     # The make that ships with msys sometimes hangs when run with -j.
173     # The ming32-make that comes with the compiler itself reportedly doesn't
174     # have this problem, but it has issues with pathnames with LLVM's build.
175     make_command.append('-j%(cores)s')
176
177   if TripleIsWindows(host):
178     # There appears to be nothing we can pass at top-level configure time
179     # that will prevent the configure scripts from finding MinGW's libiconv
180     # and using it.  We have to force this variable into the environment
181     # of the sub-configure runs, which are run via make.
182     make_command.append('HAVE_LIBICONV=no')
183   return make_command
184
185
186 def CopyWindowsHostLibs(host):
187   if not TripleIsWindows(host):
188     return []
189   if command.Runnable.use_cygwin:
190     libs = ('cyggcc_s-1.dll', 'cygiconv-2.dll', 'cygwin1.dll', 'cygintl-8.dll',
191             'cygstdc++-6.dll', 'cygz.dll')
192     return [command.Copy(
193                     os.path.join(CYGWIN_PATH, 'bin', lib),
194                     os.path.join('%(output)s', 'bin', lib))
195                 for lib in libs]
196   if pynacl.platform.IsWindows():
197     lib_path = os.path.join(MINGW_PATH, 'bin')
198     # The native minGW compiler uses winpthread, but the Ubuntu cross compiler
199     # does not.
200     libs = ('libgcc_s_sjlj-1.dll', 'libstdc++-6.dll', 'libwinpthread-1.dll')
201   else:
202     lib_path = os.path.join(CROSS_MINGW_LIBPATH)
203     libs = ('libgcc_s_sjlj-1.dll', 'libstdc++-6.dll')
204   return [command.Copy(
205                   os.path.join(lib_path, lib),
206                   os.path.join('%(output)s', 'bin', lib))
207                for lib in libs]
208
209 def GetGitSyncCmdCallback(revisions):
210   """Return a callback which returns the git sync command for a component.
211
212      This allows all the revision information to be processed here while giving
213      other modules like pnacl_targetlibs.py the ability to define their own
214      source targets with minimal boilerplate.
215   """
216   def GetGitSyncCmd(component):
217     return command.SyncGitRepo(GIT_BASE_URL + GIT_REPOS[component],
218                              '%(output)s',
219                              revisions[component])
220   return GetGitSyncCmd
221
222 def HostToolsSources(GetGitSyncCmd):
223   sources = {
224       'binutils_pnacl_src': {
225           'type': 'source',
226           'output_dirname': 'binutils',
227           'commands': [
228               GetGitSyncCmd('binutils'),
229           ],
230       },
231       # For some reason, the llvm build using --with-clang-srcdir chokes if the
232       # clang source directory is named something other than 'clang', so don't
233       # change output_dirname for clang.
234       'clang_src': {
235           'type': 'source',
236           'output_dirname': 'clang',
237           'commands': [
238               GetGitSyncCmd('clang'),
239           ],
240       },
241       'llvm_src': {
242           'type': 'source',
243           'output_dirname': 'llvm',
244           'commands': [
245               GetGitSyncCmd('llvm'),
246           ],
247       },
248   }
249   return sources
250
251
252 def HostLibs(host):
253   libs = {}
254   if TripleIsWindows(host) and not command.Runnable.use_cygwin:
255     if pynacl.platform.IsWindows():
256       ar = 'ar'
257     else:
258       ar = 'i686-w64-mingw32-ar'
259
260     libs.update({
261       'libdl': {
262           'type': 'build',
263           'inputs' : { 'src' : os.path.join(NACL_DIR, '..', 'third_party',
264                                             'dlfcn-win32') },
265           'commands': [
266               command.CopyTree('%(src)s', '.'),
267               command.Command(['i686-w64-mingw32-gcc',
268                                '-o', 'dlfcn.o', '-c', 'dlfcn.c',
269                                '-Wall', '-O3', '-fomit-frame-pointer']),
270               command.Command([ar, 'cru',
271                                'libdl.a', 'dlfcn.o']),
272               command.Copy('libdl.a',
273                            os.path.join('%(output)s', 'libdl.a')),
274               command.Copy('dlfcn.h',
275                            os.path.join('%(output)s', 'dlfcn.h')),
276           ],
277       },
278     })
279   return libs
280
281
282 def HostTools(host, options):
283   def H(component_name):
284     # Return a package name for a component name with a host triple.
285     return component_name + '_' + pynacl.gsd_storage.LegalizeName(host)
286   def IsHost64(host):
287     return fnmatch.fnmatch(host, 'x86_64*')
288   def HostSubdir(host):
289     return 'host_x86_64' if IsHost64(host) else 'host_x86_32'
290   def BinSubdir(host):
291     return 'bin64' if host == 'x86_64-linux' else 'bin'
292   tools = {
293       H('binutils_pnacl'): {
294           'dependencies': ['binutils_pnacl_src'],
295           'type': 'build',
296           'output_subdir': HostSubdir(host),
297           'commands': [
298               command.SkipForIncrementalCommand([
299                   'sh',
300                   '%(binutils_pnacl_src)s/configure'] +
301                   ConfigureHostArchFlags(host) +
302                   ['--prefix=',
303                   '--disable-silent-rules',
304                   '--target=arm-pc-nacl',
305                   '--program-prefix=le32-nacl-',
306                   '--enable-targets=arm-pc-nacl,i686-pc-nacl,x86_64-pc-nacl,' +
307                   'mipsel-pc-nacl',
308                   '--enable-deterministic-archives',
309                   '--enable-shared=no',
310                   '--enable-gold=default',
311                   '--enable-ld=no',
312                   '--enable-plugins',
313                   '--without-gas',
314                   '--without-zlib',
315                   '--with-sysroot=/arm-pc-nacl']),
316               command.Command(MakeCommand(host)),
317               command.Command(MAKE_DESTDIR_CMD + ['install-strip'])] +
318               [command.RemoveDirectory(os.path.join('%(output)s', dir))
319                for dir in ('arm-pc-nacl', 'lib', 'lib32')]
320       },
321       H('driver'): {
322         'type': 'build',
323         'output_subdir': BinSubdir(host),
324         'inputs': { 'src': os.path.join(NACL_DIR, 'pnacl', 'driver')},
325         'commands': [
326             command.Runnable(pnacl_commands.InstallDriverScripts,
327                              '%(src)s', '%(output)s',
328                              host_windows=TripleIsWindows(host),
329                              host_64bit=IsHost64(host))
330         ],
331       },
332   }
333   llvm_cmake = {
334       H('llvm'): {
335           'dependencies': ['clang_src', 'llvm_src', 'binutils_pnacl_src'],
336           'type': 'build',
337           'output_subdir': HostSubdir(host),
338           'commands': [
339               command.SkipForIncrementalCommand([
340                   'cmake', '-G', 'Ninja'] +
341                   CmakeHostArchFlags(host, options) +
342                   ['-DCMAKE_BUILD_TYPE=RelWithDebInfo',
343                   '-DCMAKE_INSTALL_PREFIX=%(output)s',
344                   '-DCMAKE_INSTALL_RPATH=$ORIGIN/../lib',
345                   '-DBUILD_SHARED_LIBS=ON',
346                   '-DLLVM_ENABLE_ASSERTIONS=ON',
347                   '-DLLVM_ENABLE_ZLIB=OFF',
348                   '-DLLVM_BUILD_TESTS=ON',
349                   '-DLLVM_APPEND_VC_REV=ON',
350                   '-DLLVM_BINUTILS_INCDIR=%(abs_binutils_pnacl_src)s/include',
351                   '-DLLVM_EXTERNAL_CLANG_SOURCE_DIR=%(clang_src)s',
352                   '%(llvm_src)s']),
353               command.Command(['ninja', '-v']),
354               command.Command(['ninja', 'install']),
355         ],
356       },
357   }
358   llvm_autoconf = {
359       H('llvm'): {
360           'dependencies': ['clang_src', 'llvm_src', 'binutils_pnacl_src'],
361           'type': 'build',
362           'output_subdir': HostSubdir(host),
363           'commands': [
364               command.SkipForIncrementalCommand([
365                   'sh',
366                   '%(llvm_src)s/configure'] +
367                   ConfigureHostArchFlags(host) +
368                   ['--prefix=/',
369                    '--enable-shared',
370                    '--disable-zlib',
371                    '--disable-terminfo',
372                    '--disable-jit',
373                    '--disable-bindings', # ocaml is currently the only binding.
374                    '--with-binutils-include=%(abs_binutils_pnacl_src)s/include',
375                    '--enable-targets=x86,arm,mips',
376                    '--program-prefix=',
377                    '--enable-optimized',
378                    '--with-clang-srcdir=%(abs_clang_src)s']),
379               command.Command(MakeCommand(host) + [
380                   'VERBOSE=1',
381                   'NACL_SANDBOX=0',
382                   'all']),
383               command.Command(MAKE_DESTDIR_CMD + ['install'])] +
384               CopyWindowsHostLibs(host),
385       },
386   }
387   if options.cmake:
388     tools.update(llvm_cmake)
389   else:
390     tools.update(llvm_autoconf)
391   if TripleIsWindows(host) and not command.Runnable.use_cygwin:
392     tools[H('binutils_pnacl')]['dependencies'].append('libdl')
393     tools[H('llvm')]['dependencies'].append('libdl')
394   return tools
395
396 # TODO(dschuff): The REV file should probably go here rather than in the driver
397 # dir
398 def Metadata():
399   data = {
400       'metadata': {
401           'type': 'build',
402           'inputs': { 'readme': os.path.join(NACL_DIR, 'pnacl', 'README') },
403           'commands': [
404               command.Copy('%(readme)s', os.path.join('%(output)s', 'README')),
405               command.WriteData(str(FEATURE_VERSION),
406                                 os.path.join('%(output)s', 'FEATURE_VERSION')),
407           ],
408       }
409   }
410   return data
411
412 def ParseComponentRevisionsFile(filename):
413   ''' Parse a simple-format deps file, with fields of the form:
414 key=value
415 Keys should match the keys in GIT_REPOS above, which match the previous
416 directory names used by gclient (with the exception that '_' in the file is
417 replaced by '-' in the returned key name).
418 Values are the git hashes for each repo.
419 Empty lines or lines beginning with '#' are ignored.
420 This function returns a dictionary mapping the keys found in the file to their
421 values.
422 '''
423   with open(filename) as f:
424     deps = {}
425     for line in f:
426       stripped = line.strip()
427       if stripped.startswith('#') or len(stripped) == 0:
428         continue
429       tokens = stripped.split('=')
430       if len(tokens) != 2:
431         raise Exception('Malformed component revisions file: ' + filename)
432       deps[tokens[0].replace('_', '-')] = tokens[1]
433   return deps
434
435 # This is to replace build.sh's use of gclient, which will eliminate the issues
436 # with msys vs cygwin git checkouts, and make testing easier. Note that the new
437 # build scripts will not share source directories with build.sh.
438 def SyncPNaClRepos(revisions):
439   sys.stdout.flush()
440   for repo, revision in revisions.iteritems():
441     destination = os.path.join(NACL_DIR, 'pnacl', 'git', repo)
442     # This replaces build.sh's newlib-nacl-headers-clean step by cleaning the
443     # the newlib repo on checkout (while silently blowing away any local
444     # changes). TODO(dschuff): find a better way to handle nacl newlib headers.
445     is_newlib = repo == 'nacl-newlib'
446     pynacl.repo_tools.SyncGitRepo(
447         GIT_BASE_URL + GIT_REPOS[repo],
448         destination,
449         revision,
450         clean=is_newlib
451     )
452
453     # For testing LLVM, Clang, etc. changes on the trybots, look for a
454     # Git bundle file created by llvm_change_try_helper.sh.
455     bundle_file = os.path.join(NACL_DIR, 'pnacl', 'not_for_commit',
456                                '%s_bundle' % repo)
457     base64_file = '%s.b64' % bundle_file
458     if os.path.exists(base64_file):
459       input_fh = open(base64_file, 'r')
460       output_fh = open(bundle_file, 'wb')
461       base64.decode(input_fh, output_fh)
462       input_fh.close()
463       output_fh.close()
464       subprocess.check_call(
465           pynacl.repo_tools.GitCmd() + ['fetch'],
466           cwd=destination
467       )
468       subprocess.check_call(
469           pynacl.repo_tools.GitCmd() + ['bundle', 'unbundle', bundle_file],
470           cwd=destination
471       )
472       commit_id_file = os.path.join(NACL_DIR, 'pnacl', 'not_for_commit',
473                                     '%s_commit_id' % repo)
474       commit_id = open(commit_id_file, 'r').readline().strip()
475       subprocess.check_call(
476           pynacl.repo_tools.GitCmd() + ['checkout', commit_id],
477           cwd=destination
478       )
479
480
481 def InstallMinGWHostCompiler():
482   """Install the MinGW host compiler used to build the host tools on Windows.
483
484   We could use an ordinary source rule for this, but that would require hashing
485   hundreds of MB of toolchain files on every build. Instead, check for the
486   presence of the specially-named file <version>.installed in the install
487   directory. If it is absent, check for the presence of the zip file
488   <version>.zip. If it is absent, attempt to download it from Google Storage.
489   Then extract the zip file and create the install file.
490   """
491   if not os.path.isfile(os.path.join(MINGW_PATH, MINGW_VERSION + '.installed')):
492     downloader = pynacl.gsd_storage.GSDStorage([], ['nativeclient-mingw'])
493     zipfilename = MINGW_VERSION + '.zip'
494     zipfilepath = os.path.join(NACL_DIR, zipfilename)
495     # If the zip file is not present, try to download it from Google Storage.
496     # If that fails, bail out.
497     if (not os.path.isfile(zipfilepath) and
498         not downloader.GetSecureFile(zipfilename, zipfilepath)):
499         print >>sys.stderr, 'Failed to install MinGW tools:'
500         print >>sys.stderr, 'could not find or download', zipfilename
501         sys.exit(1)
502     logging.info('Extracting %s' % zipfilename)
503     zf = zipfile.ZipFile(zipfilepath)
504     if os.path.exists(MINGW_PATH):
505       shutil.rmtree(MINGW_PATH)
506     zf.extractall(NACL_DIR)
507     with open(os.path.join(MINGW_PATH, MINGW_VERSION + '.installed'), 'w') as _:
508       pass
509   os.environ['MINGW'] = MINGW_PATH
510
511 if __name__ == '__main__':
512   # This sets the logging for gclient-alike repo sync. It will be overridden
513   # by the package builder based on the command-line flags.
514   logging.getLogger().setLevel(logging.DEBUG)
515   parser = argparse.ArgumentParser(add_help=False)
516   parser.add_argument('--legacy-repo-sync', action='store_true',
517                       dest='legacy_repo_sync', default=False,
518                       help='Sync the git repo directories used by build.sh')
519   parser.add_argument('--build-64bit-host', action='store_true',
520                       dest='build_64bit_host', default=False,
521                       help='Build 64-bit Linux host binaries in addition to 32')
522   parser.add_argument('--cmake', action='store_true', default=False,
523                       help="Use LLVM's cmake ninja build instead of autoconf")
524   parser.add_argument('--clang', action='store_true', default=False,
525                       help="Use clang instead of gcc with LLVM's cmake build")
526   parser.add_argument('--sanitize', choices=['address', 'thread', 'undefined'],
527                       help="Use a sanitizer with LLVM's clang cmake build")
528   args, leftover_args = parser.parse_known_args()
529   if '-h' in leftover_args or '--help' in leftover_args:
530     print 'The following arguments are specific to toolchain_build_pnacl.py:'
531     parser.print_help()
532     print 'The rest of the arguments are generic, in toolchain_main.py'
533
534   if args.sanitize and not args.cmake:
535     print 'Use of sanitizers requires a cmake build'
536     sys.exit(1)
537   if args.clang and not args.cmake:
538     print 'Use of clang is currently only supported with cmake/ninja'
539     sys.exit(1)
540
541   revisions = ParseComponentRevisionsFile(GIT_DEPS_FILE)
542   if args.legacy_repo_sync:
543     SyncPNaClRepos(revisions)
544     sys.exit(0)
545
546   if pynacl.platform.IsWindows() and not command.Runnable.use_cygwin:
547     InstallMinGWHostCompiler()
548
549   packages = {}
550   packages.update(HostToolsSources(GetGitSyncCmdCallback(revisions)))
551
552   if pynacl.platform.IsLinux64():
553     hosts = ['i686-linux']
554     if args.build_64bit_host:
555       hosts.append(pynacl.platform.PlatformTriple())
556   else:
557     hosts = [pynacl.platform.PlatformTriple()]
558   if pynacl.platform.IsLinux() and BUILD_CROSS_MINGW:
559     hosts.append('i686-w64-mingw32')
560   for host in hosts:
561     packages.update(HostLibs(host))
562     packages.update(HostTools(host, args))
563   # Don't build the target libs on Windows because of pathname issues.
564   # Don't build the target libs on Mac because the gold plugin's rpaths
565   # aren't right.
566   # On linux use the 32-bit compiler to build the target libs since that's what
567   # most developers will be using.
568   if pynacl.platform.IsLinux():
569     packages.update(pnacl_targetlibs.TargetLibsSrc(
570       GetGitSyncCmdCallback(revisions)))
571     for bias in BITCODE_BIASES:
572       packages.update(pnacl_targetlibs.BitcodeLibs(hosts[0], bias))
573     for arch in ALL_ARCHES:
574       packages.update(pnacl_targetlibs.NativeLibs(hosts[0], arch))
575     packages.update(pnacl_targetlibs.NativeLibsUnsandboxed('x86-32-linux'))
576   packages.update(Metadata())
577
578   tb = toolchain_main.PackageBuilder(packages,
579                                      leftover_args)
580   tb.Main()