blob: 561e195199604c7c3cf5991a7d9e7c9963d209c0 [file] [log] [blame]
#
# Copyright (C) 2016 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
"""Functions for building code."""
import os
import subprocess
from core import tool
import error
class Error(error.Error):
"""General build failure."""
class BuildUtilityError(Error):
"""Raised when a build utility fails or is missing."""
def _GetBuildScript(platform, extra_make_args=None):
"""Creates a shell script to run a platform build.
The script is small but uses several variables, which is why it's
easier just to build it here and run it directly. If the script
expands to be more complicated we probably want to move it into its
own file.
Args:
platform: Platform to build.
extra_make_args: additional make args as a list of strings or None.
Returns:
A string shell script that will build the platform.
"""
make_args = []
if extra_make_args:
make_args.extend(extra_make_args)
cmds = ['cd "{}"'.format(platform.os.root),
'export OUT_DIR="{}"'.format(platform.build_cache),
'. build/envsetup.sh',
'lunch "{}-{}"'.format(platform.device.name, platform.build_type),
'm {}'.format(' '.join(make_args))]
# Link all commands with && to exit immediately if one fails.
return ' && '.join(cmds)
def BuildPlatform(platform, extra_make_args=None):
"""Builds the Brillo platform.
Caller should validate target OS and Board before calling.
Args:
platform: Platform to build.
extra_make_args: additional make args as a list of strings or None.
Returns:
The build exit code.
Raises:
BuildUtilityError: subprocess invocation fails.
"""
build_script = _GetBuildScript(platform, extra_make_args)
# Set up the build environment. We strip out most environment variables,
# but some values (e.g. USER, TERM) are useful or necessary for the build.
build_env = {var: os.environ[var] for var in tool.DEFAULT_PASSTHROUGH_ENV
if var in os.environ}
# Make sure the output directory exists so we can log to it.
if not os.path.isdir(platform.build_cache):
os.makedirs(platform.build_cache)
log_file_path = os.path.join(platform.build_cache, 'bdk_last_build.log')
with platform.linked():
# The build script uses bash features like && to link multiple commands
# and to source scripts, so we invoke via bash.
try:
build_subprocess = subprocess.Popen(build_script, shell=True,
env=build_env,
executable='bash',
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
except OSError as e:
raise BuildUtilityError(
'Failed to track a platform build. Is '
'"bash" installed, accessible, and in the PATH?: {}'.format(e))
# Piping a command to tee on the shell clobbers the exit code, so
# instead we make them two separate subprocesses and pipe them together.
try:
tee_subprocess = subprocess.Popen(['tee', log_file_path],
env=build_env,
stdin=build_subprocess.stdout)
except OSError as e:
raise BuildUtilityError(
'Failed to track a platform build. Is '
'"tee" installed, accessible, and in the PATH?: {}'.format(e))
# Close stdout to avoid pipes filling up and blocking forever if tee
# fails.
# https://docs.python.org/2/library/subprocess.html#replacing-shell-pipeline.
build_subprocess.stdout.close()
tee_subprocess.communicate()
return build_subprocess.wait()