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.
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.
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
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.
28 import gyp.system_test
32 # Debugging-related imports -- remove me once we're solid.
36 generator_default_variables = {
37 'EXECUTABLE_PREFIX': '',
38 'EXECUTABLE_SUFFIX': '',
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 $<)',
54 # This appears unused --- ?
55 'CONFIGURATION_NAME': '$(BUILDTYPE)',
58 # Make supports multiple toolsets
59 generator_supports_multiple_toolsets = True
61 def ensure_directory_exists(path):
62 dir = os.path.dirname(path)
63 if dir and not os.path.exists(dir):
66 # Header of toplevel Makefile.
67 # This should go into the build tree, but it's easier to keep it here for now.
69 # We borrow heavily from the kernel build setup, though we are simpler since
70 # we don't have Kconfig tweaking settings on us.
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.
77 # The source directory tree.
80 # The name of the builddir.
81 builddir_name ?= %(builddir)s
83 # The V=1 flag on command line makes us verbosely print command lines.
90 # Specify BUILDTYPE=Release on the command line for a release build.
91 BUILDTYPE ?= %(default_configuration)s
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
100 # Object output directory.
101 obj := $(builddir)/obj
102 abs_obj := $(abspath $(obj))
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.
108 # C++ apps need to be linked with g++. Not sure what's appropriate.
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:
114 # export LINK="$(CXX)"
116 # This will allow make to invoke N linker processes as specified in -jN.
117 LINK ?= flock $(builddir)/linker.lock $(CXX) %(LINK_flags)s
120 CFLAGS.target ?= $(CFLAGS)
122 CXXFLAGS.target ?= $(CXXFLAGS)
123 LINK.target ?= $(LINK)
124 LDFLAGS.target ?= $(LDFLAGS)
126 ARFLAGS.target ?= %(ARFLAGS.target)s
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.
139 ARFLAGS.host := %(ARFLAGS.host)s
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
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
152 # foobar.o: DEP1 DEP2
154 # path/to/foobar.o: DEP1 DEP2
155 # (2) we want missing files not to cause us to fail to build.
157 # foobar.o: DEP1 DEP2 \\
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."""
168 # The depfile may not exist if the input file didn't have any #includes.
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 |\
178 sed -e 1d -e 's|$$|:|' \
184 # Command definitions:
185 # - cmd_foo is the actual command to run;
186 # - quiet_cmd_foo is the brief-output summary of the command.
188 quiet_cmd_cc = CC($(TOOLSET)) $@
189 cmd_cc = $(CC.$(TOOLSET)) $(GYP_CFLAGS) $(DEPFLAGS) $(CFLAGS.$(TOOLSET)) -c -o $@ $<
191 quiet_cmd_cxx = CXX($(TOOLSET)) $@
192 cmd_cxx = $(CXX.$(TOOLSET)) $(GYP_CXXFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $<
194 quiet_cmd_alink = AR($(TOOLSET)) $@
195 cmd_alink = rm -f $@ && $(AR.$(TOOLSET)) $(ARFLAGS.$(TOOLSET)) $@ $(filter %%.o,$^)
197 quiet_cmd_touch = TOUCH $@
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 $< $@
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)
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)
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))'
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))))
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 $|,$?)
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.
258 $(if $(or $(command_changed),$(prereq_changed)),
259 @$(call exact_echo, $($(quiet)cmd_$(1)))
260 @mkdir -p $(dir $@) $(dir $(depfile))
262 @$(call exact_echo,$(call escape_vars,cmd_$@ := $(cmd_$(1)))) > $(depfile)
263 @$(if $(2),$(fixup_dep))
267 # Declare "all" target first so it is the default, even though we don't have the
272 # Use FORCE_DO_CMD to force a target to run. Should be coupled with
279 ROOT_HEADER_SUFFIX_RULES = ("""\
280 # Suffix rules, putting all outputs into $(obj).
281 $(obj).$(TOOLSET)/%.o: $(srcdir)/%.c FORCE_DO_CMD
283 $(obj).$(TOOLSET)/%.o: $(srcdir)/%.s FORCE_DO_CMD
285 $(obj).$(TOOLSET)/%.o: $(srcdir)/%.S FORCE_DO_CMD
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)
294 # Try building from generated source, too.
295 $(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.c FORCE_DO_CMD
297 $(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.s FORCE_DO_CMD
299 $(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.S FORCE_DO_CMD
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)
308 $(obj).$(TOOLSET)/%.o: $(obj)/%.c FORCE_DO_CMD
310 $(obj).$(TOOLSET)/%.o: $(obj)/%.s FORCE_DO_CMD
312 $(obj).$(TOOLSET)/%.o: $(obj)/%.S FORCE_DO_CMD
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)
322 SHARED_HEADER_SUFFIX_RULES_COMMENT1 = ("""\
323 # Suffix rules, putting all outputs into $(obj).
326 SHARED_HEADER_SUFFIX_RULES_SRCDIR = {
328 $(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.c FORCE_DO_CMD
332 $(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.s FORCE_DO_CMD
336 $(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.S FORCE_DO_CMD
340 $(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.cpp FORCE_DO_CMD
341 @$(call do_cmd,cxx,1)
344 $(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.cc FORCE_DO_CMD
345 @$(call do_cmd,cxx,1)
348 $(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.cxx FORCE_DO_CMD
349 @$(call do_cmd,cxx,1)
353 SHARED_HEADER_SUFFIX_RULES_COMMENT2 = ("""\
354 # Try building from generated source, too.
357 SHARED_HEADER_SUFFIX_RULES_OBJDIR1 = {
359 $(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj).$(TOOLSET)/%.c FORCE_DO_CMD
363 $(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj).$(TOOLSET)/%.cc FORCE_DO_CMD
364 @$(call do_cmd,cxx,1)
367 $(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj).$(TOOLSET)/%.cpp FORCE_DO_CMD
368 @$(call do_cmd,cxx,1)
372 SHARED_HEADER_SUFFIX_RULES_OBJDIR2 = {
374 $(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.c FORCE_DO_CMD
378 $(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.cc FORCE_DO_CMD
379 @$(call do_cmd,cxx,1)
382 $(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.cpp FORCE_DO_CMD
383 @$(call do_cmd,cxx,1)
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())
396 # "all" is a concatenation of the "all" targets from all the included
397 # sub-makefiles. This is just here to clarify.
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))
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
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: ;
418 include $(depsdir)/all.deps
423 # This file is generated by gyp; do not edit.
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']):
437 def Linkable(filename):
438 """Return true if the file is linkable (should be on the link line)."""
439 return filename.endswith('.o')
442 def Target(filename):
443 """Translate a compilable filename to its .o target."""
444 return os.path.splitext(filename)[0] + '.o'
447 def EscapeShellArgument(s):
448 """Quotes an argument so that it will be interpreted literally by a POSIX
450 http://stackoverflow.com/questions/35817/whats-the-best-way-to-escape-ossystem-calls-in-python
452 return "'" + s.replace("'", "'\\''") + "'"
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('$', '$$')
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)
468 def QuoteIfNecessary(string):
469 """TODO: Should this ideally be replaced with one or more of the above
472 string = '"' + string.replace('"', '\\"') + '"'
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(' ', '_')
484 """Convert a path to its source directory form."""
487 if os.path.isabs(path):
489 return srcdir_prefix + path
492 # Map from qualified target to path to output.
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 = {}
500 class MakefileWriter:
501 """MakefileWriter packages up the writing of one target-specific foobar.mk.
503 Its only real entry point is Write(), and is mostly used for namespacing.
507 # Keep track of the total number of outputs for this makefile.
508 self._num_outputs = 0
511 def NumOutputs(self):
512 return self._num_outputs
515 def Write(self, qualified_target, base_path, output_filename, spec, configs,
517 """The main entry point: writes a .mk file for a single target.
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'
527 ensure_directory_exists(output_filename)
529 self.fp = open(output_filename, 'w')
531 self.fp.write(header)
533 self.path = base_path
534 self.target = spec['target_name']
535 self.type = spec['type']
536 self.toolset = spec['toolset']
538 deps, link_deps = self.ComputeDeps(spec)
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.
547 self.output = self.ComputeOutput(spec)
548 self._INSTALLABLE_TARGETS = ('executable', 'loadable_module',
550 if self.type in self._INSTALLABLE_TARGETS:
551 self.alias = os.path.basename(self.output)
552 install_path = self._InstallableTargetInstallPath()
554 self.alias = self.output
555 install_path = self.output
557 self.WriteLn("TOOLSET := " + self.toolset)
558 self.WriteLn("TARGET := " + self.target)
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,
565 # Rules must be early like actions.
567 self.WriteRules(spec['rules'], extra_sources, extra_outputs, part_of_all)
570 self.WriteCopies(spec['copies'], extra_outputs, part_of_all)
572 all_sources = spec.get('sources', []) + extra_sources
574 self.WriteSources(configs, deps, all_sources,
575 extra_outputs, extra_link_deps, part_of_all)
576 sources = filter(Compilable, all_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')
593 self.WriteTarget(spec, configs, deps,
594 extra_link_deps + link_deps, extra_outputs, part_of_all)
596 # Update global list of target outputs, used in dependency tracking.
597 target_outputs[qualified_target] = install_path
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
605 target_link_deps[qualified_target] = [self.output] + link_deps
610 def WriteSubMake(self, output_filename, makefile_path, targets, build_dir):
611 """Write a "sub-project" Makefile.
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).
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
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')
632 makefile_path = ' -C ' + makefile_path
633 self.WriteLn('\t$(MAKE)%s %s' % (makefile_path, ' '.join(targets)))
637 def WriteActions(self, actions, extra_sources, extra_outputs, part_of_all):
638 """Write Makefile code for any 'actions' from the gyp input.
640 extra_sources: a list that will be filled in with newly generated source
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
645 part_of_all: flag indicating this target is part of 'all'
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']
653 # Build up a list of outputs.
654 # Collect the output dirs we'll need.
657 dir = os.path.split(out)[0]
660 if int(action.get('process_outputs_as_sources', False)):
661 extra_sources += outputs
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']))
668 self.WriteLn('quiet_cmd_%s = ACTION %s $@' % (name, name))
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.
674 cd_action = 'cd %s; ' % Sourceify(self.path)
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
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))
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)
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)
707 def WriteRules(self, rules, extra_sources, extra_outputs, part_of_all):
708 """Write Makefile code for any 'rules' from the gyp input.
710 extra_sources: a list that will be filled in with newly generated source
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'
717 name = self.target + '_' + StringToMakefileVariable(rule['rule_name'])
719 self.WriteLn('### Generated for rule %s:' % name)
723 for rule_source in rule.get('rule_sources', []):
725 rule_source_basename = os.path.basename(rule_source)
726 (rule_source_root, rule_source_ext) = \
727 os.path.splitext(rule_source_basename)
729 outputs = [self.ExpandInputRoot(out, rule_source_root)
730 for out in rule['outputs']]
732 dir = os.path.dirname(out)
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)]
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
749 actions += ['@touch --no-create $@']
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)
760 action = [self.ExpandInputRoot(ac, rule_source_root)
761 for ac in rule['action']]
764 mkdirs = 'mkdir -p %s; ' % ' '.join(dirs)
766 cd_action = 'cd %s; ' % Sourceify(self.path)
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
774 # TODO(piman): when everything is cross-compile safe, remove lib.target
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,
786 'quiet_cmd_%(name)s_%(count)d = RULE %(name)s_%(count)d $@' % {
793 outputs_variable = 'rule_%s_outputs' % name
794 self.WriteList(all_outputs, outputs_variable)
795 extra_outputs.append('$(%s)' % outputs_variable)
797 self.WriteLn('### Finished generating for rule: %s' % name)
799 self.WriteLn('### Finished generating for all rules')
803 def WriteCopies(self, copies, extra_outputs, part_of_all):
804 """Write Makefile code for any 'copies' from the gyp input.
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'
810 self.WriteLn('### Generated for copy rule.')
812 variable = self.target + '_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'],
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)
827 def WriteSources(self, configs, deps, sources,
828 extra_outputs, extra_link_deps,
830 """Write Makefile code for any 'sources' from the gyp input.
831 These are source files necessary to build the current target.
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'
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')
854 includes = map(Sourceify, map(self.Absolutify, includes))
855 self.WriteList(includes, 'INCS_%s' % configname, prefix='-I')
857 compilable = filter(Compilable, sources)
858 objs = map(self.Objectify, map(self.Absolutify, map(Target, compilable)))
859 self.WriteList(objs, 'OBJS')
861 self.WriteLn('# Add to the list of files we specially track '
863 self.WriteLn('all_deps += $(OBJS)')
864 self._num_outputs += len(objs)
867 # Make sure our dependencies are built first.
869 self.WriteMakeRule(['$(OBJS)'], deps,
870 comment = 'Make sure our dependencies are built '
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.
878 self.WriteMakeRule(['$(OBJS)'], extra_outputs,
879 comment = 'Make sure our actions/rules run '
884 extra_link_deps.append('$(OBJS)')
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))")
900 # If there are any object files in our input file list, link them into our
902 extra_link_deps += filter(Linkable, sources)
907 def ComputeOutput(self, spec):
908 """Return the 'output' (full output path) of a gyp spec.
910 E.g., the loadable module 'foobar' in directory 'baz' will produce
911 '$(obj)/baz/libfoobar.so'
914 target = spec['target_name']
917 path = os.path.join('$(obj).' + self.toolset, self.path)
918 if self.type == 'static_library':
919 if target[:3] == 'lib':
921 target_prefix = 'lib'
923 elif self.type in ('loadable_module', 'shared_library'):
924 if target[:3] == 'lib':
926 target_prefix = 'lib'
928 elif self.type == 'none':
929 target = '%s.stamp' % target
930 elif self.type == 'settings':
932 elif self.type == 'executable':
933 path = os.path.join('$(builddir)')
935 print ("ERROR: What output file should be generated?",
936 "typ", self.type, "target", target)
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')
943 target_ext = '.' + product_ext
945 return os.path.join(path, target_prefix + target + target_ext)
948 def ComputeDeps(self, spec):
949 """Compute the dependencies of a gyp spec.
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).
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))
970 def WriteTarget(self, spec, configs, deps, link_deps, extra_outputs,
972 """Write Makefile code to produce the final target of the gyp spec.
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'
980 self.WriteLn('### Rules for final target.')
983 self.WriteMakeRule([self.output], extra_outputs,
984 comment = 'Build our special outputs first.',
986 self.WriteMakeRule(extra_outputs, deps,
987 comment=('Preserve order dependency of '
988 'special output on deps.'),
990 multiple_output_trick = False)
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')
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)
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.
1017 print "WARNING: no output for", self.type, target
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)
1026 self.WriteMakeRule(['all'], [self.target],
1027 comment = 'Add target alias to "all" target.',
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'
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)
1054 self.WriteMakeRule(['all'], [install_path],
1055 comment = 'Add %s to "all" target.' % file_desc,
1059 def WriteList(self, list, variable=None, prefix='', quoter=QuoteIfNecessary):
1060 """Write a variable definition that is a list of values.
1062 E.g. WriteList(['a','b'], 'foo', prefix='blah') writes out
1064 but in a pretty-printed style.
1066 self.fp.write(variable + " := ")
1068 list = [quoter(prefix + l) for l in list]
1069 self.fp.write(" \\\n\t".join(list))
1070 self.fp.write("\n\n")
1073 def WriteDoCmd(self, outputs, inputs, command, part_of_all, comment=None):
1074 """Write a Makefile rule that uses do_cmd.
1076 This makes the outputs dependent on the command line that was run,
1077 as well as support the V= make command line flag.
1079 self.WriteMakeRule(outputs, inputs,
1080 actions = ['$(call do_cmd,%s)' % command],
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)
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.
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.
1107 self.WriteLn('# ' + comment)
1109 self.WriteLn('.PHONY: ' + ' '.join(outputs))
1110 # TODO(evanm): just make order_only a list of deps instead of these hacks.
1116 force_append = ' FORCE_DO_CMD'
1120 self.WriteLn("%s: TOOLSET := $(TOOLSET)" % outputs[0])
1121 self.WriteLn('%s: %s%s%s' % (outputs[0], order_insert, ' '.join(inputs),
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
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
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
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:])))
1149 def WriteLn(self, text=''):
1150 self.fp.write(text + '\n')
1153 def Objectify(self, path):
1154 """Convert a path to its output directory form."""
1156 path = path.replace('$(obj)/', '$(obj).%s/$(TARGET)/' % self.toolset)
1158 return '$(obj).%s/$(TARGET)/%s' % (self.toolset, path)
1160 def Absolutify(self, path):
1161 """Convert a subdirectory-relative path into a base-relative path.
1162 Skips over paths that contain variables."""
1165 return os.path.normpath(os.path.join(self.path, path))
1168 def FixupArgPath(self, arg):
1169 if '/' in arg or '.h.' in arg:
1170 return self.Absolutify(arg)
1174 def ExpandInputRoot(self, template, expansion):
1175 if '%(INPUT_ROOT)s' not in 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)
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
1194 def WriteAutoRegenerationRule(params, root_makefile, makefile_name,
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) +
1217 def RunSystemTests():
1218 """Run tests against the system to compute default settings for commands.
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.
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'
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'
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
1251 link_flags = '-Wl,--threads --Wl,--thread-count=4'
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.)
1257 return { 'ARFLAGS.target': arflags_target,
1258 'ARFLAGS.host': arflags_host,
1259 'LINK_flags': link_flags }
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')
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),
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
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']
1293 if not default_configuration:
1294 default_configuration = 'Default'
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)/'
1307 'builddir': builddir_name,
1308 'default_configuration': default_configuration,
1310 header_params.update(RunSystemTests())
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)
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)
1327 include_list = set()
1328 for qualified_target in target_list:
1329 build_file, target, toolset = gyp.common.ParseQualifiedTarget(
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
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)
1347 build_files.add(relative_include_file)
1349 base_path, output_file = CalculateMakefilePath(build_file,
1350 target + '.' + toolset + options.suffix + '.mk')
1352 spec = target_dicts[qualified_target]
1353 configs = spec['configurations']
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()
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)
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.
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,
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
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')
1402 if generator_flags.get('auto_regeneration', True):
1403 WriteAutoRegenerationRule(params, root_makefile, makefile_name, build_files)
1405 # Write the rule to load dependencies. We batch 1000 files at a time to
1406 # avoid overflowing the command line.
1408 for i in range(1001, num_outputs, 1000):
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 })
1414 # Add a check to make sure we tried to process all the .d files.
1416 ifneq ($(word %(last)d,$(d_files)),)
1417 $(error Found unprocessed dependency files (gyp didn't generate enough rules!))
1419 """ % { 'last': ((num_outputs / 1000) + 1) * 1000 + 1 }
1421 root_makefile.write(SHARED_FOOTER % { 'generate_all_deps': all_deps })
1423 root_makefile.close()