2 # Copyright (c) 2012 The Chromium 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 """Entry point for both build and try bots.
8 This script is invoked from XXX, usually without arguments
9 to package an SDK. It automatically determines whether
10 this SDK is for mac, win, linux.
12 The script inspects the following environment variables:
14 BUILDBOT_BUILDERNAME to determine whether the script is run locally
15 and whether it should upload an SDK to file storage (GSTORE)
18 # pylint: disable=W0621
28 if sys.version_info < (2, 6, 0):
29 sys.stderr.write("python 2.6 or later is required run this script\n")
33 import buildbot_common
38 import generate_notice
41 import verify_filelist
43 from build_paths import SCRIPT_DIR, SDK_SRC_DIR, SRC_DIR, NACL_DIR, OUT_DIR
44 from build_paths import NACLPORTS_DIR, GSTORE, GONACL_APPENGINE_SRC_DIR
46 # Add SDK make tools scripts to the python path.
47 sys.path.append(os.path.join(SDK_SRC_DIR, 'tools'))
48 sys.path.append(os.path.join(NACL_DIR, 'build'))
53 CYGTAR = os.path.join(NACL_DIR, 'build', 'cygtar.py')
55 NACLPORTS_URL = 'https://naclports.googlecode.com/svn/trunk/src'
58 GYPBUILD_DIR = 'gypbuild'
63 def GetGlibcToolchain():
64 tcdir = os.path.join(NACL_DIR, 'toolchain', '.tars')
65 tcname = 'toolchain_%s_x86.tar.bz2' % getos.GetPlatform()
66 return os.path.join(tcdir, tcname)
69 def GetNewlibToolchain():
70 tcdir = os.path.join(NACL_DIR, 'toolchain', '.tars')
71 tcname = 'naclsdk_%s_x86.tgz' % getos.GetPlatform()
72 return os.path.join(tcdir, tcname)
75 def GetBionicToolchain():
76 tcdir = os.path.join(NACL_DIR, 'toolchain', '.tars')
77 tcname = 'naclsdk_%s_arm_bionic.tgz' % getos.GetPlatform()
78 return os.path.join(tcdir, tcname)
81 def GetPNaClToolchain():
82 tcdir = os.path.join(NACL_DIR, 'toolchain', '.tars')
83 tcname = 'naclsdk_pnacl_%s_x86.tgz' % getos.GetPlatform()
84 return os.path.join(tcdir, tcname)
87 def GetToolchainNaClInclude(tcname, tcpath, arch):
90 return os.path.join(tcpath, 'sdk', 'include')
91 return os.path.join(tcpath, 'x86_64-nacl', 'include')
93 return os.path.join(tcpath, 'arm-nacl', 'include')
95 buildbot_common.ErrorExit('Unknown architecture: %s' % arch)
98 def GetGypGenDir(xarch):
100 build_dir = GYPBUILD_DIR + '-arm'
102 build_dir = GYPBUILD_DIR
103 return os.path.join(OUT_DIR, build_dir, 'Release', 'gen')
106 def GetGypBuiltLib(tcname, xarch=None):
107 if tcname == 'pnacl':
108 tcname = 'pnacl_newlib'
111 return os.path.join(GetGypGenDir(xarch), 'tc_' + tcname, 'lib' + xarch)
114 def GetToolchainNaClLib(tcname, tcpath, xarch):
115 if tcname == 'pnacl':
116 return os.path.join(tcpath, 'sdk', 'lib')
118 return os.path.join(tcpath, 'x86_64-nacl', 'lib32')
120 return os.path.join(tcpath, 'x86_64-nacl', 'lib')
122 return os.path.join(tcpath, 'arm-nacl', 'lib')
125 def GetToolchainDirName(tcname, xarch):
126 if tcname == 'pnacl':
127 return '%s_%s' % (getos.GetPlatform(), tcname)
129 return '%s_arm_%s' % (getos.GetPlatform(), tcname)
131 return '%s_x86_%s' % (getos.GetPlatform(), tcname)
134 def GetGypToolchainLib(tcname, xarch):
135 tcpath = os.path.join(GetGypGenDir(xarch), 'sdk', 'toolchain',
136 GetToolchainDirName(tcname, xarch))
137 return GetToolchainNaClLib(tcname, tcpath, xarch)
140 def GetOutputToolchainLib(pepperdir, tcname, xarch):
141 tcpath = os.path.join(pepperdir, 'toolchain',
142 GetToolchainDirName(tcname, xarch))
143 return GetToolchainNaClLib(tcname, tcpath, xarch)
146 def GetPNaClNativeLib(tcpath, arch):
147 if arch not in ['arm', 'x86-32', 'x86-64']:
148 buildbot_common.ErrorExit('Unknown architecture %s.' % arch)
149 return os.path.join(tcpath, 'lib-' + arch)
152 def BuildStepDownloadToolchains(toolchains):
153 buildbot_common.BuildStep('Running download_toolchains.py')
154 download_script = os.path.join('build', 'download_toolchains.py')
155 args = [sys.executable, download_script, '--no-arm-trusted',
156 '--arm-untrusted', '--keep']
157 if 'bionic' in toolchains:
158 args.append('--allow-bionic')
159 buildbot_common.Run(args, cwd=NACL_DIR)
162 def BuildStepCleanPepperDirs(pepperdir, pepperdir_old):
163 buildbot_common.BuildStep('Clean Pepper Dirs')
164 buildbot_common.RemoveDir(pepperdir_old)
165 buildbot_common.RemoveDir(pepperdir)
166 buildbot_common.MakeDir(pepperdir)
169 def BuildStepMakePepperDirs(pepperdir, subdirs):
170 for subdir in subdirs:
171 buildbot_common.MakeDir(os.path.join(pepperdir, subdir))
178 'getting_started/README',
181 def BuildStepCopyTextFiles(pepperdir, pepper_ver, chrome_revision,
183 buildbot_common.BuildStep('Add Text Files')
184 InstallFiles(SDK_SRC_DIR, pepperdir, TEXT_FILES)
186 # Replace a few placeholders in README
187 readme_text = open(os.path.join(SDK_SRC_DIR, 'README')).read()
188 readme_text = readme_text.replace('${VERSION}', pepper_ver)
189 readme_text = readme_text.replace('${CHROME_REVISION}', chrome_revision)
190 readme_text = readme_text.replace('${NACL_REVISION}', nacl_revision)
192 # Year/Month/Day Hour:Minute:Second
193 time_format = '%Y/%m/%d %H:%M:%S'
194 readme_text = readme_text.replace('${DATE}',
195 datetime.datetime.now().strftime(time_format))
197 open(os.path.join(pepperdir, 'README'), 'w').write(readme_text)
200 def PrunePNaClToolchain(root):
204 # TODO(sbc): remove this once its really not needed.
205 # Currently we seem to rely on it at least for <bits/stat.h>
208 for dirname in dirs_to_prune:
209 buildbot_common.RemoveDir(os.path.join(root, dirname))
212 def BuildStepUntarToolchains(pepperdir, toolchains):
213 buildbot_common.BuildStep('Untar Toolchains')
214 platform = getos.GetPlatform()
215 tmpdir = os.path.join(OUT_DIR, 'tc_temp')
216 buildbot_common.RemoveDir(tmpdir)
217 buildbot_common.MakeDir(tmpdir)
219 if 'newlib' in toolchains:
220 # Untar the newlib toolchains
221 tarfile = GetNewlibToolchain()
222 buildbot_common.Run([sys.executable, CYGTAR, '-C', tmpdir, '-xf', tarfile],
225 # Then rename/move it to the pepper toolchain directory
226 srcdir = os.path.join(tmpdir, 'sdk', 'nacl-sdk')
227 tcname = platform + '_x86_newlib'
228 newlibdir = os.path.join(pepperdir, 'toolchain', tcname)
229 buildbot_common.Move(srcdir, newlibdir)
231 if 'bionic' in toolchains:
232 # Untar the bionic toolchains
233 tarfile = GetBionicToolchain()
234 tcname = platform + '_arm_bionic'
235 buildbot_common.Run([sys.executable, CYGTAR, '-C', tmpdir, '-xf', tarfile],
237 srcdir = os.path.join(tmpdir, tcname)
238 bionicdir = os.path.join(pepperdir, 'toolchain', tcname)
239 buildbot_common.Move(srcdir, bionicdir)
241 if 'arm' in toolchains:
242 # Copy the existing arm toolchain from native_client tree
243 tcname = platform + '_arm_newlib'
244 arm_toolchain = os.path.join(NACL_DIR, 'toolchain', tcname)
245 arm_toolchain_sdk = os.path.join(pepperdir, 'toolchain',
246 os.path.basename(arm_toolchain))
247 buildbot_common.CopyDir(arm_toolchain, arm_toolchain_sdk)
249 if 'glibc' in toolchains:
250 # Untar the glibc toolchains
251 tarfile = GetGlibcToolchain()
252 tcname = platform + '_x86_glibc'
253 buildbot_common.Run([sys.executable, CYGTAR, '-C', tmpdir, '-xf', tarfile],
256 # Then rename/move it to the pepper toolchain directory
257 srcdir = os.path.join(tmpdir, 'toolchain', platform + '_x86')
258 glibcdir = os.path.join(pepperdir, 'toolchain', tcname)
259 buildbot_common.Move(srcdir, glibcdir)
261 # Untar the pnacl toolchains
262 if 'pnacl' in toolchains:
263 tmpdir = os.path.join(tmpdir, 'pnacl')
264 buildbot_common.RemoveDir(tmpdir)
265 buildbot_common.MakeDir(tmpdir)
266 tarfile = GetPNaClToolchain()
267 tcname = platform + '_pnacl'
268 buildbot_common.Run([sys.executable, CYGTAR, '-C', tmpdir, '-xf', tarfile],
271 # Then rename/move it to the pepper toolchain directory
272 pnacldir = os.path.join(pepperdir, 'toolchain', tcname)
273 buildbot_common.Move(tmpdir, pnacldir)
274 PrunePNaClToolchain(pnacldir)
276 buildbot_common.RemoveDir(tmpdir)
278 if options.gyp and platform != 'win':
279 # If the gyp options is specified we install a toolchain
280 # wrapper so that gyp can switch toolchains via a commandline
282 bindir = os.path.join(pepperdir, 'toolchain', tcname, 'bin')
283 wrapper = os.path.join(SDK_SRC_DIR, 'tools', 'compiler-wrapper.py')
284 buildbot_common.MakeDir(bindir)
285 buildbot_common.CopyFile(wrapper, bindir)
287 # Module 'os' has no 'symlink' member (on Windows).
288 # pylint: disable=E1101
290 os.symlink('compiler-wrapper.py', os.path.join(bindir, 'i686-nacl-g++'))
291 os.symlink('compiler-wrapper.py', os.path.join(bindir, 'i686-nacl-gcc'))
292 os.symlink('compiler-wrapper.py', os.path.join(bindir, 'i686-nacl-ar'))
295 # List of toolchain headers to install.
296 # Source is relative to top of Chromium tree, destination is relative
297 # to the toolchain header directory.
300 ('native_client/src/include/nacl/nacl_exception.h', 'nacl/'),
301 ('native_client/src/include/nacl/nacl_minidump.h', 'nacl/'),
302 ('native_client/src/untrusted/irt/irt.h', ''),
303 ('native_client/src/untrusted/irt/irt_dev.h', ''),
304 ('native_client/src/untrusted/nacl/nacl_dyncode.h', 'nacl/'),
305 ('native_client/src/untrusted/nacl/nacl_startup.h', 'nacl/'),
306 ('native_client/src/untrusted/nacl/nacl_thread.h', 'nacl/'),
307 ('native_client/src/untrusted/pthread/pthread.h', ''),
308 ('native_client/src/untrusted/pthread/semaphore.h', ''),
309 ('native_client/src/untrusted/valgrind/dynamic_annotations.h', 'nacl/'),
310 ('ppapi/nacl_irt/irt_ppapi.h', ''),
313 ('native_client/src/include/nacl/nacl_exception.h', 'nacl/'),
314 ('native_client/src/include/nacl/nacl_minidump.h', 'nacl/'),
315 ('native_client/src/untrusted/irt/irt.h', ''),
316 ('native_client/src/untrusted/irt/irt_dev.h', ''),
317 ('native_client/src/untrusted/nacl/nacl_dyncode.h', 'nacl/'),
318 ('native_client/src/untrusted/nacl/nacl_startup.h', 'nacl/'),
319 ('native_client/src/untrusted/nacl/nacl_thread.h', 'nacl/'),
320 ('native_client/src/untrusted/valgrind/dynamic_annotations.h', 'nacl/'),
321 ('ppapi/nacl_irt/irt_ppapi.h', ''),
326 def InstallFiles(src_root, dest_root, file_list):
327 """Copy a set of files from src_root to dest_root according
328 to the given mapping. This allows files to be copied from
329 to a location in the destination tree that is different to the
330 location in the source tree.
332 If the destination mapping ends with a '/' then the destination
333 basename is inherited from the the source file.
335 Wildcards can be used in the source list but it is not recommended
336 as this can end up adding things to the SDK unintentionally.
338 for file_spec in file_list:
339 # The list of files to install can be a simple list of
340 # strings or a list of pairs, where each pair corresponds
341 # to a mapping from source to destination names.
342 if type(file_spec) == str:
343 src_file = dest_file = file_spec
345 src_file, dest_file = file_spec
347 src_file = os.path.join(src_root, src_file)
349 # Expand sources files using glob.
350 sources = glob.glob(src_file)
354 if len(sources) > 1 and not dest_file.endswith('/'):
355 buildbot_common.ErrorExit("Target file must end in '/' when "
356 "using globbing to install multiple files")
358 for source in sources:
359 if dest_file.endswith('/'):
360 dest = os.path.join(dest_file, os.path.basename(source))
363 dest = os.path.join(dest_root, dest)
364 if not os.path.isdir(os.path.dirname(dest)):
365 buildbot_common.MakeDir(os.path.dirname(dest))
366 buildbot_common.CopyFile(source, dest)
369 def InstallNaClHeaders(tc_dst_inc, tc_name):
370 """Copies NaCl headers to expected locations in the toolchain."""
372 # arm toolchain header should be the same as the x86 newlib
376 InstallFiles(SRC_DIR, tc_dst_inc, NACL_HEADER_MAP[tc_name])
379 def MakeNinjaRelPath(path):
380 return os.path.join(os.path.relpath(OUT_DIR, SRC_DIR), path)
387 'libminidump_generator.a',
390 'libnacl_exception.a',
391 'libnacl_list_mappings.a',
398 'libminidump_generator.a',
399 'libminidump_generator.so',
402 'libnacl_dyncode.so',
403 'libnacl_exception.a',
404 'libnacl_exception.so',
405 'libnacl_list_mappings.a',
406 'libnacl_list_mappings.so',
412 'libminidump_generator.a',
415 'libnacl_exception.a',
416 'libnacl_list_mappings.a',
425 def GypNinjaInstall(pepperdir, toolchains):
426 build_dir = GYPBUILD_DIR
427 ninja_out_dir = os.path.join(OUT_DIR, build_dir, 'Release')
429 ['sel_ldr', 'sel_ldr_x86_32'],
430 ['ncval_new', 'ncval'],
431 ['irt_core_newlib_x32.nexe', 'irt_core_x86_32.nexe'],
432 ['irt_core_newlib_x64.nexe', 'irt_core_x86_64.nexe'],
435 platform = getos.GetPlatform()
437 # TODO(binji): dump_syms doesn't currently build on Windows. See
438 # http://crbug.com/245456
439 if platform != 'win':
441 ['dump_syms', 'dump_syms'],
442 ['minidump_dump', 'minidump_dump'],
443 ['minidump_stackwalk', 'minidump_stackwalk']
446 tools_files.append(['sel_ldr64', 'sel_ldr_x86_64'])
448 if platform == 'linux':
449 tools_files.append(['nacl_helper_bootstrap',
450 'nacl_helper_bootstrap_x86_32'])
451 tools_files.append(['nacl_helper_bootstrap64',
452 'nacl_helper_bootstrap_x86_64'])
454 buildbot_common.MakeDir(os.path.join(pepperdir, 'tools'))
456 # Add .exe extensions to all windows tools
457 for pair in tools_files:
458 if platform == 'win' and not pair[0].endswith('.nexe'):
462 InstallFiles(ninja_out_dir, os.path.join(pepperdir, 'tools'), tools_files)
464 for tc in set(toolchains) & set(['newlib', 'glibc', 'pnacl']):
468 xarches = ('arm', '32', '64')
470 for xarch in xarches:
471 if tc == 'glibc' and xarch == 'arm':
474 src_dir = GetGypBuiltLib(tc, xarch)
475 dst_dir = GetOutputToolchainLib(pepperdir, tc, xarch)
476 InstallFiles(src_dir, dst_dir, TOOLCHAIN_LIBS[tc])
479 src_dir = GetGypToolchainLib(tc, xarch)
480 InstallFiles(src_dir, dst_dir, ['crt1.o'])
483 def GypNinjaBuild_NaCl(rel_out_dir):
484 gyp_py = os.path.join(NACL_DIR, 'build', 'gyp_nacl')
485 nacl_core_sdk_gyp = os.path.join(NACL_DIR, 'build', 'nacl_core_sdk.gyp')
486 all_gyp = os.path.join(NACL_DIR, 'build', 'all.gyp')
488 out_dir = MakeNinjaRelPath(rel_out_dir)
489 out_dir_arm = MakeNinjaRelPath(rel_out_dir + '-arm')
490 GypNinjaBuild('ia32', gyp_py, nacl_core_sdk_gyp, 'nacl_core_sdk', out_dir)
491 GypNinjaBuild('arm', gyp_py, nacl_core_sdk_gyp, 'nacl_core_sdk', out_dir_arm)
492 GypNinjaBuild('ia32', gyp_py, all_gyp, 'ncval_new', out_dir)
494 platform = getos.GetPlatform()
495 if platform == 'win':
496 NinjaBuild('sel_ldr64', out_dir)
498 out_dir_64 = MakeNinjaRelPath(rel_out_dir + '-64')
499 GypNinjaBuild('x64', gyp_py, nacl_core_sdk_gyp, 'sel_ldr', out_dir_64)
501 # We only need sel_ldr from the 64-bit out directory.
502 # sel_ldr needs to be renamed, so we'll call it sel_ldr64.
503 files_to_copy = [('sel_ldr', 'sel_ldr64')]
504 if platform == 'linux':
505 files_to_copy.append(('nacl_helper_bootstrap', 'nacl_helper_bootstrap64'))
507 for src, dst in files_to_copy:
508 buildbot_common.CopyFile(
509 os.path.join(SRC_DIR, out_dir_64, 'Release', src),
510 os.path.join(SRC_DIR, out_dir, 'Release', dst))
513 def GypNinjaBuild_Breakpad(rel_out_dir):
514 # TODO(binji): dump_syms doesn't currently build on Windows. See
515 # http://crbug.com/245456
516 if getos.GetPlatform() == 'win':
519 gyp_py = os.path.join(SRC_DIR, 'build', 'gyp_chromium')
520 out_dir = MakeNinjaRelPath(rel_out_dir)
521 gyp_file = os.path.join(SRC_DIR, 'breakpad', 'breakpad.gyp')
522 build_list = ['dump_syms', 'minidump_dump', 'minidump_stackwalk']
523 GypNinjaBuild('ia32', gyp_py, gyp_file, build_list, out_dir)
526 def GypNinjaBuild_PPAPI(arch, rel_out_dir):
527 gyp_py = os.path.join(SRC_DIR, 'build', 'gyp_chromium')
528 out_dir = MakeNinjaRelPath(rel_out_dir)
529 gyp_file = os.path.join(SRC_DIR, 'ppapi', 'native_client',
531 GypNinjaBuild(arch, gyp_py, gyp_file, 'ppapi_lib', out_dir)
534 def GypNinjaBuild_Pnacl(rel_out_dir, target_arch):
535 # TODO(binji): This will build the pnacl_irt_shim twice; once as part of the
536 # Chromium build, and once here. When we move more of the SDK build process
537 # to gyp, we can remove this.
538 gyp_py = os.path.join(SRC_DIR, 'build', 'gyp_chromium')
540 out_dir = MakeNinjaRelPath(rel_out_dir)
541 gyp_file = os.path.join(SRC_DIR, 'ppapi', 'native_client', 'src',
542 'untrusted', 'pnacl_irt_shim', 'pnacl_irt_shim.gyp')
543 targets = ['pnacl_irt_shim']
544 GypNinjaBuild(target_arch, gyp_py, gyp_file, targets, out_dir, False)
547 def GypNinjaBuild(arch, gyp_py_script, gyp_file, targets,
548 out_dir, force_arm_gcc=True):
549 gyp_env = dict(os.environ)
550 gyp_env['GYP_GENERATORS'] = 'ninja'
553 gyp_defines.append('mac_sdk=%s' % options.mac_sdk)
555 gyp_defines.append('target_arch=%s' % arch)
557 if getos.GetPlatform() == 'linux':
558 if os.path.exists("/usr/bin/arm-linux-gnueabihf-gcc"):
559 # TODO(sbc): make this conditional once all our linux
560 # have the ARM cross compiler installed.
561 gyp_env['CC'] = 'arm-linux-gnueabihf-gcc'
562 gyp_env['CXX'] = 'arm-linux-gnueabihf-g++'
563 gyp_env['AR'] = 'arm-linux-gnueabihf-ar'
564 gyp_env['AS'] = 'arm-linux-gnueabihf-as'
565 gyp_env['CC_host'] = 'cc'
566 gyp_env['CXX_host'] = 'c++'
567 gyp_defines += ['armv7=1', 'arm_thumb=0', 'arm_neon=1',
568 'arm_float_abi=hard']
570 gyp_defines.append('nacl_enable_arm_gcc=1')
571 if getos.GetPlatform() == 'mac':
572 gyp_defines.append('clang=1')
574 gyp_env['GYP_DEFINES'] = ' '.join(gyp_defines)
575 for key in ['GYP_GENERATORS', 'GYP_DEFINES', 'CC']:
576 value = gyp_env.get(key)
577 if value is not None:
578 print '%s="%s"' % (key, value)
579 gyp_generator_flags = ['-G', 'output_dir=%s' % (out_dir,)]
580 gyp_depth = '--depth=.'
582 [sys.executable, gyp_py_script, gyp_file, gyp_depth] + \
586 NinjaBuild(targets, out_dir)
589 def NinjaBuild(targets, out_dir):
590 if type(targets) is not list:
592 out_config_dir = os.path.join(out_dir, 'Release')
593 buildbot_common.Run(['ninja', '-C', out_config_dir] + targets, cwd=SRC_DIR)
596 def BuildStepBuildToolchains(pepperdir, toolchains):
597 buildbot_common.BuildStep('SDK Items')
599 GypNinjaBuild_NaCl(GYPBUILD_DIR)
600 GypNinjaBuild_Breakpad(GYPBUILD_DIR)
602 platform = getos.GetPlatform()
603 newlibdir = os.path.join(pepperdir, 'toolchain', platform + '_x86_newlib')
604 glibcdir = os.path.join(pepperdir, 'toolchain', platform + '_x86_glibc')
605 armdir = os.path.join(pepperdir, 'toolchain', platform + '_arm_newlib')
606 pnacldir = os.path.join(pepperdir, 'toolchain', platform + '_pnacl')
608 if set(toolchains) & set(['glibc', 'newlib']):
609 GypNinjaBuild_PPAPI('ia32', GYPBUILD_DIR)
611 if 'arm' in toolchains:
612 GypNinjaBuild_PPAPI('arm', GYPBUILD_DIR + '-arm')
614 GypNinjaInstall(pepperdir, toolchains)
616 if 'newlib' in toolchains:
617 InstallNaClHeaders(GetToolchainNaClInclude('newlib', newlibdir, 'x86'),
620 if 'glibc' in toolchains:
621 InstallNaClHeaders(GetToolchainNaClInclude('glibc', glibcdir, 'x86'),
624 if 'arm' in toolchains:
625 InstallNaClHeaders(GetToolchainNaClInclude('newlib', armdir, 'arm'),
628 if 'pnacl' in toolchains:
629 # NOTE: For ia32, gyp builds both x86-32 and x86-64 by default.
630 for arch in ('ia32', 'arm'):
631 # Fill in the latest native pnacl shim library from the chrome build.
632 build_dir = GYPBUILD_DIR + '-pnacl-' + arch
633 GypNinjaBuild_Pnacl(build_dir, arch)
635 nacl_arches = ['x86-32', 'x86-64']
637 nacl_arches = ['arm']
639 buildbot_common.ErrorExit('Unknown architecture: %s' % arch)
640 for nacl_arch in nacl_arches:
641 release_build_dir = os.path.join(OUT_DIR, build_dir, 'Release',
642 'gen', 'tc_pnacl_translate',
645 buildbot_common.CopyFile(
646 os.path.join(release_build_dir, 'libpnacl_irt_shim.a'),
647 GetPNaClNativeLib(pnacldir, nacl_arch))
649 InstallNaClHeaders(GetToolchainNaClInclude('pnacl', pnacldir, 'x86'),
653 def MakeDirectoryOrClobber(pepperdir, dirname, clobber):
654 dirpath = os.path.join(pepperdir, dirname)
656 buildbot_common.RemoveDir(dirpath)
657 buildbot_common.MakeDir(dirpath)
662 def BuildStepUpdateHelpers(pepperdir, clobber):
663 buildbot_common.BuildStep('Update project helpers')
664 build_projects.UpdateHelpers(pepperdir, clobber=clobber)
667 def BuildStepUpdateUserProjects(pepperdir, toolchains,
668 build_experimental, clobber):
669 buildbot_common.BuildStep('Update examples and libraries')
672 if not build_experimental:
673 filters['EXPERIMENTAL'] = False
675 toolchains = toolchains[:]
677 # arm isn't a valid toolchain for build_projects
678 if 'arm' in toolchains:
679 toolchains.remove('arm')
681 if 'host' in toolchains:
682 toolchains.remove('host')
683 toolchains.append(getos.GetPlatform())
685 filters['TOOLS'] = toolchains
687 # Update examples and libraries
696 tree = parse_dsc.LoadProjectTree(SDK_SRC_DIR, include=filters)
697 build_projects.UpdateProjects(pepperdir, tree, clobber=clobber,
698 toolchains=toolchains)
701 def BuildStepMakeAll(pepperdir, directory, step_name,
702 deps=True, clean=False, config='Debug', args=None):
703 buildbot_common.BuildStep(step_name)
704 build_projects.BuildProjectsBranch(pepperdir, directory, clean,
708 def BuildStepBuildLibraries(pepperdir, directory):
709 BuildStepMakeAll(pepperdir, directory, 'Build Libraries Debug',
710 clean=True, config='Debug')
711 BuildStepMakeAll(pepperdir, directory, 'Build Libraries Release',
712 clean=True, config='Release')
714 # Cleanup .pyc file generated while building libraries. Without
715 # this we would end up shipping the pyc in the SDK tarball.
716 buildbot_common.RemoveFile(os.path.join(pepperdir, 'tools', '*.pyc'))
719 def GenerateNotice(fileroot, output_filename='NOTICE', extra_files=None):
720 # Look for LICENSE files
721 license_filenames_re = re.compile('LICENSE|COPYING|COPYRIGHT')
724 for root, _, files in os.walk(fileroot):
725 for filename in files:
726 if license_filenames_re.match(filename):
727 path = os.path.join(root, filename)
728 license_files.append(path)
731 license_files += [os.path.join(fileroot, f) for f in extra_files]
732 print '\n'.join(license_files)
734 if not os.path.isabs(output_filename):
735 output_filename = os.path.join(fileroot, output_filename)
736 generate_notice.Generate(output_filename, fileroot, license_files)
739 def BuildStepVerifyFilelist(pepperdir):
740 buildbot_common.BuildStep('Verify SDK Files')
741 file_list_path = os.path.join(SCRIPT_DIR, 'sdk_files.list')
743 verify_filelist.Verify(file_list_path, pepperdir)
745 except verify_filelist.ParseException, e:
746 buildbot_common.ErrorExit('Parsing sdk_files.list failed:\n\n%s' % e)
747 except verify_filelist.VerifyException, e:
748 file_list_rel = os.path.relpath(file_list_path)
749 verify_filelist_py = os.path.splitext(verify_filelist.__file__)[0] + '.py'
750 verify_filelist_py = os.path.relpath(verify_filelist_py)
751 pepperdir_rel = os.path.relpath(pepperdir)
754 SDK verification failed:
757 Add/remove files from %s to fix.
761 to test.""" % (e, file_list_rel, verify_filelist_py, file_list_rel,
763 buildbot_common.ErrorExit(msg)
766 def BuildStepTarBundle(pepper_ver, tarfile):
767 buildbot_common.BuildStep('Tar Pepper Bundle')
768 buildbot_common.MakeDir(os.path.dirname(tarfile))
769 buildbot_common.Run([sys.executable, CYGTAR, '-C', OUT_DIR, '-cjf', tarfile,
770 'pepper_' + pepper_ver], cwd=NACL_DIR)
773 def GetManifestBundle(pepper_ver, chrome_revision, nacl_revision, tarfile,
775 with open(tarfile, 'rb') as tarfile_stream:
776 archive_sha1, archive_size = manifest_util.DownloadAndComputeHash(
779 archive = manifest_util.Archive(manifest_util.GetHostOS())
780 archive.url = archive_url
781 archive.size = archive_size
782 archive.checksum = archive_sha1
784 bundle = manifest_util.Bundle('pepper_' + pepper_ver)
785 bundle.revision = int(chrome_revision)
786 bundle.repath = 'pepper_' + pepper_ver
787 bundle.version = int(pepper_ver)
788 bundle.description = (
789 'Chrome %s bundle. Chrome revision: %s. NaCl revision: %s' % (
790 pepper_ver, chrome_revision, nacl_revision))
791 bundle.stability = 'dev'
792 bundle.recommended = 'no'
793 bundle.archives = [archive]
797 def BuildStepArchiveBundle(name, pepper_ver, chrome_revision, nacl_revision,
799 buildbot_common.BuildStep('Archive %s' % name)
800 bucket_path = 'nativeclient-mirror/nacl/nacl_sdk/%s' % (
801 build_version.ChromeVersion(),)
802 tarname = os.path.basename(tarfile)
803 tarfile_dir = os.path.dirname(tarfile)
804 buildbot_common.Archive(tarname, bucket_path, tarfile_dir)
806 # generate "manifest snippet" for this archive.
807 archive_url = GSTORE + 'nacl_sdk/%s/%s' % (
808 build_version.ChromeVersion(), tarname)
809 bundle = GetManifestBundle(pepper_ver, chrome_revision, nacl_revision,
810 tarfile, archive_url)
812 manifest_snippet_file = os.path.join(OUT_DIR, tarname + '.json')
813 with open(manifest_snippet_file, 'wb') as manifest_snippet_stream:
814 manifest_snippet_stream.write(bundle.GetDataAsString())
816 buildbot_common.Archive(tarname + '.json', bucket_path, OUT_DIR,
820 def BuildStepArchiveSDKTools():
821 # Only push up sdk_tools.tgz and nacl_sdk.zip on the linux buildbot.
822 builder_name = os.getenv('BUILDBOT_BUILDERNAME', '')
823 if builder_name == 'linux-sdk-multi':
824 buildbot_common.BuildStep('Build SDK Tools')
825 build_updater.BuildUpdater(OUT_DIR)
827 buildbot_common.BuildStep('Archive SDK Tools')
828 bucket_path = 'nativeclient-mirror/nacl/nacl_sdk/%s' % (
829 build_version.ChromeVersion(),)
830 buildbot_common.Archive('sdk_tools.tgz', bucket_path, OUT_DIR,
832 buildbot_common.Archive('nacl_sdk.zip', bucket_path, OUT_DIR,
836 def BuildStepSyncNaClPorts():
837 """Pull the pinned revision of naclports from SVN."""
838 buildbot_common.BuildStep('Sync naclports')
839 if not os.path.exists(NACLPORTS_DIR):
840 # checkout new copy of naclports
841 cmd = ['svn', 'checkout', '-q', '-r', str(NACLPORTS_REV), NACLPORTS_URL,
843 buildbot_common.Run(cmd, cwd=os.path.dirname(NACLPORTS_DIR))
845 # sync existing copy to pinned revision.
846 cmd = ['svn', 'update', '-r', str(NACLPORTS_REV)]
847 buildbot_common.Run(cmd, cwd=NACLPORTS_DIR)
850 def BuildStepBuildNaClPorts(pepper_ver, pepperdir):
851 """Build selected naclports in all configurations."""
852 # TODO(sbc): currently naclports doesn't know anything about
853 # Debug builds so the Debug subfolders are all empty.
855 env = dict(os.environ)
856 env['NACL_SDK_ROOT'] = pepperdir
857 env['PEPPER_DIR'] = os.path.basename(pepperdir) # pepper_NN
858 env['NACLPORTS_NO_ANNOTATE'] = "1"
859 env['NACLPORTS_NO_UPLOAD'] = "1"
861 build_script = 'build_tools/bots/linux/naclports-linux-sdk-bundle.sh'
862 buildbot_common.BuildStep('Build naclports')
863 buildbot_common.Run([build_script], env=env, cwd=NACLPORTS_DIR)
865 bundle_dir = os.path.join(NACLPORTS_DIR, 'out', 'sdk_bundle')
866 out_dir = os.path.join(bundle_dir, 'pepper_%s' % pepper_ver)
868 # Some naclports do not include a standalone LICENSE/COPYING file
869 # so we explicitly list those here for inclusion.
870 extra_licenses = ('tinyxml/readme.txt',
873 src_root = os.path.join(NACLPORTS_DIR, 'out', 'repository-i686')
874 output_license = os.path.join(out_dir, 'ports', 'LICENSE')
875 GenerateNotice(src_root , output_license, extra_licenses)
876 readme = os.path.join(out_dir, 'ports', 'README')
877 oshelpers.Copy(['-v', os.path.join(SDK_SRC_DIR, 'README.naclports'), readme])
880 def BuildStepTarNaClPorts(pepper_ver, tarfile):
881 """Create tar archive containing headers and libs from naclports build."""
882 buildbot_common.BuildStep('Tar naclports Bundle')
883 buildbot_common.MakeDir(os.path.dirname(tarfile))
884 pepper_dir = 'pepper_%s' % pepper_ver
885 archive_dirs = [os.path.join(pepper_dir, 'ports')]
887 ports_out = os.path.join(NACLPORTS_DIR, 'out', 'sdk_bundle')
888 cmd = [sys.executable, CYGTAR, '-C', ports_out, '-cjf', tarfile]
890 buildbot_common.Run(cmd, cwd=NACL_DIR)
893 def BuildStepBuildAppEngine(pepperdir, chrome_revision):
894 """Build the projects found in src/gonacl_appengine/src"""
895 buildbot_common.BuildStep('Build GoNaCl AppEngine Projects')
896 cmd = ['make', 'upload', 'REVISION=%s' % chrome_revision]
897 env = dict(os.environ)
898 env['NACL_SDK_ROOT'] = pepperdir
899 env['NACLPORTS_NO_ANNOTATE'] = "1"
900 buildbot_common.Run(cmd, env=env, cwd=GONACL_APPENGINE_SRC_DIR)
904 parser = optparse.OptionParser()
905 parser.add_option('--bionic', help='Add bionic build.',
907 parser.add_option('--tar', help='Force the tar step.',
909 parser.add_option('--archive', help='Force the archive step.',
911 parser.add_option('--gyp',
912 help='Use gyp to build examples/libraries/Makefiles.',
914 parser.add_option('--release', help='PPAPI release version.',
915 dest='release', default=None)
916 parser.add_option('--build-ports',
917 help='Build naclport bundle.', action='store_true')
918 parser.add_option('--build-app-engine',
919 help='Build AppEngine demos.', action='store_true')
920 parser.add_option('--experimental',
921 help='build experimental examples and libraries', action='store_true',
922 dest='build_experimental')
923 parser.add_option('--skip-toolchain', help='Skip toolchain untar',
925 parser.add_option('--mac-sdk',
926 help='Set the mac-sdk (e.g. 10.6) to use when building with ninja.')
928 # To setup bash completion for this command first install optcomplete
929 # and then add this line to your .bashrc:
930 # complete -F _optcomplete build_sdk.py
933 optcomplete.autocomplete(parser)
938 options, args = parser.parse_args(args[1:])
940 parser.error("Unexpected arguments: %s" % str(args))
942 generate_make.use_gyp = options.gyp
943 if buildbot_common.IsSDKBuilder():
944 options.archive = True
945 options.build_ports = True
946 options.build_app_engine = True
949 toolchains = ['newlib', 'glibc', 'arm', 'pnacl', 'host']
951 toolchains.append('bionic')
953 print 'Building: ' + ' '.join(toolchains)
955 if options.archive and not options.tar:
956 parser.error('Incompatible arguments with archive.')
958 chrome_version = int(build_version.ChromeMajorVersion())
959 chrome_revision = build_version.ChromeRevision()
960 nacl_revision = build_version.NaClRevision()
961 pepper_ver = str(chrome_version)
962 pepper_old = str(chrome_version - 1)
963 pepperdir = os.path.join(OUT_DIR, 'pepper_' + pepper_ver)
964 pepperdir_old = os.path.join(OUT_DIR, 'pepper_' + pepper_old)
965 tarname = 'naclsdk_' + getos.GetPlatform() + '.tar.bz2'
966 tarfile = os.path.join(OUT_DIR, tarname)
969 pepper_ver = options.release
970 print 'Building PEPPER %s at %s' % (pepper_ver, chrome_revision)
972 if 'NACL_SDK_ROOT' in os.environ:
973 # We don't want the currently configured NACL_SDK_ROOT to have any effect
975 del os.environ['NACL_SDK_ROOT']
977 if not options.skip_toolchain:
978 BuildStepCleanPepperDirs(pepperdir, pepperdir_old)
979 BuildStepMakePepperDirs(pepperdir, ['include', 'toolchain', 'tools'])
980 BuildStepDownloadToolchains(toolchains)
981 BuildStepUntarToolchains(pepperdir, toolchains)
983 BuildStepBuildToolchains(pepperdir, toolchains)
985 BuildStepUpdateHelpers(pepperdir, True)
986 BuildStepUpdateUserProjects(pepperdir, toolchains,
987 options.build_experimental, True)
989 BuildStepCopyTextFiles(pepperdir, pepper_ver, chrome_revision, nacl_revision)
991 # Ship with libraries prebuilt, so run that first.
992 BuildStepBuildLibraries(pepperdir, 'src')
993 GenerateNotice(pepperdir)
995 # Verify the SDK contains what we expect.
996 BuildStepVerifyFilelist(pepperdir)
999 BuildStepTarBundle(pepper_ver, tarfile)
1001 if options.build_ports and getos.GetPlatform() == 'linux':
1002 ports_tarfile = os.path.join(OUT_DIR, 'naclports.tar.bz2')
1003 BuildStepSyncNaClPorts()
1004 BuildStepBuildNaClPorts(pepper_ver, pepperdir)
1006 BuildStepTarNaClPorts(pepper_ver, ports_tarfile)
1008 if options.build_app_engine and getos.GetPlatform() == 'linux':
1009 BuildStepBuildAppEngine(pepperdir, chrome_revision)
1011 # Archive on non-trybots.
1013 BuildStepArchiveBundle('build', pepper_ver, chrome_revision, nacl_revision,
1015 if options.build_ports and getos.GetPlatform() == 'linux':
1016 BuildStepArchiveBundle('naclports', pepper_ver, chrome_revision,
1017 nacl_revision, ports_tarfile)
1018 BuildStepArchiveSDKTools()
1023 if __name__ == '__main__':
1025 sys.exit(main(sys.argv))
1026 except KeyboardInterrupt:
1027 buildbot_common.ErrorExit('build_sdk: interrupted')