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