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')
42 # Scons tests can check this version number to decide whether to enable tests
43 # for toolchain bug fixes or new features. This allows tests to be enabled on
44 # the toolchain buildbots/trybots before the new toolchain version is pinned
45 # (i.e. before the tests would pass on the main NaCl buildbots/trybots).
46 # If you are adding a test that depends on a toolchain change, you can
47 # increment this version number manually.
50 # For backward compatibility, these key names match the directory names
51 # previously used with gclient
53 'binutils': 'nacl-binutils.git',
54 'clang': 'pnacl-clang.git',
55 'llvm': 'pnacl-llvm.git',
56 'gcc': 'pnacl-gcc.git',
57 'libcxx': 'pnacl-libcxx.git',
58 'libcxxabi': 'pnacl-libcxxabi.git',
59 'nacl-newlib': 'nacl-newlib.git',
60 'llvm-test-suite': 'pnacl-llvm-testsuite.git',
61 'compiler-rt': 'pnacl-compiler-rt.git',
62 'subzero': 'pnacl-subzero.git',
63 'binutils-x86': 'nacl-binutils.git',
66 GIT_BASE_URL = 'https://chromium.googlesource.com/native_client/'
67 GIT_PUSH_URL = 'ssh://gerrit.chromium.org/native_client/'
68 GIT_DEPS_FILE = os.path.join(NACL_DIR, 'pnacl', 'COMPONENT_REVISIONS')
70 ALT_GIT_BASE_URL = 'https://chromium.googlesource.com/a/native_client/'
72 KNOWN_MIRRORS = [('http://git.chromium.org/native_client/', GIT_BASE_URL)]
73 PUSH_MIRRORS = [('http://git.chromium.org/native_client/', GIT_PUSH_URL),
74 (ALT_GIT_BASE_URL, GIT_PUSH_URL),
75 (GIT_BASE_URL, GIT_PUSH_URL)]
77 PACKAGE_NAME = 'Native Client SDK [%(build_signature)s]'
78 BUG_URL = 'http://gonacl.com/reportissue'
80 # TODO(dschuff): Some of this mingw logic duplicates stuff in command.py
81 BUILD_CROSS_MINGW = False
82 # Path to the mingw cross-compiler libs on Ubuntu
83 CROSS_MINGW_LIBPATH = '/usr/lib/gcc/i686-w64-mingw32/4.6'
84 # Path and version of the native mingw compiler to be installed on Windows hosts
85 MINGW_PATH = os.path.join(NACL_DIR, 'mingw32')
86 MINGW_VERSION = 'i686-w64-mingw32-4.8.1'
88 CHROME_CLANG = os.path.join(os.path.dirname(NACL_DIR), 'third_party',
89 'llvm-build', 'Release+Asserts', 'bin', 'clang')
90 CHROME_CLANGXX = CHROME_CLANG + '++'
92 ALL_ARCHES = ('x86-32', 'x86-64', 'arm', 'mips32',
93 'x86-32-nonsfi', 'arm-nonsfi')
94 # MIPS32 doesn't use biased bitcode, and nonsfi targets don't need it.
95 BITCODE_BIASES = tuple(bias for bias in ('le32', 'x86-32', 'x86-64', 'arm'))
97 MAKE_DESTDIR_CMD = ['make', 'DESTDIR=%(abs_output)s']
99 def TripleIsWindows(t):
100 return fnmatch.fnmatch(t, '*-mingw32*')
102 def TripleIsCygWin(t):
103 return fnmatch.fnmatch(t, '*-cygwin*')
105 def TripleIsLinux(t):
106 return fnmatch.fnmatch(t, '*-linux*')
109 return fnmatch.fnmatch(t, '*-darwin*')
111 def TripleIsX8664(t):
112 return fnmatch.fnmatch(t, 'x86_64*')
115 # Return a tuple (C compiler, C++ compiler) of the compilers to compile the host
117 def CompilersForHost(host):
119 # For now we only do native builds for linux and mac
120 # treat 32-bit linux like a native build
121 'i686-linux': (CHROME_CLANG, CHROME_CLANGXX),
122 'x86_64-linux': (CHROME_CLANG, CHROME_CLANGXX),
123 'x86_64-apple-darwin': (CHROME_CLANG, CHROME_CLANGXX),
124 # Windows build should work for native and cross
125 'i686-w64-mingw32': ('i686-w64-mingw32-gcc', 'i686-w64-mingw32-g++'),
126 # TODO: add arm-hosted support
127 'i686-pc-cygwin': ('gcc', 'g++'),
129 return compiler[host]
133 return '_'.join([pynacl.gsd_storage.LegalizeName(arg) for arg in args])
136 def ConfigureHostArchFlags(host, extra_cflags, options):
137 """ Return flags passed to LLVM and binutils configure for compilers and
142 native = pynacl.platform.PlatformTriple()
143 is_cross = host != native
145 if (pynacl.platform.IsLinux64() and
146 fnmatch.fnmatch(host, '*-linux*')):
147 # 64 bit linux can build 32 bit linux binaries while still being a native
148 # build for our purposes. But it's not what config.guess will yield, so
149 # use --build to force it and make sure things build correctly.
150 configure_args.append('--build=' + host)
152 configure_args.append('--host=' + host)
153 if TripleIsLinux(host) and not TripleIsX8664(host):
154 # Chrome clang defaults to 64-bit builds, even when run on 32-bit Linux.
155 extra_cc_args = ['-m32']
157 extra_cxx_args = list(extra_cc_args)
160 cc, cxx = CompilersForHost(host)
162 configure_args.append('CC=' + ' '.join([cc] + extra_cc_args))
163 configure_args.append('CXX=' + ' '.join([cxx] + extra_cxx_args))
165 if TripleIsWindows(host):
166 # The i18n support brings in runtime dependencies on MinGW DLLs
167 # that we don't want to have to distribute alongside our binaries.
168 # So just disable it, and compiler messages will always be in US English.
169 configure_args.append('--disable-nls')
170 configure_args.extend(['LDFLAGS=-L%(abs_libdl)s -ldl',
171 'CFLAGS=-isystem %(abs_libdl)s',
172 'CXXFLAGS=-isystem %(abs_libdl)s'])
174 # LLVM's linux->mingw cross build needs this
175 configure_args.append('CC_FOR_BUILD=gcc')
178 configure_args.extend(['CFLAGS=' + ' '.join(extra_cflags),
179 'CXXFLAGS=' + ' '.join(extra_cflags)])
181 configure_args.extend(
182 ['CFLAGS=' + ' '.join(extra_cflags),
183 'LDFLAGS=-L%(' + GSDJoin('abs_libcxx', host) + ')s/lib',
184 'CXXFLAGS=-stdlib=libc++ -I%(' + GSDJoin('abs_libcxx', host) +
185 ')s/include/c++/v1 ' + ' '.join(extra_cflags)])
187 return configure_args
190 def LibCxxHostArchFlags(host):
191 cc, cxx = CompilersForHost(host)
193 cmake_flags.extend(['-DCMAKE_C_COMPILER='+cc, '-DCMAKE_CXX_COMPILER='+cxx])
194 if TripleIsLinux(host) and not TripleIsX8664(host):
195 # Chrome clang defaults to 64-bit builds, even when run on 32-bit Linux
196 cmake_flags.extend(['-DCMAKE_C_FLAGS=-m32',
197 '-DCMAKE_CXX_FLAGS=-m32'])
200 def CmakeHostArchFlags(host, options):
201 """ Set flags passed to LLVM cmake for compilers and compile flags. """
203 cc, cxx = CompilersForHost(host)
205 cmake_flags.extend(['-DCMAKE_C_COMPILER='+cc, '-DCMAKE_CXX_COMPILER='+cxx])
207 # There seems to be a bug in chrome clang where it exposes the msan interface
208 # (even when compiling without msan) but then does not link with an
209 # msan-enabled compiler_rt, leaving references to __msan_allocated_memory
211 cmake_flags.append('-DHAVE_SANITIZER_MSAN_INTERFACE_H=FALSE')
213 if pynacl.platform.IsLinux64() and pynacl.platform.PlatformTriple() != host:
214 # Currently the only supported "cross" build is 64-bit Linux to 32-bit
215 # Linux. Enable it. Also disable libxml and libtinfo because our Ubuntu
216 # doesn't have 32-bit libxml or libtinfo build, and users may not have them
218 cmake_flags.extend(['-DLLVM_BUILD_32_BITS=ON',
219 '-DLLVM_ENABLE_LIBXML=OFF',
220 '-DLLVM_ENABLE_TERMINFO=OFF'])
223 cmake_flags.extend(['-DCMAKE_%s_FLAGS=-fsanitize=%s' % (c, options.sanitize)
224 for c in ('C', 'CXX')])
225 cmake_flags.append('-DCMAKE_EXE_LINKER_FLAGS=-fsanitize=%s' %
231 def ConfigureBinutilsCommon():
232 return ['--with-pkgversion=' + PACKAGE_NAME,
233 '--with-bugurl=' + BUG_URL,
236 '--disable-silent-rules',
237 '--enable-deterministic-archives',
240 def LLVMConfigureAssertionsFlags(options):
241 if options.enable_llvm_assertions:
244 return ['--disable-debug', '--disable-assertions']
247 def MakeCommand(host):
248 make_command = ['make']
249 if not pynacl.platform.IsWindows() or pynacl.platform.IsCygWin():
250 # The make that ships with msys sometimes hangs when run with -j.
251 # The ming32-make that comes with the compiler itself reportedly doesn't
252 # have this problem, but it has issues with pathnames with LLVM's build.
253 make_command.append('-j%(cores)s')
255 if TripleIsWindows(host):
256 # There appears to be nothing we can pass at top-level configure time
257 # that will prevent the configure scripts from finding MinGW's libiconv
258 # and using it. We have to force this variable into the environment
259 # of the sub-configure runs, which are run via make.
260 make_command.append('HAVE_LIBICONV=no')
264 def CopyWindowsHostLibs(host):
265 if not TripleIsWindows(host) and not TripleIsCygWin(host):
268 if TripleIsCygWin(host):
270 libs = ('cyggcc_s-1.dll', 'cygiconv-2.dll', 'cygwin1.dll',
271 'cygintl-8.dll', 'cygstdc++-6.dll', 'cygz.dll')
272 elif pynacl.platform.IsWindows():
273 lib_path = os.path.join(MINGW_PATH, 'bin')
274 # The native minGW compiler uses winpthread, but the Ubuntu cross compiler
276 libs = ('libgcc_s_sjlj-1.dll', 'libstdc++-6.dll', 'libwinpthread-1.dll')
278 lib_path = os.path.join(CROSS_MINGW_LIBPATH)
279 libs = ('libgcc_s_sjlj-1.dll', 'libstdc++-6.dll')
280 return [command.Copy(
281 os.path.join(lib_path, lib),
282 os.path.join('%(output)s', 'bin', lib))
285 def GetGitSyncCmdsCallback(revisions):
286 """Return a callback which returns the git sync commands for a component.
288 This allows all the revision information to be processed here while giving
289 other modules like pnacl_targetlibs.py the ability to define their own
290 source targets with minimal boilerplate.
292 def GetGitSyncCmds(component):
293 git_url = GIT_BASE_URL + GIT_REPOS[component]
294 git_push_url = GIT_PUSH_URL + GIT_REPOS[component]
296 # This replaces build.sh's newlib-nacl-headers-clean step by cleaning the
297 # the newlib repo on checkout (while silently blowing away any local
298 # changes). TODO(dschuff): find a better way to handle nacl newlib headers.
299 is_newlib = component == 'nacl-newlib'
300 return (command.SyncGitRepoCmds(git_url, '%(output)s', revisions[component],
302 git_cache='%(git_cache_dir)s',
303 push_url=git_push_url,
304 known_mirrors=KNOWN_MIRRORS,
305 push_mirrors=PUSH_MIRRORS) +
306 [command.Runnable(None,
307 pnacl_commands.CmdCheckoutGitBundleForTrybot,
308 component, '%(output)s')])
310 return GetGitSyncCmds
313 def HostToolsSources(GetGitSyncCmds):
317 'output_dirname': 'libcxx',
318 'commands': GetGitSyncCmds('libcxx'),
322 'output_dirname': 'libcxxabi',
323 'commands': GetGitSyncCmds('libcxxabi'),
325 'binutils_pnacl_src': {
327 'output_dirname': 'binutils',
328 'commands': GetGitSyncCmds('binutils'),
330 # For some reason, the llvm build using --with-clang-srcdir chokes if the
331 # clang source directory is named something other than 'clang', so don't
332 # change output_dirname for clang.
335 'output_dirname': 'clang',
336 'commands': GetGitSyncCmds('clang'),
340 'output_dirname': 'llvm',
341 'commands': GetGitSyncCmds('llvm'),
345 'output_dirname': 'subzero',
346 'commands': GetGitSyncCmds('subzero'),
348 'binutils_x86_src': {
350 'output_dirname': 'binutils-x86',
351 'commands': GetGitSyncCmds('binutils-x86'),
356 def TestsuiteSources(GetGitSyncCmds):
358 'llvm_testsuite_src': {
360 'output_dirname': 'llvm-test-suite',
361 'commands': GetGitSyncCmds('llvm-test-suite'),
367 def CopyHostLibcxxForLLVMBuild(host, dest, options):
368 """Copy libc++ to the working directory for build tools."""
371 if TripleIsLinux(host):
372 libname = 'libc++.so.1'
373 elif TripleIsMac(host):
374 libname = 'libc++.1.dylib'
377 return [command.Mkdir(dest, parents=True),
378 command.Copy('%(' + GSDJoin('abs_libcxx', host) +')s/lib/' + libname,
379 os.path.join(dest, libname))]
381 def HostLibs(host, options):
382 def H(component_name):
383 # Return a package name for a component name with a host triple.
384 return GSDJoin(component_name, host)
386 if TripleIsWindows(host):
387 if pynacl.platform.IsWindows():
390 ar = 'i686-w64-mingw32-ar'
395 'inputs' : { 'src' : os.path.join(NACL_DIR, '..', 'third_party',
398 command.CopyTree('%(src)s', 'src'),
399 command.Command(['i686-w64-mingw32-gcc',
400 '-o', 'dlfcn.o', '-c',
401 os.path.join('src', 'dlfcn.c'),
402 '-Wall', '-O3', '-fomit-frame-pointer']),
403 command.Command([ar, 'cru',
404 'libdl.a', 'dlfcn.o']),
405 command.Copy('libdl.a',
406 os.path.join('%(output)s', 'libdl.a')),
407 command.Copy(os.path.join('src', 'dlfcn.h'),
408 os.path.join('%(output)s', 'dlfcn.h')),
412 elif not options.gcc:
413 # Libc++ is only tested with the clang build
416 'dependencies': ['libcxx_src', 'libcxxabi_src'],
419 command.SkipForIncrementalCommand([
420 'cmake', '-G', 'Unix Makefiles'] +
421 LibCxxHostArchFlags(host) +
422 ['-DLIBCXX_CXX_ABI=libcxxabi',
423 '-DLIBCXX_LIBCXXABI_INCLUDE_PATHS=' + command.path.join(
424 '%(abs_libcxxabi_src)s', 'include'),
425 '-DLIBCXX_ENABLE_SHARED=ON',
426 '-DCMAKE_INSTALL_PREFIX=',
427 '-DCMAKE_INSTALL_NAME_DIR=@executable_path/../lib',
429 command.Command(MakeCommand(host) + ['VERBOSE=1']),
430 command.Command(MAKE_DESTDIR_CMD + ['VERBOSE=1', 'install']),
437 def HostTools(host, options):
438 def H(component_name):
439 # Return a package name for a component name with a host triple.
440 return GSDJoin(component_name, host)
441 # Return the file name with the appropriate suffix for an executable file.
443 if TripleIsWindows(host):
447 # Binutils still has some warnings when building with clang
448 warning_flags = ['-Wno-extended-offsetof', '-Wno-absolute-value',
449 '-Wno-unused-function', '-Wno-unused-const-variable',
450 '-Wno-unneeded-internal-declaration',
451 '-Wno-unused-private-field', '-Wno-format-security']
453 H('binutils_pnacl'): {
454 'dependencies': ['binutils_pnacl_src'],
457 command.SkipForIncrementalCommand([
459 '%(binutils_pnacl_src)s/configure'] +
460 ConfigureBinutilsCommon() +
461 ConfigureHostArchFlags(host, warning_flags, options) +
462 ['--target=arm-pc-nacl',
463 '--program-prefix=le32-nacl-',
464 '--enable-targets=arm-pc-nacl,i686-pc-nacl,x86_64-pc-nacl,' +
466 '--enable-shared=no',
467 '--enable-gold=default',
471 '--with-sysroot=/le32-nacl']),
472 command.Command(MakeCommand(host)),
473 command.Command(MAKE_DESTDIR_CMD + ['install-strip'])] +
474 [command.RemoveDirectory(os.path.join('%(output)s', dir))
475 for dir in ('arm-pc-nacl', 'lib', 'lib32')]
479 'output_subdir': 'bin',
480 'inputs': { 'src': PNACL_DRIVER_DIR },
484 pnacl_commands.InstallDriverScripts,
485 '%(src)s', '%(output)s',
486 host_windows=TripleIsWindows(host) or TripleIsCygWin(host),
487 host_64bit=TripleIsX8664(host))
494 'dependencies': ['clang_src', 'llvm_src', 'binutils_pnacl_src'],
497 command.SkipForIncrementalCommand([
498 'cmake', '-G', 'Ninja'] +
499 CmakeHostArchFlags(host, options) +
500 ['-DCMAKE_BUILD_TYPE=RelWithDebInfo',
501 '-DCMAKE_INSTALL_PREFIX=%(output)s',
502 '-DCMAKE_INSTALL_RPATH=$ORIGIN/../lib',
503 '-DLLVM_ENABLE_LIBCXX=ON',
504 '-DBUILD_SHARED_LIBS=ON',
505 '-DLLVM_TARGETS_TO_BUILD=X86;ARM;Mips',
506 '-DLLVM_ENABLE_ASSERTIONS=ON',
507 '-DLLVM_ENABLE_ZLIB=OFF',
508 '-DLLVM_BUILD_TESTS=ON',
509 '-DLLVM_APPEND_VC_REV=ON',
510 '-DLLVM_BINUTILS_INCDIR=%(abs_binutils_pnacl_src)s/include',
511 '-DLLVM_EXTERNAL_CLANG_SOURCE_DIR=%(clang_src)s',
513 command.Command(['ninja', '-v']),
514 command.Command(['ninja', 'install']),
520 'dependencies': ['clang_src', 'llvm_src', 'binutils_pnacl_src',
524 command.SkipForIncrementalCommand([
526 '%(llvm_src)s/configure'] +
527 ConfigureHostArchFlags(host, [], options) +
528 LLVMConfigureAssertionsFlags(options) +
532 '--disable-terminfo',
534 '--disable-bindings', # ocaml is currently the only binding.
535 '--with-binutils-include=%(abs_binutils_pnacl_src)s/include',
536 '--enable-targets=x86,arm,mips',
538 '--enable-optimized',
539 '--with-clang-srcdir=%(abs_clang_src)s'])] +
540 CopyHostLibcxxForLLVMBuild(
542 os.path.join('Release+Asserts', 'lib'),
544 [command.Command(MakeCommand(host) + [
547 'SUBZERO_SRC_ROOT=%(abs_subzero_src)s',
549 command.Command(MAKE_DESTDIR_CMD + ['install']),
550 command.Remove(*[os.path.join('%(output)s', 'lib', f) for f in
551 '*.a', '*Hello.*', 'BugpointPasses.*']),
552 command.Remove(*[os.path.join('%(output)s', 'bin', f) for f in
553 Exe('clang-format'), Exe('clang-check'),
554 Exe('c-index-test'), Exe('clang-tblgen'),
555 Exe('llvm-tblgen')])] +
556 [command.Command(['ln', '-f',
557 command.path.join('%(output)s', 'bin','clang'),
558 command.path.join('%(output)s', 'bin',
559 arch + '-nacl-clang')])
560 for arch in ['i686', 'x86_64']] +
561 [command.Command(['ln', '-f',
562 command.path.join('%(output)s', 'bin','clang'),
563 command.path.join('%(output)s', 'bin',
564 arch + '-nacl-clang++')])
565 for arch in ['i686', 'x86_64']] +
566 CopyWindowsHostLibs(host),
570 tools.update(llvm_cmake)
572 tools.update(llvm_autoconf)
573 if TripleIsWindows(host):
574 tools[H('binutils_pnacl')]['dependencies'].append('libdl')
575 tools[H('llvm')]['dependencies'].append('libdl')
576 elif not options.gcc:
577 tools[H('binutils_pnacl')]['dependencies'].append(H('libcxx'))
578 tools[H('llvm')]['dependencies'].append(H('libcxx'))
582 def TargetLibCompiler(host, options):
583 def H(component_name):
584 return GSDJoin(component_name, host)
586 # Because target_lib_compiler is not a memoized target, its name doesn't
587 # need to have the host appended to it (it can be different on different
588 # hosts), which means that target library build rules don't have to care
589 # what host they run on; they can just depend on 'target_lib_compiler'
590 'target_lib_compiler': {
592 'output_subdir': 'target_lib_compiler',
593 'dependencies': [ H('binutils_pnacl'), H('llvm') ],
594 'inputs': { 'driver': PNACL_DRIVER_DIR },
596 command.CopyRecursive('%(' + t + ')s', '%(output)s')
597 for t in [H('llvm'), H('binutils_pnacl')]] + [
599 None, pnacl_commands.InstallDriverScripts,
600 '%(driver)s', os.path.join('%(output)s', 'bin'),
601 host_windows=TripleIsWindows(host) or TripleIsCygWin(host),
602 host_64bit=TripleIsX8664(host))
607 if TripleIsWindows(host) or not options.gcc:
608 host_lib = 'libdl' if TripleIsWindows(host) else H('libcxx')
609 compiler['target_lib_compiler']['dependencies'].append(host_lib)
610 compiler['target_lib_compiler']['commands'].append(
611 command.CopyRecursive('%(' + host_lib + ')s', '%(output)s'))
615 def Metadata(revisions):
619 'inputs': { 'readme': os.path.join(NACL_DIR, 'pnacl', 'README'),
620 'COMPONENT_REVISIONS': GIT_DEPS_FILE,
621 'driver': PNACL_DRIVER_DIR },
623 command.Copy('%(readme)s', os.path.join('%(output)s', 'README')),
624 command.WriteData(str(FEATURE_VERSION),
625 os.path.join('%(output)s', 'FEATURE_VERSION')),
626 command.Runnable(None, pnacl_commands.WriteREVFile,
627 os.path.join('%(output)s', 'REV'),
637 def HostToolsDirectToNacl(host):
638 def H(component_name):
639 return GSDJoin(component_name, host)
643 'dependencies': [H('llvm'), 'binutils_x86_src'],
645 command.SkipForIncrementalCommand(
646 ['sh', '%(binutils_x86_src)s/configure'] +
647 ConfigureBinutilsCommon() +
648 ['--target=x86_64-nacl',
649 '--enable-targets=x86_64-nacl,i686-nacl',
650 '--disable-werror']),
651 command.Command(MakeCommand(host)),
652 command.Command(MAKE_DESTDIR_CMD + ['install-strip'])] +
653 # Remove the share dir from this binutils build and leave the one
654 # from the newer version used for bitcode linking. Always remove
655 # the lib dirs, which have unneeded host libs.
656 [command.RemoveDirectory(os.path.join('%(output)s', dir))
657 for dir in ('lib', 'lib32', 'lib64', 'share')] +
658 # Create the set of directories for host libs and includes, for
659 # experimentation before we actually build them.
660 # Libc includes (libs dir is created by binutils)
661 [command.Mkdir(command.path.join(
662 '%(output)s', target, 'include'), parents=True)
663 for target in ['i686-nacl', 'x86_64-nacl']] +
664 # Compiler libs (includes are shared)
665 [command.Mkdir(command.path.join('%(output)s',
666 'lib', 'clang', '3.4', 'lib', target), parents=True)
667 for target in ['i686-nacl', 'x86_64-nacl']]
672 def ParseComponentRevisionsFile(filename):
673 ''' Parse a simple-format deps file, with fields of the form:
675 Keys should match the keys in GIT_REPOS above, which match the previous
676 directory names used by gclient (with the exception that '_' in the file is
677 replaced by '-' in the returned key name).
678 Values are the git hashes for each repo.
679 Empty lines or lines beginning with '#' are ignored.
680 This function returns a dictionary mapping the keys found in the file to their
683 with open(filename) as f:
686 stripped = line.strip()
687 if stripped.startswith('#') or len(stripped) == 0:
689 tokens = stripped.split('=')
691 raise Exception('Malformed component revisions file: ' + filename)
692 deps[tokens[0].replace('_', '-')] = tokens[1]
696 def GetSyncPNaClReposSource(revisions, GetGitSyncCmds):
698 for repo, revision in revisions.iteritems():
699 sources['legacy_pnacl_%s_src' % repo] = {
701 'output_dirname': os.path.join(NACL_DIR, 'pnacl', 'git', repo),
702 'commands': GetGitSyncCmds(repo),
707 def InstallMinGWHostCompiler():
708 """Install the MinGW host compiler used to build the host tools on Windows.
710 We could use an ordinary source rule for this, but that would require hashing
711 hundreds of MB of toolchain files on every build. Instead, check for the
712 presence of the specially-named file <version>.installed in the install
713 directory. If it is absent, check for the presence of the zip file
714 <version>.zip. If it is absent, attempt to download it from Google Storage.
715 Then extract the zip file and create the install file.
717 if not os.path.isfile(os.path.join(MINGW_PATH, MINGW_VERSION + '.installed')):
718 downloader = pynacl.gsd_storage.GSDStorage([], ['nativeclient-mingw'])
719 zipfilename = MINGW_VERSION + '.zip'
720 zipfilepath = os.path.join(NACL_DIR, zipfilename)
721 # If the zip file is not present, try to download it from Google Storage.
722 # If that fails, bail out.
723 if (not os.path.isfile(zipfilepath) and
724 not downloader.GetSecureFile(zipfilename, zipfilepath)):
725 print >>sys.stderr, 'Failed to install MinGW tools:'
726 print >>sys.stderr, 'could not find or download', zipfilename
728 logging.info('Extracting %s' % zipfilename)
729 zf = zipfile.ZipFile(zipfilepath)
730 if os.path.exists(MINGW_PATH):
731 shutil.rmtree(MINGW_PATH)
732 zf.extractall(NACL_DIR)
733 with open(os.path.join(MINGW_PATH, MINGW_VERSION + '.installed'), 'w') as _:
735 os.environ['MINGW'] = MINGW_PATH
738 def GetUploadPackageTargets():
739 """Package Targets describes all the archived package targets.
741 This build can be built among many build bots, but eventually all things
742 will be combined together. This package target dictionary describes the final
743 output of the entire build.
747 common_packages = ['metadata']
749 # Target native libraries
750 for arch in ALL_ARCHES:
751 legal_arch = pynacl.gsd_storage.LegalizeName(arch)
752 common_packages.append('libs_support_native_%s' % legal_arch)
753 common_packages.append('compiler_rt_%s' % legal_arch)
754 if not 'nonsfi' in arch:
755 common_packages.append('libgcc_eh_%s' % legal_arch)
757 # Target bitcode libraries
758 for bias in BITCODE_BIASES:
759 legal_bias = pynacl.gsd_storage.LegalizeName(bias)
760 common_packages.append('newlib_%s' % legal_bias)
761 common_packages.append('libcxx_%s' % legal_bias)
762 common_packages.append('libstdcxx_%s' % legal_bias)
763 common_packages.append('libs_support_bitcode_%s' % legal_bias)
767 for os_name, arch in (('win', 'x86-32'),
769 ('linux', 'x86-64')):
770 triple = pynacl.platform.PlatformTriple(os_name, arch)
771 legal_triple = pynacl.gsd_storage.LegalizeName(triple)
772 host_packages.setdefault(os_name, []).extend(
773 ['binutils_pnacl_%s' % legal_triple,
774 'llvm_%s' % legal_triple,
775 'driver_%s' % legal_triple])
777 host_packages[os_name].append('libcxx_%s' % legal_triple)
779 # Unsandboxed target IRT libraries
780 for os_name in ('linux', 'mac'):
781 legal_triple = pynacl.gsd_storage.LegalizeName('x86-32-' + os_name)
782 host_packages[os_name].append('unsandboxed_irt_%s' % legal_triple)
784 for os_name, os_packages in host_packages.iteritems():
785 package_target = '%s_x86' % pynacl.platform.GetOS(os_name)
786 package_targets[package_target] = {}
787 package_name = 'pnacl_newlib'
788 combined_packages = os_packages + common_packages
789 package_targets[package_target][package_name] = combined_packages
791 return package_targets
793 if __name__ == '__main__':
794 # This sets the logging for gclient-alike repo sync. It will be overridden
795 # by the package builder based on the command-line flags.
796 logging.getLogger().setLevel(logging.DEBUG)
797 parser = argparse.ArgumentParser(add_help=False)
798 parser.add_argument('--legacy-repo-sync', action='store_true',
799 dest='legacy_repo_sync', default=False,
800 help='Sync the git repo directories used by build.sh')
801 parser.add_argument('--disable-llvm-assertions', action='store_false',
802 dest='enable_llvm_assertions', default=True)
803 parser.add_argument('--cmake', action='store_true', default=False,
804 help="Use LLVM's cmake ninja build instead of autoconf")
805 parser.add_argument('--gcc', action='store_true', default=False,
806 help="Use the default compiler 'cc' instead of clang")
807 parser.add_argument('--sanitize', choices=['address', 'thread', 'memory',
809 help="Use a sanitizer with LLVM's clang cmake build")
810 parser.add_argument('--testsuite-sync', action='store_true', default=False,
811 help=('Sync the sources for the LLVM testsuite. '
812 'Only useful if --sync/ is also enabled'))
813 args, leftover_args = parser.parse_known_args()
814 if '-h' in leftover_args or '--help' in leftover_args:
815 print 'The following arguments are specific to toolchain_build_pnacl.py:'
817 print 'The rest of the arguments are generic, in toolchain_main.py'
819 if args.sanitize and not args.cmake:
820 print 'Use of sanitizers requires a cmake build'
823 if args.gcc and args.cmake:
824 print 'gcc build is not supported with cmake'
830 rev = ParseComponentRevisionsFile(GIT_DEPS_FILE)
831 if args.legacy_repo_sync:
832 packages = GetSyncPNaClReposSource(rev, GetGitSyncCmdsCallback(rev))
834 # Make sure sync is inside of the args to toolchain_main.
835 if not set(['-y', '--sync', '--sync-only']).intersection(leftover_args):
836 leftover_args.append('--sync-only')
838 upload_packages = GetUploadPackageTargets()
839 if pynacl.platform.IsWindows():
840 InstallMinGWHostCompiler()
842 packages.update(HostToolsSources(GetGitSyncCmdsCallback(rev)))
843 if args.testsuite_sync:
844 packages.update(TestsuiteSources(GetGitSyncCmdsCallback(rev)))
846 hosts = [pynacl.platform.PlatformTriple()]
847 if pynacl.platform.IsLinux() and BUILD_CROSS_MINGW:
848 hosts.append(pynacl.platform.PlatformTriple('win', 'x86-32'))
850 packages.update(HostLibs(host, args))
851 packages.update(HostTools(host, args))
852 packages.update(HostToolsDirectToNacl(host))
853 packages.update(TargetLibCompiler(pynacl.platform.PlatformTriple(), args))
854 # Don't build the target libs on Windows because of pathname issues.
855 # Only the linux64 bot is canonical (i.e. it will upload its packages).
856 # The other bots will use a 'work' target instead of a 'build' target for
857 # the target libs, so they will not be memoized, but can be used for tests.
858 # TODO(dschuff): Even better would be if we could memoize non-canonical
859 # build targets without doing things like mangling their names (and for e.g.
860 # scons tests, skip running them if their dependencies haven't changed, like
862 is_canonical = pynacl.platform.IsLinux64()
863 if pynacl.platform.IsLinux() or pynacl.platform.IsMac():
864 packages.update(pnacl_targetlibs.TargetLibsSrc(
865 GetGitSyncCmdsCallback(rev)))
866 for bias in BITCODE_BIASES:
867 packages.update(pnacl_targetlibs.BitcodeLibs(bias, is_canonical))
868 for arch in ALL_ARCHES:
869 packages.update(pnacl_targetlibs.NativeLibs(arch, is_canonical))
870 packages.update(Metadata(rev))
871 if pynacl.platform.IsLinux() or pynacl.platform.IsMac():
872 packages.update(pnacl_targetlibs.UnsandboxedIRT(
873 'x86-32-%s' % pynacl.platform.GetOS()))
876 tb = toolchain_main.PackageBuilder(packages,