1# Copyright (c) 2012 Google Inc. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5# Notes:
6#
7# This generates makefiles suitable for inclusion into the Android build system
8# via an Android.mk file. It is based on make.py, the standard makefile
9# generator.
10#
11# The code below generates a separate .mk file for each target, but
12# all are sourced by the top-level GypAndroid.mk.  This means that all
13# variables in .mk-files clobber one another, and furthermore that any
14# variables set potentially clash with other Android build system variables.
15# Try to avoid setting global variables where possible.
16
17from __future__ import print_function
18
19import gyp
20import gyp.common
21import gyp.generator.make as make  # Reuse global functions from make backend.
22import os
23import re
24import subprocess
25
26generator_default_variables = {
27  'OS': 'android',
28  'EXECUTABLE_PREFIX': '',
29  'EXECUTABLE_SUFFIX': '',
30  'STATIC_LIB_PREFIX': 'lib',
31  'SHARED_LIB_PREFIX': 'lib',
32  'STATIC_LIB_SUFFIX': '.a',
33  'SHARED_LIB_SUFFIX': '.so',
34  'INTERMEDIATE_DIR': '$(gyp_intermediate_dir)',
35  'SHARED_INTERMEDIATE_DIR': '$(gyp_shared_intermediate_dir)',
36  'PRODUCT_DIR': '$(gyp_shared_intermediate_dir)',
37  'SHARED_LIB_DIR': '$(builddir)/lib.$(TOOLSET)',
38  'LIB_DIR': '$(obj).$(TOOLSET)',
39  'RULE_INPUT_ROOT': '%(INPUT_ROOT)s',  # This gets expanded by Python.
40  'RULE_INPUT_DIRNAME': '%(INPUT_DIRNAME)s',  # This gets expanded by Python.
41  'RULE_INPUT_PATH': '$(RULE_SOURCES)',
42  'RULE_INPUT_EXT': '$(suffix $<)',
43  'RULE_INPUT_NAME': '$(notdir $<)',
44  'CONFIGURATION_NAME': '$(GYP_CONFIGURATION)',
45}
46
47# Make supports multiple toolsets
48generator_supports_multiple_toolsets = True
49
50
51# Generator-specific gyp specs.
52generator_additional_non_configuration_keys = [
53    # Boolean to declare that this target does not want its name mangled.
54    'android_unmangled_name',
55    # Map of android build system variables to set.
56    'aosp_build_settings',
57]
58generator_additional_path_sections = []
59generator_extra_sources_for_rules = []
60
61
62ALL_MODULES_FOOTER = """\
63# "gyp_all_modules" is a concatenation of the "gyp_all_modules" targets from
64# all the included sub-makefiles. This is just here to clarify.
65gyp_all_modules:
66"""
67
68header = """\
69# This file is generated by gyp; do not edit.
70
71"""
72
73# Map gyp target types to Android module classes.
74MODULE_CLASSES = {
75    'static_library': 'STATIC_LIBRARIES',
76    'shared_library': 'SHARED_LIBRARIES',
77    'executable': 'EXECUTABLES',
78}
79
80
81def IsCPPExtension(ext):
82  return make.COMPILABLE_EXTENSIONS.get(ext) == 'cxx'
83
84
85def Sourceify(path):
86  """Convert a path to its source directory form. The Android backend does not
87     support options.generator_output, so this function is a noop."""
88  return path
89
90
91# Map from qualified target to path to output.
92# For Android, the target of these maps is a tuple ('static', 'modulename'),
93# ('dynamic', 'modulename'), or ('path', 'some/path') instead of a string,
94# since we link by module.
95target_outputs = {}
96# Map from qualified target to any linkable output.  A subset
97# of target_outputs.  E.g. when mybinary depends on liba, we want to
98# include liba in the linker line; when otherbinary depends on
99# mybinary, we just want to build mybinary first.
100target_link_deps = {}
101
102
103class AndroidMkWriter(object):
104  """AndroidMkWriter packages up the writing of one target-specific Android.mk.
105
106  Its only real entry point is Write(), and is mostly used for namespacing.
107  """
108
109  def __init__(self, android_top_dir):
110    self.android_top_dir = android_top_dir
111
112  def Write(self, qualified_target, relative_target, base_path, output_filename,
113            spec, configs, part_of_all, write_alias_target, sdk_version):
114    """The main entry point: writes a .mk file for a single target.
115
116    Arguments:
117      qualified_target: target we're generating
118      relative_target: qualified target name relative to the root
119      base_path: path relative to source root we're building in, used to resolve
120                 target-relative paths
121      output_filename: output .mk file name to write
122      spec, configs: gyp info
123      part_of_all: flag indicating this target is part of 'all'
124      write_alias_target: flag indicating whether to create short aliases for
125                          this target
126      sdk_version: what to emit for LOCAL_SDK_VERSION in output
127    """
128    gyp.common.EnsureDirExists(output_filename)
129
130    self.fp = open(output_filename, 'w')
131
132    self.fp.write(header)
133
134    self.qualified_target = qualified_target
135    self.relative_target = relative_target
136    self.path = base_path
137    self.target = spec['target_name']
138    self.type = spec['type']
139    self.toolset = spec['toolset']
140
141    deps, link_deps = self.ComputeDeps(spec)
142
143    # Some of the generation below can add extra output, sources, or
144    # link dependencies.  All of the out params of the functions that
145    # follow use names like extra_foo.
146    extra_outputs = []
147    extra_sources = []
148
149    self.android_class = MODULE_CLASSES.get(self.type, 'GYP')
150    self.android_module = self.ComputeAndroidModule(spec)
151    (self.android_stem, self.android_suffix) = self.ComputeOutputParts(spec)
152    self.output = self.output_binary = self.ComputeOutput(spec)
153
154    # Standard header.
155    self.WriteLn('include $(CLEAR_VARS)\n')
156
157    # Module class and name.
158    self.WriteLn('LOCAL_MODULE_CLASS := ' + self.android_class)
159    self.WriteLn('LOCAL_MODULE := ' + self.android_module)
160    # Only emit LOCAL_MODULE_STEM if it's different to LOCAL_MODULE.
161    # The library module classes fail if the stem is set. ComputeOutputParts
162    # makes sure that stem == modulename in these cases.
163    if self.android_stem != self.android_module:
164      self.WriteLn('LOCAL_MODULE_STEM := ' + self.android_stem)
165    self.WriteLn('LOCAL_MODULE_SUFFIX := ' + self.android_suffix)
166    if self.toolset == 'host':
167      self.WriteLn('LOCAL_IS_HOST_MODULE := true')
168      self.WriteLn('LOCAL_MULTILIB := $(GYP_HOST_MULTILIB)')
169    elif sdk_version > 0:
170      self.WriteLn('LOCAL_MODULE_TARGET_ARCH := '
171                   '$(TARGET_$(GYP_VAR_PREFIX)ARCH)')
172      self.WriteLn('LOCAL_SDK_VERSION := %s' % sdk_version)
173
174    # Grab output directories; needed for Actions and Rules.
175    if self.toolset == 'host':
176      self.WriteLn('gyp_intermediate_dir := '
177                   '$(call local-intermediates-dir,,$(GYP_HOST_VAR_PREFIX))')
178    else:
179      self.WriteLn('gyp_intermediate_dir := '
180                   '$(call local-intermediates-dir,,$(GYP_VAR_PREFIX))')
181    self.WriteLn('gyp_shared_intermediate_dir := '
182                 '$(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))')
183    self.WriteLn()
184
185    # List files this target depends on so that actions/rules/copies/sources
186    # can depend on the list.
187    # TODO: doesn't pull in things through transitive link deps; needed?
188    target_dependencies = [x[1] for x in deps if x[0] == 'path']
189    self.WriteLn('# Make sure our deps are built first.')
190    self.WriteList(target_dependencies, 'GYP_TARGET_DEPENDENCIES',
191                   local_pathify=True)
192
193    # Actions must come first, since they can generate more OBJs for use below.
194    if 'actions' in spec:
195      self.WriteActions(spec['actions'], extra_sources, extra_outputs)
196
197    # Rules must be early like actions.
198    if 'rules' in spec:
199      self.WriteRules(spec['rules'], extra_sources, extra_outputs)
200
201    if 'copies' in spec:
202      self.WriteCopies(spec['copies'], extra_outputs)
203
204    # GYP generated outputs.
205    self.WriteList(extra_outputs, 'GYP_GENERATED_OUTPUTS', local_pathify=True)
206
207    # Set LOCAL_ADDITIONAL_DEPENDENCIES so that Android's build rules depend
208    # on both our dependency targets and our generated files.
209    self.WriteLn('# Make sure our deps and generated files are built first.')
210    self.WriteLn('LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) '
211                 '$(GYP_GENERATED_OUTPUTS)')
212    self.WriteLn()
213
214    # Sources.
215    if spec.get('sources', []) or extra_sources:
216      self.WriteSources(spec, configs, extra_sources)
217
218    self.WriteTarget(spec, configs, deps, link_deps, part_of_all,
219                     write_alias_target)
220
221    # Update global list of target outputs, used in dependency tracking.
222    target_outputs[qualified_target] = ('path', self.output_binary)
223
224    # Update global list of link dependencies.
225    if self.type == 'static_library':
226      target_link_deps[qualified_target] = ('static', self.android_module)
227    elif self.type == 'shared_library':
228      target_link_deps[qualified_target] = ('shared', self.android_module)
229
230    self.fp.close()
231    return self.android_module
232
233
234  def WriteActions(self, actions, extra_sources, extra_outputs):
235    """Write Makefile code for any 'actions' from the gyp input.
236
237    extra_sources: a list that will be filled in with newly generated source
238                   files, if any
239    extra_outputs: a list that will be filled in with any outputs of these
240                   actions (used to make other pieces dependent on these
241                   actions)
242    """
243    for action in actions:
244      name = make.StringToMakefileVariable('%s_%s' % (self.relative_target,
245                                                      action['action_name']))
246      self.WriteLn('### Rules for action "%s":' % action['action_name'])
247      inputs = action['inputs']
248      outputs = action['outputs']
249
250      # Build up a list of outputs.
251      # Collect the output dirs we'll need.
252      dirs = set()
253      for out in outputs:
254        if not out.startswith('$'):
255          print('WARNING: Action for target "%s" writes output to local path '
256                 '"%s".' % (self.target, out))
257        dir = os.path.split(out)[0]
258        if dir:
259          dirs.add(dir)
260      if int(action.get('process_outputs_as_sources', False)):
261        extra_sources += outputs
262
263      # Prepare the actual command.
264      command = gyp.common.EncodePOSIXShellList(action['action'])
265      if 'message' in action:
266        quiet_cmd = 'Gyp action: %s ($@)' % action['message']
267      else:
268        quiet_cmd = 'Gyp action: %s ($@)' % name
269      if len(dirs) > 0:
270        command = 'mkdir -p %s' % ' '.join(dirs) + '; ' + command
271
272      cd_action = 'cd $(gyp_local_path)/%s; ' % self.path
273      command = cd_action + command
274
275      # The makefile rules are all relative to the top dir, but the gyp actions
276      # are defined relative to their containing dir.  This replaces the gyp_*
277      # variables for the action rule with an absolute version so that the
278      # output goes in the right place.
279      # Only write the gyp_* rules for the "primary" output (:1);
280      # it's superfluous for the "extra outputs", and this avoids accidentally
281      # writing duplicate dummy rules for those outputs.
282      main_output = make.QuoteSpaces(self.LocalPathify(outputs[0]))
283      self.WriteLn('%s: gyp_local_path := $(LOCAL_PATH)' % main_output)
284      self.WriteLn('%s: gyp_var_prefix := $(GYP_VAR_PREFIX)' % main_output)
285      self.WriteLn('%s: gyp_intermediate_dir := '
286                   '$(abspath $(gyp_intermediate_dir))' % main_output)
287      self.WriteLn('%s: gyp_shared_intermediate_dir := '
288                   '$(abspath $(gyp_shared_intermediate_dir))' % main_output)
289
290      # Android's envsetup.sh adds a number of directories to the path including
291      # the built host binary directory. This causes actions/rules invoked by
292      # gyp to sometimes use these instead of system versions, e.g. bison.
293      # The built host binaries may not be suitable, and can cause errors.
294      # So, we remove them from the PATH using the ANDROID_BUILD_PATHS variable
295      # set by envsetup.
296      self.WriteLn('%s: export PATH := $(subst $(ANDROID_BUILD_PATHS),,$(PATH))'
297                   % main_output)
298
299      # Don't allow spaces in input/output filenames, but make an exception for
300      # filenames which start with '$(' since it's okay for there to be spaces
301      # inside of make function/macro invocations.
302      for input in inputs:
303        if not input.startswith('$(') and ' ' in input:
304          raise gyp.common.GypError(
305              'Action input filename "%s" in target %s contains a space' %
306              (input, self.target))
307      for output in outputs:
308        if not output.startswith('$(') and ' ' in output:
309          raise gyp.common.GypError(
310              'Action output filename "%s" in target %s contains a space' %
311              (output, self.target))
312
313      self.WriteLn('%s: %s $(GYP_TARGET_DEPENDENCIES)' %
314                   (main_output, ' '.join(map(self.LocalPathify, inputs))))
315      self.WriteLn('\t@echo "%s"' % quiet_cmd)
316      self.WriteLn('\t$(hide)%s\n' % command)
317      for output in outputs[1:]:
318        # Make each output depend on the main output, with an empty command
319        # to force make to notice that the mtime has changed.
320        self.WriteLn('%s: %s ;' % (self.LocalPathify(output), main_output))
321
322      extra_outputs += outputs
323      self.WriteLn()
324
325    self.WriteLn()
326
327
328  def WriteRules(self, rules, extra_sources, extra_outputs):
329    """Write Makefile code for any 'rules' from the gyp input.
330
331    extra_sources: a list that will be filled in with newly generated source
332                   files, if any
333    extra_outputs: a list that will be filled in with any outputs of these
334                   rules (used to make other pieces dependent on these rules)
335    """
336    if len(rules) == 0:
337      return
338
339    for rule in rules:
340      if len(rule.get('rule_sources', [])) == 0:
341        continue
342      name = make.StringToMakefileVariable('%s_%s' % (self.relative_target,
343                                                      rule['rule_name']))
344      self.WriteLn('\n### Generated for rule "%s":' % name)
345      self.WriteLn('# "%s":' % rule)
346
347      inputs = rule.get('inputs')
348      for rule_source in rule.get('rule_sources', []):
349        (rule_source_dirname, rule_source_basename) = os.path.split(rule_source)
350        (rule_source_root, rule_source_ext) = \
351            os.path.splitext(rule_source_basename)
352
353        outputs = [self.ExpandInputRoot(out, rule_source_root,
354                                        rule_source_dirname)
355                   for out in rule['outputs']]
356
357        dirs = set()
358        for out in outputs:
359          if not out.startswith('$'):
360            print('WARNING: Rule for target %s writes output to local path %s'
361                   % (self.target, out))
362          dir = os.path.dirname(out)
363          if dir:
364            dirs.add(dir)
365        extra_outputs += outputs
366        if int(rule.get('process_outputs_as_sources', False)):
367          extra_sources.extend(outputs)
368
369        components = []
370        for component in rule['action']:
371          component = self.ExpandInputRoot(component, rule_source_root,
372                                           rule_source_dirname)
373          if '$(RULE_SOURCES)' in component:
374            component = component.replace('$(RULE_SOURCES)',
375                                          rule_source)
376          components.append(component)
377
378        command = gyp.common.EncodePOSIXShellList(components)
379        cd_action = 'cd $(gyp_local_path)/%s; ' % self.path
380        command = cd_action + command
381        if dirs:
382          command = 'mkdir -p %s' % ' '.join(dirs) + '; ' + command
383
384        # We set up a rule to build the first output, and then set up
385        # a rule for each additional output to depend on the first.
386        outputs = map(self.LocalPathify, outputs)
387        main_output = outputs[0]
388        self.WriteLn('%s: gyp_local_path := $(LOCAL_PATH)' % main_output)
389        self.WriteLn('%s: gyp_var_prefix := $(GYP_VAR_PREFIX)' % main_output)
390        self.WriteLn('%s: gyp_intermediate_dir := '
391                     '$(abspath $(gyp_intermediate_dir))' % main_output)
392        self.WriteLn('%s: gyp_shared_intermediate_dir := '
393                     '$(abspath $(gyp_shared_intermediate_dir))' % main_output)
394
395        # See explanation in WriteActions.
396        self.WriteLn('%s: export PATH := '
397                     '$(subst $(ANDROID_BUILD_PATHS),,$(PATH))' % main_output)
398
399        main_output_deps = self.LocalPathify(rule_source)
400        if inputs:
401          main_output_deps += ' '
402          main_output_deps += ' '.join([self.LocalPathify(f) for f in inputs])
403
404        self.WriteLn('%s: %s $(GYP_TARGET_DEPENDENCIES)' %
405                     (main_output, main_output_deps))
406        self.WriteLn('\t%s\n' % command)
407        for output in outputs[1:]:
408          # Make each output depend on the main output, with an empty command
409          # to force make to notice that the mtime has changed.
410          self.WriteLn('%s: %s ;' % (output, main_output))
411        self.WriteLn()
412
413    self.WriteLn()
414
415
416  def WriteCopies(self, copies, extra_outputs):
417    """Write Makefile code for any 'copies' from the gyp input.
418
419    extra_outputs: a list that will be filled in with any outputs of this action
420                   (used to make other pieces dependent on this action)
421    """
422    self.WriteLn('### Generated for copy rule.')
423
424    variable = make.StringToMakefileVariable(self.relative_target + '_copies')
425    outputs = []
426    for copy in copies:
427      for path in copy['files']:
428        # The Android build system does not allow generation of files into the
429        # source tree. The destination should start with a variable, which will
430        # typically be $(gyp_intermediate_dir) or
431        # $(gyp_shared_intermediate_dir). Note that we can't use an assertion
432        # because some of the gyp tests depend on this.
433        if not copy['destination'].startswith('$'):
434          print('WARNING: Copy rule for target %s writes output to '
435                 'local path %s' % (self.target, copy['destination']))
436
437        # LocalPathify() calls normpath, stripping trailing slashes.
438        path = Sourceify(self.LocalPathify(path))
439        filename = os.path.split(path)[1]
440        output = Sourceify(self.LocalPathify(os.path.join(copy['destination'],
441                                                          filename)))
442
443        self.WriteLn('%s: %s $(GYP_TARGET_DEPENDENCIES) | $(ACP)' %
444                     (output, path))
445        self.WriteLn('\t@echo Copying: $@')
446        self.WriteLn('\t$(hide) mkdir -p $(dir $@)')
447        self.WriteLn('\t$(hide) $(ACP) -rpf $< $@')
448        self.WriteLn()
449        outputs.append(output)
450    self.WriteLn('%s = %s' % (variable,
451                              ' '.join(map(make.QuoteSpaces, outputs))))
452    extra_outputs.append('$(%s)' % variable)
453    self.WriteLn()
454
455
456  def WriteSourceFlags(self, spec, configs):
457    """Write out the flags and include paths used to compile source files for
458    the current target.
459
460    Args:
461      spec, configs: input from gyp.
462    """
463    for configname, config in sorted(configs.items()):
464      extracted_includes = []
465
466      self.WriteLn('\n# Flags passed to both C and C++ files.')
467      cflags, includes_from_cflags = self.ExtractIncludesFromCFlags(
468          config.get('cflags', []) + config.get('cflags_c', []))
469      extracted_includes.extend(includes_from_cflags)
470      self.WriteList(cflags, 'MY_CFLAGS_%s' % configname)
471
472      self.WriteList(config.get('defines'), 'MY_DEFS_%s' % configname,
473                     prefix='-D', quoter=make.EscapeCppDefine)
474
475      self.WriteLn('\n# Include paths placed before CFLAGS/CPPFLAGS')
476      includes = list(config.get('include_dirs', []))
477      includes.extend(extracted_includes)
478      includes = map(Sourceify, map(self.LocalPathify, includes))
479      includes = self.NormalizeIncludePaths(includes)
480      self.WriteList(includes, 'LOCAL_C_INCLUDES_%s' % configname)
481
482      self.WriteLn('\n# Flags passed to only C++ (and not C) files.')
483      self.WriteList(config.get('cflags_cc'), 'LOCAL_CPPFLAGS_%s' % configname)
484
485    self.WriteLn('\nLOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) '
486                 '$(MY_DEFS_$(GYP_CONFIGURATION))')
487    # Undefine ANDROID for host modules
488    # TODO: the source code should not use macro ANDROID to tell if it's host
489    # or target module.
490    if self.toolset == 'host':
491      self.WriteLn('# Undefine ANDROID for host modules')
492      self.WriteLn('LOCAL_CFLAGS += -UANDROID')
493    self.WriteLn('LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) '
494                                     '$(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))')
495    self.WriteLn('LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))')
496    # Android uses separate flags for assembly file invocations, but gyp expects
497    # the same CFLAGS to be applied:
498    self.WriteLn('LOCAL_ASFLAGS := $(LOCAL_CFLAGS)')
499
500
501  def WriteSources(self, spec, configs, extra_sources):
502    """Write Makefile code for any 'sources' from the gyp input.
503    These are source files necessary to build the current target.
504    We need to handle shared_intermediate directory source files as
505    a special case by copying them to the intermediate directory and
506    treating them as a genereated sources. Otherwise the Android build
507    rules won't pick them up.
508
509    Args:
510      spec, configs: input from gyp.
511      extra_sources: Sources generated from Actions or Rules.
512    """
513    sources = filter(make.Compilable, spec.get('sources', []))
514    generated_not_sources = [x for x in extra_sources if not make.Compilable(x)]
515    extra_sources = filter(make.Compilable, extra_sources)
516
517    # Determine and output the C++ extension used by these sources.
518    # We simply find the first C++ file and use that extension.
519    all_sources = sources + extra_sources
520    local_cpp_extension = '.cpp'
521    for source in all_sources:
522      (root, ext) = os.path.splitext(source)
523      if IsCPPExtension(ext):
524        local_cpp_extension = ext
525        break
526    if local_cpp_extension != '.cpp':
527      self.WriteLn('LOCAL_CPP_EXTENSION := %s' % local_cpp_extension)
528
529    # We need to move any non-generated sources that are coming from the
530    # shared intermediate directory out of LOCAL_SRC_FILES and put them
531    # into LOCAL_GENERATED_SOURCES. We also need to move over any C++ files
532    # that don't match our local_cpp_extension, since Android will only
533    # generate Makefile rules for a single LOCAL_CPP_EXTENSION.
534    local_files = []
535    for source in sources:
536      (root, ext) = os.path.splitext(source)
537      if '$(gyp_shared_intermediate_dir)' in source:
538        extra_sources.append(source)
539      elif '$(gyp_intermediate_dir)' in source:
540        extra_sources.append(source)
541      elif IsCPPExtension(ext) and ext != local_cpp_extension:
542        extra_sources.append(source)
543      else:
544        local_files.append(os.path.normpath(os.path.join(self.path, source)))
545
546    # For any generated source, if it is coming from the shared intermediate
547    # directory then we add a Make rule to copy them to the local intermediate
548    # directory first. This is because the Android LOCAL_GENERATED_SOURCES
549    # must be in the local module intermediate directory for the compile rules
550    # to work properly. If the file has the wrong C++ extension, then we add
551    # a rule to copy that to intermediates and use the new version.
552    final_generated_sources = []
553    # If a source file gets copied, we still need to add the original source
554    # directory as header search path, for GCC searches headers in the
555    # directory that contains the source file by default.
556    origin_src_dirs = []
557    for source in extra_sources:
558      local_file = source
559      if not '$(gyp_intermediate_dir)/' in local_file:
560        basename = os.path.basename(local_file)
561        local_file = '$(gyp_intermediate_dir)/' + basename
562      (root, ext) = os.path.splitext(local_file)
563      if IsCPPExtension(ext) and ext != local_cpp_extension:
564        local_file = root + local_cpp_extension
565      if local_file != source:
566        self.WriteLn('%s: %s' % (local_file, self.LocalPathify(source)))
567        self.WriteLn('\tmkdir -p $(@D); cp $< $@')
568        origin_src_dirs.append(os.path.dirname(source))
569      final_generated_sources.append(local_file)
570
571    # We add back in all of the non-compilable stuff to make sure that the
572    # make rules have dependencies on them.
573    final_generated_sources.extend(generated_not_sources)
574    self.WriteList(final_generated_sources, 'LOCAL_GENERATED_SOURCES')
575
576    origin_src_dirs = gyp.common.uniquer(origin_src_dirs)
577    origin_src_dirs = map(Sourceify, map(self.LocalPathify, origin_src_dirs))
578    self.WriteList(origin_src_dirs, 'GYP_COPIED_SOURCE_ORIGIN_DIRS')
579
580    self.WriteList(local_files, 'LOCAL_SRC_FILES')
581
582    # Write out the flags used to compile the source; this must be done last
583    # so that GYP_COPIED_SOURCE_ORIGIN_DIRS can be used as an include path.
584    self.WriteSourceFlags(spec, configs)
585
586
587  def ComputeAndroidModule(self, spec):
588    """Return the Android module name used for a gyp spec.
589
590    We use the complete qualified target name to avoid collisions between
591    duplicate targets in different directories. We also add a suffix to
592    distinguish gyp-generated module names.
593    """
594
595    if int(spec.get('android_unmangled_name', 0)):
596      assert self.type != 'shared_library' or self.target.startswith('lib')
597      return self.target
598
599    if self.type == 'shared_library':
600      # For reasons of convention, the Android build system requires that all
601      # shared library modules are named 'libfoo' when generating -l flags.
602      prefix = 'lib_'
603    else:
604      prefix = ''
605
606    if spec['toolset'] == 'host':
607      suffix = '_$(TARGET_$(GYP_VAR_PREFIX)ARCH)_host_gyp'
608    else:
609      suffix = '_gyp'
610
611    if self.path:
612      middle = make.StringToMakefileVariable('%s_%s' % (self.path, self.target))
613    else:
614      middle = make.StringToMakefileVariable(self.target)
615
616    return ''.join([prefix, middle, suffix])
617
618
619  def ComputeOutputParts(self, spec):
620    """Return the 'output basename' of a gyp spec, split into filename + ext.
621
622    Android libraries must be named the same thing as their module name,
623    otherwise the linker can't find them, so product_name and so on must be
624    ignored if we are building a library, and the "lib" prepending is
625    not done for Android.
626    """
627    assert self.type != 'loadable_module' # TODO: not supported?
628
629    target = spec['target_name']
630    target_prefix = ''
631    target_ext = ''
632    if self.type == 'static_library':
633      target = self.ComputeAndroidModule(spec)
634      target_ext = '.a'
635    elif self.type == 'shared_library':
636      target = self.ComputeAndroidModule(spec)
637      target_ext = '.so'
638    elif self.type == 'none':
639      target_ext = '.stamp'
640    elif self.type != 'executable':
641      print("ERROR: What output file should be generated?",
642             "type", self.type, "target", target)
643
644    if self.type != 'static_library' and self.type != 'shared_library':
645      target_prefix = spec.get('product_prefix', target_prefix)
646      target = spec.get('product_name', target)
647      product_ext = spec.get('product_extension')
648      if product_ext:
649        target_ext = '.' + product_ext
650
651    target_stem = target_prefix + target
652    return (target_stem, target_ext)
653
654
655  def ComputeOutputBasename(self, spec):
656    """Return the 'output basename' of a gyp spec.
657
658    E.g., the loadable module 'foobar' in directory 'baz' will produce
659      'libfoobar.so'
660    """
661    return ''.join(self.ComputeOutputParts(spec))
662
663
664  def ComputeOutput(self, spec):
665    """Return the 'output' (full output path) of a gyp spec.
666
667    E.g., the loadable module 'foobar' in directory 'baz' will produce
668      '$(obj)/baz/libfoobar.so'
669    """
670    if self.type == 'executable':
671      # We install host executables into shared_intermediate_dir so they can be
672      # run by gyp rules that refer to PRODUCT_DIR.
673      path = '$(gyp_shared_intermediate_dir)'
674    elif self.type == 'shared_library':
675      if self.toolset == 'host':
676        path = '$($(GYP_HOST_VAR_PREFIX)HOST_OUT_INTERMEDIATE_LIBRARIES)'
677      else:
678        path = '$($(GYP_VAR_PREFIX)TARGET_OUT_INTERMEDIATE_LIBRARIES)'
679    else:
680      # Other targets just get built into their intermediate dir.
681      if self.toolset == 'host':
682        path = ('$(call intermediates-dir-for,%s,%s,true,,'
683                '$(GYP_HOST_VAR_PREFIX))' % (self.android_class,
684                                             self.android_module))
685      else:
686        path = ('$(call intermediates-dir-for,%s,%s,,,$(GYP_VAR_PREFIX))'
687                % (self.android_class, self.android_module))
688
689    assert spec.get('product_dir') is None # TODO: not supported?
690    return os.path.join(path, self.ComputeOutputBasename(spec))
691
692  def NormalizeIncludePaths(self, include_paths):
693    """ Normalize include_paths.
694    Convert absolute paths to relative to the Android top directory.
695
696    Args:
697      include_paths: A list of unprocessed include paths.
698    Returns:
699      A list of normalized include paths.
700    """
701    normalized = []
702    for path in include_paths:
703      if path[0] == '/':
704        path = gyp.common.RelativePath(path, self.android_top_dir)
705      normalized.append(path)
706    return normalized
707
708  def ExtractIncludesFromCFlags(self, cflags):
709    """Extract includes "-I..." out from cflags
710
711    Args:
712      cflags: A list of compiler flags, which may be mixed with "-I.."
713    Returns:
714      A tuple of lists: (clean_clfags, include_paths). "-I.." is trimmed.
715    """
716    clean_cflags = []
717    include_paths = []
718    for flag in cflags:
719      if flag.startswith('-I'):
720        include_paths.append(flag[2:])
721      else:
722        clean_cflags.append(flag)
723
724    return (clean_cflags, include_paths)
725
726  def FilterLibraries(self, libraries):
727    """Filter the 'libraries' key to separate things that shouldn't be ldflags.
728
729    Library entries that look like filenames should be converted to android
730    module names instead of being passed to the linker as flags.
731
732    Args:
733      libraries: the value of spec.get('libraries')
734    Returns:
735      A tuple (static_lib_modules, dynamic_lib_modules, ldflags)
736    """
737    static_lib_modules = []
738    dynamic_lib_modules = []
739    ldflags = []
740    for libs in libraries:
741      # Libs can have multiple words.
742      for lib in libs.split():
743        # Filter the system libraries, which are added by default by the Android
744        # build system.
745        if (lib == '-lc' or lib == '-lstdc++' or lib == '-lm' or
746            lib.endswith('libgcc.a')):
747          continue
748        match = re.search(r'([^/]+)\.a$', lib)
749        if match:
750          static_lib_modules.append(match.group(1))
751          continue
752        match = re.search(r'([^/]+)\.so$', lib)
753        if match:
754          dynamic_lib_modules.append(match.group(1))
755          continue
756        if lib.startswith('-l'):
757          ldflags.append(lib)
758    return (static_lib_modules, dynamic_lib_modules, ldflags)
759
760
761  def ComputeDeps(self, spec):
762    """Compute the dependencies of a gyp spec.
763
764    Returns a tuple (deps, link_deps), where each is a list of
765    filenames that will need to be put in front of make for either
766    building (deps) or linking (link_deps).
767    """
768    deps = []
769    link_deps = []
770    if 'dependencies' in spec:
771      deps.extend([target_outputs[dep] for dep in spec['dependencies']
772                   if target_outputs[dep]])
773      for dep in spec['dependencies']:
774        if dep in target_link_deps:
775          link_deps.append(target_link_deps[dep])
776      deps.extend(link_deps)
777    return (gyp.common.uniquer(deps), gyp.common.uniquer(link_deps))
778
779
780  def WriteTargetFlags(self, spec, configs, link_deps):
781    """Write Makefile code to specify the link flags and library dependencies.
782
783    spec, configs: input from gyp.
784    link_deps: link dependency list; see ComputeDeps()
785    """
786    # Libraries (i.e. -lfoo)
787    # These must be included even for static libraries as some of them provide
788    # implicit include paths through the build system.
789    libraries = gyp.common.uniquer(spec.get('libraries', []))
790    static_libs, dynamic_libs, ldflags_libs = self.FilterLibraries(libraries)
791
792    if self.type != 'static_library':
793      for configname, config in sorted(configs.items()):
794        ldflags = list(config.get('ldflags', []))
795        self.WriteLn('')
796        self.WriteList(ldflags, 'LOCAL_LDFLAGS_%s' % configname)
797      self.WriteList(ldflags_libs, 'LOCAL_GYP_LIBS')
798      self.WriteLn('LOCAL_LDFLAGS := $(LOCAL_LDFLAGS_$(GYP_CONFIGURATION)) '
799                   '$(LOCAL_GYP_LIBS)')
800
801    # Link dependencies (i.e. other gyp targets this target depends on)
802    # These need not be included for static libraries as within the gyp build
803    # we do not use the implicit include path mechanism.
804    if self.type != 'static_library':
805      static_link_deps = [x[1] for x in link_deps if x[0] == 'static']
806      shared_link_deps = [x[1] for x in link_deps if x[0] == 'shared']
807    else:
808      static_link_deps = []
809      shared_link_deps = []
810
811    # Only write the lists if they are non-empty.
812    if static_libs or static_link_deps:
813      self.WriteLn('')
814      self.WriteList(static_libs + static_link_deps,
815                     'LOCAL_STATIC_LIBRARIES')
816      self.WriteLn('# Enable grouping to fix circular references')
817      self.WriteLn('LOCAL_GROUP_STATIC_LIBRARIES := true')
818    if dynamic_libs or shared_link_deps:
819      self.WriteLn('')
820      self.WriteList(dynamic_libs + shared_link_deps,
821                     'LOCAL_SHARED_LIBRARIES')
822
823
824  def WriteTarget(self, spec, configs, deps, link_deps, part_of_all,
825                  write_alias_target):
826    """Write Makefile code to produce the final target of the gyp spec.
827
828    spec, configs: input from gyp.
829    deps, link_deps: dependency lists; see ComputeDeps()
830    part_of_all: flag indicating this target is part of 'all'
831    write_alias_target: flag indicating whether to create short aliases for this
832                        target
833    """
834    self.WriteLn('### Rules for final target.')
835
836    if self.type != 'none':
837      self.WriteTargetFlags(spec, configs, link_deps)
838
839    settings = spec.get('aosp_build_settings', {})
840    if settings:
841      self.WriteLn('### Set directly by aosp_build_settings.')
842      for k, v in settings.items():
843        if isinstance(v, list):
844          self.WriteList(v, k)
845        else:
846          self.WriteLn('%s := %s' % (k, make.QuoteIfNecessary(v)))
847      self.WriteLn('')
848
849    # Add to the set of targets which represent the gyp 'all' target. We use the
850    # name 'gyp_all_modules' as the Android build system doesn't allow the use
851    # of the Make target 'all' and because 'all_modules' is the equivalent of
852    # the Make target 'all' on Android.
853    if part_of_all and write_alias_target:
854      self.WriteLn('# Add target alias to "gyp_all_modules" target.')
855      self.WriteLn('.PHONY: gyp_all_modules')
856      self.WriteLn('gyp_all_modules: %s' % self.android_module)
857      self.WriteLn('')
858
859    # Add an alias from the gyp target name to the Android module name. This
860    # simplifies manual builds of the target, and is required by the test
861    # framework.
862    if self.target != self.android_module and write_alias_target:
863      self.WriteLn('# Alias gyp target name.')
864      self.WriteLn('.PHONY: %s' % self.target)
865      self.WriteLn('%s: %s' % (self.target, self.android_module))
866      self.WriteLn('')
867
868    # Add the command to trigger build of the target type depending
869    # on the toolset. Ex: BUILD_STATIC_LIBRARY vs. BUILD_HOST_STATIC_LIBRARY
870    # NOTE: This has to come last!
871    modifier = ''
872    if self.toolset == 'host':
873      modifier = 'HOST_'
874    if self.type == 'static_library':
875      self.WriteLn('include $(BUILD_%sSTATIC_LIBRARY)' % modifier)
876    elif self.type == 'shared_library':
877      self.WriteLn('LOCAL_PRELINK_MODULE := false')
878      self.WriteLn('include $(BUILD_%sSHARED_LIBRARY)' % modifier)
879    elif self.type == 'executable':
880      self.WriteLn('LOCAL_CXX_STL := libc++_static')
881      # Executables are for build and test purposes only, so they're installed
882      # to a directory that doesn't get included in the system image.
883      self.WriteLn('LOCAL_MODULE_PATH := $(gyp_shared_intermediate_dir)')
884      self.WriteLn('include $(BUILD_%sEXECUTABLE)' % modifier)
885    else:
886      self.WriteLn('LOCAL_MODULE_PATH := $(PRODUCT_OUT)/gyp_stamp')
887      self.WriteLn('LOCAL_UNINSTALLABLE_MODULE := true')
888      if self.toolset == 'target':
889        self.WriteLn('LOCAL_2ND_ARCH_VAR_PREFIX := $(GYP_VAR_PREFIX)')
890      else:
891        self.WriteLn('LOCAL_2ND_ARCH_VAR_PREFIX := $(GYP_HOST_VAR_PREFIX)')
892      self.WriteLn()
893      self.WriteLn('include $(BUILD_SYSTEM)/base_rules.mk')
894      self.WriteLn()
895      self.WriteLn('$(LOCAL_BUILT_MODULE): $(LOCAL_ADDITIONAL_DEPENDENCIES)')
896      self.WriteLn('\t$(hide) echo "Gyp timestamp: $@"')
897      self.WriteLn('\t$(hide) mkdir -p $(dir $@)')
898      self.WriteLn('\t$(hide) touch $@')
899      self.WriteLn()
900      self.WriteLn('LOCAL_2ND_ARCH_VAR_PREFIX :=')
901
902
903  def WriteList(self, value_list, variable=None, prefix='',
904                quoter=make.QuoteIfNecessary, local_pathify=False):
905    """Write a variable definition that is a list of values.
906
907    E.g. WriteList(['a','b'], 'foo', prefix='blah') writes out
908         foo = blaha blahb
909    but in a pretty-printed style.
910    """
911    values = ''
912    if value_list:
913      value_list = [quoter(prefix + l) for l in value_list]
914      if local_pathify:
915        value_list = [self.LocalPathify(l) for l in value_list]
916      values = ' \\\n\t' + ' \\\n\t'.join(value_list)
917    self.fp.write('%s :=%s\n\n' % (variable, values))
918
919
920  def WriteLn(self, text=''):
921    self.fp.write(text + '\n')
922
923
924  def LocalPathify(self, path):
925    """Convert a subdirectory-relative path into a normalized path which starts
926    with the make variable $(LOCAL_PATH) (i.e. the top of the project tree).
927    Absolute paths, or paths that contain variables, are just normalized."""
928    if '$(' in path or os.path.isabs(path):
929      # path is not a file in the project tree in this case, but calling
930      # normpath is still important for trimming trailing slashes.
931      return os.path.normpath(path)
932    local_path = os.path.join('$(LOCAL_PATH)', self.path, path)
933    local_path = os.path.normpath(local_path)
934    # Check that normalizing the path didn't ../ itself out of $(LOCAL_PATH)
935    # - i.e. that the resulting path is still inside the project tree. The
936    # path may legitimately have ended up containing just $(LOCAL_PATH), though,
937    # so we don't look for a slash.
938    assert local_path.startswith('$(LOCAL_PATH)'), (
939           'Path %s attempts to escape from gyp path %s !)' % (path, self.path))
940    return local_path
941
942
943  def ExpandInputRoot(self, template, expansion, dirname):
944    if '%(INPUT_ROOT)s' not in template and '%(INPUT_DIRNAME)s' not in template:
945      return template
946    path = template % {
947        'INPUT_ROOT': expansion,
948        'INPUT_DIRNAME': dirname,
949        }
950    return os.path.normpath(path)
951
952
953def PerformBuild(data, configurations, params):
954  # The android backend only supports the default configuration.
955  options = params['options']
956  makefile = os.path.abspath(os.path.join(options.toplevel_dir,
957                                          'GypAndroid.mk'))
958  env = dict(os.environ)
959  env['ONE_SHOT_MAKEFILE'] = makefile
960  arguments = ['make', '-C', os.environ['ANDROID_BUILD_TOP'], 'gyp_all_modules']
961  print('Building: %s' % arguments)
962  subprocess.check_call(arguments, env=env)
963
964
965def GenerateOutput(target_list, target_dicts, data, params):
966  options = params['options']
967  generator_flags = params.get('generator_flags', {})
968  builddir_name = generator_flags.get('output_dir', 'out')
969  limit_to_target_all = generator_flags.get('limit_to_target_all', False)
970  write_alias_targets = generator_flags.get('write_alias_targets', True)
971  sdk_version = generator_flags.get('aosp_sdk_version', 0)
972  android_top_dir = os.environ.get('ANDROID_BUILD_TOP')
973  assert android_top_dir, '$ANDROID_BUILD_TOP not set; you need to run lunch.'
974
975  def CalculateMakefilePath(build_file, base_name):
976    """Determine where to write a Makefile for a given gyp file."""
977    # Paths in gyp files are relative to the .gyp file, but we want
978    # paths relative to the source root for the master makefile.  Grab
979    # the path of the .gyp file as the base to relativize against.
980    # E.g. "foo/bar" when we're constructing targets for "foo/bar/baz.gyp".
981    base_path = gyp.common.RelativePath(os.path.dirname(build_file),
982                                        options.depth)
983    # We write the file in the base_path directory.
984    output_file = os.path.join(options.depth, base_path, base_name)
985    assert not options.generator_output, (
986        'The Android backend does not support options.generator_output.')
987    base_path = gyp.common.RelativePath(os.path.dirname(build_file),
988                                        options.toplevel_dir)
989    return base_path, output_file
990
991  # TODO:  search for the first non-'Default' target.  This can go
992  # away when we add verification that all targets have the
993  # necessary configurations.
994  default_configuration = None
995  toolsets = set([target_dicts[target]['toolset'] for target in target_list])
996  for target in target_list:
997    spec = target_dicts[target]
998    if spec['default_configuration'] != 'Default':
999      default_configuration = spec['default_configuration']
1000      break
1001  if not default_configuration:
1002    default_configuration = 'Default'
1003
1004  srcdir = '.'
1005  makefile_name = 'GypAndroid' + options.suffix + '.mk'
1006  makefile_path = os.path.join(options.toplevel_dir, makefile_name)
1007  assert not options.generator_output, (
1008      'The Android backend does not support options.generator_output.')
1009  gyp.common.EnsureDirExists(makefile_path)
1010  root_makefile = open(makefile_path, 'w')
1011
1012  root_makefile.write(header)
1013
1014  # We set LOCAL_PATH just once, here, to the top of the project tree. This
1015  # allows all the other paths we use to be relative to the Android.mk file,
1016  # as the Android build system expects.
1017  root_makefile.write('\nLOCAL_PATH := $(call my-dir)\n')
1018
1019  # Find the list of targets that derive from the gyp file(s) being built.
1020  needed_targets = set()
1021  for build_file in params['build_files']:
1022    for target in gyp.common.AllTargets(target_list, target_dicts, build_file):
1023      needed_targets.add(target)
1024
1025  build_files = set()
1026  include_list = set()
1027  android_modules = {}
1028  for qualified_target in target_list:
1029    build_file, target, toolset = gyp.common.ParseQualifiedTarget(
1030        qualified_target)
1031    relative_build_file = gyp.common.RelativePath(build_file,
1032                                                  options.toplevel_dir)
1033    build_files.add(relative_build_file)
1034    included_files = data[build_file]['included_files']
1035    for included_file in included_files:
1036      # The included_files entries are relative to the dir of the build file
1037      # that included them, so we have to undo that and then make them relative
1038      # to the root dir.
1039      relative_include_file = gyp.common.RelativePath(
1040          gyp.common.UnrelativePath(included_file, build_file),
1041          options.toplevel_dir)
1042      abs_include_file = os.path.abspath(relative_include_file)
1043      # If the include file is from the ~/.gyp dir, we should use absolute path
1044      # so that relocating the src dir doesn't break the path.
1045      if (params['home_dot_gyp'] and
1046          abs_include_file.startswith(params['home_dot_gyp'])):
1047        build_files.add(abs_include_file)
1048      else:
1049        build_files.add(relative_include_file)
1050
1051    base_path, output_file = CalculateMakefilePath(build_file,
1052        target + '.' + toolset + options.suffix + '.mk')
1053
1054    spec = target_dicts[qualified_target]
1055    configs = spec['configurations']
1056
1057    part_of_all = qualified_target in needed_targets
1058    if limit_to_target_all and not part_of_all:
1059      continue
1060
1061    relative_target = gyp.common.QualifiedTarget(relative_build_file, target,
1062                                                 toolset)
1063    writer = AndroidMkWriter(android_top_dir)
1064    android_module = writer.Write(qualified_target, relative_target, base_path,
1065                                  output_file, spec, configs,
1066                                  part_of_all=part_of_all,
1067                                  write_alias_target=write_alias_targets,
1068                                  sdk_version=sdk_version)
1069    if android_module in android_modules:
1070      print('ERROR: Android module names must be unique. The following '
1071             'targets both generate Android module name %s.\n  %s\n  %s' %
1072             (android_module, android_modules[android_module],
1073              qualified_target))
1074      return
1075    android_modules[android_module] = qualified_target
1076
1077    # Our root_makefile lives at the source root.  Compute the relative path
1078    # from there to the output_file for including.
1079    mkfile_rel_path = gyp.common.RelativePath(output_file,
1080                                              os.path.dirname(makefile_path))
1081    include_list.add(mkfile_rel_path)
1082
1083  root_makefile.write('GYP_CONFIGURATION ?= %s\n' % default_configuration)
1084  root_makefile.write('GYP_VAR_PREFIX ?=\n')
1085  root_makefile.write('GYP_HOST_VAR_PREFIX ?=\n')
1086  root_makefile.write('GYP_HOST_MULTILIB ?= first\n')
1087
1088  # Write out the sorted list of includes.
1089  root_makefile.write('\n')
1090  for include_file in sorted(include_list):
1091    root_makefile.write('include $(LOCAL_PATH)/' + include_file + '\n')
1092  root_makefile.write('\n')
1093
1094  if write_alias_targets:
1095    root_makefile.write(ALL_MODULES_FOOTER)
1096
1097  root_makefile.close()
1098