| # 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. |
| |
| import os |
| import subprocess |
| import sys |
| |
| import build_common |
| from build_options import OPTIONS |
| from util import platform_util |
| |
| # Paths for various tools, libs, and sdks. |
| _SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) |
| _PEPPER_VERSION = 'pepper_canary' |
| _CANNED_QEMU_ARM = 'canned/host/bin/linux-x86_64/qemu-arm' |
| _DEXMAKER_PATH = os.path.join('third_party', 'android', 'external', 'dexmaker') |
| _NACL_DEPS_PATH = os.path.join(_SCRIPT_DIR, 'DEPS.naclsdk') |
| _NACL_SDK_PATH = os.path.join('third_party', 'nacl_sdk', _PEPPER_VERSION) |
| _NACL_TOOLS_PATH = os.path.join(_NACL_SDK_PATH, 'tools') |
| _PNACL_BIN_PATH = os.path.join(_NACL_SDK_PATH, 'toolchain/linux_pnacl/bin') |
| # TODO(crbug.com/247242): support --naclsdktype={debug,release} |
| _NACL_SDK_RELEASE = 'Release' # alternative: Debug |
| _QEMU_ARM_LD_PATH = '/usr/arm-linux-gnueabihf' |
| _CHROMEOS_USR_LOCAL_DIR = '/usr/local' |
| _CLANG_DIR = 'third_party/android/prebuilts/clang/linux-x86/host/3.5' |
| _CLANG_BIN_DIR = os.path.join(_CLANG_DIR, 'bin') |
| _CLANG_INCLUDE_DIR = os.path.join(_CLANG_DIR, 'lib', 'clang', '3.5', 'include') |
| |
| # Used in get_gcc_raw_version(). |
| _GCC_RAW_VERSION_CACHE = {} |
| |
| # The pinned version of the Android SDK's build tools is used for ARC build. |
| _ANDROID_SDK_BUILD_TOOLS_PINNED_VERSION = '19.1.0' |
| |
| |
| def _get_android_build_tools_dir(): |
| return os.path.join('third_party', 'android', 'build', 'tools') |
| |
| |
| def get_android_api_level(): |
| """Returns the pinned version of the Android API.""" |
| return _ANDROID_SDK_BUILD_TOOLS_PINNED_VERSION.split('.')[0] |
| |
| |
| def get_android_sdk_build_tools_pinned_version(): |
| """Returns the pinned version of the Android SDK's build tools.""" |
| return _ANDROID_SDK_BUILD_TOOLS_PINNED_VERSION |
| |
| |
| def get_android_sdk_build_tools_dir(): |
| return os.path.join('third_party', 'android-sdk', 'build-tools', |
| get_android_sdk_build_tools_pinned_version()) |
| |
| |
| def get_clang_include_dir(): |
| return _CLANG_INCLUDE_DIR |
| |
| |
| def get_chromeos_arc_root_with_exec(*subdirs): |
| """Returns a directory whose filesystem is mounted without noexec. |
| |
| Chrome OS mounts most filesystems with noexec mount option, which prevents |
| executable files from being executed directly. In order to run executable |
| files for testing, we need to copy the files to a directory whose filesystem |
| is mounted without noexec. This function returns /usr/local/arc as one of |
| such directories. |subdirs| is joined to this path. |
| """ |
| return os.path.join(_CHROMEOS_USR_LOCAL_DIR, 'arc', *subdirs) |
| |
| |
| def get_adb_path_for_chromeos(): |
| """Returns the directory that contains the adb executable for Chrome OS.""" |
| |
| if platform_util.is_running_on_chromeos(): |
| # The adb binary is copied to a directory whose filesystem is mounted |
| # without noexec mount options on Chrome OS. |
| root = get_chromeos_arc_root_with_exec() |
| else: |
| root = build_common.get_arc_root() |
| |
| # Chrome OS based on linux-i686 is not supported. |
| target = 'linux-arm' if OPTIONS.is_arm() else 'linux-x86_64' |
| return os.path.join(root, 'out/adb', target, 'adb') |
| |
| |
| def _get_adb_path_for_localhost(): |
| root = os.path.join(build_common.get_arc_root(), 'out/adb') |
| if platform_util.is_running_on_mac(): |
| return os.path.join(root, 'mac-x86_64/adb') |
| elif platform_util.is_running_on_cygwin(): |
| return os.path.join(root, 'win-x86_64/adb.exe') |
| elif platform_util.is_running_on_chromeos(): |
| return get_adb_path_for_chromeos() |
| else: |
| # For Linux desktop. |
| return 'third_party/android-sdk/platform-tools/adb' |
| |
| |
| def get_nacl_sdk_path(): |
| return _NACL_SDK_PATH |
| |
| |
| def get_nacl_toolchain_root(): |
| return os.path.join(_NACL_SDK_PATH, 'toolchain/linux_x86_glibc') |
| |
| |
| def get_nacl_toolchain_libs_path(bitsize): |
| return os.path.join(get_nacl_toolchain_root(), 'x86_64-nacl/lib%d' % bitsize) |
| |
| |
| def get_nacl_toolchain_path(): |
| return os.path.join(get_nacl_toolchain_root(), 'bin') |
| |
| |
| def get_nacl_tool(tool): |
| return os.path.join(_NACL_TOOLS_PATH, tool) |
| |
| |
| def get_nacl_irt_core(bitsize): |
| return get_nacl_tool('irt_core_x86_%d.nexe' % bitsize) |
| |
| |
| def get_nacl_runner(bitsize, bin_dir=None, |
| extra_library_paths=None, extra_envs=None): |
| extra_library_paths = extra_library_paths or [] |
| extra_envs = extra_envs or {} |
| # We use the NACL_IRT_DEV_FILENAME interface for unit tests. |
| args = ['env', 'NACL_DANGEROUS_ENABLE_FILE_ACCESS=1'] |
| |
| arch = 'x86_%d' % bitsize |
| sel_ldr = get_nacl_tool('sel_ldr_%s' % arch) |
| irt_core = get_nacl_irt_core(bitsize) |
| if bin_dir: |
| sel_ldr = os.path.join(bin_dir, sel_ldr) |
| irt_core = os.path.join(bin_dir, irt_core) |
| args.extend([sel_ldr, '-a', '-B', irt_core]) |
| library_path = build_common.get_load_library_path() |
| if bin_dir: |
| library_path = os.path.join(bin_dir, library_path) |
| args.extend(['-E', 'LD_LIBRARY_PATH=' + |
| ':'.join([library_path] + extra_library_paths)]) |
| for key, value in extra_envs.iteritems(): |
| args.extend(['-E', '%s=%s' % (key, value)]) |
| args.append('%s/runnable-ld.so' % library_path) |
| return args |
| |
| |
| def get_bare_metal_runner(use_qemu_arm=False, bin_dir=None, |
| extra_library_paths=None, extra_envs=None): |
| extra_library_paths = extra_library_paths or [] |
| extra_envs = extra_envs or {} |
| args = [] |
| if use_qemu_arm: |
| args.extend(get_qemu_arm_args()) |
| loader = build_common.get_bare_metal_loader() |
| load_library_path = build_common.get_load_library_path() |
| if bin_dir: |
| load_library_path = os.path.join(bin_dir, load_library_path) |
| loader = os.path.join(bin_dir, loader) |
| args.append(loader) |
| args.extend(['-E', 'LD_LIBRARY_PATH=' + |
| ':'.join([load_library_path] + extra_library_paths)]) |
| for key, value in extra_envs.iteritems(): |
| args.extend(['-E', '%s=%s' % (key, value)]) |
| args.append(os.path.join(load_library_path, 'runnable-ld.so')) |
| return args |
| |
| |
| def get_target_runner(bin_dir=None, extra_library_paths=None, extra_envs=None): |
| if OPTIONS.is_bare_metal_build(): |
| return get_bare_metal_runner(bin_dir=bin_dir, |
| extra_library_paths=extra_library_paths, |
| extra_envs=extra_envs) |
| else: |
| return get_nacl_runner(OPTIONS.get_target_bitsize(), bin_dir=bin_dir, |
| extra_library_paths=extra_library_paths, |
| extra_envs=extra_envs) |
| |
| |
| def get_qemu_arm_args(): |
| return [_CANNED_QEMU_ARM, '-L', _QEMU_ARM_LD_PATH] |
| |
| |
| def _get_create_nmf_script(): |
| return 'src/packaging/create_nmf.py' |
| |
| |
| def _get_create_nmf(): |
| return ' '.join([ |
| # These environ variables are needed for our fork of create_nmf.py. |
| 'PYTHONPATH=third_party/chromium-ppapi/native_client_sdk/src/tools', |
| 'NACL_SDK_ROOT=third_party/nacl_sdk/pepper_canary', |
| sys.executable, |
| _get_create_nmf_script()]) |
| |
| |
| def get_create_nmf_dependencies(): |
| deps = [_get_create_nmf_script(), 'src/packaging/lib/quote.py'] |
| objdump = get_tool(OPTIONS.target(), 'objdump') |
| if objdump.startswith(get_nacl_toolchain_path()): |
| deps.append(objdump) |
| return deps |
| |
| |
| def _get_native_runner(target): |
| if target == 'host' or target == 'java': |
| return '' |
| return 'env LD_LIBRARY_PATH=' + build_common.get_load_library_path(target) |
| |
| |
| def _get_valgrind_runner(target): |
| valgrind_lib_path = 'third_party/valgrind/linux_x64/lib/valgrind' |
| valgrind_env = ('env VALGRIND_LIB=%s VALGRIND_LIB_INNER=%s' % |
| (valgrind_lib_path, valgrind_lib_path)) |
| valgrind_path = 'third_party/valgrind/linux_x64/bin/valgrind' |
| valgrind_options = [ |
| '--error-exitcode=1', '--num-callers=50', '--gen-suppressions=all', |
| '--trace-children=yes', '--trace-children-skip=env', '--leak-check=full', |
| '--suppressions=src/build/valgrind/memcheck/suppressions.txt'] |
| if target.startswith('bare_metal_'): |
| runner = ' '.join(get_bare_metal_runner()) |
| else: |
| runner = _get_native_runner(target) |
| return '%s %s %s %s' % ( |
| valgrind_env, valgrind_path, ' '.join(valgrind_options), runner) |
| |
| |
| def _get_java_command(command): |
| # First, look at environment variable. E.g. JAR for jar, JAVAC for javac. |
| env_var = os.getenv(command.upper()) |
| if env_var: |
| return env_var |
| |
| # Then, if java_dir is set, look at its bin/ directory. |
| java_dir = OPTIONS.java_dir() |
| if java_dir: |
| bin_path = os.path.join(java_dir, 'bin', command) |
| if os.path.exists(bin_path): |
| return bin_path |
| return command |
| |
| |
| def _get_tool_map(): |
| android_build_tools_dir = _get_android_build_tools_dir() |
| android_sdk_build_tools_dir = get_android_sdk_build_tools_dir() |
| |
| return { |
| 'host': { |
| 'cxx': os.getenv('HOSTCXX', 'g++'), |
| 'cc': os.getenv('HOSTCC', 'gcc'), |
| 'ld': os.getenv('HOSTLD', 'g++'), |
| 'ar': os.getenv('HOSTAR', 'ar'), |
| 'nm': os.getenv('HOSTNM', 'nm'), |
| 'objcopy': os.getenv('HOSTOBJCOPY', 'objcopy'), |
| 'objdump': os.getenv('HOSTOBJDUMP', 'objdump'), |
| 'addr2line': os.getenv('HOSTADDR2LINE', 'addr2line'), |
| 'strip': os.getenv('HOSTSTRIP', 'strip'), |
| 'runner': _get_native_runner('host'), |
| 'valgrind_runner': _get_valgrind_runner('host'), |
| 'gdb': 'gdb', |
| 'create_nmf': _get_create_nmf(), |
| 'deps': [], |
| 'adb': _get_adb_path_for_localhost(), |
| }, |
| 'nacl_i686': { |
| 'cxx': (os.path.join(get_nacl_toolchain_path(), 'x86_64-nacl-g++') + |
| ' -m32'), |
| 'cc': (os.path.join(get_nacl_toolchain_path(), 'x86_64-nacl-gcc') + |
| ' -m32'), |
| 'ld': os.path.join(get_nacl_toolchain_path(), 'i686-nacl-g++'), |
| 'ar': os.path.join(get_nacl_toolchain_path(), 'i686-nacl-ar'), |
| 'nm': os.path.join(get_nacl_toolchain_path(), 'i686-nacl-nm'), |
| 'objcopy': os.path.join(get_nacl_toolchain_path(), |
| 'i686-nacl-objcopy'), |
| 'objdump': os.path.join(get_nacl_toolchain_path(), |
| 'i686-nacl-objdump'), |
| 'addr2line': os.path.join(get_nacl_toolchain_path(), |
| 'i686-nacl-addr2line'), |
| 'strip': os.path.join(get_nacl_toolchain_path(), 'i686-nacl-strip'), |
| 'runner': ' '.join(get_nacl_runner(32)), |
| # The target does not support Valgrind. Use nacl_runner. |
| 'valgrind_runner': ' '.join(get_nacl_runner(32)), |
| 'ncval': os.path.join(_NACL_TOOLS_PATH, 'ncval'), |
| 'gdb': os.path.join(get_nacl_toolchain_path(), 'i686-nacl-gdb'), |
| 'irt': 'nacl_irt_x86_32.nexe', |
| 'deps': [_NACL_DEPS_PATH], |
| 'llvm_tblgen': build_common.get_build_path_for_executable( |
| 'tblgen', is_host=True), |
| 'clangxx': os.path.join(_PNACL_BIN_PATH, 'i686-nacl-clang++'), |
| 'clang': os.path.join(_PNACL_BIN_PATH, 'i686-nacl-clang'), |
| }, |
| 'nacl_x86_64': { |
| 'cxx': os.path.join(get_nacl_toolchain_path(), 'x86_64-nacl-g++'), |
| 'cc': os.path.join(get_nacl_toolchain_path(), 'x86_64-nacl-gcc'), |
| 'ld': os.path.join(get_nacl_toolchain_path(), 'x86_64-nacl-g++'), |
| 'ar': os.path.join(get_nacl_toolchain_path(), 'x86_64-nacl-ar'), |
| 'nm': os.path.join(get_nacl_toolchain_path(), 'x86_64-nacl-nm'), |
| 'objcopy': os.path.join(get_nacl_toolchain_path(), |
| 'x86_64-nacl-objcopy'), |
| 'objdump': os.path.join(get_nacl_toolchain_path(), |
| 'x86_64-nacl-objdump'), |
| 'addr2line': os.path.join(get_nacl_toolchain_path(), |
| 'x86_64-nacl-addr2line'), |
| 'strip': os.path.join(get_nacl_toolchain_path(), 'x86_64-nacl-strip'), |
| 'runner': ' '.join(get_nacl_runner(64)), |
| # The target does not support Valgrind. Use nacl_runner. |
| 'valgrind_runner': ' '.join(get_nacl_runner(64)), |
| 'ncval': os.path.join(_NACL_TOOLS_PATH, 'ncval'), |
| 'gdb': os.path.join(get_nacl_toolchain_path(), 'x86_64-nacl-gdb'), |
| 'irt': 'nacl_irt_x86_64.nexe', |
| 'deps': [_NACL_DEPS_PATH], |
| 'llvm_tblgen': build_common.get_build_path_for_executable( |
| 'tblgen', is_host=True), |
| 'clangxx': os.path.join(_PNACL_BIN_PATH, 'x86_64-nacl-clang++'), |
| 'clang': os.path.join(_PNACL_BIN_PATH, 'x86_64-nacl-clang'), |
| }, |
| 'bare_metal_i686': { |
| 'cxx': os.getenv('TARGETCXX', 'g++'), |
| 'cc': os.getenv('TARGETCC', 'gcc'), |
| 'clangxx': os.path.join(_CLANG_BIN_DIR, 'clang++'), |
| 'clang': os.path.join(_CLANG_BIN_DIR, 'clang'), |
| 'ld': os.getenv('TARGETLD', 'g++'), |
| 'ar': os.getenv('TARGETAR', 'ar'), |
| 'nm': os.getenv('TARGETNM', 'nm'), |
| 'objcopy': os.getenv('TARGETOBJCOPY', 'objcopy'), |
| 'objdump': os.getenv('TARGETOBJDUMP', 'objdump'), |
| 'addr2line': os.getenv('TARGETADDR2LINE', 'addr2line'), |
| 'strip': os.getenv('TARGETSTRIP', 'strip'), |
| 'runner': ' '.join(get_bare_metal_runner()), |
| 'valgrind_runner': _get_valgrind_runner('bare_metal_i686'), |
| 'gdb': 'gdb', |
| 'deps': [], |
| 'llvm_tblgen': build_common.get_build_path_for_executable( |
| 'tblgen', is_host=True), |
| }, |
| 'bare_metal_arm': { |
| 'cxx': os.getenv('TARGETCXX', ' arm-linux-gnueabihf-g++'), |
| 'cc': os.getenv('TARGETCC', ' arm-linux-gnueabihf-gcc'), |
| 'clangxx': os.path.join(_CLANG_BIN_DIR, 'clang++'), |
| 'clang': os.path.join(_CLANG_BIN_DIR, 'clang'), |
| 'ld': os.getenv('TARGETLD', 'arm-linux-gnueabihf-g++'), |
| 'ar': os.getenv('TARGETAR', 'arm-linux-gnueabihf-ar'), |
| 'nm': os.getenv('TARGETNM', 'arm-linux-gnueabihf-nm'), |
| 'objcopy': os.getenv('TARGETOBJCOPY', 'arm-linux-gnueabihf-objcopy'), |
| 'objdump': os.getenv('TARGETOBJDUMP', 'arm-linux-gnueabihf-objdump'), |
| 'addr2line': os.getenv('TARGETADDR2LINE', |
| 'arm-linux-gnueabihf-addr2line'), |
| 'strip': os.getenv('TARGETSTRIP', 'arm-linux-gnueabihf-strip'), |
| 'runner': ' '.join(get_bare_metal_runner(use_qemu_arm=True)), |
| # We do not support valgrind on Bare Metal ARM. |
| 'valgrind_runner': ' '.join(get_bare_metal_runner(use_qemu_arm=True)), |
| 'gdb': build_common.get_gdb_multiarch_path(), |
| 'deps': [], |
| 'llvm_tblgen': build_common.get_build_path_for_executable( |
| 'tblgen', is_host=True), |
| }, |
| 'java': { |
| 'aapt': os.getenv( |
| 'AAPT', os.path.join(android_sdk_build_tools_dir, 'aapt')), |
| 'aidl': os.path.join(android_sdk_build_tools_dir, 'aidl'), |
| 'dx': os.getenv( |
| 'DX', os.path.join(android_sdk_build_tools_dir, 'dx')), |
| 'deps': [], |
| 'dexopt': build_common.get_build_path_for_executable( |
| 'dexopt', is_host=True), |
| 'dexdump': build_common.get_build_path_for_executable( |
| 'dexdump', is_host=True), |
| 'java-event-log-tags': os.path.join(android_build_tools_dir, |
| 'java-event-log-tags.py'), |
| 'jar': _get_java_command('jar'), |
| 'jarjar': os.getenv('JARJAR', os.path.join( |
| _DEXMAKER_PATH, 'lib', 'jarjar.jar')), |
| 'java': _get_java_command('java'), |
| 'javac': _get_java_command('javac'), |
| 'runner': _get_native_runner('java'), |
| 'zipalign': 'third_party/android-sdk/tools/zipalign', |
| }, |
| } |
| |
| |
| def get_tool(target, tool, with_cc_wrapper=True): |
| if tool == 'asm' or tool == 'asm_with_preprocessing': |
| tool = 'cc' |
| if tool == 'ld_system_library': |
| tool = 'ld' |
| command = _get_tool_map()[target][tool] |
| if (tool in ['cc', 'cxx', 'clang', 'clangxx'] and |
| OPTIONS.cc_wrapper() and with_cc_wrapper): |
| command = OPTIONS.cc_wrapper() + ' ' + command |
| return command |
| |
| |
| def get_gcc_raw_version(target): |
| """Returns the gcc version of as a string like "4.8.2".""" |
| |
| raw_version = _GCC_RAW_VERSION_CACHE.get(target, 0) |
| if raw_version: |
| return raw_version |
| cc = get_tool(target, 'cc', with_cc_wrapper=False) |
| # Should call split() as cc might be prefixed with a wrapper like goma. |
| raw_version = subprocess.check_output(cc.split() + ['-dumpversion']).strip() |
| |
| _GCC_RAW_VERSION_CACHE[target] = raw_version |
| return raw_version |
| |
| |
| def get_gcc_version(target): |
| """Returns the gcc version of as an array of three integers. |
| |
| Array of intgers is used so that two versions can be compared easily. |
| Example: [4, 8, 0] < [4, 10, 0]. The result is cached so gcc is not run |
| multiple times for the same target. |
| """ |
| |
| raw_version = get_gcc_raw_version(target) |
| version = [int(x) for x in raw_version.split('.')] |
| while len(version) < 3: |
| version.append(0) |
| assert len(version) == 3 |
| |
| return version |
| |
| |
| def has_clang(target, is_host=False): |
| if is_host: |
| target = 'host' |
| tools = _get_tool_map()[target] |
| result = 'clang' in tools |
| assert result == ('clangxx' in tools) |
| return result |