103
105
global generator_wants_sorted_dependencies
104
106
generator_wants_sorted_dependencies = True
108
output_dir = params['options'].generator_output or \
109
params['options'].toplevel_dir
110
builddir_name = generator_flags.get('output_dir', 'out')
111
qualified_out_dir = os.path.normpath(os.path.join(
112
output_dir, builddir_name, 'gypfiles'))
107
def ensure_directory_exists(path):
108
dir = os.path.dirname(path)
109
if dir and not os.path.exists(dir):
114
global generator_filelist_paths
115
generator_filelist_paths = {
116
'toplevel': params['options'].toplevel_dir,
117
'qualified_out_dir': qualified_out_dir,
113
121
# The .d checking code below uses these functions:
212
LINK_COMMANDS_AIX = """\
213
quiet_cmd_alink = AR($(TOOLSET)) $@
214
cmd_alink = rm -f $@ && $(AR.$(TOOLSET)) crs $@ $(filter %.o,$^)
216
quiet_cmd_alink_thin = AR($(TOOLSET)) $@
217
cmd_alink_thin = rm -f $@ && $(AR.$(TOOLSET)) crs $@ $(filter %.o,$^)
219
quiet_cmd_link = LINK($(TOOLSET)) $@
220
cmd_link = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(LD_INPUTS) $(LIBS)
222
quiet_cmd_solink = SOLINK($(TOOLSET)) $@
223
cmd_solink = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(LD_INPUTS) $(LIBS)
225
quiet_cmd_solink_module = SOLINK_MODULE($(TOOLSET)) $@
226
cmd_solink_module = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(filter-out FORCE_DO_CMD, $^) $(LIBS)
204
230
# Header of toplevel Makefile.
205
231
# This should go into the build tree, but it's easier to keep it here for now.
206
232
SHARED_HEADER = ("""\
255
281
AR.target ?= $(AR)
257
283
# C++ apps need to be linked with g++.
259
# Note: flock is used to seralize linking. Linking is a memory-intensive
260
# process so running parallel links can often lead to thrashing. To disable
261
# the serialization, override LINK via an envrionment variable as follows:
265
# This will allow make to invoke N linker processes as specified in -jN.
266
LINK ?= %(flock)s $(builddir)/linker.lock $(CXX.target)
284
LINK ?= $(CXX.target)
268
286
# TODO(evan): move all cross-compilation logic to gyp-time so we don't need
269
287
# to replicate this environment fallback in make as well.
479
497
cmd_infoplist = $(CC.$(TOOLSET)) -E -P -Wno-trigraphs -x c $(INFOPLIST_DEFINES) "$<" -o "$@"
482
SHARED_HEADER_SUN_COMMANDS = """
483
# gyp-sun-tool is written next to the root Makefile by gyp.
484
# Use $(4) for the command, since $(2) and $(3) are used as flag by do_cmd
486
quiet_cmd_sun_tool = SUNTOOL $(4) $<
487
cmd_sun_tool = ./gyp-sun-tool $(4) $< "$@"
491
501
def WriteRootHeaderSuffixRules(writer):
492
502
extensions = sorted(COMPILABLE_EXTENSIONS.keys(), key=str.lower)
614
624
return s.replace(' ', quote)
627
# TODO: Avoid code duplication with _ValidateSourcesForMSVSProject in msvs.py.
628
def _ValidateSourcesForOSX(spec, all_sources):
629
"""Makes sure if duplicate basenames are not specified in the source list.
632
spec: The target dictionary containing the properties of the target.
634
if spec.get('type', None) != 'static_library':
638
for source in all_sources:
639
name, ext = os.path.splitext(source)
640
is_compiled_file = ext in [
641
'.c', '.cc', '.cpp', '.cxx', '.m', '.mm', '.s', '.S']
642
if not is_compiled_file:
644
basename = os.path.basename(name) # Don't include extension.
645
basenames.setdefault(basename, []).append(source)
648
for basename, files in basenames.iteritems():
650
error += ' %s: %s\n' % (basename, ' '.join(files))
653
print('static library %s has several files with the same basename:\n' %
654
spec['target_name'] + error + 'libtool on OS X will generate' +
655
' warnings for them.')
656
raise GypError('Duplicate basenames in sources section, see list above')
617
659
# Map from qualified target to path to output.
618
660
target_outputs = {}
619
661
# Map from qualified target to any linkable output. A subset
973
1019
# accidentally writing duplicate dummy rules for those outputs.
974
1020
self.WriteLn('%s: obj := $(abs_obj)' % outputs[0])
975
1021
self.WriteLn('%s: builddir := $(abs_builddir)' % outputs[0])
976
self.WriteMakeRule(outputs, inputs + ['FORCE_DO_CMD'], actions)
1022
self.WriteMakeRule(outputs, inputs, actions,
1023
command="%s_%d" % (name, count))
977
1024
# Spaces in rule filenames are not supported, but rule variables have
978
1025
# spaces in them (e.g. RULE_INPUT_PATH expands to '$(abspath $<)').
979
1026
# The spaces within the variables are valid, so remove the variables
1084
1131
for output, res in gyp.xcode_emulation.GetMacBundleResources(
1085
1132
generator_default_variables['PRODUCT_DIR'], self.xcode_settings,
1086
1133
map(Sourceify, map(self.Absolutify, resources))):
1087
self.WriteDoCmd([output], [res], 'mac_tool,,,copy-bundle-resource',
1089
bundle_deps.append(output)
1134
_, ext = os.path.splitext(output)
1135
if ext != '.xcassets':
1136
# Make does not supports '.xcassets' emulation.
1137
self.WriteDoCmd([output], [res], 'mac_tool,,,copy-bundle-resource',
1139
bundle_deps.append(output)
1092
1142
def WriteMacInfoPlist(self, bundle_deps):
1651
1702
def WriteMakeRule(self, outputs, inputs, actions=None, comment=None,
1652
order_only=False, force=False, phony=False):
1703
order_only=False, force=False, phony=False, command=None):
1653
1704
"""Write a Makefile rule, with some extra tricks.
1655
1706
outputs: a list of outputs for the rule (note: this is not directly
1670
1722
self.WriteLn('# ' + comment)
1672
1724
self.WriteLn('.PHONY: ' + ' '.join(outputs))
1673
# TODO(evanm): just make order_only a list of deps instead of these hacks.
1726
self.WriteLn("%s: TOOLSET := $(TOOLSET)" % outputs[0])
1727
force_append = ' FORCE_DO_CMD' if force else ''
1676
pick_output = ' '.join(outputs)
1679
pick_output = outputs[0]
1681
force_append = ' FORCE_DO_CMD'
1685
self.WriteLn("%s: TOOLSET := $(TOOLSET)" % outputs[0])
1686
self.WriteLn('%s: %s%s%s' % (pick_output, order_insert, ' '.join(inputs),
1730
# Order only rule: Just write a simple rule.
1731
# TODO(evanm): just make order_only a list of deps instead of this hack.
1732
self.WriteLn('%s: | %s%s' %
1733
(' '.join(outputs), ' '.join(inputs), force_append))
1734
elif len(outputs) == 1:
1735
# Regular rule, one output: Just write a simple rule.
1736
self.WriteLn('%s: %s%s' % (outputs[0], ' '.join(inputs), force_append))
1738
# Regular rule, more than one output: Multiple outputs are tricky in
1739
# make. We will write three rules:
1740
# - All outputs depend on an intermediate file.
1741
# - Make .INTERMEDIATE depend on the intermediate.
1742
# - The intermediate file depends on the inputs and executes the
1744
# - The intermediate recipe will 'touch' the intermediate file.
1745
# - The multi-output rule will have an do-nothing recipe.
1746
intermediate = "%s.intermediate" % (command if command else self.target)
1747
self.WriteLn('%s: %s' % (' '.join(outputs), intermediate))
1748
self.WriteLn('\t%s' % '@:');
1749
self.WriteLn('%s: %s' % ('.INTERMEDIATE', intermediate))
1750
self.WriteLn('%s: %s%s' %
1751
(intermediate, ' '.join(inputs), force_append))
1752
actions.insert(0, '$(call do_cmd,touch)')
1689
1755
for action in actions:
1690
1756
self.WriteLn('\t%s' % action)
1691
if not order_only and len(outputs) > 1:
1692
# If we have more than one output, a rule like
1694
# that for *each* output we must run the action, potentially
1695
# in parallel. That is not what we're trying to write -- what
1696
# we want is that we run the action once and it generates all
1698
# http://www.gnu.org/software/hello/manual/automake/Multiple-Outputs.html
1699
# discusses this problem and has this solution:
1700
# 1) Write the naive rule that would produce parallel runs of
1702
# 2) Make the outputs seralized on each other, so we won't start
1703
# a parallel run until the first run finishes, at which point
1704
# we'll have generated all the outputs and we're done.
1705
self.WriteLn('%s: %s' % (' '.join(outputs[1:]), outputs[0]))
1706
# Add a dummy command to the "extra outputs" rule, otherwise make seems to
1707
# think these outputs haven't (couldn't have?) changed, and thus doesn't
1708
# flag them as changed (i.e. include in '$?') when evaluating dependent
1709
# rules, which in turn causes do_cmd() to skip running dependent commands.
1710
self.WriteLn('%s: ;' % (' '.join(outputs[1:])))
1934
1980
# We write the file in the base_path directory.
1935
1981
output_file = os.path.join(options.depth, base_path, base_name)
1936
1982
if options.generator_output:
1937
output_file = os.path.join(options.generator_output, output_file)
1983
output_file = os.path.join(
1984
options.depth, options.generator_output, base_path, base_name)
1938
1985
base_path = gyp.common.RelativePath(os.path.dirname(build_file),
1939
1986
options.toplevel_dir)
1940
1987
return base_path, output_file
1957
2004
makefile_path = os.path.join(options.toplevel_dir, makefile_name)
1958
2005
if options.generator_output:
1959
2006
global srcdir_prefix
1960
makefile_path = os.path.join(options.generator_output, makefile_path)
2007
makefile_path = os.path.join(
2008
options.toplevel_dir, options.generator_output, makefile_name)
1961
2009
srcdir = gyp.common.RelativePath(srcdir, options.generator_output)
1962
2010
srcdir_prefix = '$(srcdir)/'
1987
2035
elif flavor == 'solaris':
1988
2036
header_params.update({
1989
'flock': './gyp-sun-tool flock',
2037
'flock': './gyp-flock-tool flock',
1990
2038
'flock_index': 2,
1991
'extra_commands': SHARED_HEADER_SUN_COMMANDS,
1993
2040
elif flavor == 'freebsd':
1994
2041
# Note: OpenBSD has sysutils/flock. lockf seems to be FreeBSD specific.
1995
2042
header_params.update({
1996
2043
'flock': 'lockf',
2045
elif flavor == 'aix':
2046
header_params.update({
2047
'link_commands': LINK_COMMANDS_AIX,
2048
'flock': './gyp-flock-tool flock',
1999
2052
header_params.update({
2000
2053
'CC.target': GetEnvironFallback(('CC_target', 'CC'), '$(CC)'),
2028
2080
make_global_settings += (
2029
2081
'ifneq (,$(filter $(origin %s), undefined default))\n' % key)
2030
2082
# Let gyp-time envvars win over global settings.
2031
if key in os.environ:
2032
value = os.environ[key]
2083
env_key = key.replace('.', '_') # CC.host -> CC_host
2084
if env_key in os.environ:
2085
value = os.environ[env_key]
2033
2086
make_global_settings += ' %s = %s\n' % (key, value)
2034
2087
make_global_settings += 'endif\n'
2072
2125
this_make_global_settings = data[build_file].get('make_global_settings', [])
2073
2126
assert make_global_settings_array == this_make_global_settings, (
2074
"make_global_settings needs to be the same for all targets.")
2127
"make_global_settings needs to be the same for all targets. %s vs. %s" %
2128
(this_make_global_settings, make_global_settings))
2076
2130
build_files.add(gyp.common.RelativePath(build_file, options.toplevel_dir))
2077
2131
included_files = data[build_file]['included_files']