This is a massive upgrade removing almost all pre-waf 1.6 script code. In addition, this does away with custom pkgconfig.py script for making .pc files and replaces it with waf's builtin mechanism. Massive thanks to Alex Afanasyev for ideas and bugfixing, to Alina Quereilhac for bugfixing and testing, and to Tom Henderson for thorough testing.
414 lines
11 KiB
Python
414 lines
11 KiB
Python
#!/usr/bin/env python
|
|
# encoding: utf-8
|
|
# Thomas Nagy, 2006-2010 (ita)
|
|
|
|
"""
|
|
This tool is totally deprecated
|
|
|
|
Try using:
|
|
.pc.in files for .pc files
|
|
the feature intltool_in - see demos/intltool
|
|
make-like rules
|
|
"""
|
|
|
|
import shutil, re, os
|
|
from waflib import TaskGen, Node, Task, Utils, Build, Errors
|
|
from waflib.TaskGen import feature, after_method, before_method
|
|
from waflib.Logs import debug
|
|
|
|
def copy_attrs(orig, dest, names, only_if_set=False):
|
|
"""
|
|
copy class attributes from an object to another
|
|
"""
|
|
for a in Utils.to_list(names):
|
|
u = getattr(orig, a, ())
|
|
if u or not only_if_set:
|
|
setattr(dest, a, u)
|
|
|
|
def copy_func(tsk):
|
|
"Make a file copy. This might be used to make other kinds of file processing (even calling a compiler is possible)"
|
|
env = tsk.env
|
|
infile = tsk.inputs[0].abspath()
|
|
outfile = tsk.outputs[0].abspath()
|
|
try:
|
|
shutil.copy2(infile, outfile)
|
|
except (OSError, IOError):
|
|
return 1
|
|
else:
|
|
if tsk.chmod: os.chmod(outfile, tsk.chmod)
|
|
return 0
|
|
|
|
def action_process_file_func(tsk):
|
|
"Ask the function attached to the task to process it"
|
|
if not tsk.fun: raise Errors.WafError('task must have a function attached to it for copy_func to work!')
|
|
return tsk.fun(tsk)
|
|
|
|
@feature('cmd')
|
|
def apply_cmd(self):
|
|
"call a command everytime"
|
|
if not self.fun: raise Errors.WafError('cmdobj needs a function!')
|
|
tsk = Task.TaskBase()
|
|
tsk.fun = self.fun
|
|
tsk.env = self.env
|
|
self.tasks.append(tsk)
|
|
tsk.install_path = self.install_path
|
|
|
|
@feature('copy')
|
|
@before_method('process_source')
|
|
def apply_copy(self):
|
|
Utils.def_attrs(self, fun=copy_func)
|
|
self.default_install_path = 0
|
|
|
|
lst = self.to_list(self.source)
|
|
self.meths.remove('process_source')
|
|
|
|
for filename in lst:
|
|
node = self.path.find_resource(filename)
|
|
if not node: raise Errors.WafError('cannot find input file %s for processing' % filename)
|
|
|
|
target = self.target
|
|
if not target or len(lst)>1: target = node.name
|
|
|
|
# TODO the file path may be incorrect
|
|
newnode = self.path.find_or_declare(target)
|
|
|
|
tsk = self.create_task('copy', node, newnode)
|
|
tsk.fun = self.fun
|
|
tsk.chmod = getattr(self, 'chmod', Utils.O644)
|
|
|
|
if not tsk.env:
|
|
tsk.debug()
|
|
raise Errors.WafError('task without an environment')
|
|
|
|
def subst_func(tsk):
|
|
"Substitutes variables in a .in file"
|
|
|
|
m4_re = re.compile('@(\w+)@', re.M)
|
|
|
|
code = tsk.inputs[0].read() #Utils.readf(infile)
|
|
|
|
# replace all % by %% to prevent errors by % signs in the input file while string formatting
|
|
code = code.replace('%', '%%')
|
|
|
|
s = m4_re.sub(r'%(\1)s', code)
|
|
|
|
env = tsk.env
|
|
di = getattr(tsk, 'dict', {}) or getattr(tsk.generator, 'dict', {})
|
|
if not di:
|
|
names = m4_re.findall(code)
|
|
for i in names:
|
|
di[i] = env.get_flat(i) or env.get_flat(i.upper())
|
|
|
|
tsk.outputs[0].write(s % di)
|
|
|
|
@feature('subst')
|
|
@before_method('process_source')
|
|
def apply_subst(self):
|
|
Utils.def_attrs(self, fun=subst_func)
|
|
lst = self.to_list(self.source)
|
|
self.meths.remove('process_source')
|
|
|
|
self.dict = getattr(self, 'dict', {})
|
|
|
|
for filename in lst:
|
|
node = self.path.find_resource(filename)
|
|
if not node: raise Errors.WafError('cannot find input file %s for processing' % filename)
|
|
|
|
if self.target:
|
|
newnode = self.path.find_or_declare(self.target)
|
|
else:
|
|
newnode = node.change_ext('')
|
|
|
|
try:
|
|
self.dict = self.dict.get_merged_dict()
|
|
except AttributeError:
|
|
pass
|
|
|
|
if self.dict and not self.env['DICT_HASH']:
|
|
self.env = self.env.derive()
|
|
keys = list(self.dict.keys())
|
|
keys.sort()
|
|
lst = [self.dict[x] for x in keys]
|
|
self.env['DICT_HASH'] = str(Utils.h_list(lst))
|
|
|
|
tsk = self.create_task('copy', node, newnode)
|
|
tsk.fun = self.fun
|
|
tsk.dict = self.dict
|
|
tsk.dep_vars = ['DICT_HASH']
|
|
tsk.chmod = getattr(self, 'chmod', Utils.O644)
|
|
|
|
if not tsk.env:
|
|
tsk.debug()
|
|
raise Errors.WafError('task without an environment')
|
|
|
|
####################
|
|
## command-output ####
|
|
####################
|
|
|
|
class cmd_arg(object):
|
|
"""command-output arguments for representing files or folders"""
|
|
def __init__(self, name, template='%s'):
|
|
self.name = name
|
|
self.template = template
|
|
self.node = None
|
|
|
|
class input_file(cmd_arg):
|
|
def find_node(self, base_path):
|
|
assert isinstance(base_path, Node.Node)
|
|
self.node = base_path.find_resource(self.name)
|
|
if self.node is None:
|
|
raise Errors.WafError("Input file %s not found in " % (self.name, base_path))
|
|
|
|
def get_path(self, env, absolute):
|
|
if absolute:
|
|
return self.template % self.node.abspath()
|
|
else:
|
|
return self.template % self.node.srcpath()
|
|
|
|
class output_file(cmd_arg):
|
|
def find_node(self, base_path):
|
|
assert isinstance(base_path, Node.Node)
|
|
self.node = base_path.find_or_declare(self.name)
|
|
if self.node is None:
|
|
raise Errors.WafError("Output file %s not found in " % (self.name, base_path))
|
|
|
|
def get_path(self, env, absolute):
|
|
if absolute:
|
|
return self.template % self.node.abspath()
|
|
else:
|
|
return self.template % self.node.bldpath()
|
|
|
|
class cmd_dir_arg(cmd_arg):
|
|
def find_node(self, base_path):
|
|
assert isinstance(base_path, Node.Node)
|
|
self.node = base_path.find_dir(self.name)
|
|
if self.node is None:
|
|
raise Errors.WafError("Directory %s not found in " % (self.name, base_path))
|
|
|
|
class input_dir(cmd_dir_arg):
|
|
def get_path(self, dummy_env, dummy_absolute):
|
|
return self.template % self.node.abspath()
|
|
|
|
class output_dir(cmd_dir_arg):
|
|
def get_path(self, env, dummy_absolute):
|
|
return self.template % self.node.abspath()
|
|
|
|
|
|
class command_output(Task.Task):
|
|
color = "BLUE"
|
|
def __init__(self, env, command, command_node, command_args, stdin, stdout, cwd, os_env, stderr):
|
|
Task.Task.__init__(self, env=env)
|
|
assert isinstance(command, (str, Node.Node))
|
|
self.command = command
|
|
self.command_args = command_args
|
|
self.stdin = stdin
|
|
self.stdout = stdout
|
|
self.cwd = cwd
|
|
self.os_env = os_env
|
|
self.stderr = stderr
|
|
|
|
if command_node is not None: self.dep_nodes = [command_node]
|
|
self.dep_vars = [] # additional environment variables to look
|
|
|
|
def run(self):
|
|
task = self
|
|
#assert len(task.inputs) > 0
|
|
|
|
def input_path(node, template):
|
|
if task.cwd is None:
|
|
return template % node.bldpath()
|
|
else:
|
|
return template % node.abspath()
|
|
def output_path(node, template):
|
|
fun = node.abspath
|
|
if task.cwd is None: fun = node.bldpath
|
|
return template % fun()
|
|
|
|
if isinstance(task.command, Node.Node):
|
|
argv = [input_path(task.command, '%s')]
|
|
else:
|
|
argv = [task.command]
|
|
|
|
for arg in task.command_args:
|
|
if isinstance(arg, str):
|
|
argv.append(arg)
|
|
else:
|
|
assert isinstance(arg, cmd_arg)
|
|
argv.append(arg.get_path(task.env, (task.cwd is not None)))
|
|
|
|
if task.stdin:
|
|
stdin = open(input_path(task.stdin, '%s'))
|
|
else:
|
|
stdin = None
|
|
|
|
if task.stdout:
|
|
stdout = open(output_path(task.stdout, '%s'), "w")
|
|
else:
|
|
stdout = None
|
|
|
|
if task.stderr:
|
|
stderr = open(output_path(task.stderr, '%s'), "w")
|
|
else:
|
|
stderr = None
|
|
|
|
if task.cwd is None:
|
|
cwd = ('None (actually %r)' % os.getcwd())
|
|
else:
|
|
cwd = repr(task.cwd)
|
|
debug("command-output: cwd=%s, stdin=%r, stdout=%r, argv=%r" %
|
|
(cwd, stdin, stdout, argv))
|
|
|
|
if task.os_env is None:
|
|
os_env = os.environ
|
|
else:
|
|
os_env = task.os_env
|
|
command = Utils.subprocess.Popen(argv, stdin=stdin, stdout=stdout, stderr=stderr, cwd=task.cwd, env=os_env)
|
|
return command.wait()
|
|
|
|
@feature('command-output')
|
|
def init_cmd_output(self):
|
|
Utils.def_attrs(self,
|
|
stdin = None,
|
|
stdout = None,
|
|
stderr = None,
|
|
# the command to execute
|
|
command = None,
|
|
|
|
# whether it is an external command; otherwise it is assumed
|
|
# to be an executable binary or script that lives in the
|
|
# source or build tree.
|
|
command_is_external = False,
|
|
|
|
# extra parameters (argv) to pass to the command (excluding
|
|
# the command itself)
|
|
argv = [],
|
|
|
|
# dependencies to other objects -> this is probably not what you want (ita)
|
|
# values must be 'task_gen' instances (not names!)
|
|
dependencies = [],
|
|
|
|
# dependencies on env variable contents
|
|
dep_vars = [],
|
|
|
|
# input files that are implicit, i.e. they are not
|
|
# stdin, nor are they mentioned explicitly in argv
|
|
hidden_inputs = [],
|
|
|
|
# output files that are implicit, i.e. they are not
|
|
# stdout, nor are they mentioned explicitly in argv
|
|
hidden_outputs = [],
|
|
|
|
# change the subprocess to this cwd (must use obj.input_dir() or output_dir() here)
|
|
cwd = None,
|
|
|
|
# OS environment variables to pass to the subprocess
|
|
# if None, use the default environment variables unchanged
|
|
os_env = None)
|
|
|
|
@feature('command-output')
|
|
@after_method('init_cmd_output')
|
|
def apply_cmd_output(self):
|
|
if self.command is None:
|
|
raise Errors.WafError("command-output missing command")
|
|
if self.command_is_external:
|
|
cmd = self.command
|
|
cmd_node = None
|
|
else:
|
|
cmd_node = self.path.find_resource(self.command)
|
|
assert cmd_node is not None, ('''Could not find command '%s' in source tree.
|
|
Hint: if this is an external command,
|
|
use command_is_external=True''') % (self.command,)
|
|
cmd = cmd_node
|
|
|
|
if self.cwd is None:
|
|
cwd = None
|
|
|
|
args = []
|
|
inputs = []
|
|
outputs = []
|
|
|
|
for arg in self.argv:
|
|
if isinstance(arg, cmd_arg):
|
|
arg.find_node(self.path)
|
|
if isinstance(arg, input_file):
|
|
inputs.append(arg.node)
|
|
if isinstance(arg, output_file):
|
|
outputs.append(arg.node)
|
|
|
|
if self.stdout is None:
|
|
stdout = None
|
|
else:
|
|
assert isinstance(self.stdout, str)
|
|
stdout = self.path.find_or_declare(self.stdout)
|
|
if stdout is None:
|
|
raise Errors.WafError("File %s not found" % (self.stdout,))
|
|
outputs.append(stdout)
|
|
|
|
if self.stderr is None:
|
|
stderr = None
|
|
else:
|
|
assert isinstance(self.stderr, str)
|
|
stderr = self.path.find_or_declare(self.stderr)
|
|
if stderr is None:
|
|
raise Errors.WafError("File %s not found" % (self.stderr,))
|
|
outputs.append(stderr)
|
|
|
|
if self.stdin is None:
|
|
stdin = None
|
|
else:
|
|
assert isinstance(self.stdin, str)
|
|
stdin = self.path.find_resource(self.stdin)
|
|
if stdin is None:
|
|
raise Errors.WafError("File %s not found" % (self.stdin,))
|
|
inputs.append(stdin)
|
|
|
|
for hidden_input in self.to_list(self.hidden_inputs):
|
|
node = self.path.find_resource(hidden_input)
|
|
if node is None:
|
|
raise Errors.WafError("File %s not found in dir %s" % (hidden_input, self.path))
|
|
inputs.append(node)
|
|
|
|
for hidden_output in self.to_list(self.hidden_outputs):
|
|
node = self.path.find_or_declare(hidden_output)
|
|
if node is None:
|
|
raise Errors.WafError("File %s not found in dir %s" % (hidden_output, self.path))
|
|
outputs.append(node)
|
|
|
|
if not (inputs or getattr(self, 'no_inputs', None)):
|
|
raise Errors.WafError('command-output objects must have at least one input file or give self.no_inputs')
|
|
if not (outputs or getattr(self, 'no_outputs', None)):
|
|
raise Errors.WafError('command-output objects must have at least one output file or give self.no_outputs')
|
|
|
|
cwd = self.bld.variant_dir
|
|
task = command_output(self.env, cmd, cmd_node, self.argv, stdin, stdout, cwd, self.os_env, stderr)
|
|
task.generator = self
|
|
copy_attrs(self, task, 'before after ext_in ext_out', only_if_set=True)
|
|
self.tasks.append(task)
|
|
|
|
task.inputs = inputs
|
|
task.outputs = outputs
|
|
task.dep_vars = self.to_list(self.dep_vars)
|
|
|
|
for dep in self.dependencies:
|
|
assert dep is not self
|
|
dep.post()
|
|
for dep_task in dep.tasks:
|
|
task.set_run_after(dep_task)
|
|
|
|
if not task.inputs:
|
|
# the case for svnversion, always run, and update the output nodes
|
|
task.runnable_status = type(Task.TaskBase.run)(runnable_status, task, task.__class__) # always run
|
|
task.post_run = type(Task.TaskBase.run)(post_run, task, task.__class__)
|
|
|
|
# TODO the case with no outputs?
|
|
|
|
def post_run(self):
|
|
for x in self.outputs:
|
|
x.sig = Utils.h_file(x.abspath())
|
|
|
|
def runnable_status(self):
|
|
return self.RUN_ME
|
|
|
|
Task.task_factory('copy', vars=[], func=action_process_file_func)
|
|
|