summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBen Smith <binji@chromium.org>2014-11-10 17:17:38 -0800
committerBen Smith <binji@chromium.org>2014-11-11 01:18:54 +0000
commit54f447dd725b3dd4667166f8139f7ffa35078349 (patch)
tree7822566014b7fced7bf3d9d91070ada394af53ec
parent64ea407ab8b8b1b75dc78f534eb05f6c070fc044 (diff)
downloadchromium_src-54f447dd725b3dd4667166f8139f7ffa35078349.zip
chromium_src-54f447dd725b3dd4667166f8139f7ffa35078349.tar.gz
chromium_src-54f447dd725b3dd4667166f8139f7ffa35078349.tar.bz2
[NaCl SDK] Add build_artifacts.py script
This is in preparation for moving NaCl SDK out of the Chrome repo. BUG=none R=sbc@chromium.org, noelallen@chromium.org Review URL: https://codereview.chromium.org/702603002 Cr-Commit-Position: refs/heads/master@{#303559}
-rwxr-xr-xnative_client_sdk/src/build_tools/build_artifacts.py587
-rw-r--r--native_client_sdk/src/build_tools/build_paths.py1
-rwxr-xr-xnative_client_sdk/src/build_tools/tests/build_artifacts_test.py309
-rwxr-xr-xnative_client_sdk/src/test_all.py1
4 files changed, 898 insertions, 0 deletions
diff --git a/native_client_sdk/src/build_tools/build_artifacts.py b/native_client_sdk/src/build_tools/build_artifacts.py
new file mode 100755
index 0000000..1a9f0d8
--- /dev/null
+++ b/native_client_sdk/src/build_tools/build_artifacts.py
@@ -0,0 +1,587 @@
+#!/usr/bin/env python
+# Copyright 2014 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.
+
+"""Script to build binary components of the SDK.
+
+This script builds binary components of the Native Client SDK, create tarballs
+for them, and uploads them to Google Cloud Storage.
+
+This prevents a source dependency on the Chromium/NaCl tree in the Native
+Client SDK repo.
+"""
+
+import argparse
+import datetime
+import glob
+import hashlib
+import json
+import os
+import sys
+import tempfile
+
+if sys.version_info < (2, 7, 0):
+ sys.stderr.write("python 2.7 or later is required run this script\n")
+ sys.exit(1)
+
+import buildbot_common
+import build_version
+from build_paths import NACL_DIR, OUT_DIR, SRC_DIR, SDK_SRC_DIR
+from build_paths import BUILD_ARCHIVE_DIR
+
+sys.path.append(os.path.join(SDK_SRC_DIR, 'tools'))
+
+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')
+VERSION_JSON = os.path.join(BUILD_ARCHIVE_DIR, 'version.json')
+
+
+PLATFORM = getos.GetPlatform()
+TAR = oshelpers.FindExeInPath('tar')
+options = None
+all_archives = []
+
+
+# Mapping from toolchain name to the equivalent package_version.py directory
+# name.
+TOOLCHAIN_PACKAGE_MAP = {
+ 'newlib': 'nacl_x86_newlib',
+ 'bionic': 'nacl_arm_bionic',
+ 'arm': 'nacl_arm_newlib',
+ 'glibc': 'nacl_x86_glibc',
+ 'pnacl': 'pnacl_newlib'}
+
+
+def Tar(archive_path, root, files):
+ if os.path.exists(TAR):
+ cmd = [TAR]
+ else:
+ cmd = [sys.executable, CYGTAR]
+ cmd.extend(['-cjf', archive_path])
+ cmd.extend(files)
+ buildbot_common.Run(cmd, cwd=root)
+
+
+def ComputeSha(filename):
+ with open(filename) as f:
+ return hashlib.sha1(f.read()).hexdigest()
+
+
+class TempDir(object):
+ def __init__(self, prefix=None, dont_remove=False):
+ self.prefix = prefix
+ self.name = None
+ self.dont_remove = dont_remove
+ self.created = False
+ self.destroyed = False
+
+ def Create(self):
+ assert not self.created
+ self.name = tempfile.mkdtemp(prefix=self.prefix)
+ return self
+
+ def Destroy(self):
+ assert not self.destroyed
+ if not self.dont_remove:
+ buildbot_common.RemoveDir(self.name)
+
+ def __enter__(self):
+ self.Create()
+ return self.name
+
+ def __exit__(self, exc, value, tb):
+ return self.Destroy()
+
+
+class Archive(object):
+ def __init__(self, name):
+ self.name = '%s_%s' % (PLATFORM, name)
+ self.archive_name = self.name + '.tar.bz2'
+ self.archive_path = os.path.join(BUILD_ARCHIVE_DIR, self.archive_name)
+ self.dirname = os.path.join(BUILD_ARCHIVE_DIR, self.name)
+ self._MakeDirname()
+
+ def _MakeDirname(self):
+ if os.path.exists(self.dirname):
+ buildbot_common.RemoveDir(self.dirname)
+ buildbot_common.MakeDir(self.dirname)
+
+ def Copy(self, src_root, file_list):
+ if type(file_list) is not list:
+ file_list = [file_list]
+
+ 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) is 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:
+ if not (dest_file.endswith('/') or dest_file == ''):
+ buildbot_common.ErrorExit(
+ "Target file %r must end in '/' or be empty when "
+ "using globbing to install files %r" % (dest_file, sources))
+
+ 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(self.dirname, dest)
+ if not os.path.isdir(os.path.dirname(dest)):
+ buildbot_common.MakeDir(os.path.dirname(dest))
+ if os.path.isdir(source):
+ buildbot_common.CopyDir(source, dest)
+ else:
+ buildbot_common.CopyFile(source, dest)
+
+ def CreateArchiveShaFile(self):
+ sha1 = ComputeSha(self.archive_path)
+ sha1_filename = self.archive_path + '.sha1'
+ with open(sha1_filename, 'w') as f:
+ f.write(sha1)
+
+ def Tar(self):
+ Tar(self.archive_path, BUILD_ARCHIVE_DIR, [
+ self.name,
+ os.path.basename(VERSION_JSON)])
+ self.CreateArchiveShaFile()
+ all_archives.append(self.archive_name)
+
+
+def MakeToolchainArchive(toolchain):
+ archive = Archive(toolchain)
+
+ build_platform = '%s_x86' % PLATFORM
+
+ with TempDir('tc_%s_' % toolchain) as tmpdir:
+ package_name = os.path.join(build_platform,
+ TOOLCHAIN_PACKAGE_MAP.get(toolchain))
+
+ # Extract all of the packages into the temp directory.
+ buildbot_common.Run([sys.executable, PKGVER,
+ '--packages', package_name,
+ '--tar-dir', NACL_TOOLCHAINTARS_DIR,
+ '--dest-dir', tmpdir,
+ 'extract'])
+
+ # Copy all the files we extracted to the correct destination.
+ archive.Copy(os.path.join(tmpdir, package_name), ('*', ''))
+
+ archive.Tar()
+
+
+def MakeNinjaRelPath(path):
+ return os.path.join(os.path.relpath(OUT_DIR, SRC_DIR), path)
+
+
+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 GypNinjaBuild(arch, gyp_py_script, gyp_file, targets, out_dir):
+ 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 PLATFORM == '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', 'nacl_enable_arm_gcc=1']
+ if options.no_arm_trusted:
+ gyp_defines.append('disable_cross_trusted=1')
+ if PLATFORM == 'mac':
+ gyp_defines.append('clang=1')
+
+ gyp_env['GYP_DEFINES'] = ' '.join(gyp_defines)
+ generator_flags = ['-G', 'output_dir=%s' % out_dir]
+ depth = '--depth=.'
+ cmd = [sys.executable, gyp_py_script, gyp_file, depth] + generator_flags
+ buildbot_common.Run(cmd, cwd=SRC_DIR, env=gyp_env)
+ NinjaBuild(targets, out_dir)
+
+
+def GetToolsFiles():
+ 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'),
+ ]
+
+ if PLATFORM == 'linux':
+ files.append(['nacl_helper_bootstrap', 'nacl_helper_bootstrap_x86_32'])
+ files.append(['nonsfi_loader_newlib_x32_nonsfi.nexe',
+ 'nonsfi_loader_x86_32'])
+
+ # Add .exe extensions to all windows tools
+ for pair in files:
+ if PLATFORM == 'win' and not pair[0].endswith('.nexe'):
+ pair[0] += '.exe'
+ pair[1] += '.exe'
+
+ return files
+
+
+def GetTools64Files():
+ files = []
+ if PLATFORM == 'win':
+ files.append('sel_ldr64')
+ else:
+ files.append(('sel_ldr', 'sel_ldr_x86_64'))
+
+ if PLATFORM == 'linux':
+ files.append(('nacl_helper_bootstrap', 'nacl_helper_bootstrap_x86_64'))
+
+ return files
+
+
+def GetToolsArmFiles():
+ assert PLATFORM == 'linux'
+ return [('irt_core_newlib_arm.nexe', 'irt_core_arm.nexe'),
+ ('sel_ldr', 'sel_ldr_arm'),
+ ('nacl_helper_bootstrap', 'nacl_helper_bootstrap_arm')]
+
+
+def GetNewlibToolchainLibs():
+ return ['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']
+
+
+def GetGlibcToolchainLibs():
+ return ['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']
+
+
+def GetPNaClToolchainLibs():
+ return ['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 GetBionicToolchainLibs():
+ return ['libminidump_generator.a',
+ 'libnacl_dyncode.a',
+ 'libnacl_exception.a',
+ 'libnacl_list_mappings.a',
+ 'libppapi.a']
+
+
+def GetToolchainNaClLib(tcname, tcpath, xarch):
+ if tcname == 'pnacl':
+ return os.path.join(tcpath, 'le32-nacl', 'lib')
+ elif xarch == 'x86_32':
+ return os.path.join(tcpath, 'x86_64-nacl', 'lib32')
+ elif xarch == 'x86_64':
+ return os.path.join(tcpath, 'x86_64-nacl', 'lib')
+ elif xarch == 'arm':
+ return os.path.join(tcpath, 'arm-nacl', 'lib')
+
+
+def GetGypBuiltLib(root, tcname, xarch=None):
+ if tcname == 'pnacl':
+ tcname = 'pnacl_newlib'
+ if xarch == 'x86_32':
+ xarch = '32'
+ elif xarch == 'x86_64':
+ xarch = '64'
+ elif not xarch:
+ xarch = ''
+ return os.path.join(root, 'Release', 'gen', 'tc_' + tcname, 'lib' + xarch)
+
+
+def GetGypToolchainLib(root, tcname, xarch):
+ if xarch == 'arm':
+ toolchain = xarch
+ else:
+ toolchain = tcname
+
+ tcpath = os.path.join(root, 'Release', 'gen', 'sdk', '%s_x86' % PLATFORM,
+ TOOLCHAIN_PACKAGE_MAP[toolchain])
+ return GetToolchainNaClLib(tcname, tcpath, xarch)
+
+
+def MakeGypArchives():
+ join = os.path.join
+ gyp_nacl = join(NACL_DIR, 'build', 'gyp_nacl')
+ gyp_chromium = join(SRC_DIR, 'build', 'gyp_chromium')
+ nacl_core_sdk_gyp = join(NACL_DIR, 'build', 'nacl_core_sdk.gyp')
+ all_gyp = join(NACL_DIR, 'build', 'all.gyp')
+ breakpad_gyp = join(SRC_DIR, 'breakpad', 'breakpad.gyp')
+ ppapi_gyp = join(SRC_DIR, 'ppapi', 'native_client', 'native_client.gyp')
+ breakpad_targets = ['dump_syms', 'minidump_dump', 'minidump_stackwalk']
+
+ # Build
+ tmpdir_obj = TempDir('nacl_core_sdk_', dont_remove=True).Create()
+ tmpdir = tmpdir_obj.name
+ GypNinjaBuild('ia32', gyp_nacl, nacl_core_sdk_gyp, 'nacl_core_sdk', tmpdir)
+ GypNinjaBuild('ia32', gyp_nacl, all_gyp, 'ncval_new', tmpdir)
+ GypNinjaBuild('ia32', gyp_chromium, breakpad_gyp, breakpad_targets, tmpdir)
+ GypNinjaBuild('ia32', gyp_chromium, ppapi_gyp, 'ppapi_lib', tmpdir)
+ GypNinjaBuild('x64', gyp_chromium, ppapi_gyp, 'ppapi_lib', tmpdir)
+
+ tmpdir64_obj = TempDir('nacl_core_sdk_64_', dont_remove=True).Create()
+ tmpdir_64 = tmpdir64_obj.name
+ if PLATFORM == 'win':
+ GypNinjaBuild('ia32', gyp_nacl, nacl_core_sdk_gyp, 'sel_ldr64', tmpdir_64)
+ else:
+ GypNinjaBuild('x64', gyp_nacl, nacl_core_sdk_gyp, 'sel_ldr', tmpdir_64)
+
+ tmpdirarm_obj = TempDir('nacl_core_sdk_arm_', dont_remove=True).Create()
+ tmpdir_arm = tmpdirarm_obj.name
+ GypNinjaBuild('arm', gyp_nacl, nacl_core_sdk_gyp, 'nacl_core_sdk', tmpdir_arm)
+ GypNinjaBuild('arm', gyp_chromium, ppapi_gyp, 'ppapi_lib', tmpdir_arm)
+
+ # Tools archive
+ archive = Archive('tools')
+ archive.Copy(join(tmpdir, 'Release'), GetToolsFiles())
+ archive.Copy(join(tmpdir_64, 'Release'), GetTools64Files())
+ if PLATFORM == 'linux':
+ archive.Copy(join(tmpdir_arm, 'Release'), GetToolsArmFiles())
+ # TODO(binji): dump_syms doesn't currently build on Windows. See
+ # http://crbug.com/245456
+ if PLATFORM != 'win':
+ archive.Copy(join(tmpdir, 'Release'), breakpad_targets)
+ archive.Tar()
+
+ # newlib x86 libs archives
+ for arch in ('x86_32', 'x86_64'):
+ archive = Archive('newlib_%s_libs' % arch)
+ archive.Copy(GetGypBuiltLib(tmpdir, 'newlib', arch),
+ GetNewlibToolchainLibs())
+ archive.Copy(GetGypToolchainLib(tmpdir, 'newlib', arch), 'crt1.o')
+ archive.Tar()
+
+ # newlib arm libs archive
+ archive = Archive('newlib_arm_libs')
+ archive.Copy(GetGypBuiltLib(tmpdir_arm, 'newlib', 'arm'),
+ GetNewlibToolchainLibs())
+ archive.Copy(GetGypToolchainLib(tmpdir_arm, 'newlib', 'arm'), 'crt1.o')
+ archive.Tar()
+
+ # glibc x86 libs archives
+ for arch in ('x86_32', 'x86_64'):
+ archive = Archive('glibc_%s_libs' % arch)
+ archive.Copy(GetGypBuiltLib(tmpdir, 'glibc', arch), GetGlibcToolchainLibs())
+ archive.Copy(GetGypToolchainLib(tmpdir, 'glibc', arch), 'crt1.o')
+ archive.Tar()
+
+ # pnacl libs archive
+ archive = Archive('pnacl_libs')
+ archive.Copy(GetGypBuiltLib(tmpdir, 'pnacl'), GetPNaClToolchainLibs())
+ archive.Tar()
+
+ if PLATFORM == 'linux':
+ # bionic arm libs archive (use newlib-built files)
+ archive = Archive('bionic_arm_libs')
+ archive.Copy(GetGypBuiltLib(tmpdir_arm, 'newlib', 'arm'),
+ GetBionicToolchainLibs())
+ archive.Copy(GetGypToolchainLib(tmpdir_arm, 'newlib', 'arm'), 'crt1.o')
+ archive.Tar()
+
+ # Destroy the temporary directories
+ tmpdir_obj.Destroy()
+ tmpdirarm_obj.Destroy()
+ tmpdir64_obj.Destroy()
+
+
+def MakePNaClArchives():
+ join = os.path.join
+ gyp_chromium = join(SRC_DIR, 'build', 'gyp_chromium')
+ pnacl_irt_shim_gyp = join(SRC_DIR, 'ppapi', 'native_client', 'src',
+ 'untrusted', 'pnacl_irt_shim', 'pnacl_irt_shim.gyp')
+
+ with TempDir('pnacl_irt_shim_ia32_') as tmpdir:
+ GypNinjaBuild('ia32', gyp_chromium, pnacl_irt_shim_gyp, 'aot', tmpdir)
+
+ archive = Archive('pnacl_translator_x86_32_libs')
+ libdir = join(tmpdir, 'Release', 'gen', 'tc_pnacl_translate', 'lib-x86-32')
+ archive.Copy(libdir, 'libpnacl_irt_shim.a')
+ archive.Tar()
+
+ archive = Archive('pnacl_translator_x86_64_libs')
+ libdir = join(tmpdir, 'Release', 'gen', 'tc_pnacl_translate', 'lib-x86-32')
+ archive.Copy(libdir, 'libpnacl_irt_shim.a')
+ archive.Tar()
+
+ with TempDir('pnacl_irt_shim_arm_') as tmpdir:
+ GypNinjaBuild('arm', gyp_chromium, pnacl_irt_shim_gyp, 'aot', tmpdir)
+
+ archive = Archive('pnacl_translator_arm_libs')
+ libdir = join(tmpdir, 'Release', 'gen', 'tc_pnacl_translate', 'lib-arm')
+ archive.Copy(libdir, 'libpnacl_irt_shim.a')
+ archive.Tar()
+
+
+def GetNewlibHeaders():
+ return [
+ ('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', '')]
+
+
+def GetGlibcHeaders():
+ return [
+ ('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', '')]
+
+
+def GetBionicHeaders():
+ return [('ppapi/nacl_irt/public/irt_ppapi.h', '')]
+
+
+def MakeToolchainHeaderArchives():
+ archive = Archive('newlib_headers')
+ archive.Copy(SRC_DIR, GetNewlibHeaders())
+ archive.Tar()
+
+ archive = Archive('glibc_headers')
+ archive.Copy(SRC_DIR, GetGlibcHeaders())
+ archive.Tar()
+
+ if PLATFORM == 'linux':
+ archive = Archive('bionic_headers')
+ archive.Copy(SRC_DIR, GetBionicHeaders())
+ archive.Tar()
+
+
+def MakePepperArchive():
+ archive = Archive('ppapi')
+ archive.Copy(os.path.join(SRC_DIR, 'ppapi'), ['c', 'cpp', 'lib', 'utility'])
+ archive.Tar()
+
+
+def UploadArchives():
+ major_version = build_version.ChromeMajorVersion()
+ chrome_revision = build_version.ChromeRevision()
+ commit_position = build_version.ChromeCommitPosition()
+ git_sha = build_version.ParseCommitPosition(commit_position)[0]
+ short_sha = git_sha[:9]
+ archive_version = '%s-%s-%s' % (major_version, chrome_revision, short_sha)
+ bucket_path = 'native-client-sdk/archives/%s' % archive_version
+ for archive_name in all_archives:
+ buildbot_common.Archive(archive_name, bucket_path,
+ cwd=BUILD_ARCHIVE_DIR, step_link=False)
+ sha1_filename = archive_name + '.sha1'
+ buildbot_common.Archive(sha1_filename, bucket_path,
+ cwd=BUILD_ARCHIVE_DIR, step_link=False)
+
+
+def MakeVersionJson():
+ time_format = '%Y/%m/%d %H:%M:%S'
+ data = {
+ 'chrome_version': build_version.ChromeVersionNoTrunk(),
+ 'chrome_revision': build_version.ChromeRevision(),
+ 'chrome_commit_position': build_version.ChromeCommitPosition(),
+ 'nacl_revision': build_version.NaClRevision(),
+ 'build_date': datetime.datetime.now().strftime(time_format)}
+
+ dirname = os.path.dirname(VERSION_JSON)
+ if not os.path.exists(dirname):
+ buildbot_common.MakeDir(dirname)
+ with open(VERSION_JSON, 'w') as outf:
+ json.dump(data, outf, indent=2, separators=(',', ': '))
+
+
+def main(args):
+ parser = argparse.ArgumentParser(description=__doc__)
+ parser.add_argument('--mac-sdk',
+ help='Set the mac-sdk (e.g. 10.6) to use when building with ninja.')
+ parser.add_argument('--no-arm-trusted', action='store_true',
+ help='Disable building of ARM trusted components (sel_ldr, etc).')
+ parser.add_argument('--upload', action='store_true',
+ help='Upload tarballs to GCS.')
+
+ global options
+ options = parser.parse_args(args)
+
+ toolchains = ['pnacl', 'newlib', 'glibc', 'arm']
+ if PLATFORM == 'linux':
+ toolchains.append('bionic')
+
+ MakeVersionJson()
+ for tc in toolchains:
+ MakeToolchainArchive(tc)
+ MakeGypArchives()
+ MakePNaClArchives()
+ MakeToolchainHeaderArchives()
+ MakePepperArchive()
+ if options.upload:
+ UploadArchives()
+
+ return 0
+
+if __name__ == '__main__':
+ try:
+ sys.exit(main(sys.argv[1:]))
+ except KeyboardInterrupt:
+ buildbot_common.ErrorExit('build_artifacts: interrupted')
diff --git a/native_client_sdk/src/build_tools/build_paths.py b/native_client_sdk/src/build_tools/build_paths.py
index f5a0663..f24070b 100644
--- a/native_client_sdk/src/build_tools/build_paths.py
+++ b/native_client_sdk/src/build_tools/build_paths.py
@@ -14,6 +14,7 @@ SDK_DIR = os.path.dirname(SDK_SRC_DIR)
SRC_DIR = os.path.dirname(SDK_DIR)
NACL_DIR = os.path.join(SRC_DIR, 'native_client')
OUT_DIR = os.path.join(SRC_DIR, 'out')
+BUILD_ARCHIVE_DIR = os.path.join(OUT_DIR, 'nacl_sdk_build')
PPAPI_DIR = os.path.join(SRC_DIR, 'ppapi')
NACLPORTS_DIR = os.path.join(OUT_DIR, 'naclports')
GONACL_APPENGINE_DIR = os.path.join(SDK_SRC_DIR, 'gonacl_appengine')
diff --git a/native_client_sdk/src/build_tools/tests/build_artifacts_test.py b/native_client_sdk/src/build_tools/tests/build_artifacts_test.py
new file mode 100755
index 0000000..2666fab
--- /dev/null
+++ b/native_client_sdk/src/build_tools/tests/build_artifacts_test.py
@@ -0,0 +1,309 @@
+#!/usr/bin/env python
+# Copyright (c) 2014 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.
+
+import os
+import ntpath
+import posixpath
+import sys
+import collections
+import unittest
+
+SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
+BUILD_TOOLS_DIR = os.path.dirname(SCRIPT_DIR)
+CHROME_SRC = os.path.dirname(os.path.dirname(os.path.dirname(BUILD_TOOLS_DIR)))
+MOCK_DIR = os.path.join(CHROME_SRC, "third_party", "pymock")
+
+# For the mock library
+sys.path.append(MOCK_DIR)
+from mock import call, patch, Mock
+
+sys.path.append(BUILD_TOOLS_DIR)
+import build_artifacts
+
+
+class BasePosixTestCase(unittest.TestCase):
+ def setUp(self):
+ self.addCleanup(patch.stopall)
+ patch('build_artifacts.PLATFORM', 'posix').start()
+ patch('build_artifacts.BUILD_ARCHIVE_DIR', '/archive_dir/').start()
+ patch('os.path.join', posixpath.join).start()
+
+
+class PosixTestCase(BasePosixTestCase):
+ def setUp(self):
+ BasePosixTestCase.setUp(self)
+
+ def testGetToolchainNaClLib(self):
+ tests = [
+ (('newlib', 'x86_32'), 'foo/x86_64-nacl/lib32'),
+ (('newlib', 'x86_64'), 'foo/x86_64-nacl/lib'),
+ (('newlib', 'arm'), 'foo/arm-nacl/lib'),
+ (('glibc', 'x86_32'), 'foo/x86_64-nacl/lib32'),
+ (('glibc', 'x86_64'), 'foo/x86_64-nacl/lib'),
+ (('bionic', 'arm'), 'foo/arm-nacl/lib'),
+ (('pnacl', None), 'foo/le32-nacl/lib'),
+ ]
+
+ for test in tests:
+ self.assertEqual(
+ build_artifacts.GetToolchainNaClLib(test[0][0], 'foo', test[0][1]),
+ test[1])
+
+ def testGetGypBuiltLib(self):
+ tests = [
+ (('newlib', 'x86_32'), 'foo/Release/gen/tc_newlib/lib32'),
+ (('newlib', 'x86_64'), 'foo/Release/gen/tc_newlib/lib64'),
+ (('newlib', 'arm'), 'foo/Release/gen/tc_newlib/libarm'),
+ (('glibc', 'x86_32'), 'foo/Release/gen/tc_glibc/lib32'),
+ (('glibc', 'x86_64'), 'foo/Release/gen/tc_glibc/lib64'),
+ (('pnacl', None), 'foo/Release/gen/tc_pnacl_newlib/lib')
+ ]
+
+ for test in tests:
+ self.assertEqual(
+ build_artifacts.GetGypBuiltLib('foo', test[0][0], test[0][1]),
+ test[1])
+
+ def testGetGypToolchainLib(self):
+ tests = [
+ (('newlib', 'x86_32'),
+ 'foo/Release/gen/sdk/posix_x86/nacl_x86_newlib/x86_64-nacl/lib32'),
+ (('newlib', 'x86_64'),
+ 'foo/Release/gen/sdk/posix_x86/nacl_x86_newlib/x86_64-nacl/lib'),
+ (('newlib', 'arm'),
+ 'foo/Release/gen/sdk/posix_x86/nacl_arm_newlib/arm-nacl/lib'),
+ (('glibc', 'x86_32'),
+ 'foo/Release/gen/sdk/posix_x86/nacl_x86_glibc/x86_64-nacl/lib32'),
+ (('glibc', 'x86_64'),
+ 'foo/Release/gen/sdk/posix_x86/nacl_x86_glibc/x86_64-nacl/lib'),
+ # Bionic uses the newlib toolchain lib directory
+ (('bionic', 'arm'),
+ 'foo/Release/gen/sdk/posix_x86/nacl_arm_newlib/arm-nacl/lib'),
+ (('pnacl', None),
+ 'foo/Release/gen/sdk/posix_x86/pnacl_newlib/le32-nacl/lib'),
+ ]
+
+ for test in tests:
+ self.assertEqual(
+ build_artifacts.GetGypToolchainLib('foo', test[0][0], test[0][1]),
+ test[1])
+
+ @patch('build_artifacts.all_archives', ['foo.tar.bz2', 'bar.tar.bz2'])
+ @patch('build_version.ChromeMajorVersion', Mock(return_value='40'))
+ @patch('build_version.ChromeRevision', Mock(return_value='302630'))
+ @patch('build_version.ChromeCommitPosition', Mock(return_value=
+ '1492c3d296476fe12cafecabba6ebabe-refs/heads/master@{#302630}'))
+ @patch('buildbot_common.Archive')
+ def testUploadArchives(self, archive_mock):
+ build_artifacts.UploadArchives()
+ cwd = '/archive_dir/'
+ bucket_path = 'native-client-sdk/archives/40-302630-1492c3d29'
+ archive_mock.assert_has_calls([
+ call('foo.tar.bz2', bucket_path, cwd=cwd, step_link=False),
+ call('foo.tar.bz2.sha1', bucket_path, cwd=cwd, step_link=False),
+ call('bar.tar.bz2', bucket_path, cwd=cwd, step_link=False),
+ call('bar.tar.bz2.sha1', bucket_path, cwd=cwd, step_link=False)
+ ])
+
+
+class GypNinjaPosixTestCase(BasePosixTestCase):
+ def setUp(self):
+ BasePosixTestCase.setUp(self)
+ patch('sys.executable', 'python').start()
+ patch('build_artifacts.SRC_DIR', 'src_dir').start()
+ patch('os.environ', {}).start()
+ self.run_mock = patch('buildbot_common.Run').start()
+ self.options_mock = patch('build_artifacts.options').start()
+ self.options_mock.mac_sdk = False
+ self.options_mock.no_arm_trusted = False
+
+ def testSimple(self):
+ build_artifacts.GypNinjaBuild(
+ None, 'gyp.py', 'foo.gyp', 'target', 'out_dir')
+ self.run_mock.assert_has_calls([
+ call(['python', 'gyp.py', 'foo.gyp', '--depth=.', '-G',
+ 'output_dir=out_dir'],
+ cwd='src_dir',
+ env={'GYP_GENERATORS': 'ninja', 'GYP_DEFINES': ''}),
+ call(['ninja', '-C', 'out_dir/Release', 'target'], cwd='src_dir')
+ ])
+
+ def testTargetArch(self):
+ build_artifacts.GypNinjaBuild(
+ 'x64', 'gyp.py', 'foo.gyp', 'target', 'out_dir')
+ self.run_mock.assert_has_calls([
+ call(['python', 'gyp.py', 'foo.gyp', '--depth=.', '-G',
+ 'output_dir=out_dir'],
+ cwd='src_dir',
+ env={
+ 'GYP_GENERATORS': 'ninja',
+ 'GYP_DEFINES': 'target_arch=x64'
+ }),
+ call(['ninja', '-C', 'out_dir/Release', 'target'], cwd='src_dir')
+ ])
+
+ def testMultipleTargets(self):
+ build_artifacts.GypNinjaBuild(
+ None, 'gyp.py', 'foo.gyp', ['target1', 'target2'], 'out_dir')
+ self.run_mock.assert_has_calls([
+ call(['python', 'gyp.py', 'foo.gyp', '--depth=.', '-G',
+ 'output_dir=out_dir'],
+ cwd='src_dir',
+ env={'GYP_GENERATORS': 'ninja', 'GYP_DEFINES': ''}),
+ call(['ninja', '-C', 'out_dir/Release', 'target1', 'target2'],
+ cwd='src_dir')
+ ])
+
+ def testMacSdk(self):
+ build_artifacts.PLATFORM = 'mac'
+ self.options_mock.mac_sdk = '10.6'
+ build_artifacts.GypNinjaBuild(
+ None, 'gyp.py', 'foo.gyp', 'target', 'out_dir')
+ self.run_mock.assert_has_calls([
+ call(['python', 'gyp.py', 'foo.gyp', '--depth=.', '-G',
+ 'output_dir=out_dir'],
+ cwd='src_dir',
+ env={
+ 'GYP_GENERATORS': 'ninja',
+ 'GYP_DEFINES': 'mac_sdk=10.6 clang=1'
+ }),
+ call(['ninja', '-C', 'out_dir/Release', 'target'], cwd='src_dir')
+ ])
+
+ def testArmLinux(self):
+ build_artifacts.PLATFORM = 'linux'
+ build_artifacts.GypNinjaBuild(
+ 'arm', 'gyp.py', 'foo.gyp', 'target', 'out_dir')
+ self.run_mock.assert_has_calls([
+ call(['python', 'gyp.py', 'foo.gyp', '--depth=.', '-G',
+ 'output_dir=out_dir'],
+ cwd='src_dir',
+ env={
+ 'GYP_GENERATORS': 'ninja',
+ 'GYP_DEFINES': 'target_arch=arm armv7=1 arm_thumb=0 arm_neon=1'
+ ' arm_float_abi=hard nacl_enable_arm_gcc=1',
+ 'CC': 'arm-linux-gnueabihf-gcc',
+ 'CXX': 'arm-linux-gnueabihf-g++',
+ 'AR': 'arm-linux-gnueabihf-ar',
+ 'AS': 'arm-linux-gnueabihf-as',
+ 'CC_host': 'cc',
+ 'CXX_host': 'c++',
+ }),
+ call(['ninja', '-C', 'out_dir/Release', 'target'], cwd='src_dir')
+ ])
+
+ def testNoArmTrusted(self):
+ build_artifacts.PLATFORM = 'linux'
+ self.options_mock.no_arm_trusted = True
+ build_artifacts.GypNinjaBuild(
+ 'arm', 'gyp.py', 'foo.gyp', 'target', 'out_dir')
+ self.run_mock.assert_has_calls([
+ call(['python', 'gyp.py', 'foo.gyp', '--depth=.', '-G',
+ 'output_dir=out_dir'],
+ cwd='src_dir',
+ env={
+ 'GYP_GENERATORS': 'ninja',
+ 'GYP_DEFINES': 'target_arch=arm armv7=1 arm_thumb=0 arm_neon=1'
+ ' arm_float_abi=hard nacl_enable_arm_gcc=1'
+ ' disable_cross_trusted=1',
+ 'CC': 'arm-linux-gnueabihf-gcc',
+ 'CXX': 'arm-linux-gnueabihf-g++',
+ 'AR': 'arm-linux-gnueabihf-ar',
+ 'AS': 'arm-linux-gnueabihf-as',
+ 'CC_host': 'cc',
+ 'CXX_host': 'c++',
+ }),
+ call(['ninja', '-C', 'out_dir/Release', 'target'], cwd='src_dir')
+ ])
+
+
+class ArchivePosixTestCase(BasePosixTestCase):
+ def setUp(self):
+ BasePosixTestCase.setUp(self)
+ self.makedir_mock = patch('buildbot_common.MakeDir').start()
+ self.copyfile_mock = patch('buildbot_common.CopyFile').start()
+ self.copydir_mock = patch('buildbot_common.CopyDir').start()
+ self.isdir_mock = patch('os.path.isdir').start()
+ patch('os.path.exists', Mock(return_value=False)).start()
+
+ def dummy_isdir(path):
+ if path == '/archive_dir/posix_foo':
+ return True
+ return False
+ self.isdir_mock.side_effect = dummy_isdir
+
+ self.archive = build_artifacts.Archive('foo')
+
+ def testInit(self):
+ self.assertEqual(self.archive.name, 'posix_foo')
+ self.assertEqual(self.archive.archive_name, 'posix_foo.tar.bz2')
+ self.assertEqual(self.archive.archive_path,
+ '/archive_dir/posix_foo.tar.bz2')
+ self.assertEqual(self.archive.dirname, '/archive_dir/posix_foo')
+ self.makedir_mock.assert_called_once_with('/archive_dir/posix_foo')
+
+ @patch('glob.glob', Mock(side_effect=lambda x: [x]))
+ def testCopySimple(self):
+ self.archive.Copy('/copy_from', ['file1', 'file2'])
+ self.assertEqual(self.copydir_mock.call_count, 0)
+ self.copyfile_mock.assert_has_calls([
+ call('/copy_from/file1', '/archive_dir/posix_foo/file1'),
+ call('/copy_from/file2', '/archive_dir/posix_foo/file2')])
+
+ @patch('glob.glob')
+ def testCopyGlob(self, glob_mock):
+ glob_mock.return_value = ['/copy_from/foo', '/copy_from/bar']
+ self.archive.Copy('/copy_from', [('*', '')])
+ glob_mock.assert_called_once_with('/copy_from/*')
+ self.assertEqual(self.copydir_mock.call_count, 0)
+ self.copyfile_mock.assert_has_calls([
+ call('/copy_from/foo', '/archive_dir/posix_foo/'),
+ call('/copy_from/bar', '/archive_dir/posix_foo/')])
+
+ @patch('glob.glob', Mock(side_effect=lambda x: [x]))
+ def testCopyRename(self):
+ self.archive.Copy('/copy_from', [('file1', 'file1_renamed')])
+ self.assertEqual(self.copydir_mock.call_count, 0)
+ self.copyfile_mock.assert_called_once_with(
+ '/copy_from/file1', '/archive_dir/posix_foo/file1_renamed')
+
+ @patch('glob.glob', Mock(side_effect=lambda x: [x]))
+ def testCopyNewDir(self):
+ self.archive.Copy('/copy_from', [('file1', 'todir/')])
+ self.assertEqual(self.copydir_mock.call_count, 0)
+ self.copyfile_mock.assert_called_once_with(
+ '/copy_from/file1', '/archive_dir/posix_foo/todir/file1')
+
+ @patch('glob.glob', Mock(side_effect=lambda x: [x]))
+ def testCopyDir(self):
+ self.isdir_mock.side_effect = lambda _: True
+ self.archive.Copy('/copy_from', ['dirname'])
+ self.assertEqual(self.copyfile_mock.call_count, 0)
+ self.copydir_mock.assert_called_once_with(
+ '/copy_from/dirname', '/archive_dir/posix_foo/dirname')
+
+
+class WinTestCase(unittest.TestCase):
+ def setUp(self):
+ patch('build_artifacts.PLATFORM', 'win').start()
+ patch('build_artifacts.BUILD_ARCHIVE_DIR', 'c:\\archive_dir\\').start()
+ patch('os.path.join', ntpath.join).start()
+
+ def tearDown(self):
+ patch.stopall()
+
+ @patch('os.path.exists', Mock(return_value=False))
+ @patch('buildbot_common.MakeDir')
+ def testArchiveInit(self, makedir_mock):
+ archive = build_artifacts.Archive('foo')
+ self.assertEqual(archive.name, 'win_foo')
+ self.assertEqual(archive.archive_name, 'win_foo.tar.bz2')
+ self.assertEqual(archive.archive_path, r'c:\archive_dir\win_foo.tar.bz2')
+ self.assertEqual(archive.dirname, r'c:\archive_dir\win_foo')
+ makedir_mock.assert_called_once_with(r'c:\archive_dir\win_foo')
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/native_client_sdk/src/test_all.py b/native_client_sdk/src/test_all.py
index 6f2113a..4a451f4 100755
--- a/native_client_sdk/src/test_all.py
+++ b/native_client_sdk/src/test_all.py
@@ -30,6 +30,7 @@ EXTRACT_PACKAGES = ['nacl_x86_glibc']
TOOLCHAIN_OUT = os.path.join(build_paths.OUT_DIR, 'sdk_tests', 'toolchain')
TEST_MODULES = [
+ 'build_artifacts_test',
'build_version_test',
'create_html_test',
'create_nmf_test',