diff options
-rw-r--r-- | build.py | 37 | ||||
-rwxr-xr-x | builder.py | 20 | ||||
-rwxr-xr-x | interpreter.py | 37 | ||||
-rwxr-xr-x | shellgenerator.py | 21 |
4 files changed, 70 insertions, 45 deletions
diff --git a/build.py b/build.py new file mode 100644 index 0000000..61a51f4 --- /dev/null +++ b/build.py @@ -0,0 +1,37 @@ +#!/usr/bin/python3 -tt + +# Copyright 2012 Jussi Pakkanen + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +class Build: + """A class that holds the status of one build including + all dependencies and so on. + """ + + def __init__(self, environment): + self.environment = environment + self.project = None + self.targets = {} + self.compilers = [] + self.tests = [] + self.static_linker = self.environment.detect_static_linker() + + def get_project(self): + return self.project + + def get_targets(self): + return self.targets + + def get_tests(self): + return self.tests @@ -18,7 +18,7 @@ from optparse import OptionParser import sys, stat import os.path import environment, interpreter -import shellgenerator +import shellgenerator, build parser = OptionParser() @@ -27,7 +27,7 @@ parser.add_option('--libdir', default='lib', dest='libdir') parser.add_option('--includedir', default='include', dest='includedir') parser.add_option('--datadir', default='share', dest='datadir') -class Builder(): +class BuilderApp(): builder_filename = 'builder.txt' def __init__(self, dir1, dir2, options): @@ -35,7 +35,7 @@ class Builder(): self.options = options def has_builder_file(self, dirname): - fname = os.path.join(dirname, Builder.builder_filename) + fname = os.path.join(dirname, BuilderApp.builder_filename) try: ifile = open(fname, 'r') ifile.close() @@ -55,20 +55,22 @@ class Builder(): raise RuntimeError('Source and build directories must not be the same. Create a pristine build directory.') if self.has_builder_file(ndir1): if self.has_builder_file(ndir2): - raise RuntimeError('Both directories contain a builder file %s.' % Builder.builder_filename) + raise RuntimeError('Both directories contain a builder file %s.' % BuilderApp.builder_filename) return (ndir1, ndir2) if self.has_builder_file(ndir2): return (ndir2, ndir1) - raise RuntimeError('Neither directory contains a builder file %s.' % Builder.builder_filename) + raise RuntimeError('Neither directory contains a builder file %s.' % BuilderApp.builder_filename) def generate(self): - code = open(os.path.join(self.source_dir, Builder.builder_filename)).read() + code = open(os.path.join(self.source_dir, BuilderApp.builder_filename)).read() if len(code.strip()) == 0: raise interpreter.InvalidCode('Builder file is empty.') assert(isinstance(code, str)) env = environment.Environment(self.source_dir, self.build_dir) - intr = interpreter.Interpreter(code, env) - g = shellgenerator.ShellGenerator(intr, env) + b = build.Build(env) + intr = interpreter.Interpreter(code, b) + intr.run() + g = shellgenerator.ShellGenerator(b) g.generate() if __name__ == '__main__': @@ -81,7 +83,7 @@ if __name__ == '__main__': dir2 = args[2] else: dir2 = '.' - builder = Builder(dir1, dir2, options) + builder = BuilderApp(dir1, dir2, options) print ('Source dir: ' + builder.source_dir) print ('Build dir: ' + builder.build_dir) builder.generate() diff --git a/interpreter.py b/interpreter.py index 9d3aa78..85993fd 100755 --- a/interpreter.py +++ b/interpreter.py @@ -116,17 +116,13 @@ class Test(InterpreterObject): class Interpreter(): - def __init__(self, code, environment): + def __init__(self, code, build): + self.build = build self.ast = parser.build_ast(code) self.sanity_check_ast() - self.project = None - self.compilers = [] - self.targets = {} self.variables = {} - self.environment = environment - self.static_linker = self.environment.detect_static_linker() + self.environment = build.environment self.build_func_dict() - self.tests = [] def build_func_dict(self): self.funcs = {'project' : self.func_project, @@ -139,15 +135,6 @@ class Interpreter(): 'add_test' : self.func_add_test } - def get_project(self): - return self.project - - def get_targets(self): - return self.targets - - def get_tests(self): - return self.tests - def sanity_check_ast(self): if not isinstance(self.ast, nodes.CodeBlock): raise InvalidCode('AST is of invalid type. Possibly a bug in the parser.') @@ -189,10 +176,10 @@ class Interpreter(): def func_project(self, node, args): self.validate_arguments(args, 1, [str]) - if self.project is not None: + if self.build.project is not None: raise InvalidCode('Second call to project() on line %d.' % node.lineno()) - self.project = args[0] - print('Project name is "%s".' % self.project) + self.build.project = args[0] + print('Project name is "%s".' % self.build.project) def func_message(self, node, args): self.validate_arguments(args, 1, [str]) @@ -204,17 +191,17 @@ class Interpreter(): for a in args: if not isinstance(a, str): raise InvalidArguments('Line %d: Argument %s is not a string.' % (node.lineno(), str(a))) - if len(self.compilers) > 0: + if len(self.build.compilers) > 0: raise InvalidCode('Function language() can only be called once (line %d).' % node.lineno()) for lang in args: if lang.lower() == 'c': comp = self.environment.detect_c_compiler() comp.sanity_check(self.environment.get_scratch_dir()) - self.compilers.append(comp) + self.build.compilers.append(comp) elif lang.lower() == 'c++': comp = self.environment.detect_cxx_compiler() comp.sanity_check(self.environment.get_scratch_dir()) - self.compilers.append(comp) + self.build.compilers.append(comp) else: raise InvalidCode('Tried to use unknown language "%s".' % lang) @@ -236,7 +223,7 @@ class Interpreter(): def func_add_test(self, node, args): self.validate_arguments(args, 2, [str, Executable]) t = Test(args[0], args[1]) - self.tests.append(t) + self.build.tests.append(t) print('Adding test "%s"' % args[0]) def build_target(self, node, args, targetclass): @@ -245,10 +232,10 @@ class Interpreter(): raise InvalidArguments('Line %d: Argument %s is not a string.' % (node.lineno(), str(a))) name= args[0] sources = args[1:] - if name in self.targets: + if name in self.build.targets: raise InvalidCode('Line %d: tried to create target "%s", but a target of that name already exists.' % (node.lineno(), name)) l = targetclass(name, sources, self.environment) - self.targets[name] = l + self.build.targets[name] = l print('Creating build target "%s" with %d files.' % (name, len(sources))) return l diff --git a/shellgenerator.py b/shellgenerator.py index 009ac7c..e493354 100755 --- a/shellgenerator.py +++ b/shellgenerator.py @@ -22,15 +22,14 @@ def shell_quote(cmdlist): class ShellGenerator(): - def __init__(self, interpreter, environment): - self.environment = environment - self.interpreter = interpreter + def __init__(self, build): + self.build = build + self.environment = build.environment self.build_filename = 'compile.sh' self.test_filename = 'run_tests.sh' self.processed_targets = {} def generate(self): - self.interpreter.run() self.generate_compile_script() self.generate_test_script() @@ -39,7 +38,7 @@ class ShellGenerator(): outfile = open(outfilename, 'w') outfile.write('#!/bin/sh\n\n') outfile.write('echo This is an autogenerated shell script build file for project \\"%s\\".\n' - % self.interpreter.get_project()) + % self.build.get_project()) outfile.write('echo This is experimental and most likely will not work!\n') cdcmd = ['cd', self.environment.get_build_dir()] outfile.write(' '.join(shell_quote(cdcmd)) + '\n') @@ -53,7 +52,7 @@ class ShellGenerator(): outfile = open(outfilename, 'w') outfile.write('#!/bin/sh\n\n') outfile.write('echo This is an autogenerated shell script test file for project \\"%s\\".\n' - % self.interpreter.get_project()) + % self.build.get_project()) outfile.write('echo Run the compile script before this one or bad things will happen!\n') cdcmd = ['cd', self.environment.get_build_dir()] outfile.write(' '.join(shell_quote(cdcmd)) + '\n') @@ -63,7 +62,7 @@ class ShellGenerator(): stat.S_IRGRP | stat.S_IXGRP | stat.S_IROTH | stat.S_IXOTH) def generate_tests(self, outfile): - for t in self.interpreter.get_tests(): + for t in self.build.get_tests(): cmds = [] cmds.append(self.get_target_filename(t.get_exe())) outfile.write('echo Running test \\"%s\\".\n' % t.get_name()) @@ -71,7 +70,7 @@ class ShellGenerator(): def generate_single_compile(self, target, outfile, src): compiler = None - for i in self.interpreter.compilers: + for i in self.build.compilers: if i.can_compile(src): compiler = i break @@ -108,9 +107,9 @@ class ShellGenerator(): def generate_link(self, target, outfile, outname, obj_list): if isinstance(target, interpreter.StaticLibrary): - linker = self.interpreter.static_linker + linker = self.build.static_linker else: - linker = self.interpreter.compilers[0] # Fixme. + linker = self.build.compilers[0] # Fixme. commands = [] commands += linker.get_exelist() if isinstance(target, interpreter.Executable): @@ -138,7 +137,7 @@ class ShellGenerator(): return dirname def generate_commands(self, outfile): - for i in self.interpreter.get_targets().items(): + for i in self.build.get_targets().items(): target = i[1] self.generate_target(target, outfile) |