diff options
author | ancarola <raffaele.ancarola@epfl.ch> | 2019-01-27 01:16:41 +0100 |
---|---|---|
committer | ancarola <raffaele.ancarola@epfl.ch> | 2019-01-27 01:16:41 +0100 |
commit | 3a805a030a0c2a6eb8e2f823f3aaac049556c933 (patch) | |
tree | cc92905ad5aa5ff0e2855390c8c4356ad3832918 | |
parent | Small fix T& -> T* (diff) | |
parent | Add g++ flag to use gold instead of ld for faster linkage (diff) | |
download | flatland-3a805a030a0c2a6eb8e2f823f3aaac049556c933.tar.gz flatland-3a805a030a0c2a6eb8e2f823f3aaac049556c933.zip |
Merge remote-tracking branch 'nao/master'
Configure
-rw-r--r-- | .gitignore | 3 | ||||
-rwxr-xr-x | configure.py | 32 | ||||
-rw-r--r-- | ninja/ninja_syntax.py | 183 | ||||
-rw-r--r-- | ninja/rules.ninja | 2 |
4 files changed, 216 insertions, 4 deletions
@@ -8,6 +8,9 @@ build .ninja_log build.ninja +# ctag files +tags + # vim editor **/*.swp diff --git a/configure.py b/configure.py index d313554..14c45cd 100755 --- a/configure.py +++ b/configure.py @@ -30,8 +30,27 @@ def find_sources(path): return sources, objects -def add_test(bf, test_source, tested_sources): - print("adding test {}".format(test_source) + " to test {}".format(tested_sources)) + +def add_test(bf, test_source, library): + print("adding test {}".format(test_source)) + + # replace extension + test_object = re.sub(".cpp$", ".o", test_source) + test_binary = re.sub(".o$", "", test_object) + + # add path prefix + test_source = "test/" + test_source + test_object = "build/test/" + test_object + test_binary = "build/test/" + test_binary + + print("build {}: cpp {}".format(test_object, test_source), file=bf) + print("build {}: link {}".format(test_binary, test_object), file=bf) + print(" lflags = $lflags {}".format(library), file=bf) + print("\n", file=bf) + + +def add_specific_test(bf, test_source, tested_sources): + print("adding specific test {}".format(test_source) + " to test {}".format(tested_sources)) # replace extension test_object = re.sub(".cpp$", ".o", test_source) @@ -87,4 +106,11 @@ with open("build.ninja", "w") as bf: print("\n", file=bf) # add tests - add_test(bf, "task_test.cpp", ["engine/task.cpp"]) + add_specific_test(bf, "task_test.cpp", ["engine/task.cpp"]) + add_test(bf, "signal_test.cpp", "build/libflatland.so") + + print("default build/test/signal_test", file=bf) + +# run ctags for vim :) +os.system("if type ctags; then ctags -R . ; fi") + diff --git a/ninja/ninja_syntax.py b/ninja/ninja_syntax.py new file mode 100644 index 0000000..051bac1 --- /dev/null +++ b/ninja/ninja_syntax.py @@ -0,0 +1,183 @@ +#!/usr/bin/python + +"""Python module for generating .ninja files. + +Note that this is emphatically not a required piece of Ninja; it's +just a helpful utility for build-file-generation systems that already +use Python. +""" + +import re +import textwrap + +def escape_path(word): + return word.replace('$ ', '$$ ').replace(' ', '$ ').replace(':', '$:') + +class Writer(object): + def __init__(self, output, width=78): + self.output = output + self.width = width + + def newline(self): + self.output.write('\n') + + def comment(self, text, has_path=False): + for line in textwrap.wrap(text, self.width - 2, break_long_words=False, + break_on_hyphens=False): + self.output.write('# ' + line + '\n') + + def variable(self, key, value, indent=0): + if value is None: + return + if isinstance(value, list): + value = ' '.join(filter(None, value)) # Filter out empty strings. + self._line('%s = %s' % (key, value), indent) + + def pool(self, name, depth): + self._line('pool %s' % name) + self.variable('depth', depth, indent=1) + + def rule(self, name, command, description=None, depfile=None, + generator=False, pool=None, restat=False, rspfile=None, + rspfile_content=None, deps=None): + self._line('rule %s' % name) + self.variable('command', command, indent=1) + if description: + self.variable('description', description, indent=1) + if depfile: + self.variable('depfile', depfile, indent=1) + if generator: + self.variable('generator', '1', indent=1) + if pool: + self.variable('pool', pool, indent=1) + if restat: + self.variable('restat', '1', indent=1) + if rspfile: + self.variable('rspfile', rspfile, indent=1) + if rspfile_content: + self.variable('rspfile_content', rspfile_content, indent=1) + if deps: + self.variable('deps', deps, indent=1) + + def build(self, outputs, rule, inputs=None, implicit=None, order_only=None, + variables=None, implicit_outputs=None, pool=None): + outputs = as_list(outputs) + out_outputs = [escape_path(x) for x in outputs] + all_inputs = [escape_path(x) for x in as_list(inputs)] + + if implicit: + implicit = [escape_path(x) for x in as_list(implicit)] + all_inputs.append('|') + all_inputs.extend(implicit) + if order_only: + order_only = [escape_path(x) for x in as_list(order_only)] + all_inputs.append('||') + all_inputs.extend(order_only) + if implicit_outputs: + implicit_outputs = [escape_path(x) + for x in as_list(implicit_outputs)] + out_outputs.append('|') + out_outputs.extend(implicit_outputs) + + self._line('build %s: %s' % (' '.join(out_outputs), + ' '.join([rule] + all_inputs))) + if pool is not None: + self._line(' pool = %s' % pool) + + if variables: + if isinstance(variables, dict): + iterator = iter(variables.items()) + else: + iterator = iter(variables) + + for key, val in iterator: + self.variable(key, val, indent=1) + + return outputs + + def include(self, path): + self._line('include %s' % path) + + def subninja(self, path): + self._line('subninja %s' % path) + + def default(self, paths): + self._line('default %s' % ' '.join(as_list(paths))) + + def _count_dollars_before_index(self, s, i): + """Returns the number of '$' characters right in front of s[i].""" + dollar_count = 0 + dollar_index = i - 1 + while dollar_index > 0 and s[dollar_index] == '$': + dollar_count += 1 + dollar_index -= 1 + return dollar_count + + def _line(self, text, indent=0): + """Write 'text' word-wrapped at self.width characters.""" + leading_space = ' ' * indent + while len(leading_space) + len(text) > self.width: + # The text is too wide; wrap if possible. + + # Find the rightmost space that would obey our width constraint and + # that's not an escaped space. + available_space = self.width - len(leading_space) - len(' $') + space = available_space + while True: + space = text.rfind(' ', 0, space) + if (space < 0 or + self._count_dollars_before_index(text, space) % 2 == 0): + break + + if space < 0: + # No such space; just use the first unescaped space we can find. + space = available_space - 1 + while True: + space = text.find(' ', space + 1) + if (space < 0 or + self._count_dollars_before_index(text, space) % 2 == 0): + break + if space < 0: + # Give up on breaking. + break + + self.output.write(leading_space + text[0:space] + ' $\n') + text = text[space+1:] + + # Subsequent lines are continuations, so indent them. + leading_space = ' ' * (indent+2) + + self.output.write(leading_space + text + '\n') + + def close(self): + self.output.close() + + +def as_list(input): + if input is None: + return [] + if isinstance(input, list): + return input + return [input] + + +def escape(string): + """Escape a string such that it can be embedded into a Ninja file without + further interpretation.""" + assert '\n' not in string, 'Ninja syntax does not allow newlines' + # We only have one special metacharacter: '$'. + return string.replace('$', '$$') + + +def expand(string, vars, local_vars={}): + """Expand a string containing $vars as Ninja would. + + Note: doesn't handle the full Ninja variable syntax, but it's enough + to make configure.py's use of it work. + """ + def exp(m): + var = m.group(1) + if var == '$': + return '$' + return local_vars.get(var, vars.get(var, '')) + return re.sub(r'\$(\$|\w*)', exp, string) diff --git a/ninja/rules.ninja b/ninja/rules.ninja index a2f3b56..7ab5e46 100644 --- a/ninja/rules.ninja +++ b/ninja/rules.ninja @@ -9,7 +9,7 @@ cflags = $cflags -Wconversion libs = -lSDL2 #lib/libmm/build/libmm.a lib/libwsdl2/build/libwsdl2.a -lflags = $libs +lflags = $libs -fuse-ld=gold flags = -fdiagnostics-color |