#! /usr/bin/env python # encoding: utf-8 # Thomas Nagy, 2005 (ita) # genobj is an abstract class for declaring targets: # * creates tasks (consisting of a task, an environment, a list of source and list of target) # * sets environment on the tasks (which are copies most of the time) # * modifies environments as needed # # genobj cannot be used as it is, so you must create a subclass # # subclassing # * makes it possible to share environment copies for several objects at once (efficiency) # * be careful to call Object.genobj.__init__(...) in the init of your subclass # # composition # * makes it possible to declare new kind of targets quickly (give a pattern ? and the action name) # * is not really flexible, but lightweight # * cf cppobj for more details on this scheme import os, shutil, types import Action, Params, Environment, Runner, Task, Common from Params import debug, error, trace, fatal g_allobjs=[] # call flush for every group of object to process def flush(): bld = Params.g_build trace("delayed operation called") while len(bld.m_outstanding_objs)>0: trace("posting object") obj=bld.m_outstanding_objs.pop() obj.post() # TODO useless bld.m_posted_objs.append(obj) trace("object posted") class genobj: def __init__(self, type): self.m_type = type self.m_posted = 0 self.m_current_path = Params.g_build.m_curdirnode # emulate chdir when reading scripts self.name = '' # give a name to the target # TODO if we are building something, we need to make sure the folder is scanned #if not Params.g_build.m_curdirnode in Params... # targets / sources self.source = '' self.target = '' # we use a simple list for the tasks TODO not used ? self.m_tasks = [] # no default environment - in case if self.env = None # register ourselves - used at install time g_allobjs.append(self) # allow delayed operations on objects created (declarative style) # an object is then posted when another one is added # of course, you may want to post the object yourself first :) #flush() Params.g_build.m_outstanding_objs.append(self) if not type in self.get_valid_types(): error("BUG genobj::init : invalid type given") def get_valid_types(self): return ['program', 'shlib', 'staticlib', 'other'] # runs the code to create the tasks def post(self): if not self.env: self.env = Params.g_build.m_allenvs['default'] if self.m_posted: error("OBJECT ALREADY POSTED") return self.apply() self.m_posted=1 # probably important ? def to_real_file(self, file): # append the builddir to the file name, calls object to .. :) pass # the following function is used to modify the environments of the tasks def setForAll(self, var, val): for task in self.m_tasks: task.setvar(var, val) # the following function is used to modify the environments of the tasks def prependAll(self, var, val): for task in self.m_tasks: task.prependvar(var, val) # the following function is used to modify the environments of the tasks def appendAll(self, var, val): for task in self.m_tasks: task.appendvar(var, val) # the lower the nice is, the higher priority tasks will run at # groups are sorted like this [2, 4, 5, 100, 200] # the tasks with lower nice will run first # if tasks have an odd priority number, they will be run only sequentially # if tasks have an even priority number, they will be allowed to be run in parallel def create_task(self, type, env, nice=10): task = Task.Task(type, env, nice) self.m_tasks.append(task) return task # creates the tasks, override this method def apply(self): # subclass me trace("nothing to do") def get_mirror_node(self, node, filename): tree=Params.g_build.m_tree return tree.mirror_file(node, filename) def file_in(self, filename): return [ self.get_mirror_node(self.m_current_path, filename) ] # an object is to be posted, even if only for install # the install function is called for uninstalling too def install(self): # subclass me pass def install_results(self, var, subdir, task): trace('install results called') current = Params.g_build.m_curdirnode # TODO what is the pythonic replacement for these three lines ? lst = [] for node in task.m_outputs: lst.append( node.relpath_gen(current) ) Common.install_files(var, subdir, lst) # ['CXX', ..] -> [env['CXX'], ..] def list_to_env_list(env, vars_list): def get_env_value(var): # TODO add a cache here ? #return env[var] try: v = env[var] if type(v) is types.ListType: return " ".join(v) else: return v except: debug("variable %s does not exist in env !" % var) return '' return map(get_env_value, vars_list) def sign_env_vars(env, vars_list): #lst = list_to_env_list(env, vars_list) #val = reduce( lambda a,b : Params.h_string(b)+Params.h_string(a), lst ) #return val lst = list_to_env_list(env, vars_list) return Params.h_list(lst) def reset(): g_allobjs=[] # The main functor # build objects without having to add tons of import statements g_allclasses = {} def createObj(objname, *k, **kw): try: return g_allclasses[objname](*k, **kw) except: print "error in createObj", objname raise def register(name, classval): global g_allclasses if name in g_allclasses: trace('class exists in g_allclasses '+name) return g_allclasses[name] = classval