1# Copyright (c) 2013 Google Inc. All rights reserved. 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4 5# Notes: 6# 7# This is all roughly based on the Makefile system used by the Linux 8# kernel, but is a non-recursive make -- we put the entire dependency 9# graph in front of make and let it figure it out. 10# 11# The code below generates a separate .mk file for each target, but 12# all are sourced by the top-level Makefile. This means that all 13# variables in .mk-files clobber one another. Be careful to use := 14# where appropriate for immediate evaluation, and similarly to watch 15# that you're not relying on a variable value to last beween different 16# .mk files. 17# 18# TODOs: 19# 20# Global settings and utility functions are currently stuffed in the 21# toplevel Makefile. It may make sense to generate some .mk files on 22# the side to keep the the files readable. 23 24import os 25import re 26import sys 27import subprocess 28import gyp 29import gyp.common 30import gyp.xcode_emulation 31from gyp.common import GetEnvironFallback 32 33generator_default_variables = { 34 'EXECUTABLE_PREFIX': '', 35 'EXECUTABLE_SUFFIX': '', 36 'STATIC_LIB_PREFIX': 'lib', 37 'SHARED_LIB_PREFIX': 'lib', 38 'STATIC_LIB_SUFFIX': '.a', 39 'INTERMEDIATE_DIR': '$(obj).$(TOOLSET)/$(TARGET)/geni', 40 'SHARED_INTERMEDIATE_DIR': '$(obj)/gen', 41 'PRODUCT_DIR': '$(builddir)', 42 'RULE_INPUT_ROOT': '%(INPUT_ROOT)s', # This gets expanded by Python. 43 'RULE_INPUT_DIRNAME': '%(INPUT_DIRNAME)s', # This gets expanded by Python. 44 'RULE_INPUT_PATH': '$(abspath $<)', 45 'RULE_INPUT_EXT': '$(suffix $<)', 46 'RULE_INPUT_NAME': '$(notdir $<)', 47 'CONFIGURATION_NAME': '$(BUILDTYPE)', 48} 49 50# Make supports multiple toolsets 51generator_supports_multiple_toolsets = True 52 53# Request sorted dependencies in the order from dependents to dependencies. 54generator_wants_sorted_dependencies = False 55 56# Placates pylint. 57generator_additional_non_configuration_keys = [] 58generator_additional_path_sections = [] 59generator_extra_sources_for_rules = [] 60generator_filelist_paths = None 61 62 63def CalculateVariables(default_variables, params): 64 """Calculate additional variables for use in the build (called by gyp).""" 65 flavor = gyp.common.GetFlavor(params) 66 if flavor == 'mac': 67 default_variables.setdefault('OS', 'mac') 68 default_variables.setdefault('SHARED_LIB_SUFFIX', '.dylib') 69 default_variables.setdefault('SHARED_LIB_DIR', 70 generator_default_variables['PRODUCT_DIR']) 71 default_variables.setdefault('LIB_DIR', 72 generator_default_variables['PRODUCT_DIR']) 73 74 # Copy additional generator configuration data from Xcode, which is shared 75 # by the Mac Make generator. 76 import gyp.generator.xcode as xcode_generator 77 global generator_additional_non_configuration_keys 78 generator_additional_non_configuration_keys = getattr(xcode_generator, 79 'generator_additional_non_configuration_keys', []) 80 global generator_additional_path_sections 81 generator_additional_path_sections = getattr(xcode_generator, 82 'generator_additional_path_sections', []) 83 global generator_extra_sources_for_rules 84 generator_extra_sources_for_rules = getattr(xcode_generator, 85 'generator_extra_sources_for_rules', []) 86 COMPILABLE_EXTENSIONS.update({'.m': 'objc', '.mm' : 'objcxx'}) 87 else: 88 operating_system = flavor 89 if flavor == 'android': 90 operating_system = 'linux' # Keep this legacy behavior for now. 91 default_variables.setdefault('OS', operating_system) 92 default_variables.setdefault('SHARED_LIB_SUFFIX', '.so') 93 default_variables.setdefault('SHARED_LIB_DIR','$(builddir)/lib.$(TOOLSET)') 94 default_variables.setdefault('LIB_DIR', '$(obj).$(TOOLSET)') 95 96 97def CalculateGeneratorInputInfo(params): 98 """Calculate the generator specific info that gets fed to input (called by 99 gyp).""" 100 generator_flags = params.get('generator_flags', {}) 101 android_ndk_version = generator_flags.get('android_ndk_version', None) 102 # Android NDK requires a strict link order. 103 if android_ndk_version: 104 global generator_wants_sorted_dependencies 105 generator_wants_sorted_dependencies = True 106 107 output_dir = params['options'].generator_output or \ 108 params['options'].toplevel_dir 109 builddir_name = generator_flags.get('output_dir', 'out') 110 qualified_out_dir = os.path.normpath(os.path.join( 111 output_dir, builddir_name, 'gypfiles')) 112 113 global generator_filelist_paths 114 generator_filelist_paths = { 115 'toplevel': params['options'].toplevel_dir, 116 'qualified_out_dir': qualified_out_dir, 117 } 118 119 120# The .d checking code below uses these functions: 121# wildcard, sort, foreach, shell, wordlist 122# wildcard can handle spaces, the rest can't. 123# Since I could find no way to make foreach work with spaces in filenames 124# correctly, the .d files have spaces replaced with another character. The .d 125# file for 126# Chromium\ Framework.framework/foo 127# is for example 128# out/Release/.deps/out/Release/Chromium?Framework.framework/foo 129# This is the replacement character. 130SPACE_REPLACEMENT = '?' 131 132 133LINK_COMMANDS_LINUX = """\ 134quiet_cmd_alink = AR($(TOOLSET)) $@ 135cmd_alink = rm -f $@ && $(AR.$(TOOLSET)) crs $@ $(filter %.o,$^) 136 137quiet_cmd_alink_thin = AR($(TOOLSET)) $@ 138cmd_alink_thin = rm -f $@ && $(AR.$(TOOLSET)) crsT $@ $(filter %.o,$^) 139 140# Due to circular dependencies between libraries :(, we wrap the 141# special "figure out circular dependencies" flags around the entire 142# input list during linking. 143quiet_cmd_link = LINK($(TOOLSET)) $@ 144cmd_link = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ -Wl,--start-group $(LD_INPUTS) -Wl,--end-group $(LIBS) 145 146# We support two kinds of shared objects (.so): 147# 1) shared_library, which is just bundling together many dependent libraries 148# into a link line. 149# 2) loadable_module, which is generating a module intended for dlopen(). 150# 151# They differ only slightly: 152# In the former case, we want to package all dependent code into the .so. 153# In the latter case, we want to package just the API exposed by the 154# outermost module. 155# This means shared_library uses --whole-archive, while loadable_module doesn't. 156# (Note that --whole-archive is incompatible with the --start-group used in 157# normal linking.) 158 159# Other shared-object link notes: 160# - Set SONAME to the library filename so our binaries don't reference 161# the local, absolute paths used on the link command-line. 162quiet_cmd_solink = SOLINK($(TOOLSET)) $@ 163cmd_solink = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -Wl,-soname=$(@F) -o $@ -Wl,--whole-archive $(LD_INPUTS) -Wl,--no-whole-archive $(LIBS) 164 165quiet_cmd_solink_module = SOLINK_MODULE($(TOOLSET)) $@ 166cmd_solink_module = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -Wl,-soname=$(@F) -o $@ -Wl,--start-group $(filter-out FORCE_DO_CMD, $^) -Wl,--end-group $(LIBS) 167""" 168 169LINK_COMMANDS_MAC = """\ 170quiet_cmd_alink = LIBTOOL-STATIC $@ 171cmd_alink = rm -f $@ && ./gyp-mac-tool filter-libtool libtool $(GYP_LIBTOOLFLAGS) -static -o $@ $(filter %.o,$^) 172 173quiet_cmd_link = LINK($(TOOLSET)) $@ 174cmd_link = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o "$@" $(LD_INPUTS) $(LIBS) 175 176quiet_cmd_solink = SOLINK($(TOOLSET)) $@ 177cmd_solink = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o "$@" $(LD_INPUTS) $(LIBS) 178 179quiet_cmd_solink_module = SOLINK_MODULE($(TOOLSET)) $@ 180cmd_solink_module = $(LINK.$(TOOLSET)) -bundle $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(filter-out FORCE_DO_CMD, $^) $(LIBS) 181""" 182 183LINK_COMMANDS_ANDROID = """\ 184quiet_cmd_alink = AR($(TOOLSET)) $@ 185cmd_alink = rm -f $@ && $(AR.$(TOOLSET)) crs $@ $(filter %.o,$^) 186 187quiet_cmd_alink_thin = AR($(TOOLSET)) $@ 188cmd_alink_thin = rm -f $@ && $(AR.$(TOOLSET)) crsT $@ $(filter %.o,$^) 189 190# Due to circular dependencies between libraries :(, we wrap the 191# special "figure out circular dependencies" flags around the entire 192# input list during linking. 193quiet_cmd_link = LINK($(TOOLSET)) $@ 194quiet_cmd_link_host = LINK($(TOOLSET)) $@ 195cmd_link = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ -Wl,--start-group $(LD_INPUTS) -Wl,--end-group $(LIBS) 196cmd_link_host = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(LD_INPUTS) $(LIBS) 197 198# Other shared-object link notes: 199# - Set SONAME to the library filename so our binaries don't reference 200# the local, absolute paths used on the link command-line. 201quiet_cmd_solink = SOLINK($(TOOLSET)) $@ 202cmd_solink = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -Wl,-soname=$(@F) -o $@ -Wl,--whole-archive $(LD_INPUTS) -Wl,--no-whole-archive $(LIBS) 203 204quiet_cmd_solink_module = SOLINK_MODULE($(TOOLSET)) $@ 205cmd_solink_module = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -Wl,-soname=$(@F) -o $@ -Wl,--start-group $(filter-out FORCE_DO_CMD, $^) -Wl,--end-group $(LIBS) 206quiet_cmd_solink_module_host = SOLINK_MODULE($(TOOLSET)) $@ 207cmd_solink_module_host = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -Wl,-soname=$(@F) -o $@ $(filter-out FORCE_DO_CMD, $^) $(LIBS) 208""" 209 210 211LINK_COMMANDS_AIX = """\ 212quiet_cmd_alink = AR($(TOOLSET)) $@ 213cmd_alink = rm -f $@ && $(AR.$(TOOLSET)) crs $@ $(filter %.o,$^) 214 215quiet_cmd_alink_thin = AR($(TOOLSET)) $@ 216cmd_alink_thin = rm -f $@ && $(AR.$(TOOLSET)) crs $@ $(filter %.o,$^) 217 218quiet_cmd_link = LINK($(TOOLSET)) $@ 219cmd_link = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(LD_INPUTS) $(LIBS) 220 221quiet_cmd_solink = SOLINK($(TOOLSET)) $@ 222cmd_solink = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(LD_INPUTS) $(LIBS) 223 224quiet_cmd_solink_module = SOLINK_MODULE($(TOOLSET)) $@ 225cmd_solink_module = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(filter-out FORCE_DO_CMD, $^) $(LIBS) 226""" 227 228 229# Header of toplevel Makefile. 230# This should go into the build tree, but it's easier to keep it here for now. 231SHARED_HEADER = ("""\ 232# We borrow heavily from the kernel build setup, though we are simpler since 233# we don't have Kconfig tweaking settings on us. 234 235# The implicit make rules have it looking for RCS files, among other things. 236# We instead explicitly write all the rules we care about. 237# It's even quicker (saves ~200ms) to pass -r on the command line. 238MAKEFLAGS=-r 239 240# The source directory tree. 241srcdir := %(srcdir)s 242abs_srcdir := $(abspath $(srcdir)) 243 244# The name of the builddir. 245builddir_name ?= %(builddir)s 246 247# The V=1 flag on command line makes us verbosely print command lines. 248ifdef V 249 quiet= 250else 251 quiet=quiet_ 252endif 253 254# Specify BUILDTYPE=Release on the command line for a release build. 255BUILDTYPE ?= %(default_configuration)s 256 257# Directory all our build output goes into. 258# Note that this must be two directories beneath src/ for unit tests to pass, 259# as they reach into the src/ directory for data with relative paths. 260builddir ?= $(builddir_name)/$(BUILDTYPE) 261abs_builddir := $(abspath $(builddir)) 262depsdir := $(builddir)/.deps 263 264# Object output directory. 265obj := $(builddir)/obj 266abs_obj := $(abspath $(obj)) 267 268# We build up a list of every single one of the targets so we can slurp in the 269# generated dependency rule Makefiles in one pass. 270all_deps := 271 272%(make_global_settings)s 273 274CC.target ?= %(CC.target)s 275CFLAGS.target ?= $(CFLAGS) 276CXX.target ?= %(CXX.target)s 277CXXFLAGS.target ?= $(CXXFLAGS) 278LINK.target ?= %(LINK.target)s 279LDFLAGS.target ?= $(LDFLAGS) 280AR.target ?= $(AR) 281 282# C++ apps need to be linked with g++. 283# 284# Note: flock is used to seralize linking. Linking is a memory-intensive 285# process so running parallel links can often lead to thrashing. To disable 286# the serialization, override LINK via an envrionment variable as follows: 287# 288# export LINK=g++ 289# 290# This will allow make to invoke N linker processes as specified in -jN. 291LINK ?= %(flock)s $(builddir)/linker.lock $(CXX.target) 292 293# TODO(evan): move all cross-compilation logic to gyp-time so we don't need 294# to replicate this environment fallback in make as well. 295CC.host ?= %(CC.host)s 296CFLAGS.host ?= 297CXX.host ?= %(CXX.host)s 298CXXFLAGS.host ?= 299LINK.host ?= %(LINK.host)s 300LDFLAGS.host ?= 301AR.host ?= %(AR.host)s 302 303# Define a dir function that can handle spaces. 304# http://www.gnu.org/software/make/manual/make.html#Syntax-of-Functions 305# "leading spaces cannot appear in the text of the first argument as written. 306# These characters can be put into the argument value by variable substitution." 307empty := 308space := $(empty) $(empty) 309 310# http://stackoverflow.com/questions/1189781/using-make-dir-or-notdir-on-a-path-with-spaces 311replace_spaces = $(subst $(space),""" + SPACE_REPLACEMENT + """,$1) 312unreplace_spaces = $(subst """ + SPACE_REPLACEMENT + """,$(space),$1) 313dirx = $(call unreplace_spaces,$(dir $(call replace_spaces,$1))) 314 315# Flags to make gcc output dependency info. Note that you need to be 316# careful here to use the flags that ccache and distcc can understand. 317# We write to a dep file on the side first and then rename at the end 318# so we can't end up with a broken dep file. 319depfile = $(depsdir)/$(call replace_spaces,$@).d 320DEPFLAGS = -MMD -MF $(depfile).raw 321 322# We have to fixup the deps output in a few ways. 323# (1) the file output should mention the proper .o file. 324# ccache or distcc lose the path to the target, so we convert a rule of 325# the form: 326# foobar.o: DEP1 DEP2 327# into 328# path/to/foobar.o: DEP1 DEP2 329# (2) we want missing files not to cause us to fail to build. 330# We want to rewrite 331# foobar.o: DEP1 DEP2 \\ 332# DEP3 333# to 334# DEP1: 335# DEP2: 336# DEP3: 337# so if the files are missing, they're just considered phony rules. 338# We have to do some pretty insane escaping to get those backslashes 339# and dollar signs past make, the shell, and sed at the same time. 340# Doesn't work with spaces, but that's fine: .d files have spaces in 341# their names replaced with other characters.""" 342r""" 343define fixup_dep 344# The depfile may not exist if the input file didn't have any #includes. 345touch $(depfile).raw 346# Fixup path as in (1). 347sed -e "s|^$(notdir $@)|$@|" $(depfile).raw >> $(depfile) 348# Add extra rules as in (2). 349# We remove slashes and replace spaces with new lines; 350# remove blank lines; 351# delete the first line and append a colon to the remaining lines. 352sed -e 's|\\||' -e 'y| |\n|' $(depfile).raw |\ 353 grep -v '^$$' |\ 354 sed -e 1d -e 's|$$|:|' \ 355 >> $(depfile) 356rm $(depfile).raw 357endef 358""" 359""" 360# Command definitions: 361# - cmd_foo is the actual command to run; 362# - quiet_cmd_foo is the brief-output summary of the command. 363 364quiet_cmd_cc = CC($(TOOLSET)) $@ 365cmd_cc = $(CC.$(TOOLSET)) $(GYP_CFLAGS) $(DEPFLAGS) $(CFLAGS.$(TOOLSET)) -c -o $@ $< 366 367quiet_cmd_cxx = CXX($(TOOLSET)) $@ 368cmd_cxx = $(CXX.$(TOOLSET)) $(GYP_CXXFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $< 369%(extra_commands)s 370quiet_cmd_touch = TOUCH $@ 371cmd_touch = touch $@ 372 373quiet_cmd_copy = COPY $@ 374# send stderr to /dev/null to ignore messages when linking directories. 375cmd_copy = ln -f "$<" "$@" 2>/dev/null || (rm -rf "$@" && cp -af "$<" "$@") 376 377%(link_commands)s 378""" 379 380r""" 381# Define an escape_quotes function to escape single quotes. 382# This allows us to handle quotes properly as long as we always use 383# use single quotes and escape_quotes. 384escape_quotes = $(subst ','\'',$(1)) 385# This comment is here just to include a ' to unconfuse syntax highlighting. 386# Define an escape_vars function to escape '$' variable syntax. 387# This allows us to read/write command lines with shell variables (e.g. 388# $LD_LIBRARY_PATH), without triggering make substitution. 389escape_vars = $(subst $$,$$$$,$(1)) 390# Helper that expands to a shell command to echo a string exactly as it is in 391# make. This uses printf instead of echo because printf's behaviour with respect 392# to escape sequences is more portable than echo's across different shells 393# (e.g., dash, bash). 394exact_echo = printf '%%s\n' '$(call escape_quotes,$(1))' 395""" 396""" 397# Helper to compare the command we're about to run against the command 398# we logged the last time we ran the command. Produces an empty 399# string (false) when the commands match. 400# Tricky point: Make has no string-equality test function. 401# The kernel uses the following, but it seems like it would have false 402# positives, where one string reordered its arguments. 403# arg_check = $(strip $(filter-out $(cmd_$(1)), $(cmd_$@)) \\ 404# $(filter-out $(cmd_$@), $(cmd_$(1)))) 405# We instead substitute each for the empty string into the other, and 406# say they're equal if both substitutions produce the empty string. 407# .d files contain """ + SPACE_REPLACEMENT + \ 408 """ instead of spaces, take that into account. 409command_changed = $(or $(subst $(cmd_$(1)),,$(cmd_$(call replace_spaces,$@))),\\ 410 $(subst $(cmd_$(call replace_spaces,$@)),,$(cmd_$(1)))) 411 412# Helper that is non-empty when a prerequisite changes. 413# Normally make does this implicitly, but we force rules to always run 414# so we can check their command lines. 415# $? -- new prerequisites 416# $| -- order-only dependencies 417prereq_changed = $(filter-out FORCE_DO_CMD,$(filter-out $|,$?)) 418 419# Helper that executes all postbuilds until one fails. 420define do_postbuilds 421 @E=0;\\ 422 for p in $(POSTBUILDS); do\\ 423 eval $$p;\\ 424 E=$$?;\\ 425 if [ $$E -ne 0 ]; then\\ 426 break;\\ 427 fi;\\ 428 done;\\ 429 if [ $$E -ne 0 ]; then\\ 430 rm -rf "$@";\\ 431 exit $$E;\\ 432 fi 433endef 434 435# do_cmd: run a command via the above cmd_foo names, if necessary. 436# Should always run for a given target to handle command-line changes. 437# Second argument, if non-zero, makes it do asm/C/C++ dependency munging. 438# Third argument, if non-zero, makes it do POSTBUILDS processing. 439# Note: We intentionally do NOT call dirx for depfile, since it contains """ + \ 440 SPACE_REPLACEMENT + """ for 441# spaces already and dirx strips the """ + SPACE_REPLACEMENT + \ 442 """ characters. 443define do_cmd 444$(if $(or $(command_changed),$(prereq_changed)), 445 @$(call exact_echo, $($(quiet)cmd_$(1))) 446 @mkdir -p "$(call dirx,$@)" "$(dir $(depfile))" 447 $(if $(findstring flock,$(word %(flock_index)d,$(cmd_$1))), 448 @$(cmd_$(1)) 449 @echo " $(quiet_cmd_$(1)): Finished", 450 @$(cmd_$(1)) 451 ) 452 @$(call exact_echo,$(call escape_vars,cmd_$(call replace_spaces,$@) := $(cmd_$(1)))) > $(depfile) 453 @$(if $(2),$(fixup_dep)) 454 $(if $(and $(3), $(POSTBUILDS)), 455 $(call do_postbuilds) 456 ) 457) 458endef 459 460# Declare the "%(default_target)s" target first so it is the default, 461# even though we don't have the deps yet. 462.PHONY: %(default_target)s 463%(default_target)s: 464 465# make looks for ways to re-generate included makefiles, but in our case, we 466# don't have a direct way. Explicitly telling make that it has nothing to do 467# for them makes it go faster. 468%%.d: ; 469 470# Use FORCE_DO_CMD to force a target to run. Should be coupled with 471# do_cmd. 472.PHONY: FORCE_DO_CMD 473FORCE_DO_CMD: 474 475""") 476 477SHARED_HEADER_MAC_COMMANDS = """ 478quiet_cmd_objc = CXX($(TOOLSET)) $@ 479cmd_objc = $(CC.$(TOOLSET)) $(GYP_OBJCFLAGS) $(DEPFLAGS) -c -o $@ $< 480 481quiet_cmd_objcxx = CXX($(TOOLSET)) $@ 482cmd_objcxx = $(CXX.$(TOOLSET)) $(GYP_OBJCXXFLAGS) $(DEPFLAGS) -c -o $@ $< 483 484# Commands for precompiled header files. 485quiet_cmd_pch_c = CXX($(TOOLSET)) $@ 486cmd_pch_c = $(CC.$(TOOLSET)) $(GYP_PCH_CFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $< 487quiet_cmd_pch_cc = CXX($(TOOLSET)) $@ 488cmd_pch_cc = $(CC.$(TOOLSET)) $(GYP_PCH_CXXFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $< 489quiet_cmd_pch_m = CXX($(TOOLSET)) $@ 490cmd_pch_m = $(CC.$(TOOLSET)) $(GYP_PCH_OBJCFLAGS) $(DEPFLAGS) -c -o $@ $< 491quiet_cmd_pch_mm = CXX($(TOOLSET)) $@ 492cmd_pch_mm = $(CC.$(TOOLSET)) $(GYP_PCH_OBJCXXFLAGS) $(DEPFLAGS) -c -o $@ $< 493 494# gyp-mac-tool is written next to the root Makefile by gyp. 495# Use $(4) for the command, since $(2) and $(3) are used as flag by do_cmd 496# already. 497quiet_cmd_mac_tool = MACTOOL $(4) $< 498cmd_mac_tool = ./gyp-mac-tool $(4) $< "$@" 499 500quiet_cmd_mac_package_framework = PACKAGE FRAMEWORK $@ 501cmd_mac_package_framework = ./gyp-mac-tool package-framework "$@" $(4) 502 503quiet_cmd_infoplist = INFOPLIST $@ 504cmd_infoplist = $(CC.$(TOOLSET)) -E -P -Wno-trigraphs -x c $(INFOPLIST_DEFINES) "$<" -o "$@" 505""" 506 507 508def WriteRootHeaderSuffixRules(writer): 509 extensions = sorted(COMPILABLE_EXTENSIONS.keys(), key=str.lower) 510 511 writer.write('# Suffix rules, putting all outputs into $(obj).\n') 512 for ext in extensions: 513 writer.write('$(obj).$(TOOLSET)/%%.o: $(srcdir)/%%%s FORCE_DO_CMD\n' % ext) 514 writer.write('\t@$(call do_cmd,%s,1)\n' % COMPILABLE_EXTENSIONS[ext]) 515 516 writer.write('\n# Try building from generated source, too.\n') 517 for ext in extensions: 518 writer.write( 519 '$(obj).$(TOOLSET)/%%.o: $(obj).$(TOOLSET)/%%%s FORCE_DO_CMD\n' % ext) 520 writer.write('\t@$(call do_cmd,%s,1)\n' % COMPILABLE_EXTENSIONS[ext]) 521 writer.write('\n') 522 for ext in extensions: 523 writer.write('$(obj).$(TOOLSET)/%%.o: $(obj)/%%%s FORCE_DO_CMD\n' % ext) 524 writer.write('\t@$(call do_cmd,%s,1)\n' % COMPILABLE_EXTENSIONS[ext]) 525 writer.write('\n') 526 527 528SHARED_HEADER_SUFFIX_RULES_COMMENT1 = ("""\ 529# Suffix rules, putting all outputs into $(obj). 530""") 531 532 533SHARED_HEADER_SUFFIX_RULES_COMMENT2 = ("""\ 534# Try building from generated source, too. 535""") 536 537 538SHARED_FOOTER = """\ 539# "all" is a concatenation of the "all" targets from all the included 540# sub-makefiles. This is just here to clarify. 541all: 542 543# Add in dependency-tracking rules. $(all_deps) is the list of every single 544# target in our tree. Only consider the ones with .d (dependency) info: 545d_files := $(wildcard $(foreach f,$(all_deps),$(depsdir)/$(f).d)) 546ifneq ($(d_files),) 547 include $(d_files) 548endif 549""" 550 551header = """\ 552# This file is generated by gyp; do not edit. 553 554""" 555 556# Maps every compilable file extension to the do_cmd that compiles it. 557COMPILABLE_EXTENSIONS = { 558 '.c': 'cc', 559 '.cc': 'cxx', 560 '.cpp': 'cxx', 561 '.cxx': 'cxx', 562 '.s': 'cc', 563 '.S': 'cc', 564} 565 566def Compilable(filename): 567 """Return true if the file is compilable (should be in OBJS).""" 568 for res in (filename.endswith(e) for e in COMPILABLE_EXTENSIONS): 569 if res: 570 return True 571 return False 572 573 574def Linkable(filename): 575 """Return true if the file is linkable (should be on the link line).""" 576 return filename.endswith('.o') 577 578 579def Target(filename): 580 """Translate a compilable filename to its .o target.""" 581 return os.path.splitext(filename)[0] + '.o' 582 583 584def EscapeShellArgument(s): 585 """Quotes an argument so that it will be interpreted literally by a POSIX 586 shell. Taken from 587 http://stackoverflow.com/questions/35817/whats-the-best-way-to-escape-ossystem-calls-in-python 588 """ 589 return "'" + s.replace("'", "'\\''") + "'" 590 591 592def EscapeMakeVariableExpansion(s): 593 """Make has its own variable expansion syntax using $. We must escape it for 594 string to be interpreted literally.""" 595 return s.replace('$', '$$') 596 597 598def EscapeCppDefine(s): 599 """Escapes a CPP define so that it will reach the compiler unaltered.""" 600 s = EscapeShellArgument(s) 601 s = EscapeMakeVariableExpansion(s) 602 # '#' characters must be escaped even embedded in a string, else Make will 603 # treat it as the start of a comment. 604 return s.replace('#', r'\#') 605 606 607def QuoteIfNecessary(string): 608 """TODO: Should this ideally be replaced with one or more of the above 609 functions?""" 610 if '"' in string: 611 string = '"' + string.replace('"', '\\"') + '"' 612 return string 613 614 615def StringToMakefileVariable(string): 616 """Convert a string to a value that is acceptable as a make variable name.""" 617 return re.sub('[^a-zA-Z0-9_]', '_', string) 618 619 620srcdir_prefix = '' 621def Sourceify(path): 622 """Convert a path to its source directory form.""" 623 if '$(' in path: 624 return path 625 if os.path.isabs(path): 626 return path 627 return srcdir_prefix + path 628 629 630def QuoteSpaces(s, quote=r'\ '): 631 return s.replace(' ', quote) 632 633 634# Map from qualified target to path to output. 635target_outputs = {} 636# Map from qualified target to any linkable output. A subset 637# of target_outputs. E.g. when mybinary depends on liba, we want to 638# include liba in the linker line; when otherbinary depends on 639# mybinary, we just want to build mybinary first. 640target_link_deps = {} 641 642 643class MakefileWriter: 644 """MakefileWriter packages up the writing of one target-specific foobar.mk. 645 646 Its only real entry point is Write(), and is mostly used for namespacing. 647 """ 648 649 def __init__(self, generator_flags, flavor): 650 self.generator_flags = generator_flags 651 self.flavor = flavor 652 653 self.suffix_rules_srcdir = {} 654 self.suffix_rules_objdir1 = {} 655 self.suffix_rules_objdir2 = {} 656 657 # Generate suffix rules for all compilable extensions. 658 for ext in COMPILABLE_EXTENSIONS.keys(): 659 # Suffix rules for source folder. 660 self.suffix_rules_srcdir.update({ext: ("""\ 661$(obj).$(TOOLSET)/$(TARGET)/%%.o: $(srcdir)/%%%s FORCE_DO_CMD 662 @$(call do_cmd,%s,1) 663""" % (ext, COMPILABLE_EXTENSIONS[ext]))}) 664 665 # Suffix rules for generated source files. 666 self.suffix_rules_objdir1.update({ext: ("""\ 667$(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj).$(TOOLSET)/%%%s FORCE_DO_CMD 668 @$(call do_cmd,%s,1) 669""" % (ext, COMPILABLE_EXTENSIONS[ext]))}) 670 self.suffix_rules_objdir2.update({ext: ("""\ 671$(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD 672 @$(call do_cmd,%s,1) 673""" % (ext, COMPILABLE_EXTENSIONS[ext]))}) 674 675 676 def Write(self, qualified_target, base_path, output_filename, spec, configs, 677 part_of_all): 678 """The main entry point: writes a .mk file for a single target. 679 680 Arguments: 681 qualified_target: target we're generating 682 base_path: path relative to source root we're building in, used to resolve 683 target-relative paths 684 output_filename: output .mk file name to write 685 spec, configs: gyp info 686 part_of_all: flag indicating this target is part of 'all' 687 """ 688 gyp.common.EnsureDirExists(output_filename) 689 690 self.fp = open(output_filename, 'w') 691 692 self.fp.write(header) 693 694 self.qualified_target = qualified_target 695 self.path = base_path 696 self.target = spec['target_name'] 697 self.type = spec['type'] 698 self.toolset = spec['toolset'] 699 700 self.is_mac_bundle = gyp.xcode_emulation.IsMacBundle(self.flavor, spec) 701 if self.flavor == 'mac': 702 self.xcode_settings = gyp.xcode_emulation.XcodeSettings(spec) 703 else: 704 self.xcode_settings = None 705 706 deps, link_deps = self.ComputeDeps(spec) 707 708 # Some of the generation below can add extra output, sources, or 709 # link dependencies. All of the out params of the functions that 710 # follow use names like extra_foo. 711 extra_outputs = [] 712 extra_sources = [] 713 extra_link_deps = [] 714 extra_mac_bundle_resources = [] 715 mac_bundle_deps = [] 716 717 if self.is_mac_bundle: 718 self.output = self.ComputeMacBundleOutput(spec) 719 self.output_binary = self.ComputeMacBundleBinaryOutput(spec) 720 else: 721 self.output = self.output_binary = self.ComputeOutput(spec) 722 723 self.is_standalone_static_library = bool( 724 spec.get('standalone_static_library', 0)) 725 self._INSTALLABLE_TARGETS = ('executable', 'loadable_module', 726 'shared_library') 727 if (self.is_standalone_static_library or 728 self.type in self._INSTALLABLE_TARGETS): 729 self.alias = os.path.basename(self.output) 730 install_path = self._InstallableTargetInstallPath() 731 else: 732 self.alias = self.output 733 install_path = self.output 734 735 self.WriteLn("TOOLSET := " + self.toolset) 736 self.WriteLn("TARGET := " + self.target) 737 738 # Actions must come first, since they can generate more OBJs for use below. 739 if 'actions' in spec: 740 self.WriteActions(spec['actions'], extra_sources, extra_outputs, 741 extra_mac_bundle_resources, part_of_all) 742 743 # Rules must be early like actions. 744 if 'rules' in spec: 745 self.WriteRules(spec['rules'], extra_sources, extra_outputs, 746 extra_mac_bundle_resources, part_of_all) 747 748 if 'copies' in spec: 749 self.WriteCopies(spec['copies'], extra_outputs, part_of_all) 750 751 # Bundle resources. 752 if self.is_mac_bundle: 753 all_mac_bundle_resources = ( 754 spec.get('mac_bundle_resources', []) + extra_mac_bundle_resources) 755 self.WriteMacBundleResources(all_mac_bundle_resources, mac_bundle_deps) 756 self.WriteMacInfoPlist(mac_bundle_deps) 757 758 # Sources. 759 all_sources = spec.get('sources', []) + extra_sources 760 if all_sources: 761 self.WriteSources( 762 configs, deps, all_sources, extra_outputs, 763 extra_link_deps, part_of_all, 764 gyp.xcode_emulation.MacPrefixHeader( 765 self.xcode_settings, lambda p: Sourceify(self.Absolutify(p)), 766 self.Pchify)) 767 sources = filter(Compilable, all_sources) 768 if sources: 769 self.WriteLn(SHARED_HEADER_SUFFIX_RULES_COMMENT1) 770 extensions = set([os.path.splitext(s)[1] for s in sources]) 771 for ext in extensions: 772 if ext in self.suffix_rules_srcdir: 773 self.WriteLn(self.suffix_rules_srcdir[ext]) 774 self.WriteLn(SHARED_HEADER_SUFFIX_RULES_COMMENT2) 775 for ext in extensions: 776 if ext in self.suffix_rules_objdir1: 777 self.WriteLn(self.suffix_rules_objdir1[ext]) 778 for ext in extensions: 779 if ext in self.suffix_rules_objdir2: 780 self.WriteLn(self.suffix_rules_objdir2[ext]) 781 self.WriteLn('# End of this set of suffix rules') 782 783 # Add dependency from bundle to bundle binary. 784 if self.is_mac_bundle: 785 mac_bundle_deps.append(self.output_binary) 786 787 self.WriteTarget(spec, configs, deps, extra_link_deps + link_deps, 788 mac_bundle_deps, extra_outputs, part_of_all) 789 790 # Update global list of target outputs, used in dependency tracking. 791 target_outputs[qualified_target] = install_path 792 793 # Update global list of link dependencies. 794 if self.type in ('static_library', 'shared_library'): 795 target_link_deps[qualified_target] = self.output_binary 796 797 # Currently any versions have the same effect, but in future the behavior 798 # could be different. 799 if self.generator_flags.get('android_ndk_version', None): 800 self.WriteAndroidNdkModuleRule(self.target, all_sources, link_deps) 801 802 self.fp.close() 803 804 805 def WriteSubMake(self, output_filename, makefile_path, targets, build_dir): 806 """Write a "sub-project" Makefile. 807 808 This is a small, wrapper Makefile that calls the top-level Makefile to build 809 the targets from a single gyp file (i.e. a sub-project). 810 811 Arguments: 812 output_filename: sub-project Makefile name to write 813 makefile_path: path to the top-level Makefile 814 targets: list of "all" targets for this sub-project 815 build_dir: build output directory, relative to the sub-project 816 """ 817 gyp.common.EnsureDirExists(output_filename) 818 self.fp = open(output_filename, 'w') 819 self.fp.write(header) 820 # For consistency with other builders, put sub-project build output in the 821 # sub-project dir (see test/subdirectory/gyptest-subdir-all.py). 822 self.WriteLn('export builddir_name ?= %s' % 823 os.path.join(os.path.dirname(output_filename), build_dir)) 824 self.WriteLn('.PHONY: all') 825 self.WriteLn('all:') 826 if makefile_path: 827 makefile_path = ' -C ' + makefile_path 828 self.WriteLn('\t$(MAKE)%s %s' % (makefile_path, ' '.join(targets))) 829 self.fp.close() 830 831 832 def WriteActions(self, actions, extra_sources, extra_outputs, 833 extra_mac_bundle_resources, part_of_all): 834 """Write Makefile code for any 'actions' from the gyp input. 835 836 extra_sources: a list that will be filled in with newly generated source 837 files, if any 838 extra_outputs: a list that will be filled in with any outputs of these 839 actions (used to make other pieces dependent on these 840 actions) 841 part_of_all: flag indicating this target is part of 'all' 842 """ 843 env = self.GetSortedXcodeEnv() 844 for action in actions: 845 name = StringToMakefileVariable('%s_%s' % (self.qualified_target, 846 action['action_name'])) 847 self.WriteLn('### Rules for action "%s":' % action['action_name']) 848 inputs = action['inputs'] 849 outputs = action['outputs'] 850 851 # Build up a list of outputs. 852 # Collect the output dirs we'll need. 853 dirs = set() 854 for out in outputs: 855 dir = os.path.split(out)[0] 856 if dir: 857 dirs.add(dir) 858 if int(action.get('process_outputs_as_sources', False)): 859 extra_sources += outputs 860 if int(action.get('process_outputs_as_mac_bundle_resources', False)): 861 extra_mac_bundle_resources += outputs 862 863 # Write the actual command. 864 action_commands = action['action'] 865 if self.flavor == 'mac': 866 action_commands = [gyp.xcode_emulation.ExpandEnvVars(command, env) 867 for command in action_commands] 868 command = gyp.common.EncodePOSIXShellList(action_commands) 869 if 'message' in action: 870 self.WriteLn('quiet_cmd_%s = ACTION %s $@' % (name, action['message'])) 871 else: 872 self.WriteLn('quiet_cmd_%s = ACTION %s $@' % (name, name)) 873 if len(dirs) > 0: 874 command = 'mkdir -p %s' % ' '.join(dirs) + '; ' + command 875 876 cd_action = 'cd %s; ' % Sourceify(self.path or '.') 877 878 # command and cd_action get written to a toplevel variable called 879 # cmd_foo. Toplevel variables can't handle things that change per 880 # makefile like $(TARGET), so hardcode the target. 881 command = command.replace('$(TARGET)', self.target) 882 cd_action = cd_action.replace('$(TARGET)', self.target) 883 884 # Set LD_LIBRARY_PATH in case the action runs an executable from this 885 # build which links to shared libs from this build. 886 # actions run on the host, so they should in theory only use host 887 # libraries, but until everything is made cross-compile safe, also use 888 # target libraries. 889 # TODO(piman): when everything is cross-compile safe, remove lib.target 890 self.WriteLn('cmd_%s = LD_LIBRARY_PATH=$(builddir)/lib.host:' 891 '$(builddir)/lib.target:$$LD_LIBRARY_PATH; ' 892 'export LD_LIBRARY_PATH; ' 893 '%s%s' 894 % (name, cd_action, command)) 895 self.WriteLn() 896 outputs = map(self.Absolutify, outputs) 897 # The makefile rules are all relative to the top dir, but the gyp actions 898 # are defined relative to their containing dir. This replaces the obj 899 # variable for the action rule with an absolute version so that the output 900 # goes in the right place. 901 # Only write the 'obj' and 'builddir' rules for the "primary" output (:1); 902 # it's superfluous for the "extra outputs", and this avoids accidentally 903 # writing duplicate dummy rules for those outputs. 904 # Same for environment. 905 self.WriteLn("%s: obj := $(abs_obj)" % QuoteSpaces(outputs[0])) 906 self.WriteLn("%s: builddir := $(abs_builddir)" % QuoteSpaces(outputs[0])) 907 self.WriteSortedXcodeEnv(outputs[0], self.GetSortedXcodeEnv()) 908 909 for input in inputs: 910 assert ' ' not in input, ( 911 "Spaces in action input filenames not supported (%s)" % input) 912 for output in outputs: 913 assert ' ' not in output, ( 914 "Spaces in action output filenames not supported (%s)" % output) 915 916 # See the comment in WriteCopies about expanding env vars. 917 outputs = [gyp.xcode_emulation.ExpandEnvVars(o, env) for o in outputs] 918 inputs = [gyp.xcode_emulation.ExpandEnvVars(i, env) for i in inputs] 919 920 self.WriteDoCmd(outputs, map(Sourceify, map(self.Absolutify, inputs)), 921 part_of_all=part_of_all, command=name) 922 923 # Stuff the outputs in a variable so we can refer to them later. 924 outputs_variable = 'action_%s_outputs' % name 925 self.WriteLn('%s := %s' % (outputs_variable, ' '.join(outputs))) 926 extra_outputs.append('$(%s)' % outputs_variable) 927 self.WriteLn() 928 929 self.WriteLn() 930 931 932 def WriteRules(self, rules, extra_sources, extra_outputs, 933 extra_mac_bundle_resources, part_of_all): 934 """Write Makefile code for any 'rules' from the gyp input. 935 936 extra_sources: a list that will be filled in with newly generated source 937 files, if any 938 extra_outputs: a list that will be filled in with any outputs of these 939 rules (used to make other pieces dependent on these rules) 940 part_of_all: flag indicating this target is part of 'all' 941 """ 942 env = self.GetSortedXcodeEnv() 943 for rule in rules: 944 name = StringToMakefileVariable('%s_%s' % (self.qualified_target, 945 rule['rule_name'])) 946 count = 0 947 self.WriteLn('### Generated for rule %s:' % name) 948 949 all_outputs = [] 950 951 for rule_source in rule.get('rule_sources', []): 952 dirs = set() 953 (rule_source_dirname, rule_source_basename) = os.path.split(rule_source) 954 (rule_source_root, rule_source_ext) = \ 955 os.path.splitext(rule_source_basename) 956 957 outputs = [self.ExpandInputRoot(out, rule_source_root, 958 rule_source_dirname) 959 for out in rule['outputs']] 960 961 for out in outputs: 962 dir = os.path.dirname(out) 963 if dir: 964 dirs.add(dir) 965 if int(rule.get('process_outputs_as_sources', False)): 966 extra_sources += outputs 967 if int(rule.get('process_outputs_as_mac_bundle_resources', False)): 968 extra_mac_bundle_resources += outputs 969 inputs = map(Sourceify, map(self.Absolutify, [rule_source] + 970 rule.get('inputs', []))) 971 actions = ['$(call do_cmd,%s_%d)' % (name, count)] 972 973 if name == 'resources_grit': 974 # HACK: This is ugly. Grit intentionally doesn't touch the 975 # timestamp of its output file when the file doesn't change, 976 # which is fine in hash-based dependency systems like scons 977 # and forge, but not kosher in the make world. After some 978 # discussion, hacking around it here seems like the least 979 # amount of pain. 980 actions += ['@touch --no-create $@'] 981 982 # See the comment in WriteCopies about expanding env vars. 983 outputs = [gyp.xcode_emulation.ExpandEnvVars(o, env) for o in outputs] 984 inputs = [gyp.xcode_emulation.ExpandEnvVars(i, env) for i in inputs] 985 986 outputs = map(self.Absolutify, outputs) 987 all_outputs += outputs 988 # Only write the 'obj' and 'builddir' rules for the "primary" output 989 # (:1); it's superfluous for the "extra outputs", and this avoids 990 # accidentally writing duplicate dummy rules for those outputs. 991 self.WriteLn('%s: obj := $(abs_obj)' % outputs[0]) 992 self.WriteLn('%s: builddir := $(abs_builddir)' % outputs[0]) 993 self.WriteMakeRule(outputs, inputs + ['FORCE_DO_CMD'], actions) 994 # Spaces in rule filenames are not supported, but rule variables have 995 # spaces in them (e.g. RULE_INPUT_PATH expands to '$(abspath $<)'). 996 # The spaces within the variables are valid, so remove the variables 997 # before checking. 998 variables_with_spaces = re.compile(r'\$\([^ ]* \$<\)') 999 for output in outputs: 1000 output = re.sub(variables_with_spaces, '', output) 1001 assert ' ' not in output, ( 1002 "Spaces in rule filenames not yet supported (%s)" % output) 1003 self.WriteLn('all_deps += %s' % ' '.join(outputs)) 1004 1005 action = [self.ExpandInputRoot(ac, rule_source_root, 1006 rule_source_dirname) 1007 for ac in rule['action']] 1008 mkdirs = '' 1009 if len(dirs) > 0: 1010 mkdirs = 'mkdir -p %s; ' % ' '.join(dirs) 1011 cd_action = 'cd %s; ' % Sourceify(self.path or '.') 1012 1013 # action, cd_action, and mkdirs get written to a toplevel variable 1014 # called cmd_foo. Toplevel variables can't handle things that change 1015 # per makefile like $(TARGET), so hardcode the target. 1016 if self.flavor == 'mac': 1017 action = [gyp.xcode_emulation.ExpandEnvVars(command, env) 1018 for command in action] 1019 action = gyp.common.EncodePOSIXShellList(action) 1020 action = action.replace('$(TARGET)', self.target) 1021 cd_action = cd_action.replace('$(TARGET)', self.target) 1022 mkdirs = mkdirs.replace('$(TARGET)', self.target) 1023 1024 # Set LD_LIBRARY_PATH in case the rule runs an executable from this 1025 # build which links to shared libs from this build. 1026 # rules run on the host, so they should in theory only use host 1027 # libraries, but until everything is made cross-compile safe, also use 1028 # target libraries. 1029 # TODO(piman): when everything is cross-compile safe, remove lib.target 1030 self.WriteLn( 1031 "cmd_%(name)s_%(count)d = LD_LIBRARY_PATH=" 1032 "$(builddir)/lib.host:$(builddir)/lib.target:$$LD_LIBRARY_PATH; " 1033 "export LD_LIBRARY_PATH; " 1034 "%(cd_action)s%(mkdirs)s%(action)s" % { 1035 'action': action, 1036 'cd_action': cd_action, 1037 'count': count, 1038 'mkdirs': mkdirs, 1039 'name': name, 1040 }) 1041 self.WriteLn( 1042 'quiet_cmd_%(name)s_%(count)d = RULE %(name)s_%(count)d $@' % { 1043 'count': count, 1044 'name': name, 1045 }) 1046 self.WriteLn() 1047 count += 1 1048 1049 outputs_variable = 'rule_%s_outputs' % name 1050 self.WriteList(all_outputs, outputs_variable) 1051 extra_outputs.append('$(%s)' % outputs_variable) 1052 1053 self.WriteLn('### Finished generating for rule: %s' % name) 1054 self.WriteLn() 1055 self.WriteLn('### Finished generating for all rules') 1056 self.WriteLn('') 1057 1058 1059 def WriteCopies(self, copies, extra_outputs, part_of_all): 1060 """Write Makefile code for any 'copies' from the gyp input. 1061 1062 extra_outputs: a list that will be filled in with any outputs of this action 1063 (used to make other pieces dependent on this action) 1064 part_of_all: flag indicating this target is part of 'all' 1065 """ 1066 self.WriteLn('### Generated for copy rule.') 1067 1068 variable = StringToMakefileVariable(self.qualified_target + '_copies') 1069 outputs = [] 1070 for copy in copies: 1071 for path in copy['files']: 1072 # Absolutify() may call normpath, and will strip trailing slashes. 1073 path = Sourceify(self.Absolutify(path)) 1074 filename = os.path.split(path)[1] 1075 output = Sourceify(self.Absolutify(os.path.join(copy['destination'], 1076 filename))) 1077 1078 # If the output path has variables in it, which happens in practice for 1079 # 'copies', writing the environment as target-local doesn't work, 1080 # because the variables are already needed for the target name. 1081 # Copying the environment variables into global make variables doesn't 1082 # work either, because then the .d files will potentially contain spaces 1083 # after variable expansion, and .d file handling cannot handle spaces. 1084 # As a workaround, manually expand variables at gyp time. Since 'copies' 1085 # can't run scripts, there's no need to write the env then. 1086 # WriteDoCmd() will escape spaces for .d files. 1087 env = self.GetSortedXcodeEnv() 1088 output = gyp.xcode_emulation.ExpandEnvVars(output, env) 1089 path = gyp.xcode_emulation.ExpandEnvVars(path, env) 1090 self.WriteDoCmd([output], [path], 'copy', part_of_all) 1091 outputs.append(output) 1092 self.WriteLn('%s = %s' % (variable, ' '.join(map(QuoteSpaces, outputs)))) 1093 extra_outputs.append('$(%s)' % variable) 1094 self.WriteLn() 1095 1096 1097 def WriteMacBundleResources(self, resources, bundle_deps): 1098 """Writes Makefile code for 'mac_bundle_resources'.""" 1099 self.WriteLn('### Generated for mac_bundle_resources') 1100 1101 for output, res in gyp.xcode_emulation.GetMacBundleResources( 1102 generator_default_variables['PRODUCT_DIR'], self.xcode_settings, 1103 map(Sourceify, map(self.Absolutify, resources))): 1104 self.WriteDoCmd([output], [res], 'mac_tool,,,copy-bundle-resource', 1105 part_of_all=True) 1106 bundle_deps.append(output) 1107 1108 1109 def WriteMacInfoPlist(self, bundle_deps): 1110 """Write Makefile code for bundle Info.plist files.""" 1111 info_plist, out, defines, extra_env = gyp.xcode_emulation.GetMacInfoPlist( 1112 generator_default_variables['PRODUCT_DIR'], self.xcode_settings, 1113 lambda p: Sourceify(self.Absolutify(p))) 1114 if not info_plist: 1115 return 1116 if defines: 1117 # Create an intermediate file to store preprocessed results. 1118 intermediate_plist = ('$(obj).$(TOOLSET)/$(TARGET)/' + 1119 os.path.basename(info_plist)) 1120 self.WriteList(defines, intermediate_plist + ': INFOPLIST_DEFINES', '-D', 1121 quoter=EscapeCppDefine) 1122 self.WriteMakeRule([intermediate_plist], [info_plist], 1123 ['$(call do_cmd,infoplist)', 1124 # "Convert" the plist so that any weird whitespace changes from the 1125 # preprocessor do not affect the XML parser in mac_tool. 1126 '@plutil -convert xml1 $@ $@']) 1127 info_plist = intermediate_plist 1128 # plists can contain envvars and substitute them into the file. 1129 self.WriteSortedXcodeEnv( 1130 out, self.GetSortedXcodeEnv(additional_settings=extra_env)) 1131 self.WriteDoCmd([out], [info_plist], 'mac_tool,,,copy-info-plist', 1132 part_of_all=True) 1133 bundle_deps.append(out) 1134 1135 1136 def WriteSources(self, configs, deps, sources, 1137 extra_outputs, extra_link_deps, 1138 part_of_all, precompiled_header): 1139 """Write Makefile code for any 'sources' from the gyp input. 1140 These are source files necessary to build the current target. 1141 1142 configs, deps, sources: input from gyp. 1143 extra_outputs: a list of extra outputs this action should be dependent on; 1144 used to serialize action/rules before compilation 1145 extra_link_deps: a list that will be filled in with any outputs of 1146 compilation (to be used in link lines) 1147 part_of_all: flag indicating this target is part of 'all' 1148 """ 1149 1150 # Write configuration-specific variables for CFLAGS, etc. 1151 for configname in sorted(configs.keys()): 1152 config = configs[configname] 1153 self.WriteList(config.get('defines'), 'DEFS_%s' % configname, prefix='-D', 1154 quoter=EscapeCppDefine) 1155 1156 if self.flavor == 'mac': 1157 cflags = self.xcode_settings.GetCflags(configname) 1158 cflags_c = self.xcode_settings.GetCflagsC(configname) 1159 cflags_cc = self.xcode_settings.GetCflagsCC(configname) 1160 cflags_objc = self.xcode_settings.GetCflagsObjC(configname) 1161 cflags_objcc = self.xcode_settings.GetCflagsObjCC(configname) 1162 else: 1163 cflags = config.get('cflags') 1164 cflags_c = config.get('cflags_c') 1165 cflags_cc = config.get('cflags_cc') 1166 1167 self.WriteLn("# Flags passed to all source files."); 1168 self.WriteList(cflags, 'CFLAGS_%s' % configname) 1169 self.WriteLn("# Flags passed to only C files."); 1170 self.WriteList(cflags_c, 'CFLAGS_C_%s' % configname) 1171 self.WriteLn("# Flags passed to only C++ files."); 1172 self.WriteList(cflags_cc, 'CFLAGS_CC_%s' % configname) 1173 if self.flavor == 'mac': 1174 self.WriteLn("# Flags passed to only ObjC files."); 1175 self.WriteList(cflags_objc, 'CFLAGS_OBJC_%s' % configname) 1176 self.WriteLn("# Flags passed to only ObjC++ files."); 1177 self.WriteList(cflags_objcc, 'CFLAGS_OBJCC_%s' % configname) 1178 includes = config.get('include_dirs') 1179 if includes: 1180 includes = map(Sourceify, map(self.Absolutify, includes)) 1181 self.WriteList(includes, 'INCS_%s' % configname, prefix='-I') 1182 1183 compilable = filter(Compilable, sources) 1184 objs = map(self.Objectify, map(self.Absolutify, map(Target, compilable))) 1185 self.WriteList(objs, 'OBJS') 1186 1187 for obj in objs: 1188 assert ' ' not in obj, ( 1189 "Spaces in object filenames not supported (%s)" % obj) 1190 self.WriteLn('# Add to the list of files we specially track ' 1191 'dependencies for.') 1192 self.WriteLn('all_deps += $(OBJS)') 1193 self.WriteLn() 1194 1195 # Make sure our dependencies are built first. 1196 if deps: 1197 self.WriteMakeRule(['$(OBJS)'], deps, 1198 comment = 'Make sure our dependencies are built ' 1199 'before any of us.', 1200 order_only = True) 1201 1202 # Make sure the actions and rules run first. 1203 # If they generate any extra headers etc., the per-.o file dep tracking 1204 # will catch the proper rebuilds, so order only is still ok here. 1205 if extra_outputs: 1206 self.WriteMakeRule(['$(OBJS)'], extra_outputs, 1207 comment = 'Make sure our actions/rules run ' 1208 'before any of us.', 1209 order_only = True) 1210 1211 pchdeps = precompiled_header.GetObjDependencies(compilable, objs ) 1212 if pchdeps: 1213 self.WriteLn('# Dependencies from obj files to their precompiled headers') 1214 for source, obj, gch in pchdeps: 1215 self.WriteLn('%s: %s' % (obj, gch)) 1216 self.WriteLn('# End precompiled header dependencies') 1217 1218 if objs: 1219 extra_link_deps.append('$(OBJS)') 1220 self.WriteLn("""\ 1221# CFLAGS et al overrides must be target-local. 1222# See "Target-specific Variable Values" in the GNU Make manual.""") 1223 self.WriteLn("$(OBJS): TOOLSET := $(TOOLSET)") 1224 self.WriteLn("$(OBJS): GYP_CFLAGS := " 1225 "$(DEFS_$(BUILDTYPE)) " 1226 "$(INCS_$(BUILDTYPE)) " 1227 "%s " % precompiled_header.GetInclude('c') + 1228 "$(CFLAGS_$(BUILDTYPE)) " 1229 "$(CFLAGS_C_$(BUILDTYPE))") 1230 self.WriteLn("$(OBJS): GYP_CXXFLAGS := " 1231 "$(DEFS_$(BUILDTYPE)) " 1232 "$(INCS_$(BUILDTYPE)) " 1233 "%s " % precompiled_header.GetInclude('cc') + 1234 "$(CFLAGS_$(BUILDTYPE)) " 1235 "$(CFLAGS_CC_$(BUILDTYPE))") 1236 if self.flavor == 'mac': 1237 self.WriteLn("$(OBJS): GYP_OBJCFLAGS := " 1238 "$(DEFS_$(BUILDTYPE)) " 1239 "$(INCS_$(BUILDTYPE)) " 1240 "%s " % precompiled_header.GetInclude('m') + 1241 "$(CFLAGS_$(BUILDTYPE)) " 1242 "$(CFLAGS_C_$(BUILDTYPE)) " 1243 "$(CFLAGS_OBJC_$(BUILDTYPE))") 1244 self.WriteLn("$(OBJS): GYP_OBJCXXFLAGS := " 1245 "$(DEFS_$(BUILDTYPE)) " 1246 "$(INCS_$(BUILDTYPE)) " 1247 "%s " % precompiled_header.GetInclude('mm') + 1248 "$(CFLAGS_$(BUILDTYPE)) " 1249 "$(CFLAGS_CC_$(BUILDTYPE)) " 1250 "$(CFLAGS_OBJCC_$(BUILDTYPE))") 1251 1252 self.WritePchTargets(precompiled_header.GetPchBuildCommands()) 1253 1254 # If there are any object files in our input file list, link them into our 1255 # output. 1256 extra_link_deps += filter(Linkable, sources) 1257 1258 self.WriteLn() 1259 1260 def WritePchTargets(self, pch_commands): 1261 """Writes make rules to compile prefix headers.""" 1262 if not pch_commands: 1263 return 1264 1265 for gch, lang_flag, lang, input in pch_commands: 1266 extra_flags = { 1267 'c': '$(CFLAGS_C_$(BUILDTYPE))', 1268 'cc': '$(CFLAGS_CC_$(BUILDTYPE))', 1269 'm': '$(CFLAGS_C_$(BUILDTYPE)) $(CFLAGS_OBJC_$(BUILDTYPE))', 1270 'mm': '$(CFLAGS_CC_$(BUILDTYPE)) $(CFLAGS_OBJCC_$(BUILDTYPE))', 1271 }[lang] 1272 var_name = { 1273 'c': 'GYP_PCH_CFLAGS', 1274 'cc': 'GYP_PCH_CXXFLAGS', 1275 'm': 'GYP_PCH_OBJCFLAGS', 1276 'mm': 'GYP_PCH_OBJCXXFLAGS', 1277 }[lang] 1278 self.WriteLn("%s: %s := %s " % (gch, var_name, lang_flag) + 1279 "$(DEFS_$(BUILDTYPE)) " 1280 "$(INCS_$(BUILDTYPE)) " 1281 "$(CFLAGS_$(BUILDTYPE)) " + 1282 extra_flags) 1283 1284 self.WriteLn('%s: %s FORCE_DO_CMD' % (gch, input)) 1285 self.WriteLn('\t@$(call do_cmd,pch_%s,1)' % lang) 1286 self.WriteLn('') 1287 assert ' ' not in gch, ( 1288 "Spaces in gch filenames not supported (%s)" % gch) 1289 self.WriteLn('all_deps += %s' % gch) 1290 self.WriteLn('') 1291 1292 1293 def ComputeOutputBasename(self, spec): 1294 """Return the 'output basename' of a gyp spec. 1295 1296 E.g., the loadable module 'foobar' in directory 'baz' will produce 1297 'libfoobar.so' 1298 """ 1299 assert not self.is_mac_bundle 1300 1301 if self.flavor == 'mac' and self.type in ( 1302 'static_library', 'executable', 'shared_library', 'loadable_module'): 1303 return self.xcode_settings.GetExecutablePath() 1304 1305 target = spec['target_name'] 1306 target_prefix = '' 1307 target_ext = '' 1308 if self.type == 'static_library': 1309 if target[:3] == 'lib': 1310 target = target[3:] 1311 target_prefix = 'lib' 1312 target_ext = '.a' 1313 elif self.type in ('loadable_module', 'shared_library'): 1314 if target[:3] == 'lib': 1315 target = target[3:] 1316 target_prefix = 'lib' 1317 target_ext = '.so' 1318 elif self.type == 'none': 1319 target = '%s.stamp' % target 1320 elif self.type != 'executable': 1321 print ("ERROR: What output file should be generated?", 1322 "type", self.type, "target", target) 1323 1324 target_prefix = spec.get('product_prefix', target_prefix) 1325 target = spec.get('product_name', target) 1326 product_ext = spec.get('product_extension') 1327 if product_ext: 1328 target_ext = '.' + product_ext 1329 1330 return target_prefix + target + target_ext 1331 1332 1333 def _InstallImmediately(self): 1334 return self.toolset == 'target' and self.flavor == 'mac' and self.type in ( 1335 'static_library', 'executable', 'shared_library', 'loadable_module') 1336 1337 1338 def ComputeOutput(self, spec): 1339 """Return the 'output' (full output path) of a gyp spec. 1340 1341 E.g., the loadable module 'foobar' in directory 'baz' will produce 1342 '$(obj)/baz/libfoobar.so' 1343 """ 1344 assert not self.is_mac_bundle 1345 1346 path = os.path.join('$(obj).' + self.toolset, self.path) 1347 if self.type == 'executable' or self._InstallImmediately(): 1348 path = '$(builddir)' 1349 path = spec.get('product_dir', path) 1350 return os.path.join(path, self.ComputeOutputBasename(spec)) 1351 1352 1353 def ComputeMacBundleOutput(self, spec): 1354 """Return the 'output' (full output path) to a bundle output directory.""" 1355 assert self.is_mac_bundle 1356 path = generator_default_variables['PRODUCT_DIR'] 1357 return os.path.join(path, self.xcode_settings.GetWrapperName()) 1358 1359 1360 def ComputeMacBundleBinaryOutput(self, spec): 1361 """Return the 'output' (full output path) to the binary in a bundle.""" 1362 path = generator_default_variables['PRODUCT_DIR'] 1363 return os.path.join(path, self.xcode_settings.GetExecutablePath()) 1364 1365 1366 def ComputeDeps(self, spec): 1367 """Compute the dependencies of a gyp spec. 1368 1369 Returns a tuple (deps, link_deps), where each is a list of 1370 filenames that will need to be put in front of make for either 1371 building (deps) or linking (link_deps). 1372 """ 1373 deps = [] 1374 link_deps = [] 1375 if 'dependencies' in spec: 1376 deps.extend([target_outputs[dep] for dep in spec['dependencies'] 1377 if target_outputs[dep]]) 1378 for dep in spec['dependencies']: 1379 if dep in target_link_deps: 1380 link_deps.append(target_link_deps[dep]) 1381 deps.extend(link_deps) 1382 # TODO: It seems we need to transitively link in libraries (e.g. -lfoo)? 1383 # This hack makes it work: 1384 # link_deps.extend(spec.get('libraries', [])) 1385 return (gyp.common.uniquer(deps), gyp.common.uniquer(link_deps)) 1386 1387 1388 def WriteDependencyOnExtraOutputs(self, target, extra_outputs): 1389 self.WriteMakeRule([self.output_binary], extra_outputs, 1390 comment = 'Build our special outputs first.', 1391 order_only = True) 1392 1393 1394 def WriteTarget(self, spec, configs, deps, link_deps, bundle_deps, 1395 extra_outputs, part_of_all): 1396 """Write Makefile code to produce the final target of the gyp spec. 1397 1398 spec, configs: input from gyp. 1399 deps, link_deps: dependency lists; see ComputeDeps() 1400 extra_outputs: any extra outputs that our target should depend on 1401 part_of_all: flag indicating this target is part of 'all' 1402 """ 1403 1404 self.WriteLn('### Rules for final target.') 1405 1406 if extra_outputs: 1407 self.WriteDependencyOnExtraOutputs(self.output_binary, extra_outputs) 1408 self.WriteMakeRule(extra_outputs, deps, 1409 comment=('Preserve order dependency of ' 1410 'special output on deps.'), 1411 order_only = True) 1412 1413 target_postbuilds = {} 1414 if self.type != 'none': 1415 for configname in sorted(configs.keys()): 1416 config = configs[configname] 1417 if self.flavor == 'mac': 1418 ldflags = self.xcode_settings.GetLdflags(configname, 1419 generator_default_variables['PRODUCT_DIR'], 1420 lambda p: Sourceify(self.Absolutify(p))) 1421 1422 # TARGET_POSTBUILDS_$(BUILDTYPE) is added to postbuilds later on. 1423 gyp_to_build = gyp.common.InvertRelativePath(self.path) 1424 target_postbuild = self.xcode_settings.AddImplicitPostbuilds( 1425 configname, 1426 QuoteSpaces(os.path.normpath(os.path.join(gyp_to_build, 1427 self.output))), 1428 QuoteSpaces(os.path.normpath(os.path.join(gyp_to_build, 1429 self.output_binary)))) 1430 if target_postbuild: 1431 target_postbuilds[configname] = target_postbuild 1432 else: 1433 ldflags = config.get('ldflags', []) 1434 # Compute an rpath for this output if needed. 1435 if any(dep.endswith('.so') or '.so.' in dep for dep in deps): 1436 # We want to get the literal string "$ORIGIN" into the link command, 1437 # so we need lots of escaping. 1438 ldflags.append(r'-Wl,-rpath=\$$ORIGIN/lib.%s/' % self.toolset) 1439 ldflags.append(r'-Wl,-rpath-link=\$(builddir)/lib.%s/' % 1440 self.toolset) 1441 library_dirs = config.get('library_dirs', []) 1442 ldflags += [('-L%s' % library_dir) for library_dir in library_dirs] 1443 self.WriteList(ldflags, 'LDFLAGS_%s' % configname) 1444 if self.flavor == 'mac': 1445 self.WriteList(self.xcode_settings.GetLibtoolflags(configname), 1446 'LIBTOOLFLAGS_%s' % configname) 1447 libraries = spec.get('libraries') 1448 if libraries: 1449 # Remove duplicate entries 1450 libraries = gyp.common.uniquer(libraries) 1451 if self.flavor == 'mac': 1452 libraries = self.xcode_settings.AdjustLibraries(libraries) 1453 self.WriteList(libraries, 'LIBS') 1454 self.WriteLn('%s: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE))' % 1455 QuoteSpaces(self.output_binary)) 1456 self.WriteLn('%s: LIBS := $(LIBS)' % QuoteSpaces(self.output_binary)) 1457 1458 if self.flavor == 'mac': 1459 self.WriteLn('%s: GYP_LIBTOOLFLAGS := $(LIBTOOLFLAGS_$(BUILDTYPE))' % 1460 QuoteSpaces(self.output_binary)) 1461 1462 # Postbuild actions. Like actions, but implicitly depend on the target's 1463 # output. 1464 postbuilds = [] 1465 if self.flavor == 'mac': 1466 if target_postbuilds: 1467 postbuilds.append('$(TARGET_POSTBUILDS_$(BUILDTYPE))') 1468 postbuilds.extend( 1469 gyp.xcode_emulation.GetSpecPostbuildCommands(spec)) 1470 1471 if postbuilds: 1472 # Envvars may be referenced by TARGET_POSTBUILDS_$(BUILDTYPE), 1473 # so we must output its definition first, since we declare variables 1474 # using ":=". 1475 self.WriteSortedXcodeEnv(self.output, self.GetSortedXcodePostbuildEnv()) 1476 1477 for configname in target_postbuilds: 1478 self.WriteLn('%s: TARGET_POSTBUILDS_%s := %s' % 1479 (QuoteSpaces(self.output), 1480 configname, 1481 gyp.common.EncodePOSIXShellList(target_postbuilds[configname]))) 1482 1483 # Postbuilds expect to be run in the gyp file's directory, so insert an 1484 # implicit postbuild to cd to there. 1485 postbuilds.insert(0, gyp.common.EncodePOSIXShellList(['cd', self.path])) 1486 for i in xrange(len(postbuilds)): 1487 if not postbuilds[i].startswith('$'): 1488 postbuilds[i] = EscapeShellArgument(postbuilds[i]) 1489 self.WriteLn('%s: builddir := $(abs_builddir)' % QuoteSpaces(self.output)) 1490 self.WriteLn('%s: POSTBUILDS := %s' % ( 1491 QuoteSpaces(self.output), ' '.join(postbuilds))) 1492 1493 # A bundle directory depends on its dependencies such as bundle resources 1494 # and bundle binary. When all dependencies have been built, the bundle 1495 # needs to be packaged. 1496 if self.is_mac_bundle: 1497 # If the framework doesn't contain a binary, then nothing depends 1498 # on the actions -- make the framework depend on them directly too. 1499 self.WriteDependencyOnExtraOutputs(self.output, extra_outputs) 1500 1501 # Bundle dependencies. Note that the code below adds actions to this 1502 # target, so if you move these two lines, move the lines below as well. 1503 self.WriteList(map(QuoteSpaces, bundle_deps), 'BUNDLE_DEPS') 1504 self.WriteLn('%s: $(BUNDLE_DEPS)' % QuoteSpaces(self.output)) 1505 1506 # After the framework is built, package it. Needs to happen before 1507 # postbuilds, since postbuilds depend on this. 1508 if self.type in ('shared_library', 'loadable_module'): 1509 self.WriteLn('\t@$(call do_cmd,mac_package_framework,,,%s)' % 1510 self.xcode_settings.GetFrameworkVersion()) 1511 1512 # Bundle postbuilds can depend on the whole bundle, so run them after 1513 # the bundle is packaged, not already after the bundle binary is done. 1514 if postbuilds: 1515 self.WriteLn('\t@$(call do_postbuilds)') 1516 postbuilds = [] # Don't write postbuilds for target's output. 1517 1518 # Needed by test/mac/gyptest-rebuild.py. 1519 self.WriteLn('\t@true # No-op, used by tests') 1520 1521 # Since this target depends on binary and resources which are in 1522 # nested subfolders, the framework directory will be older than 1523 # its dependencies usually. To prevent this rule from executing 1524 # on every build (expensive, especially with postbuilds), expliclity 1525 # update the time on the framework directory. 1526 self.WriteLn('\t@touch -c %s' % QuoteSpaces(self.output)) 1527 1528 if postbuilds: 1529 assert not self.is_mac_bundle, ('Postbuilds for bundles should be done ' 1530 'on the bundle, not the binary (target \'%s\')' % self.target) 1531 assert 'product_dir' not in spec, ('Postbuilds do not work with ' 1532 'custom product_dir') 1533 1534 if self.type == 'executable': 1535 self.WriteLn('%s: LD_INPUTS := %s' % ( 1536 QuoteSpaces(self.output_binary), 1537 ' '.join(map(QuoteSpaces, link_deps)))) 1538 if self.toolset == 'host' and self.flavor == 'android': 1539 self.WriteDoCmd([self.output_binary], link_deps, 'link_host', 1540 part_of_all, postbuilds=postbuilds) 1541 else: 1542 self.WriteDoCmd([self.output_binary], link_deps, 'link', part_of_all, 1543 postbuilds=postbuilds) 1544 1545 elif self.type == 'static_library': 1546 for link_dep in link_deps: 1547 assert ' ' not in link_dep, ( 1548 "Spaces in alink input filenames not supported (%s)" % link_dep) 1549 if (self.flavor not in ('mac', 'openbsd', 'win') and not 1550 self.is_standalone_static_library): 1551 self.WriteDoCmd([self.output_binary], link_deps, 'alink_thin', 1552 part_of_all, postbuilds=postbuilds) 1553 else: 1554 self.WriteDoCmd([self.output_binary], link_deps, 'alink', part_of_all, 1555 postbuilds=postbuilds) 1556 elif self.type == 'shared_library': 1557 self.WriteLn('%s: LD_INPUTS := %s' % ( 1558 QuoteSpaces(self.output_binary), 1559 ' '.join(map(QuoteSpaces, link_deps)))) 1560 self.WriteDoCmd([self.output_binary], link_deps, 'solink', part_of_all, 1561 postbuilds=postbuilds) 1562 elif self.type == 'loadable_module': 1563 for link_dep in link_deps: 1564 assert ' ' not in link_dep, ( 1565 "Spaces in module input filenames not supported (%s)" % link_dep) 1566 if self.toolset == 'host' and self.flavor == 'android': 1567 self.WriteDoCmd([self.output_binary], link_deps, 'solink_module_host', 1568 part_of_all, postbuilds=postbuilds) 1569 else: 1570 self.WriteDoCmd( 1571 [self.output_binary], link_deps, 'solink_module', part_of_all, 1572 postbuilds=postbuilds) 1573 elif self.type == 'none': 1574 # Write a stamp line. 1575 self.WriteDoCmd([self.output_binary], deps, 'touch', part_of_all, 1576 postbuilds=postbuilds) 1577 else: 1578 print "WARNING: no output for", self.type, target 1579 1580 # Add an alias for each target (if there are any outputs). 1581 # Installable target aliases are created below. 1582 if ((self.output and self.output != self.target) and 1583 (self.type not in self._INSTALLABLE_TARGETS)): 1584 self.WriteMakeRule([self.target], [self.output], 1585 comment='Add target alias', phony = True) 1586 if part_of_all: 1587 self.WriteMakeRule(['all'], [self.target], 1588 comment = 'Add target alias to "all" target.', 1589 phony = True) 1590 1591 # Add special-case rules for our installable targets. 1592 # 1) They need to install to the build dir or "product" dir. 1593 # 2) They get shortcuts for building (e.g. "make chrome"). 1594 # 3) They are part of "make all". 1595 if (self.type in self._INSTALLABLE_TARGETS or 1596 self.is_standalone_static_library): 1597 if self.type == 'shared_library': 1598 file_desc = 'shared library' 1599 elif self.type == 'static_library': 1600 file_desc = 'static library' 1601 else: 1602 file_desc = 'executable' 1603 install_path = self._InstallableTargetInstallPath() 1604 installable_deps = [self.output] 1605 if (self.flavor == 'mac' and not 'product_dir' in spec and 1606 self.toolset == 'target'): 1607 # On mac, products are created in install_path immediately. 1608 assert install_path == self.output, '%s != %s' % ( 1609 install_path, self.output) 1610 1611 # Point the target alias to the final binary output. 1612 self.WriteMakeRule([self.target], [install_path], 1613 comment='Add target alias', phony = True) 1614 if install_path != self.output: 1615 assert not self.is_mac_bundle # See comment a few lines above. 1616 self.WriteDoCmd([install_path], [self.output], 'copy', 1617 comment = 'Copy this to the %s output path.' % 1618 file_desc, part_of_all=part_of_all) 1619 installable_deps.append(install_path) 1620 if self.output != self.alias and self.alias != self.target: 1621 self.WriteMakeRule([self.alias], installable_deps, 1622 comment = 'Short alias for building this %s.' % 1623 file_desc, phony = True) 1624 if part_of_all: 1625 self.WriteMakeRule(['all'], [install_path], 1626 comment = 'Add %s to "all" target.' % file_desc, 1627 phony = True) 1628 1629 1630 def WriteList(self, value_list, variable=None, prefix='', 1631 quoter=QuoteIfNecessary): 1632 """Write a variable definition that is a list of values. 1633 1634 E.g. WriteList(['a','b'], 'foo', prefix='blah') writes out 1635 foo = blaha blahb 1636 but in a pretty-printed style. 1637 """ 1638 values = '' 1639 if value_list: 1640 value_list = [quoter(prefix + l) for l in value_list] 1641 values = ' \\\n\t' + ' \\\n\t'.join(value_list) 1642 self.fp.write('%s :=%s\n\n' % (variable, values)) 1643 1644 1645 def WriteDoCmd(self, outputs, inputs, command, part_of_all, comment=None, 1646 postbuilds=False): 1647 """Write a Makefile rule that uses do_cmd. 1648 1649 This makes the outputs dependent on the command line that was run, 1650 as well as support the V= make command line flag. 1651 """ 1652 suffix = '' 1653 if postbuilds: 1654 assert ',' not in command 1655 suffix = ',,1' # Tell do_cmd to honor $POSTBUILDS 1656 self.WriteMakeRule(outputs, inputs, 1657 actions = ['$(call do_cmd,%s%s)' % (command, suffix)], 1658 comment = comment, 1659 force = True) 1660 # Add our outputs to the list of targets we read depfiles from. 1661 # all_deps is only used for deps file reading, and for deps files we replace 1662 # spaces with ? because escaping doesn't work with make's $(sort) and 1663 # other functions. 1664 outputs = [QuoteSpaces(o, SPACE_REPLACEMENT) for o in outputs] 1665 self.WriteLn('all_deps += %s' % ' '.join(outputs)) 1666 1667 1668 def WriteMakeRule(self, outputs, inputs, actions=None, comment=None, 1669 order_only=False, force=False, phony=False): 1670 """Write a Makefile rule, with some extra tricks. 1671 1672 outputs: a list of outputs for the rule (note: this is not directly 1673 supported by make; see comments below) 1674 inputs: a list of inputs for the rule 1675 actions: a list of shell commands to run for the rule 1676 comment: a comment to put in the Makefile above the rule (also useful 1677 for making this Python script's code self-documenting) 1678 order_only: if true, makes the dependency order-only 1679 force: if true, include FORCE_DO_CMD as an order-only dep 1680 phony: if true, the rule does not actually generate the named output, the 1681 output is just a name to run the rule 1682 """ 1683 outputs = map(QuoteSpaces, outputs) 1684 inputs = map(QuoteSpaces, inputs) 1685 1686 if comment: 1687 self.WriteLn('# ' + comment) 1688 if phony: 1689 self.WriteLn('.PHONY: ' + ' '.join(outputs)) 1690 # TODO(evanm): just make order_only a list of deps instead of these hacks. 1691 if order_only: 1692 order_insert = '| ' 1693 pick_output = ' '.join(outputs) 1694 else: 1695 order_insert = '' 1696 pick_output = outputs[0] 1697 if force: 1698 force_append = ' FORCE_DO_CMD' 1699 else: 1700 force_append = '' 1701 if actions: 1702 self.WriteLn("%s: TOOLSET := $(TOOLSET)" % outputs[0]) 1703 self.WriteLn('%s: %s%s%s' % (pick_output, order_insert, ' '.join(inputs), 1704 force_append)) 1705 if actions: 1706 for action in actions: 1707 self.WriteLn('\t%s' % action) 1708 if not order_only and len(outputs) > 1: 1709 # If we have more than one output, a rule like 1710 # foo bar: baz 1711 # that for *each* output we must run the action, potentially 1712 # in parallel. That is not what we're trying to write -- what 1713 # we want is that we run the action once and it generates all 1714 # the files. 1715 # http://www.gnu.org/software/hello/manual/automake/Multiple-Outputs.html 1716 # discusses this problem and has this solution: 1717 # 1) Write the naive rule that would produce parallel runs of 1718 # the action. 1719 # 2) Make the outputs seralized on each other, so we won't start 1720 # a parallel run until the first run finishes, at which point 1721 # we'll have generated all the outputs and we're done. 1722 self.WriteLn('%s: %s' % (' '.join(outputs[1:]), outputs[0])) 1723 # Add a dummy command to the "extra outputs" rule, otherwise make seems to 1724 # think these outputs haven't (couldn't have?) changed, and thus doesn't 1725 # flag them as changed (i.e. include in '$?') when evaluating dependent 1726 # rules, which in turn causes do_cmd() to skip running dependent commands. 1727 self.WriteLn('%s: ;' % (' '.join(outputs[1:]))) 1728 self.WriteLn() 1729 1730 1731 def WriteAndroidNdkModuleRule(self, module_name, all_sources, link_deps): 1732 """Write a set of LOCAL_XXX definitions for Android NDK. 1733 1734 These variable definitions will be used by Android NDK but do nothing for 1735 non-Android applications. 1736 1737 Arguments: 1738 module_name: Android NDK module name, which must be unique among all 1739 module names. 1740 all_sources: A list of source files (will be filtered by Compilable). 1741 link_deps: A list of link dependencies, which must be sorted in 1742 the order from dependencies to dependents. 1743 """ 1744 if self.type not in ('executable', 'shared_library', 'static_library'): 1745 return 1746 1747 self.WriteLn('# Variable definitions for Android applications') 1748 self.WriteLn('include $(CLEAR_VARS)') 1749 self.WriteLn('LOCAL_MODULE := ' + module_name) 1750 self.WriteLn('LOCAL_CFLAGS := $(CFLAGS_$(BUILDTYPE)) ' 1751 '$(DEFS_$(BUILDTYPE)) ' 1752 # LOCAL_CFLAGS is applied to both of C and C++. There is 1753 # no way to specify $(CFLAGS_C_$(BUILDTYPE)) only for C 1754 # sources. 1755 '$(CFLAGS_C_$(BUILDTYPE)) ' 1756 # $(INCS_$(BUILDTYPE)) includes the prefix '-I' while 1757 # LOCAL_C_INCLUDES does not expect it. So put it in 1758 # LOCAL_CFLAGS. 1759 '$(INCS_$(BUILDTYPE))') 1760 # LOCAL_CXXFLAGS is obsolete and LOCAL_CPPFLAGS is preferred. 1761 self.WriteLn('LOCAL_CPPFLAGS := $(CFLAGS_CC_$(BUILDTYPE))') 1762 self.WriteLn('LOCAL_C_INCLUDES :=') 1763 self.WriteLn('LOCAL_LDLIBS := $(LDFLAGS_$(BUILDTYPE)) $(LIBS)') 1764 1765 # Detect the C++ extension. 1766 cpp_ext = {'.cc': 0, '.cpp': 0, '.cxx': 0} 1767 default_cpp_ext = '.cpp' 1768 for filename in all_sources: 1769 ext = os.path.splitext(filename)[1] 1770 if ext in cpp_ext: 1771 cpp_ext[ext] += 1 1772 if cpp_ext[ext] > cpp_ext[default_cpp_ext]: 1773 default_cpp_ext = ext 1774 self.WriteLn('LOCAL_CPP_EXTENSION := ' + default_cpp_ext) 1775 1776 self.WriteList(map(self.Absolutify, filter(Compilable, all_sources)), 1777 'LOCAL_SRC_FILES') 1778 1779 # Filter out those which do not match prefix and suffix and produce 1780 # the resulting list without prefix and suffix. 1781 def DepsToModules(deps, prefix, suffix): 1782 modules = [] 1783 for filepath in deps: 1784 filename = os.path.basename(filepath) 1785 if filename.startswith(prefix) and filename.endswith(suffix): 1786 modules.append(filename[len(prefix):-len(suffix)]) 1787 return modules 1788 1789 # Retrieve the default value of 'SHARED_LIB_SUFFIX' 1790 params = {'flavor': 'linux'} 1791 default_variables = {} 1792 CalculateVariables(default_variables, params) 1793 1794 self.WriteList( 1795 DepsToModules(link_deps, 1796 generator_default_variables['SHARED_LIB_PREFIX'], 1797 default_variables['SHARED_LIB_SUFFIX']), 1798 'LOCAL_SHARED_LIBRARIES') 1799 self.WriteList( 1800 DepsToModules(link_deps, 1801 generator_default_variables['STATIC_LIB_PREFIX'], 1802 generator_default_variables['STATIC_LIB_SUFFIX']), 1803 'LOCAL_STATIC_LIBRARIES') 1804 1805 if self.type == 'executable': 1806 self.WriteLn('include $(BUILD_EXECUTABLE)') 1807 elif self.type == 'shared_library': 1808 self.WriteLn('include $(BUILD_SHARED_LIBRARY)') 1809 elif self.type == 'static_library': 1810 self.WriteLn('include $(BUILD_STATIC_LIBRARY)') 1811 self.WriteLn() 1812 1813 1814 def WriteLn(self, text=''): 1815 self.fp.write(text + '\n') 1816 1817 1818 def GetSortedXcodeEnv(self, additional_settings=None): 1819 return gyp.xcode_emulation.GetSortedXcodeEnv( 1820 self.xcode_settings, "$(abs_builddir)", 1821 os.path.join("$(abs_srcdir)", self.path), "$(BUILDTYPE)", 1822 additional_settings) 1823 1824 1825 def GetSortedXcodePostbuildEnv(self): 1826 # CHROMIUM_STRIP_SAVE_FILE is a chromium-specific hack. 1827 # TODO(thakis): It would be nice to have some general mechanism instead. 1828 strip_save_file = self.xcode_settings.GetPerTargetSetting( 1829 'CHROMIUM_STRIP_SAVE_FILE', '') 1830 # Even if strip_save_file is empty, explicitly write it. Else a postbuild 1831 # might pick up an export from an earlier target. 1832 return self.GetSortedXcodeEnv( 1833 additional_settings={'CHROMIUM_STRIP_SAVE_FILE': strip_save_file}) 1834 1835 1836 def WriteSortedXcodeEnv(self, target, env): 1837 for k, v in env: 1838 # For 1839 # foo := a\ b 1840 # the escaped space does the right thing. For 1841 # export foo := a\ b 1842 # it does not -- the backslash is written to the env as literal character. 1843 # So don't escape spaces in |env[k]|. 1844 self.WriteLn('%s: export %s := %s' % (QuoteSpaces(target), k, v)) 1845 1846 1847 def Objectify(self, path): 1848 """Convert a path to its output directory form.""" 1849 if '$(' in path: 1850 path = path.replace('$(obj)/', '$(obj).%s/$(TARGET)/' % self.toolset) 1851 if not '$(obj)' in path: 1852 path = '$(obj).%s/$(TARGET)/%s' % (self.toolset, path) 1853 return path 1854 1855 1856 def Pchify(self, path, lang): 1857 """Convert a prefix header path to its output directory form.""" 1858 path = self.Absolutify(path) 1859 if '$(' in path: 1860 path = path.replace('$(obj)/', '$(obj).%s/$(TARGET)/pch-%s' % 1861 (self.toolset, lang)) 1862 return path 1863 return '$(obj).%s/$(TARGET)/pch-%s/%s' % (self.toolset, lang, path) 1864 1865 1866 def Absolutify(self, path): 1867 """Convert a subdirectory-relative path into a base-relative path. 1868 Skips over paths that contain variables.""" 1869 if '$(' in path: 1870 # Don't call normpath in this case, as it might collapse the 1871 # path too aggressively if it features '..'. However it's still 1872 # important to strip trailing slashes. 1873 return path.rstrip('/') 1874 return os.path.normpath(os.path.join(self.path, path)) 1875 1876 1877 def ExpandInputRoot(self, template, expansion, dirname): 1878 if '%(INPUT_ROOT)s' not in template and '%(INPUT_DIRNAME)s' not in template: 1879 return template 1880 path = template % { 1881 'INPUT_ROOT': expansion, 1882 'INPUT_DIRNAME': dirname, 1883 } 1884 return path 1885 1886 1887 def _InstallableTargetInstallPath(self): 1888 """Returns the location of the final output for an installable target.""" 1889 # Xcode puts shared_library results into PRODUCT_DIR, and some gyp files 1890 # rely on this. Emulate this behavior for mac. 1891 if (self.type == 'shared_library' and 1892 (self.flavor != 'mac' or self.toolset != 'target')): 1893 # Install all shared libs into a common directory (per toolset) for 1894 # convenient access with LD_LIBRARY_PATH. 1895 return '$(builddir)/lib.%s/%s' % (self.toolset, self.alias) 1896 return '$(builddir)/' + self.alias 1897 1898 1899def WriteAutoRegenerationRule(params, root_makefile, makefile_name, 1900 build_files): 1901 """Write the target to regenerate the Makefile.""" 1902 options = params['options'] 1903 build_files_args = [gyp.common.RelativePath(filename, options.toplevel_dir) 1904 for filename in params['build_files_arg']] 1905 1906 gyp_binary = gyp.common.FixIfRelativePath(params['gyp_binary'], 1907 options.toplevel_dir) 1908 if not gyp_binary.startswith(os.sep): 1909 gyp_binary = os.path.join('.', gyp_binary) 1910 1911 root_makefile.write( 1912 "quiet_cmd_regen_makefile = ACTION Regenerating $@\n" 1913 "cmd_regen_makefile = cd $(srcdir); %(cmd)s\n" 1914 "%(makefile_name)s: %(deps)s\n" 1915 "\t$(call do_cmd,regen_makefile)\n\n" % { 1916 'makefile_name': makefile_name, 1917 'deps': ' '.join(map(Sourceify, build_files)), 1918 'cmd': gyp.common.EncodePOSIXShellList( 1919 [gyp_binary, '-fmake'] + 1920 gyp.RegenerateFlags(options) + 1921 build_files_args)}) 1922 1923 1924def PerformBuild(data, configurations, params): 1925 options = params['options'] 1926 for config in configurations: 1927 arguments = ['make'] 1928 if options.toplevel_dir and options.toplevel_dir != '.': 1929 arguments += '-C', options.toplevel_dir 1930 arguments.append('BUILDTYPE=' + config) 1931 print 'Building [%s]: %s' % (config, arguments) 1932 subprocess.check_call(arguments) 1933 1934 1935def GenerateOutput(target_list, target_dicts, data, params): 1936 options = params['options'] 1937 flavor = gyp.common.GetFlavor(params) 1938 generator_flags = params.get('generator_flags', {}) 1939 builddir_name = generator_flags.get('output_dir', 'out') 1940 android_ndk_version = generator_flags.get('android_ndk_version', None) 1941 default_target = generator_flags.get('default_target', 'all') 1942 1943 def CalculateMakefilePath(build_file, base_name): 1944 """Determine where to write a Makefile for a given gyp file.""" 1945 # Paths in gyp files are relative to the .gyp file, but we want 1946 # paths relative to the source root for the master makefile. Grab 1947 # the path of the .gyp file as the base to relativize against. 1948 # E.g. "foo/bar" when we're constructing targets for "foo/bar/baz.gyp". 1949 base_path = gyp.common.RelativePath(os.path.dirname(build_file), 1950 options.depth) 1951 # We write the file in the base_path directory. 1952 output_file = os.path.join(options.depth, base_path, base_name) 1953 if options.generator_output: 1954 output_file = os.path.join( 1955 options.depth, options.generator_output, base_path, base_name) 1956 base_path = gyp.common.RelativePath(os.path.dirname(build_file), 1957 options.toplevel_dir) 1958 return base_path, output_file 1959 1960 # TODO: search for the first non-'Default' target. This can go 1961 # away when we add verification that all targets have the 1962 # necessary configurations. 1963 default_configuration = None 1964 toolsets = set([target_dicts[target]['toolset'] for target in target_list]) 1965 for target in target_list: 1966 spec = target_dicts[target] 1967 if spec['default_configuration'] != 'Default': 1968 default_configuration = spec['default_configuration'] 1969 break 1970 if not default_configuration: 1971 default_configuration = 'Default' 1972 1973 srcdir = '.' 1974 makefile_name = 'Makefile' + options.suffix 1975 makefile_path = os.path.join(options.toplevel_dir, makefile_name) 1976 if options.generator_output: 1977 global srcdir_prefix 1978 makefile_path = os.path.join( 1979 options.toplevel_dir, options.generator_output, makefile_name) 1980 srcdir = gyp.common.RelativePath(srcdir, options.generator_output) 1981 srcdir_prefix = '$(srcdir)/' 1982 1983 flock_command= 'flock' 1984 header_params = { 1985 'default_target': default_target, 1986 'builddir': builddir_name, 1987 'default_configuration': default_configuration, 1988 'flock': flock_command, 1989 'flock_index': 1, 1990 'link_commands': LINK_COMMANDS_LINUX, 1991 'extra_commands': '', 1992 'srcdir': srcdir, 1993 } 1994 if flavor == 'mac': 1995 flock_command = './gyp-mac-tool flock' 1996 header_params.update({ 1997 'flock': flock_command, 1998 'flock_index': 2, 1999 'link_commands': LINK_COMMANDS_MAC, 2000 'extra_commands': SHARED_HEADER_MAC_COMMANDS, 2001 }) 2002 elif flavor == 'android': 2003 header_params.update({ 2004 'link_commands': LINK_COMMANDS_ANDROID, 2005 }) 2006 elif flavor == 'solaris': 2007 header_params.update({ 2008 'flock': './gyp-flock-tool flock', 2009 'flock_index': 2, 2010 }) 2011 elif flavor == 'freebsd': 2012 # Note: OpenBSD has sysutils/flock. lockf seems to be FreeBSD specific. 2013 header_params.update({ 2014 'flock': 'lockf', 2015 }) 2016 elif flavor == 'aix': 2017 header_params.update({ 2018 'link_commands': LINK_COMMANDS_AIX, 2019 'flock': './gyp-flock-tool flock', 2020 'flock_index': 2, 2021 }) 2022 2023 header_params.update({ 2024 'CC.target': GetEnvironFallback(('CC_target', 'CC'), '$(CC)'), 2025 'AR.target': GetEnvironFallback(('AR_target', 'AR'), '$(AR)'), 2026 'CXX.target': GetEnvironFallback(('CXX_target', 'CXX'), '$(CXX)'), 2027 'LINK.target': GetEnvironFallback(('LINK_target', 'LINK'), '$(LINK)'), 2028 'CC.host': GetEnvironFallback(('CC_host',), 'gcc'), 2029 'AR.host': GetEnvironFallback(('AR_host',), 'ar'), 2030 'CXX.host': GetEnvironFallback(('CXX_host',), 'g++'), 2031 'LINK.host': GetEnvironFallback(('LINK_host',), '$(CXX.host)'), 2032 }) 2033 2034 build_file, _, _ = gyp.common.ParseQualifiedTarget(target_list[0]) 2035 make_global_settings_array = data[build_file].get('make_global_settings', []) 2036 wrappers = {} 2037 wrappers['LINK'] = '%s $(builddir)/linker.lock' % flock_command 2038 for key, value in make_global_settings_array: 2039 if key.endswith('_wrapper'): 2040 wrappers[key[:-len('_wrapper')]] = '$(abspath %s)' % value 2041 make_global_settings = '' 2042 for key, value in make_global_settings_array: 2043 if re.match('.*_wrapper', key): 2044 continue 2045 if value[0] != '$': 2046 value = '$(abspath %s)' % value 2047 wrapper = wrappers.get(key) 2048 if wrapper: 2049 value = '%s %s' % (wrapper, value) 2050 del wrappers[key] 2051 if key in ('CC', 'CC.host', 'CXX', 'CXX.host'): 2052 make_global_settings += ( 2053 'ifneq (,$(filter $(origin %s), undefined default))\n' % key) 2054 # Let gyp-time envvars win over global settings. 2055 env_key = key.replace('.', '_') # CC.host -> CC_host 2056 if env_key in os.environ: 2057 value = os.environ[env_key] 2058 make_global_settings += ' %s = %s\n' % (key, value) 2059 make_global_settings += 'endif\n' 2060 else: 2061 make_global_settings += '%s ?= %s\n' % (key, value) 2062 # TODO(ukai): define cmd when only wrapper is specified in 2063 # make_global_settings. 2064 2065 header_params['make_global_settings'] = make_global_settings 2066 2067 gyp.common.EnsureDirExists(makefile_path) 2068 root_makefile = open(makefile_path, 'w') 2069 root_makefile.write(SHARED_HEADER % header_params) 2070 # Currently any versions have the same effect, but in future the behavior 2071 # could be different. 2072 if android_ndk_version: 2073 root_makefile.write( 2074 '# Define LOCAL_PATH for build of Android applications.\n' 2075 'LOCAL_PATH := $(call my-dir)\n' 2076 '\n') 2077 for toolset in toolsets: 2078 root_makefile.write('TOOLSET := %s\n' % toolset) 2079 WriteRootHeaderSuffixRules(root_makefile) 2080 2081 # Put build-time support tools next to the root Makefile. 2082 dest_path = os.path.dirname(makefile_path) 2083 gyp.common.CopyTool(flavor, dest_path) 2084 2085 # Find the list of targets that derive from the gyp file(s) being built. 2086 needed_targets = set() 2087 for build_file in params['build_files']: 2088 for target in gyp.common.AllTargets(target_list, target_dicts, build_file): 2089 needed_targets.add(target) 2090 2091 build_files = set() 2092 include_list = set() 2093 for qualified_target in target_list: 2094 build_file, target, toolset = gyp.common.ParseQualifiedTarget( 2095 qualified_target) 2096 2097 this_make_global_settings = data[build_file].get('make_global_settings', []) 2098 assert make_global_settings_array == this_make_global_settings, ( 2099 "make_global_settings needs to be the same for all targets. %s vs. %s" % 2100 (this_make_global_settings, make_global_settings)) 2101 2102 build_files.add(gyp.common.RelativePath(build_file, options.toplevel_dir)) 2103 included_files = data[build_file]['included_files'] 2104 for included_file in included_files: 2105 # The included_files entries are relative to the dir of the build file 2106 # that included them, so we have to undo that and then make them relative 2107 # to the root dir. 2108 relative_include_file = gyp.common.RelativePath( 2109 gyp.common.UnrelativePath(included_file, build_file), 2110 options.toplevel_dir) 2111 abs_include_file = os.path.abspath(relative_include_file) 2112 # If the include file is from the ~/.gyp dir, we should use absolute path 2113 # so that relocating the src dir doesn't break the path. 2114 if (params['home_dot_gyp'] and 2115 abs_include_file.startswith(params['home_dot_gyp'])): 2116 build_files.add(abs_include_file) 2117 else: 2118 build_files.add(relative_include_file) 2119 2120 base_path, output_file = CalculateMakefilePath(build_file, 2121 target + '.' + toolset + options.suffix + '.mk') 2122 2123 spec = target_dicts[qualified_target] 2124 configs = spec['configurations'] 2125 2126 if flavor == 'mac': 2127 gyp.xcode_emulation.MergeGlobalXcodeSettingsToSpec(data[build_file], spec) 2128 2129 writer = MakefileWriter(generator_flags, flavor) 2130 writer.Write(qualified_target, base_path, output_file, spec, configs, 2131 part_of_all=qualified_target in needed_targets) 2132 2133 # Our root_makefile lives at the source root. Compute the relative path 2134 # from there to the output_file for including. 2135 mkfile_rel_path = gyp.common.RelativePath(output_file, 2136 os.path.dirname(makefile_path)) 2137 include_list.add(mkfile_rel_path) 2138 2139 # Write out per-gyp (sub-project) Makefiles. 2140 depth_rel_path = gyp.common.RelativePath(options.depth, os.getcwd()) 2141 for build_file in build_files: 2142 # The paths in build_files were relativized above, so undo that before 2143 # testing against the non-relativized items in target_list and before 2144 # calculating the Makefile path. 2145 build_file = os.path.join(depth_rel_path, build_file) 2146 gyp_targets = [target_dicts[target]['target_name'] for target in target_list 2147 if target.startswith(build_file) and 2148 target in needed_targets] 2149 # Only generate Makefiles for gyp files with targets. 2150 if not gyp_targets: 2151 continue 2152 base_path, output_file = CalculateMakefilePath(build_file, 2153 os.path.splitext(os.path.basename(build_file))[0] + '.Makefile') 2154 makefile_rel_path = gyp.common.RelativePath(os.path.dirname(makefile_path), 2155 os.path.dirname(output_file)) 2156 writer.WriteSubMake(output_file, makefile_rel_path, gyp_targets, 2157 builddir_name) 2158 2159 2160 # Write out the sorted list of includes. 2161 root_makefile.write('\n') 2162 for include_file in sorted(include_list): 2163 # We wrap each .mk include in an if statement so users can tell make to 2164 # not load a file by setting NO_LOAD. The below make code says, only 2165 # load the .mk file if the .mk filename doesn't start with a token in 2166 # NO_LOAD. 2167 root_makefile.write( 2168 "ifeq ($(strip $(foreach prefix,$(NO_LOAD),\\\n" 2169 " $(findstring $(join ^,$(prefix)),\\\n" 2170 " $(join ^," + include_file + ")))),)\n") 2171 root_makefile.write(" include " + include_file + "\n") 2172 root_makefile.write("endif\n") 2173 root_makefile.write('\n') 2174 2175 if (not generator_flags.get('standalone') 2176 and generator_flags.get('auto_regeneration', True)): 2177 WriteAutoRegenerationRule(params, root_makefile, makefile_name, build_files) 2178 2179 root_makefile.write(SHARED_FOOTER) 2180 2181 root_makefile.close() 2182