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:
"""
-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',
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:
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)
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
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)
# 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 := '
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))))
"""
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)
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 := '
# 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):
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):
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):
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.
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):
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():
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):
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)
# 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))
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()
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='',
'INPUT_ROOT': expansion,
'INPUT_DIRNAME': dirname,
}
- return path
+ return os.path.normpath(path)
def PerformBuild(data, configurations, 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.'
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' %
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')
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()