Extracted build data to its own class.
This commit is contained in:
parent
36e2b0cd37
commit
c71f82432f
|
@ -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
|
20
builder.py
20
builder.py
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
Loading…
Reference in New Issue