| # |
| # 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() |