From 100fc27ebb071b7833e0c6f0c10145206ad257e7 Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Sun, 18 Sep 2011 12:08:43 -0700 Subject: Upgrade gyp to r1046 --- tools/gyp/pylib/gyp/generator/make.py | 142 +++++++------ tools/gyp/pylib/gyp/generator/msvs.py | 34 +++- tools/gyp/pylib/gyp/generator/ninja.py | 49 +++-- tools/gyp/pylib/gyp/input.py | 8 +- tools/gyp/tools/Xcode/README | 5 + .../gyp/tools/Xcode/Specifications/gyp.pbfilespec | 27 +++ .../gyp/tools/Xcode/Specifications/gyp.xclangspec | 226 +++++++++++++++++++++ 7 files changed, 393 insertions(+), 98 deletions(-) create mode 100644 tools/gyp/tools/Xcode/README create mode 100644 tools/gyp/tools/Xcode/Specifications/gyp.pbfilespec create mode 100644 tools/gyp/tools/Xcode/Specifications/gyp.xclangspec (limited to 'tools') diff --git a/tools/gyp/pylib/gyp/generator/make.py b/tools/gyp/pylib/gyp/generator/make.py index 24037ab1775..2413b6a9241 100644 --- a/tools/gyp/pylib/gyp/generator/make.py +++ b/tools/gyp/pylib/gyp/generator/make.py @@ -61,12 +61,7 @@ generator_wants_sorted_dependencies = False def GetFlavor(params): """Returns |params.flavor| if it's set, the system's default flavor else.""" - flavors = { - 'darwin': 'mac', - 'sunos5': 'solaris', - } - flavor = flavors.get(sys.platform, 'linux') - return params.get('flavor', flavor) + return params.get('flavor', 'mac' if sys.platform == 'darwin' else 'linux') def CalculateVariables(default_variables, params): @@ -75,8 +70,7 @@ def CalculateVariables(default_variables, params): default_variables['LINKER_SUPPORTS_ICF'] = \ gyp.system_test.TestLinkerSupportsICF(cc_command=cc_target) - flavor = GetFlavor(params) - if flavor == 'mac': + if GetFlavor(params) == 'mac': default_variables.setdefault('OS', 'mac') default_variables.setdefault('SHARED_LIB_SUFFIX', '.dylib') default_variables.setdefault('SHARED_LIB_DIR', @@ -99,7 +93,7 @@ def CalculateVariables(default_variables, params): global COMPILABLE_EXTENSIONS COMPILABLE_EXTENSIONS.update({'.m': 'objc', '.mm' : 'objcxx'}) else: - default_variables.setdefault('OS', flavor) + default_variables.setdefault('OS', 'linux') default_variables.setdefault('SHARED_LIB_SUFFIX', '.so') default_variables.setdefault('SHARED_LIB_DIR','$(builddir)/lib.$(TOOLSET)') default_variables.setdefault('LIB_DIR', '$(obj).$(TOOLSET)') @@ -186,6 +180,31 @@ quiet_cmd_solink_module = SOLINK_MODULE($(TOOLSET)) $@ cmd_solink_module = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(filter-out FORCE_DO_CMD, $^) $(LIBS) """ +LINK_COMMANDS_ANDROID = """\ +quiet_cmd_alink = AR($(TOOLSET)) $@ +cmd_alink = rm -f $@ && $(AR.$(TOOLSET)) $(ARFLAGS.$(TOOLSET)) $@ $(filter %.o,$^) + +# Due to circular dependencies between libraries :(, we wrap the +# special "figure out circular dependencies" flags around the entire +# input list during linking. +quiet_cmd_link = LINK($(TOOLSET)) $@ +quiet_cmd_link_host = LINK($(TOOLSET)) $@ +cmd_link = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ -Wl,--start-group $(LD_INPUTS) -Wl,--end-group $(LIBS) +cmd_link_host = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(LD_INPUTS) $(LIBS) + +# Other shared-object link notes: +# - Set SONAME to the library filename so our binaries don't reference +# the local, absolute paths used on the link command-line. +quiet_cmd_solink = SOLINK($(TOOLSET)) $@ +cmd_solink = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -Wl,-soname=$(@F) -o $@ -Wl,--whole-archive $(LD_INPUTS) -Wl,--no-whole-archive $(LIBS) + +quiet_cmd_solink_module = SOLINK_MODULE($(TOOLSET)) $@ +cmd_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) +quiet_cmd_solink_module_host = SOLINK_MODULE($(TOOLSET)) $@ +cmd_solink_module_host = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -Wl,-soname=$(@F) -o $@ $(filter-out FORCE_DO_CMD, $^) $(LIBS) +""" + + # Header of toplevel Makefile. # This should go into the build tree, but it's easier to keep it here for now. SHARED_HEADER = ("""\ @@ -228,16 +247,16 @@ abs_obj := $(abspath $(obj)) # generated dependency rule Makefiles in one pass. all_deps := -# C++ apps need to be linked with g++. Not sure what's appropriate. +# C++ apps need to be linked with g++. # -# Note, the flock is used to seralize linking. Linking is a memory-intensive +# Note: flock is used to seralize linking. Linking is a memory-intensive # process so running parallel links can often lead to thrashing. To disable -# the serialization, override FLOCK via an envrionment variable as follows: +# the serialization, override LINK via an envrionment variable as follows: # -# export FLOCK= +# export LINK=g++ # # This will allow make to invoke N linker processes as specified in -jN. -FLOCK ?= %(flock)s $(builddir)/linker.lock +LINK ?= %(flock)s $(builddir)/linker.lock $(CXX) %(make_global_settings)s @@ -330,7 +349,7 @@ cmd_cc = $(CC.$(TOOLSET)) $(GYP_CFLAGS) $(DEPFLAGS) $(CFLAGS.$(TOOLSET)) -c -o $ quiet_cmd_cxx = CXX($(TOOLSET)) $@ cmd_cxx = $(CXX.$(TOOLSET)) $(GYP_CXXFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $< -%(extra_commands)s +%(mac_commands)s quiet_cmd_touch = TOUCH $@ cmd_touch = touch $@ @@ -444,14 +463,6 @@ quiet_cmd_mac_package_framework = PACKAGE FRAMEWORK $@ cmd_mac_package_framework = ./gyp-mac-tool package-framework "$@" $(4) """ -SHARED_HEADER_SUN_COMMANDS = """ -# gyp-sun-tool is written next to the root Makefile by gyp. -# Use $(4) for the command, since $(2) and $(3) are used as flag by do_cmd -# already. -quiet_cmd_sun_tool = SUNTOOL $(4) $< -cmd_sun_tool = ./gyp-sun-tool $(4) $< "$@" -""" - def WriteRootHeaderSuffixRules(writer): extensions = sorted(COMPILABLE_EXTENSIONS.keys(), key=str.lower) @@ -1023,24 +1034,29 @@ class MacPrefixHeader(object): # This doesn't support per-configuration prefix headers. Good enough # for now. self.header = None + self.compile_headers = False if path_provider.flavor == 'mac': self.header = path_provider.xcode_settings.GetPerTargetSetting( 'GCC_PREFIX_HEADER') + self.compile_headers = path_provider.xcode_settings.GetPerTargetSetting( + 'GCC_PRECOMPILE_PREFIX_HEADER', default='NO') != 'NO' self.compiled_headers = {} if self.header: self.header = path_provider.Absolutify(self.header) - for lang in ['c', 'cc', 'm', 'mm']: - self.compiled_headers[lang] = path_provider.Pchify(self.header, lang) + if self.compile_headers: + for lang in ['c', 'cc', 'm', 'mm']: + self.compiled_headers[lang] = path_provider.Pchify(self.header, lang) def _Gch(self, lang): """Returns the actual file name of the prefix header for language |lang|.""" + assert self.compile_headers return self.compiled_headers[lang] + '.gch' def WriteObjDependencies(self, compilable, objs, writer): """Writes dependencies from the object files in |objs| to the corresponding precompiled header file. |compilable[i]| has to be the source file belonging to |objs[i]|.""" - if not self.header: + if not self.header or not self.compile_headers: return writer.WriteLn('# Dependencies from obj files to their precompiled headers') @@ -1058,13 +1074,16 @@ class MacPrefixHeader(object): def GetInclude(self, lang): """Gets the cflags to include the prefix header for language |lang|.""" - if lang not in self.compiled_headers: + if self.compile_headers and lang in self.compiled_headers: + return '-include %s ' % self.compiled_headers[lang] + elif self.header: + return '-include %s ' % self.header + else: return '' - return '-include %s ' % self.compiled_headers[lang] def WritePchTargets(self, writer): """Writes make rules to compile the prefix headers.""" - if not self.header: + if not self.header or not self.compile_headers: return writer.WriteLn(self._Gch('c') + ": GYP_PCH_CFLAGS := " @@ -1919,8 +1938,13 @@ $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD 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, - postbuilds=postbuilds) + if self.toolset == 'host' and self.flavor == 'android': + self.WriteDoCmd([self.output_binary], link_deps, 'link_host', + part_of_all, postbuilds=postbuilds) + else: + 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, ( @@ -1936,9 +1960,13 @@ $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD 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, - postbuilds=postbuilds) + if self.toolset == 'host' and self.flavor == 'android': + self.WriteDoCmd([self.output_binary], link_deps, 'solink_module_host', + part_of_all, postbuilds=postbuilds) + else: + self.WriteDoCmd( + [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, @@ -2396,31 +2424,17 @@ def RunSystemTests(flavor): 'LINK_flags': link_flags } -def CopyTool(flavor, out_path): - """Finds (mac|sun)_tool.gyp in the gyp directory and copies it to |out_path|.""" - prefix = { 'solaris': 'sun', 'mac': 'mac' }.get(flavor, None) - if not prefix: - return - - tool_path = os.path.join(out_path, 'gyp-%s-tool' % prefix) - if os.path.exists(tool_path): - os.remove(tool_path) - - # Slurp input file. +def CopyMacTool(out_path): + """Finds mac_tool.gyp in the gyp directory and copies it to |out_path|.""" source_path = os.path.join( - os.path.dirname(os.path.abspath(__file__)), '..', '%s_tool.py' % prefix) + os.path.dirname(os.path.abspath(__file__)), '..', 'mac_tool.py') source_file = open(source_path) source = source_file.readlines() source_file.close() - - # Add header and write it out. - tool_file = open(tool_path, 'w') - tool_file.write( + mactool_file = open(out_path, 'w') + mactool_file.write( ''.join([source[0], '# Generated by gyp. Do not edit.\n'] + source[1:])) - tool_file.close() - - # Make file executable. - os.chmod(tool_path, 0o755) + mactool_file.close() def GenerateOutput(target_list, target_dicts, data, params): @@ -2474,7 +2488,7 @@ def GenerateOutput(target_list, target_dicts, data, params): 'flock': 'flock', 'flock_index': 1, 'link_commands': LINK_COMMANDS_LINUX, - 'extra_commands': '', + 'mac_commands': '', 'srcdir': srcdir, } if flavor == 'mac': @@ -2482,15 +2496,12 @@ def GenerateOutput(target_list, target_dicts, data, params): 'flock': './gyp-mac-tool flock', 'flock_index': 2, 'link_commands': LINK_COMMANDS_MAC, - 'extra_commands': SHARED_HEADER_MAC_COMMANDS, + 'mac_commands': SHARED_HEADER_MAC_COMMANDS, }) - elif flavor == 'solaris': + if flavor == 'android': header_params.update({ - 'flock': './gyp-sun-tool flock', - 'flock_index': 2, - 'extra_commands': SHARED_HEADER_SUN_COMMANDS, + 'link_commands': LINK_COMMANDS_ANDROID, }) - header_params.update(RunSystemTests(flavor)) build_file, _, _ = gyp.common.ParseQualifiedTarget(target_list[0]) @@ -2528,8 +2539,13 @@ def GenerateOutput(target_list, target_dicts, data, params): WriteRootHeaderSuffixRules(root_makefile) # Put mac_tool next to the root Makefile. - dest_path = os.path.dirname(makefile_path) - CopyTool(flavor, dest_path) + if flavor == 'mac': + mactool_path = os.path.join(os.path.dirname(makefile_path), 'gyp-mac-tool') + if os.path.exists(mactool_path): + os.remove(mactool_path) + CopyMacTool(mactool_path) + # Make file executable. + os.chmod(mactool_path, 0755) # Find the list of targets that derive from the gyp file(s) being built. needed_targets = set() diff --git a/tools/gyp/pylib/gyp/generator/msvs.py b/tools/gyp/pylib/gyp/generator/msvs.py index dfecbda7861..38ea3a271fc 100644 --- a/tools/gyp/pylib/gyp/generator/msvs.py +++ b/tools/gyp/pylib/gyp/generator/msvs.py @@ -547,7 +547,7 @@ def _GenerateExternalRules(rules, output_dir, spec, # Write out all: target, including mkdir for each output directory. mk_file.write('all: %s\n' % ' '.join(first_outputs_cyg)) for od in all_output_dirs: - mk_file.write('\tmkdir -p %s\n' % od) + mk_file.write('\tmkdir -p `cygpath -u "%s"`\n' % od) mk_file.write('\n') # Define how each output is generated. for rule in rules: @@ -882,7 +882,7 @@ def _GenerateMSVSProject(project, options, version): p.AddFiles(sources) _AddToolFilesToMSVS(p, spec) - _HandlePreCompileHeaderStubs(p, spec) + _HandlePreCompiledHeaders(p, sources, spec) _AddActions(actions_to_add, spec, relative_path_of_gyp_file) _AddCopies(actions_to_add, spec) _WriteMSVSUserFile(project.path, version, spec) @@ -1383,8 +1383,12 @@ def _AddToolFilesToMSVS(p, spec): p.AddToolFile(f) -def _HandlePreCompileHeaderStubs(p, spec): - # Handle pre-compiled headers source stubs specially. +def _HandlePreCompiledHeaders(p, sources, spec): + # Pre-compiled header source stubs need a different compiler flag + # (generate precompiled header) and any source file not of the same + # kind (i.e. C vs. C++) as the precompiled header source stub needs + # to have use of precompiled headers disabled. + extensions_excluded_from_precompile = [] for config_name, config in spec['configurations'].iteritems(): source = config.get('msvs_precompiled_source') if source: @@ -1394,6 +1398,28 @@ def _HandlePreCompileHeaderStubs(p, spec): {'UsePrecompiledHeader': '1'}) p.AddFileConfig(source, _ConfigFullName(config_name, config), {}, tools=[tool]) + basename, extension = os.path.splitext(source) + if extension == '.c': + extensions_excluded_from_precompile = ['.cc', '.cpp', '.cxx'] + else: + extensions_excluded_from_precompile = ['.c'] + def DisableForSourceTree(source_tree): + for source in source_tree: + if isinstance(source, MSVSProject.Filter): + DisableForSourceTree(source.contents) + else: + basename, extension = os.path.splitext(source) + if extension in extensions_excluded_from_precompile: + for config_name, config in spec['configurations'].iteritems(): + tool = MSVSProject.Tool('VCCLCompilerTool', + {'UsePrecompiledHeader': '0', + 'ForcedIncludeFiles': '$(NOINHERIT)'}) + p.AddFileConfig(_FixPath(source), + _ConfigFullName(config_name, config), + {}, tools=[tool]) + # Do nothing if there was no precompiled source. + if extensions_excluded_from_precompile: + DisableForSourceTree(sources) def _AddActions(actions_to_add, spec, relative_path_of_gyp_file): diff --git a/tools/gyp/pylib/gyp/generator/ninja.py b/tools/gyp/pylib/gyp/generator/ninja.py index b63e42cdb08..4e5a12f1002 100644 --- a/tools/gyp/pylib/gyp/generator/ninja.py +++ b/tools/gyp/pylib/gyp/generator/ninja.py @@ -41,10 +41,10 @@ generator_default_variables = { # Special variables that may be used by gyp 'rule' targets. # We generate definitions for these variables on the fly when processing a # rule. - 'RULE_INPUT_ROOT': '$root', - 'RULE_INPUT_PATH': '$source', - 'RULE_INPUT_EXT': '$ext', - 'RULE_INPUT_NAME': '$name', + 'RULE_INPUT_ROOT': '${root}', + 'RULE_INPUT_PATH': '${source}', + 'RULE_INPUT_EXT': '${ext}', + 'RULE_INPUT_NAME': '${name}', } # TODO: enable cross compiling once we figure out: @@ -195,12 +195,17 @@ class NinjaWriter: return os.path.normpath(os.path.join(obj, self.base_dir, path_dir, path_basename)) - def StampPath(self, name): - """Return a path for a stamp file with a particular name. + def WriteCollapsedDependencies(self, name, targets): + """Given a list of targets, return a dependency list for a single + file representing the result of building all the targets. - Stamp files are used to collapse a dependency on a bunch of files - into a single file.""" - return self.GypPathToUniqueOutput(name + '.stamp') + Uses a stamp file if necessary.""" + + if len(targets) > 1: + stamp = self.GypPathToUniqueOutput(name + '.stamp') + targets = self.ninja.build(stamp, 'stamp', targets) + self.ninja.newline() + return targets def WriteSpec(self, spec, config): """The main entry point for NinjaWriter: write the build rules for a spec. @@ -220,14 +225,10 @@ class NinjaWriter: # running any of its internal steps. prebuild = [] if 'dependencies' in spec: - prebuild_deps = [] for dep in spec['dependencies']: if dep in self.target_outputs: - prebuild_deps.append(self.target_outputs[dep][0]) - if prebuild_deps: - stamp = self.StampPath('predepends') - prebuild = self.ninja.build(stamp, 'stamp', prebuild_deps) - self.ninja.newline() + prebuild.append(self.target_outputs[dep][0]) + prebuild = self.WriteCollapsedDependencies('predepends', prebuild) # Write out actions, rules, and copies. These must happen before we # compile any sources, so compute a list of predependencies for sources @@ -270,11 +271,7 @@ class NinjaWriter: if 'copies' in spec: outputs += self.WriteCopies(spec['copies'], prebuild) - # To simplify downstream build edges, ensure we generate a single - # stamp file that represents the results of all of the above. - if len(outputs) > 1: - stamp = self.StampPath('actions_rules_copies') - outputs = self.ninja.build(stamp, 'stamp', outputs) + outputs = self.WriteCollapsedDependencies('actions_rules_copies', outputs) return outputs @@ -322,9 +319,10 @@ class NinjaWriter: # First write out a rule for the rule action. name = rule['rule_name'] args = rule['action'] - description = self.GenerateDescription('RULE', - rule.get('message', None), - '%s $source' % name) + description = self.GenerateDescription( + 'RULE', + rule.get('message', None), + ('%s ' + generator_default_variables['RULE_INPUT_PATH']) % name) rule_name = self.WriteNewNinjaRule(name, args, description) # TODO: if the command references the outputs directly, we should @@ -337,7 +335,7 @@ class NinjaWriter: needed_variables = set(['source']) for argument in args: for var in special_locals: - if '$' + var in argument: + if ('${%s}' % var) in argument: needed_variables.add(var) # For each source file, write an edge that generates all the outputs. @@ -348,7 +346,8 @@ class NinjaWriter: # Gather the list of outputs, expanding $vars if possible. outputs = [] for output in rule['outputs']: - outputs.append(output.replace('$root', root)) + outputs.append(output.replace( + generator_default_variables['RULE_INPUT_ROOT'], root)) if int(rule.get('process_outputs_as_sources', False)): extra_sources += outputs diff --git a/tools/gyp/pylib/gyp/input.py b/tools/gyp/pylib/gyp/input.py index d4eeebc0fc1..4204f63276e 100644 --- a/tools/gyp/pylib/gyp/input.py +++ b/tools/gyp/pylib/gyp/input.py @@ -1328,7 +1328,7 @@ class DependencyGraphNode(object): setting. When adding a target to the list of dependencies, this function will - recurse into itself with |initial| set to False, to collect depenedencies + recurse into itself with |initial| set to False, to collect dependencies that are linked into the linkable target for which the list is being built. """ if dependencies == None: @@ -1369,11 +1369,7 @@ class DependencyGraphNode(object): # The target is linkable, add it to the list of link dependencies. if self.ref not in dependencies: - if target_type != 'none': - # Special case: "none" type targets don't produce any linkable products - # and shouldn't be exposed as link dependencies, although dependencies - # of "none" type targets may still be link dependencies. - dependencies.append(self.ref) + dependencies.append(self.ref) if initial or not is_linkable: # If this is a subsequent target and it's linkable, don't look any # further for linkable dependencies, as they'll already be linked into diff --git a/tools/gyp/tools/Xcode/README b/tools/gyp/tools/Xcode/README new file mode 100644 index 00000000000..2492a2c2f8f --- /dev/null +++ b/tools/gyp/tools/Xcode/README @@ -0,0 +1,5 @@ +Specifications contains syntax formatters for Xcode 3. These do not appear to be supported yet on Xcode 4. To use these with Xcode 3 please install both the gyp.pbfilespec and gyp.xclangspec files in + +~/Library/Application Support/Developer/Shared/Xcode/Specifications/ + +and restart Xcode. \ No newline at end of file diff --git a/tools/gyp/tools/Xcode/Specifications/gyp.pbfilespec b/tools/gyp/tools/Xcode/Specifications/gyp.pbfilespec new file mode 100644 index 00000000000..85e2e268a51 --- /dev/null +++ b/tools/gyp/tools/Xcode/Specifications/gyp.pbfilespec @@ -0,0 +1,27 @@ +/* + gyp.pbfilespec + GYP source file spec for Xcode 3 + + There is not much documentation available regarding the format + of .pbfilespec files. As a starting point, see for instance the + outdated documentation at: + http://maxao.free.fr/xcode-plugin-interface/specifications.html + and the files in: + /Developer/Library/PrivateFrameworks/XcodeEdit.framework/Versions/A/Resources/ + + Place this file in directory: + ~/Library/Application Support/Developer/Shared/Xcode/Specifications/ +*/ + +( + { + Identifier = sourcecode.gyp; + BasedOn = sourcecode; + Name = "GYP Files"; + Extensions = ("gyp", "gypi"); + MIMETypes = ("text/gyp"); + Language = "xcode.lang.gyp"; + IsTextFile = YES; + IsSourceFile = YES; + } +) diff --git a/tools/gyp/tools/Xcode/Specifications/gyp.xclangspec b/tools/gyp/tools/Xcode/Specifications/gyp.xclangspec new file mode 100644 index 00000000000..3b3506d319e --- /dev/null +++ b/tools/gyp/tools/Xcode/Specifications/gyp.xclangspec @@ -0,0 +1,226 @@ +/* + Copyright (c) 2011 Google Inc. All rights reserved. + Use of this source code is governed by a BSD-style license that can be + found in the LICENSE file. + + gyp.xclangspec + GYP language specification for Xcode 3 + + There is not much documentation available regarding the format + of .xclangspec files. As a starting point, see for instance the + outdated documentation at: + http://maxao.free.fr/xcode-plugin-interface/specifications.html + and the files in: + /Developer/Library/PrivateFrameworks/XcodeEdit.framework/Versions/A/Resources/ + + Place this file in directory: + ~/Library/Application Support/Developer/Shared/Xcode/Specifications/ +*/ + +( + + { + Identifier = "xcode.lang.gyp.keyword"; + Syntax = { + Words = ( + "and", + "or", + "