Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / tools / gyp / pylib / gyp / generator / android.py
index 41346e2..4129b8e 100644 (file)
@@ -50,12 +50,14 @@ generator_supports_multiple_toolsets = True
 generator_additional_non_configuration_keys = [
     # Boolean to declare that this target does not want its name mangled.
     'android_unmangled_name',
+    # Map of android build system variables to set.
+    'aosp_build_settings',
 ]
 generator_additional_path_sections = []
 generator_extra_sources_for_rules = []
 
 
-SHARED_FOOTER = """\
+ALL_MODULES_FOOTER = """\
 # "gyp_all_modules" is a concatenation of the "gyp_all_modules" targets from
 # all the included sub-makefiles. This is just here to clarify.
 gyp_all_modules:
@@ -66,33 +68,6 @@ header = """\
 
 """
 
-android_standard_include_paths = set([
-    # JNI_H_INCLUDE in build/core/binary.mk
-    'dalvik/libnativehelper/include/nativehelper',
-    # from SRC_HEADERS in build/core/config.mk
-    'system/core/include',
-    'hardware/libhardware/include',
-    'hardware/libhardware_legacy/include',
-    'hardware/ril/include',
-    'dalvik/libnativehelper/include',
-    'frameworks/native/include',
-    'frameworks/native/opengl/include',
-    'frameworks/base/include',
-    'frameworks/base/opengl/include',
-    'frameworks/base/native/include',
-    'external/skia/include',
-    # TARGET_C_INCLUDES in build/core/combo/TARGET_linux-arm.mk
-    'bionic/libc/arch-arm/include',
-    'bionic/libc/include',
-    'bionic/libstdc++/include',
-    'bionic/libc/kernel/common',
-    'bionic/libc/kernel/arch-arm',
-    'bionic/libm/include',
-    'bionic/libm/include/arm',
-    'bionic/libthread_db/include',
-    ])
-
-
 # Map gyp target types to Android module classes.
 MODULE_CLASSES = {
     'static_library': 'STATIC_LIBRARIES',
@@ -133,7 +108,7 @@ class AndroidMkWriter(object):
     self.android_top_dir = android_top_dir
 
   def Write(self, qualified_target, relative_target, base_path, output_filename,
-            spec, configs, part_of_all):
+            spec, configs, part_of_all, write_alias_target, sdk_version):
     """The main entry point: writes a .mk file for a single target.
 
     Arguments:
@@ -144,6 +119,9 @@ class AndroidMkWriter(object):
       output_filename: output .mk file name to write
       spec, configs: gyp info
       part_of_all: flag indicating this target is part of 'all'
+      write_alias_target: flag indicating whether to create short aliases for
+                          this target
+      sdk_version: what to emit for LOCAL_SDK_VERSION in output
     """
     gyp.common.EnsureDirExists(output_filename)
 
@@ -183,14 +161,23 @@ class AndroidMkWriter(object):
     if self.android_stem != self.android_module:
       self.WriteLn('LOCAL_MODULE_STEM := ' + self.android_stem)
     self.WriteLn('LOCAL_MODULE_SUFFIX := ' + self.android_suffix)
-    self.WriteLn('LOCAL_MODULE_TAGS := optional')
     if self.toolset == 'host':
       self.WriteLn('LOCAL_IS_HOST_MODULE := true')
+      self.WriteLn('LOCAL_MULTILIB := $(GYP_HOST_MULTILIB)')
+    else:
+      self.WriteLn('LOCAL_MODULE_TARGET_ARCH := '
+                   '$(TARGET_$(GYP_VAR_PREFIX)ARCH)')
+      self.WriteLn('LOCAL_SDK_VERSION := %s' % sdk_version)
 
     # Grab output directories; needed for Actions and Rules.
-    self.WriteLn('gyp_intermediate_dir := $(call local-intermediates-dir)')
+    if self.toolset == 'host':
+      self.WriteLn('gyp_intermediate_dir := '
+                   '$(call local-intermediates-dir,,$(GYP_HOST_VAR_PREFIX))')
+    else:
+      self.WriteLn('gyp_intermediate_dir := '
+                   '$(call local-intermediates-dir,,$(GYP_VAR_PREFIX))')
     self.WriteLn('gyp_shared_intermediate_dir := '
-                 '$(call intermediates-dir-for,GYP,shared)')
+                 '$(call intermediates-dir-for,GYP,shared,,,$(GYP_VAR_PREFIX))')
     self.WriteLn()
 
     # List files this target depends on so that actions/rules/copies/sources
@@ -226,7 +213,8 @@ class AndroidMkWriter(object):
     if spec.get('sources', []) or extra_sources:
       self.WriteSources(spec, configs, extra_sources)
 
-    self.WriteTarget(spec, configs, deps, link_deps, part_of_all)
+    self.WriteTarget(spec, configs, deps, link_deps, part_of_all,
+                     write_alias_target)
 
     # Update global list of target outputs, used in dependency tracking.
     target_outputs[qualified_target] = ('path', self.output_binary)
@@ -291,6 +279,7 @@ class AndroidMkWriter(object):
       # writing duplicate dummy rules for those outputs.
       main_output = make.QuoteSpaces(self.LocalPathify(outputs[0]))
       self.WriteLn('%s: gyp_local_path := $(LOCAL_PATH)' % main_output)
+      self.WriteLn('%s: gyp_var_prefix := $(GYP_VAR_PREFIX)' % main_output)
       self.WriteLn('%s: gyp_intermediate_dir := '
                    '$(abspath $(gyp_intermediate_dir))' % main_output)
       self.WriteLn('%s: gyp_shared_intermediate_dir := '
@@ -305,12 +294,19 @@ class AndroidMkWriter(object):
       self.WriteLn('%s: export PATH := $(subst $(ANDROID_BUILD_PATHS),,$(PATH))'
                    % main_output)
 
+      # Don't allow spaces in input/output filenames, but make an exception for
+      # filenames which start with '$(' since it's okay for there to be spaces
+      # inside of make function/macro invocations.
       for input in inputs:
-        assert ' ' not in input, (
-            "Spaces in action input filenames not supported (%s)"  % input)
+        if not input.startswith('$(') and ' ' in input:
+          raise gyp.common.GypError(
+              'Action input filename "%s" in target %s contains a space' %
+              (input, self.target))
       for output in outputs:
-        assert ' ' not in output, (
-            "Spaces in action output filenames not supported (%s)"  % output)
+        if not output.startswith('$(') and ' ' in output:
+          raise gyp.common.GypError(
+              'Action output filename "%s" in target %s contains a space' %
+              (output, self.target))
 
       self.WriteLn('%s: %s $(GYP_TARGET_DEPENDENCIES)' %
                    (main_output, ' '.join(map(self.LocalPathify, inputs))))
@@ -337,13 +333,10 @@ class AndroidMkWriter(object):
     """
     if len(rules) == 0:
       return
-    rule_trigger = '%s_rule_trigger' % self.android_module
 
-    did_write_rule = False
     for rule in rules:
       if len(rule.get('rule_sources', [])) == 0:
         continue
-      did_write_rule = True
       name = make.StringToMakefileVariable('%s_%s' % (self.relative_target,
                                                       rule['rule_name']))
       self.WriteLn('\n### Generated for rule "%s":' % name)
@@ -391,6 +384,7 @@ class AndroidMkWriter(object):
         outputs = map(self.LocalPathify, outputs)
         main_output = outputs[0]
         self.WriteLn('%s: gyp_local_path := $(LOCAL_PATH)' % main_output)
+        self.WriteLn('%s: gyp_var_prefix := $(GYP_VAR_PREFIX)' % main_output)
         self.WriteLn('%s: gyp_intermediate_dir := '
                      '$(abspath $(gyp_intermediate_dir))' % main_output)
         self.WriteLn('%s: gyp_shared_intermediate_dir := '
@@ -412,13 +406,9 @@ class AndroidMkWriter(object):
           # Make each output depend on the main output, with an empty command
           # to force make to notice that the mtime has changed.
           self.WriteLn('%s: %s ;' % (output, main_output))
-        self.WriteLn('.PHONY: %s' % (rule_trigger))
-        self.WriteLn('%s: %s' % (rule_trigger, main_output))
-        self.WriteLn('')
-    if did_write_rule:
-      extra_sources.append(rule_trigger)  # Force all rules to run.
-      self.WriteLn('### Finished generating for all rules')
-      self.WriteLn('')
+        self.WriteLn()
+
+    self.WriteLn()
 
 
   def WriteCopies(self, copies, extra_outputs):
@@ -501,6 +491,9 @@ class AndroidMkWriter(object):
     self.WriteLn('LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) '
                                      '$(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))')
     self.WriteLn('LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))')
+    # Android uses separate flags for assembly file invocations, but gyp expects
+    # the same CFLAGS to be applied:
+    self.WriteLn('LOCAL_ASFLAGS := $(LOCAL_CFLAGS)')
 
 
   def WriteSources(self, spec, configs, extra_sources):
@@ -609,16 +602,16 @@ class AndroidMkWriter(object):
       prefix = ''
 
     if spec['toolset'] == 'host':
-      suffix = '_host_gyp'
+      suffix = '_$(TARGET_$(GYP_VAR_PREFIX)ARCH)_host_gyp'
     else:
       suffix = '_gyp'
 
     if self.path:
-      name = '%s%s_%s%s' % (prefix, self.path, self.target, suffix)
+      middle = make.StringToMakefileVariable('%s_%s' % (self.path, self.target))
     else:
-      name = '%s%s%s' % (prefix, self.target, suffix)
+      middle = make.StringToMakefileVariable(self.target)
 
-    return make.StringToMakefileVariable(name)
+    return ''.join([prefix, middle, suffix])
 
 
   def ComputeOutputParts(self, spec):
@@ -672,32 +665,31 @@ class AndroidMkWriter(object):
     E.g., the loadable module 'foobar' in directory 'baz' will produce
       '$(obj)/baz/libfoobar.so'
     """
-    if self.type == 'executable' and self.toolset == 'host':
+    if self.type == 'executable':
       # We install host executables into shared_intermediate_dir so they can be
       # run by gyp rules that refer to PRODUCT_DIR.
       path = '$(gyp_shared_intermediate_dir)'
     elif self.type == 'shared_library':
       if self.toolset == 'host':
-        path = '$(HOST_OUT_INTERMEDIATE_LIBRARIES)'
+        path = '$($(GYP_HOST_VAR_PREFIX)HOST_OUT_INTERMEDIATE_LIBRARIES)'
       else:
-        path = '$(TARGET_OUT_INTERMEDIATE_LIBRARIES)'
+        path = '$($(GYP_VAR_PREFIX)TARGET_OUT_INTERMEDIATE_LIBRARIES)'
     else:
       # Other targets just get built into their intermediate dir.
       if self.toolset == 'host':
-        path = '$(call intermediates-dir-for,%s,%s,true)' % (self.android_class,
-                                                            self.android_module)
+        path = ('$(call intermediates-dir-for,%s,%s,true,,'
+                '$(GYP_HOST_VAR_PREFIX))' % (self.android_class,
+                                             self.android_module))
       else:
-        path = '$(call intermediates-dir-for,%s,%s)' % (self.android_class,
-                                                        self.android_module)
+        path = ('$(call intermediates-dir-for,%s,%s,,,$(GYP_VAR_PREFIX))'
+                % (self.android_class, self.android_module))
 
     assert spec.get('product_dir') is None # TODO: not supported?
     return os.path.join(path, self.ComputeOutputBasename(spec))
 
   def NormalizeIncludePaths(self, include_paths):
     """ Normalize include_paths.
-    Convert absolute paths to relative to the Android top directory;
-    filter out include paths that are already brought in by the Android build
-    system.
+    Convert absolute paths to relative to the Android top directory.
 
     Args:
       include_paths: A list of unprocessed include paths.
@@ -708,10 +700,7 @@ class AndroidMkWriter(object):
     for path in include_paths:
       if path[0] == '/':
         path = gyp.common.RelativePath(path, self.android_top_dir)
-
-      # Filter out the Android standard search path.
-      if path not in android_standard_include_paths:
-        normalized.append(path)
+      normalized.append(path)
     return normalized
 
   def ExtractIncludesFromCFlags(self, cflags):
@@ -732,16 +721,20 @@ class AndroidMkWriter(object):
 
     return (clean_cflags, include_paths)
 
-  def ComputeAndroidLibraryModuleNames(self, libraries):
-    """Compute the Android module names from libraries, ie spec.get('libraries')
+  def FilterLibraries(self, libraries):
+    """Filter the 'libraries' key to separate things that shouldn't be ldflags.
+
+    Library entries that look like filenames should be converted to android
+    module names instead of being passed to the linker as flags.
 
     Args:
       libraries: the value of spec.get('libraries')
     Returns:
-      A tuple (static_lib_modules, dynamic_lib_modules)
+      A tuple (static_lib_modules, dynamic_lib_modules, ldflags)
     """
     static_lib_modules = []
     dynamic_lib_modules = []
+    ldflags = []
     for libs in libraries:
       # Libs can have multiple words.
       for lib in libs.split():
@@ -758,13 +751,9 @@ class AndroidMkWriter(object):
         if match:
           dynamic_lib_modules.append(match.group(1))
           continue
-        # "-lstlport" -> libstlport
         if lib.startswith('-l'):
-          if lib.endswith('_static'):
-            static_lib_modules.append('lib' + lib[2:])
-          else:
-            dynamic_lib_modules.append('lib' + lib[2:])
-    return (static_lib_modules, dynamic_lib_modules)
+          ldflags.append(lib)
+    return (static_lib_modules, dynamic_lib_modules, ldflags)
 
 
   def ComputeDeps(self, spec):
@@ -792,47 +781,74 @@ class AndroidMkWriter(object):
     spec, configs: input from gyp.
     link_deps: link dependency list; see ComputeDeps()
     """
-    for configname, config in sorted(configs.iteritems()):
-      ldflags = list(config.get('ldflags', []))
-      self.WriteLn('')
-      self.WriteList(ldflags, 'LOCAL_LDFLAGS_%s' % configname)
-    self.WriteLn('\nLOCAL_LDFLAGS := $(LOCAL_LDFLAGS_$(GYP_CONFIGURATION))')
-
     # Libraries (i.e. -lfoo)
+    # These must be included even for static libraries as some of them provide
+    # implicit include paths through the build system.
     libraries = gyp.common.uniquer(spec.get('libraries', []))
-    static_libs, dynamic_libs = self.ComputeAndroidLibraryModuleNames(
-        libraries)
-
-    # Link dependencies (i.e. libfoo.a, libfoo.so)
-    static_link_deps = [x[1] for x in link_deps if x[0] == 'static']
-    shared_link_deps = [x[1] for x in link_deps if x[0] == 'shared']
-    self.WriteLn('')
-    self.WriteList(static_libs + static_link_deps,
-                   'LOCAL_STATIC_LIBRARIES')
-    self.WriteLn('# Enable grouping to fix circular references')
-    self.WriteLn('LOCAL_GROUP_STATIC_LIBRARIES := true')
-    self.WriteLn('')
-    self.WriteList(dynamic_libs + shared_link_deps,
-                   'LOCAL_SHARED_LIBRARIES')
-
-
-  def WriteTarget(self, spec, configs, deps, link_deps, part_of_all):
+    static_libs, dynamic_libs, ldflags_libs = self.FilterLibraries(libraries)
+
+    if self.type != 'static_library':
+      for configname, config in sorted(configs.iteritems()):
+        ldflags = list(config.get('ldflags', []))
+        self.WriteLn('')
+        self.WriteList(ldflags, 'LOCAL_LDFLAGS_%s' % configname)
+      self.WriteList(ldflags_libs, 'LOCAL_GYP_LIBS')
+      self.WriteLn('LOCAL_LDFLAGS := $(LOCAL_LDFLAGS_$(GYP_CONFIGURATION)) '
+                   '$(LOCAL_GYP_LIBS)')
+
+    # Link dependencies (i.e. other gyp targets this target depends on)
+    # These need not be included for static libraries as within the gyp build
+    # we do not use the implicit include path mechanism.
+    if self.type != 'static_library':
+      static_link_deps = [x[1] for x in link_deps if x[0] == 'static']
+      shared_link_deps = [x[1] for x in link_deps if x[0] == 'shared']
+    else:
+      static_link_deps = []
+      shared_link_deps = []
+
+    # Only write the lists if they are non-empty.
+    if static_libs or static_link_deps:
+      self.WriteLn('')
+      self.WriteList(static_libs + static_link_deps,
+                     'LOCAL_STATIC_LIBRARIES')
+      self.WriteLn('# Enable grouping to fix circular references')
+      self.WriteLn('LOCAL_GROUP_STATIC_LIBRARIES := true')
+    if dynamic_libs or shared_link_deps:
+      self.WriteLn('')
+      self.WriteList(dynamic_libs + shared_link_deps,
+                     'LOCAL_SHARED_LIBRARIES')
+
+
+  def WriteTarget(self, spec, configs, deps, link_deps, part_of_all,
+                  write_alias_target):
     """Write Makefile code to produce the final target of the gyp spec.
 
     spec, configs: input from gyp.
     deps, link_deps: dependency lists; see ComputeDeps()
     part_of_all: flag indicating this target is part of 'all'
+    write_alias_target: flag indicating whether to create short aliases for this
+                        target
     """
     self.WriteLn('### Rules for final target.')
 
     if self.type != 'none':
       self.WriteTargetFlags(spec, configs, link_deps)
 
+    settings = spec.get('aosp_build_settings', {})
+    if settings:
+      self.WriteLn('### Set directly by aosp_build_settings.')
+      for k, v in settings.iteritems():
+        if isinstance(v, list):
+          self.WriteList(v, k)
+        else:
+          self.WriteLn('%s := %s' % (k, make.QuoteIfNecessary(v)))
+      self.WriteLn('')
+
     # Add to the set of targets which represent the gyp 'all' target. We use the
     # name 'gyp_all_modules' as the Android build system doesn't allow the use
     # of the Make target 'all' and because 'all_modules' is the equivalent of
     # the Make target 'all' on Android.
-    if part_of_all:
+    if part_of_all and write_alias_target:
       self.WriteLn('# Add target alias to "gyp_all_modules" target.')
       self.WriteLn('.PHONY: gyp_all_modules')
       self.WriteLn('gyp_all_modules: %s' % self.android_module)
@@ -841,7 +857,7 @@ class AndroidMkWriter(object):
     # Add an alias from the gyp target name to the Android module name. This
     # simplifies manual builds of the target, and is required by the test
     # framework.
-    if self.target != self.android_module:
+    if self.target != self.android_module and write_alias_target:
       self.WriteLn('# Alias gyp target name.')
       self.WriteLn('.PHONY: %s' % self.target)
       self.WriteLn('%s: %s' % (self.target, self.android_module))
@@ -859,17 +875,17 @@ class AndroidMkWriter(object):
       self.WriteLn('LOCAL_PRELINK_MODULE := false')
       self.WriteLn('include $(BUILD_%sSHARED_LIBRARY)' % modifier)
     elif self.type == 'executable':
-      if self.toolset == 'host':
-        self.WriteLn('LOCAL_MODULE_PATH := $(gyp_shared_intermediate_dir)')
-      else:
-        # Don't install target executables for now, as it results in them being
-        # included in ROM. This can be revisited if there's a reason to install
-        # them later.
-        self.WriteLn('LOCAL_UNINSTALLABLE_MODULE := true')
+      # Executables are for build and test purposes only, so they're installed
+      # to a directory that doesn't get included in the system image.
+      self.WriteLn('LOCAL_MODULE_PATH := $(gyp_shared_intermediate_dir)')
       self.WriteLn('include $(BUILD_%sEXECUTABLE)' % modifier)
     else:
       self.WriteLn('LOCAL_MODULE_PATH := $(PRODUCT_OUT)/gyp_stamp')
       self.WriteLn('LOCAL_UNINSTALLABLE_MODULE := true')
+      if self.toolset == 'target':
+        self.WriteLn('LOCAL_2ND_ARCH_VAR_PREFIX := $(GYP_VAR_PREFIX)')
+      else:
+        self.WriteLn('LOCAL_2ND_ARCH_VAR_PREFIX := $(GYP_HOST_VAR_PREFIX)')
       self.WriteLn()
       self.WriteLn('include $(BUILD_SYSTEM)/base_rules.mk')
       self.WriteLn()
@@ -877,6 +893,8 @@ class AndroidMkWriter(object):
       self.WriteLn('\t$(hide) echo "Gyp timestamp: $@"')
       self.WriteLn('\t$(hide) mkdir -p $(dir $@)')
       self.WriteLn('\t$(hide) touch $@')
+      self.WriteLn()
+      self.WriteLn('LOCAL_2ND_ARCH_VAR_PREFIX :=')
 
 
   def WriteList(self, value_list, variable=None, prefix='',
@@ -926,7 +944,7 @@ class AndroidMkWriter(object):
         'INPUT_ROOT': expansion,
         'INPUT_DIRNAME': dirname,
         }
-    return path
+    return os.path.normpath(path)
 
 
 def PerformBuild(data, configurations, params):
@@ -946,6 +964,8 @@ def GenerateOutput(target_list, target_dicts, data, params):
   generator_flags = params.get('generator_flags', {})
   builddir_name = generator_flags.get('output_dir', 'out')
   limit_to_target_all = generator_flags.get('limit_to_target_all', False)
+  write_alias_targets = generator_flags.get('write_alias_targets', True)
+  sdk_version = generator_flags.get('aosp_sdk_version', 19)
   android_top_dir = os.environ.get('ANDROID_BUILD_TOP')
   assert android_top_dir, '$ANDROID_BUILD_TOP not set; you need to run lunch.'
 
@@ -1041,7 +1061,9 @@ def GenerateOutput(target_list, target_dicts, data, params):
     writer = AndroidMkWriter(android_top_dir)
     android_module = writer.Write(qualified_target, relative_target, base_path,
                                   output_file, spec, configs,
-                                  part_of_all=part_of_all)
+                                  part_of_all=part_of_all,
+                                  write_alias_target=write_alias_targets,
+                                  sdk_version=sdk_version)
     if android_module in android_modules:
       print ('ERROR: Android module names must be unique. The following '
              'targets both generate Android module name %s.\n  %s\n  %s' %
@@ -1057,6 +1079,9 @@ def GenerateOutput(target_list, target_dicts, data, params):
     include_list.add(mkfile_rel_path)
 
   root_makefile.write('GYP_CONFIGURATION ?= %s\n' % default_configuration)
+  root_makefile.write('GYP_VAR_PREFIX ?=\n')
+  root_makefile.write('GYP_HOST_VAR_PREFIX ?=\n')
+  root_makefile.write('GYP_HOST_MULTILIB ?=\n')
 
   # Write out the sorted list of includes.
   root_makefile.write('\n')
@@ -1064,6 +1089,7 @@ def GenerateOutput(target_list, target_dicts, data, params):
     root_makefile.write('include $(LOCAL_PATH)/' + include_file + '\n')
   root_makefile.write('\n')
 
-  root_makefile.write(SHARED_FOOTER)
+  if write_alias_targets:
+    root_makefile.write(ALL_MODULES_FOOTER)
 
   root_makefile.close()