diff options
author | Ryan Dahl <ry@tinyclouds.org> | 2011-08-22 17:08:16 -0700 |
---|---|---|
committer | Ryan Dahl <ry@tinyclouds.org> | 2011-08-22 17:09:57 -0700 |
commit | 80dd8182907314ae99f5572798c86176e2086c47 (patch) | |
tree | 3dddb582141ef135a93789a288c25eed543f32f9 /tools/gyp/pylib/gyp/generator/make.py | |
parent | c2ae39b8d60407261d1963461087798458b31358 (diff) | |
download | android-node-v8-80dd8182907314ae99f5572798c86176e2086c47.tar.gz android-node-v8-80dd8182907314ae99f5572798c86176e2086c47.tar.bz2 android-node-v8-80dd8182907314ae99f5572798c86176e2086c47.zip |
Upgrade GYP to r1010
Diffstat (limited to 'tools/gyp/pylib/gyp/generator/make.py')
-rw-r--r-- | tools/gyp/pylib/gyp/generator/make.py | 260 |
1 files changed, 183 insertions, 77 deletions
diff --git a/tools/gyp/pylib/gyp/generator/make.py b/tools/gyp/pylib/gyp/generator/make.py index 5ebc5c96c7..b8914785bf 100644 --- a/tools/gyp/pylib/gyp/generator/make.py +++ b/tools/gyp/pylib/gyp/generator/make.py @@ -29,7 +29,6 @@ import gyp.system_test import os.path import os import sys -import stat # Debugging-related imports -- remove me once we're solid. import code @@ -374,6 +373,7 @@ prereq_changed = $(filter-out FORCE_DO_CMD,$(filter-out $|,$?)) # do_cmd: run a command via the above cmd_foo names, if necessary. # Should always run for a given target to handle command-line changes. # Second argument, if non-zero, makes it do asm/C/C++ dependency munging. +# Third argument, if non-zero, makes it do POSTBUILDS processing. # Note: We intentionally do NOT call dirx for depfile, since it contains """ + \ SPACE_REPLACEMENT + """ for # spaces already and dirx strips the """ + SPACE_REPLACEMENT + \ @@ -389,6 +389,9 @@ $(if $(or $(command_changed),$(prereq_changed)), ) @$(call exact_echo,$(call escape_vars,cmd_$(call replace_spaces,$@) := $(cmd_$(1)))) > $(depfile) @$(if $(2),$(fixup_dep)) + $(if $(and $(3), $(POSTBUILDS)), + @for p in $(POSTBUILDS); do eval $$p; done + ) ) endef @@ -422,12 +425,13 @@ quiet_cmd_pch_mm = CXX($(TOOLSET)) $@ cmd_pch_mm = $(CC.$(TOOLSET)) $(GYP_PCH_OBJCXXFLAGS) $(DEPFLAGS) -c -o $@ $< # gyp-mac-tool is written next to the root Makefile by gyp. -# Use #(3) for the command, since $(2) is used as flag by do_cmd already. -quiet_cmd_mac_tool = MACTOOL $(3) $< -cmd_mac_tool = ./gyp-mac-tool $(3) $< "$@" +# Use $(4) for the command, since $(2) and $(3) are used as flag by do_cmd +# already. +quiet_cmd_mac_tool = MACTOOL $(4) $< +cmd_mac_tool = ./gyp-mac-tool $(4) $< "$@" quiet_cmd_mac_package_framework = PACKAGE FRAMEWORK $@ -cmd_mac_package_framework = ./gyp-mac-tool package-framework "$@" $(3) +cmd_mac_package_framework = ./gyp-mac-tool package-framework "$@" $(4) """ @@ -676,9 +680,9 @@ class XcodeSettings(object): return os.path.join(self.GetBundleContentsFolderPath(), 'Resources', 'Info.plist') - def GetBundleBinaryPath(self): - """Returns the directory name of the bundle represented by this target. E.g. - Chromium.app/Contents/MacOS/Chromium. Only valid for bundles.""" + def _GetBundleBinaryPath(self): + """Returns the name of the bundle binary of by this target. + E.g. Chromium.app/Contents/MacOS/Chromium. Only valid for bundles.""" assert self._IsBundle() if self.spec['type'] in ('loadable_module', 'shared_library'): path = self.GetBundleContentsFolderPath() @@ -687,6 +691,53 @@ class XcodeSettings(object): return os.path.join(path, self.spec.get('product_name', self.spec['target_name'])) + def _GetStandaloneExecutableSuffix(self): + if 'product_extension' in self.spec: + return '.' + self.spec['product_extension'] + return { + 'executable': '', + 'static_library': '.a', + 'shared_library': '.dylib', + 'loadable_module': '.so', + }[self.spec['type']] + + def _GetStandaloneExecutablePrefix(self): + return self.spec.get('product_prefix', { + 'executable': '', + 'static_library': 'lib', + 'shared_library': 'lib', + # Non-bundled loadable_modules are called foo.so for some reason + # (that is, .so and no prefix) with the xcode build -- match that. + 'loadable_module': '', + }[self.spec['type']]) + + def _GetStandaloneBinaryPath(self): + """Returns the name of the non-bundle binary represented by this target. + E.g. hello_world. Only valid for non-bundles.""" + assert not self._IsBundle() + assert self.spec['type'] in ( + 'executable', 'shared_library', 'static_library', 'loadable_module') + target = self.spec['target_name'] + if self.spec['type'] == 'static_library': + if target[:3] == 'lib': + target = target[3:] + elif self.spec['type'] in ('loadable_module', 'shared_library'): + if target[:3] == 'lib': + target = target[3:] + + target_prefix = self._GetStandaloneExecutablePrefix() + target = self.spec.get('product_name', target) + target_ext = self._GetStandaloneExecutableSuffix() + return target_prefix + target + target_ext + + def GetExecutablePath(self): + """Returns the directory name of the bundle represented by this target. E.g. + Chromium.app/Contents/MacOS/Chromium.""" + if self._IsBundle(): + return self._GetBundleBinaryPath() + else: + return self._GetStandaloneBinaryPath() + def GetCflags(self, configname): """Returns flags that need to be added to .c, .cc, .m, and .mm compilations.""" @@ -838,6 +889,10 @@ class XcodeSettings(object): ldflags, 'DYLIB_COMPATIBILITY_VERSION', '-compatibility_version %s') self._Appendf( ldflags, 'DYLIB_CURRENT_VERSION', '-current_version %s') + self._Appendf( + ldflags, 'MACOSX_DEPLOYMENT_TARGET', '-mmacosx-version-min=%s') + self._Appendf( + ldflags, 'SDKROOT', '-isysroot /Developer/SDKs/%s.sdk') for library_path in self._Settings().get('LIBRARY_SEARCH_PATHS', []): ldflags.append('-L' + library_path) @@ -855,37 +910,47 @@ class XcodeSettings(object): ldflags.append('-L' + generator_default_variables['PRODUCT_DIR']) install_name = self.GetPerTargetSetting('LD_DYLIB_INSTALL_NAME') + install_base = self.GetPerTargetSetting('DYLIB_INSTALL_NAME_BASE') + default_install_name = \ + '$(DYLIB_INSTALL_NAME_BASE:standardizepath)/$(EXECUTABLE_PATH)' + if not install_name and install_base: + install_name = default_install_name + if install_name: # Hardcode support for the variables used in chromium for now, to unblock # people using the make build. if '$' in install_name: - assert install_name == ('$(DYLIB_INSTALL_NAME_BASE:standardizepath)/' - '$(WRAPPER_NAME)/$(PRODUCT_NAME)'), ( + assert install_name in ('$(DYLIB_INSTALL_NAME_BASE:standardizepath)/' + '$(WRAPPER_NAME)/$(PRODUCT_NAME)', default_install_name), ( 'Variables in LD_DYLIB_INSTALL_NAME are not generally supported yet' ' in target \'%s\' (got \'%s\')' % (self.spec['target_name'], install_name)) - install_base = self.GetPerTargetSetting('DYLIB_INSTALL_NAME_BASE') # I'm not quite sure what :standardizepath does. Just call normpath(), - # but don't let @executable_path/../foo collapse to foo - prefix, rest = '', install_base - if install_base.startswith('@'): - prefix, rest = install_base.split('/', 1) - rest = os.path.normpath(rest) # :standardizepath - install_base = os.path.join(prefix, rest) + # but don't let @executable_path/../foo collapse to foo. + if '/' in install_base: + prefix, rest = '', install_base + if install_base.startswith('@'): + prefix, rest = install_base.split('/', 1) + rest = os.path.normpath(rest) # :standardizepath + install_base = os.path.join(prefix, rest) install_name = install_name.replace( '$(DYLIB_INSTALL_NAME_BASE:standardizepath)', install_base) + if self._IsBundle(): + # These are only valid for bundles, hence the |if|. + install_name = install_name.replace( + '$(WRAPPER_NAME)', self.GetWrapperName()) + install_name = install_name.replace( + '$(PRODUCT_NAME)', self.GetProductName()) + else: + assert '$(WRAPPER_NAME)' not in install_name + assert '$(PRODUCT_NAME)' not in install_name + install_name = install_name.replace( - '$(WRAPPER_NAME)', self.GetWrapperName()) - install_name = install_name.replace( - '$(PRODUCT_NAME)', self.GetProductName()) + '$(EXECUTABLE_PATH)', self.GetExecutablePath()) install_name = QuoteSpaces(install_name) ldflags.append('-install_name ' + install_name) - elif self.GetPerTargetSetting('DYLIB_INSTALL_NAME_BASE'): - # LD_DYLIB_INSTALL_NAME defaults to - # $(DYLIB_INSTALL_NAME_BASE:standardizepath)/$(EXECUTABLE_PATH). - print 'Warning: DYLIB_INSTALL_NAME_BASE is not fully implemented.' self.configname = None return ldflags @@ -1453,7 +1518,7 @@ $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD if output.endswith('.xib'): output = output[0:-3] + 'nib' - self.WriteDoCmd([output], [path], 'mac_tool,,copy-bundle-resource', + self.WriteDoCmd([output], [path], 'mac_tool,,,copy-bundle-resource', part_of_all=True) bundle_deps.append(output) @@ -1467,7 +1532,7 @@ $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD dest_plist = os.path.join(path, self.xcode_settings.GetBundlePlistPath()) dest_plist = QuoteSpaces(dest_plist) self.WriteXcodeEnv(dest_plist, spec) # plists can contain envvars. - self.WriteDoCmd([dest_plist], [info_plist], 'mac_tool,,copy-info-plist', + self.WriteDoCmd([dest_plist], [info_plist], 'mac_tool,,,copy-info-plist', part_of_all=True) bundle_deps.append(dest_plist) @@ -1593,18 +1658,21 @@ $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD self.WriteLn() - def ComputeOutput(self, spec): - """Return the 'output' (full output path) of a gyp spec. + def ComputeOutputBasename(self, spec): + """Return the 'output basename' of a gyp spec. E.g., the loadable module 'foobar' in directory 'baz' will produce - '$(obj)/baz/libfoobar.so' + 'libfoobar.so' """ assert not self.is_mac_bundle + if self.flavor == 'mac' and self.type in ( + 'static_library', 'executable', 'shared_library', 'loadable_module'): + return self.xcode_settings.GetExecutablePath() + target = spec['target_name'] target_prefix = '' target_ext = '' - path = os.path.join('$(obj).' + self.toolset, self.path) if self.type == 'static_library': if target[:3] == 'lib': target = target[3:] @@ -1615,31 +1683,37 @@ $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD target = target[3:] target_prefix = 'lib' target_ext = '.so' - if self.flavor == 'mac': - if self.type == 'shared_library': - target_ext = '.dylib' - else: - # Non-bundled loadable_modules are called foo.so for some reason - # (that is, .so and no prefix) with the xcode build -- match that. - target_prefix = '' elif self.type == 'none': target = '%s.stamp' % target - elif self.type == 'settings': - return '' # Doesn't have any output. - elif self.type == 'executable': - path = os.path.join('$(builddir)') - else: + elif self.type != 'executable': print ("ERROR: What output file should be generated?", "type", self.type, "target", target) - path = spec.get('product_dir', path) target_prefix = spec.get('product_prefix', target_prefix) target = spec.get('product_name', target) product_ext = spec.get('product_extension') if product_ext: target_ext = '.' + product_ext - return os.path.join(path, target_prefix + target + target_ext) + return target_prefix + target + target_ext + + + def ComputeOutput(self, spec): + """Return the 'output' (full output path) of a gyp spec. + + E.g., the loadable module 'foobar' in directory 'baz' will produce + '$(obj)/baz/libfoobar.so' + """ + assert not self.is_mac_bundle + + if self.type == 'settings': + return '' # Doesn't have any output. + + path = os.path.join('$(obj).' + self.toolset, self.path) + if self.type == 'executable': + path = '$(builddir)' + path = spec.get('product_dir', path) + return os.path.join(path, self.ComputeOutputBasename(spec)) def ComputeMacBundleOutput(self, spec): @@ -1652,7 +1726,7 @@ $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD def ComputeMacBundleBinaryOutput(self, spec): """Return the 'output' (full output path) to the binary in a bundle.""" path = generator_default_variables['PRODUCT_DIR'] - return os.path.join(path, self.xcode_settings.GetBundleBinaryPath()) + return os.path.join(path, self.xcode_settings.GetExecutablePath()) def ComputeDeps(self, spec): @@ -1731,6 +1805,21 @@ $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD '%s: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE))' % self.output_binary) self.WriteLn('%s: LIBS := $(LIBS)' % self.output_binary) + postbuilds = [] + if self.flavor == 'mac': + # Postbuild actions. Like actions, but implicitly depend on the target's + # output. + for postbuild in spec.get('postbuilds', []): + postbuilds.append('echo POSTBUILD\\(%s\\) %s' % ( + self.target, postbuild['postbuild_name'])) + shell_list = postbuild['action'] + # The first element is the command. If it's a relative path, it's + # a script in the source tree relative to the gyp file and needs to be + # absolutified. Else, it's in the PATH (e.g. install_name_tool, ln). + if os.path.sep in shell_list[0]: + shell_list[0] = self.Absolutify(shell_list[0]) + postbuilds.append('%s' % gyp.common.EncodePOSIXShellList(shell_list)) + # A bundle directory depends on its dependencies such as bundle resources # and bundle binary. When all dependencies have been built, the bundle # needs to be packaged. @@ -1749,22 +1838,14 @@ $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD # After the framework is built, package it. Needs to happen before # postbuilds, since postbuilds depend on this. if self.type in ('shared_library', 'loadable_module'): - self.WriteLn('\t@$(call do_cmd,mac_package_framework,0,%s)' % + self.WriteLn('\t@$(call do_cmd,mac_package_framework,0,0,%s)' % self.xcode_settings.GetFrameworkVersion()) - # Postbuild actions. Like actions, but implicitly depend on the output - # framework. - for postbuild in spec.get('postbuilds', []): - self.WriteLn('\t@echo POSTBUILD %s' % postbuild['postbuild_name']) - shell_list = postbuild['action'] - # The first element is the command. If it's a relative path, it's - # a script in the source tree relative to the gyp file and needs to be - # absolutified. Else, it's in the PATH (e.g. install_name_tool, ln). - if os.path.sep in shell_list[0]: - shell_list[0] = self.Absolutify(shell_list[0]) - # TODO: Honor V=1 etc. Not using do_cmd because since this is part of - # the framework rule, there's no need for .d file processing here. - self.WriteLn('\t@%s' % gyp.common.EncodePOSIXShellList(shell_list)) + # Bundle postbuilds can depend on the whole bundle, so run them after + # the bundle is packaged, not already after the bundle binary is done. + for postbuild in postbuilds: + self.WriteLn('\t@' + postbuild) + postbuilds = [] # Don't write postbuilds for target's output. # Needed by test/mac/gyptest-rebuild.py. self.WriteLn('\t@true # No-op, used by tests') @@ -1775,32 +1856,43 @@ $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD # on every build (expensive, especially with postbuilds), expliclity # update the time on the framework directory. self.WriteLn('\t@touch -c %s' % self.output) - elif 'postbuilds' in spec: - print ("Warning: 'postbuild' support for non-bundles " - "isn't implemented yet (target '%s)'." % self.target) + + if postbuilds: + assert not self.is_mac_bundle, ('Postbuilds for bundles should be done ' + 'on the bundle, not the binary (target \'%s\')' % self.target) + self.WriteXcodeEnv(self.output_binary, spec) # For postbuilds + postbuilds = [EscapeShellArgument(p) for p in postbuilds] + self.WriteLn('%s: builddir := $(abs_builddir)' % self.output_binary) + self.WriteLn('%s: POSTBUILDS := %s' % ( + self.output_binary, ' '.join(postbuilds))) if self.type == 'executable': self.WriteLn( '%s: LD_INPUTS := %s' % (self.output_binary, ' '.join(link_deps))) - self.WriteDoCmd([self.output_binary], link_deps, 'link', part_of_all) + self.WriteDoCmd([self.output_binary], link_deps, 'link', part_of_all, + postbuilds=postbuilds) elif self.type == 'static_library': for link_dep in link_deps: assert ' ' not in link_dep, ( "Spaces in alink input filenames not supported (%s)" % link_dep) - self.WriteDoCmd([self.output_binary], link_deps, 'alink', part_of_all) + self.WriteDoCmd([self.output_binary], link_deps, 'alink', part_of_all, + postbuilds=postbuilds) elif self.type == 'shared_library': self.WriteLn( '%s: LD_INPUTS := %s' % (self.output_binary, ' '.join(link_deps))) - self.WriteDoCmd([self.output_binary], link_deps, 'solink', part_of_all) + self.WriteDoCmd([self.output_binary], link_deps, 'solink', part_of_all, + postbuilds=postbuilds) elif self.type == 'loadable_module': for link_dep in link_deps: assert ' ' not in link_dep, ( "Spaces in module input filenames not supported (%s)" % link_dep) self.WriteDoCmd( - [self.output_binary], link_deps, 'solink_module', part_of_all) + [self.output_binary], link_deps, 'solink_module', part_of_all, + postbuilds=postbuilds) elif self.type == 'none': # Write a stamp line. - self.WriteDoCmd([self.output_binary], deps, 'touch', part_of_all) + self.WriteDoCmd([self.output_binary], deps, 'touch', part_of_all, + postbuilds=postbuilds) elif self.type == 'settings': # Only used for passing flags around. pass @@ -1867,14 +1959,19 @@ $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD self.fp.write("\n\n") - def WriteDoCmd(self, outputs, inputs, command, part_of_all, comment=None): + def WriteDoCmd(self, outputs, inputs, command, part_of_all, comment=None, + postbuilds=False): """Write a Makefile rule that uses do_cmd. This makes the outputs dependent on the command line that was run, as well as support the V= make command line flag. """ + suffix = '' + if postbuilds: + assert ',' not in command + suffix = ',,1' # Tell do_cmd to honor $POSTBUILDS self.WriteMakeRule(outputs, inputs, - actions = ['$(call do_cmd,%s)' % command], + actions = ['$(call do_cmd,%s%s)' % (command, suffix)], comment = comment, force = True) # Add our outputs to the list of targets we read depfiles from. @@ -2042,6 +2139,18 @@ $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD product_name = spec.get('product_name', self.output) + # Some postbuilds try to read a build output file at + # ""${BUILT_PRODUCTS_DIR}/${FULL_PRODUCT_NAME}". Static libraries end up + # "$(obj).target", so + # BUILT_PRODUCTS_DIR is $(builddir) + # FULL_PRODUCT_NAME is $(out).target/path/to/lib.a + # Since $(obj) contains out/Debug already, the postbuild + # would get out/Debug/out/Debug/obj.target/path/to/lib.a. To prevent this, + # remove the "out/Debug" prefix from $(obj). + if product_name.startswith('$(obj)'): + product_name = ( + '$(subst $(builddir)/,,$(obj))' + product_name[len('$(obj)'):]) + built_products_dir = generator_default_variables['PRODUCT_DIR'] srcroot = self.path if target_relative_path: @@ -2052,6 +2161,8 @@ $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD 'BUILT_PRODUCTS_DIR' : built_products_dir, 'CONFIGURATION' : '$(BUILDTYPE)', 'PRODUCT_NAME' : product_name, + # See /Developer/Platforms/MacOSX.platform/Developer/Library/Xcode/Specifications/MacOSX\ Product\ Types.xcspec for FULL_PRODUCT_NAME + 'FULL_PRODUCT_NAME' : product_name, 'SRCROOT' : srcroot, # This is not true for static libraries, but currently the env is only # written for bundles: @@ -2060,13 +2171,9 @@ $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD } if self.type in ('executable', 'shared_library'): env['EXECUTABLE_NAME'] = os.path.basename(self.output_binary) - # Can't use self.output_binary here because it's not in the products dir. - # We really care about the final location of the dylib anyway. - env['EXECUTABLE_PATH'] = StripProductDir( - self._InstallableTargetInstallPath()) + if self.type in ('executable', 'shared_library', 'loadable_module'): + env['EXECUTABLE_PATH'] = self.xcode_settings.GetExecutablePath() if self.is_mac_bundle: - # Overwrite this to point to the binary _in_ the bundle. - env['EXECUTABLE_PATH'] = self.xcode_settings.GetBundleBinaryPath() env['CONTENTS_FOLDER_PATH'] = \ self.xcode_settings.GetBundleContentsFolderPath() env['INFOPLIST_PATH'] = self.xcode_settings.GetBundlePlistPath() @@ -2312,8 +2419,7 @@ def GenerateOutput(target_list, target_dicts, data, params): if os.path.exists(mactool_path): os.remove(mactool_path) CopyMacTool(mactool_path) - os.chmod(mactool_path, stat.S_IRWXU | stat.S_IRGRP | stat.S_IXGRP | - stat.S_IROTH | stat.S_IXOTH) # Make file executable. + os.chmod(mactool_path, 0o755) # Make file executable. # Find the list of targets that derive from the gyp file(s) being built. needed_targets = set() |