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