blob: 1e7511c2c8f8a1f14405a6ef06484bc1ed441777 [file]
"""Build step class for building x86 cast_shell."""
import logging
import os
import sys
from helpers import branch_utils
from helpers import cast_shell_utils
from helpers import gn_utils
from helpers import ninja_utils
from slave import base_step
from slave.step import gn_check_step
_UNIT_TEST_HELPER_MODULE = 'unit_test.unit_test_helper'
BUILD_SCRIPT_PROJECT = 'chromecast/internal'
BUILD_SCRIPT_REL_PATH = 'build/build_chromecast.py'
CAST_SHELL_EXE = 'cast_shell'
def _InjectPythonPath(path):
if path not in sys.path:
sys.path.append(path)
class NonOtaBuildBaseStep(base_step.BaseStep):
"""Base step for building and running a non-ota build.
This is for any non-ota build that uses the build_chromecast.py build flow
instead of the OTA `make` build flow.
"""
def __init__(self, name, branding, build_type, product, build_flavor,
sanitizer=None, build_args_product=None,
build_args_official=None, **kwargs):
"""Creates a UnittestBaseStep instance.
Args:
name: The name of the step.
branding: Build branding (chromium or chrome).
build_type: Type of system to build for ('x86', 'clang', or 'arm').
product: product to build for (ie. 'chromecast', 'audio').
build_flavor: Flavor of build ('Debug', 'Eng', 'Release').
build_args_official: Whether to do an official build (disables debugging).
sanitizer: Clang saniziter to run with ('asan', 'msan', 'tsan', 'ubsan').
build_args_product: The build/args/product/*.gn product to build for.
build_args_official: Whether the build is an official build. MUST be set
for any build that will ship to users. Disables debugging; do not
set for development builds.
**kwargs: Any additional args to pass to BaseStep.
"""
super().__init__(name=name, **kwargs)
# TODO(b/73231972) remove branding, build_type, product, build_flavor
# after migration to new builds
assert branding in ['chromium', 'chrome', None]
assert build_type in ['x86', 'clang', 'arm', 'arm64', None]
assert product in [
'chromecast', 'audio', 'android', 'atv', 'display', None]
assert build_flavor in ['Debug', 'Eng', 'Release', None]
assert sanitizer in ['asan', 'msan', 'tsan', 'ubsan', None]
assert build_args_product
assert build_args_official is not None
self._branding = branding
self._build_type = build_type
self._product = product
self._build_flavor = build_flavor
self._build_args_official = build_args_official
self._enable_gn_check = gn_utils.is_gn_check_enabled(self.manifest_branch,
product)
self._sanitizer = sanitizer
self._build_args_product = build_args_product
self._build_target = kwargs.get('build_target')
# Re-calculate the out directory. This mimics the calculation done in
# build_chromecast.py because we don't want to just import it and we can't
# refactor it because we have old branches we need to be able to build.
chrome_root = self.get_project_path('chromium/src')
self._outdir = os.path.join(chrome_root, 'out_' + build_args_product)
if self._build_flavor is None:
return
build_out_parts = ['out', build_type, product, 'gn']
if sanitizer:
build_out_parts.append(sanitizer)
self._build_out_dir = os.path.join(chrome_root, '_'.join(build_out_parts))
flavor_part = 'Release' if build_flavor == 'Eng' else build_flavor
self._outdir = os.path.join(self._build_out_dir, flavor_part)
@property
def build_type_dir(self):
# TODO(b/73231972) remove build_type based logic once deprecated
if self._build_type is None:
if '_arm_' in self._build_args_product:
return 'arm'
elif '_arm64_' in self._build_args_product:
return 'arm64'
elif '_x86_' in self._build_args_product:
return 'x86'
return 'clang'
return self._build_type
@property
def build_flavor_dir(self):
# TODO(b/73231972) remove build_flavor based logic once deprecated
# castshell builds had build_flavor == Debug despite non debug suffix
if self._build_flavor is None:
return 'Debug' if ('debug' in self._build_args_product or
'castshell' in self._build_args_product
) else 'Release'
return 'Release' if self._build_flavor == 'Eng' else self._build_flavor
@property
def build_product_dir(self):
# TODO(b/73231972) remove product based logic once deprecated
if self._product is None:
return 'chromecast'
return self._product
def _get_minimum_required_argv_for_outdir(self):
"""Returns the arguments needed to get the outdir from build_chromecast.py.
The chromecast/internal/build/build_chromecast.py script takes many command
line arguments, but only a select few are needed to be able to determine
the out directory that a build will happen in.
This helper method assembles the minimum set of arguments required to
pass to build_chromecast.py to be generate the correct out directory.
Returns:
A list of arguments
"""
# Set up the argv as if running the build_chromecast.py script.
argv = [
'build_chromecast.py',
'--archive_dir', self.get_gcs_dir(),
'--build_args_product', self._build_args_product,
'--build_number', self.build_number,
'--chrome_root', self.get_project_path('chromium/src')]
# TODO(b/73231972) remove unused flags once migrated to new builds
if self._build_flavor:
argv += ['--build_flavor', self._build_flavor]
if self._build_type:
argv += ['--build_type', self._build_type]
if self._branding:
argv += ['--chromecast_branding', self._branding]
if self._product:
argv += ['--product_name', self._product]
if self._sanitizer:
argv += ['--sanitizer', self._sanitizer]
if self._build_target:
argv += ['--build_target', self._build_target]
return argv
def run(self):
raise NotImplementedError
class CastShellStep(NonOtaBuildBaseStep, gn_check_step.GnCheckStepBase):
"""Build step class for building cast_shell."""
def __init__(self, branding, build_type, product, build_flavor,
enable_assistant, sanitizer=None, archive_to_tmp=False,
skip_create_zip=False, strip_binaries=False, **kwargs):
"""Creates a CastShellStep instance.
Args:
branding: Build branding ('chromium' or 'chrome').
build_type: Type of system to build for ('x86', 'clang', or 'arm').
product: product to build for (ie. 'chromecast', 'audio').
build_flavor: Flavor of build ('Debug', 'Eng', 'Release').
enable_assistant: enable Assistant functionality. Audio products only.
sanitizer: Clang saniziter to run with ('asan', 'msan', 'tsan', 'ubsan').
**kwargs: Any additional args to pass to BaseStep.
"""
self._enable_code_coverage = kwargs.pop('code_coverage', False)
gn_check_step.GnCheckStepBase.__init__(self, **kwargs)
NonOtaBuildBaseStep.__init__(self, 'build cast_shell', branding,
build_type, product, build_flavor,
sanitizer=sanitizer, **kwargs)
self._enable_assistant = enable_assistant
self._archive_to_tmp = archive_to_tmp
self._skip_create_zip = skip_create_zip
self._strip_binaries = strip_binaries
self._unit_test_helper = None
@property
def unit_test_helper(self):
"""Use the unit_test_helper module to be consistent with Catabuilder."""
if not self._unit_test_helper:
_InjectPythonPath(self.get_project_path('test'))
self._unit_test_helper = __import__(
_UNIT_TEST_HELPER_MODULE, fromlist=[''])
return self._unit_test_helper
@property
def out_dir(self):
return self._outdir
def BuildCastShell(self):
self.archive_dir = \
self.get_tmp_dir() if self._archive_to_tmp else self.get_gcs_dir()
base_path = self.get_project_path(BUILD_SCRIPT_PROJECT)
build_script = os.path.join(base_path, BUILD_SCRIPT_REL_PATH)
command = ['python3', build_script,
'--archive_dir', self.archive_dir,
'--build_args_product', self._build_args_product,
'--build_number', self.build_number,
'--chrome_root', self.get_project_path('chromium/src')]
command += self.build_accelerator.build_chromecast_flags
# TODO(b/73231972) remove unused flags once migrated to new builds
if self._build_flavor:
command += ['--build_flavor', self._build_flavor]
if self._build_type:
command += ['--build_type', self._build_type]
if self._branding:
command += ['--chromecast_branding', self._branding]
if self._product:
command += ['--product_name', self._product]
if self._build_args_official:
command += ['--official']
if self._enable_assistant:
command += ['--enable_assistant']
if self._enable_gn_check:
command += ['--enable_gn_check']
if self._sanitizer:
command += ['--sanitizer', self._sanitizer]
if self._build_target:
command += ['--build_target', self._build_target]
if self._enable_code_coverage:
command += ['--enable_code_coverage']
if self._skip_create_zip:
command += ['--skip_create_zip']
returncode, stdout, _ = self.exec_subprocess(command)
if returncode != 0:
comments = ninja_utils.ninja_failure_to_comments(stdout, max_errors=3)
for comment in comments:
self.add_review({'message': comment})
if self._enable_gn_check:
self.gn_check_to_review(stdout)
return returncode
def StripBinaries(self):
"""Strips binaries and *.so files built."""
# out_dir: "chromium/src/out_audioassistant_grte_eng"
# build_out_dirname = "out_audioassistant_grte_eng"
# buildout_dir_path = "/tmp/Xvsgfvcfg/out_audioassistant_grte_eng"
# build_chromecast.py copies files from build_out_dir to buildout_dir_path
build_out_dirname = os.path.basename(self._outdir)
buildout_dir_path = os.path.join(self.archive_dir, build_out_dirname)
binaries_to_strip = []
if not os.path.exists(buildout_dir_path):
print(
'Directory %s not found. Skipping strip binaries.'
% buildout_dir_path)
return
# Filter out directories and non *.so files from build outputs
for path in os.listdir(buildout_dir_path):
if os.path.isfile(os.path.join(buildout_dir_path, path)) \
and ('.so' in path):
binaries_to_strip.append(os.path.join(buildout_dir_path, path))
CAST_BINARIES_LIST = [
'cast_shell',
'aurora',
'ml_framework',
'exo_main',
'hello_world'
]
# Add cast binaries to binaries_to_strip
for path in os.listdir(buildout_dir_path):
if os.path.isfile(os.path.join(buildout_dir_path, path)) \
and (path in CAST_BINARIES_LIST):
binaries_to_strip.append(os.path.join(buildout_dir_path, path))
# Strip binaries to same path's
for binary_path in binaries_to_strip:
print('Stripping %s' % binary_path)
try:
self.unit_test_helper.StripBinary(binary_path)
except Exception as e:
logging.error(
'Error while stripping binary %s %s' % (binary_path, str(e)))
def run(self):
"""Builds cast_shell.
Returns:
True iff there were no errors.
"""
returncode = self.BuildCastShell()
if self._strip_binaries:
self.StripBinaries()
cast_shell_exe_path = os.path.join(self._outdir, CAST_SHELL_EXE)
self.add_step_data(cast_shell_utils.CAST_SHELL_EXE_PATH,
cast_shell_exe_path)
print("Cast shell exe path: ", cast_shell_exe_path)
return returncode == 0