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