initial import
[vuplus_webkit] / Source / ThirdParty / gyp / pylib / gyp / generator / make.py
1 #!/usr/bin/python
2
3 # Copyright (c) 2009 Google Inc. All rights reserved.
4 # Use of this source code is governed by a BSD-style license that can be
5 # found in the LICENSE file.
6
7 # Notes:
8 #
9 # This is all roughly based on the Makefile system used by the Linux
10 # kernel, but is a non-recursive make -- we put the entire dependency
11 # graph in front of make and let it figure it out.
12 #
13 # The code below generates a separate .mk file for each target, but
14 # all are sourced by the top-level Makefile.  This means that all
15 # variables in .mk-files clobber one another.  Be careful to use :=
16 # where appropriate for immediate evaluation, and similarly to watch
17 # that you're not relying on a variable value to last beween different
18 # .mk files.
19 #
20 # TODOs:
21 #
22 # Global settings and utility functions are currently stuffed in the
23 # toplevel Makefile.  It may make sense to generate some .mk files on
24 # the side to keep the the files readable.
25
26 import gyp
27 import gyp.common
28 import gyp.system_test
29 import os.path
30 import os
31
32 # Debugging-related imports -- remove me once we're solid.
33 import code
34 import pprint
35
36 generator_default_variables = {
37   'EXECUTABLE_PREFIX': '',
38   'EXECUTABLE_SUFFIX': '',
39   'OS': 'linux',
40   'STATIC_LIB_PREFIX': 'lib',
41   'SHARED_LIB_PREFIX': 'lib',
42   'STATIC_LIB_SUFFIX': '.a',
43   'SHARED_LIB_SUFFIX': '.so',
44   'INTERMEDIATE_DIR': '$(obj).$(TOOLSET)/geni',
45   'SHARED_INTERMEDIATE_DIR': '$(obj)/gen',
46   'PRODUCT_DIR': '$(builddir)',
47   'SHARED_LIB_DIR': '$(builddir)/lib.$(TOOLSET)',
48   'LIB_DIR': '$(obj).$(TOOLSET)',
49   'RULE_INPUT_ROOT': '%(INPUT_ROOT)s',  # This gets expanded by Python.
50   'RULE_INPUT_PATH': '$(abspath $<)',
51   'RULE_INPUT_EXT': '$(suffix $<)',
52   'RULE_INPUT_NAME': '$(notdir $<)',
53
54   # This appears unused --- ?
55   'CONFIGURATION_NAME': '$(BUILDTYPE)',
56 }
57
58 # Make supports multiple toolsets
59 generator_supports_multiple_toolsets = True
60
61 def ensure_directory_exists(path):
62   dir = os.path.dirname(path)
63   if dir and not os.path.exists(dir):
64     os.makedirs(dir)
65
66 # Header of toplevel Makefile.
67 # This should go into the build tree, but it's easier to keep it here for now.
68 SHARED_HEADER = ("""\
69 # We borrow heavily from the kernel build setup, though we are simpler since
70 # we don't have Kconfig tweaking settings on us.
71
72 # The implicit make rules have it looking for RCS files, among other things.
73 # We instead explicitly write all the rules we care about.
74 # It's even quicker (saves ~200ms) to pass -r on the command line.
75 MAKEFLAGS=-r
76
77 # The source directory tree.
78 srcdir := %(srcdir)s
79
80 # The name of the builddir.
81 builddir_name ?= %(builddir)s
82
83 # The V=1 flag on command line makes us verbosely print command lines.
84 ifdef V
85   quiet=
86 else
87   quiet=quiet_
88 endif
89
90 # Specify BUILDTYPE=Release on the command line for a release build.
91 BUILDTYPE ?= %(default_configuration)s
92
93 # Directory all our build output goes into.
94 # Note that this must be two directories beneath src/ for unit tests to pass,
95 # as they reach into the src/ directory for data with relative paths.
96 builddir ?= $(builddir_name)/$(BUILDTYPE)
97 abs_builddir := $(abspath $(builddir))
98 depsdir := $(builddir)/.deps
99
100 # Object output directory.
101 obj := $(builddir)/obj
102 abs_obj := $(abspath $(obj))
103
104 # We build up a list of every single one of the targets so we can slurp in the
105 # generated dependency rule Makefiles in one pass.
106 all_deps :=
107
108 # C++ apps need to be linked with g++.  Not sure what's appropriate.
109 #
110 # Note, the flock is used to seralize linking. Linking is a memory-intensive
111 # process so running parallel links can often lead to thrashing.  To disable
112 # the serialization, override LINK via an envrionment variable as follows:
113 #
114 #   export LINK="$(CXX)"
115 #
116 # This will allow make to invoke N linker processes as specified in -jN.
117 LINK ?= flock $(builddir)/linker.lock $(CXX) %(LINK_flags)s
118
119 CC.target ?= $(CC)
120 CFLAGS.target ?= $(CFLAGS)
121 CXX.target ?= $(CXX)
122 CXXFLAGS.target ?= $(CXXFLAGS)
123 LINK.target ?= $(LINK)
124 LDFLAGS.target ?= $(LDFLAGS)
125 AR.target ?= $(AR)
126 ARFLAGS.target ?= %(ARFLAGS.target)s
127
128 # N.B.: the logic of which commands to run should match the computation done
129 # in gyp's make.py where ARFLAGS.host etc. is computed.
130 # TODO(evan): move all cross-compilation logic to gyp-time so we don't need
131 # to replicate this environment fallback in make as well.
132 CC.host ?= gcc
133 CFLAGS.host ?=
134 CXX.host ?= g++
135 CXXFLAGS.host ?=
136 LINK.host ?= g++
137 LDFLAGS.host ?=
138 AR.host ?= ar
139 ARFLAGS.host := %(ARFLAGS.host)s
140
141 # Flags to make gcc output dependency info.  Note that you need to be
142 # careful here to use the flags that ccache and distcc can understand.
143 # We write to a dep file on the side first and then rename at the end
144 # so we can't end up with a broken dep file.
145 depfile = $(depsdir)/$@.d
146 DEPFLAGS = -MMD -MF $(depfile).raw
147
148 # We have to fixup the deps output in a few ways.
149 # (1) the file output should mention the proper .o file.
150 # ccache or distcc lose the path to the target, so we convert a rule of
151 # the form:
152 #   foobar.o: DEP1 DEP2
153 # into
154 #   path/to/foobar.o: DEP1 DEP2
155 # (2) we want missing files not to cause us to fail to build.
156 # We want to rewrite
157 #   foobar.o: DEP1 DEP2 \\
158 #               DEP3
159 # to
160 #   DEP1:
161 #   DEP2:
162 #   DEP3:
163 # so if the files are missing, they're just considered phony rules.
164 # We have to do some pretty insane escaping to get those backslashes
165 # and dollar signs past make, the shell, and sed at the same time."""
166 r"""
167 define fixup_dep
168 # The depfile may not exist if the input file didn't have any #includes.
169 touch $(depfile).raw
170 # Fixup path as in (1).
171 sed -e "s|^$(notdir $@)|$@|" $(depfile).raw >> $(depfile)
172 # Add extra rules as in (2).
173 # We remove slashes and replace spaces with new lines;
174 # remove blank lines;
175 # delete the first line and append a colon to the remaining lines.
176 sed -e 's|\\||' -e 'y| |\n|' $(depfile).raw |\
177   grep -v '^$$'                             |\
178   sed -e 1d -e 's|$$|:|'                     \
179     >> $(depfile)
180 rm $(depfile).raw
181 endef
182 """
183 """
184 # Command definitions:
185 # - cmd_foo is the actual command to run;
186 # - quiet_cmd_foo is the brief-output summary of the command.
187
188 quiet_cmd_cc = CC($(TOOLSET)) $@
189 cmd_cc = $(CC.$(TOOLSET)) $(GYP_CFLAGS) $(DEPFLAGS) $(CFLAGS.$(TOOLSET)) -c -o $@ $<
190
191 quiet_cmd_cxx = CXX($(TOOLSET)) $@
192 cmd_cxx = $(CXX.$(TOOLSET)) $(GYP_CXXFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $<
193
194 quiet_cmd_alink = AR($(TOOLSET)) $@
195 cmd_alink = rm -f $@ && $(AR.$(TOOLSET)) $(ARFLAGS.$(TOOLSET)) $@ $(filter %%.o,$^)
196
197 quiet_cmd_touch = TOUCH $@
198 cmd_touch = touch $@
199
200 quiet_cmd_copy = COPY $@
201 # send stderr to /dev/null to ignore messages when linking directories.
202 cmd_copy = ln -f $< $@ 2>/dev/null || cp -af $< $@
203
204 # Due to circular dependencies between libraries :(, we wrap the
205 # special "figure out circular dependencies" flags around the entire
206 # input list during linking.
207 quiet_cmd_link = LINK($(TOOLSET)) $@
208 cmd_link = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ -Wl,--start-group $(filter-out FORCE_DO_CMD, $^) -Wl,--end-group $(LIBS)
209
210 # Shared-object link (for generating .so).
211 # Set SONAME to the library filename so our binaries don't reference the local,
212 # absolute paths used on the link command-line.
213 # TODO: perhaps this can share with the LINK command above?
214 quiet_cmd_solink = SOLINK($(TOOLSET)) $@
215 cmd_solink = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -Wl,-soname=$(@F) -o $@ -Wl,--start-group $(filter-out FORCE_DO_CMD, $^) -Wl,--end-group $(LIBS)
216 """
217 r"""
218 # Define an escape_quotes function to escape single quotes.
219 # This allows us to handle quotes properly as long as we always use
220 # use single quotes and escape_quotes.
221 escape_quotes = $(subst ','\'',$(1))
222 # This comment is here just to include a ' to unconfuse syntax highlighting.
223 # Define an escape_vars function to escape '$' variable syntax.
224 # This allows us to read/write command lines with shell variables (e.g.
225 # $LD_LIBRARY_PATH), without triggering make substitution.
226 escape_vars = $(subst $$,$$$$,$(1))
227 # Helper that expands to a shell command to echo a string exactly as it is in
228 # make. This uses printf instead of echo because printf's behaviour with respect
229 # to escape sequences is more portable than echo's across different shells
230 # (e.g., dash, bash).
231 exact_echo = printf '%%s\n' '$(call escape_quotes,$(1))'
232 """
233 """
234 # Helper to compare the command we're about to run against the command
235 # we logged the last time we ran the command.  Produces an empty
236 # string (false) when the commands match.
237 # Tricky point: Make has no string-equality test function.
238 # The kernel uses the following, but it seems like it would have false
239 # positives, where one string reordered its arguments.
240 #   arg_check = $(strip $(filter-out $(cmd_$(1)), $(cmd_$@)) \\
241 #                       $(filter-out $(cmd_$@), $(cmd_$(1))))
242 # We instead substitute each for the empty string into the other, and
243 # say they're equal if both substitutions produce the empty string.
244 command_changed = $(or $(subst $(cmd_$(1)),,$(cmd_$@)),\\
245                        $(subst $(cmd_$@),,$(cmd_$(1))))
246
247 # Helper that is non-empty when a prerequisite changes.
248 # Normally make does this implicitly, but we force rules to always run
249 # so we can check their command lines.
250 #   $? -- new prerequisites
251 #   $| -- order-only dependencies
252 prereq_changed = $(filter-out $|,$?)
253
254 # do_cmd: run a command via the above cmd_foo names, if necessary.
255 # Should always run for a given target to handle command-line changes.
256 # Second argument, if non-zero, makes it do asm/C/C++ dependency munging.
257 define do_cmd
258 $(if $(or $(command_changed),$(prereq_changed)),
259   @$(call exact_echo,  $($(quiet)cmd_$(1)))
260   @mkdir -p $(dir $@) $(dir $(depfile))
261   @$(cmd_$(1))
262   @$(call exact_echo,$(call escape_vars,cmd_$@ := $(cmd_$(1)))) > $(depfile)
263   @$(if $(2),$(fixup_dep))
264 )
265 endef
266
267 # Declare "all" target first so it is the default, even though we don't have the
268 # deps yet.
269 .PHONY: all
270 all:
271
272 # Use FORCE_DO_CMD to force a target to run.  Should be coupled with
273 # do_cmd.
274 .PHONY: FORCE_DO_CMD
275 FORCE_DO_CMD:
276
277 """)
278
279 ROOT_HEADER_SUFFIX_RULES = ("""\
280 # Suffix rules, putting all outputs into $(obj).
281 $(obj).$(TOOLSET)/%.o: $(srcdir)/%.c FORCE_DO_CMD
282         @$(call do_cmd,cc,1)
283 $(obj).$(TOOLSET)/%.o: $(srcdir)/%.s FORCE_DO_CMD
284         @$(call do_cmd,cc,1)
285 $(obj).$(TOOLSET)/%.o: $(srcdir)/%.S FORCE_DO_CMD
286         @$(call do_cmd,cc,1)
287 $(obj).$(TOOLSET)/%.o: $(srcdir)/%.cpp FORCE_DO_CMD
288         @$(call do_cmd,cxx,1)
289 $(obj).$(TOOLSET)/%.o: $(srcdir)/%.cc FORCE_DO_CMD
290         @$(call do_cmd,cxx,1)
291 $(obj).$(TOOLSET)/%.o: $(srcdir)/%.cxx FORCE_DO_CMD
292         @$(call do_cmd,cxx,1)
293
294 # Try building from generated source, too.
295 $(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.c FORCE_DO_CMD
296         @$(call do_cmd,cc,1)
297 $(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.s FORCE_DO_CMD
298         @$(call do_cmd,cc,1)
299 $(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.S FORCE_DO_CMD
300         @$(call do_cmd,cc,1)
301 $(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cc FORCE_DO_CMD
302         @$(call do_cmd,cxx,1)
303 $(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cpp FORCE_DO_CMD
304         @$(call do_cmd,cxx,1)
305 $(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cxx FORCE_DO_CMD
306         @$(call do_cmd,cxx,1)
307
308 $(obj).$(TOOLSET)/%.o: $(obj)/%.c FORCE_DO_CMD
309         @$(call do_cmd,cc,1)
310 $(obj).$(TOOLSET)/%.o: $(obj)/%.s FORCE_DO_CMD
311         @$(call do_cmd,cc,1)
312 $(obj).$(TOOLSET)/%.o: $(obj)/%.S FORCE_DO_CMD
313         @$(call do_cmd,cc,1)
314 $(obj).$(TOOLSET)/%.o: $(obj)/%.cc FORCE_DO_CMD
315         @$(call do_cmd,cxx,1)
316 $(obj).$(TOOLSET)/%.o: $(obj)/%.cpp FORCE_DO_CMD
317         @$(call do_cmd,cxx,1)
318 $(obj).$(TOOLSET)/%.o: $(obj)/%.cxx FORCE_DO_CMD
319         @$(call do_cmd,cxx,1)
320 """)
321
322 SHARED_HEADER_SUFFIX_RULES_COMMENT1 = ("""\
323 # Suffix rules, putting all outputs into $(obj).
324 """)
325
326 SHARED_HEADER_SUFFIX_RULES_SRCDIR = {
327     '.c': ("""\
328 $(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.c FORCE_DO_CMD
329         @$(call do_cmd,cc,1)
330 """),
331     '.s': ("""\
332 $(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.s FORCE_DO_CMD
333         @$(call do_cmd,cc,1)
334 """),
335     '.S': ("""\
336 $(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.S FORCE_DO_CMD
337         @$(call do_cmd,cc,1)
338 """),
339     '.cpp': ("""\
340 $(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.cpp FORCE_DO_CMD
341         @$(call do_cmd,cxx,1)
342 """),
343     '.cc': ("""\
344 $(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.cc FORCE_DO_CMD
345         @$(call do_cmd,cxx,1)
346 """),
347     '.cxx': ("""\
348 $(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.cxx FORCE_DO_CMD
349         @$(call do_cmd,cxx,1)
350 """),
351 }
352
353 SHARED_HEADER_SUFFIX_RULES_COMMENT2 = ("""\
354 # Try building from generated source, too.
355 """)
356
357 SHARED_HEADER_SUFFIX_RULES_OBJDIR1 = {
358     '.c': ("""\
359 $(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj).$(TOOLSET)/%.c FORCE_DO_CMD
360         @$(call do_cmd,cc,1)
361 """),
362     '.cc': ("""\
363 $(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj).$(TOOLSET)/%.cc FORCE_DO_CMD
364         @$(call do_cmd,cxx,1)
365 """),
366     '.cpp': ("""\
367 $(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj).$(TOOLSET)/%.cpp FORCE_DO_CMD
368         @$(call do_cmd,cxx,1)
369 """),
370 }
371
372 SHARED_HEADER_SUFFIX_RULES_OBJDIR2 = {
373     '.c': ("""\
374 $(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.c FORCE_DO_CMD
375         @$(call do_cmd,cc,1)
376 """),
377     '.cc': ("""\
378 $(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.cc FORCE_DO_CMD
379         @$(call do_cmd,cxx,1)
380 """),
381     '.cpp': ("""\
382 $(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.cpp FORCE_DO_CMD
383         @$(call do_cmd,cxx,1)
384 """),
385 }
386
387 SHARED_HEADER_SUFFIX_RULES = (
388     SHARED_HEADER_SUFFIX_RULES_COMMENT1 +
389     ''.join(SHARED_HEADER_SUFFIX_RULES_SRCDIR.values()) +
390     SHARED_HEADER_SUFFIX_RULES_COMMENT2 +
391     ''.join(SHARED_HEADER_SUFFIX_RULES_OBJDIR1.values()) +
392     ''.join(SHARED_HEADER_SUFFIX_RULES_OBJDIR2.values())
393 )
394
395 SHARED_FOOTER = """\
396 # "all" is a concatenation of the "all" targets from all the included
397 # sub-makefiles. This is just here to clarify.
398 all:
399
400 # Add in dependency-tracking rules.  $(all_deps) is the list of every single
401 # target in our tree.  First, only consider targets that already have been
402 # built, as unbuilt targets will be built regardless of dependency info:
403 all_deps := $(wildcard $(sort $(all_deps)))
404 # Of those, only consider the ones with .d (dependency) info:
405 d_files := $(wildcard $(foreach f,$(all_deps),$(depsdir)/$(f).d))
406 ifneq ($(d_files),)
407   # Rather than include each individual .d file, concatenate them into a
408   # single file which make is able to load faster.  We split this into
409   # commands that take 1000 files at a time to avoid overflowing the
410   # command line.
411   $(shell cat $(wordlist 1,1000,$(d_files)) > $(depsdir)/all.deps)
412 %(generate_all_deps)s
413   # make looks for ways to re-generate included makefiles, but in our case, we
414   # don't have a direct way. Explicitly telling make that it has nothing to do
415   # for them makes it go faster.
416   $(depsdir)/all.deps: ;
417
418   include $(depsdir)/all.deps
419 endif
420 """
421
422 header = """\
423 # This file is generated by gyp; do not edit.
424
425 """
426
427
428 def Compilable(filename):
429   """Return true if the file is compilable (should be in OBJS)."""
430   for res in (filename.endswith(e) for e
431              in ['.c', '.cc', '.cpp', '.cxx', '.s', '.S']):
432     if res:
433       return True
434   return False
435
436
437 def Linkable(filename):
438   """Return true if the file is linkable (should be on the link line)."""
439   return filename.endswith('.o')
440
441
442 def Target(filename):
443   """Translate a compilable filename to its .o target."""
444   return os.path.splitext(filename)[0] + '.o'
445
446
447 def EscapeShellArgument(s):
448   """Quotes an argument so that it will be interpreted literally by a POSIX
449      shell. Taken from
450      http://stackoverflow.com/questions/35817/whats-the-best-way-to-escape-ossystem-calls-in-python
451      """
452   return "'" + s.replace("'", "'\\''") + "'"
453
454
455 def EscapeMakeVariableExpansion(s):
456   """Make has its own variable expansion syntax using $. We must escape it for
457      string to be interpreted literally."""
458   return s.replace('$', '$$')
459
460
461 def EscapeCppDefine(s):
462   """Escapes a CPP define so that it will reach the compiler unaltered."""
463   s = EscapeShellArgument(s)
464   s = EscapeMakeVariableExpansion(s)
465   return s
466
467
468 def QuoteIfNecessary(string):
469   """TODO: Should this ideally be replaced with one or more of the above
470      functions?"""
471   if '"' in string:
472     string = '"' + string.replace('"', '\\"') + '"'
473   return string
474
475
476 def StringToMakefileVariable(string):
477   """Convert a string to a value that is acceptable as a make variable name."""
478   # TODO: replace other metacharacters that we encounter.
479   return string.replace(' ', '_')
480
481
482 srcdir_prefix = ''
483 def Sourceify(path):
484   """Convert a path to its source directory form."""
485   if '$(' in path:
486     return path
487   if os.path.isabs(path):
488     return path
489   return srcdir_prefix + path
490
491
492 # Map from qualified target to path to output.
493 target_outputs = {}
494 # Map from qualified target to a list of all linker dependencies,
495 # transitively expanded.
496 # Used in building shared-library-based executables.
497 target_link_deps = {}
498
499
500 class MakefileWriter:
501   """MakefileWriter packages up the writing of one target-specific foobar.mk.
502
503   Its only real entry point is Write(), and is mostly used for namespacing.
504   """
505
506   def __init__(self):
507     # Keep track of the total number of outputs for this makefile.
508     self._num_outputs = 0
509
510
511   def NumOutputs(self):
512     return self._num_outputs
513
514
515   def Write(self, qualified_target, base_path, output_filename, spec, configs,
516             part_of_all):
517     """The main entry point: writes a .mk file for a single target.
518
519     Arguments:
520       qualified_target: target we're generating
521       base_path: path relative to source root we're building in, used to resolve
522                  target-relative paths
523       output_filename: output .mk file name to write
524       spec, configs: gyp info
525       part_of_all: flag indicating this target is part of 'all'
526     """
527     ensure_directory_exists(output_filename)
528
529     self.fp = open(output_filename, 'w')
530
531     self.fp.write(header)
532
533     self.path = base_path
534     self.target = spec['target_name']
535     self.type = spec['type']
536     self.toolset = spec['toolset']
537
538     deps, link_deps = self.ComputeDeps(spec)
539
540     # Some of the generation below can add extra output, sources, or
541     # link dependencies.  All of the out params of the functions that
542     # follow use names like extra_foo.
543     extra_outputs = []
544     extra_sources = []
545     extra_link_deps = []
546
547     self.output = self.ComputeOutput(spec)
548     self._INSTALLABLE_TARGETS = ('executable', 'loadable_module',
549                                  'shared_library')
550     if self.type in self._INSTALLABLE_TARGETS:
551       self.alias = os.path.basename(self.output)
552       install_path = self._InstallableTargetInstallPath()
553     else:
554       self.alias = self.output
555       install_path = self.output
556
557     self.WriteLn("TOOLSET := " + self.toolset)
558     self.WriteLn("TARGET := " + self.target)
559
560     # Actions must come first, since they can generate more OBJs for use below.
561     if 'actions' in spec:
562       self.WriteActions(spec['actions'], extra_sources, extra_outputs,
563                         part_of_all)
564
565     # Rules must be early like actions.
566     if 'rules' in spec:
567       self.WriteRules(spec['rules'], extra_sources, extra_outputs, part_of_all)
568
569     if 'copies' in spec:
570       self.WriteCopies(spec['copies'], extra_outputs, part_of_all)
571
572     all_sources = spec.get('sources', []) + extra_sources
573     if all_sources:
574       self.WriteSources(configs, deps, all_sources,
575                         extra_outputs, extra_link_deps, part_of_all)
576       sources = filter(Compilable, all_sources)
577       if sources:
578         self.WriteLn(SHARED_HEADER_SUFFIX_RULES_COMMENT1)
579         extensions = set([os.path.splitext(s)[1] for s in sources])
580         for ext in extensions:
581           if ext in SHARED_HEADER_SUFFIX_RULES_SRCDIR:
582             self.WriteLn(SHARED_HEADER_SUFFIX_RULES_SRCDIR[ext])
583         self.WriteLn(SHARED_HEADER_SUFFIX_RULES_COMMENT2)
584         for ext in extensions:
585           if ext in SHARED_HEADER_SUFFIX_RULES_OBJDIR1:
586             self.WriteLn(SHARED_HEADER_SUFFIX_RULES_OBJDIR1[ext])
587         for ext in extensions:
588           if ext in SHARED_HEADER_SUFFIX_RULES_OBJDIR2:
589             self.WriteLn(SHARED_HEADER_SUFFIX_RULES_OBJDIR2[ext])
590         self.WriteLn('# End of this set of suffix rules')
591
592
593     self.WriteTarget(spec, configs, deps,
594                      extra_link_deps + link_deps, extra_outputs, part_of_all)
595
596     # Update global list of target outputs, used in dependency tracking.
597     target_outputs[qualified_target] = install_path
598
599     # Update global list of link dependencies.
600     if self.type == 'static_library':
601       target_link_deps[qualified_target] = [self.output]
602     elif self.type == 'shared_library':
603       # Anyone that uses us transitively depend on all of our link
604       # dependencies.
605       target_link_deps[qualified_target] = [self.output] + link_deps
606
607     self.fp.close()
608
609
610   def WriteSubMake(self, output_filename, makefile_path, targets, build_dir):
611     """Write a "sub-project" Makefile.
612
613     This is a small, wrapper Makefile that calls the top-level Makefile to build
614     the targets from a single gyp file (i.e. a sub-project).
615
616     Arguments:
617       output_filename: sub-project Makefile name to write
618       makefile_path: path to the top-level Makefile
619       targets: list of "all" targets for this sub-project
620       build_dir: build output directory, relative to the sub-project
621     """
622     ensure_directory_exists(output_filename)
623     self.fp = open(output_filename, 'w')
624     self.fp.write(header)
625     # For consistency with other builders, put sub-project build output in the
626     # sub-project dir (see test/subdirectory/gyptest-subdir-all.py).
627     self.WriteLn('export builddir_name ?= %s' %
628                  os.path.join(os.path.dirname(output_filename), build_dir))
629     self.WriteLn('.PHONY: all')
630     self.WriteLn('all:')
631     if makefile_path:
632       makefile_path = ' -C ' + makefile_path
633     self.WriteLn('\t$(MAKE)%s %s' % (makefile_path, ' '.join(targets)))
634     self.fp.close()
635
636
637   def WriteActions(self, actions, extra_sources, extra_outputs, part_of_all):
638     """Write Makefile code for any 'actions' from the gyp input.
639
640     extra_sources: a list that will be filled in with newly generated source
641                    files, if any
642     extra_outputs: a list that will be filled in with any outputs of these
643                    actions (used to make other pieces dependent on these
644                    actions)
645     part_of_all: flag indicating this target is part of 'all'
646     """
647     for action in actions:
648       name = self.target + '_' + StringToMakefileVariable(action['action_name'])
649       self.WriteLn('### Rules for action "%s":' % action['action_name'])
650       inputs = action['inputs']
651       outputs = action['outputs']
652
653       # Build up a list of outputs.
654       # Collect the output dirs we'll need.
655       dirs = set()
656       for out in outputs:
657         dir = os.path.split(out)[0]
658         if dir:
659           dirs.add(dir)
660       if int(action.get('process_outputs_as_sources', False)):
661         extra_sources += outputs
662
663       # Write the actual command.
664       command = gyp.common.EncodePOSIXShellList(action['action'])
665       if 'message' in action:
666         self.WriteLn('quiet_cmd_%s = ACTION %s $@' % (name, action['message']))
667       else:
668         self.WriteLn('quiet_cmd_%s = ACTION %s $@' % (name, name))
669       if len(dirs) > 0:
670         command = 'mkdir -p %s' % ' '.join(dirs) + '; ' + command
671       # Set LD_LIBRARY_PATH in case the action runs an executable from this
672       # build which links to shared libs from this build.
673       if self.path:
674         cd_action = 'cd %s; ' % Sourceify(self.path)
675       else:
676         cd_action = ''
677       # actions run on the host, so they should in theory only use host
678       # libraries, but until everything is made cross-compile safe, also use
679       # target libraries.
680       # TODO(piman): when everything is cross-compile safe, remove lib.target
681       self.WriteLn('cmd_%s = export LD_LIBRARY_PATH=$(builddir)/lib.host:'
682                    '$(builddir)/lib.target:$$LD_LIBRARY_PATH; %s%s'
683                    % (name, cd_action, command))
684       self.WriteLn()
685       outputs = map(self.Absolutify, outputs)
686       # The makefile rules are all relative to the top dir, but the gyp actions
687       # are defined relative to their containing dir.  This replaces the obj
688       # variable for the action rule with an absolute version so that the output
689       # goes in the right place.
690       # Only write the 'obj' and 'builddir' rules for the "primary" output (:1);
691       # it's superfluous for the "extra outputs", and this avoids accidentally
692       # writing duplicate dummy rules for those outputs.
693       self.WriteMakeRule(outputs[:1], ['obj := $(abs_obj)'])
694       self.WriteMakeRule(outputs[:1], ['builddir := $(abs_builddir)'])
695       self.WriteDoCmd(outputs, map(Sourceify, map(self.Absolutify, inputs)),
696                       part_of_all=part_of_all, command=name)
697
698       # Stuff the outputs in a variable so we can refer to them later.
699       outputs_variable = 'action_%s_outputs' % name
700       self.WriteLn('%s := %s' % (outputs_variable, ' '.join(outputs)))
701       extra_outputs.append('$(%s)' % outputs_variable)
702       self.WriteLn()
703
704     self.WriteLn()
705
706
707   def WriteRules(self, rules, extra_sources, extra_outputs, part_of_all):
708     """Write Makefile code for any 'rules' from the gyp input.
709
710     extra_sources: a list that will be filled in with newly generated source
711                    files, if any
712     extra_outputs: a list that will be filled in with any outputs of these
713                    rules (used to make other pieces dependent on these rules)
714     part_of_all: flag indicating this target is part of 'all'
715     """
716     for rule in rules:
717       name = self.target + '_' + StringToMakefileVariable(rule['rule_name'])
718       count = 0
719       self.WriteLn('### Generated for rule %s:' % name)
720
721       all_outputs = []
722
723       for rule_source in rule.get('rule_sources', []):
724         dirs = set()
725         rule_source_basename = os.path.basename(rule_source)
726         (rule_source_root, rule_source_ext) = \
727             os.path.splitext(rule_source_basename)
728
729         outputs = [self.ExpandInputRoot(out, rule_source_root)
730                    for out in rule['outputs']]
731         for out in outputs:
732           dir = os.path.dirname(out)
733           if dir:
734             dirs.add(dir)
735           if int(rule.get('process_outputs_as_sources', False)):
736             extra_sources.append(out)
737         all_outputs += outputs
738         inputs = map(Sourceify, map(self.Absolutify, [rule_source] +
739                                     rule.get('inputs', [])))
740         actions = ['$(call do_cmd,%s_%d)' % (name, count)]
741
742         if name == 'resources_grit':
743           # HACK: This is ugly.  Grit intentionally doesn't touch the
744           # timestamp of its output file when the file doesn't change,
745           # which is fine in hash-based dependency systems like scons
746           # and forge, but not kosher in the make world.  After some
747           # discussion, hacking around it here seems like the least
748           # amount of pain.
749           actions += ['@touch --no-create $@']
750
751         # Only write the 'obj' and 'builddir' rules for the "primary" output
752         # (:1); it's superfluous for the "extra outputs", and this avoids
753         # accidentally writing duplicate dummy rules for those outputs.
754         self.WriteMakeRule(outputs[:1], ['obj := $(abs_obj)'])
755         self.WriteMakeRule(outputs[:1], ['builddir := $(abs_builddir)'])
756         self.WriteMakeRule(outputs, inputs + ['FORCE_DO_CMD'], actions)
757         self.WriteLn('all_deps += %s' % ' '.join(outputs))
758         self._num_outputs += len(outputs)
759
760         action = [self.ExpandInputRoot(ac, rule_source_root)
761                   for ac in rule['action']]
762         mkdirs = ''
763         if len(dirs) > 0:
764           mkdirs = 'mkdir -p %s; ' % ' '.join(dirs)
765         if self.path:
766           cd_action = 'cd %s; ' % Sourceify(self.path)
767         else:
768           cd_action = ''
769         # Set LD_LIBRARY_PATH in case the rule runs an executable from this
770         # build which links to shared libs from this build.
771         # rules run on the host, so they should in theory only use host
772         # libraries, but until everything is made cross-compile safe, also use
773         # target libraries.
774         # TODO(piman): when everything is cross-compile safe, remove lib.target
775         self.WriteLn(
776             "cmd_%(name)s_%(count)d = export LD_LIBRARY_PATH="
777               "$(builddir)/lib.host:$(builddir)/lib.target:$$LD_LIBRARY_PATH; "
778               "%(cd_action)s%(mkdirs)s%(action)s" % {
779           'action': gyp.common.EncodePOSIXShellList(action),
780           'cd_action': cd_action,
781           'count': count,
782           'mkdirs': mkdirs,
783           'name': name,
784         })
785         self.WriteLn(
786             'quiet_cmd_%(name)s_%(count)d = RULE %(name)s_%(count)d $@' % {
787           'count': count,
788           'name': name,
789         })
790         self.WriteLn()
791         count += 1
792
793       outputs_variable = 'rule_%s_outputs' % name
794       self.WriteList(all_outputs, outputs_variable)
795       extra_outputs.append('$(%s)' % outputs_variable)
796
797       self.WriteLn('### Finished generating for rule: %s' % name)
798       self.WriteLn()
799     self.WriteLn('### Finished generating for all rules')
800     self.WriteLn('')
801
802
803   def WriteCopies(self, copies, extra_outputs, part_of_all):
804     """Write Makefile code for any 'copies' from the gyp input.
805
806     extra_outputs: a list that will be filled in with any outputs of this action
807                    (used to make other pieces dependent on this action)
808     part_of_all: flag indicating this target is part of 'all'
809     """
810     self.WriteLn('### Generated for copy rule.')
811
812     variable = self.target + '_copies'
813     outputs = []
814     for copy in copies:
815       for path in copy['files']:
816         path = Sourceify(self.Absolutify(path))
817         filename = os.path.split(path)[1]
818         output = Sourceify(self.Absolutify(os.path.join(copy['destination'],
819                                                         filename)))
820         self.WriteDoCmd([output], [path], 'copy', part_of_all)
821         outputs.append(output)
822     self.WriteLn('%s = %s' % (variable, ' '.join(outputs)))
823     extra_outputs.append('$(%s)' % variable)
824     self.WriteLn()
825
826
827   def WriteSources(self, configs, deps, sources,
828                    extra_outputs, extra_link_deps,
829                    part_of_all):
830     """Write Makefile code for any 'sources' from the gyp input.
831     These are source files necessary to build the current target.
832
833     configs, deps, sources: input from gyp.
834     extra_outputs: a list of extra outputs this action should be dependent on;
835                    used to serialize action/rules before compilation
836     extra_link_deps: a list that will be filled in with any outputs of
837                      compilation (to be used in link lines)
838     part_of_all: flag indicating this target is part of 'all'
839     """
840
841     # Write configuration-specific variables for CFLAGS, etc.
842     for configname in sorted(configs.keys()):
843       config = configs[configname]
844       self.WriteList(config.get('defines'), 'DEFS_%s' % configname, prefix='-D',
845           quoter=EscapeCppDefine)
846       self.WriteLn("# Flags passed to both C and C++ files.");
847       self.WriteList(config.get('cflags'), 'CFLAGS_%s' % configname)
848       self.WriteLn("# Flags passed to only C (and not C++) files.");
849       self.WriteList(config.get('cflags_c'), 'CFLAGS_C_%s' % configname)
850       self.WriteLn("# Flags passed to only C++ (and not C) files.");
851       self.WriteList(config.get('cflags_cc'), 'CFLAGS_CC_%s' % configname)
852       includes = config.get('include_dirs')
853       if includes:
854         includes = map(Sourceify, map(self.Absolutify, includes))
855       self.WriteList(includes, 'INCS_%s' % configname, prefix='-I')
856
857     compilable = filter(Compilable, sources)
858     objs = map(self.Objectify, map(self.Absolutify, map(Target, compilable)))
859     self.WriteList(objs, 'OBJS')
860
861     self.WriteLn('# Add to the list of files we specially track '
862                  'dependencies for.')
863     self.WriteLn('all_deps += $(OBJS)')
864     self._num_outputs += len(objs)
865     self.WriteLn()
866
867     # Make sure our dependencies are built first.
868     if deps:
869       self.WriteMakeRule(['$(OBJS)'], deps,
870                          comment = 'Make sure our dependencies are built '
871                                    'before any of us.',
872                          order_only = True)
873
874     # Make sure the actions and rules run first.
875     # If they generate any extra headers etc., the per-.o file dep tracking
876     # will catch the proper rebuilds, so order only is still ok here.
877     if extra_outputs:
878       self.WriteMakeRule(['$(OBJS)'], extra_outputs,
879                          comment = 'Make sure our actions/rules run '
880                                    'before any of us.',
881                          order_only = True)
882
883     if objs:
884       extra_link_deps.append('$(OBJS)')
885       self.WriteLn("""\
886 # CFLAGS et al overrides must be target-local.
887 # See "Target-specific Variable Values" in the GNU Make manual.""")
888       self.WriteLn("$(OBJS): TOOLSET := $(TOOLSET)")
889       self.WriteLn("$(OBJS): GYP_CFLAGS := "
890                    "$(DEFS_$(BUILDTYPE)) "
891                    "$(INCS_$(BUILDTYPE)) "
892                    "$(CFLAGS_$(BUILDTYPE)) "
893                    "$(CFLAGS_C_$(BUILDTYPE))")
894       self.WriteLn("$(OBJS): GYP_CXXFLAGS := "
895                    "$(DEFS_$(BUILDTYPE)) "
896                    "$(INCS_$(BUILDTYPE)) "
897                    "$(CFLAGS_$(BUILDTYPE)) "
898                    "$(CFLAGS_CC_$(BUILDTYPE))")
899
900     # If there are any object files in our input file list, link them into our
901     # output.
902     extra_link_deps += filter(Linkable, sources)
903
904     self.WriteLn()
905
906
907   def ComputeOutput(self, spec):
908     """Return the 'output' (full output path) of a gyp spec.
909
910     E.g., the loadable module 'foobar' in directory 'baz' will produce
911       '$(obj)/baz/libfoobar.so'
912     """
913     output = None
914     target = spec['target_name']
915     target_prefix = ''
916     target_ext = ''
917     path = os.path.join('$(obj).' + self.toolset, self.path)
918     if self.type == 'static_library':
919       if target[:3] == 'lib':
920         target = target[3:]
921       target_prefix = 'lib'
922       target_ext = '.a'
923     elif self.type in ('loadable_module', 'shared_library'):
924       if target[:3] == 'lib':
925         target = target[3:]
926       target_prefix = 'lib'
927       target_ext = '.so'
928     elif self.type == 'none':
929       target = '%s.stamp' % target
930     elif self.type == 'settings':
931       return None
932     elif self.type == 'executable':
933       path = os.path.join('$(builddir)')
934     else:
935       print ("ERROR: What output file should be generated?",
936              "typ", self.type, "target", target)
937
938     path = spec.get('product_dir', path)
939     target_prefix = spec.get('product_prefix', target_prefix)
940     target = spec.get('product_name', target)
941     product_ext = spec.get('product_extension')
942     if product_ext:
943       target_ext = '.' + product_ext
944
945     return os.path.join(path, target_prefix + target + target_ext)
946
947
948   def ComputeDeps(self, spec):
949     """Compute the dependencies of a gyp spec.
950
951     Returns a tuple (deps, link_deps), where each is a list of
952     filenames that will need to be put in front of make for either
953     building (deps) or linking (link_deps).
954     """
955     deps = []
956     link_deps = []
957     if 'dependencies' in spec:
958       deps.extend([target_outputs[dep] for dep in spec['dependencies']
959                    if target_outputs[dep]])
960       for dep in spec['dependencies']:
961         if dep in target_link_deps:
962           link_deps.extend(target_link_deps[dep])
963       deps.extend(link_deps)
964       # TODO: It seems we need to transitively link in libraries (e.g. -lfoo)?
965       # This hack makes it work:
966       # link_deps.extend(spec.get('libraries', []))
967     return (gyp.common.uniquer(deps), gyp.common.uniquer(link_deps))
968
969
970   def WriteTarget(self, spec, configs, deps, link_deps, extra_outputs,
971                   part_of_all):
972     """Write Makefile code to produce the final target of the gyp spec.
973
974     spec, configs: input from gyp.
975     deps, link_deps: dependency lists; see ComputeDeps()
976     extra_outputs: any extra outputs that our target should depend on
977     part_of_all: flag indicating this target is part of 'all'
978     """
979
980     self.WriteLn('### Rules for final target.')
981
982     if extra_outputs:
983       self.WriteMakeRule([self.output], extra_outputs,
984                          comment = 'Build our special outputs first.',
985                          order_only = True)
986       self.WriteMakeRule(extra_outputs, deps,
987                          comment=('Preserve order dependency of '
988                                   'special output on deps.'),
989                          order_only = True,
990                          multiple_output_trick = False)
991
992     if self.type not in ('settings', 'none'):
993       for configname in sorted(configs.keys()):
994         config = configs[configname]
995         self.WriteList(config.get('ldflags'), 'LDFLAGS_%s' % configname)
996       libraries = spec.get('libraries')
997       if libraries:
998         # Remove duplicate entries
999         libraries = gyp.common.uniquer(libraries)
1000       self.WriteList(libraries, 'LIBS')
1001       self.WriteLn('%s: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE))' % self.output)
1002       self.WriteLn('%s: LIBS := $(LIBS)' % self.output)
1003
1004     if self.type == 'executable':
1005       self.WriteDoCmd([self.output], link_deps, 'link', part_of_all)
1006     elif self.type == 'static_library':
1007       self.WriteDoCmd([self.output], link_deps, 'alink', part_of_all)
1008     elif self.type in ('loadable_module', 'shared_library'):
1009       self.WriteDoCmd([self.output], link_deps, 'solink', part_of_all)
1010     elif self.type == 'none':
1011       # Write a stamp line.
1012       self.WriteDoCmd([self.output], deps, 'touch', part_of_all)
1013     elif self.type == 'settings':
1014       # Only used for passing flags around.
1015       pass
1016     else:
1017       print "WARNING: no output for", self.type, target
1018
1019     # Add an alias for each target (if there are any outputs).
1020     # Installable target aliases are created below.
1021     if ((self.output and self.output != self.target) and
1022         (self.type not in self._INSTALLABLE_TARGETS)):
1023       self.WriteMakeRule([self.target], [self.output],
1024                          comment='Add target alias', phony = True)
1025       if part_of_all:
1026         self.WriteMakeRule(['all'], [self.target],
1027                            comment = 'Add target alias to "all" target.',
1028                            phony = True)
1029
1030     # Add special-case rules for our installable targets.
1031     # 1) They need to install to the build dir or "product" dir.
1032     # 2) They get shortcuts for building (e.g. "make chrome").
1033     # 3) They are part of "make all".
1034     if self.type in self._INSTALLABLE_TARGETS:
1035       if self.type == 'shared_library':
1036         file_desc = 'shared library'
1037       else:
1038         file_desc = 'executable'
1039       install_path = self._InstallableTargetInstallPath()
1040       installable_deps = [self.output]
1041       # Point the target alias to the final binary output.
1042       self.WriteMakeRule([self.target], [install_path],
1043                          comment='Add target alias', phony = True)
1044       if install_path != self.output:
1045         self.WriteDoCmd([install_path], [self.output], 'copy',
1046                         comment = 'Copy this to the %s output path.' %
1047                         file_desc, part_of_all=part_of_all)
1048         installable_deps.append(install_path)
1049       if self.output != self.alias and self.alias != self.target:
1050         self.WriteMakeRule([self.alias], installable_deps,
1051                            comment = 'Short alias for building this %s.' %
1052                            file_desc, phony = True)
1053       if part_of_all:
1054         self.WriteMakeRule(['all'], [install_path],
1055                            comment = 'Add %s to "all" target.' % file_desc,
1056                            phony = True)
1057
1058
1059   def WriteList(self, list, variable=None, prefix='', quoter=QuoteIfNecessary):
1060     """Write a variable definition that is a list of values.
1061
1062     E.g. WriteList(['a','b'], 'foo', prefix='blah') writes out
1063          foo = blaha blahb
1064     but in a pretty-printed style.
1065     """
1066     self.fp.write(variable + " := ")
1067     if list:
1068       list = [quoter(prefix + l) for l in list]
1069       self.fp.write(" \\\n\t".join(list))
1070     self.fp.write("\n\n")
1071
1072
1073   def WriteDoCmd(self, outputs, inputs, command, part_of_all, comment=None):
1074     """Write a Makefile rule that uses do_cmd.
1075
1076     This makes the outputs dependent on the command line that was run,
1077     as well as support the V= make command line flag.
1078     """
1079     self.WriteMakeRule(outputs, inputs,
1080                        actions = ['$(call do_cmd,%s)' % command],
1081                        comment = comment,
1082                        force = True)
1083     # Add our outputs to the list of targets we read depfiles from.
1084     self.WriteLn('all_deps += %s' % ' '.join(outputs))
1085     self._num_outputs += len(outputs)
1086
1087
1088   def WriteMakeRule(self, outputs, inputs, actions=None, comment=None,
1089                     order_only=False, force=False, phony=False,
1090                     multiple_output_trick=True):
1091     """Write a Makefile rule, with some extra tricks.
1092
1093     outputs: a list of outputs for the rule (note: this is not directly
1094              supported by make; see comments below)
1095     inputs: a list of inputs for the rule
1096     actions: a list of shell commands to run for the rule
1097     comment: a comment to put in the Makefile above the rule (also useful
1098              for making this Python script's code self-documenting)
1099     order_only: if true, makes the dependency order-only
1100     force: if true, include FORCE_DO_CMD as an order-only dep
1101     phony: if true, the rule does not actually generate the named output, the
1102            output is just a name to run the rule
1103     multiple_output_trick: if true (the default), perform tricks such as dummy
1104            rules to avoid problems with multiple outputs.
1105     """
1106     if comment:
1107       self.WriteLn('# ' + comment)
1108     if phony:
1109       self.WriteLn('.PHONY: ' + ' '.join(outputs))
1110     # TODO(evanm): just make order_only a list of deps instead of these hacks.
1111     if order_only:
1112       order_insert = '| '
1113     else:
1114       order_insert = ''
1115     if force:
1116       force_append = ' FORCE_DO_CMD'
1117     else:
1118       force_append = ''
1119     if actions:
1120       self.WriteLn("%s: TOOLSET := $(TOOLSET)" % outputs[0])
1121     self.WriteLn('%s: %s%s%s' % (outputs[0], order_insert, ' '.join(inputs),
1122                                  force_append))
1123     if actions:
1124       for action in actions:
1125         self.WriteLn('\t%s' % action)
1126     if multiple_output_trick and len(outputs) > 1:
1127       # If we have more than one output, a rule like
1128       #   foo bar: baz
1129       # that for *each* output we must run the action, potentially
1130       # in parallel.  That is not what we're trying to write -- what
1131       # we want is that we run the action once and it generates all
1132       # the files.
1133       # http://www.gnu.org/software/hello/manual/automake/Multiple-Outputs.html
1134       # discusses this problem and has this solution:
1135       # 1) Write the naive rule that would produce parallel runs of
1136       # the action.
1137       # 2) Make the outputs seralized on each other, so we won't start
1138       # a parallel run until the first run finishes, at which point
1139       # we'll have generated all the outputs and we're done.
1140       self.WriteLn('%s: %s' % (' '.join(outputs[1:]), outputs[0]))
1141       # Add a dummy command to the "extra outputs" rule, otherwise make seems to
1142       # think these outputs haven't (couldn't have?) changed, and thus doesn't
1143       # flag them as changed (i.e. include in '$?') when evaluating dependent
1144       # rules, which in turn causes do_cmd() to skip running dependent commands.
1145       self.WriteLn('%s: ;' % (' '.join(outputs[1:])))
1146     self.WriteLn()
1147
1148
1149   def WriteLn(self, text=''):
1150     self.fp.write(text + '\n')
1151
1152
1153   def Objectify(self, path):
1154     """Convert a path to its output directory form."""
1155     if '$(' in path:
1156       path = path.replace('$(obj)/', '$(obj).%s/$(TARGET)/' % self.toolset)
1157       return path
1158     return '$(obj).%s/$(TARGET)/%s' % (self.toolset, path)
1159
1160   def Absolutify(self, path):
1161     """Convert a subdirectory-relative path into a base-relative path.
1162     Skips over paths that contain variables."""
1163     if '$(' in path:
1164       return path
1165     return os.path.normpath(os.path.join(self.path, path))
1166
1167
1168   def FixupArgPath(self, arg):
1169     if '/' in arg or '.h.' in arg:
1170       return self.Absolutify(arg)
1171     return arg
1172
1173
1174   def ExpandInputRoot(self, template, expansion):
1175     if '%(INPUT_ROOT)s' not in template:
1176       return template
1177     path = template % { 'INPUT_ROOT': expansion }
1178     if not os.path.dirname(path):
1179       # If it's just the file name, turn it into a path so FixupArgPath()
1180       # will know to Absolutify() it.
1181       path = os.path.join('.', path)
1182     return path
1183
1184
1185   def _InstallableTargetInstallPath(self):
1186     """Returns the location of the final output for an installable target."""
1187     if self.type == 'shared_library':
1188       # Install all shared libs into a common directory (per toolset) for
1189       # convenient access with LD_LIBRARY_PATH.
1190       return '$(builddir)/lib.%s/%s' % (self.toolset, self.alias)
1191     return '$(builddir)/' + self.alias
1192
1193
1194 def WriteAutoRegenerationRule(params, root_makefile, makefile_name,
1195                               build_files):
1196   """Write the target to regenerate the Makefile."""
1197   options = params['options']
1198   build_files_args = [gyp.common.RelativePath(filename, options.toplevel_dir)
1199                       for filename in params['build_files_arg']]
1200   gyp_binary = gyp.common.FixIfRelativePath(params['gyp_binary'],
1201                                             options.toplevel_dir)
1202   if not gyp_binary.startswith(os.sep):
1203     gyp_binary = os.path.join('.', gyp_binary)
1204   root_makefile.write(
1205       "quiet_cmd_regen_makefile = ACTION Regenerating $@\n"
1206       "cmd_regen_makefile = %(cmd)s\n"
1207       "%(makefile_name)s: %(deps)s\n"
1208       "\t$(call do_cmd,regen_makefile)\n\n" % {
1209           'makefile_name': makefile_name,
1210           'deps': ' '.join(map(Sourceify, build_files)),
1211           'cmd': gyp.common.EncodePOSIXShellList(
1212                      [gyp_binary, '-fmake'] +
1213                      gyp.RegenerateFlags(options) +
1214                      build_files_args)})
1215
1216
1217 def RunSystemTests():
1218   """Run tests against the system to compute default settings for commands.
1219
1220   Returns:
1221     dictionary of settings matching the block of command-lines used in
1222     SHARED_HEADER.  E.g. the dictionary will contain a ARFLAGS.target
1223     key for the default ARFLAGS for the target ar command.
1224   """
1225   # Compute flags used for building static archives.
1226   # N.B.: this fallback logic should match the logic in SHARED_HEADER.
1227   # See comment there for more details.
1228   ar_target = os.environ.get('AR.target', os.environ.get('AR', 'ar'))
1229   cc_target = os.environ.get('CC.target', os.environ.get('CC', 'cc'))
1230   arflags_target = 'crs'
1231   if gyp.system_test.TestArSupportsT(ar_command=ar_target,
1232                                      cc_command=cc_target):
1233     arflags_target = 'crsT'
1234
1235   ar_host = os.environ.get('AR.host', 'ar')
1236   cc_host = os.environ.get('CC.host', 'gcc')
1237   arflags_host = 'crs'
1238   # It feels redundant to compute this again given that most builds aren't
1239   # cross-compiles, but due to quirks of history CC.host defaults to 'gcc'
1240   # while CC.target defaults to 'cc', so the commands really are different
1241   # even though they're nearly guaranteed to run the same code underneath.
1242   if gyp.system_test.TestArSupportsT(ar_command=ar_host, cc_command=cc_host):
1243     arflags_host = 'crsT'
1244
1245   link_flags = ''
1246   if gyp.system_test.TestLinkerSupportsThreads(cc_command=cc_target):
1247     # N.B. we don't test for cross-compilation; as currently written, we
1248     # don't even use flock when linking in the cross-compile setup!
1249     # TODO(evan): refactor cross-compilation such that this code can
1250     # be reused.
1251     link_flags = '-Wl,--threads --Wl,--thread-count=4'
1252
1253   # TODO(evan): cache this output.  (But then we'll need to add extra
1254   # flags to gyp to flush the cache, yuk!  It's fast enough for now to
1255   # just run it every time.)
1256
1257   return { 'ARFLAGS.target': arflags_target,
1258            'ARFLAGS.host': arflags_host,
1259            'LINK_flags': link_flags }
1260
1261
1262 def GenerateOutput(target_list, target_dicts, data, params):
1263   options = params['options']
1264   generator_flags = params.get('generator_flags', {})
1265   builddir_name = generator_flags.get('output_dir', 'out')
1266
1267   def CalculateMakefilePath(build_file, base_name):
1268     """Determine where to write a Makefile for a given gyp file."""
1269     # Paths in gyp files are relative to the .gyp file, but we want
1270     # paths relative to the source root for the master makefile.  Grab
1271     # the path of the .gyp file as the base to relativize against.
1272     # E.g. "foo/bar" when we're constructing targets for "foo/bar/baz.gyp".
1273     base_path = gyp.common.RelativePath(os.path.dirname(build_file),
1274                                         options.depth)
1275     # We write the file in the base_path directory.
1276     output_file = os.path.join(options.depth, base_path, base_name)
1277     if options.generator_output:
1278       output_file = os.path.join(options.generator_output, output_file)
1279     base_path = gyp.common.RelativePath(os.path.dirname(build_file),
1280                                         options.toplevel_dir)
1281     return base_path, output_file
1282
1283   # TODO:  search for the first non-'Default' target.  This can go
1284   # away when we add verification that all targets have the
1285   # necessary configurations.
1286   default_configuration = None
1287   toolsets = set([target_dicts[target]['toolset'] for target in target_list])
1288   for target in target_list:
1289     spec = target_dicts[target]
1290     if spec['default_configuration'] != 'Default':
1291       default_configuration = spec['default_configuration']
1292       break
1293   if not default_configuration:
1294     default_configuration = 'Default'
1295
1296   srcdir = '.'
1297   makefile_name = 'Makefile' + options.suffix
1298   makefile_path = os.path.join(options.toplevel_dir, makefile_name)
1299   if options.generator_output:
1300     global srcdir_prefix
1301     makefile_path = os.path.join(options.generator_output, makefile_path)
1302     srcdir = gyp.common.RelativePath(srcdir, options.generator_output)
1303     srcdir_prefix = '$(srcdir)/'
1304
1305   header_params = {
1306       'srcdir': srcdir,
1307       'builddir': builddir_name,
1308       'default_configuration': default_configuration,
1309     }
1310   header_params.update(RunSystemTests())
1311
1312   ensure_directory_exists(makefile_path)
1313   root_makefile = open(makefile_path, 'w')
1314   root_makefile.write(SHARED_HEADER % header_params)
1315   for toolset in toolsets:
1316     root_makefile.write('TOOLSET := %s\n' % toolset)
1317     root_makefile.write(ROOT_HEADER_SUFFIX_RULES)
1318
1319   # Find the list of targets that derive from the gyp file(s) being built.
1320   needed_targets = set()
1321   for build_file in params['build_files']:
1322     for target in gyp.common.AllTargets(target_list, target_dicts, build_file):
1323       needed_targets.add(target)
1324
1325   num_outputs = 0
1326   build_files = set()
1327   include_list = set()
1328   for qualified_target in target_list:
1329     build_file, target, toolset = gyp.common.ParseQualifiedTarget(
1330         qualified_target)
1331     build_files.add(gyp.common.RelativePath(build_file, options.toplevel_dir))
1332     included_files = data[build_file]['included_files']
1333     for included_file in included_files:
1334       # The included_files entries are relative to the dir of the build file
1335       # that included them, so we have to undo that and then make them relative
1336       # to the root dir.
1337       relative_include_file = gyp.common.RelativePath(
1338           gyp.common.UnrelativePath(included_file, build_file),
1339           options.toplevel_dir)
1340       abs_include_file = os.path.abspath(relative_include_file)
1341       # If the include file is from the ~/.gyp dir, we should use absolute path
1342       # so that relocating the src dir doesn't break the path.
1343       if (params['home_dot_gyp'] and
1344           abs_include_file.startswith(params['home_dot_gyp'])):
1345         build_files.add(abs_include_file)
1346       else:
1347         build_files.add(relative_include_file)
1348
1349     base_path, output_file = CalculateMakefilePath(build_file,
1350         target + '.' + toolset + options.suffix + '.mk')
1351
1352     spec = target_dicts[qualified_target]
1353     configs = spec['configurations']
1354
1355     writer = MakefileWriter()
1356     writer.Write(qualified_target, base_path, output_file, spec, configs,
1357                  part_of_all=qualified_target in needed_targets)
1358     num_outputs += writer.NumOutputs()
1359
1360     # Our root_makefile lives at the source root.  Compute the relative path
1361     # from there to the output_file for including.
1362     mkfile_rel_path = gyp.common.RelativePath(output_file,
1363                                               os.path.dirname(makefile_path))
1364     include_list.add(mkfile_rel_path)
1365
1366   # Write out per-gyp (sub-project) Makefiles.
1367   depth_rel_path = gyp.common.RelativePath(options.depth, os.getcwd())
1368   for build_file in build_files:
1369     # The paths in build_files were relativized above, so undo that before
1370     # testing against the non-relativized items in target_list and before
1371     # calculating the Makefile path.
1372     build_file = os.path.join(depth_rel_path, build_file)
1373     gyp_targets = [target_dicts[target]['target_name'] for target in target_list
1374                    if target.startswith(build_file) and
1375                    target in needed_targets]
1376     # Only generate Makefiles for gyp files with targets.
1377     if not gyp_targets:
1378       continue
1379     base_path, output_file = CalculateMakefilePath(build_file,
1380         os.path.splitext(os.path.basename(build_file))[0] + '.Makefile')
1381     makefile_rel_path = gyp.common.RelativePath(os.path.dirname(makefile_path),
1382                                                 os.path.dirname(output_file))
1383     writer.WriteSubMake(output_file, makefile_rel_path, gyp_targets,
1384                         builddir_name)
1385
1386
1387   # Write out the sorted list of includes.
1388   root_makefile.write('\n')
1389   for include_file in sorted(include_list):
1390     # We wrap each .mk include in an if statement so users can tell make to
1391     # not load a file by setting NO_LOAD.  The below make code says, only
1392     # load the .mk file if the .mk filename doesn't start with a token in
1393     # NO_LOAD.
1394     root_makefile.write(
1395         "ifeq ($(strip $(foreach prefix,$(NO_LOAD),\\\n"
1396         "    $(findstring $(join ^,$(prefix)),\\\n"
1397         "                 $(join ^," + include_file + ")))),)\n")
1398     root_makefile.write("  include " + include_file + "\n")
1399     root_makefile.write("endif\n")
1400   root_makefile.write('\n')
1401
1402   if generator_flags.get('auto_regeneration', True):
1403     WriteAutoRegenerationRule(params, root_makefile, makefile_name, build_files)
1404
1405   # Write the rule to load dependencies.  We batch 1000 files at a time to
1406   # avoid overflowing the command line.
1407   all_deps = ""
1408   for i in range(1001, num_outputs, 1000):
1409     all_deps += ("""
1410   ifneq ($(word %(start)d,$(d_files)),)
1411     $(shell cat $(wordlist %(start)d,%(end)d,$(d_files)) >> $(depsdir)/all.deps)
1412   endif""" % { 'start': i, 'end': i + 999 })
1413
1414   # Add a check to make sure we tried to process all the .d files.
1415   all_deps += """
1416   ifneq ($(word %(last)d,$(d_files)),)
1417     $(error Found unprocessed dependency files (gyp didn't generate enough rules!))
1418   endif
1419 """ % { 'last': ((num_outputs / 1000) + 1) * 1000 + 1 }
1420
1421   root_makefile.write(SHARED_FOOTER % { 'generate_all_deps': all_deps })
1422
1423   root_makefile.close()