waf

FORK: waf with some random patches
git clone https://git.neptards.moe/neptards/waf.git
Log | Files | Refs | README

Configure.py (19198B)


      1 #!/usr/bin/env python
      2 # encoding: utf-8
      3 # Thomas Nagy, 2005-2018 (ita)
      4 
      5 """
      6 Configuration system
      7 
      8 A :py:class:`waflib.Configure.ConfigurationContext` instance is created when ``waf configure`` is called, it is used to:
      9 
     10 * create data dictionaries (ConfigSet instances)
     11 * store the list of modules to import
     12 * hold configuration routines such as ``find_program``, etc
     13 """
     14 
     15 import os, re, shlex, shutil, sys, time, traceback
     16 from waflib import ConfigSet, Utils, Options, Logs, Context, Build, Errors
     17 
     18 WAF_CONFIG_LOG = 'config.log'
     19 """Name of the configuration log file"""
     20 
     21 autoconfig = False
     22 """Execute the configuration automatically"""
     23 
     24 conf_template = '''# project %(app)s configured on %(now)s by
     25 # waf %(wafver)s (abi %(abi)s, python %(pyver)x on %(systype)s)
     26 # using %(args)s
     27 #'''
     28 
     29 class ConfigurationContext(Context.Context):
     30 	'''configures the project'''
     31 
     32 	cmd = 'configure'
     33 
     34 	error_handlers = []
     35 	"""
     36 	Additional functions to handle configuration errors
     37 	"""
     38 
     39 	def __init__(self, **kw):
     40 		super(ConfigurationContext, self).__init__(**kw)
     41 		self.environ = dict(os.environ)
     42 		self.all_envs = {}
     43 
     44 		self.top_dir = None
     45 		self.out_dir = None
     46 
     47 		self.tools = [] # tools loaded in the configuration, and that will be loaded when building
     48 
     49 		self.hash = 0
     50 		self.files = []
     51 
     52 		self.tool_cache = []
     53 
     54 		self.setenv('')
     55 
     56 	def setenv(self, name, env=None):
     57 		"""
     58 		Set a new config set for conf.env. If a config set of that name already exists,
     59 		recall it without modification.
     60 
     61 		The name is the filename prefix to save to ``c4che/NAME_cache.py``, and it
     62 		is also used as *variants* by the build commands.
     63 		Though related to variants, whatever kind of data may be stored in the config set::
     64 
     65 			def configure(cfg):
     66 				cfg.env.ONE = 1
     67 				cfg.setenv('foo')
     68 				cfg.env.ONE = 2
     69 
     70 			def build(bld):
     71 				2 == bld.env_of_name('foo').ONE
     72 
     73 		:param name: name of the configuration set
     74 		:type name: string
     75 		:param env: ConfigSet to copy, or an empty ConfigSet is created
     76 		:type env: :py:class:`waflib.ConfigSet.ConfigSet`
     77 		"""
     78 		if name not in self.all_envs or env:
     79 			if not env:
     80 				env = ConfigSet.ConfigSet()
     81 				self.prepare_env(env)
     82 			else:
     83 				env = env.derive()
     84 			self.all_envs[name] = env
     85 		self.variant = name
     86 
     87 	def get_env(self):
     88 		"""Getter for the env property"""
     89 		return self.all_envs[self.variant]
     90 	def set_env(self, val):
     91 		"""Setter for the env property"""
     92 		self.all_envs[self.variant] = val
     93 
     94 	env = property(get_env, set_env)
     95 
     96 	def init_dirs(self):
     97 		"""
     98 		Initialize the project directory and the build directory
     99 		"""
    100 
    101 		top = self.top_dir
    102 		if not top:
    103 			top = Options.options.top
    104 		if not top:
    105 			top = getattr(Context.g_module, Context.TOP, None)
    106 		if not top:
    107 			top = self.path.abspath()
    108 		top = os.path.abspath(top)
    109 
    110 		self.srcnode = (os.path.isabs(top) and self.root or self.path).find_dir(top)
    111 		assert(self.srcnode)
    112 
    113 		out = self.out_dir
    114 		if not out:
    115 			out = Options.options.out
    116 		if not out:
    117 			out = getattr(Context.g_module, Context.OUT, None)
    118 		if not out:
    119 			out = Options.lockfile.replace('.lock-waf_%s_' % sys.platform, '').replace('.lock-waf', '')
    120 
    121 		# someone can be messing with symlinks
    122 		out = os.path.realpath(out)
    123 
    124 		self.bldnode = (os.path.isabs(out) and self.root or self.path).make_node(out)
    125 		self.bldnode.mkdir()
    126 
    127 		if not os.path.isdir(self.bldnode.abspath()):
    128 			self.fatal('Could not create the build directory %s' % self.bldnode.abspath())
    129 
    130 	def execute(self):
    131 		"""
    132 		See :py:func:`waflib.Context.Context.execute`
    133 		"""
    134 		self.init_dirs()
    135 
    136 		self.cachedir = self.bldnode.make_node(Build.CACHE_DIR)
    137 		self.cachedir.mkdir()
    138 
    139 		path = os.path.join(self.bldnode.abspath(), WAF_CONFIG_LOG)
    140 		self.logger = Logs.make_logger(path, 'cfg')
    141 
    142 		app = getattr(Context.g_module, 'APPNAME', '')
    143 		if app:
    144 			ver = getattr(Context.g_module, 'VERSION', '')
    145 			if ver:
    146 				app = "%s (%s)" % (app, ver)
    147 
    148 		params = {'now': time.ctime(), 'pyver': sys.hexversion, 'systype': sys.platform, 'args': " ".join(sys.argv), 'wafver': Context.WAFVERSION, 'abi': Context.ABI, 'app': app}
    149 		self.to_log(conf_template % params)
    150 		self.msg('Setting top to', self.srcnode.abspath())
    151 		self.msg('Setting out to', self.bldnode.abspath())
    152 
    153 		if id(self.srcnode) == id(self.bldnode):
    154 			Logs.warn('Setting top == out')
    155 		elif id(self.path) != id(self.srcnode):
    156 			if self.srcnode.is_child_of(self.path):
    157 				Logs.warn('Are you certain that you do not want to set top="." ?')
    158 
    159 		super(ConfigurationContext, self).execute()
    160 
    161 		self.store()
    162 
    163 		Context.top_dir = self.srcnode.abspath()
    164 		Context.out_dir = self.bldnode.abspath()
    165 
    166 		# this will write a configure lock so that subsequent builds will
    167 		# consider the current path as the root directory (see prepare_impl).
    168 		# to remove: use 'waf distclean'
    169 		env = ConfigSet.ConfigSet()
    170 		env.argv = sys.argv
    171 		env.options = Options.options.__dict__
    172 		env.config_cmd = self.cmd
    173 
    174 		env.run_dir = Context.run_dir
    175 		env.top_dir = Context.top_dir
    176 		env.out_dir = Context.out_dir
    177 
    178 		# conf.hash & conf.files hold wscript files paths and hash
    179 		# (used only by Configure.autoconfig)
    180 		env.hash = self.hash
    181 		env.files = self.files
    182 		env.environ = dict(self.environ)
    183 		env.launch_dir = Context.launch_dir
    184 
    185 		if not (self.env.NO_LOCK_IN_RUN or env.environ.get('NO_LOCK_IN_RUN') or getattr(Options.options, 'no_lock_in_run')):
    186 			env.store(os.path.join(Context.run_dir, Options.lockfile))
    187 		if not (self.env.NO_LOCK_IN_TOP or env.environ.get('NO_LOCK_IN_TOP') or getattr(Options.options, 'no_lock_in_top')):
    188 			env.store(os.path.join(Context.top_dir, Options.lockfile))
    189 		if not (self.env.NO_LOCK_IN_OUT or env.environ.get('NO_LOCK_IN_OUT') or getattr(Options.options, 'no_lock_in_out')):
    190 			env.store(os.path.join(Context.out_dir, Options.lockfile))
    191 
    192 	def prepare_env(self, env):
    193 		"""
    194 		Insert *PREFIX*, *BINDIR* and *LIBDIR* values into ``env``
    195 
    196 		:type env: :py:class:`waflib.ConfigSet.ConfigSet`
    197 		:param env: a ConfigSet, usually ``conf.env``
    198 		"""
    199 		if not env.PREFIX:
    200 			if Options.options.prefix or Utils.is_win32:
    201 				env.PREFIX = Options.options.prefix
    202 			else:
    203 				env.PREFIX = '/'
    204 		if not env.BINDIR:
    205 			if Options.options.bindir:
    206 				env.BINDIR = Options.options.bindir
    207 			else:
    208 				env.BINDIR = Utils.subst_vars('${PREFIX}/bin', env)
    209 		if not env.LIBDIR:
    210 			if Options.options.libdir:
    211 				env.LIBDIR = Options.options.libdir
    212 			else:
    213 				env.LIBDIR = Utils.subst_vars('${PREFIX}/lib%s' % Utils.lib64(), env)
    214 
    215 	def store(self):
    216 		"""Save the config results into the cache file"""
    217 		n = self.cachedir.make_node('build.config.py')
    218 		n.write('version = 0x%x\ntools = %r\n' % (Context.HEXVERSION, self.tools))
    219 
    220 		if not self.all_envs:
    221 			self.fatal('nothing to store in the configuration context!')
    222 
    223 		for key in self.all_envs:
    224 			tmpenv = self.all_envs[key]
    225 			tmpenv.store(os.path.join(self.cachedir.abspath(), key + Build.CACHE_SUFFIX))
    226 
    227 	def load(self, tool_list, tooldir=None, funs=None, with_sys_path=True, cache=False):
    228 		"""
    229 		Load Waf tools, which will be imported whenever a build is started.
    230 
    231 		:param tool_list: waf tools to import
    232 		:type tool_list: list of string
    233 		:param tooldir: paths for the imports
    234 		:type tooldir: list of string
    235 		:param funs: functions to execute from the waf tools
    236 		:type funs: list of string
    237 		:param cache: whether to prevent the tool from running twice
    238 		:type cache: bool
    239 		"""
    240 
    241 		tools = Utils.to_list(tool_list)
    242 		if tooldir:
    243 			tooldir = Utils.to_list(tooldir)
    244 		for tool in tools:
    245 			# avoid loading the same tool more than once with the same functions
    246 			# used by composite projects
    247 
    248 			if cache:
    249 				mag = (tool, id(self.env), tooldir, funs)
    250 				if mag in self.tool_cache:
    251 					self.to_log('(tool %s is already loaded, skipping)' % tool)
    252 					continue
    253 				self.tool_cache.append(mag)
    254 
    255 			module = None
    256 			try:
    257 				module = Context.load_tool(tool, tooldir, ctx=self, with_sys_path=with_sys_path)
    258 			except ImportError as e:
    259 				self.fatal('Could not load the Waf tool %r from %r\n%s' % (tool, getattr(e, 'waf_sys_path', sys.path), e))
    260 			except Exception as e:
    261 				self.to_log('imp %r (%r & %r)' % (tool, tooldir, funs))
    262 				self.to_log(traceback.format_exc())
    263 				raise
    264 
    265 			if funs is not None:
    266 				self.eval_rules(funs)
    267 			else:
    268 				func = getattr(module, 'configure', None)
    269 				if func:
    270 					if type(func) is type(Utils.readf):
    271 						func(self)
    272 					else:
    273 						self.eval_rules(func)
    274 
    275 			self.tools.append({'tool':tool, 'tooldir':tooldir, 'funs':funs})
    276 
    277 	def post_recurse(self, node):
    278 		"""
    279 		Records the path and a hash of the scripts visited, see :py:meth:`waflib.Context.Context.post_recurse`
    280 
    281 		:param node: script
    282 		:type node: :py:class:`waflib.Node.Node`
    283 		"""
    284 		super(ConfigurationContext, self).post_recurse(node)
    285 		self.hash = Utils.h_list((self.hash, node.read('rb')))
    286 		self.files.append(node.abspath())
    287 
    288 	def eval_rules(self, rules):
    289 		"""
    290 		Execute configuration tests provided as list of functions to run
    291 
    292 		:param rules: list of configuration method names
    293 		:type rules: list of string
    294 		"""
    295 		self.rules = Utils.to_list(rules)
    296 		for x in self.rules:
    297 			f = getattr(self, x)
    298 			if not f:
    299 				self.fatal('No such configuration function %r' % x)
    300 			f()
    301 
    302 def conf(f):
    303 	"""
    304 	Decorator: attach new configuration functions to :py:class:`waflib.Build.BuildContext` and
    305 	:py:class:`waflib.Configure.ConfigurationContext`. The methods bound will accept a parameter
    306 	named 'mandatory' to disable the configuration errors::
    307 
    308 		def configure(conf):
    309 			conf.find_program('abc', mandatory=False)
    310 
    311 	:param f: method to bind
    312 	:type f: function
    313 	"""
    314 	def fun(*k, **kw):
    315 		mandatory = kw.pop('mandatory', True)
    316 		try:
    317 			return f(*k, **kw)
    318 		except Errors.ConfigurationError:
    319 			if mandatory:
    320 				raise
    321 
    322 	fun.__name__ = f.__name__
    323 	setattr(ConfigurationContext, f.__name__, fun)
    324 	setattr(Build.BuildContext, f.__name__, fun)
    325 	return f
    326 
    327 @conf
    328 def add_os_flags(self, var, dest=None, dup=False):
    329 	"""
    330 	Import operating system environment values into ``conf.env`` dict::
    331 
    332 		def configure(conf):
    333 			conf.add_os_flags('CFLAGS')
    334 
    335 	:param var: variable to use
    336 	:type var: string
    337 	:param dest: destination variable, by default the same as var
    338 	:type dest: string
    339 	:param dup: add the same set of flags again
    340 	:type dup: bool
    341 	"""
    342 	try:
    343 		flags = shlex.split(self.environ[var])
    344 	except KeyError:
    345 		return
    346 	if dup or ''.join(flags) not in ''.join(Utils.to_list(self.env[dest or var])):
    347 		self.env.append_value(dest or var, flags)
    348 
    349 @conf
    350 def cmd_to_list(self, cmd):
    351 	"""
    352 	Detect if a command is written in pseudo shell like ``ccache g++`` and return a list.
    353 
    354 	:param cmd: command
    355 	:type cmd: a string or a list of string
    356 	"""
    357 	if isinstance(cmd, str):
    358 		if os.path.isfile(cmd):
    359 			# do not take any risk
    360 			return [cmd]
    361 		if os.sep == '/':
    362 			return shlex.split(cmd)
    363 		else:
    364 			try:
    365 				return shlex.split(cmd, posix=False)
    366 			except TypeError:
    367 				# Python 2.5 on windows?
    368 				return shlex.split(cmd)
    369 	return cmd
    370 
    371 @conf
    372 def check_waf_version(self, mini='1.9.99', maxi='2.1.0', **kw):
    373 	"""
    374 	Raise a Configuration error if the Waf version does not strictly match the given bounds::
    375 
    376 		conf.check_waf_version(mini='1.9.99', maxi='2.1.0')
    377 
    378 	:type  mini: number, tuple or string
    379 	:param mini: Minimum required version
    380 	:type  maxi: number, tuple or string
    381 	:param maxi: Maximum allowed version
    382 	"""
    383 	self.start_msg('Checking for waf version in %s-%s' % (str(mini), str(maxi)), **kw)
    384 	ver = Context.HEXVERSION
    385 	if Utils.num2ver(mini) > ver:
    386 		self.fatal('waf version should be at least %r (%r found)' % (Utils.num2ver(mini), ver))
    387 	if Utils.num2ver(maxi) < ver:
    388 		self.fatal('waf version should be at most %r (%r found)' % (Utils.num2ver(maxi), ver))
    389 	self.end_msg('ok', **kw)
    390 
    391 @conf
    392 def find_file(self, filename, path_list=[]):
    393 	"""
    394 	Find a file in a list of paths
    395 
    396 	:param filename: name of the file to search for
    397 	:param path_list: list of directories to search
    398 	:return: the first matching filename; else a configuration exception is raised
    399 	"""
    400 	for n in Utils.to_list(filename):
    401 		for d in Utils.to_list(path_list):
    402 			p = os.path.expanduser(os.path.join(d, n))
    403 			if os.path.exists(p):
    404 				return p
    405 	self.fatal('Could not find %r' % filename)
    406 
    407 @conf
    408 def find_program(self, filename, **kw):
    409 	"""
    410 	Search for a program on the operating system
    411 
    412 	When var is used, you may set os.environ[var] to help find a specific program version, for example::
    413 
    414 		$ CC='ccache gcc' waf configure
    415 
    416 	:param path_list: paths to use for searching
    417 	:type param_list: list of string
    418 	:param var: store the result to conf.env[var] where var defaults to filename.upper() if not provided; the result is stored as a list of strings
    419 	:type var: string
    420 	:param value: obtain the program from the value passed exclusively
    421 	:type value: list or string (list is preferred)
    422 	:param exts: list of extensions for the binary (do not add an extension for portability)
    423 	:type exts: list of string
    424 	:param msg: name to display in the log, by default filename is used
    425 	:type msg: string
    426 	:param interpreter: interpreter for the program
    427 	:type interpreter: ConfigSet variable key
    428 	:raises: :py:class:`waflib.Errors.ConfigurationError`
    429 	"""
    430 
    431 	exts = kw.get('exts', Utils.is_win32 and '.exe,.com,.bat,.cmd' or ',.sh,.pl,.py')
    432 
    433 	environ = kw.get('environ', getattr(self, 'environ', os.environ))
    434 
    435 	ret = ''
    436 
    437 	filename = Utils.to_list(filename)
    438 	msg = kw.get('msg', ', '.join(filename))
    439 
    440 	var = kw.get('var', '')
    441 	if not var:
    442 		var = re.sub(r'\W', '_', filename[0].upper())
    443 
    444 	path_list = kw.get('path_list', '')
    445 	if path_list:
    446 		path_list = Utils.to_list(path_list)
    447 	else:
    448 		path_list = environ.get('PATH', '').split(os.pathsep)
    449 
    450 	if kw.get('value'):
    451 		# user-provided in command-line options and passed to find_program
    452 		ret = self.cmd_to_list(kw['value'])
    453 	elif environ.get(var):
    454 		# user-provided in the os environment
    455 		ret = self.cmd_to_list(environ[var])
    456 	elif self.env[var]:
    457 		# a default option in the wscript file
    458 		ret = self.cmd_to_list(self.env[var])
    459 	else:
    460 		if not ret:
    461 			ret = self.find_binary(filename, exts.split(','), path_list)
    462 		if not ret and Utils.winreg:
    463 			ret = Utils.get_registry_app_path(Utils.winreg.HKEY_CURRENT_USER, filename)
    464 		if not ret and Utils.winreg:
    465 			ret = Utils.get_registry_app_path(Utils.winreg.HKEY_LOCAL_MACHINE, filename)
    466 		ret = self.cmd_to_list(ret)
    467 
    468 	if ret:
    469 		if len(ret) == 1:
    470 			retmsg = ret[0]
    471 		else:
    472 			retmsg = ret
    473 	else:
    474 		retmsg = False
    475 
    476 	self.msg('Checking for program %r' % msg, retmsg, **kw)
    477 	if not kw.get('quiet'):
    478 		self.to_log('find program=%r paths=%r var=%r -> %r' % (filename, path_list, var, ret))
    479 
    480 	if not ret:
    481 		self.fatal(kw.get('errmsg', '') or 'Could not find the program %r' % filename)
    482 
    483 	interpreter = kw.get('interpreter')
    484 	if interpreter is None:
    485 		if not Utils.check_exe(ret[0], env=environ):
    486 			self.fatal('Program %r is not executable' % ret)
    487 		self.env[var] = ret
    488 	else:
    489 		self.env[var] = self.env[interpreter] + ret
    490 
    491 	return ret
    492 
    493 @conf
    494 def find_binary(self, filenames, exts, paths):
    495 	for f in filenames:
    496 		for ext in exts:
    497 			exe_name = f + ext
    498 			if os.path.isabs(exe_name):
    499 				if os.path.isfile(exe_name):
    500 					return exe_name
    501 			else:
    502 				for path in paths:
    503 					x = os.path.expanduser(os.path.join(path, exe_name))
    504 					if os.path.isfile(x):
    505 						return x
    506 	return None
    507 
    508 @conf
    509 def run_build(self, *k, **kw):
    510 	"""
    511 	Create a temporary build context to execute a build. A temporary reference to that build
    512 	context is kept on self.test_bld for debugging purposes.
    513 	The arguments to this function are passed to a single task generator for that build.
    514 	Only three parameters are mandatory:
    515 
    516 	:param features: features to pass to a task generator created in the build
    517 	:type features: list of string
    518 	:param compile_filename: file to create for the compilation (default: *test.c*)
    519 	:type compile_filename: string
    520 	:param code: input file contents
    521 	:type code: string
    522 
    523 	Though this function returns *0* by default, the build may bind attribute named *retval* on the
    524 	build context object to return a particular value. See :py:func:`waflib.Tools.c_config.test_exec_fun` for example.
    525 
    526 	The temporary builds creates a temporary folder; the name of that folder is calculated
    527 	by hashing input arguments to this function, with the exception of :py:class:`waflib.ConfigSet.ConfigSet`
    528 	objects which are used for both reading and writing values.
    529 
    530 	This function also features a cache which is disabled by default; that cache relies
    531 	on the hash value calculated as indicated above::
    532 
    533 		def options(opt):
    534 			opt.add_option('--confcache', dest='confcache', default=0,
    535 				action='count', help='Use a configuration cache')
    536 
    537 	And execute the configuration with the following command-line::
    538 
    539 		$ waf configure --confcache
    540 
    541 	"""
    542 	buf = []
    543 	for key in sorted(kw.keys()):
    544 		v = kw[key]
    545 		if isinstance(v, ConfigSet.ConfigSet):
    546 			# values are being written to, so they are excluded from contributing to the hash
    547 			continue
    548 		elif hasattr(v, '__call__'):
    549 			buf.append(Utils.h_fun(v))
    550 		else:
    551 			buf.append(str(v))
    552 	h = Utils.h_list(buf)
    553 	dir = self.bldnode.abspath() + os.sep + (not Utils.is_win32 and '.' or '') + 'conf_check_' + Utils.to_hex(h)
    554 
    555 	cachemode = kw.get('confcache', getattr(Options.options, 'confcache', None))
    556 
    557 	if not cachemode and os.path.exists(dir):
    558 		shutil.rmtree(dir)
    559 
    560 	try:
    561 		os.makedirs(dir)
    562 	except OSError:
    563 		pass
    564 
    565 	try:
    566 		os.stat(dir)
    567 	except OSError:
    568 		self.fatal('cannot use the configuration test folder %r' % dir)
    569 
    570 	if cachemode == 1:
    571 		try:
    572 			proj = ConfigSet.ConfigSet(os.path.join(dir, 'cache_run_build'))
    573 		except EnvironmentError:
    574 			pass
    575 		else:
    576 			ret = proj['cache_run_build']
    577 			if isinstance(ret, str) and ret.startswith('Test does not build'):
    578 				self.fatal(ret)
    579 			return ret
    580 
    581 	bdir = os.path.join(dir, 'testbuild')
    582 
    583 	if not os.path.exists(bdir):
    584 		os.makedirs(bdir)
    585 
    586 	cls_name = kw.get('run_build_cls') or getattr(self, 'run_build_cls', 'build')
    587 	self.test_bld = bld = Context.create_context(cls_name, top_dir=dir, out_dir=bdir)
    588 	bld.init_dirs()
    589 	bld.progress_bar = 0
    590 	bld.targets = '*'
    591 
    592 	bld.logger = self.logger
    593 	bld.all_envs.update(self.all_envs) # not really necessary
    594 	bld.env = kw['env']
    595 
    596 	bld.kw = kw
    597 	bld.conf = self
    598 	ret = -1
    599 	try:
    600 		kw['build_fun'](bld)
    601 		try:
    602 			bld.compile()
    603 		except Errors.WafError:
    604 			ret = 'Test does not build: %s' % traceback.format_exc()
    605 			self.fatal(ret)
    606 		else:
    607 			ret = getattr(bld, 'retval', 0)
    608 	finally:
    609 		if cachemode:
    610 			# cache the results each time
    611 			proj = ConfigSet.ConfigSet()
    612 			proj['cache_run_build'] = ret
    613 			proj.store(os.path.join(dir, 'cache_run_build'))
    614 		else:
    615 			shutil.rmtree(dir)
    616 	return ret
    617 
    618 @conf
    619 def ret_msg(self, msg, args):
    620 	if isinstance(msg, str):
    621 		return msg
    622 	return msg(args)
    623 
    624 @conf
    625 def test(self, *k, **kw):
    626 
    627 	if not 'env' in kw:
    628 		kw['env'] = self.env.derive()
    629 
    630 	# validate_c for example
    631 	if kw.get('validate'):
    632 		kw['validate'](kw)
    633 
    634 	self.start_msg(kw['msg'], **kw)
    635 	ret = None
    636 	try:
    637 		ret = self.run_build(*k, **kw)
    638 	except self.errors.ConfigurationError:
    639 		self.end_msg(kw['errmsg'], 'YELLOW', **kw)
    640 		if Logs.verbose > 1:
    641 			raise
    642 		else:
    643 			self.fatal('The configuration failed')
    644 	else:
    645 		kw['success'] = ret
    646 
    647 	if kw.get('post_check'):
    648 		ret = kw['post_check'](kw)
    649 
    650 	if ret:
    651 		self.end_msg(kw['errmsg'], 'YELLOW', **kw)
    652 		self.fatal('The configuration failed %r' % ret)
    653 	else:
    654 		self.end_msg(self.ret_msg(kw['okmsg'], kw), **kw)
    655 	return ret
    656