| # Copyright 2018 The Fuchsia Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| from recipe_engine import recipe_api |
| |
| |
| class NinjaApi(recipe_api.RecipeApi): |
| """APIs for interacting with Ninja. |
| |
| Clients must call set_path before using this module, to point to the prebuilt Ninja |
| binary. |
| """ |
| |
| def __init__(self, *args, **kwargs): |
| super(NinjaApi, self).__init__(*args, **kwargs) |
| self._exe = None |
| |
| def __call__(self, |
| build_dir, |
| targets, |
| step_name='ninja', |
| job_count=None, |
| build_file=None, |
| fail_threshold=None, |
| verbose=False): |
| """Runs Ninja. |
| |
| Args: |
| build_dir (Path): CD into this directory before executing. |
| job_count (int): No. parallel jobs (Ninja default is to guess from available CPUs). |
| targets (List(string)): List of targets to build. |
| build_file (Path): Ninja build file (default=build.ninja) |
| fail_threshold (int): Keep going until this many jobs fail (Ninja default of 1). |
| step_name (string): Step name (default: 'ninja'). |
| verbose (bool): Show all command lines when building. |
| |
| Returns: |
| The step result of running Ninja. |
| """ |
| assert self._exe, 'missing executable. Did you call set_path?' |
| |
| # Construct command for ninja |
| ninja_command = [ |
| self._exe, |
| '-C', |
| build_dir, |
| ] |
| |
| if job_count: |
| ninja_command.extend(['-j', job_count]) |
| if build_file: |
| ninja_command.extend(['-f', build_file]) |
| if fail_threshold: |
| ninja_command.extend(['-k', fail_threshold]) |
| if verbose: |
| ninja_command.append('-v') |
| |
| # Sort the targets for a deterministic ordering. This will ease reviews, |
| # as a re-ordering of build logic will yield the same ninja invocation. |
| ninja_command.extend(sorted(targets)) |
| |
| # Use ninja_wrapper to run ninja build |
| ninja_wrapper_args = [ |
| '--ninja_info_output', |
| self.m.json.output( |
| add_json_log='on_failure', name='failure_json_summary'), |
| '--failure_output', |
| self.m.raw_io.output( |
| add_output_log='on_failure', name='failure_raw_summary'), |
| ] |
| ninja_wrapper_args.append('--') |
| ninja_wrapper_args.extend(ninja_command) |
| |
| test_json = { |
| 'failures': [{ |
| 'output_nodes': ['a.o'], |
| 'rule': 'CXX', |
| 'output': 'error info', |
| 'dependencies': ['b/a.cc'] |
| }] |
| } |
| test_failure_output = '[1/1] CXX a.o\nerror info\n' |
| step_test_data = ( |
| lambda: self.m.json.test_api.output(test_json, name='ninja_info') + self |
| .m.raw_io.test_api.output(test_failure_output, name='failure_summary')) |
| |
| return self.m.python( |
| step_name, |
| script=self.resource('ninja_wrapper.py'), |
| args=ninja_wrapper_args, |
| step_test_data=step_test_data) |
| |
| def set_path(self, path): |
| """Sets the path to the Ninja executable.""" |
| self._exe = path |