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.
6 """Recipes for PNaCl toolchain packages.
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.
12 The real entry plumbing and CLI flags are also in toolchain_main.py.
22 sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
23 import pynacl.gsd_storage
24 import pynacl.platform
25 import pynacl.repo_tools
29 import pnacl_targetlibs
32 SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
33 NACL_DIR = os.path.dirname(SCRIPT_DIR)
34 # Use the argparse from third_party to ensure it's the same on all platorms
35 python_lib_dir = os.path.join(os.path.dirname(NACL_DIR), 'third_party',
36 'python_libs', 'argparse')
37 sys.path.insert(0, python_lib_dir)
40 PNACL_DRIVER_DIR = os.path.join(NACL_DIR, 'pnacl', 'driver')
41 NACL_TOOLS_DIR = os.path.join(NACL_DIR, 'tools')
43 # Scons tests can check this version number to decide whether to enable tests
44 # for toolchain bug fixes or new features. This allows tests to be enabled on
45 # the toolchain buildbots/trybots before the new toolchain version is pinned
46 # (i.e. before the tests would pass on the main NaCl buildbots/trybots).
47 # If you are adding a test that depends on a toolchain change, you can
48 # increment this version number manually.
51 # For backward compatibility, these key names match the directory names
52 # previously used with gclient
54 'binutils': 'nacl-binutils.git',
55 'clang': 'pnacl-clang.git',
56 'llvm': 'pnacl-llvm.git',
57 'gcc': 'pnacl-gcc.git',
58 'libcxx': 'pnacl-libcxx.git',
59 'libcxxabi': 'pnacl-libcxxabi.git',
60 'nacl-newlib': 'nacl-newlib.git',
61 'llvm-test-suite': 'pnacl-llvm-testsuite.git',
62 'compiler-rt': 'pnacl-compiler-rt.git',
63 'subzero': 'pnacl-subzero.git',
64 'binutils-x86': 'nacl-binutils.git',
67 GIT_BASE_URL = 'https://chromium.googlesource.com/native_client/'
68 GIT_PUSH_URL = 'ssh://gerrit.chromium.org/native_client/'
69 GIT_DEPS_FILE = os.path.join(NACL_DIR, 'pnacl', 'COMPONENT_REVISIONS')
71 ALT_GIT_BASE_URL = 'https://chromium.googlesource.com/a/native_client/'
73 KNOWN_MIRRORS = [('http://git.chromium.org/native_client/', GIT_BASE_URL)]
74 PUSH_MIRRORS = [('http://git.chromium.org/native_client/', GIT_PUSH_URL),
75 (ALT_GIT_BASE_URL, GIT_PUSH_URL),
76 (GIT_BASE_URL, GIT_PUSH_URL)]
78 PACKAGE_NAME = 'Native Client SDK [%(build_signature)s]'
79 BUG_URL = 'http://gonacl.com/reportissue'
81 # TODO(dschuff): Some of this mingw logic duplicates stuff in command.py
82 BUILD_CROSS_MINGW = False
83 # Path to the mingw cross-compiler libs on Ubuntu
84 CROSS_MINGW_LIBPATH = '/usr/lib/gcc/i686-w64-mingw32/4.6'
85 # Path and version of the native mingw compiler to be installed on Windows hosts
86 MINGW_PATH = os.path.join(NACL_DIR, 'mingw32')
87 MINGW_VERSION = 'i686-w64-mingw32-4.8.1'
89 CHROME_CLANG = os.path.join(os.path.dirname(NACL_DIR), 'third_party',
90 'llvm-build', 'Release+Asserts', 'bin', 'clang')
91 CHROME_CLANGXX = CHROME_CLANG + '++'
93 # Redirectors are small shims acting like sym links with optional arguments.
94 # For mac/linux we simply use a shell script which create small redirector
95 # shell scripts. For windows we compile an executable which redirects to
96 # the target using a compiled in table.
97 REDIRECTOR_SCRIPT = os.path.join(NACL_TOOLS_DIR, 'create_redirector.sh')
98 REDIRECTOR_WIN32_SRC = os.path.join(NACL_TOOLS_DIR, 'redirector')
100 TOOL_X64_I686_REDIRECTS = [
103 ('ld', '-melf_i386_nacl'),
106 TRANSLATOR_ARCHES = ('x86-32', 'x86-64', 'arm', 'mips32',
107 'x86-32-nonsfi', 'arm-nonsfi')
108 # MIPS32 doesn't use biased bitcode, and nonsfi targets don't need it.
109 BITCODE_BIASES = tuple(
110 bias for bias in ('le32', 'i686_bc', 'x86_64_bc', 'arm_bc'))
112 DIRECT_TO_NACL_ARCHES = ('x86_64', 'i686')
114 MAKE_DESTDIR_CMD = ['make', 'DESTDIR=%(abs_output)s']
116 def TripleIsWindows(t):
117 return fnmatch.fnmatch(t, '*-mingw32*')
119 def TripleIsCygWin(t):
120 return fnmatch.fnmatch(t, '*-cygwin*')
122 def TripleIsLinux(t):
123 return fnmatch.fnmatch(t, '*-linux*')
126 return fnmatch.fnmatch(t, '*-darwin*')
128 def TripleIsX8664(t):
129 return fnmatch.fnmatch(t, 'x86_64*')
132 # Return a tuple (C compiler, C++ compiler) of the compilers to compile the host
134 def CompilersForHost(host):
136 # For now we only do native builds for linux and mac
137 # treat 32-bit linux like a native build
138 'i686-linux': (CHROME_CLANG, CHROME_CLANGXX),
139 'x86_64-linux': (CHROME_CLANG, CHROME_CLANGXX),
140 'x86_64-apple-darwin': (CHROME_CLANG, CHROME_CLANGXX),
141 # Windows build should work for native and cross
142 'i686-w64-mingw32': ('i686-w64-mingw32-gcc', 'i686-w64-mingw32-g++'),
143 # TODO: add arm-hosted support
144 'i686-pc-cygwin': ('gcc', 'g++'),
146 return compiler[host]
150 return '_'.join([pynacl.gsd_storage.LegalizeName(arg) for arg in args])
153 def ConfigureHostArchFlags(host, extra_cflags, options):
154 """ Return flags passed to LLVM and binutils configure for compilers and
159 native = pynacl.platform.PlatformTriple()
160 is_cross = host != native
162 if (pynacl.platform.IsLinux64() and
163 fnmatch.fnmatch(host, '*-linux*')):
164 # 64 bit linux can build 32 bit linux binaries while still being a native
165 # build for our purposes. But it's not what config.guess will yield, so
166 # use --build to force it and make sure things build correctly.
167 configure_args.append('--build=' + host)
169 configure_args.append('--host=' + host)
170 if TripleIsLinux(host) and not TripleIsX8664(host):
171 # Chrome clang defaults to 64-bit builds, even when run on 32-bit Linux.
172 extra_cc_args = ['-m32']
174 extra_cxx_args = list(extra_cc_args)
177 cc, cxx = CompilersForHost(host)
179 configure_args.append('CC=' + ' '.join([cc] + extra_cc_args))
180 configure_args.append('CXX=' + ' '.join([cxx] + extra_cxx_args))
182 if TripleIsWindows(host):
183 # The i18n support brings in runtime dependencies on MinGW DLLs
184 # that we don't want to have to distribute alongside our binaries.
185 # So just disable it, and compiler messages will always be in US English.
186 configure_args.append('--disable-nls')
187 configure_args.extend(['LDFLAGS=-L%(abs_libdl)s -ldl',
188 'CFLAGS=-isystem %(abs_libdl)s',
189 'CXXFLAGS=-isystem %(abs_libdl)s'])
191 # LLVM's linux->mingw cross build needs this
192 configure_args.append('CC_FOR_BUILD=gcc')
195 configure_args.extend(['CFLAGS=' + ' '.join(extra_cflags),
196 'CXXFLAGS=' + ' '.join(extra_cflags)])
198 configure_args.extend(
199 ['CFLAGS=' + ' '.join(extra_cflags),
200 'LDFLAGS=-L%(' + GSDJoin('abs_libcxx', host) + ')s/lib',
201 'CXXFLAGS=-stdlib=libc++ -I%(' + GSDJoin('abs_libcxx', host) +
202 ')s/include/c++/v1 ' + ' '.join(extra_cflags)])
204 return configure_args
207 def LibCxxHostArchFlags(host):
208 cc, cxx = CompilersForHost(host)
210 cmake_flags.extend(['-DCMAKE_C_COMPILER='+cc, '-DCMAKE_CXX_COMPILER='+cxx])
211 if TripleIsLinux(host) and not TripleIsX8664(host):
212 # Chrome clang defaults to 64-bit builds, even when run on 32-bit Linux
213 cmake_flags.extend(['-DCMAKE_C_FLAGS=-m32',
214 '-DCMAKE_CXX_FLAGS=-m32'])
217 def CmakeHostArchFlags(host, options):
218 """ Set flags passed to LLVM cmake for compilers and compile flags. """
220 cc, cxx = CompilersForHost(host)
222 cmake_flags.extend(['-DCMAKE_C_COMPILER='+cc, '-DCMAKE_CXX_COMPILER='+cxx])
224 # There seems to be a bug in chrome clang where it exposes the msan interface
225 # (even when compiling without msan) but then does not link with an
226 # msan-enabled compiler_rt, leaving references to __msan_allocated_memory
228 cmake_flags.append('-DHAVE_SANITIZER_MSAN_INTERFACE_H=FALSE')
231 cmake_flags.extend(['-DCMAKE_%s_FLAGS=-fsanitize=%s' % (c, options.sanitize)
232 for c in ('C', 'CXX')])
233 cmake_flags.append('-DCMAKE_EXE_LINKER_FLAGS=-fsanitize=%s' %
239 def ConfigureBinutilsCommon():
240 return ['--with-pkgversion=' + PACKAGE_NAME,
241 '--with-bugurl=' + BUG_URL,
244 '--disable-silent-rules',
245 '--enable-deterministic-archives',
248 def LLVMConfigureAssertionsFlags(options):
249 if options.enable_llvm_assertions:
252 return ['--disable-debug', '--disable-assertions']
255 def MakeCommand(host):
256 make_command = ['make']
257 if not pynacl.platform.IsWindows() or pynacl.platform.IsCygWin():
258 # The make that ships with msys sometimes hangs when run with -j.
259 # The ming32-make that comes with the compiler itself reportedly doesn't
260 # have this problem, but it has issues with pathnames with LLVM's build.
261 make_command.append('-j%(cores)s')
263 if TripleIsWindows(host):
264 # There appears to be nothing we can pass at top-level configure time
265 # that will prevent the configure scripts from finding MinGW's libiconv
266 # and using it. We have to force this variable into the environment
267 # of the sub-configure runs, which are run via make.
268 make_command.append('HAVE_LIBICONV=no')
272 def CopyWindowsHostLibs(host):
273 if not TripleIsWindows(host) and not TripleIsCygWin(host):
276 if TripleIsCygWin(host):
278 libs = ('cyggcc_s-1.dll', 'cygiconv-2.dll', 'cygwin1.dll',
279 'cygintl-8.dll', 'cygstdc++-6.dll', 'cygz.dll')
280 elif pynacl.platform.IsWindows():
281 lib_path = os.path.join(MINGW_PATH, 'bin')
282 # The native minGW compiler uses winpthread, but the Ubuntu cross compiler
284 libs = ('libgcc_s_sjlj-1.dll', 'libstdc++-6.dll', 'libwinpthread-1.dll')
286 lib_path = os.path.join(CROSS_MINGW_LIBPATH)
287 libs = ('libgcc_s_sjlj-1.dll', 'libstdc++-6.dll')
288 return [command.Copy(
289 os.path.join(lib_path, lib),
290 os.path.join('%(output)s', 'bin', lib))
293 def GetGitSyncCmdsCallback(revisions):
294 """Return a callback which returns the git sync commands for a component.
296 This allows all the revision information to be processed here while giving
297 other modules like pnacl_targetlibs.py the ability to define their own
298 source targets with minimal boilerplate.
300 def GetGitSyncCmds(component):
301 git_url = GIT_BASE_URL + GIT_REPOS[component]
302 git_push_url = GIT_PUSH_URL + GIT_REPOS[component]
304 return (command.SyncGitRepoCmds(git_url, '%(output)s', revisions[component],
305 git_cache='%(git_cache_dir)s',
306 push_url=git_push_url,
307 known_mirrors=KNOWN_MIRRORS,
308 push_mirrors=PUSH_MIRRORS) +
309 [command.Runnable(lambda opts: opts.IsBot(),
310 pnacl_commands.CmdCheckoutGitBundleForTrybot,
311 component, '%(output)s')])
313 return GetGitSyncCmds
316 def HostToolsSources(GetGitSyncCmds):
320 'output_dirname': 'libcxx',
321 'commands': GetGitSyncCmds('libcxx'),
325 'output_dirname': 'libcxxabi',
326 'commands': GetGitSyncCmds('libcxxabi'),
328 'binutils_pnacl_src': {
330 'output_dirname': 'binutils',
331 'commands': GetGitSyncCmds('binutils'),
333 # For some reason, the llvm build using --with-clang-srcdir chokes if the
334 # clang source directory is named something other than 'clang', so don't
335 # change output_dirname for clang.
338 'output_dirname': 'clang',
339 'commands': GetGitSyncCmds('clang'),
343 'output_dirname': 'llvm',
344 'commands': GetGitSyncCmds('llvm'),
348 'output_dirname': 'subzero',
349 'commands': GetGitSyncCmds('subzero'),
351 'binutils_x86_src': {
353 'output_dirname': 'binutils-x86',
354 'commands': GetGitSyncCmds('binutils-x86'),
359 def TestsuiteSources(GetGitSyncCmds):
361 'llvm_testsuite_src': {
363 'output_dirname': 'llvm-test-suite',
364 'commands': GetGitSyncCmds('llvm-test-suite'),
370 def CopyHostLibcxxForLLVMBuild(host, dest, options):
371 """Copy libc++ to the working directory for build tools."""
374 if TripleIsLinux(host):
375 libname = 'libc++.so.1'
376 elif TripleIsMac(host):
377 libname = 'libc++.1.dylib'
380 return [command.Mkdir(dest, parents=True),
381 command.Copy('%(' + GSDJoin('abs_libcxx', host) +')s/lib/' + libname,
382 os.path.join(dest, libname))]
384 def HostLibs(host, options):
385 def H(component_name):
386 # Return a package name for a component name with a host triple.
387 return GSDJoin(component_name, host)
389 if TripleIsWindows(host):
390 if pynacl.platform.IsWindows():
393 ar = 'i686-w64-mingw32-ar'
398 'inputs' : { 'src' : os.path.join(NACL_DIR, '..', 'third_party',
401 command.CopyTree('%(src)s', 'src'),
402 command.Command(['i686-w64-mingw32-gcc',
403 '-o', 'dlfcn.o', '-c',
404 os.path.join('src', 'dlfcn.c'),
405 '-Wall', '-O3', '-fomit-frame-pointer']),
406 command.Command([ar, 'cru',
407 'libdl.a', 'dlfcn.o']),
408 command.Copy('libdl.a',
409 os.path.join('%(output)s', 'libdl.a')),
410 command.Copy(os.path.join('src', 'dlfcn.h'),
411 os.path.join('%(output)s', 'dlfcn.h')),
415 elif not options.gcc:
416 # Libc++ is only tested with the clang build
419 'dependencies': ['libcxx_src', 'libcxxabi_src'],
422 command.SkipForIncrementalCommand([
423 'cmake', '-G', 'Unix Makefiles'] +
424 LibCxxHostArchFlags(host) +
425 ['-DLIBCXX_CXX_ABI=libcxxabi',
426 '-DLIBCXX_LIBCXXABI_INCLUDE_PATHS=' + command.path.join(
427 '%(abs_libcxxabi_src)s', 'include'),
428 '-DLIBCXX_ENABLE_SHARED=ON',
429 '-DCMAKE_INSTALL_PREFIX=',
430 '-DCMAKE_INSTALL_NAME_DIR=@executable_path/../lib',
432 command.Command(MakeCommand(host) + ['VERBOSE=1']),
433 command.Command(MAKE_DESTDIR_CMD + ['VERBOSE=1', 'install']),
440 def HostTools(host, options):
441 def H(component_name):
442 # Return a package name for a component name with a host triple.
443 return GSDJoin(component_name, host)
444 # Return the file name with the appropriate suffix for an executable file.
446 if TripleIsWindows(host):
450 # Binutils still has some warnings when building with clang
451 warning_flags = ['-Wno-extended-offsetof', '-Wno-absolute-value',
452 '-Wno-unused-function', '-Wno-unused-const-variable',
453 '-Wno-unneeded-internal-declaration',
454 '-Wno-unused-private-field', '-Wno-format-security']
456 H('binutils_pnacl'): {
457 'dependencies': ['binutils_pnacl_src'],
460 command.SkipForIncrementalCommand([
462 '%(binutils_pnacl_src)s/configure'] +
463 ConfigureBinutilsCommon() +
464 ConfigureHostArchFlags(host, warning_flags, options) +
465 ['--target=arm-pc-nacl',
466 '--program-prefix=le32-nacl-',
467 '--enable-targets=arm-pc-nacl,i686-pc-nacl,x86_64-pc-nacl,' +
469 '--enable-shared=no',
470 '--enable-gold=default',
474 '--with-sysroot=/le32-nacl']),
475 command.Command(MakeCommand(host)),
476 command.Command(MAKE_DESTDIR_CMD + ['install-strip'])] +
477 [command.RemoveDirectory(os.path.join('%(output)s', dir))
478 for dir in ('arm-pc-nacl', 'lib', 'lib32')]
482 'output_subdir': 'bin',
483 'inputs': { 'src': PNACL_DRIVER_DIR },
487 pnacl_commands.InstallDriverScripts,
488 '%(src)s', '%(output)s',
489 host_windows=TripleIsWindows(host) or TripleIsCygWin(host),
490 host_64bit=TripleIsX8664(host))
497 'dependencies': ['clang_src', 'llvm_src', 'binutils_pnacl_src'],
500 command.SkipForIncrementalCommand([
501 'cmake', '-G', 'Ninja'] +
502 CmakeHostArchFlags(host, options) +
503 ['-DCMAKE_BUILD_TYPE=RelWithDebInfo',
504 '-DCMAKE_INSTALL_PREFIX=%(output)s',
505 '-DCMAKE_INSTALL_RPATH=$ORIGIN/../lib',
506 '-DLLVM_ENABLE_LIBCXX=ON',
507 '-DBUILD_SHARED_LIBS=ON',
508 '-DLLVM_TARGETS_TO_BUILD=X86;ARM;Mips',
509 '-DLLVM_ENABLE_ASSERTIONS=ON',
510 '-DLLVM_ENABLE_ZLIB=OFF',
511 '-DLLVM_BUILD_TESTS=ON',
512 '-DLLVM_APPEND_VC_REV=ON',
513 '-DLLVM_BINUTILS_INCDIR=%(abs_binutils_pnacl_src)s/include',
514 '-DLLVM_EXTERNAL_CLANG_SOURCE_DIR=%(clang_src)s',
516 command.Command(['ninja', '-v']),
517 command.Command(['ninja', 'install']),
523 'dependencies': ['clang_src', 'llvm_src', 'binutils_pnacl_src',
527 command.SkipForIncrementalCommand([
529 '%(llvm_src)s/configure'] +
530 ConfigureHostArchFlags(host, [], options) +
531 LLVMConfigureAssertionsFlags(options) +
535 '--disable-terminfo',
537 '--disable-bindings', # ocaml is currently the only binding.
538 '--with-binutils-include=%(abs_binutils_pnacl_src)s/include',
539 '--enable-targets=x86,arm,mips',
541 '--enable-optimized',
542 '--with-clang-srcdir=%(abs_clang_src)s'])] +
543 CopyHostLibcxxForLLVMBuild(
545 os.path.join('Release+Asserts', 'lib'),
547 [command.Command(MakeCommand(host) + [
550 'SUBZERO_SRC_ROOT=%(abs_subzero_src)s',
552 command.Command(MAKE_DESTDIR_CMD + ['install']),
553 command.Remove(*[os.path.join('%(output)s', 'lib', f) for f in
554 '*.a', '*Hello.*', 'BugpointPasses.*']),
555 command.Remove(*[os.path.join('%(output)s', 'bin', f) for f in
556 Exe('clang-format'), Exe('clang-check'),
557 Exe('c-index-test'), Exe('clang-tblgen'),
558 Exe('llvm-tblgen')])] +
559 [command.Command(['ln', '-f',
560 command.path.join('%(output)s', 'bin','clang'),
561 command.path.join('%(output)s', 'bin',
562 arch + '-nacl-clang')])
563 for arch in DIRECT_TO_NACL_ARCHES] +
564 [command.Command(['ln', '-f',
565 command.path.join('%(output)s', 'bin','clang'),
566 command.path.join('%(output)s', 'bin',
567 arch + '-nacl-clang++')])
568 for arch in DIRECT_TO_NACL_ARCHES] +
569 CopyWindowsHostLibs(host),
573 tools.update(llvm_cmake)
575 tools.update(llvm_autoconf)
576 if TripleIsWindows(host):
577 tools[H('binutils_pnacl')]['dependencies'].append('libdl')
578 tools[H('llvm')]['dependencies'].append('libdl')
579 elif not options.gcc:
580 tools[H('binutils_pnacl')]['dependencies'].append(H('libcxx'))
581 tools[H('llvm')]['dependencies'].append(H('libcxx'))
585 def TargetLibCompiler(host, options):
586 def H(component_name):
587 return GSDJoin(component_name, host)
589 # Because target_lib_compiler is not a memoized target, its name doesn't
590 # need to have the host appended to it (it can be different on different
591 # hosts), which means that target library build rules don't have to care
592 # what host they run on; they can just depend on 'target_lib_compiler'
593 'target_lib_compiler': {
595 'output_subdir': 'target_lib_compiler',
596 'dependencies': [ H('binutils_pnacl'), H('llvm'), H('binutils_x86') ],
597 'inputs': { 'driver': PNACL_DRIVER_DIR },
599 command.CopyRecursive('%(' + t + ')s', '%(output)s')
600 for t in [H('llvm'), H('binutils_pnacl'), H('binutils_x86')]] + [
602 None, pnacl_commands.InstallDriverScripts,
603 '%(driver)s', os.path.join('%(output)s', 'bin'),
604 host_windows=TripleIsWindows(host) or TripleIsCygWin(host),
605 host_64bit=TripleIsX8664(host))
610 if TripleIsWindows(host) or not options.gcc:
611 host_lib = 'libdl' if TripleIsWindows(host) else H('libcxx')
612 compiler['target_lib_compiler']['dependencies'].append(host_lib)
613 compiler['target_lib_compiler']['commands'].append(
614 command.CopyRecursive('%(' + host_lib + ')s', '%(output)s'))
618 def Metadata(revisions):
622 'inputs': { 'readme': os.path.join(NACL_DIR, 'pnacl', 'README'),
623 'COMPONENT_REVISIONS': GIT_DEPS_FILE,
624 'driver': PNACL_DRIVER_DIR },
626 command.Copy('%(readme)s', os.path.join('%(output)s', 'README')),
627 command.WriteData(str(FEATURE_VERSION),
628 os.path.join('%(output)s', 'FEATURE_VERSION')),
629 command.Runnable(None, pnacl_commands.WriteREVFile,
630 os.path.join('%(output)s', 'REV'),
640 def HostToolsDirectToNacl(host):
641 def H(component_name):
642 return GSDJoin(component_name, host)
646 if TripleIsWindows(host):
647 redirector_table = ''
648 for tool, args in TOOL_X64_I686_REDIRECTS:
649 redirector_table += ' {L"/bin/i686-nacl-%s.exe",' % tool + \
650 ' L"/bin/x86_64-nacl-%s.exe",' % tool + \
653 cc, cxx = CompilersForHost(host)
657 'inputs': { 'source_directory': REDIRECTOR_WIN32_SRC },
659 command.CopyTree('%(source_directory)s', '%(output)s'),
660 command.WriteData(redirector_table,
661 os.path.join('%(output)s',
662 'redirector_table.txt')),
667 'dependencies': ['redirector_src'],
669 command.Mkdir('%(output)s', parents=True),
670 command.Command([cc, '-O3', '-std=c99',
672 os.path.join(NACL_DIR, '..'),
674 os.path.join('%(output)s', 'redirector.exe'),
675 os.path.join('%(redirector_src)s',
681 redirect_deps = ['redirector']
686 command.path.join('%(redirector)s', 'redirector.exe'),
687 command.path.join('%(output)s', 'bin', 'i686-nacl-%s.exe' % tool)])
688 for tool, args in TOOL_X64_I686_REDIRECTS]
691 redirect_inputs = { 'redirector_script': REDIRECTOR_SCRIPT }
694 '%(abs_redirector_script)s',
695 command.path.join('%(output)s', 'bin', 'i686-nacl-' + tool),
696 'x86_64-nacl-' + tool,
698 for tool, args in TOOL_X64_I686_REDIRECTS]
703 'dependencies': ['binutils_x86_src'] + redirect_deps,
704 'inputs': redirect_inputs,
706 command.SkipForIncrementalCommand(
707 ['sh', '%(binutils_x86_src)s/configure'] +
708 ConfigureBinutilsCommon() +
709 ['--target=x86_64-nacl',
710 '--enable-targets=x86_64-nacl,i686-nacl',
711 '--disable-werror']),
712 command.Command(MakeCommand(host)),
713 command.Command(MAKE_DESTDIR_CMD + ['install-strip'])] +
714 # Remove the share dir from this binutils build and leave the one
715 # from the newer version used for bitcode linking. Always remove
716 # the lib dirs, which have unneeded host libs.
717 [command.RemoveDirectory(os.path.join('%(output)s', dir))
718 for dir in ('lib', 'lib32', 'lib64', 'share')] +
719 # Create the set of directories for target libs and includes, for
720 # experimentation before we actually build them.
721 # Libc includes (libs dir is created by binutils)
722 # TODO(dschuff): remove these when they are populated by target
724 [command.Mkdir(command.path.join(
725 '%(output)s', 'x86_64-nacl', 'include'), parents=True),
726 command.Mkdir(command.path.join(
727 '%(output)s', 'x86_64-nacl', 'lib32')),
728 command.Command(['ln', '-s', command.path.join('..','lib32'),
730 '%(output)s', 'x86_64-nacl', 'lib', '32')]),
731 command.Command(['ln', '-s', 'lib',
733 '%(output)s', 'x86_64-nacl', 'lib64')])] +
734 # Compiler libs (includes are shared)
735 [command.Mkdir(command.path.join('%(output)s',
736 'lib', 'clang', '3.4', 'lib', target), parents=True)
737 for target in ['i686-nacl', 'x86_64-nacl']] +
738 # Create links for i686-flavored names of the tools. For now we
739 # don't use the redirector scripts that pass different arguments
740 # because the compiler driver doesn't need them.
743 command.path.join('%(output)s', 'bin', 'x86_64-nacl-' + tool),
744 command.path.join('%(output)s', 'bin', 'i686-nacl-' + tool)])
745 for tool in ['addr2line', 'ar', 'nm', 'objcopy', 'objdump',
746 'ranlib', 'readelf', 'size', 'strings', 'strip']] +
752 def ParseComponentRevisionsFile(filename):
753 ''' Parse a simple-format deps file, with fields of the form:
755 Keys should match the keys in GIT_REPOS above, which match the previous
756 directory names used by gclient (with the exception that '_' in the file is
757 replaced by '-' in the returned key name).
758 Values are the git hashes for each repo.
759 Empty lines or lines beginning with '#' are ignored.
760 This function returns a dictionary mapping the keys found in the file to their
763 with open(filename) as f:
766 stripped = line.strip()
767 if stripped.startswith('#') or len(stripped) == 0:
769 tokens = stripped.split('=')
771 raise Exception('Malformed component revisions file: ' + filename)
772 deps[tokens[0].replace('_', '-')] = tokens[1]
776 def GetSyncPNaClReposSource(revisions, GetGitSyncCmds):
778 for repo, revision in revisions.iteritems():
779 sources['legacy_pnacl_%s_src' % repo] = {
781 'output_dirname': os.path.join(NACL_DIR, 'pnacl', 'git', repo),
782 'commands': GetGitSyncCmds(repo),
787 def InstallMinGWHostCompiler():
788 """Install the MinGW host compiler used to build the host tools on Windows.
790 We could use an ordinary source rule for this, but that would require hashing
791 hundreds of MB of toolchain files on every build. Instead, check for the
792 presence of the specially-named file <version>.installed in the install
793 directory. If it is absent, check for the presence of the zip file
794 <version>.zip. If it is absent, attempt to download it from Google Storage.
795 Then extract the zip file and create the install file.
797 if not os.path.isfile(os.path.join(MINGW_PATH, MINGW_VERSION + '.installed')):
798 downloader = pynacl.gsd_storage.GSDStorage([], ['nativeclient-mingw'])
799 zipfilename = MINGW_VERSION + '.zip'
800 zipfilepath = os.path.join(NACL_DIR, zipfilename)
801 # If the zip file is not present, try to download it from Google Storage.
802 # If that fails, bail out.
803 if (not os.path.isfile(zipfilepath) and
804 not downloader.GetSecureFile(zipfilename, zipfilepath)):
805 print >>sys.stderr, 'Failed to install MinGW tools:'
806 print >>sys.stderr, 'could not find or download', zipfilename
808 logging.info('Extracting %s' % zipfilename)
809 zf = zipfile.ZipFile(zipfilepath)
810 if os.path.exists(MINGW_PATH):
811 shutil.rmtree(MINGW_PATH)
812 zf.extractall(NACL_DIR)
813 with open(os.path.join(MINGW_PATH, MINGW_VERSION + '.installed'), 'w') as _:
815 os.environ['MINGW'] = MINGW_PATH
818 def GetUploadPackageTargets():
819 """Package Targets describes all the archived package targets.
821 This build can be built among many build bots, but eventually all things
822 will be combined together. This package target dictionary describes the final
823 output of the entire build.
827 common_packages = ['metadata']
829 # Target translator libraries
830 for arch in TRANSLATOR_ARCHES:
831 legal_arch = pynacl.gsd_storage.LegalizeName(arch)
832 common_packages.append('libs_support_translator_%s' % legal_arch)
833 common_packages.append('compiler_rt_%s' % legal_arch)
834 if not 'nonsfi' in arch:
835 common_packages.append('libgcc_eh_%s' % legal_arch)
838 for bias in BITCODE_BIASES:
839 legal_bias = pynacl.gsd_storage.LegalizeName(bias)
840 common_packages.append('newlib_%s' % legal_bias)
841 common_packages.append('libcxx_%s' % legal_bias)
842 common_packages.append('libstdcxx_%s' % legal_bias)
843 common_packages.append('libs_support_%s' % legal_bias)
845 # Direct-to-nacl target libraries
846 for arch in DIRECT_TO_NACL_ARCHES:
847 common_packages.append('newlib_%s' % arch)
848 common_packages.append('libcxx_%s' % arch)
849 common_packages.append('libs_support_%s' % arch)
853 for os_name, arch in (('win', 'x86-32'),
855 ('linux', 'x86-64')):
856 triple = pynacl.platform.PlatformTriple(os_name, arch)
857 legal_triple = pynacl.gsd_storage.LegalizeName(triple)
858 host_packages.setdefault(os_name, []).extend(
859 ['binutils_pnacl_%s' % legal_triple,
860 'binutils_x86_%s' % legal_triple,
861 'llvm_%s' % legal_triple,
862 'driver_%s' % legal_triple])
864 host_packages[os_name].append('libcxx_%s' % legal_triple)
866 # Unsandboxed target IRT libraries
867 for os_name in ('linux', 'mac'):
868 legal_triple = pynacl.gsd_storage.LegalizeName('x86-32-' + os_name)
869 host_packages[os_name].append('unsandboxed_irt_%s' % legal_triple)
871 for os_name, os_packages in host_packages.iteritems():
872 package_target = '%s_x86' % pynacl.platform.GetOS(os_name)
873 package_targets[package_target] = {}
874 package_name = 'pnacl_newlib'
875 combined_packages = os_packages + common_packages
876 package_targets[package_target][package_name] = combined_packages
878 return package_targets
880 if __name__ == '__main__':
881 # This sets the logging for gclient-alike repo sync. It will be overridden
882 # by the package builder based on the command-line flags.
883 logging.getLogger().setLevel(logging.DEBUG)
884 parser = argparse.ArgumentParser(add_help=False)
885 parser.add_argument('--legacy-repo-sync', action='store_true',
886 dest='legacy_repo_sync', default=False,
887 help='Sync the git repo directories used by build.sh')
888 parser.add_argument('--disable-llvm-assertions', action='store_false',
889 dest='enable_llvm_assertions', default=True)
890 parser.add_argument('--cmake', action='store_true', default=False,
891 help="Use LLVM's cmake ninja build instead of autoconf")
892 parser.add_argument('--gcc', action='store_true', default=False,
893 help="Use the default compiler 'cc' instead of clang")
894 parser.add_argument('--sanitize', choices=['address', 'thread', 'memory',
896 help="Use a sanitizer with LLVM's clang cmake build")
897 parser.add_argument('--testsuite-sync', action='store_true', default=False,
898 help=('Sync the sources for the LLVM testsuite. '
899 'Only useful if --sync/ is also enabled'))
900 args, leftover_args = parser.parse_known_args()
901 if '-h' in leftover_args or '--help' in leftover_args:
902 print 'The following arguments are specific to toolchain_build_pnacl.py:'
904 print 'The rest of the arguments are generic, in toolchain_main.py'
906 if args.sanitize and not args.cmake:
907 print 'Use of sanitizers requires a cmake build'
910 if args.gcc and args.cmake:
911 print 'gcc build is not supported with cmake'
917 rev = ParseComponentRevisionsFile(GIT_DEPS_FILE)
918 if args.legacy_repo_sync:
919 packages = GetSyncPNaClReposSource(rev, GetGitSyncCmdsCallback(rev))
921 # Make sure sync is inside of the args to toolchain_main.
922 if not set(['-y', '--sync', '--sync-only']).intersection(leftover_args):
923 leftover_args.append('--sync-only')
925 upload_packages = GetUploadPackageTargets()
926 if pynacl.platform.IsWindows():
927 InstallMinGWHostCompiler()
929 packages.update(HostToolsSources(GetGitSyncCmdsCallback(rev)))
930 if args.testsuite_sync:
931 packages.update(TestsuiteSources(GetGitSyncCmdsCallback(rev)))
933 hosts = [pynacl.platform.PlatformTriple()]
934 if pynacl.platform.IsLinux() and BUILD_CROSS_MINGW:
935 hosts.append(pynacl.platform.PlatformTriple('win', 'x86-32'))
937 packages.update(HostLibs(host, args))
938 packages.update(HostTools(host, args))
939 packages.update(HostToolsDirectToNacl(host))
940 packages.update(TargetLibCompiler(pynacl.platform.PlatformTriple(), args))
941 # Don't build the target libs on Windows because of pathname issues.
942 # Only the linux64 bot is canonical (i.e. it will upload its packages).
943 # The other bots will use a 'work' target instead of a 'build' target for
944 # the target libs, so they will not be memoized, but can be used for tests.
945 # TODO(dschuff): Even better would be if we could memoize non-canonical
946 # build targets without doing things like mangling their names (and for e.g.
947 # scons tests, skip running them if their dependencies haven't changed, like
949 is_canonical = pynacl.platform.IsLinux64()
950 if pynacl.platform.IsLinux() or pynacl.platform.IsMac():
951 packages.update(pnacl_targetlibs.TargetLibsSrc(
952 GetGitSyncCmdsCallback(rev)))
953 for bias in BITCODE_BIASES:
954 packages.update(pnacl_targetlibs.TargetLibs(bias, is_canonical))
955 for arch in DIRECT_TO_NACL_ARCHES:
956 packages.update(pnacl_targetlibs.TargetLibs(arch, is_canonical))
957 for arch in TRANSLATOR_ARCHES:
958 packages.update(pnacl_targetlibs.TranslatorLibs(arch, is_canonical))
959 packages.update(Metadata(rev))
960 if pynacl.platform.IsLinux() or pynacl.platform.IsMac():
961 packages.update(pnacl_targetlibs.UnsandboxedIRT(
962 'x86-32-%s' % pynacl.platform.GetOS()))
965 tb = toolchain_main.PackageBuilder(packages,