| # Copyright 2017 The Cobalt Authors. All Rights Reserved. |
| # |
| # 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. |
| """Wrapper to generate build files from .gyp files.""" |
| |
| import logging |
| import os |
| import shlex |
| import sys |
| |
| import _env # pylint: disable=unused-import |
| from starboard.tools import build |
| from starboard.tools import paths |
| from starboard.tools import platform |
| |
| |
| def _Dedupe(sequence): |
| visited = set() |
| return [x for x in sequence if not (x in visited or visited.add(x))] |
| |
| |
| def _GetHostOS(): |
| """Returns the name of the hosting OS.""" |
| host_os_names = { |
| 'linux2': 'linux', |
| 'linux3': 'linux', |
| 'darwin': 'linux', |
| 'win32': 'win', |
| } |
| |
| if sys.platform not in host_os_names: |
| if sys.platform == 'cygwin': |
| logging.error('There may be several incompatibilities when trying to ' |
| 'build from within cygwin. When using a bash shell is ' |
| 'preferred, consider using msysgit instead (see ' |
| 'https://msysgit.github.io).') |
| raise RuntimeError('Unsupported platform: %s' % sys.platform) |
| |
| return host_os_names[sys.platform] |
| |
| |
| def _AppendIncludes(includes, args): |
| for include in includes: |
| args.append('-I{}'.format(include)) |
| |
| |
| def _AppendVariables(variables, args): |
| for var in variables: |
| args.append('-D{}={}'.format(var, variables[var])) |
| |
| |
| def _AppendGeneratorVariables(variables, args): |
| for var in variables: |
| args.append('-G{}={}'.format(var, variables[var])) |
| |
| |
| class GypRunner(object): |
| """Responsible for running GYP.""" |
| |
| def __init__(self, options): |
| options.build_configs = _Dedupe(options.build_configs) |
| self.options = options |
| self.common_args = [] |
| self.platform_configuration = build.GetPlatformConfig(options.platform) |
| if not self.platform_configuration: |
| raise RuntimeError('Unable to load PlatformConfiguration.') |
| |
| env_vars = self.platform_configuration.GetEnvironmentVariables() |
| self.app_configuration = ( |
| self.platform_configuration.GetApplicationConfiguration( |
| options.application)) |
| |
| if not self.app_configuration: |
| raise RuntimeError('Unable to load an ApplicationConfiguration.') |
| |
| app_env_vars = self.app_configuration.GetEnvironmentVariables() |
| if app_env_vars: |
| env_vars.update(app_env_vars) |
| os.environ.update(env_vars) |
| self._MakeCommonArguments() |
| |
| def BuildConfigs(self): |
| """Builds all configs specified in the options.""" |
| if not self.options.build_configs: |
| raise RuntimeError('No build config types specified.') |
| |
| for config_name in self.options.build_configs: |
| logging.info('Building config: %s', config_name) |
| result = self.BuildConfig(config_name) |
| if result: |
| return result |
| return 0 |
| |
| def BuildConfig(self, config_name): |
| """Builds the GYP file for a given config.""" |
| |
| # Make a copy of the common arguments. |
| args = self.common_args[:] |
| |
| configuration_variables = { |
| # Default deploy script. Certain platforms may choose to change this. |
| 'include_path_platform_deploy_gypi': |
| 'starboard/build/default_no_deploy.gypi' |
| } |
| configuration_variables.update( |
| self.platform_configuration.GetVariables(config_name)) |
| app_variables = self.app_configuration.GetVariables(config_name) |
| if app_variables: |
| configuration_variables.update(app_variables) |
| _AppendVariables(configuration_variables, args) |
| |
| # Add the symbolizer path for ASAN to allow translation of callstacks. |
| asan_symbolizer_path = '' |
| if configuration_variables.get('use_asan', 0) == 1: |
| compiler_commandline = shlex.split(os.environ.get('CC', '')) |
| for path in compiler_commandline: |
| if os.path.isfile(path): |
| test_path = os.path.join(os.path.dirname(path), 'llvm-symbolizer') |
| if os.path.isfile(test_path): |
| asan_symbolizer_path = test_path |
| break |
| asan_variables = { |
| 'asan_symbolizer_path': asan_symbolizer_path, |
| } |
| _AppendVariables(asan_variables, args) |
| |
| # Add config specific generator variables. |
| generator_config = '{}_{}'.format(self.options.platform, config_name) |
| |
| generator_variables = { |
| 'config': generator_config, |
| } |
| generator_variables.update( |
| self.platform_configuration.GetGeneratorVariables(config_name)) |
| app_generator_variables = ( |
| self.app_configuration.GetGeneratorVariables(config_name)) |
| if app_generator_variables: |
| generator_variables.update(app_generator_variables) |
| _AppendGeneratorVariables(generator_variables, args) |
| |
| build_file = self.options.build_file |
| if not build_file: |
| build_file = self.app_configuration.GetDefaultTargetBuildFile() |
| |
| if not build_file: |
| build_file = self.platform_configuration.GetDefaultTargetBuildFile() |
| |
| if not build_file: |
| raise RuntimeError('Unable to determine target GYP file.') |
| |
| # That target build file goes last. |
| args.append(build_file) |
| logging.debug('GYP arguments: %s', args) |
| return build.GetGyp().main(args) |
| |
| def _MakeCommonArguments(self): |
| """Makes a list of GYP arguments that are common to all configurations.""" |
| |
| platform_name = self.platform_configuration.GetName() |
| if not platform.IsValid(platform_name): |
| raise RuntimeError('Invalid platform: %s' % platform_name) |
| |
| source_tree_dir = paths.REPOSITORY_ROOT |
| self.common_args = [ |
| # Set the build format. |
| '--format={}-{}'.format(self.platform_configuration.GetBuildFormat(), |
| platform_name), |
| |
| # Set the depth argument to the top level directory. This will define |
| # the DEPTH variable which is the relative path between the directory |
| # containing the processed build file and the top level directory. |
| '--depth={}'.format(source_tree_dir), |
| |
| # Set the top of the source tree. |
| '--toplevel-dir={}'.format(source_tree_dir), |
| ] |
| |
| # Pass through the debug options. |
| for debug in self.options.debug: |
| self.common_args.append('--debug=%s' % debug) |
| |
| if self.options.check: |
| self.common_args.append('--check') |
| |
| # Append common GYP variables. |
| common_variables = { |
| 'OS': 'starboard', |
| 'CC_HOST': os.environ.get('CC_HOST', os.environ.get('CC', '')), |
| 'host_os': _GetHostOS(), |
| 'starboard_path': os.path.relpath(platform.Get(platform_name).path, |
| source_tree_dir), |
| 'starboard_platform_name': platform_name, |
| } |
| |
| _AppendVariables(common_variables, self.common_args) |
| |
| # Append generator variables. |
| generator_variables = { |
| # Set the output folder name; affects all generators but MSVS. |
| 'output_dir': 'out', |
| } |
| _AppendGeneratorVariables(generator_variables, self.common_args) |
| |
| # Append GYPI includes which will be included by GYP before any processed |
| # build file. |
| gyp_includes = [ |
| os.path.join(paths.REPOSITORY_ROOT, 'starboard', 'build', |
| 'base_configuration.gypi'), |
| |
| # TODO: Remove dependency on common.gypi by moving the required bits |
| # into base_configuration.gypi. |
| os.path.join(paths.REPOSITORY_ROOT, 'build', 'common.gypi'), |
| ] |
| gyp_includes.extend(self.platform_configuration.GetIncludes()) |
| if self.app_configuration: |
| gyp_includes[:0] = self.app_configuration.GetPreIncludes() |
| gyp_includes.extend(self.app_configuration.GetPostIncludes()) |
| _AppendIncludes(gyp_includes, self.common_args) |