| #!/usr/bin/env python |
| # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| """Entry point for both build and try bots. |
| |
| This script is invoked from XXX, usually without arguments |
| to package an SDK. It automatically determines whether |
| this SDK is for mac, win, linux. |
| |
| The script inspects the following environment variables: |
| |
| BUILDBOT_BUILDERNAME to determine whether the script is run locally |
| and whether it should upload an SDK to file storage (GSTORE) |
| """ |
| |
| # pylint: disable=W0621 |
| |
| # std python includes |
| import datetime |
| import glob |
| import optparse |
| import os |
| import re |
| import sys |
| |
| if sys.version_info < (2, 6, 0): |
| sys.stderr.write("python 2.6 or later is required run this script\n") |
| sys.exit(1) |
| |
| # local includes |
| import buildbot_common |
| import build_projects |
| import build_updater |
| import build_version |
| import generate_notice |
| import manifest_util |
| import parse_dsc |
| import verify_filelist |
| |
| from build_paths import SCRIPT_DIR, SDK_SRC_DIR, SRC_DIR, NACL_DIR, OUT_DIR |
| from build_paths import NACLPORTS_DIR, GSTORE, GONACL_APPENGINE_SRC_DIR |
| |
| # Add SDK make tools scripts to the python path. |
| sys.path.append(os.path.join(SDK_SRC_DIR, 'tools')) |
| sys.path.append(os.path.join(NACL_DIR, 'build')) |
| |
| import getos |
| import oshelpers |
| |
| BUILD_DIR = os.path.join(NACL_DIR, 'build') |
| NACL_TOOLCHAIN_DIR = os.path.join(NACL_DIR, 'toolchain') |
| NACL_TOOLCHAINTARS_DIR = os.path.join(NACL_TOOLCHAIN_DIR, '.tars') |
| |
| CYGTAR = os.path.join(BUILD_DIR, 'cygtar.py') |
| PKGVER = os.path.join(BUILD_DIR, 'package_version', 'package_version.py') |
| |
| NACLPORTS_URL = 'https://chromium.googlesource.com/external/naclports.git' |
| NACLPORTS_REV = 'e53078c33d99b0b3cbadbbbbb92cccf7a48d5dc1' |
| |
| GYPBUILD_DIR = 'gypbuild' |
| |
| options = None |
| |
| # Map of: ToolchainName: (PackageName, SDKDir). |
| TOOLCHAIN_PACKAGE_MAP = { |
| 'newlib': ('nacl_x86_newlib', '%(platform)s_x86_newlib'), |
| 'bionic': ('nacl_arm_bionic', '%(platform)s_arm_bionic'), |
| 'arm': ('nacl_arm_newlib', '%(platform)s_arm_newlib'), |
| 'glibc': ('nacl_x86_glibc', '%(platform)s_x86_glibc'), |
| 'pnacl': ('pnacl_newlib', '%(platform)s_pnacl') |
| } |
| |
| |
| def GetToolchainNaClInclude(tcname, tcpath, arch): |
| if arch == 'x86': |
| if tcname == 'pnacl': |
| return os.path.join(tcpath, 'le32-nacl', 'include') |
| return os.path.join(tcpath, 'x86_64-nacl', 'include') |
| elif arch == 'arm': |
| return os.path.join(tcpath, 'arm-nacl', 'include') |
| else: |
| buildbot_common.ErrorExit('Unknown architecture: %s' % arch) |
| |
| |
| def GetGypGenDir(xarch): |
| if xarch == 'arm': |
| build_dir = GYPBUILD_DIR + '-arm' |
| else: |
| build_dir = GYPBUILD_DIR |
| return os.path.join(OUT_DIR, build_dir, 'Release', 'gen') |
| |
| |
| def GetGypBuiltLib(tcname, xarch=None): |
| if tcname == 'pnacl': |
| tcname = 'pnacl_newlib' |
| if not xarch: |
| xarch = '' |
| return os.path.join(GetGypGenDir(xarch), 'tc_' + tcname, 'lib' + xarch) |
| |
| |
| def GetToolchainNaClLib(tcname, tcpath, xarch): |
| if tcname == 'pnacl': |
| return os.path.join(tcpath, 'le32-nacl', 'lib') |
| elif xarch == '32': |
| return os.path.join(tcpath, 'x86_64-nacl', 'lib32') |
| elif xarch == '64': |
| return os.path.join(tcpath, 'x86_64-nacl', 'lib') |
| elif xarch == 'arm': |
| return os.path.join(tcpath, 'arm-nacl', 'lib') |
| |
| |
| def GetToolchainDirName(tcname, xarch): |
| if tcname == 'pnacl': |
| return '%s_%s' % (getos.GetPlatform(), tcname) |
| elif xarch == 'arm': |
| return '%s_arm_%s' % (getos.GetPlatform(), tcname) |
| else: |
| return '%s_x86_%s' % (getos.GetPlatform(), tcname) |
| |
| |
| def GetGypToolchainLib(tcname, xarch): |
| if xarch == 'arm': |
| toolchain = xarch |
| else: |
| toolchain = tcname |
| |
| tcpath = os.path.join(GetGypGenDir(xarch), 'sdk', |
| '%s_x86' % getos.GetPlatform(), |
| TOOLCHAIN_PACKAGE_MAP[toolchain][0]) |
| return GetToolchainNaClLib(tcname, tcpath, xarch) |
| |
| |
| def GetOutputToolchainLib(pepperdir, tcname, xarch): |
| tcpath = os.path.join(pepperdir, 'toolchain', |
| GetToolchainDirName(tcname, xarch)) |
| return GetToolchainNaClLib(tcname, tcpath, xarch) |
| |
| |
| def GetPNaClTranslatorLib(tcpath, arch): |
| if arch not in ['arm', 'x86-32', 'x86-64']: |
| buildbot_common.ErrorExit('Unknown architecture %s.' % arch) |
| return os.path.join(tcpath, 'translator', arch, 'lib') |
| |
| |
| def BuildStepDownloadToolchains(toolchains): |
| buildbot_common.BuildStep('Running package_version.py') |
| args = [sys.executable, PKGVER, '--exclude', 'arm_trusted'] |
| if 'bionic' in toolchains: |
| build_platform = '%s_x86' % getos.GetPlatform() |
| args.extend(['--append', os.path.join(build_platform, 'nacl_arm_bionic')]) |
| args.append('sync') |
| buildbot_common.Run(args, cwd=NACL_DIR) |
| |
| |
| def BuildStepCleanPepperDirs(pepperdir, pepperdir_old): |
| buildbot_common.BuildStep('Clean Pepper Dirs') |
| buildbot_common.RemoveDir(pepperdir_old) |
| buildbot_common.RemoveDir(pepperdir) |
| buildbot_common.MakeDir(pepperdir) |
| |
| |
| def BuildStepMakePepperDirs(pepperdir, subdirs): |
| for subdir in subdirs: |
| buildbot_common.MakeDir(os.path.join(pepperdir, subdir)) |
| |
| TEXT_FILES = [ |
| 'AUTHORS', |
| 'COPYING', |
| 'LICENSE', |
| 'README.Makefiles', |
| 'getting_started/README', |
| ] |
| |
| def BuildStepCopyTextFiles(pepperdir, pepper_ver, chrome_revision, |
| nacl_revision): |
| buildbot_common.BuildStep('Add Text Files') |
| InstallFiles(SDK_SRC_DIR, pepperdir, TEXT_FILES) |
| |
| # Replace a few placeholders in README |
| readme_text = open(os.path.join(SDK_SRC_DIR, 'README')).read() |
| readme_text = readme_text.replace('${VERSION}', pepper_ver) |
| readme_text = readme_text.replace('${CHROME_REVISION}', chrome_revision) |
| readme_text = readme_text.replace('${CHROME_COMMIT_POSITION}', |
| build_version.ChromeCommitPosition()) |
| readme_text = readme_text.replace('${NACL_REVISION}', nacl_revision) |
| |
| # Year/Month/Day Hour:Minute:Second |
| time_format = '%Y/%m/%d %H:%M:%S' |
| readme_text = readme_text.replace('${DATE}', |
| datetime.datetime.now().strftime(time_format)) |
| |
| open(os.path.join(pepperdir, 'README'), 'w').write(readme_text) |
| |
| |
| def BuildStepUntarToolchains(pepperdir, toolchains): |
| buildbot_common.BuildStep('Untar Toolchains') |
| platform = getos.GetPlatform() |
| build_platform = '%s_x86' % platform |
| tmpdir = os.path.join(OUT_DIR, 'tc_temp') |
| buildbot_common.RemoveDir(tmpdir) |
| buildbot_common.MakeDir(tmpdir) |
| |
| # Create a list of extract packages tuples, the first part should be |
| # "$PACKAGE_TARGET/$PACKAGE". The second part should be the destination |
| # directory relative to pepperdir/toolchain. |
| extract_packages = [] |
| for toolchain in toolchains: |
| toolchain_map = TOOLCHAIN_PACKAGE_MAP.get(toolchain, None) |
| if toolchain_map: |
| package_name, tcname = toolchain_map |
| package_tuple = (os.path.join(build_platform, package_name), |
| tcname % {'platform': platform}) |
| extract_packages.append(package_tuple) |
| |
| if extract_packages: |
| # Extract all of the packages into the temp directory. |
| package_names = [package_tuple[0] for package_tuple in extract_packages] |
| buildbot_common.Run([sys.executable, PKGVER, |
| '--packages', ','.join(package_names), |
| '--tar-dir', NACL_TOOLCHAINTARS_DIR, |
| '--dest-dir', tmpdir, |
| 'extract']) |
| |
| # Move all the packages we extracted to the correct destination. |
| for package_name, dest_dir in extract_packages: |
| full_src_dir = os.path.join(tmpdir, package_name) |
| full_dst_dir = os.path.join(pepperdir, 'toolchain', dest_dir) |
| buildbot_common.Move(full_src_dir, full_dst_dir) |
| |
| # Cleanup the temporary directory we are no longer using. |
| buildbot_common.RemoveDir(tmpdir) |
| |
| |
| # List of toolchain headers to install. |
| # Source is relative to top of Chromium tree, destination is relative |
| # to the toolchain header directory. |
| NACL_HEADER_MAP = { |
| 'newlib': [ |
| ('native_client/src/include/nacl/nacl_exception.h', 'nacl/'), |
| ('native_client/src/include/nacl/nacl_minidump.h', 'nacl/'), |
| ('native_client/src/untrusted/irt/irt.h', ''), |
| ('native_client/src/untrusted/irt/irt_dev.h', ''), |
| ('native_client/src/untrusted/irt/irt_extension.h', ''), |
| ('native_client/src/untrusted/nacl/nacl_dyncode.h', 'nacl/'), |
| ('native_client/src/untrusted/nacl/nacl_startup.h', 'nacl/'), |
| ('native_client/src/untrusted/pthread/pthread.h', ''), |
| ('native_client/src/untrusted/pthread/semaphore.h', ''), |
| ('native_client/src/untrusted/valgrind/dynamic_annotations.h', 'nacl/'), |
| ('ppapi/nacl_irt/public/irt_ppapi.h', ''), |
| ], |
| 'glibc': [ |
| ('native_client/src/include/nacl/nacl_exception.h', 'nacl/'), |
| ('native_client/src/include/nacl/nacl_minidump.h', 'nacl/'), |
| ('native_client/src/untrusted/irt/irt.h', ''), |
| ('native_client/src/untrusted/irt/irt_dev.h', ''), |
| ('native_client/src/untrusted/nacl/nacl_dyncode.h', 'nacl/'), |
| ('native_client/src/untrusted/nacl/nacl_startup.h', 'nacl/'), |
| ('native_client/src/untrusted/valgrind/dynamic_annotations.h', 'nacl/'), |
| ('ppapi/nacl_irt/public/irt_ppapi.h', ''), |
| ], |
| 'bionic': [ |
| ('ppapi/nacl_irt/public/irt_ppapi.h', ''), |
| ], |
| 'host': [] |
| } |
| |
| def InstallFiles(src_root, dest_root, file_list): |
| """Copy a set of files from src_root to dest_root according |
| to the given mapping. This allows files to be copied from |
| to a location in the destination tree that is different to the |
| location in the source tree. |
| |
| If the destination mapping ends with a '/' then the destination |
| basename is inherited from the the source file. |
| |
| Wildcards can be used in the source list but it is not recommended |
| as this can end up adding things to the SDK unintentionally. |
| """ |
| for file_spec in file_list: |
| # The list of files to install can be a simple list of |
| # strings or a list of pairs, where each pair corresponds |
| # to a mapping from source to destination names. |
| if type(file_spec) == str: |
| src_file = dest_file = file_spec |
| else: |
| src_file, dest_file = file_spec |
| |
| src_file = os.path.join(src_root, src_file) |
| |
| # Expand sources files using glob. |
| sources = glob.glob(src_file) |
| if not sources: |
| sources = [src_file] |
| |
| if len(sources) > 1 and not dest_file.endswith('/'): |
| buildbot_common.ErrorExit("Target file must end in '/' when " |
| "using globbing to install multiple files") |
| |
| for source in sources: |
| if dest_file.endswith('/'): |
| dest = os.path.join(dest_file, os.path.basename(source)) |
| else: |
| dest = dest_file |
| dest = os.path.join(dest_root, dest) |
| if not os.path.isdir(os.path.dirname(dest)): |
| buildbot_common.MakeDir(os.path.dirname(dest)) |
| buildbot_common.CopyFile(source, dest) |
| |
| |
| def InstallNaClHeaders(tc_dst_inc, tc_name): |
| """Copies NaCl headers to expected locations in the toolchain.""" |
| if tc_name == 'arm': |
| # arm toolchain header should be the same as the x86 newlib |
| # ones |
| tc_name = 'newlib' |
| |
| InstallFiles(SRC_DIR, tc_dst_inc, NACL_HEADER_MAP[tc_name]) |
| |
| |
| def MakeNinjaRelPath(path): |
| return os.path.join(os.path.relpath(OUT_DIR, SRC_DIR), path) |
| |
| |
| TOOLCHAIN_LIBS = { |
| 'bionic' : [ |
| 'libminidump_generator.a', |
| 'libnacl_dyncode.a', |
| 'libnacl_exception.a', |
| 'libnacl_list_mappings.a', |
| 'libppapi.a', |
| ], |
| 'newlib' : [ |
| 'crti.o', |
| 'crtn.o', |
| 'libminidump_generator.a', |
| 'libnacl.a', |
| 'libnacl_dyncode.a', |
| 'libnacl_exception.a', |
| 'libnacl_list_mappings.a', |
| 'libnosys.a', |
| 'libppapi.a', |
| 'libppapi_stub.a', |
| 'libpthread.a', |
| ], |
| 'glibc': [ |
| 'libminidump_generator.a', |
| 'libminidump_generator.so', |
| 'libnacl.a', |
| 'libnacl_dyncode.a', |
| 'libnacl_dyncode.so', |
| 'libnacl_exception.a', |
| 'libnacl_exception.so', |
| 'libnacl_list_mappings.a', |
| 'libnacl_list_mappings.so', |
| 'libppapi.a', |
| 'libppapi.so', |
| 'libppapi_stub.a', |
| ], |
| 'pnacl': [ |
| 'libminidump_generator.a', |
| 'libnacl.a', |
| 'libnacl_dyncode.a', |
| 'libnacl_exception.a', |
| 'libnacl_list_mappings.a', |
| 'libnosys.a', |
| 'libppapi.a', |
| 'libppapi_stub.a', |
| 'libpthread.a', |
| ] |
| } |
| |
| |
| def GypNinjaInstall(pepperdir, toolchains): |
| build_dir = GYPBUILD_DIR |
| ninja_out_dir = os.path.join(OUT_DIR, build_dir, 'Release') |
| tools_files = [ |
| ['sel_ldr', 'sel_ldr_x86_32'], |
| ['ncval_new', 'ncval'], |
| ['irt_core_newlib_x32.nexe', 'irt_core_x86_32.nexe'], |
| ['irt_core_newlib_x64.nexe', 'irt_core_x86_64.nexe'], |
| ] |
| |
| platform = getos.GetPlatform() |
| |
| # TODO(binji): dump_syms doesn't currently build on Windows. See |
| # http://crbug.com/245456 |
| if platform != 'win': |
| tools_files += [ |
| ['dump_syms', 'dump_syms'], |
| ['minidump_dump', 'minidump_dump'], |
| ['minidump_stackwalk', 'minidump_stackwalk'] |
| ] |
| |
| tools_files.append(['sel_ldr64', 'sel_ldr_x86_64']) |
| |
| if platform == 'linux': |
| tools_files.append(['nacl_helper_bootstrap', |
| 'nacl_helper_bootstrap_x86_32']) |
| tools_files.append(['nacl_helper_bootstrap64', |
| 'nacl_helper_bootstrap_x86_64']) |
| tools_files.append(['nonsfi_loader_newlib_x32_nonsfi.nexe', |
| 'nonsfi_loader_x86_32']) |
| |
| buildbot_common.MakeDir(os.path.join(pepperdir, 'tools')) |
| |
| # Add .exe extensions to all windows tools |
| for pair in tools_files: |
| if platform == 'win' and not pair[0].endswith('.nexe'): |
| pair[0] += '.exe' |
| pair[1] += '.exe' |
| |
| InstallFiles(ninja_out_dir, os.path.join(pepperdir, 'tools'), tools_files) |
| |
| # Add ARM binaries |
| if platform == 'linux' and not options.no_arm_trusted: |
| tools_files = [ |
| ['irt_core_newlib_arm.nexe', 'irt_core_arm.nexe'], |
| ['irt_core_newlib_arm.nexe', 'irt_core_arm.nexe'], |
| ['sel_ldr', 'sel_ldr_arm'], |
| ['nacl_helper_bootstrap', 'nacl_helper_bootstrap_arm'] |
| ] |
| ninja_out_dir = os.path.join(OUT_DIR, build_dir + '-arm', 'Release') |
| InstallFiles(ninja_out_dir, os.path.join(pepperdir, 'tools'), tools_files) |
| |
| for tc in set(toolchains) & set(['newlib', 'glibc', 'pnacl']): |
| if tc == 'pnacl': |
| xarches = (None,) |
| else: |
| xarches = ('arm', '32', '64') |
| |
| for xarch in xarches: |
| if tc == 'glibc' and xarch == 'arm': |
| continue |
| |
| src_dir = GetGypBuiltLib(tc, xarch) |
| dst_dir = GetOutputToolchainLib(pepperdir, tc, xarch) |
| InstallFiles(src_dir, dst_dir, TOOLCHAIN_LIBS[tc]) |
| |
| # Copy ARM newlib components to bionic |
| if tc == 'newlib' and xarch == 'arm' and 'bionic' in toolchains: |
| bionic_dir = GetOutputToolchainLib(pepperdir, 'bionic', xarch) |
| InstallFiles(src_dir, bionic_dir, TOOLCHAIN_LIBS['bionic']) |
| |
| if tc != 'pnacl': |
| src_dir = GetGypToolchainLib(tc, xarch) |
| InstallFiles(src_dir, dst_dir, ['crt1.o']) |
| |
| |
| def GypNinjaBuild_NaCl(rel_out_dir): |
| gyp_py = os.path.join(NACL_DIR, 'build', 'gyp_nacl') |
| nacl_core_sdk_gyp = os.path.join(NACL_DIR, 'build', 'nacl_core_sdk.gyp') |
| all_gyp = os.path.join(NACL_DIR, 'build', 'all.gyp') |
| |
| out_dir = MakeNinjaRelPath(rel_out_dir) |
| out_dir_arm = MakeNinjaRelPath(rel_out_dir + '-arm') |
| GypNinjaBuild('ia32', gyp_py, nacl_core_sdk_gyp, 'nacl_core_sdk', out_dir) |
| GypNinjaBuild('arm', gyp_py, nacl_core_sdk_gyp, 'nacl_core_sdk', out_dir_arm) |
| GypNinjaBuild('ia32', gyp_py, all_gyp, 'ncval_new', out_dir) |
| |
| platform = getos.GetPlatform() |
| if platform == 'win': |
| NinjaBuild('sel_ldr64', out_dir) |
| else: |
| out_dir_64 = MakeNinjaRelPath(rel_out_dir + '-64') |
| GypNinjaBuild('x64', gyp_py, nacl_core_sdk_gyp, 'sel_ldr', out_dir_64) |
| |
| # We only need sel_ldr from the 64-bit out directory. |
| # sel_ldr needs to be renamed, so we'll call it sel_ldr64. |
| files_to_copy = [('sel_ldr', 'sel_ldr64')] |
| if platform == 'linux': |
| files_to_copy.append(('nacl_helper_bootstrap', 'nacl_helper_bootstrap64')) |
| |
| for src, dst in files_to_copy: |
| buildbot_common.CopyFile( |
| os.path.join(SRC_DIR, out_dir_64, 'Release', src), |
| os.path.join(SRC_DIR, out_dir, 'Release', dst)) |
| |
| |
| def GypNinjaBuild_Breakpad(rel_out_dir): |
| # TODO(binji): dump_syms doesn't currently build on Windows. See |
| # http://crbug.com/245456 |
| if getos.GetPlatform() == 'win': |
| return |
| |
| gyp_py = os.path.join(SRC_DIR, 'build', 'gyp_chromium') |
| out_dir = MakeNinjaRelPath(rel_out_dir) |
| gyp_file = os.path.join(SRC_DIR, 'breakpad', 'breakpad.gyp') |
| build_list = ['dump_syms', 'minidump_dump', 'minidump_stackwalk'] |
| GypNinjaBuild('ia32', gyp_py, gyp_file, build_list, out_dir) |
| |
| |
| def GypNinjaBuild_PPAPI(arch, rel_out_dir): |
| gyp_py = os.path.join(SRC_DIR, 'build', 'gyp_chromium') |
| out_dir = MakeNinjaRelPath(rel_out_dir) |
| gyp_file = os.path.join(SRC_DIR, 'ppapi', 'native_client', |
| 'native_client.gyp') |
| GypNinjaBuild(arch, gyp_py, gyp_file, 'ppapi_lib', out_dir) |
| |
| |
| def GypNinjaBuild_Pnacl(rel_out_dir, target_arch): |
| # TODO(binji): This will build the pnacl_irt_shim twice; once as part of the |
| # Chromium build, and once here. When we move more of the SDK build process |
| # to gyp, we can remove this. |
| gyp_py = os.path.join(SRC_DIR, 'build', 'gyp_chromium') |
| |
| out_dir = MakeNinjaRelPath(rel_out_dir) |
| gyp_file = os.path.join(SRC_DIR, 'ppapi', 'native_client', 'src', |
| 'untrusted', 'pnacl_irt_shim', 'pnacl_irt_shim.gyp') |
| targets = ['aot'] |
| GypNinjaBuild(target_arch, gyp_py, gyp_file, targets, out_dir, False) |
| |
| |
| def GypNinjaBuild(arch, gyp_py_script, gyp_file, targets, |
| out_dir, force_arm_gcc=True): |
| gyp_env = dict(os.environ) |
| gyp_env['GYP_GENERATORS'] = 'ninja' |
| gyp_defines = [] |
| if options.mac_sdk: |
| gyp_defines.append('mac_sdk=%s' % options.mac_sdk) |
| if arch: |
| gyp_defines.append('target_arch=%s' % arch) |
| if arch == 'arm': |
| if getos.GetPlatform() == 'linux': |
| gyp_env['CC'] = 'arm-linux-gnueabihf-gcc' |
| gyp_env['CXX'] = 'arm-linux-gnueabihf-g++' |
| gyp_env['AR'] = 'arm-linux-gnueabihf-ar' |
| gyp_env['AS'] = 'arm-linux-gnueabihf-as' |
| gyp_env['CC_host'] = 'cc' |
| gyp_env['CXX_host'] = 'c++' |
| gyp_defines += ['armv7=1', 'arm_thumb=0', 'arm_neon=1', |
| 'arm_float_abi=hard'] |
| if force_arm_gcc: |
| gyp_defines.append('nacl_enable_arm_gcc=1') |
| if options.no_arm_trusted: |
| gyp_defines.append('disable_cross_trusted=1') |
| if getos.GetPlatform() == 'mac': |
| gyp_defines.append('clang=1') |
| |
| gyp_env['GYP_DEFINES'] = ' '.join(gyp_defines) |
| for key in ['GYP_GENERATORS', 'GYP_DEFINES', 'CC']: |
| value = gyp_env.get(key) |
| if value is not None: |
| print '%s="%s"' % (key, value) |
| gyp_generator_flags = ['-G', 'output_dir=%s' % (out_dir,)] |
| gyp_depth = '--depth=.' |
| buildbot_common.Run( |
| [sys.executable, gyp_py_script, gyp_file, gyp_depth] + \ |
| gyp_generator_flags, |
| cwd=SRC_DIR, |
| env=gyp_env) |
| NinjaBuild(targets, out_dir) |
| |
| |
| def NinjaBuild(targets, out_dir): |
| if type(targets) is not list: |
| targets = [targets] |
| out_config_dir = os.path.join(out_dir, 'Release') |
| buildbot_common.Run(['ninja', '-C', out_config_dir] + targets, cwd=SRC_DIR) |
| |
| |
| def BuildStepBuildToolchains(pepperdir, toolchains): |
| buildbot_common.BuildStep('SDK Items') |
| |
| GypNinjaBuild_NaCl(GYPBUILD_DIR) |
| GypNinjaBuild_Breakpad(GYPBUILD_DIR) |
| |
| platform = getos.GetPlatform() |
| newlibdir = os.path.join(pepperdir, 'toolchain', platform + '_x86_newlib') |
| glibcdir = os.path.join(pepperdir, 'toolchain', platform + '_x86_glibc') |
| armdir = os.path.join(pepperdir, 'toolchain', platform + '_arm_newlib') |
| pnacldir = os.path.join(pepperdir, 'toolchain', platform + '_pnacl') |
| bionicdir = os.path.join(pepperdir, 'toolchain', platform + '_arm_bionic') |
| |
| if set(toolchains) & set(['glibc', 'newlib']): |
| GypNinjaBuild_PPAPI('ia32', GYPBUILD_DIR) |
| GypNinjaBuild_PPAPI('x64', GYPBUILD_DIR) |
| |
| if 'arm' in toolchains: |
| GypNinjaBuild_PPAPI('arm', GYPBUILD_DIR + '-arm') |
| |
| GypNinjaInstall(pepperdir, toolchains) |
| |
| if 'newlib' in toolchains: |
| InstallNaClHeaders(GetToolchainNaClInclude('newlib', newlibdir, 'x86'), |
| 'newlib') |
| |
| if 'glibc' in toolchains: |
| InstallNaClHeaders(GetToolchainNaClInclude('glibc', glibcdir, 'x86'), |
| 'glibc') |
| |
| if 'arm' in toolchains: |
| InstallNaClHeaders(GetToolchainNaClInclude('newlib', armdir, 'arm'), |
| 'arm') |
| |
| if 'bionic' in toolchains: |
| InstallNaClHeaders(GetToolchainNaClInclude('bionic', bionicdir, 'arm'), |
| 'bionic') |
| |
| if 'pnacl' in toolchains: |
| # NOTE: For ia32, gyp builds both x86-32 and x86-64 by default. |
| for arch in ('ia32', 'arm'): |
| # Fill in the latest native pnacl shim library from the chrome build. |
| build_dir = GYPBUILD_DIR + '-pnacl-' + arch |
| GypNinjaBuild_Pnacl(build_dir, arch) |
| if arch == 'ia32': |
| nacl_arches = ['x86-32', 'x86-64'] |
| elif arch == 'arm': |
| nacl_arches = ['arm'] |
| else: |
| buildbot_common.ErrorExit('Unknown architecture: %s' % arch) |
| for nacl_arch in nacl_arches: |
| release_build_dir = os.path.join(OUT_DIR, build_dir, 'Release', |
| 'gen', 'tc_pnacl_translate', |
| 'lib-' + nacl_arch) |
| |
| pnacl_translator_lib_dir = GetPNaClTranslatorLib(pnacldir, nacl_arch) |
| if not os.path.isdir(pnacl_translator_lib_dir): |
| buildbot_common.ErrorExit('Expected %s directory to exist.' % |
| pnacl_translator_lib_dir) |
| |
| buildbot_common.CopyFile( |
| os.path.join(release_build_dir, 'libpnacl_irt_shim.a'), |
| pnacl_translator_lib_dir) |
| |
| InstallNaClHeaders(GetToolchainNaClInclude('pnacl', pnacldir, 'x86'), |
| 'newlib') |
| |
| |
| def MakeDirectoryOrClobber(pepperdir, dirname, clobber): |
| dirpath = os.path.join(pepperdir, dirname) |
| if clobber: |
| buildbot_common.RemoveDir(dirpath) |
| buildbot_common.MakeDir(dirpath) |
| |
| return dirpath |
| |
| |
| def BuildStepUpdateHelpers(pepperdir, clobber): |
| buildbot_common.BuildStep('Update project helpers') |
| build_projects.UpdateHelpers(pepperdir, clobber=clobber) |
| |
| |
| def BuildStepUpdateUserProjects(pepperdir, toolchains, |
| build_experimental, clobber): |
| buildbot_common.BuildStep('Update examples and libraries') |
| |
| filters = {} |
| if not build_experimental: |
| filters['EXPERIMENTAL'] = False |
| if toolchains: |
| toolchains = toolchains[:] |
| |
| # arm isn't a valid toolchain for build_projects |
| if 'arm' in toolchains: |
| toolchains.remove('arm') |
| |
| if 'host' in toolchains: |
| toolchains.remove('host') |
| toolchains.append(getos.GetPlatform()) |
| |
| filters['TOOLS'] = toolchains |
| |
| # Update examples and libraries |
| filters['DEST'] = [ |
| 'getting_started', |
| 'examples/api', |
| 'examples/benchmarks', |
| 'examples/demo', |
| 'examples/tutorial', |
| 'src' |
| ] |
| |
| tree = parse_dsc.LoadProjectTree(SDK_SRC_DIR, include=filters) |
| build_projects.UpdateProjects(pepperdir, tree, clobber=clobber, |
| toolchains=toolchains) |
| |
| |
| def BuildStepMakeAll(pepperdir, directory, step_name, |
| deps=True, clean=False, config='Debug', args=None): |
| buildbot_common.BuildStep(step_name) |
| build_projects.BuildProjectsBranch(pepperdir, directory, clean, |
| deps, config, args) |
| |
| |
| def BuildStepBuildLibraries(pepperdir, directory): |
| BuildStepMakeAll(pepperdir, directory, 'Build Libraries Debug', |
| clean=True, config='Debug') |
| BuildStepMakeAll(pepperdir, directory, 'Build Libraries Release', |
| clean=True, config='Release') |
| |
| # Cleanup .pyc file generated while building libraries. Without |
| # this we would end up shipping the pyc in the SDK tarball. |
| buildbot_common.RemoveFile(os.path.join(pepperdir, 'tools', '*.pyc')) |
| |
| |
| def GenerateNotice(fileroot, output_filename='NOTICE', extra_files=None): |
| # Look for LICENSE files |
| license_filenames_re = re.compile('LICENSE|COPYING|COPYRIGHT') |
| |
| license_files = [] |
| for root, _, files in os.walk(fileroot): |
| for filename in files: |
| if license_filenames_re.match(filename): |
| path = os.path.join(root, filename) |
| license_files.append(path) |
| |
| if extra_files: |
| license_files += [os.path.join(fileroot, f) for f in extra_files] |
| print '\n'.join(license_files) |
| |
| if not os.path.isabs(output_filename): |
| output_filename = os.path.join(fileroot, output_filename) |
| generate_notice.Generate(output_filename, fileroot, license_files) |
| |
| |
| def BuildStepVerifyFilelist(pepperdir): |
| buildbot_common.BuildStep('Verify SDK Files') |
| file_list_path = os.path.join(SCRIPT_DIR, 'sdk_files.list') |
| try: |
| verify_filelist.Verify(file_list_path, pepperdir) |
| print 'OK' |
| except verify_filelist.ParseException, e: |
| buildbot_common.ErrorExit('Parsing sdk_files.list failed:\n\n%s' % e) |
| except verify_filelist.VerifyException, e: |
| file_list_rel = os.path.relpath(file_list_path) |
| verify_filelist_py = os.path.splitext(verify_filelist.__file__)[0] + '.py' |
| verify_filelist_py = os.path.relpath(verify_filelist_py) |
| pepperdir_rel = os.path.relpath(pepperdir) |
| |
| msg = """\ |
| SDK verification failed: |
| |
| %s |
| Add/remove files from %s to fix. |
| |
| Run: |
| ./%s %s %s |
| to test.""" % (e, file_list_rel, verify_filelist_py, file_list_rel, |
| pepperdir_rel) |
| buildbot_common.ErrorExit(msg) |
| |
| |
| def BuildStepTarBundle(pepper_ver, tarfile): |
| buildbot_common.BuildStep('Tar Pepper Bundle') |
| buildbot_common.MakeDir(os.path.dirname(tarfile)) |
| buildbot_common.Run([sys.executable, CYGTAR, '-C', OUT_DIR, '-cjf', tarfile, |
| 'pepper_' + pepper_ver], cwd=NACL_DIR) |
| |
| |
| def GetManifestBundle(pepper_ver, chrome_revision, nacl_revision, tarfile, |
| archive_url): |
| with open(tarfile, 'rb') as tarfile_stream: |
| archive_sha1, archive_size = manifest_util.DownloadAndComputeHash( |
| tarfile_stream) |
| |
| archive = manifest_util.Archive(manifest_util.GetHostOS()) |
| archive.url = archive_url |
| archive.size = archive_size |
| archive.checksum = archive_sha1 |
| |
| bundle = manifest_util.Bundle('pepper_' + pepper_ver) |
| bundle.revision = int(chrome_revision) |
| bundle.repath = 'pepper_' + pepper_ver |
| bundle.version = int(pepper_ver) |
| bundle.description = ( |
| 'Chrome %s bundle. Chrome revision: %s. NaCl revision: %s' % ( |
| pepper_ver, chrome_revision, nacl_revision)) |
| bundle.stability = 'dev' |
| bundle.recommended = 'no' |
| bundle.archives = [archive] |
| return bundle |
| |
| |
| def BuildStepArchiveBundle(name, pepper_ver, chrome_revision, nacl_revision, |
| tarfile): |
| buildbot_common.BuildStep('Archive %s' % name) |
| bucket_path = 'nativeclient-mirror/nacl/nacl_sdk/%s' % ( |
| build_version.ChromeVersion(),) |
| tarname = os.path.basename(tarfile) |
| tarfile_dir = os.path.dirname(tarfile) |
| buildbot_common.Archive(tarname, bucket_path, tarfile_dir) |
| |
| # generate "manifest snippet" for this archive. |
| archive_url = GSTORE + 'nacl_sdk/%s/%s' % ( |
| build_version.ChromeVersion(), tarname) |
| bundle = GetManifestBundle(pepper_ver, chrome_revision, nacl_revision, |
| tarfile, archive_url) |
| |
| manifest_snippet_file = os.path.join(OUT_DIR, tarname + '.json') |
| with open(manifest_snippet_file, 'wb') as manifest_snippet_stream: |
| manifest_snippet_stream.write(bundle.GetDataAsString()) |
| |
| buildbot_common.Archive(tarname + '.json', bucket_path, OUT_DIR, |
| step_link=False) |
| |
| |
| def BuildStepArchiveSDKTools(): |
| # Only push up sdk_tools.tgz and nacl_sdk.zip on the linux buildbot. |
| builder_name = os.getenv('BUILDBOT_BUILDERNAME', '') |
| if builder_name == 'linux-sdk-multi': |
| buildbot_common.BuildStep('Build SDK Tools') |
| build_updater.BuildUpdater(OUT_DIR) |
| |
| buildbot_common.BuildStep('Archive SDK Tools') |
| bucket_path = 'nativeclient-mirror/nacl/nacl_sdk/%s' % ( |
| build_version.ChromeVersion(),) |
| buildbot_common.Archive('sdk_tools.tgz', bucket_path, OUT_DIR, |
| step_link=False) |
| buildbot_common.Archive('nacl_sdk.zip', bucket_path, OUT_DIR, |
| step_link=False) |
| |
| |
| def BuildStepSyncNaClPorts(): |
| """Pull the pinned revision of naclports from SVN.""" |
| buildbot_common.BuildStep('Sync naclports') |
| |
| # In case a previous svn checkout exists, remove it. |
| # TODO(sbc): remove this once all the build machines |
| # have removed the old checkout |
| if (os.path.exists(NACLPORTS_DIR) and |
| not os.path.exists(os.path.join(NACLPORTS_DIR, '.git'))): |
| buildbot_common.RemoveDir(NACLPORTS_DIR) |
| |
| if not os.path.exists(NACLPORTS_DIR): |
| # checkout new copy of naclports |
| cmd = ['git', 'clone', NACLPORTS_URL, 'naclports'] |
| buildbot_common.Run(cmd, cwd=os.path.dirname(NACLPORTS_DIR)) |
| else: |
| # checkout new copy of naclports |
| buildbot_common.Run(['git', 'fetch'], cwd=NACLPORTS_DIR) |
| |
| # sync to required revision |
| cmd = ['git', 'checkout', str(NACLPORTS_REV)] |
| buildbot_common.Run(cmd, cwd=NACLPORTS_DIR) |
| |
| |
| def BuildStepBuildNaClPorts(pepper_ver, pepperdir): |
| """Build selected naclports in all configurations.""" |
| # TODO(sbc): currently naclports doesn't know anything about |
| # Debug builds so the Debug subfolders are all empty. |
| |
| env = dict(os.environ) |
| env['NACL_SDK_ROOT'] = pepperdir |
| env['PEPPER_DIR'] = os.path.basename(pepperdir) # pepper_NN |
| env['NACLPORTS_NO_ANNOTATE'] = "1" |
| env['NACLPORTS_NO_UPLOAD'] = "1" |
| env['BUILDBOT_GOT_REVISION'] = str(NACLPORTS_REV) |
| |
| build_script = 'build_tools/buildbot_sdk_bundle.sh' |
| buildbot_common.BuildStep('Build naclports') |
| |
| bundle_dir = os.path.join(NACLPORTS_DIR, 'out', 'sdk_bundle') |
| out_dir = os.path.join(bundle_dir, 'pepper_%s' % pepper_ver) |
| |
| # Remove the sdk_bundle directory to remove stale files from previous builds. |
| buildbot_common.RemoveDir(bundle_dir) |
| |
| buildbot_common.Run([build_script], env=env, cwd=NACLPORTS_DIR) |
| |
| # Some naclports do not include a standalone LICENSE/COPYING file |
| # so we explicitly list those here for inclusion. |
| extra_licenses = ('tinyxml/readme.txt', |
| 'jpeg-8d/README', |
| 'zlib-1.2.3/README') |
| src_root = os.path.join(NACLPORTS_DIR, 'out', 'build') |
| output_license = os.path.join(out_dir, 'ports', 'LICENSE') |
| GenerateNotice(src_root , output_license, extra_licenses) |
| readme = os.path.join(out_dir, 'ports', 'README') |
| oshelpers.Copy(['-v', os.path.join(SDK_SRC_DIR, 'README.naclports'), readme]) |
| |
| |
| def BuildStepTarNaClPorts(pepper_ver, tarfile): |
| """Create tar archive containing headers and libs from naclports build.""" |
| buildbot_common.BuildStep('Tar naclports Bundle') |
| buildbot_common.MakeDir(os.path.dirname(tarfile)) |
| pepper_dir = 'pepper_%s' % pepper_ver |
| archive_dirs = [os.path.join(pepper_dir, 'ports')] |
| |
| ports_out = os.path.join(NACLPORTS_DIR, 'out', 'sdk_bundle') |
| cmd = [sys.executable, CYGTAR, '-C', ports_out, '-cjf', tarfile] |
| cmd += archive_dirs |
| buildbot_common.Run(cmd, cwd=NACL_DIR) |
| |
| |
| def BuildStepBuildAppEngine(pepperdir, chrome_revision): |
| """Build the projects found in src/gonacl_appengine/src""" |
| buildbot_common.BuildStep('Build GoNaCl AppEngine Projects') |
| cmd = ['make', 'upload', 'REVISION=%s' % chrome_revision] |
| env = dict(os.environ) |
| env['NACL_SDK_ROOT'] = pepperdir |
| env['NACLPORTS_NO_ANNOTATE'] = "1" |
| buildbot_common.Run(cmd, env=env, cwd=GONACL_APPENGINE_SRC_DIR) |
| |
| |
| def main(args): |
| parser = optparse.OptionParser(description=__doc__) |
| parser.add_option('--nacl-tree-path', |
| help='Path to native client tree for bionic build.', |
| dest='nacl_tree_path') |
| parser.add_option('--qemu', help='Add qemu for ARM.', |
| action='store_true') |
| parser.add_option('--bionic', help='Add bionic build.', |
| action='store_true') |
| parser.add_option('--tar', help='Force the tar step.', |
| action='store_true') |
| parser.add_option('--archive', help='Force the archive step.', |
| action='store_true') |
| parser.add_option('--release', help='PPAPI release version.', |
| dest='release', default=None) |
| parser.add_option('--build-ports', |
| help='Build naclport bundle.', action='store_true') |
| parser.add_option('--build-app-engine', |
| help='Build AppEngine demos.', action='store_true') |
| parser.add_option('--experimental', |
| help='build experimental examples and libraries', action='store_true', |
| dest='build_experimental') |
| parser.add_option('--skip-toolchain', help='Skip toolchain untar', |
| action='store_true') |
| parser.add_option('--mac-sdk', |
| help='Set the mac-sdk (e.g. 10.6) to use when building with ninja.') |
| parser.add_option('--no-arm-trusted', action='store_true', |
| help='Disable building of ARM trusted components (sel_ldr, etc).') |
| |
| # To setup bash completion for this command first install optcomplete |
| # and then add this line to your .bashrc: |
| # complete -F _optcomplete build_sdk.py |
| try: |
| import optcomplete |
| optcomplete.autocomplete(parser) |
| except ImportError: |
| pass |
| |
| global options |
| options, args = parser.parse_args(args[1:]) |
| if args: |
| parser.error("Unexpected arguments: %s" % str(args)) |
| |
| if options.nacl_tree_path: |
| options.bionic = True |
| toolchain_build = os.path.join(options.nacl_tree_path, 'toolchain_build') |
| print 'WARNING: Building bionic toolchain from NaCl checkout.' |
| print 'This option builds bionic from the sources currently in the' |
| print 'provided NativeClient checkout, and the results instead of ' |
| print 'downloading a toolchain from the builder. This may result in a' |
| print 'NaCl SDK that can not run on ToT chrome.' |
| print 'NOTE: To clobber you will need to run toolchain_build_bionic.py' |
| print 'directly from the NativeClient checkout.' |
| print '' |
| response = raw_input("Type 'y' and hit enter to continue.\n") |
| if response != 'y' and response != 'Y': |
| print 'Aborting.' |
| return 1 |
| |
| # Get head version of NativeClient tree |
| buildbot_common.BuildStep('Build bionic toolchain.') |
| buildbot_common.Run([sys.executable, 'toolchain_build_bionic.py', '-f'], |
| cwd=toolchain_build) |
| else: |
| toolchain_build = None |
| |
| if buildbot_common.IsSDKBuilder(): |
| options.archive = True |
| options.build_ports = True |
| # TODO(binji): re-enable app_engine build when the linux builder stops |
| # breaking when trying to git clone from github. |
| # See http://crbug.com/412969. |
| options.build_app_engine = False |
| options.tar = True |
| |
| # NOTE: order matters here. This will be the order that is specified in the |
| # Makefiles; the first toolchain will be the default. |
| toolchains = ['pnacl', 'newlib', 'glibc', 'arm', 'host'] |
| |
| # Changes for experimental bionic builder |
| if options.bionic: |
| toolchains.append('bionic') |
| options.build_ports = False |
| options.build_app_engine = False |
| |
| print 'Building: ' + ' '.join(toolchains) |
| |
| if options.archive and not options.tar: |
| parser.error('Incompatible arguments with archive.') |
| |
| chrome_version = int(build_version.ChromeMajorVersion()) |
| chrome_revision = build_version.ChromeRevision() |
| nacl_revision = build_version.NaClRevision() |
| pepper_ver = str(chrome_version) |
| pepper_old = str(chrome_version - 1) |
| pepperdir = os.path.join(OUT_DIR, 'pepper_' + pepper_ver) |
| pepperdir_old = os.path.join(OUT_DIR, 'pepper_' + pepper_old) |
| if options.bionic: |
| tarname = 'naclsdk_bionic.tar.bz2' |
| else: |
| tarname = 'naclsdk_' + getos.GetPlatform() + '.tar.bz2' |
| tarfile = os.path.join(OUT_DIR, tarname) |
| |
| if options.release: |
| pepper_ver = options.release |
| print 'Building PEPPER %s at %s' % (pepper_ver, chrome_revision) |
| |
| if 'NACL_SDK_ROOT' in os.environ: |
| # We don't want the currently configured NACL_SDK_ROOT to have any effect |
| # of the build. |
| del os.environ['NACL_SDK_ROOT'] |
| |
| if not options.skip_toolchain: |
| BuildStepCleanPepperDirs(pepperdir, pepperdir_old) |
| BuildStepMakePepperDirs(pepperdir, ['include', 'toolchain', 'tools']) |
| BuildStepDownloadToolchains(toolchains) |
| if options.nacl_tree_path: |
| # Instead of untarring, copy the raw bionic toolchain |
| not_bionic = [i for i in toolchains if i != 'bionic'] |
| BuildStepUntarToolchains(pepperdir, not_bionic) |
| tcname = GetToolchainDirName('bionic', 'arm') |
| srcdir = os.path.join(toolchain_build, 'out', tcname) |
| bionicdir = os.path.join(pepperdir, 'toolchain', tcname) |
| oshelpers.Copy(['-r', srcdir, bionicdir]) |
| else: |
| BuildStepUntarToolchains(pepperdir, toolchains) |
| |
| BuildStepBuildToolchains(pepperdir, toolchains) |
| |
| BuildStepUpdateHelpers(pepperdir, True) |
| BuildStepUpdateUserProjects(pepperdir, toolchains, |
| options.build_experimental, True) |
| |
| BuildStepCopyTextFiles(pepperdir, pepper_ver, chrome_revision, nacl_revision) |
| |
| # Ship with libraries prebuilt, so run that first. |
| BuildStepBuildLibraries(pepperdir, 'src') |
| GenerateNotice(pepperdir) |
| |
| # Verify the SDK contains what we expect. |
| if not options.bionic: |
| BuildStepVerifyFilelist(pepperdir) |
| |
| if options.tar: |
| BuildStepTarBundle(pepper_ver, tarfile) |
| |
| if options.build_ports and getos.GetPlatform() == 'linux': |
| ports_tarfile = os.path.join(OUT_DIR, 'naclports.tar.bz2') |
| BuildStepSyncNaClPorts() |
| BuildStepBuildNaClPorts(pepper_ver, pepperdir) |
| if options.tar: |
| BuildStepTarNaClPorts(pepper_ver, ports_tarfile) |
| |
| if options.build_app_engine and getos.GetPlatform() == 'linux': |
| BuildStepBuildAppEngine(pepperdir, chrome_revision) |
| |
| if options.qemu: |
| qemudir = os.path.join(NACL_DIR, 'toolchain', 'linux_arm-trusted') |
| oshelpers.Copy(['-r', qemudir, pepperdir]) |
| |
| # Archive on non-trybots. |
| if options.archive: |
| BuildStepArchiveBundle('build', pepper_ver, chrome_revision, nacl_revision, |
| tarfile) |
| if options.build_ports and getos.GetPlatform() == 'linux': |
| BuildStepArchiveBundle('naclports', pepper_ver, chrome_revision, |
| nacl_revision, ports_tarfile) |
| BuildStepArchiveSDKTools() |
| |
| return 0 |
| |
| |
| if __name__ == '__main__': |
| try: |
| sys.exit(main(sys.argv)) |
| except KeyboardInterrupt: |
| buildbot_common.ErrorExit('build_sdk: interrupted') |