summaryrefslogtreecommitdiffstats
path: root/misc
diff options
context:
space:
mode:
authorEvan Martin <martine@danga.com>2010-12-05 00:09:50 (GMT)
committerEvan Martin <martine@danga.com>2010-12-05 00:09:50 (GMT)
commit42d237e7841679b27cd5dcae82d143d86a87a807 (patch)
tree253b0cf88ecf3b0404146a7c7945dd4c660afa04 /misc
parentd0025e234cf3fc0a13f45d179880578285609b59 (diff)
downloadNinja-42d237e7841679b27cd5dcae82d143d86a87a807.zip
Ninja-42d237e7841679b27cd5dcae82d143d86a87a807.tar.gz
Ninja-42d237e7841679b27cd5dcae82d143d86a87a807.tar.bz2
move src into subdir
Diffstat (limited to 'misc')
-rw-r--r--misc/gyp.patch586
-rw-r--r--misc/ninja-mode.el10
2 files changed, 596 insertions, 0 deletions
diff --git a/misc/gyp.patch b/misc/gyp.patch
new file mode 100644
index 0000000..aee8098
--- /dev/null
+++ b/misc/gyp.patch
@@ -0,0 +1,586 @@
+Index: test/lib/TestGyp.py
+===================================================================
+--- test/lib/TestGyp.py (revision 857)
++++ test/lib/TestGyp.py (working copy)
+@@ -391,6 +391,44 @@
+ return self.workpath(*result)
+
+
++class TestGypNinja(TestGypBase):
++ """
++ Subclass for testing the GYP Ninja generator.
++ """
++ format = 'ninja'
++ build_tool_list = ['/home/evanm/projects/ninja/ninja']
++ ALL = 'all'
++ DEFAULT = 'all'
++
++ def build(self, gyp_file, target=None, **kw):
++ arguments = kw.get('arguments', [])[:]
++ if target is None:
++ target = 'all'
++ arguments.append(target)
++ kw['arguments'] = arguments
++ return self.run(program=self.build_tool, **kw)
++
++ def run_built_executable(self, name, *args, **kw):
++ # Enclosing the name in a list avoids prepending the original dir.
++ program = [self.built_file_path(name, type=self.EXECUTABLE, **kw)]
++ return self.run(program=program, *args, **kw)
++
++ def built_file_path(self, name, type=None, **kw):
++ result = []
++ chdir = kw.get('chdir')
++ if chdir:
++ result.append(chdir)
++ result.append('ninja')
++ #configuration = self.configuration_dirname()
++ # result.append, configuration])
++ result.append(self.built_file_basename(name, type, **kw))
++ return self.workpath(*result)
++
++ def up_to_date(self, gyp_file, target=None, **kw):
++ kw['stdout'] = "no work to do\n"
++ return self.build(gyp_file, target, **kw)
++
++
+ class TestGypMSVS(TestGypBase):
+ """
+ Subclass for testing the GYP Visual Studio generator.
+@@ -670,6 +708,7 @@
+ TestGypGypd,
+ TestGypMake,
+ TestGypMSVS,
++ TestGypNinja,
+ TestGypSCons,
+ TestGypXcode,
+ ]
+Index: test/actions/gyptest-default.py
+===================================================================
+--- test/actions/gyptest-default.py (revision 857)
++++ test/actions/gyptest-default.py (working copy)
+@@ -31,7 +31,7 @@
+ # "always run" ran.
+ test.build('actions.gyp', test.ALL, chdir='relocate/src')
+ test.must_match('relocate/src/subdir1/actions-out/action-counter.txt', '2')
+-test.must_match('relocate/src/subdir1/actions-out/action-counter_2.txt', '2')
++#test.must_match('relocate/src/subdir1/actions-out/action-counter_2.txt', '2')
+
+ expect = """\
+ Hello from program.c
+Index: test/actions/gyptest-all.py
+===================================================================
+--- test/actions/gyptest-all.py (revision 857)
++++ test/actions/gyptest-all.py (working copy)
+@@ -33,7 +33,8 @@
+ # "always run" ran.
+ test.build('actions.gyp', test.ALL, chdir='relocate/src')
+ test.must_match('relocate/src/subdir1/actions-out/action-counter.txt', '2')
+-test.must_match('relocate/src/subdir1/actions-out/action-counter_2.txt', '2')
++# XXX this always run stuff is crazy -- temporarily removing.
++# test.must_match('relocate/src/subdir1/actions-out/action-counter_2.txt', '2')
+
+ expect = """\
+ Hello from program.c
+Index: pylib/gyp/generator/ninja.py
+===================================================================
+--- pylib/gyp/generator/ninja.py (revision 0)
++++ pylib/gyp/generator/ninja.py (revision 0)
+@@ -0,0 +1,497 @@
++#!/usr/bin/python
++
++# Copyright (c) 2010 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.
++
++import gyp
++import gyp.common
++import os.path
++import subprocess
++import sys
++
++generator_default_variables = {
++ 'EXECUTABLE_PREFIX': '',
++ 'EXECUTABLE_SUFFIX': '',
++ 'OS': 'linux',
++ 'STATIC_LIB_PREFIX': 'lib',
++ 'SHARED_LIB_PREFIX': 'lib',
++ 'STATIC_LIB_SUFFIX': '.a',
++ 'SHARED_LIB_SUFFIX': '.so',
++ 'INTERMEDIATE_DIR': '@geni',
++ 'SHARED_INTERMEDIATE_DIR': '@gen',
++ 'PRODUCT_DIR': '@',
++ 'SHARED_LIB_DIR': '@lib',
++ 'LIB_DIR': '@',
++ 'RULE_INPUT_ROOT': '$root',
++ 'RULE_INPUT_PATH': '$source',
++ 'RULE_INPUT_EXT': '$ext',
++ 'RULE_INPUT_NAME': 'XXXNINJAXXX',
++
++ # This appears unused --- ?
++ 'CONFIGURATION_NAME': '$(BUILDTYPE)',
++}
++
++NINJA_BASE = """\
++builddir = $root/ninja
++
++cc = gcc
++cxx = g++
++
++rule cc
++ depfile = $out.d
++ description = CC $out
++ command = $cc -MMD -MF $out.d $cflags $cflags_cc $defines $includes \\
++ -c $in -o $out
++
++rule cxx
++ depfile = $out.d
++ description = CXX $out
++ command = $cxx -MMD -MF $out.d $cflags $cflags_cxx $defines $includes \\
++ -c $in -o $out
++
++rule alink
++ description = AR $out
++ command = rm -f $out && ar rcs $out $in
++
++rule solink
++ description = LINK $out
++ command = g++ -shared $ldflags -o $out -Wl,-soname=$soname \\
++ -Wl,--start-group $in -Wl,--end-group $libs
++
++rule link
++ description = LINK $out
++ command = g++ $ldflags -o $out -Wl,-rpath=@lib \\
++ -Wl,--start-group $in -Wl,--end-group $libs
++
++rule stamp
++ description = STAMP $out
++ command = touch $out
++
++rule copy
++ description = COPY $out
++ command = ln $in $out
++
++""" % {
++ 'cwd': os.getcwd(),
++}
++
++def QuoteShellArgument(arg):
++ assert "'" not in arg
++ return "'" + arg + "'"
++
++def MaybeQuoteShellArgument(arg):
++ if '"' in arg or ' ' in arg:
++ return QuoteShellArgument(arg)
++ return arg
++
++def FixBuildDirPath(path):
++ """gyp doesn't know about our "@foo" syntax, and prepends paths to it."""
++ ofs = path.find('@')
++ if ofs > 0:
++ return path[ofs:]
++ return path
++
++class NinjaWriter:
++ def __init__(self, linkable_outputs, order_only_outputs, base_dir, path):
++ self.linkable_outputs = linkable_outputs
++ self.order_only_outputs = order_only_outputs
++ self.base_dir = base_dir
++ self.path = path
++ self.file = open(path, 'w')
++ self.variables = {} # XXX take in global values.
++
++ def InputPath(self, path):
++ if path.startswith('@'):
++ return path
++ return os.path.normpath(os.path.join(self.base_dir, path))
++
++ def OutputPath(self, path):
++ if path.startswith('@'):
++ return path
++ return '@' + os.path.normpath(os.path.join('obj', self.name, self.base_dir, path))
++
++ def StampPath(self, name):
++ return '@' + os.path.join('obj', self.name, name + '.stamp')
++
++ def WriteSpec(self, spec, config):
++ self.name = spec['target_name'] # XXX remove bad chars
++
++ if spec['type'] == 'settings':
++ return
++
++ # Compute predepends for all rules.
++ prebuild_deps = []
++ # self.prebuild_stamp is the filename that all our files depend upon,
++ # if any.
++ self.prebuild_stamp = None
++ if 'dependencies' in spec:
++ for d in spec['dependencies']:
++ dep = self.linkable_outputs.get(d)
++ if dep:
++ prebuild_deps.append(dep)
++ dep = self.order_only_outputs.get(d)
++ if dep:
++ prebuild_deps.append(dep)
++ if prebuild_deps:
++ self.prebuild_stamp = self.StampPath('predepends')
++ self.WriteEdge([self.prebuild_stamp], 'stamp', prebuild_deps,
++ use_prebuild_stamp=False)
++ self.WriteLn()
++
++ sources_predepends = []
++ extra_sources = []
++ if 'actions' in spec:
++ sources_predepends.append(
++ self.WriteActions(spec['actions'], extra_sources))
++
++ if 'rules' in spec:
++ sources_predepends.append(
++ self.WriteRules(spec['rules'], extra_sources))
++
++ if 'copies' in spec:
++ sources_predepends.append(
++ self.WriteCopies(spec['copies']))
++
++ link_deps = []
++ sources = spec.get('sources', []) + extra_sources
++ if sources:
++ link_deps = self.WriteSources(config, sources, sources_predepends)
++
++ return self.WriteTarget(spec, config, link_deps or sources_predepends)
++
++ def WriteActions(self, actions, extra_sources):
++ all_outputs = []
++ for action in actions:
++ # First write out a rule for the action.
++ # XXX we shouldn't need to qualify names; we do it because currently
++ # the rule namespace is global, but it really should be scoped to the
++ # subninja.
++ name = self.name + '.' + action['action_name'].replace(' ', '_')
++ command = gyp.common.EncodePOSIXShellList(action['action'])
++ if self.base_dir:
++ command = 'cd %s; %s' % (self.base_dir, command)
++ self.WriteRule(name=name, command=command,
++ description=action.get('message', None))
++
++ inputs = [self.InputPath(i) for i in action['inputs']]
++ if int(action.get('process_outputs_as_sources', False)):
++ extra_sources += action['outputs']
++ outputs = [self.OutputPath(o) for o in action['outputs']]
++
++ # Then write out an edge using the rule.
++ self.WriteEdge(outputs, name, inputs)
++ all_outputs += outputs
++
++ # And a phony edge to run the action by name.
++ self.WriteEdge([name], 'phony', outputs, use_prebuild_stamp=False)
++
++ self.WriteLn()
++
++ # Write out a stamp file for all the actions.
++ stamp = self.StampPath('actions')
++ self.WriteEdge([stamp], 'stamp', all_outputs)
++ return stamp
++
++ def WriteRules(self, rules, extra_sources):
++ all_outputs = []
++ for rule in rules:
++ # First write out a rule for the rule action.
++ # XXX we shouldn't need to qualify names; we do it because currently
++ # the rule namespace is global, but it really should be scoped to the
++ # subninja.
++ self.WriteLn('# rule: ' + repr(rule))
++ name = self.name + '.' + rule['rule_name'].replace(' ', '_')
++ action = rule['action']
++ command = gyp.common.EncodePOSIXShellList(action)
++ if self.base_dir:
++ command = 'cd %s; %s' % (self.base_dir, command)
++ # XXX do rules have a short name?
++ description = '%s: %s' % (self.name, rule['rule_name'])
++ self.WriteRule(name=name, command=command, description=description)
++ self.WriteLn()
++
++ # TODO: if the command references the outputs directly, we should
++ # simplify it to just use $out.
++
++ # Compute which edge-scoped variables all build rules will need
++ # to provide.
++ special_locals = ('source', 'root', 'ext')
++ needed_variables = set()
++ for argument in action:
++ for var in special_locals:
++ if '$' + var in argument:
++ needed_variables.add(var)
++
++ # For each source file, write an edge that generates all the outputs.
++ for source in rule.get('rule_sources', []):
++ basename = os.path.basename(source)
++ root, ext = os.path.splitext(basename)
++
++ outputs = []
++ for output in rule['outputs']:
++ outputs.append(output.replace('$root', root))
++
++ extra_bindings = []
++ for var in needed_variables:
++ if var == 'root':
++ extra_bindings.append(('root', root))
++ elif var == 'source':
++ extra_bindings.append(('source', source))
++ elif var == 'ext':
++ extra_bindings.append(('ext', ext))
++ else:
++ assert var == None, var # XXX Not yet implemented.
++ # XXX need to add extra dependencies on rule inputs
++ # (e.g. if generator program changes, we need to rerun)
++ self.WriteEdge(outputs, name, [self.InputPath(source)],
++ extra_bindings=extra_bindings)
++
++ if int(rule.get('process_outputs_as_sources', False)):
++ extra_sources += outputs
++
++ all_outputs.extend(outputs)
++
++ # Write out a stamp file for all the actions.
++ stamp = self.StampPath('rules')
++ self.WriteEdge([stamp], 'stamp', all_outputs)
++ self.WriteLn()
++ return stamp
++
++ def WriteCopies(self, copies):
++ outputs = []
++ for copy in copies:
++ for path in copy['files']:
++ filename = os.path.split(path)[1]
++ src = self.InputPath(path)
++ dst = self.OutputPath(os.path.join(copy['destination'], filename))
++ self.WriteEdge([dst], 'copy', [src])
++ outputs.append(dst)
++
++ stamp = self.StampPath('copies')
++ self.WriteEdge([stamp], 'stamp', outputs)
++ self.WriteLn()
++ return stamp
++
++ def WriteSources(self, config, sources, predepends):
++ self.WriteVariableList('defines', ['-D' + d for d in config.get('defines', [])],
++ quoter=MaybeQuoteShellArgument)
++ includes = [FixBuildDirPath(self.InputPath(i))
++ for i in config.get('include_dirs', [])]
++ self.WriteVariableList('includes', ['-I' + i for i in includes])
++ self.WriteVariableList('cflags', config.get('cflags'))
++ self.WriteVariableList('cflags_cc', config.get('cflags_c'))
++ self.WriteVariableList('cflags_cxx', config.get('cflags_cc'))
++ self.WriteLn()
++ outputs = []
++ for source in sources:
++ filename, ext = os.path.splitext(source)
++ ext = ext[1:]
++ if ext in ('cc', 'cpp', 'cxx'):
++ command = 'cxx'
++ elif ext in ('c', 's', 'S'):
++ command = 'cc'
++ else:
++ # if ext in ('h', 'hxx'):
++ # elif ext in ('re', 'gperf', 'grd', ):
++ continue
++ input = self.InputPath(source)
++ output = self.OutputPath(filename + '.o')
++ self.WriteEdge([output], command, [input], predepends)
++ outputs.append(output)
++ self.WriteLn()
++ return outputs
++
++ def WriteTarget(self, spec, config, link_deps):
++ # XXX only write these for rules that will use them
++ self.WriteVariableList('ldflags', config.get('ldflags'))
++ self.WriteVariableList('libs', spec.get('libraries'))
++
++ output = self.ComputeOutput(spec)
++ if 'dependencies' in spec:
++ for dep in spec['dependencies']:
++ dep = self.linkable_outputs.get(dep)
++ if dep:
++ link_deps.append(dep)
++ command_map = {
++ 'executable': 'link',
++ 'static_library': 'alink',
++ 'loadable_module': 'solink',
++ 'shared_library': 'solink',
++ 'none': 'stamp',
++ }
++ command = command_map[spec['type']]
++ extra_bindings = []
++ if command == 'solink':
++ extra_bindings.append(('soname', os.path.split(output)[1]))
++ self.WriteEdge([output], command, link_deps,
++ extra_bindings=extra_bindings,
++ use_prebuild_stamp=False)
++
++ if spec['type'] == 'executable':
++ self.WriteEdge([self.ComputeOutputFileName(spec)], 'phony', [output],
++ use_prebuild_stamp=False)
++ return output
++
++ def ComputeOutputFileName(self, spec):
++ target = spec['target_name']
++
++ # Snip out an extra 'lib' if appropriate.
++ if '_library' in spec['type'] and target[:3] == 'lib':
++ target = target[3:]
++
++ if spec['type'] == 'static_library':
++ return 'lib%s.a' % target
++ elif spec['type'] in ('loadable_module', 'shared_library'):
++ return 'lib%s.so' % target
++ elif spec['type'] == 'none':
++ return '%s.stamp' % target
++ elif spec['type'] == 'settings':
++ return None
++ elif spec['type'] == 'executable':
++ return spec.get('product_name', target)
++ else:
++ raise 'Unhandled output type', spec['type']
++
++ def ComputeOutput(self, spec):
++ filename = self.ComputeOutputFileName(spec)
++
++ # Executables and loadable modules go into the output root.
++ if spec['type'] in ('executable', 'loadable_module'):
++ path = ''
++ elif spec['type'] == 'shared_library':
++ path = 'lib'
++ else:
++ # Everything else goes into our per-target dir.
++ path = self.base_dir
++
++ # XXX what are all these extra variables?
++ path = spec.get('product_dir', path)
++ assert 'product_prefix' not in spec
++ if 'product_name' in spec:
++ print 'XXX ignoring product_name'
++ assert 'product_extension' not in spec
++ #target_prefix = spec.get('product_prefix', target_prefix)
++ #target = spec.get('product_name', target)
++ #product_ext = spec.get('product_extension')
++
++ return '@' + os.path.join(path, filename)
++
++ def WriteRule(self, name, command, description=None):
++ self.WriteLn('rule %s' % name)
++ self.WriteLn(' command = %s' % command)
++ if description:
++ self.WriteLn(' description = %s' % description)
++
++ def WriteEdge(self, outputs, command, inputs,
++ order_only_inputs=[],
++ use_prebuild_stamp=True,
++ extra_bindings=[]):
++ extra_inputs = order_only_inputs[:]
++ if use_prebuild_stamp and self.prebuild_stamp:
++ extra_inputs.append(self.prebuild_stamp)
++ if extra_inputs:
++ extra_inputs = ['|'] + extra_inputs
++ self.WriteList('build ' + ' '.join(outputs) + ': ' + command,
++ inputs + extra_inputs)
++ if extra_bindings:
++ for key, val in extra_bindings:
++ self.WriteLn(' %s = %s' % (key, val))
++
++ def WriteVariableList(self, var, values, quoter=lambda x: x):
++ if self.variables.get(var, []) == values:
++ return
++ self.variables[var] = values
++ self.WriteList(var + ' =', values, quoter=quoter)
++
++ def WriteList(self, decl, values, quoter=lambda x: x):
++ self.Write(decl)
++ if not values:
++ self.WriteLn()
++ return
++
++ col = len(decl) + 3
++ for value in values:
++ value = quoter(value)
++ if col != 0 and col + len(value) >= 78:
++ self.WriteLn(' \\')
++ self.Write(' ' * 4)
++ col = 4
++ else:
++ self.Write(' ')
++ col += 1
++ self.Write(value)
++ col += len(value)
++ self.WriteLn()
++
++ def Write(self, *args):
++ self.file.write(' '.join(args))
++
++ def WriteLn(self, *args):
++ self.file.write(' '.join(args) + '\n')
++
++
++def tput(str):
++ return subprocess.Popen(['tput',str], stdout=subprocess.PIPE).communicate()[0]
++tput_clear = tput('el1')
++import time
++def OverPrint(*args):
++ #sys.stdout.write(tput_clear + '\r' + ' '.join(args))
++ sys.stdout.write(' '.join(args) + '\n')
++ sys.stdout.flush()
++ #time.sleep(0.01) # XXX
++
++def GenerateOutput(target_list, target_dicts, data, params):
++ options = params['options']
++ generator_flags = params.get('generator_flags', {})
++ builddir_name = generator_flags.get('output_dir', 'ninja')
++
++ src_root = options.depth
++ config_name = 'Default'
++ master_ninja = open(os.path.join(src_root, 'build.ninja'), 'w')
++ master_ninja.write(NINJA_BASE)
++
++ all_targets = set()
++ for build_file in params['build_files']:
++ for target in gyp.common.AllTargets(target_list, target_dicts, build_file):
++ all_targets.add(target)
++ all_outputs = set()
++
++ subninjas = set()
++ linkable_outputs = {}
++ order_only_outputs = {}
++ for qualified_target in target_list:
++ # qualified_target is like: third_party/icu/icu.gyp:icui18n#target
++ #OverPrint(qualified_target)
++ build_file, target, _ = gyp.common.ParseQualifiedTarget(qualified_target)
++
++ build_file = gyp.common.RelativePath(build_file, src_root)
++ base_path = os.path.dirname(build_file)
++ ninja_path = os.path.join(base_path, target + '.ninja')
++ output_file = os.path.join(src_root, ninja_path)
++ spec = target_dicts[qualified_target]
++ if config_name not in spec['configurations']:
++ config_name = spec['default_configuration']
++ config = spec['configurations'][config_name]
++
++ writer = NinjaWriter(linkable_outputs, order_only_outputs,
++ base_path, output_file)
++ subninjas.add(ninja_path)
++
++ output = writer.WriteSpec(spec, config)
++ if 'library' in spec['type']:
++ linkable_outputs[qualified_target] = output
++ else:
++ order_only_outputs[qualified_target] = output
++
++ if qualified_target in all_targets:
++ all_outputs.add(output)
++
++ for ninja in subninjas:
++ print >>master_ninja, 'subninja', ninja
++
++ if all_outputs:
++ print >>master_ninja, 'build all: phony |' + ' '.join(all_outputs)
++
++ master_ninja.close()
++ OverPrint('done.\n')
diff --git a/misc/ninja-mode.el b/misc/ninja-mode.el
new file mode 100644
index 0000000..ddbcfd8
--- /dev/null
+++ b/misc/ninja-mode.el
@@ -0,0 +1,10 @@
+;; Simple emacs mode for editing .ninja files.
+;; Just some syntax highlighting for now.
+
+(setq ninja-keywords
+ '(("^\\<rule\\>\\|^\\<build\\>\\|^\\<subninja\\>" . font-lock-keyword-face)
+ ("\\([[:alnum:]_]+\\) =" . (1 font-lock-variable-name-face))
+ ))
+(define-derived-mode ninja-mode fundamental-mode "ninja"
+ (setq font-lock-defaults '(ninja-keywords))
+ )