Blame third_party/waf/waflib/Build.py

rpm-build 95f51c
#!/usr/bin/env python
rpm-build 95f51c
# encoding: utf-8
rpm-build 95f51c
# Thomas Nagy, 2005-2018 (ita)
rpm-build 95f51c
rpm-build 95f51c
"""
rpm-build 95f51c
Classes related to the build phase (build, clean, install, step, etc)
rpm-build 95f51c
rpm-build 95f51c
The inheritance tree is the following:
rpm-build 95f51c
rpm-build 95f51c
"""
rpm-build 95f51c
rpm-build 95f51c
import os, sys, errno, re, shutil, stat
rpm-build 95f51c
try:
rpm-build 95f51c
	import cPickle
rpm-build 95f51c
except ImportError:
rpm-build 95f51c
	import pickle as cPickle
rpm-build 95f51c
from waflib import Node, Runner, TaskGen, Utils, ConfigSet, Task, Logs, Options, Context, Errors
rpm-build 95f51c
rpm-build 95f51c
CACHE_DIR = 'c4che'
rpm-build 95f51c
"""Name of the cache directory"""
rpm-build 95f51c
rpm-build 95f51c
CACHE_SUFFIX = '_cache.py'
rpm-build 95f51c
"""ConfigSet cache files for variants are written under :py:attr:´waflib.Build.CACHE_DIR´ in the form ´variant_name´_cache.py"""
rpm-build 95f51c
rpm-build 95f51c
INSTALL = 1337
rpm-build 95f51c
"""Positive value '->' install, see :py:attr:`waflib.Build.BuildContext.is_install`"""
rpm-build 95f51c
rpm-build 95f51c
UNINSTALL = -1337
rpm-build 95f51c
"""Negative value '<-' uninstall, see :py:attr:`waflib.Build.BuildContext.is_install`"""
rpm-build 95f51c
rpm-build 95f51c
SAVED_ATTRS = 'root node_sigs task_sigs imp_sigs raw_deps node_deps'.split()
rpm-build 95f51c
"""Build class members to save between the runs; these should be all dicts
rpm-build 95f51c
except for `root` which represents a :py:class:`waflib.Node.Node` instance
rpm-build 95f51c
"""
rpm-build 95f51c
rpm-build 95f51c
CFG_FILES = 'cfg_files'
rpm-build 95f51c
"""Files from the build directory to hash before starting the build (``config.h`` written during the configuration)"""
rpm-build 95f51c
rpm-build 95f51c
POST_AT_ONCE = 0
rpm-build 95f51c
"""Post mode: all task generators are posted before any task executed"""
rpm-build 95f51c
rpm-build 95f51c
POST_LAZY = 1
rpm-build 95f51c
"""Post mode: post the task generators group after group, the tasks in the next group are created when the tasks in the previous groups are done"""
rpm-build 95f51c
rpm-build 95f51c
PROTOCOL = -1
rpm-build 95f51c
if sys.platform == 'cli':
rpm-build 95f51c
	PROTOCOL = 0
rpm-build 95f51c
rpm-build 95f51c
class BuildContext(Context.Context):
rpm-build 95f51c
	'''executes the build'''
rpm-build 95f51c
rpm-build 95f51c
	cmd = 'build'
rpm-build 95f51c
	variant = ''
rpm-build 95f51c
rpm-build 95f51c
	def __init__(self, **kw):
rpm-build 95f51c
		super(BuildContext, self).__init__(**kw)
rpm-build 95f51c
rpm-build 95f51c
		self.is_install = 0
rpm-build 95f51c
		"""Non-zero value when installing or uninstalling file"""
rpm-build 95f51c
rpm-build 95f51c
		self.top_dir = kw.get('top_dir', Context.top_dir)
rpm-build 95f51c
		"""See :py:attr:`waflib.Context.top_dir`; prefer :py:attr:`waflib.Build.BuildContext.srcnode`"""
rpm-build 95f51c
rpm-build 95f51c
		self.out_dir = kw.get('out_dir', Context.out_dir)
rpm-build 95f51c
		"""See :py:attr:`waflib.Context.out_dir`; prefer :py:attr:`waflib.Build.BuildContext.bldnode`"""
rpm-build 95f51c
rpm-build 95f51c
		self.run_dir = kw.get('run_dir', Context.run_dir)
rpm-build 95f51c
		"""See :py:attr:`waflib.Context.run_dir`"""
rpm-build 95f51c
rpm-build 95f51c
		self.launch_dir = Context.launch_dir
rpm-build 95f51c
		"""See :py:attr:`waflib.Context.out_dir`; prefer :py:meth:`waflib.Build.BuildContext.launch_node`"""
rpm-build 95f51c
rpm-build 95f51c
		self.post_mode = POST_LAZY
rpm-build 95f51c
		"""Whether to post the task generators at once or group-by-group (default is group-by-group)"""
rpm-build 95f51c
rpm-build 95f51c
		self.cache_dir = kw.get('cache_dir')
rpm-build 95f51c
		if not self.cache_dir:
rpm-build 95f51c
			self.cache_dir = os.path.join(self.out_dir, CACHE_DIR)
rpm-build 95f51c
rpm-build 95f51c
		self.all_envs = {}
rpm-build 95f51c
		"""Map names to :py:class:`waflib.ConfigSet.ConfigSet`, the empty string must map to the default environment"""
rpm-build 95f51c
rpm-build 95f51c
		# ======================================= #
rpm-build 95f51c
		# cache variables
rpm-build 95f51c
rpm-build 95f51c
		self.node_sigs = {}
rpm-build 95f51c
		"""Dict mapping build nodes to task identifier (uid), it indicates whether a task created a particular file (persists across builds)"""
rpm-build 95f51c
rpm-build 95f51c
		self.task_sigs = {}
rpm-build 95f51c
		"""Dict mapping task identifiers (uid) to task signatures (persists across builds)"""
rpm-build 95f51c
rpm-build 95f51c
		self.imp_sigs = {}
rpm-build 95f51c
		"""Dict mapping task identifiers (uid) to implicit task dependencies used for scanning targets (persists across builds)"""
rpm-build 95f51c
rpm-build 95f51c
		self.node_deps = {}
rpm-build 95f51c
		"""Dict mapping task identifiers (uid) to node dependencies found by :py:meth:`waflib.Task.Task.scan` (persists across builds)"""
rpm-build 95f51c
rpm-build 95f51c
		self.raw_deps = {}
rpm-build 95f51c
		"""Dict mapping task identifiers (uid) to custom data returned by :py:meth:`waflib.Task.Task.scan` (persists across builds)"""
rpm-build 95f51c
rpm-build 95f51c
		self.task_gen_cache_names = {}
rpm-build 95f51c
rpm-build 95f51c
		self.jobs = Options.options.jobs
rpm-build 95f51c
		"""Amount of jobs to run in parallel"""
rpm-build 95f51c
rpm-build 95f51c
		self.targets = Options.options.targets
rpm-build 95f51c
		"""List of targets to build (default: \\*)"""
rpm-build 95f51c
rpm-build 95f51c
		self.keep = Options.options.keep
rpm-build 95f51c
		"""Whether the build should continue past errors"""
rpm-build 95f51c
rpm-build 95f51c
		self.progress_bar = Options.options.progress_bar
rpm-build 95f51c
		"""
rpm-build 95f51c
		Level of progress status:
rpm-build 95f51c
rpm-build 95f51c
		0. normal output
rpm-build 95f51c
		1. progress bar
rpm-build 95f51c
		2. IDE output
rpm-build 95f51c
		3. No output at all
rpm-build 95f51c
		"""
rpm-build 95f51c
rpm-build 95f51c
		# Manual dependencies.
rpm-build 95f51c
		self.deps_man = Utils.defaultdict(list)
rpm-build 95f51c
		"""Manual dependencies set by :py:meth:`waflib.Build.BuildContext.add_manual_dependency`"""
rpm-build 95f51c
rpm-build 95f51c
		# just the structure here
rpm-build 95f51c
		self.current_group = 0
rpm-build 95f51c
		"""
rpm-build 95f51c
		Current build group
rpm-build 95f51c
		"""
rpm-build 95f51c
rpm-build 95f51c
		self.groups = []
rpm-build 95f51c
		"""
rpm-build 95f51c
		List containing lists of task generators
rpm-build 95f51c
		"""
rpm-build 95f51c
rpm-build 95f51c
		self.group_names = {}
rpm-build 95f51c
		"""
rpm-build 95f51c
		Map group names to the group lists. See :py:meth:`waflib.Build.BuildContext.add_group`
rpm-build 95f51c
		"""
rpm-build 95f51c
rpm-build 95f51c
		for v in SAVED_ATTRS:
rpm-build 95f51c
			if not hasattr(self, v):
rpm-build 95f51c
				setattr(self, v, {})
rpm-build 95f51c
rpm-build 95f51c
	def get_variant_dir(self):
rpm-build 95f51c
		"""Getter for the variant_dir attribute"""
rpm-build 95f51c
		if not self.variant:
rpm-build 95f51c
			return self.out_dir
rpm-build 95f51c
		return os.path.join(self.out_dir, os.path.normpath(self.variant))
rpm-build 95f51c
	variant_dir = property(get_variant_dir, None)
rpm-build 95f51c
rpm-build 95f51c
	def __call__(self, *k, **kw):
rpm-build 95f51c
		"""
rpm-build 95f51c
		Create a task generator and add it to the current build group. The following forms are equivalent::
rpm-build 95f51c
rpm-build 95f51c
			def build(bld):
rpm-build 95f51c
				tg = bld(a=1, b=2)
rpm-build 95f51c
rpm-build 95f51c
			def build(bld):
rpm-build 95f51c
				tg = bld()
rpm-build 95f51c
				tg.a = 1
rpm-build 95f51c
				tg.b = 2
rpm-build 95f51c
rpm-build 95f51c
			def build(bld):
rpm-build 95f51c
				tg = TaskGen.task_gen(a=1, b=2)
rpm-build 95f51c
				bld.add_to_group(tg, None)
rpm-build 95f51c
rpm-build 95f51c
		:param group: group name to add the task generator to
rpm-build 95f51c
		:type group: string
rpm-build 95f51c
		"""
rpm-build 95f51c
		kw['bld'] = self
rpm-build 95f51c
		ret = TaskGen.task_gen(*k, **kw)
rpm-build 95f51c
		self.task_gen_cache_names = {} # reset the cache, each time
rpm-build 95f51c
		self.add_to_group(ret, group=kw.get('group'))
rpm-build 95f51c
		return ret
rpm-build 95f51c
rpm-build 95f51c
	def __copy__(self):
rpm-build 95f51c
		"""
rpm-build 95f51c
		Build contexts cannot be copied
rpm-build 95f51c
rpm-build 95f51c
		:raises: :py:class:`waflib.Errors.WafError`
rpm-build 95f51c
		"""
rpm-build 95f51c
		raise Errors.WafError('build contexts cannot be copied')
rpm-build 95f51c
rpm-build 95f51c
	def load_envs(self):
rpm-build 95f51c
		"""
rpm-build 95f51c
		The configuration command creates files of the form ``build/c4che/NAMEcache.py``. This method
rpm-build 95f51c
		creates a :py:class:`waflib.ConfigSet.ConfigSet` instance for each ``NAME`` by reading those
rpm-build 95f51c
		files and stores them in :py:attr:`waflib.Build.BuildContext.allenvs`.
rpm-build 95f51c
		"""
rpm-build 95f51c
		node = self.root.find_node(self.cache_dir)
rpm-build 95f51c
		if not node:
rpm-build 95f51c
			raise Errors.WafError('The project was not configured: run "waf configure" first!')
rpm-build 95f51c
		lst = node.ant_glob('**/*%s' % CACHE_SUFFIX, quiet=True)
rpm-build 95f51c
rpm-build 95f51c
		if not lst:
rpm-build 95f51c
			raise Errors.WafError('The cache directory is empty: reconfigure the project')
rpm-build 95f51c
rpm-build 95f51c
		for x in lst:
rpm-build 95f51c
			name = x.path_from(node).replace(CACHE_SUFFIX, '').replace('\\', '/')
rpm-build 95f51c
			env = ConfigSet.ConfigSet(x.abspath())
rpm-build 95f51c
			self.all_envs[name] = env
rpm-build 95f51c
			for f in env[CFG_FILES]:
rpm-build 95f51c
				newnode = self.root.find_resource(f)
rpm-build 95f51c
				if not newnode or not newnode.exists():
rpm-build 95f51c
					raise Errors.WafError('Missing configuration file %r, reconfigure the project!' % f)
rpm-build 95f51c
rpm-build 95f51c
	def init_dirs(self):
rpm-build 95f51c
		"""
rpm-build 95f51c
		Initialize the project directory and the build directory by creating the nodes
rpm-build 95f51c
		:py:attr:`waflib.Build.BuildContext.srcnode` and :py:attr:`waflib.Build.BuildContext.bldnode`
rpm-build 95f51c
		corresponding to ``top_dir`` and ``variant_dir`` respectively. The ``bldnode`` directory is
rpm-build 95f51c
		created if necessary.
rpm-build 95f51c
		"""
rpm-build 95f51c
		if not (os.path.isabs(self.top_dir) and os.path.isabs(self.out_dir)):
rpm-build 95f51c
			raise Errors.WafError('The project was not configured: run "waf configure" first!')
rpm-build 95f51c
rpm-build 95f51c
		self.path = self.srcnode = self.root.find_dir(self.top_dir)
rpm-build 95f51c
		self.bldnode = self.root.make_node(self.variant_dir)
rpm-build 95f51c
		self.bldnode.mkdir()
rpm-build 95f51c
rpm-build 95f51c
	def execute(self):
rpm-build 95f51c
		"""
rpm-build 95f51c
		Restore data from previous builds and call :py:meth:`waflib.Build.BuildContext.execute_build`.
rpm-build 95f51c
		Overrides from :py:func:`waflib.Context.Context.execute`
rpm-build 95f51c
		"""
rpm-build 95f51c
		self.restore()
rpm-build 95f51c
		if not self.all_envs:
rpm-build 95f51c
			self.load_envs()
rpm-build 95f51c
		self.execute_build()
rpm-build 95f51c
rpm-build 95f51c
	def execute_build(self):
rpm-build 95f51c
		"""
rpm-build 95f51c
		Execute the build by:
rpm-build 95f51c
rpm-build 95f51c
		* reading the scripts (see :py:meth:`waflib.Context.Context.recurse`)
rpm-build 95f51c
		* calling :py:meth:`waflib.Build.BuildContext.pre_build` to call user build functions
rpm-build 95f51c
		* calling :py:meth:`waflib.Build.BuildContext.compile` to process the tasks
rpm-build 95f51c
		* calling :py:meth:`waflib.Build.BuildContext.post_build` to call user build functions
rpm-build 95f51c
		"""
rpm-build 95f51c
rpm-build 95f51c
		Logs.info("Waf: Entering directory `%s'", self.variant_dir)
rpm-build 95f51c
		self.recurse([self.run_dir])
rpm-build 95f51c
		self.pre_build()
rpm-build 95f51c
rpm-build 95f51c
		# display the time elapsed in the progress bar
rpm-build 95f51c
		self.timer = Utils.Timer()
rpm-build 95f51c
rpm-build 95f51c
		try:
rpm-build 95f51c
			self.compile()
rpm-build 95f51c
		finally:
rpm-build 95f51c
			if self.progress_bar == 1 and sys.stderr.isatty():
rpm-build 95f51c
				c = self.producer.processed or 1
rpm-build 95f51c
				m = self.progress_line(c, c, Logs.colors.BLUE, Logs.colors.NORMAL)
rpm-build 95f51c
				Logs.info(m, extra={'stream': sys.stderr, 'c1': Logs.colors.cursor_off, 'c2' : Logs.colors.cursor_on})
rpm-build 95f51c
			Logs.info("Waf: Leaving directory `%s'", self.variant_dir)
rpm-build 95f51c
		try:
rpm-build 95f51c
			self.producer.bld = None
rpm-build 95f51c
			del self.producer
rpm-build 95f51c
		except AttributeError:
rpm-build 95f51c
			pass
rpm-build 95f51c
		self.post_build()
rpm-build 95f51c
rpm-build 95f51c
	def restore(self):
rpm-build 95f51c
		"""
rpm-build 95f51c
		Load data from a previous run, sets the attributes listed in :py:const:`waflib.Build.SAVED_ATTRS`
rpm-build 95f51c
		"""
rpm-build 95f51c
		try:
rpm-build 95f51c
			env = ConfigSet.ConfigSet(os.path.join(self.cache_dir, 'build.config.py'))
rpm-build 95f51c
		except EnvironmentError:
rpm-build 95f51c
			pass
rpm-build 95f51c
		else:
rpm-build 95f51c
			if env.version < Context.HEXVERSION:
rpm-build 95f51c
				raise Errors.WafError('Project was configured with a different version of Waf, please reconfigure it')
rpm-build 95f51c
rpm-build 95f51c
			for t in env.tools:
rpm-build 95f51c
				self.setup(**t)
rpm-build 95f51c
rpm-build 95f51c
		dbfn = os.path.join(self.variant_dir, Context.DBFILE)
rpm-build 95f51c
		try:
rpm-build 95f51c
			data = Utils.readf(dbfn, 'rb')
rpm-build 95f51c
		except (EnvironmentError, EOFError):
rpm-build 95f51c
			# handle missing file/empty file
rpm-build 95f51c
			Logs.debug('build: Could not load the build cache %s (missing)', dbfn)
rpm-build 95f51c
		else:
rpm-build 95f51c
			try:
rpm-build 95f51c
				Node.pickle_lock.acquire()
rpm-build 95f51c
				Node.Nod3 = self.node_class
rpm-build 95f51c
				try:
rpm-build 95f51c
					data = cPickle.loads(data)
rpm-build 95f51c
				except Exception as e:
rpm-build 95f51c
					Logs.debug('build: Could not pickle the build cache %s: %r', dbfn, e)
rpm-build 95f51c
				else:
rpm-build 95f51c
					for x in SAVED_ATTRS:
rpm-build 95f51c
						setattr(self, x, data.get(x, {}))
rpm-build 95f51c
			finally:
rpm-build 95f51c
				Node.pickle_lock.release()
rpm-build 95f51c
rpm-build 95f51c
		self.init_dirs()
rpm-build 95f51c
rpm-build 95f51c
	def store(self):
rpm-build 95f51c
		"""
rpm-build 95f51c
		Store data for next runs, set the attributes listed in :py:const:`waflib.Build.SAVED_ATTRS`. Uses a temporary
rpm-build 95f51c
		file to avoid problems on ctrl+c.
rpm-build 95f51c
		"""
rpm-build 95f51c
		data = {}
rpm-build 95f51c
		for x in SAVED_ATTRS:
rpm-build 95f51c
			data[x] = getattr(self, x)
rpm-build 95f51c
		db = os.path.join(self.variant_dir, Context.DBFILE)
rpm-build 95f51c
rpm-build 95f51c
		try:
rpm-build 95f51c
			Node.pickle_lock.acquire()
rpm-build 95f51c
			Node.Nod3 = self.node_class
rpm-build 95f51c
			x = cPickle.dumps(data, PROTOCOL)
rpm-build 95f51c
		finally:
rpm-build 95f51c
			Node.pickle_lock.release()
rpm-build 95f51c
rpm-build 95f51c
		Utils.writef(db + '.tmp', x, m='wb')
rpm-build 95f51c
rpm-build 95f51c
		try:
rpm-build 95f51c
			st = os.stat(db)
rpm-build 95f51c
			os.remove(db)
rpm-build 95f51c
			if not Utils.is_win32: # win32 has no chown but we're paranoid
rpm-build 95f51c
				os.chown(db + '.tmp', st.st_uid, st.st_gid)
rpm-build 95f51c
		except (AttributeError, OSError):
rpm-build 95f51c
			pass
rpm-build 95f51c
rpm-build 95f51c
		# do not use shutil.move (copy is not thread-safe)
rpm-build 95f51c
		os.rename(db + '.tmp', db)
rpm-build 95f51c
rpm-build 95f51c
	def compile(self):
rpm-build 95f51c
		"""
rpm-build 95f51c
		Run the build by creating an instance of :py:class:`waflib.Runner.Parallel`
rpm-build 95f51c
		The cache file is written when at least a task was executed.
rpm-build 95f51c
rpm-build 95f51c
		:raises: :py:class:`waflib.Errors.BuildError` in case the build fails
rpm-build 95f51c
		"""
rpm-build 95f51c
		Logs.debug('build: compile()')
rpm-build 95f51c
rpm-build 95f51c
		# delegate the producer-consumer logic to another object to reduce the complexity
rpm-build 95f51c
		self.producer = Runner.Parallel(self, self.jobs)
rpm-build 95f51c
		self.producer.biter = self.get_build_iterator()
rpm-build 95f51c
		try:
rpm-build 95f51c
			self.producer.start()
rpm-build 95f51c
		except KeyboardInterrupt:
rpm-build 95f51c
			if self.is_dirty():
rpm-build 95f51c
				self.store()
rpm-build 95f51c
			raise
rpm-build 95f51c
		else:
rpm-build 95f51c
			if self.is_dirty():
rpm-build 95f51c
				self.store()
rpm-build 95f51c
rpm-build 95f51c
		if self.producer.error:
rpm-build 95f51c
			raise Errors.BuildError(self.producer.error)
rpm-build 95f51c
rpm-build 95f51c
	def is_dirty(self):
rpm-build 95f51c
		return self.producer.dirty
rpm-build 95f51c
rpm-build 95f51c
	def setup(self, tool, tooldir=None, funs=None):
rpm-build 95f51c
		"""
rpm-build 95f51c
		Import waf tools defined during the configuration::
rpm-build 95f51c
rpm-build 95f51c
			def configure(conf):
rpm-build 95f51c
				conf.load('glib2')
rpm-build 95f51c
rpm-build 95f51c
			def build(bld):
rpm-build 95f51c
				pass # glib2 is imported implicitly
rpm-build 95f51c
rpm-build 95f51c
		:param tool: tool list
rpm-build 95f51c
		:type tool: list
rpm-build 95f51c
		:param tooldir: optional tool directory (sys.path)
rpm-build 95f51c
		:type tooldir: list of string
rpm-build 95f51c
		:param funs: unused variable
rpm-build 95f51c
		"""
rpm-build 95f51c
		if isinstance(tool, list):
rpm-build 95f51c
			for i in tool:
rpm-build 95f51c
				self.setup(i, tooldir)
rpm-build 95f51c
			return
rpm-build 95f51c
rpm-build 95f51c
		module = Context.load_tool(tool, tooldir)
rpm-build 95f51c
		if hasattr(module, "setup"):
rpm-build 95f51c
			module.setup(self)
rpm-build 95f51c
rpm-build 95f51c
	def get_env(self):
rpm-build 95f51c
		"""Getter for the env property"""
rpm-build 95f51c
		try:
rpm-build 95f51c
			return self.all_envs[self.variant]
rpm-build 95f51c
		except KeyError:
rpm-build 95f51c
			return self.all_envs['']
rpm-build 95f51c
	def set_env(self, val):
rpm-build 95f51c
		"""Setter for the env property"""
rpm-build 95f51c
		self.all_envs[self.variant] = val
rpm-build 95f51c
rpm-build 95f51c
	env = property(get_env, set_env)
rpm-build 95f51c
rpm-build 95f51c
	def add_manual_dependency(self, path, value):
rpm-build 95f51c
		"""
rpm-build 95f51c
		Adds a dependency from a node object to a value::
rpm-build 95f51c
rpm-build 95f51c
			def build(bld):
rpm-build 95f51c
				bld.add_manual_dependency(
rpm-build 95f51c
					bld.path.find_resource('wscript'),
rpm-build 95f51c
					bld.root.find_resource('/etc/fstab'))
rpm-build 95f51c
rpm-build 95f51c
		:param path: file path
rpm-build 95f51c
		:type path: string or :py:class:`waflib.Node.Node`
rpm-build 95f51c
		:param value: value to depend
rpm-build 95f51c
		:type value: :py:class:`waflib.Node.Node`, byte object, or function returning a byte object
rpm-build 95f51c
		"""
rpm-build 95f51c
		if not path:
rpm-build 95f51c
			raise ValueError('Invalid input path %r' % path)
rpm-build 95f51c
rpm-build 95f51c
		if isinstance(path, Node.Node):
rpm-build 95f51c
			node = path
rpm-build 95f51c
		elif os.path.isabs(path):
rpm-build 95f51c
			node = self.root.find_resource(path)
rpm-build 95f51c
		else:
rpm-build 95f51c
			node = self.path.find_resource(path)
rpm-build 95f51c
		if not node:
rpm-build 95f51c
			raise ValueError('Could not find the path %r' % path)
rpm-build 95f51c
rpm-build 95f51c
		if isinstance(value, list):
rpm-build 95f51c
			self.deps_man[node].extend(value)
rpm-build 95f51c
		else:
rpm-build 95f51c
			self.deps_man[node].append(value)
rpm-build 95f51c
rpm-build 95f51c
	def launch_node(self):
rpm-build 95f51c
		"""Returns the launch directory as a :py:class:`waflib.Node.Node` object (cached)"""
rpm-build 95f51c
		try:
rpm-build 95f51c
			# private cache
rpm-build 95f51c
			return self.p_ln
rpm-build 95f51c
		except AttributeError:
rpm-build 95f51c
			self.p_ln = self.root.find_dir(self.launch_dir)
rpm-build 95f51c
			return self.p_ln
rpm-build 95f51c
rpm-build 95f51c
	def hash_env_vars(self, env, vars_lst):
rpm-build 95f51c
		"""
rpm-build 95f51c
		Hashes configuration set variables::
rpm-build 95f51c
rpm-build 95f51c
			def build(bld):
rpm-build 95f51c
				bld.hash_env_vars(bld.env, ['CXX', 'CC'])
rpm-build 95f51c
rpm-build 95f51c
		This method uses an internal cache.
rpm-build 95f51c
rpm-build 95f51c
		:param env: Configuration Set
rpm-build 95f51c
		:type env: :py:class:`waflib.ConfigSet.ConfigSet`
rpm-build 95f51c
		:param vars_lst: list of variables
rpm-build 95f51c
		:type vars_list: list of string
rpm-build 95f51c
		"""
rpm-build 95f51c
rpm-build 95f51c
		if not env.table:
rpm-build 95f51c
			env = env.parent
rpm-build 95f51c
			if not env:
rpm-build 95f51c
				return Utils.SIG_NIL
rpm-build 95f51c
rpm-build 95f51c
		idx = str(id(env)) + str(vars_lst)
rpm-build 95f51c
		try:
rpm-build 95f51c
			cache = self.cache_env
rpm-build 95f51c
		except AttributeError:
rpm-build 95f51c
			cache = self.cache_env = {}
rpm-build 95f51c
		else:
rpm-build 95f51c
			try:
rpm-build 95f51c
				return self.cache_env[idx]
rpm-build 95f51c
			except KeyError:
rpm-build 95f51c
				pass
rpm-build 95f51c
rpm-build 95f51c
		lst = [env[a] for a in vars_lst]
rpm-build 95f51c
		cache[idx] = ret = Utils.h_list(lst)
rpm-build 95f51c
		Logs.debug('envhash: %s %r', Utils.to_hex(ret), lst)
rpm-build 95f51c
		return ret
rpm-build 95f51c
rpm-build 95f51c
	def get_tgen_by_name(self, name):
rpm-build 95f51c
		"""
rpm-build 95f51c
		Fetches a task generator by its name or its target attribute;
rpm-build 95f51c
		the name must be unique in a build::
rpm-build 95f51c
rpm-build 95f51c
			def build(bld):
rpm-build 95f51c
				tg = bld(name='foo')
rpm-build 95f51c
				tg == bld.get_tgen_by_name('foo')
rpm-build 95f51c
rpm-build 95f51c
		This method use a private internal cache.
rpm-build 95f51c
rpm-build 95f51c
		:param name: Task generator name
rpm-build 95f51c
		:raises: :py:class:`waflib.Errors.WafError` in case there is no task genenerator by that name
rpm-build 95f51c
		"""
rpm-build 95f51c
		cache = self.task_gen_cache_names
rpm-build 95f51c
		if not cache:
rpm-build 95f51c
			# create the index lazily
rpm-build 95f51c
			for g in self.groups:
rpm-build 95f51c
				for tg in g:
rpm-build 95f51c
					try:
rpm-build 95f51c
						cache[tg.name] = tg
rpm-build 95f51c
					except AttributeError:
rpm-build 95f51c
						# raised if not a task generator, which should be uncommon
rpm-build 95f51c
						pass
rpm-build 95f51c
		try:
rpm-build 95f51c
			return cache[name]
rpm-build 95f51c
		except KeyError:
rpm-build 95f51c
			raise Errors.WafError('Could not find a task generator for the name %r' % name)
rpm-build 95f51c
rpm-build 95f51c
	def progress_line(self, idx, total, col1, col2):
rpm-build 95f51c
		"""
rpm-build 95f51c
		Computes a progress bar line displayed when running ``waf -p``
rpm-build 95f51c
rpm-build 95f51c
		:returns: progress bar line
rpm-build 95f51c
		:rtype: string
rpm-build 95f51c
		"""
rpm-build 95f51c
		if not sys.stderr.isatty():
rpm-build 95f51c
			return ''
rpm-build 95f51c
rpm-build 95f51c
		n = len(str(total))
rpm-build 95f51c
rpm-build 95f51c
		Utils.rot_idx += 1
rpm-build 95f51c
		ind = Utils.rot_chr[Utils.rot_idx % 4]
rpm-build 95f51c
rpm-build 95f51c
		pc = (100. * idx)/total
rpm-build 95f51c
		fs = "[%%%dd/%%d][%%s%%2d%%%%%%s][%s][" % (n, ind)
rpm-build 95f51c
		left = fs % (idx, total, col1, pc, col2)
rpm-build 95f51c
		right = '][%s%s%s]' % (col1, self.timer, col2)
rpm-build 95f51c
rpm-build 95f51c
		cols = Logs.get_term_cols() - len(left) - len(right) + 2*len(col1) + 2*len(col2)
rpm-build 95f51c
		if cols < 7:
rpm-build 95f51c
			cols = 7
rpm-build 95f51c
rpm-build 95f51c
		ratio = ((cols * idx)//total) - 1
rpm-build 95f51c
rpm-build 95f51c
		bar = ('='*ratio+'>').ljust(cols)
rpm-build 95f51c
		msg = Logs.indicator % (left, bar, right)
rpm-build 95f51c
rpm-build 95f51c
		return msg
rpm-build 95f51c
rpm-build 95f51c
	def declare_chain(self, *k, **kw):
rpm-build 95f51c
		"""
rpm-build 95f51c
		Wraps :py:func:`waflib.TaskGen.declare_chain` for convenience
rpm-build 95f51c
		"""
rpm-build 95f51c
		return TaskGen.declare_chain(*k, **kw)
rpm-build 95f51c
rpm-build 95f51c
	def pre_build(self):
rpm-build 95f51c
		"""Executes user-defined methods before the build starts, see :py:meth:`waflib.Build.BuildContext.add_pre_fun`"""
rpm-build 95f51c
		for m in getattr(self, 'pre_funs', []):
rpm-build 95f51c
			m(self)
rpm-build 95f51c
rpm-build 95f51c
	def post_build(self):
rpm-build 95f51c
		"""Executes user-defined methods after the build is successful, see :py:meth:`waflib.Build.BuildContext.add_post_fun`"""
rpm-build 95f51c
		for m in getattr(self, 'post_funs', []):
rpm-build 95f51c
			m(self)
rpm-build 95f51c
rpm-build 95f51c
	def add_pre_fun(self, meth):
rpm-build 95f51c
		"""
rpm-build 95f51c
		Binds a callback method to execute after the scripts are read and before the build starts::
rpm-build 95f51c
rpm-build 95f51c
			def mycallback(bld):
rpm-build 95f51c
				print("Hello, world!")
rpm-build 95f51c
rpm-build 95f51c
			def build(bld):
rpm-build 95f51c
				bld.add_pre_fun(mycallback)
rpm-build 95f51c
		"""
rpm-build 95f51c
		try:
rpm-build 95f51c
			self.pre_funs.append(meth)
rpm-build 95f51c
		except AttributeError:
rpm-build 95f51c
			self.pre_funs = [meth]
rpm-build 95f51c
rpm-build 95f51c
	def add_post_fun(self, meth):
rpm-build 95f51c
		"""
rpm-build 95f51c
		Binds a callback method to execute immediately after the build is successful::
rpm-build 95f51c
rpm-build 95f51c
			def call_ldconfig(bld):
rpm-build 95f51c
				bld.exec_command('/sbin/ldconfig')
rpm-build 95f51c
rpm-build 95f51c
			def build(bld):
rpm-build 95f51c
				if bld.cmd == 'install':
rpm-build 95f51c
					bld.add_pre_fun(call_ldconfig)
rpm-build 95f51c
		"""
rpm-build 95f51c
		try:
rpm-build 95f51c
			self.post_funs.append(meth)
rpm-build 95f51c
		except AttributeError:
rpm-build 95f51c
			self.post_funs = [meth]
rpm-build 95f51c
rpm-build 95f51c
	def get_group(self, x):
rpm-build 95f51c
		"""
rpm-build 95f51c
		Returns the build group named `x`, or the current group if `x` is None
rpm-build 95f51c
rpm-build 95f51c
		:param x: name or number or None
rpm-build 95f51c
		:type x: string, int or None
rpm-build 95f51c
		"""
rpm-build 95f51c
		if not self.groups:
rpm-build 95f51c
			self.add_group()
rpm-build 95f51c
		if x is None:
rpm-build 95f51c
			return self.groups[self.current_group]
rpm-build 95f51c
		if x in self.group_names:
rpm-build 95f51c
			return self.group_names[x]
rpm-build 95f51c
		return self.groups[x]
rpm-build 95f51c
rpm-build 95f51c
	def add_to_group(self, tgen, group=None):
rpm-build 95f51c
		"""Adds a task or a task generator to the build; there is no attempt to remove it if it was already added."""
rpm-build 95f51c
		assert(isinstance(tgen, TaskGen.task_gen) or isinstance(tgen, Task.Task))
rpm-build 95f51c
		tgen.bld = self
rpm-build 95f51c
		self.get_group(group).append(tgen)
rpm-build 95f51c
rpm-build 95f51c
	def get_group_name(self, g):
rpm-build 95f51c
		"""
rpm-build 95f51c
		Returns the name of the input build group
rpm-build 95f51c
rpm-build 95f51c
		:param g: build group object or build group index
rpm-build 95f51c
		:type g: integer or list
rpm-build 95f51c
		:return: name
rpm-build 95f51c
		:rtype: string
rpm-build 95f51c
		"""
rpm-build 95f51c
		if not isinstance(g, list):
rpm-build 95f51c
			g = self.groups[g]
rpm-build 95f51c
		for x in self.group_names:
rpm-build 95f51c
			if id(self.group_names[x]) == id(g):
rpm-build 95f51c
				return x
rpm-build 95f51c
		return ''
rpm-build 95f51c
rpm-build 95f51c
	def get_group_idx(self, tg):
rpm-build 95f51c
		"""
rpm-build 95f51c
		Returns the index of the group containing the task generator given as argument::
rpm-build 95f51c
rpm-build 95f51c
			def build(bld):
rpm-build 95f51c
				tg = bld(name='nada')
rpm-build 95f51c
				0 == bld.get_group_idx(tg)
rpm-build 95f51c
rpm-build 95f51c
		:param tg: Task generator object
rpm-build 95f51c
		:type tg: :py:class:`waflib.TaskGen.task_gen`
rpm-build 95f51c
		:rtype: int
rpm-build 95f51c
		"""
rpm-build 95f51c
		se = id(tg)
rpm-build 95f51c
		for i, tmp in enumerate(self.groups):
rpm-build 95f51c
			for t in tmp:
rpm-build 95f51c
				if id(t) == se:
rpm-build 95f51c
					return i
rpm-build 95f51c
		return None
rpm-build 95f51c
rpm-build 95f51c
	def add_group(self, name=None, move=True):
rpm-build 95f51c
		"""
rpm-build 95f51c
		Adds a new group of tasks/task generators. By default the new group becomes
rpm-build 95f51c
		the default group for new task generators (make sure to create build groups in order).
rpm-build 95f51c
rpm-build 95f51c
		:param name: name for this group
rpm-build 95f51c
		:type name: string
rpm-build 95f51c
		:param move: set this new group as default group (True by default)
rpm-build 95f51c
		:type move: bool
rpm-build 95f51c
		:raises: :py:class:`waflib.Errors.WafError` if a group by the name given already exists
rpm-build 95f51c
		"""
rpm-build 95f51c
		if name and name in self.group_names:
rpm-build 95f51c
			raise Errors.WafError('add_group: name %s already present', name)
rpm-build 95f51c
		g = []
rpm-build 95f51c
		self.group_names[name] = g
rpm-build 95f51c
		self.groups.append(g)
rpm-build 95f51c
		if move:
rpm-build 95f51c
			self.current_group = len(self.groups) - 1
rpm-build 95f51c
rpm-build 95f51c
	def set_group(self, idx):
rpm-build 95f51c
		"""
rpm-build 95f51c
		Sets the build group at position idx as current so that newly added
rpm-build 95f51c
		task generators are added to this one by default::
rpm-build 95f51c
rpm-build 95f51c
			def build(bld):
rpm-build 95f51c
				bld(rule='touch ${TGT}', target='foo.txt')
rpm-build 95f51c
				bld.add_group() # now the current group is 1
rpm-build 95f51c
				bld(rule='touch ${TGT}', target='bar.txt')
rpm-build 95f51c
				bld.set_group(0) # now the current group is 0
rpm-build 95f51c
				bld(rule='touch ${TGT}', target='truc.txt') # build truc.txt before bar.txt
rpm-build 95f51c
rpm-build 95f51c
		:param idx: group name or group index
rpm-build 95f51c
		:type idx: string or int
rpm-build 95f51c
		"""
rpm-build 95f51c
		if isinstance(idx, str):
rpm-build 95f51c
			g = self.group_names[idx]
rpm-build 95f51c
			for i, tmp in enumerate(self.groups):
rpm-build 95f51c
				if id(g) == id(tmp):
rpm-build 95f51c
					self.current_group = i
rpm-build 95f51c
					break
rpm-build 95f51c
		else:
rpm-build 95f51c
			self.current_group = idx
rpm-build 95f51c
rpm-build 95f51c
	def total(self):
rpm-build 95f51c
		"""
rpm-build 95f51c
		Approximate task count: this value may be inaccurate if task generators
rpm-build 95f51c
		are posted lazily (see :py:attr:`waflib.Build.BuildContext.post_mode`).
rpm-build 95f51c
		The value :py:attr:`waflib.Runner.Parallel.total` is updated during the task execution.
rpm-build 95f51c
rpm-build 95f51c
		:rtype: int
rpm-build 95f51c
		"""
rpm-build 95f51c
		total = 0
rpm-build 95f51c
		for group in self.groups:
rpm-build 95f51c
			for tg in group:
rpm-build 95f51c
				try:
rpm-build 95f51c
					total += len(tg.tasks)
rpm-build 95f51c
				except AttributeError:
rpm-build 95f51c
					total += 1
rpm-build 95f51c
		return total
rpm-build 95f51c
rpm-build 95f51c
	def get_targets(self):
rpm-build 95f51c
		"""
rpm-build 95f51c
		This method returns a pair containing the index of the last build group to post,
rpm-build 95f51c
		and the list of task generator objects corresponding to the target names.
rpm-build 95f51c
rpm-build 95f51c
		This is used internally by :py:meth:`waflib.Build.BuildContext.get_build_iterator`
rpm-build 95f51c
		to perform partial builds::
rpm-build 95f51c
rpm-build 95f51c
			$ waf --targets=myprogram,myshlib
rpm-build 95f51c
rpm-build 95f51c
		:return: the minimum build group index, and list of task generators
rpm-build 95f51c
		:rtype: tuple
rpm-build 95f51c
		"""
rpm-build 95f51c
		to_post = []
rpm-build 95f51c
		min_grp = 0
rpm-build 95f51c
		for name in self.targets.split(','):
rpm-build 95f51c
			tg = self.get_tgen_by_name(name)
rpm-build 95f51c
			m = self.get_group_idx(tg)
rpm-build 95f51c
			if m > min_grp:
rpm-build 95f51c
				min_grp = m
rpm-build 95f51c
				to_post = [tg]
rpm-build 95f51c
			elif m == min_grp:
rpm-build 95f51c
				to_post.append(tg)
rpm-build 95f51c
		return (min_grp, to_post)
rpm-build 95f51c
rpm-build 95f51c
	def get_all_task_gen(self):
rpm-build 95f51c
		"""
rpm-build 95f51c
		Returns a list of all task generators for troubleshooting purposes.
rpm-build 95f51c
		"""
rpm-build 95f51c
		lst = []
rpm-build 95f51c
		for g in self.groups:
rpm-build 95f51c
			lst.extend(g)
rpm-build 95f51c
		return lst
rpm-build 95f51c
rpm-build 95f51c
	def post_group(self):
rpm-build 95f51c
		"""
rpm-build 95f51c
		Post task generators from the group indexed by self.current_group; used internally
rpm-build 95f51c
		by :py:meth:`waflib.Build.BuildContext.get_build_iterator`
rpm-build 95f51c
		"""
rpm-build 95f51c
		def tgpost(tg):
rpm-build 95f51c
			try:
rpm-build 95f51c
				f = tg.post
rpm-build 95f51c
			except AttributeError:
rpm-build 95f51c
				pass
rpm-build 95f51c
			else:
rpm-build 95f51c
				f()
rpm-build 95f51c
rpm-build 95f51c
		if self.targets == '*':
rpm-build 95f51c
			for tg in self.groups[self.current_group]:
rpm-build 95f51c
				tgpost(tg)
rpm-build 95f51c
		elif self.targets:
rpm-build 95f51c
			if self.current_group < self._min_grp:
rpm-build 95f51c
				for tg in self.groups[self.current_group]:
rpm-build 95f51c
					tgpost(tg)
rpm-build 95f51c
			else:
rpm-build 95f51c
				for tg in self._exact_tg:
rpm-build 95f51c
					tg.post()
rpm-build 95f51c
		else:
rpm-build 95f51c
			ln = self.launch_node()
rpm-build 95f51c
			if ln.is_child_of(self.bldnode):
rpm-build 95f51c
				Logs.warn('Building from the build directory, forcing --targets=*')
rpm-build 95f51c
				ln = self.srcnode
rpm-build 95f51c
			elif not ln.is_child_of(self.srcnode):
rpm-build 95f51c
				Logs.warn('CWD %s is not under %s, forcing --targets=* (run distclean?)', ln.abspath(), self.srcnode.abspath())
rpm-build 95f51c
				ln = self.srcnode
rpm-build 95f51c
rpm-build 95f51c
			def is_post(tg, ln):
rpm-build 95f51c
				try:
rpm-build 95f51c
					p = tg.path
rpm-build 95f51c
				except AttributeError:
rpm-build 95f51c
					pass
rpm-build 95f51c
				else:
rpm-build 95f51c
					if p.is_child_of(ln):
rpm-build 95f51c
						return True
rpm-build 95f51c
rpm-build 95f51c
			def is_post_group():
rpm-build 95f51c
				for i, g in enumerate(self.groups):
rpm-build 95f51c
					if i > self.current_group:
rpm-build 95f51c
						for tg in g:
rpm-build 95f51c
							if is_post(tg, ln):
rpm-build 95f51c
								return True
rpm-build 95f51c
rpm-build 95f51c
			if self.post_mode == POST_LAZY and ln != self.srcnode:
rpm-build 95f51c
				# partial folder builds require all targets from a previous build group
rpm-build 95f51c
				if is_post_group():
rpm-build 95f51c
					ln = self.srcnode
rpm-build 95f51c
rpm-build 95f51c
			for tg in self.groups[self.current_group]:
rpm-build 95f51c
				if is_post(tg, ln):
rpm-build 95f51c
					tgpost(tg)
rpm-build 95f51c
rpm-build 95f51c
	def get_tasks_group(self, idx):
rpm-build 95f51c
		"""
rpm-build 95f51c
		Returns all task instances for the build group at position idx,
rpm-build 95f51c
		used internally by :py:meth:`waflib.Build.BuildContext.get_build_iterator`
rpm-build 95f51c
rpm-build 95f51c
		:rtype: list of :py:class:`waflib.Task.Task`
rpm-build 95f51c
		"""
rpm-build 95f51c
		tasks = []
rpm-build 95f51c
		for tg in self.groups[idx]:
rpm-build 95f51c
			try:
rpm-build 95f51c
				tasks.extend(tg.tasks)
rpm-build 95f51c
			except AttributeError: # not a task generator
rpm-build 95f51c
				tasks.append(tg)
rpm-build 95f51c
		return tasks
rpm-build 95f51c
rpm-build 95f51c
	def get_build_iterator(self):
rpm-build 95f51c
		"""
rpm-build 95f51c
		Creates a Python generator object that returns lists of tasks that may be processed in parallel.
rpm-build 95f51c
rpm-build 95f51c
		:return: tasks which can be executed immediately
rpm-build 95f51c
		:rtype: generator returning lists of :py:class:`waflib.Task.Task`
rpm-build 95f51c
		"""
rpm-build 95f51c
		if self.targets and self.targets != '*':
rpm-build 95f51c
			(self._min_grp, self._exact_tg) = self.get_targets()
rpm-build 95f51c
rpm-build 95f51c
		if self.post_mode != POST_LAZY:
rpm-build 95f51c
			for self.current_group, _ in enumerate(self.groups):
rpm-build 95f51c
				self.post_group()
rpm-build 95f51c
rpm-build 95f51c
		for self.current_group, _ in enumerate(self.groups):
rpm-build 95f51c
			# first post the task generators for the group
rpm-build 95f51c
			if self.post_mode != POST_AT_ONCE:
rpm-build 95f51c
				self.post_group()
rpm-build 95f51c
rpm-build 95f51c
			# then extract the tasks
rpm-build 95f51c
			tasks = self.get_tasks_group(self.current_group)
rpm-build 95f51c
rpm-build 95f51c
			# if the constraints are set properly (ext_in/ext_out, before/after)
rpm-build 95f51c
			# the call to set_file_constraints may be removed (can be a 15% penalty on no-op rebuilds)
rpm-build 95f51c
			# (but leave set_file_constraints for the installation step)
rpm-build 95f51c
			#
rpm-build 95f51c
			# if the tasks have only files, set_file_constraints is required but set_precedence_constraints is not necessary
rpm-build 95f51c
			#
rpm-build 95f51c
			Task.set_file_constraints(tasks)
rpm-build 95f51c
			Task.set_precedence_constraints(tasks)
rpm-build 95f51c
rpm-build 95f51c
			self.cur_tasks = tasks
rpm-build 95f51c
			if tasks:
rpm-build 95f51c
				yield tasks
rpm-build 95f51c
rpm-build 95f51c
		while 1:
rpm-build 95f51c
			# the build stops once there are no tasks to process
rpm-build 95f51c
			yield []
rpm-build 95f51c
rpm-build 95f51c
	def install_files(self, dest, files, **kw):
rpm-build 95f51c
		"""
rpm-build 95f51c
		Creates a task generator to install files on the system::
rpm-build 95f51c
rpm-build 95f51c
			def build(bld):
rpm-build 95f51c
				bld.install_files('${DATADIR}', self.path.find_resource('wscript'))
rpm-build 95f51c
rpm-build 95f51c
		:param dest: path representing the destination directory
rpm-build 95f51c
		:type dest: :py:class:`waflib.Node.Node` or string (absolute path)
rpm-build 95f51c
		:param files: input files
rpm-build 95f51c
		:type files: list of strings or list of :py:class:`waflib.Node.Node`
rpm-build 95f51c
		:param env: configuration set to expand *dest*
rpm-build 95f51c
		:type env: :py:class:`waflib.ConfigSet.ConfigSet`
rpm-build 95f51c
		:param relative_trick: preserve the folder hierarchy when installing whole folders
rpm-build 95f51c
		:type relative_trick: bool
rpm-build 95f51c
		:param cwd: parent node for searching srcfile, when srcfile is not an instance of :py:class:`waflib.Node.Node`
rpm-build 95f51c
		:type cwd: :py:class:`waflib.Node.Node`
rpm-build 95f51c
		:param postpone: execute the task immediately to perform the installation (False by default)
rpm-build 95f51c
		:type postpone: bool
rpm-build 95f51c
		"""
rpm-build 95f51c
		assert(dest)
rpm-build 95f51c
		tg = self(features='install_task', install_to=dest, install_from=files, **kw)
rpm-build 95f51c
		tg.dest = tg.install_to
rpm-build 95f51c
		tg.type = 'install_files'
rpm-build 95f51c
		if not kw.get('postpone', True):
rpm-build 95f51c
			tg.post()
rpm-build 95f51c
		return tg
rpm-build 95f51c
rpm-build 95f51c
	def install_as(self, dest, srcfile, **kw):
rpm-build 95f51c
		"""
rpm-build 95f51c
		Creates a task generator to install a file on the system with a different name::
rpm-build 95f51c
rpm-build 95f51c
			def build(bld):
rpm-build 95f51c
				bld.install_as('${PREFIX}/bin', 'myapp', chmod=Utils.O755)
rpm-build 95f51c
rpm-build 95f51c
		:param dest: destination file
rpm-build 95f51c
		:type dest: :py:class:`waflib.Node.Node` or string (absolute path)
rpm-build 95f51c
		:param srcfile: input file
rpm-build 95f51c
		:type srcfile: string or :py:class:`waflib.Node.Node`
rpm-build 95f51c
		:param cwd: parent node for searching srcfile, when srcfile is not an instance of :py:class:`waflib.Node.Node`
rpm-build 95f51c
		:type cwd: :py:class:`waflib.Node.Node`
rpm-build 95f51c
		:param env: configuration set for performing substitutions in dest
rpm-build 95f51c
		:type env: :py:class:`waflib.ConfigSet.ConfigSet`
rpm-build 95f51c
		:param postpone: execute the task immediately to perform the installation (False by default)
rpm-build 95f51c
		:type postpone: bool
rpm-build 95f51c
		"""
rpm-build 95f51c
		assert(dest)
rpm-build 95f51c
		tg = self(features='install_task', install_to=dest, install_from=srcfile, **kw)
rpm-build 95f51c
		tg.dest = tg.install_to
rpm-build 95f51c
		tg.type = 'install_as'
rpm-build 95f51c
		if not kw.get('postpone', True):
rpm-build 95f51c
			tg.post()
rpm-build 95f51c
		return tg
rpm-build 95f51c
rpm-build 95f51c
	def symlink_as(self, dest, src, **kw):
rpm-build 95f51c
		"""
rpm-build 95f51c
		Creates a task generator to install a symlink::
rpm-build 95f51c
rpm-build 95f51c
			def build(bld):
rpm-build 95f51c
				bld.symlink_as('${PREFIX}/lib/libfoo.so', 'libfoo.so.1.2.3')
rpm-build 95f51c
rpm-build 95f51c
		:param dest: absolute path of the symlink
rpm-build 95f51c
		:type dest: :py:class:`waflib.Node.Node` or string (absolute path)
rpm-build 95f51c
		:param src: link contents, which is a relative or absolute path which may exist or not
rpm-build 95f51c
		:type src: string
rpm-build 95f51c
		:param env: configuration set for performing substitutions in dest
rpm-build 95f51c
		:type env: :py:class:`waflib.ConfigSet.ConfigSet`
rpm-build 95f51c
		:param add: add the task created to a build group - set ``False`` only if the installation task is created after the build has started
rpm-build 95f51c
		:type add: bool
rpm-build 95f51c
		:param postpone: execute the task immediately to perform the installation
rpm-build 95f51c
		:type postpone: bool
rpm-build 95f51c
		:param relative_trick: make the symlink relative (default: ``False``)
rpm-build 95f51c
		:type relative_trick: bool
rpm-build 95f51c
		"""
rpm-build 95f51c
		assert(dest)
rpm-build 95f51c
		tg = self(features='install_task', install_to=dest, install_from=src, **kw)
rpm-build 95f51c
		tg.dest = tg.install_to
rpm-build 95f51c
		tg.type = 'symlink_as'
rpm-build 95f51c
		tg.link = src
rpm-build 95f51c
		# TODO if add: self.add_to_group(tsk)
rpm-build 95f51c
		if not kw.get('postpone', True):
rpm-build 95f51c
			tg.post()
rpm-build 95f51c
		return tg
rpm-build 95f51c
rpm-build 95f51c
@TaskGen.feature('install_task')
rpm-build 95f51c
@TaskGen.before_method('process_rule', 'process_source')
rpm-build 95f51c
def process_install_task(self):
rpm-build 95f51c
	"""Creates the installation task for the current task generator; uses :py:func:`waflib.Build.add_install_task` internally."""
rpm-build 95f51c
	self.add_install_task(**self.__dict__)
rpm-build 95f51c
rpm-build 95f51c
@TaskGen.taskgen_method
rpm-build 95f51c
def add_install_task(self, **kw):
rpm-build 95f51c
	"""
rpm-build 95f51c
	Creates the installation task for the current task generator, and executes it immediately if necessary
rpm-build 95f51c
rpm-build 95f51c
	:returns: An installation task
rpm-build 95f51c
	:rtype: :py:class:`waflib.Build.inst`
rpm-build 95f51c
	"""
rpm-build 95f51c
	if not self.bld.is_install:
rpm-build 95f51c
		return
rpm-build 95f51c
	if not kw['install_to']:
rpm-build 95f51c
		return
rpm-build 95f51c
rpm-build 95f51c
	if kw['type'] == 'symlink_as' and Utils.is_win32:
rpm-build 95f51c
		if kw.get('win32_install'):
rpm-build 95f51c
			kw['type'] = 'install_as'
rpm-build 95f51c
		else:
rpm-build 95f51c
			# just exit
rpm-build 95f51c
			return
rpm-build 95f51c
rpm-build 95f51c
	tsk = self.install_task = self.create_task('inst')
rpm-build 95f51c
	tsk.chmod = kw.get('chmod', Utils.O644)
rpm-build 95f51c
	tsk.link = kw.get('link', '') or kw.get('install_from', '')
rpm-build 95f51c
	tsk.relative_trick = kw.get('relative_trick', False)
rpm-build 95f51c
	tsk.type = kw['type']
rpm-build 95f51c
	tsk.install_to = tsk.dest = kw['install_to']
rpm-build 95f51c
	tsk.install_from = kw['install_from']
rpm-build 95f51c
	tsk.relative_base = kw.get('cwd') or kw.get('relative_base', self.path)
rpm-build 95f51c
	tsk.install_user = kw.get('install_user')
rpm-build 95f51c
	tsk.install_group = kw.get('install_group')
rpm-build 95f51c
	tsk.init_files()
rpm-build 95f51c
	if not kw.get('postpone', True):
rpm-build 95f51c
		tsk.run_now()
rpm-build 95f51c
	return tsk
rpm-build 95f51c
rpm-build 95f51c
@TaskGen.taskgen_method
rpm-build 95f51c
def add_install_files(self, **kw):
rpm-build 95f51c
	"""
rpm-build 95f51c
	Creates an installation task for files
rpm-build 95f51c
rpm-build 95f51c
	:returns: An installation task
rpm-build 95f51c
	:rtype: :py:class:`waflib.Build.inst`
rpm-build 95f51c
	"""
rpm-build 95f51c
	kw['type'] = 'install_files'
rpm-build 95f51c
	return self.add_install_task(**kw)
rpm-build 95f51c
rpm-build 95f51c
@TaskGen.taskgen_method
rpm-build 95f51c
def add_install_as(self, **kw):
rpm-build 95f51c
	"""
rpm-build 95f51c
	Creates an installation task for a single file
rpm-build 95f51c
rpm-build 95f51c
	:returns: An installation task
rpm-build 95f51c
	:rtype: :py:class:`waflib.Build.inst`
rpm-build 95f51c
	"""
rpm-build 95f51c
	kw['type'] = 'install_as'
rpm-build 95f51c
	return self.add_install_task(**kw)
rpm-build 95f51c
rpm-build 95f51c
@TaskGen.taskgen_method
rpm-build 95f51c
def add_symlink_as(self, **kw):
rpm-build 95f51c
	"""
rpm-build 95f51c
	Creates an installation task for a symbolic link
rpm-build 95f51c
rpm-build 95f51c
	:returns: An installation task
rpm-build 95f51c
	:rtype: :py:class:`waflib.Build.inst`
rpm-build 95f51c
	"""
rpm-build 95f51c
	kw['type'] = 'symlink_as'
rpm-build 95f51c
	return self.add_install_task(**kw)
rpm-build 95f51c
rpm-build 95f51c
class inst(Task.Task):
rpm-build 95f51c
	"""Task that installs files or symlinks; it is typically executed by :py:class:`waflib.Build.InstallContext` and :py:class:`waflib.Build.UnInstallContext`"""
rpm-build 95f51c
	def __str__(self):
rpm-build 95f51c
		"""Returns an empty string to disable the standard task display"""
rpm-build 95f51c
		return ''
rpm-build 95f51c
rpm-build 95f51c
	def uid(self):
rpm-build 95f51c
		"""Returns a unique identifier for the task"""
rpm-build 95f51c
		lst = self.inputs + self.outputs + [self.link, self.generator.path.abspath()]
rpm-build 95f51c
		return Utils.h_list(lst)
rpm-build 95f51c
rpm-build 95f51c
	def init_files(self):
rpm-build 95f51c
		"""
rpm-build 95f51c
		Initializes the task input and output nodes
rpm-build 95f51c
		"""
rpm-build 95f51c
		if self.type == 'symlink_as':
rpm-build 95f51c
			inputs = []
rpm-build 95f51c
		else:
rpm-build 95f51c
			inputs = self.generator.to_nodes(self.install_from)
rpm-build 95f51c
			if self.type == 'install_as':
rpm-build 95f51c
				assert len(inputs) == 1
rpm-build 95f51c
		self.set_inputs(inputs)
rpm-build 95f51c
rpm-build 95f51c
		dest = self.get_install_path()
rpm-build 95f51c
		outputs = []
rpm-build 95f51c
		if self.type == 'symlink_as':
rpm-build 95f51c
			if self.relative_trick:
rpm-build 95f51c
				self.link = os.path.relpath(self.link, os.path.dirname(dest))
rpm-build 95f51c
			outputs.append(self.generator.bld.root.make_node(dest))
rpm-build 95f51c
		elif self.type == 'install_as':
rpm-build 95f51c
			outputs.append(self.generator.bld.root.make_node(dest))
rpm-build 95f51c
		else:
rpm-build 95f51c
			for y in inputs:
rpm-build 95f51c
				if self.relative_trick:
rpm-build 95f51c
					destfile = os.path.join(dest, y.path_from(self.relative_base))
rpm-build 95f51c
				else:
rpm-build 95f51c
					destfile = os.path.join(dest, y.name)
rpm-build 95f51c
				outputs.append(self.generator.bld.root.make_node(destfile))
rpm-build 95f51c
		self.set_outputs(outputs)
rpm-build 95f51c
rpm-build 95f51c
	def runnable_status(self):
rpm-build 95f51c
		"""
rpm-build 95f51c
		Installation tasks are always executed, so this method returns either :py:const:`waflib.Task.ASK_LATER` or :py:const:`waflib.Task.RUN_ME`.
rpm-build 95f51c
		"""
rpm-build 95f51c
		ret = super(inst, self).runnable_status()
rpm-build 95f51c
		if ret == Task.SKIP_ME and self.generator.bld.is_install:
rpm-build 95f51c
			return Task.RUN_ME
rpm-build 95f51c
		return ret
rpm-build 95f51c
rpm-build 95f51c
	def post_run(self):
rpm-build 95f51c
		"""
rpm-build 95f51c
		Disables any post-run operations
rpm-build 95f51c
		"""
rpm-build 95f51c
		pass
rpm-build 95f51c
rpm-build 95f51c
	def get_install_path(self, destdir=True):
rpm-build 95f51c
		"""
rpm-build 95f51c
		Returns the destination path where files will be installed, pre-pending `destdir`.
rpm-build 95f51c
rpm-build 95f51c
		Relative paths will be interpreted relative to `PREFIX` if no `destdir` is given.
rpm-build 95f51c
rpm-build 95f51c
		:rtype: string
rpm-build 95f51c
		"""
rpm-build 95f51c
		if isinstance(self.install_to, Node.Node):
rpm-build 95f51c
			dest = self.install_to.abspath()
rpm-build 95f51c
		else:
rpm-build 95f51c
			dest = os.path.normpath(Utils.subst_vars(self.install_to, self.env))
rpm-build 95f51c
		if not os.path.isabs(dest):
rpm-build 95f51c
		    dest = os.path.join(self.env.PREFIX, dest)
rpm-build 95f51c
		if destdir and Options.options.destdir:
rpm-build 95f51c
			dest = os.path.join(Options.options.destdir, os.path.splitdrive(dest)[1].lstrip(os.sep))
rpm-build 95f51c
		return dest
rpm-build 95f51c
rpm-build 95f51c
	def copy_fun(self, src, tgt):
rpm-build 95f51c
		"""
rpm-build 95f51c
		Copies a file from src to tgt, preserving permissions and trying to work
rpm-build 95f51c
		around path limitations on Windows platforms. On Unix-like platforms,
rpm-build 95f51c
		the owner/group of the target file may be set through install_user/install_group
rpm-build 95f51c
rpm-build 95f51c
		:param src: absolute path
rpm-build 95f51c
		:type src: string
rpm-build 95f51c
		:param tgt: absolute path
rpm-build 95f51c
		:type tgt: string
rpm-build 95f51c
		"""
rpm-build 95f51c
		# override this if you want to strip executables
rpm-build 95f51c
		# kw['tsk'].source is the task that created the files in the build
rpm-build 95f51c
		if Utils.is_win32 and len(tgt) > 259 and not tgt.startswith('\\\\?\\'):
rpm-build 95f51c
			tgt = '\\\\?\\' + tgt
rpm-build 95f51c
		shutil.copy2(src, tgt)
rpm-build 95f51c
		self.fix_perms(tgt)
rpm-build 95f51c
rpm-build 95f51c
	def rm_empty_dirs(self, tgt):
rpm-build 95f51c
		"""
rpm-build 95f51c
		Removes empty folders recursively when uninstalling.
rpm-build 95f51c
rpm-build 95f51c
		:param tgt: absolute path
rpm-build 95f51c
		:type tgt: string
rpm-build 95f51c
		"""
rpm-build 95f51c
		while tgt:
rpm-build 95f51c
			tgt = os.path.dirname(tgt)
rpm-build 95f51c
			try:
rpm-build 95f51c
				os.rmdir(tgt)
rpm-build 95f51c
			except OSError:
rpm-build 95f51c
				break
rpm-build 95f51c
rpm-build 95f51c
	def run(self):
rpm-build 95f51c
		"""
rpm-build 95f51c
		Performs file or symlink installation
rpm-build 95f51c
		"""
rpm-build 95f51c
		is_install = self.generator.bld.is_install
rpm-build 95f51c
		if not is_install: # unnecessary?
rpm-build 95f51c
			return
rpm-build 95f51c
rpm-build 95f51c
		for x in self.outputs:
rpm-build 95f51c
			if is_install == INSTALL:
rpm-build 95f51c
				x.parent.mkdir()
rpm-build 95f51c
		if self.type == 'symlink_as':
rpm-build 95f51c
			fun = is_install == INSTALL and self.do_link or self.do_unlink
rpm-build 95f51c
			fun(self.link, self.outputs[0].abspath())
rpm-build 95f51c
		else:
rpm-build 95f51c
			fun = is_install == INSTALL and self.do_install or self.do_uninstall
rpm-build 95f51c
			launch_node = self.generator.bld.launch_node()
rpm-build 95f51c
			for x, y in zip(self.inputs, self.outputs):
rpm-build 95f51c
				fun(x.abspath(), y.abspath(), x.path_from(launch_node))
rpm-build 95f51c
rpm-build 95f51c
	def run_now(self):
rpm-build 95f51c
		"""
rpm-build 95f51c
		Try executing the installation task right now
rpm-build 95f51c
rpm-build 95f51c
		:raises: :py:class:`waflib.Errors.TaskNotReady`
rpm-build 95f51c
		"""
rpm-build 95f51c
		status = self.runnable_status()
rpm-build 95f51c
		if status not in (Task.RUN_ME, Task.SKIP_ME):
rpm-build 95f51c
			raise Errors.TaskNotReady('Could not process %r: status %r' % (self, status))
rpm-build 95f51c
		self.run()
rpm-build 95f51c
		self.hasrun = Task.SUCCESS
rpm-build 95f51c
rpm-build 95f51c
	def do_install(self, src, tgt, lbl, **kw):
rpm-build 95f51c
		"""
rpm-build 95f51c
		Copies a file from src to tgt with given file permissions. The actual copy is only performed
rpm-build 95f51c
		if the source and target file sizes or timestamps differ. When the copy occurs,
rpm-build 95f51c
		the file is always first removed and then copied so as to prevent stale inodes.
rpm-build 95f51c
rpm-build 95f51c
		:param src: file name as absolute path
rpm-build 95f51c
		:type src: string
rpm-build 95f51c
		:param tgt: file destination, as absolute path
rpm-build 95f51c
		:type tgt: string
rpm-build 95f51c
		:param lbl: file source description
rpm-build 95f51c
		:type lbl: string
rpm-build 95f51c
		:param chmod: installation mode
rpm-build 95f51c
		:type chmod: int
rpm-build 95f51c
		:raises: :py:class:`waflib.Errors.WafError` if the file cannot be written
rpm-build 95f51c
		"""
rpm-build 95f51c
		if not Options.options.force:
rpm-build 95f51c
			# check if the file is already there to avoid a copy
rpm-build 95f51c
			try:
rpm-build 95f51c
				st1 = os.stat(tgt)
rpm-build 95f51c
				st2 = os.stat(src)
rpm-build 95f51c
			except OSError:
rpm-build 95f51c
				pass
rpm-build 95f51c
			else:
rpm-build 95f51c
				# same size and identical timestamps -> make no copy
rpm-build 95f51c
				if st1.st_mtime + 2 >= st2.st_mtime and st1.st_size == st2.st_size:
rpm-build 95f51c
					if not self.generator.bld.progress_bar:
rpm-build 95f51c
rpm-build 95f51c
						c1 = Logs.colors.NORMAL
rpm-build 95f51c
						c2 = Logs.colors.BLUE
rpm-build 95f51c
rpm-build 95f51c
						Logs.info('%s- install %s%s%s (from %s)', c1, c2, tgt, c1, lbl)
rpm-build 95f51c
					return False
rpm-build 95f51c
rpm-build 95f51c
		if not self.generator.bld.progress_bar:
rpm-build 95f51c
rpm-build 95f51c
			c1 = Logs.colors.NORMAL
rpm-build 95f51c
			c2 = Logs.colors.BLUE
rpm-build 95f51c
rpm-build 95f51c
			Logs.info('%s+ install %s%s%s (from %s)', c1, c2, tgt, c1, lbl)
rpm-build 95f51c
rpm-build 95f51c
		# Give best attempt at making destination overwritable,
rpm-build 95f51c
		# like the 'install' utility used by 'make install' does.
rpm-build 95f51c
		try:
rpm-build 95f51c
			os.chmod(tgt, Utils.O644 | stat.S_IMODE(os.stat(tgt).st_mode))
rpm-build 95f51c
		except EnvironmentError:
rpm-build 95f51c
			pass
rpm-build 95f51c
rpm-build 95f51c
		# following is for shared libs and stale inodes (-_-)
rpm-build 95f51c
		try:
rpm-build 95f51c
			os.remove(tgt)
rpm-build 95f51c
		except OSError:
rpm-build 95f51c
			pass
rpm-build 95f51c
rpm-build 95f51c
		try:
rpm-build 95f51c
			self.copy_fun(src, tgt)
rpm-build 95f51c
		except EnvironmentError as e:
rpm-build 95f51c
			if not os.path.exists(src):
rpm-build 95f51c
				Logs.error('File %r does not exist', src)
rpm-build 95f51c
			elif not os.path.isfile(src):
rpm-build 95f51c
				Logs.error('Input %r is not a file', src)
rpm-build 95f51c
			raise Errors.WafError('Could not install the file %r' % tgt, e)
rpm-build 95f51c
rpm-build 95f51c
	def fix_perms(self, tgt):
rpm-build 95f51c
		"""
rpm-build 95f51c
		Change the ownership of the file/folder/link pointed by the given path
rpm-build 95f51c
		This looks up for `install_user` or `install_group` attributes
rpm-build 95f51c
		on the task or on the task generator::
rpm-build 95f51c
rpm-build 95f51c
			def build(bld):
rpm-build 95f51c
				bld.install_as('${PREFIX}/wscript',
rpm-build 95f51c
					'wscript',
rpm-build 95f51c
					install_user='nobody', install_group='nogroup')
rpm-build 95f51c
				bld.symlink_as('${PREFIX}/wscript_link',
rpm-build 95f51c
					Utils.subst_vars('${PREFIX}/wscript', bld.env),
rpm-build 95f51c
					install_user='nobody', install_group='nogroup')
rpm-build 95f51c
		"""
rpm-build 95f51c
		if not Utils.is_win32:
rpm-build 95f51c
			user = getattr(self, 'install_user', None) or getattr(self.generator, 'install_user', None)
rpm-build 95f51c
			group = getattr(self, 'install_group', None) or getattr(self.generator, 'install_group', None)
rpm-build 95f51c
			if user or group:
rpm-build 95f51c
				Utils.lchown(tgt, user or -1, group or -1)
rpm-build 95f51c
		if not os.path.islink(tgt):
rpm-build 95f51c
			os.chmod(tgt, self.chmod)
rpm-build 95f51c
rpm-build 95f51c
	def do_link(self, src, tgt, **kw):
rpm-build 95f51c
		"""
rpm-build 95f51c
		Creates a symlink from tgt to src.
rpm-build 95f51c
rpm-build 95f51c
		:param src: file name as absolute path
rpm-build 95f51c
		:type src: string
rpm-build 95f51c
		:param tgt: file destination, as absolute path
rpm-build 95f51c
		:type tgt: string
rpm-build 95f51c
		"""
rpm-build 95f51c
		if os.path.islink(tgt) and os.readlink(tgt) == src:
rpm-build 95f51c
			if not self.generator.bld.progress_bar:
rpm-build 95f51c
				c1 = Logs.colors.NORMAL
rpm-build 95f51c
				c2 = Logs.colors.BLUE
rpm-build 95f51c
				Logs.info('%s- symlink %s%s%s (to %s)', c1, c2, tgt, c1, src)
rpm-build 95f51c
		else:
rpm-build 95f51c
			try:
rpm-build 95f51c
				os.remove(tgt)
rpm-build 95f51c
			except OSError:
rpm-build 95f51c
				pass
rpm-build 95f51c
			if not self.generator.bld.progress_bar:
rpm-build 95f51c
				c1 = Logs.colors.NORMAL
rpm-build 95f51c
				c2 = Logs.colors.BLUE
rpm-build 95f51c
				Logs.info('%s+ symlink %s%s%s (to %s)', c1, c2, tgt, c1, src)
rpm-build 95f51c
			os.symlink(src, tgt)
rpm-build 95f51c
			self.fix_perms(tgt)
rpm-build 95f51c
rpm-build 95f51c
	def do_uninstall(self, src, tgt, lbl, **kw):
rpm-build 95f51c
		"""
rpm-build 95f51c
		See :py:meth:`waflib.Build.inst.do_install`
rpm-build 95f51c
		"""
rpm-build 95f51c
		if not self.generator.bld.progress_bar:
rpm-build 95f51c
			c1 = Logs.colors.NORMAL
rpm-build 95f51c
			c2 = Logs.colors.BLUE
rpm-build 95f51c
			Logs.info('%s- remove %s%s%s', c1, c2, tgt, c1)
rpm-build 95f51c
rpm-build 95f51c
		#self.uninstall.append(tgt)
rpm-build 95f51c
		try:
rpm-build 95f51c
			os.remove(tgt)
rpm-build 95f51c
		except OSError as e:
rpm-build 95f51c
			if e.errno != errno.ENOENT:
rpm-build 95f51c
				if not getattr(self, 'uninstall_error', None):
rpm-build 95f51c
					self.uninstall_error = True
rpm-build 95f51c
					Logs.warn('build: some files could not be uninstalled (retry with -vv to list them)')
rpm-build 95f51c
				if Logs.verbose > 1:
rpm-build 95f51c
					Logs.warn('Could not remove %s (error code %r)', e.filename, e.errno)
rpm-build 95f51c
		self.rm_empty_dirs(tgt)
rpm-build 95f51c
rpm-build 95f51c
	def do_unlink(self, src, tgt, **kw):
rpm-build 95f51c
		"""
rpm-build 95f51c
		See :py:meth:`waflib.Build.inst.do_link`
rpm-build 95f51c
		"""
rpm-build 95f51c
		try:
rpm-build 95f51c
			if not self.generator.bld.progress_bar:
rpm-build 95f51c
				c1 = Logs.colors.NORMAL
rpm-build 95f51c
				c2 = Logs.colors.BLUE
rpm-build 95f51c
				Logs.info('%s- remove %s%s%s', c1, c2, tgt, c1)
rpm-build 95f51c
			os.remove(tgt)
rpm-build 95f51c
		except OSError:
rpm-build 95f51c
			pass
rpm-build 95f51c
		self.rm_empty_dirs(tgt)
rpm-build 95f51c
rpm-build 95f51c
class InstallContext(BuildContext):
rpm-build 95f51c
	'''installs the targets on the system'''
rpm-build 95f51c
	cmd = 'install'
rpm-build 95f51c
rpm-build 95f51c
	def __init__(self, **kw):
rpm-build 95f51c
		super(InstallContext, self).__init__(**kw)
rpm-build 95f51c
		self.is_install = INSTALL
rpm-build 95f51c
rpm-build 95f51c
class UninstallContext(InstallContext):
rpm-build 95f51c
	'''removes the targets installed'''
rpm-build 95f51c
	cmd = 'uninstall'
rpm-build 95f51c
rpm-build 95f51c
	def __init__(self, **kw):
rpm-build 95f51c
		super(UninstallContext, self).__init__(**kw)
rpm-build 95f51c
		self.is_install = UNINSTALL
rpm-build 95f51c
rpm-build 95f51c
class CleanContext(BuildContext):
rpm-build 95f51c
	'''cleans the project'''
rpm-build 95f51c
	cmd = 'clean'
rpm-build 95f51c
	def execute(self):
rpm-build 95f51c
		"""
rpm-build 95f51c
		See :py:func:`waflib.Build.BuildContext.execute`.
rpm-build 95f51c
		"""
rpm-build 95f51c
		self.restore()
rpm-build 95f51c
		if not self.all_envs:
rpm-build 95f51c
			self.load_envs()
rpm-build 95f51c
rpm-build 95f51c
		self.recurse([self.run_dir])
rpm-build 95f51c
		try:
rpm-build 95f51c
			self.clean()
rpm-build 95f51c
		finally:
rpm-build 95f51c
			self.store()
rpm-build 95f51c
rpm-build 95f51c
	def clean(self):
rpm-build 95f51c
		"""
rpm-build 95f51c
		Remove most files from the build directory, and reset all caches.
rpm-build 95f51c
rpm-build 95f51c
		Custom lists of files to clean can be declared as `bld.clean_files`.
rpm-build 95f51c
		For example, exclude `build/program/myprogram` from getting removed::
rpm-build 95f51c
rpm-build 95f51c
			def build(bld):
rpm-build 95f51c
				bld.clean_files = bld.bldnode.ant_glob('**',
rpm-build 95f51c
					excl='.lock* config.log c4che/* config.h program/myprogram',
rpm-build 95f51c
					quiet=True, generator=True)
rpm-build 95f51c
		"""
rpm-build 95f51c
		Logs.debug('build: clean called')
rpm-build 95f51c
rpm-build 95f51c
		if hasattr(self, 'clean_files'):
rpm-build 95f51c
			for n in self.clean_files:
rpm-build 95f51c
				n.delete()
rpm-build 95f51c
		elif self.bldnode != self.srcnode:
rpm-build 95f51c
			# would lead to a disaster if top == out
rpm-build 95f51c
			lst = []
rpm-build 95f51c
			for env in self.all_envs.values():
rpm-build 95f51c
				lst.extend(self.root.find_or_declare(f) for f in env[CFG_FILES])
rpm-build 95f51c
			excluded_dirs = '.lock* *conf_check_*/** config.log %s/*' % CACHE_DIR
rpm-build 95f51c
			for n in self.bldnode.ant_glob('**/*', excl=excluded_dirs, quiet=True):
rpm-build 95f51c
				if n in lst:
rpm-build 95f51c
					continue
rpm-build 95f51c
				n.delete()
rpm-build 95f51c
		self.root.children = {}
rpm-build 95f51c
rpm-build 95f51c
		for v in SAVED_ATTRS:
rpm-build 95f51c
			if v == 'root':
rpm-build 95f51c
				continue
rpm-build 95f51c
			setattr(self, v, {})
rpm-build 95f51c
rpm-build 95f51c
class ListContext(BuildContext):
rpm-build 95f51c
	'''lists the targets to execute'''
rpm-build 95f51c
	cmd = 'list'
rpm-build 95f51c
rpm-build 95f51c
	def execute(self):
rpm-build 95f51c
		"""
rpm-build 95f51c
		In addition to printing the name of each build target,
rpm-build 95f51c
		a description column will include text for each task
rpm-build 95f51c
		generator which has a "description" field set.
rpm-build 95f51c
rpm-build 95f51c
		See :py:func:`waflib.Build.BuildContext.execute`.
rpm-build 95f51c
		"""
rpm-build 95f51c
		self.restore()
rpm-build 95f51c
		if not self.all_envs:
rpm-build 95f51c
			self.load_envs()
rpm-build 95f51c
rpm-build 95f51c
		self.recurse([self.run_dir])
rpm-build 95f51c
		self.pre_build()
rpm-build 95f51c
rpm-build 95f51c
		# display the time elapsed in the progress bar
rpm-build 95f51c
		self.timer = Utils.Timer()
rpm-build 95f51c
rpm-build 95f51c
		for g in self.groups:
rpm-build 95f51c
			for tg in g:
rpm-build 95f51c
				try:
rpm-build 95f51c
					f = tg.post
rpm-build 95f51c
				except AttributeError:
rpm-build 95f51c
					pass
rpm-build 95f51c
				else:
rpm-build 95f51c
					f()
rpm-build 95f51c
rpm-build 95f51c
		try:
rpm-build 95f51c
			# force the cache initialization
rpm-build 95f51c
			self.get_tgen_by_name('')
rpm-build 95f51c
		except Errors.WafError:
rpm-build 95f51c
			pass
rpm-build 95f51c
rpm-build 95f51c
		targets = sorted(self.task_gen_cache_names)
rpm-build 95f51c
rpm-build 95f51c
		# figure out how much to left-justify, for largest target name
rpm-build 95f51c
		line_just = max(len(t) for t in targets) if targets else 0
rpm-build 95f51c
rpm-build 95f51c
		for target in targets:
rpm-build 95f51c
			tgen = self.task_gen_cache_names[target]
rpm-build 95f51c
rpm-build 95f51c
			# Support displaying the description for the target
rpm-build 95f51c
			# if it was set on the tgen
rpm-build 95f51c
			descript = getattr(tgen, 'description', '')
rpm-build 95f51c
			if descript:
rpm-build 95f51c
				target = target.ljust(line_just)
rpm-build 95f51c
				descript = ': %s' % descript
rpm-build 95f51c
rpm-build 95f51c
			Logs.pprint('GREEN', target, label=descript)
rpm-build 95f51c
rpm-build 95f51c
class StepContext(BuildContext):
rpm-build 95f51c
	'''executes tasks in a step-by-step fashion, for debugging'''
rpm-build 95f51c
	cmd = 'step'
rpm-build 95f51c
rpm-build 95f51c
	def __init__(self, **kw):
rpm-build 95f51c
		super(StepContext, self).__init__(**kw)
rpm-build 95f51c
		self.files = Options.options.files
rpm-build 95f51c
rpm-build 95f51c
	def compile(self):
rpm-build 95f51c
		"""
rpm-build 95f51c
		Overrides :py:meth:`waflib.Build.BuildContext.compile` to perform a partial build
rpm-build 95f51c
		on tasks matching the input/output pattern given (regular expression matching)::
rpm-build 95f51c
rpm-build 95f51c
			$ waf step --files=foo.c,bar.c,in:truc.c,out:bar.o
rpm-build 95f51c
			$ waf step --files=in:foo.cpp.1.o # link task only
rpm-build 95f51c
rpm-build 95f51c
		"""
rpm-build 95f51c
		if not self.files:
rpm-build 95f51c
			Logs.warn('Add a pattern for the debug build, for example "waf step --files=main.c,app"')
rpm-build 95f51c
			BuildContext.compile(self)
rpm-build 95f51c
			return
rpm-build 95f51c
rpm-build 95f51c
		targets = []
rpm-build 95f51c
		if self.targets and self.targets != '*':
rpm-build 95f51c
			targets = self.targets.split(',')
rpm-build 95f51c
rpm-build 95f51c
		for g in self.groups:
rpm-build 95f51c
			for tg in g:
rpm-build 95f51c
				if targets and tg.name not in targets:
rpm-build 95f51c
					continue
rpm-build 95f51c
rpm-build 95f51c
				try:
rpm-build 95f51c
					f = tg.post
rpm-build 95f51c
				except AttributeError:
rpm-build 95f51c
					pass
rpm-build 95f51c
				else:
rpm-build 95f51c
					f()
rpm-build 95f51c
rpm-build 95f51c
			for pat in self.files.split(','):
rpm-build 95f51c
				matcher = self.get_matcher(pat)
rpm-build 95f51c
				for tg in g:
rpm-build 95f51c
					if isinstance(tg, Task.Task):
rpm-build 95f51c
						lst = [tg]
rpm-build 95f51c
					else:
rpm-build 95f51c
						lst = tg.tasks
rpm-build 95f51c
					for tsk in lst:
rpm-build 95f51c
						do_exec = False
rpm-build 95f51c
						for node in tsk.inputs:
rpm-build 95f51c
							if matcher(node, output=False):
rpm-build 95f51c
								do_exec = True
rpm-build 95f51c
								break
rpm-build 95f51c
						for node in tsk.outputs:
rpm-build 95f51c
							if matcher(node, output=True):
rpm-build 95f51c
								do_exec = True
rpm-build 95f51c
								break
rpm-build 95f51c
						if do_exec:
rpm-build 95f51c
							ret = tsk.run()
rpm-build 95f51c
							Logs.info('%s -> exit %r', tsk, ret)
rpm-build 95f51c
rpm-build 95f51c
	def get_matcher(self, pat):
rpm-build 95f51c
		"""
rpm-build 95f51c
		Converts a step pattern into a function
rpm-build 95f51c
rpm-build 95f51c
		:param: pat: pattern of the form in:truc.c,out:bar.o
rpm-build 95f51c
		:returns: Python function that uses Node objects as inputs and returns matches
rpm-build 95f51c
		:rtype: function
rpm-build 95f51c
		"""
rpm-build 95f51c
		# this returns a function
rpm-build 95f51c
		inn = True
rpm-build 95f51c
		out = True
rpm-build 95f51c
		if pat.startswith('in:'):
rpm-build 95f51c
			out = False
rpm-build 95f51c
			pat = pat.replace('in:', '')
rpm-build 95f51c
		elif pat.startswith('out:'):
rpm-build 95f51c
			inn = False
rpm-build 95f51c
			pat = pat.replace('out:', '')
rpm-build 95f51c
rpm-build 95f51c
		anode = self.root.find_node(pat)
rpm-build 95f51c
		pattern = None
rpm-build 95f51c
		if not anode:
rpm-build 95f51c
			if not pat.startswith('^'):
rpm-build 95f51c
				pat = '^.+?%s' % pat
rpm-build 95f51c
			if not pat.endswith('$'):
rpm-build 95f51c
				pat = '%s$' % pat
rpm-build 95f51c
			pattern = re.compile(pat)
rpm-build 95f51c
rpm-build 95f51c
		def match(node, output):
rpm-build 95f51c
			if output and not out:
rpm-build 95f51c
				return False
rpm-build 95f51c
			if not output and not inn:
rpm-build 95f51c
				return False
rpm-build 95f51c
rpm-build 95f51c
			if anode:
rpm-build 95f51c
				return anode == node
rpm-build 95f51c
			else:
rpm-build 95f51c
				return pattern.match(node.abspath())
rpm-build 95f51c
		return match
rpm-build 95f51c
rpm-build 95f51c
class EnvContext(BuildContext):
rpm-build 95f51c
	"""Subclass EnvContext to create commands that require configuration data in 'env'"""
rpm-build 95f51c
	fun = cmd = None
rpm-build 95f51c
	def execute(self):
rpm-build 95f51c
		"""
rpm-build 95f51c
		See :py:func:`waflib.Build.BuildContext.execute`.
rpm-build 95f51c
		"""
rpm-build 95f51c
		self.restore()
rpm-build 95f51c
		if not self.all_envs:
rpm-build 95f51c
			self.load_envs()
rpm-build 95f51c
		self.recurse([self.run_dir])
rpm-build 95f51c