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