#!/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. """Build NaCl tools (e.g. sel_ldr and ncval) at a given revision.""" import build_utils import optparse import os import shutil import subprocess import sys import tempfile bot = build_utils.BotAnnotator() # The suffix used for NaCl moduels that are installed, such as irt_core. NEXE_SUFFIX = '.nexe' def MakeInstallDirs(options): '''Create the necessary install directories in the SDK staging area. ''' install_dir = os.path.join(options.toolchain, 'bin'); if not os.path.exists(install_dir): os.makedirs(install_dir) runtime_dir = os.path.join(options.toolchain, 'runtime'); if not os.path.exists(runtime_dir): os.makedirs(runtime_dir) def Build(options): '''Build 32-bit and 64-bit versions of needed NaCL tools and libs.''' nacl_dir = os.path.join(options.nacl_dir, 'native_client') toolchain_option = 'naclsdk_mode=custom:%s' % options.toolchain libc_option = '' if options.lib == 'newlib' else ' --nacl_glibc' if sys.platform == 'win32': scons = os.path.join(nacl_dir, 'scons.bat') bits32 = 'vcvarsall.bat x86 && ' bits64 = 'vcvarsall.bat x86_amd64 && ' else: scons = os.path.join(nacl_dir, 'scons') bits32 = '' bits64 = '' # Build sel_ldr and ncval. def BuildTools(prefix, bits, target): cmd = '%s%s -j %s --mode=%s platform=x86-%s naclsdk_validate=0 %s %s%s' % ( prefix, scons, options.jobs, options.variant, bits, target, toolchain_option, libc_option) bot.Run(cmd, shell=True, cwd=nacl_dir) BuildTools(bits32, '32', 'sdl=none sel_ldr ncval') BuildTools(bits64, '64', 'sdl=none sel_ldr ncval') # Build irt_core, which is needed for running .nexes with sel_ldr. def BuildIRT(bits): cmd = '%s -j %s irt_core --mode=opt-host,nacl platform=x86-%s %s' % ( scons, options.jobs, bits, toolchain_option) bot.Run(cmd, shell=True, cwd=nacl_dir) # only build the IRT using the newlib chain. glibc does not support IRT. if options.lib == 'newlib': BuildIRT(32) BuildIRT(64) # Build and install untrusted libraries. def BuildAndInstallLibsAndHeaders(bits): cmd = ('%s install --mode=opt-host,nacl libdir=%s includedir=%s ' 'platform=x86-%s force_sel_ldr=none %s%s') % ( scons, os.path.join(options.toolchain, 'x86_64-nacl', 'lib32' if bits == 32 else 'lib'), os.path.join(options.toolchain, 'x86_64-nacl', 'include'), bits, toolchain_option, libc_option) bot.Run(cmd, shell=True, cwd=nacl_dir) BuildAndInstallLibsAndHeaders(32) BuildAndInstallLibsAndHeaders(64) def Install(options, tools=[], runtimes=[]): '''Install the NaCl tools and runtimes into the SDK staging area. Assumes that all necessary artifacts are built into the NaCl scons-out/staging directory, and copies them from there into the SDK staging area under toolchain. Args: options: The build options object. This is populated from command-line args at start-up. tools: A list of tool names, these should *not* have any executable suffix - this utility adds that (e.g. '.exe' on Windows). runtimes: A list of IRT runtimes. These artifacts should *not* have any suffix attached - this utility adds the '.nexe' suffix along with an ISA-specific string (e.g. '_x86_32'). ''' # TODO(bradnelson): add an 'install' alias to the main build for this. nacl_dir = os.path.join(options.nacl_dir, 'native_client') tool_build_path_32 = os.path.join(nacl_dir, 'scons-out', '%s-x86-32' % (options.variant), 'staging') tool_build_path_64 = os.path.join(nacl_dir, 'scons-out', '%s-x86-64' % (options.variant), 'staging') for nacl_tool in tools: shutil.copy(os.path.join(tool_build_path_32, '%s%s' % (nacl_tool, options.exe_suffix)), os.path.join(options.toolchain, 'bin', '%s_x86_32%s' % (nacl_tool, options.exe_suffix))) shutil.copy(os.path.join(tool_build_path_64, '%s%s' % (nacl_tool, options.exe_suffix)), os.path.join(options.toolchain, 'bin', '%s_x86_64%s' % (nacl_tool, options.exe_suffix))) irt_build_path_32 = os.path.join(nacl_dir, 'scons-out', 'nacl_irt-x86-32', 'staging') irt_build_path_64 = os.path.join(nacl_dir, 'scons-out', 'nacl_irt-x86-64', 'staging') for nacl_irt in runtimes: shutil.copy(os.path.join(irt_build_path_32, '%s%s' % (nacl_irt, NEXE_SUFFIX)), os.path.join(options.toolchain, 'runtime', '%s_x86_32%s' % (nacl_irt, NEXE_SUFFIX))) shutil.copy(os.path.join(irt_build_path_64, '%s%s' % (nacl_irt, NEXE_SUFFIX)), os.path.join(options.toolchain, 'runtime', '%s_x86_64%s' % (nacl_irt, NEXE_SUFFIX))) def BuildNaClTools(options): if(options.clean): bot.Print('Removing scons-out') scons_out = os.path.join(options.nacl_dir, 'native_client', 'scons-out') build_utils.CleanDirectory(scons_out) else: MakeInstallDirs(options) Build(options) Install(options, tools=['sel_ldr', 'ncval'], runtimes=['irt_core']) return 0 def main(argv): if sys.platform in ['win32', 'cygwin']: exe_suffix = '.exe' else: exe_suffix = '' script_dir = os.path.abspath(os.path.dirname(__file__)) parser = optparse.OptionParser() parser.add_option( '-t', '--toolchain', dest='toolchain', default='toolchain', help='where to put the NaCl tool binaries') parser.add_option( '-l', '--lib', dest='lib', default='newlib', help='whether to build against newlib (default) or glibc') parser.add_option( '-c', '--clean', action='store_true', dest='clean', default=False, help='whether to clean up the checkout files') parser.add_option( '-j', '--jobs', dest='jobs', default='1', help='Number of parallel jobs to use while building nacl tools') parser.add_option( '-n', '--nacl_dir', dest='nacl_dir', default=os.path.join(script_dir, 'packages', 'native_client'), help='Location of Native Client repository used for building tools') (options, args) = parser.parse_args(argv) if args: parser.print_help() bot.Print('ERROR: invalid argument(s): %s' % args) return 1 options.toolchain = os.path.abspath(options.toolchain) options.exe_suffix = exe_suffix # Pick variant. if sys.platform in ['win32', 'cygwin']: variant = 'dbg-win' elif sys.platform == 'darwin': variant = 'dbg-mac' elif sys.platform in ['linux', 'linux2']: variant = 'dbg-linux' else: assert False options.variant = variant if options.lib not in ['newlib', 'glibc']: bot.Print('ERROR: --lib must either be newlib or glibc') return 1 return BuildNaClTools(options) if __name__ == '__main__': sys.exit(main(sys.argv[1:]))