mirror of
https://gitlab.com/ita1024/waf.git
synced 2024-11-22 09:57:15 +01:00
conf.check generalization using arbitrary build functions
This commit is contained in:
parent
08c4b175bf
commit
d491de7486
@ -1,6 +1,6 @@
|
||||
#! /usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# Thomas Nagy, 2005, 2010 (ita)
|
||||
# Thomas Nagy, 2005, 2014 (ita)
|
||||
|
||||
VERSION='1.0.0'
|
||||
APPNAME='tex_test'
|
||||
@ -15,6 +15,15 @@ def configure(conf):
|
||||
if not conf.env.MAKEGLOSSARIES:
|
||||
conf.fatal('could not find the program makeglossaries which is absolutely required for this example')
|
||||
|
||||
|
||||
# and example of a complex configuration test
|
||||
def build_latex_test(bld):
|
||||
def write_tex(tsk):
|
||||
tsk.outputs[0].write(r'''\documentclass[a4paper,12pt]{article} \usepackage{ucs} \begin{document} test \end{document} ''')
|
||||
bld(rule=write_tex, target='main.tex')
|
||||
bld(features='tex', type='pdflatex', source='main.tex', prompt=0)
|
||||
conf.test(build_fun=build_latex_test, msg='Checking for UCS', okmsg='ok', errmsg='ucs.sty is missing install latex-extras')
|
||||
|
||||
def build(bld):
|
||||
bld.recurse('src')
|
||||
|
||||
|
@ -68,7 +68,7 @@ image::classes_build{PIC}["Build classes"{backend@docbook:,width=500:},align="ce
|
||||
|
||||
==== Context commands and recursion
|
||||
|
||||
The context commands are designed to be as independent as possible, and may be executed concurrently. The main application is the execution of small builds as part of configuration tests. For example, the method 'waflib.Tools.c_config.run_c_code' creates a private build context internally to perform the tests.
|
||||
The context commands are designed to be as independent as possible, and may be executed concurrently. The main application is the execution of small builds as part of configuration tests. For example, the method 'waflib.Configure.run_build' creates a private build context internally to perform the tests.
|
||||
Here is an example of a build that creates and executes simple configuration contexts concurrently:
|
||||
|
||||
// architecture_link
|
||||
|
@ -493,10 +493,6 @@ Configuration methods
|
||||
|
||||
* ret_msg_
|
||||
|
||||
.. _run_c_code: tools/c_config.html#waflib.Tools.c_config.run_c_code
|
||||
|
||||
* run_c_code_
|
||||
|
||||
.. _scc_common_flags: tools/suncc.html#waflib.Tools.suncc.scc_common_flags
|
||||
|
||||
* scc_common_flags_
|
||||
|
@ -12,7 +12,7 @@ A :py:class:`waflib.Configure.ConfigurationContext` instance is created when ``w
|
||||
* hold configuration routines such as ``find_program``, etc
|
||||
"""
|
||||
|
||||
import os, shlex, sys, time, re
|
||||
import os, shlex, sys, time, re, shutil
|
||||
from waflib import ConfigSet, Utils, Options, Logs, Context, Build, Errors
|
||||
|
||||
try:
|
||||
@ -571,3 +571,143 @@ def find_binary(self, filenames, exts, paths):
|
||||
return x
|
||||
return None
|
||||
|
||||
|
||||
@conf
|
||||
def run_build(self, *k, **kw):
|
||||
"""
|
||||
Create a temporary build context to execute a build. A reference to that build
|
||||
context is kept on self.test_bld for debugging purposes, and you should not rely
|
||||
on it too much (read the note on the cache below).
|
||||
The parameters given in the arguments to this function are passed as arguments for
|
||||
a single task generator created in the build. Only three parameters are obligatory:
|
||||
|
||||
:param features: features to pass to a task generator created in the build
|
||||
:type features: list of string
|
||||
:param compile_filename: file to create for the compilation (default: *test.c*)
|
||||
:type compile_filename: string
|
||||
:param code: code to write in the filename to compile
|
||||
:type code: string
|
||||
|
||||
Though this function returns *0* by default, the build may set an attribute named *retval* on the
|
||||
build context object to return a particular value. See :py:func:`waflib.Tools.c_config.test_exec_fun` for example.
|
||||
|
||||
This function also provides a limited cache. To use it, provide the following option::
|
||||
|
||||
def options(opt):
|
||||
opt.add_option('--confcache', dest='confcache', default=0,
|
||||
action='count', help='Use a configuration cache')
|
||||
|
||||
And execute the configuration with the following command-line::
|
||||
|
||||
$ waf configure --confcache
|
||||
|
||||
"""
|
||||
|
||||
lst = [str(v) for (p, v) in kw.items() if p != 'env']
|
||||
h = Utils.h_list(lst)
|
||||
dir = self.bldnode.abspath() + os.sep + (not Utils.is_win32 and '.' or '') + 'conf_check_' + Utils.to_hex(h)
|
||||
|
||||
try:
|
||||
os.makedirs(dir)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
try:
|
||||
os.stat(dir)
|
||||
except OSError:
|
||||
self.fatal('cannot use the configuration test folder %r' % dir)
|
||||
|
||||
cachemode = getattr(Options.options, 'confcache', None)
|
||||
if cachemode == 1:
|
||||
try:
|
||||
proj = ConfigSet.ConfigSet(os.path.join(dir, 'cache_run_build'))
|
||||
except OSError:
|
||||
pass
|
||||
except IOError:
|
||||
pass
|
||||
else:
|
||||
ret = proj['cache_run_build']
|
||||
if isinstance(ret, str) and ret.startswith('Test does not build'):
|
||||
self.fatal(ret)
|
||||
return ret
|
||||
|
||||
bdir = os.path.join(dir, 'testbuild')
|
||||
|
||||
if not os.path.exists(bdir):
|
||||
os.makedirs(bdir)
|
||||
|
||||
self.test_bld = bld = Build.BuildContext(top_dir=dir, out_dir=bdir)
|
||||
bld.init_dirs()
|
||||
bld.progress_bar = 0
|
||||
bld.targets = '*'
|
||||
|
||||
bld.logger = self.logger
|
||||
bld.all_envs.update(self.all_envs) # not really necessary
|
||||
bld.env = kw['env']
|
||||
|
||||
# OMG huge hack
|
||||
bld.kw = kw
|
||||
bld.conf = self
|
||||
kw['build_fun'](bld)
|
||||
|
||||
ret = -1
|
||||
try:
|
||||
try:
|
||||
bld.compile()
|
||||
except Errors.WafError:
|
||||
ret = 'Test does not build: %s' % Utils.ex_stack()
|
||||
self.fatal(ret)
|
||||
else:
|
||||
ret = getattr(bld, 'retval', 0)
|
||||
finally:
|
||||
if cachemode == 1:
|
||||
# cache the results each time
|
||||
proj = ConfigSet.ConfigSet()
|
||||
proj['cache_run_build'] = ret
|
||||
proj.store(os.path.join(dir, 'cache_run_build'))
|
||||
else:
|
||||
shutil.rmtree(dir)
|
||||
|
||||
return ret
|
||||
|
||||
@conf
|
||||
def ret_msg(self, msg, args):
|
||||
if isinstance(msg, str):
|
||||
return msg
|
||||
return msg(args)
|
||||
|
||||
@conf
|
||||
def test(self, *k, **kw):
|
||||
|
||||
if not 'env' in kw:
|
||||
kw['env'] = self.env.derive()
|
||||
|
||||
# validate_c for example
|
||||
if kw.get('validate', None):
|
||||
kw['validate'](kw)
|
||||
|
||||
self.start_msg(kw['msg'], **kw)
|
||||
ret = None
|
||||
try:
|
||||
ret = self.run_build(*k, **kw)
|
||||
except self.errors.ConfigurationError:
|
||||
self.end_msg(kw['errmsg'], 'YELLOW', **kw)
|
||||
if Logs.verbose > 1:
|
||||
raise
|
||||
else:
|
||||
self.fatal('The configuration failed')
|
||||
else:
|
||||
kw['success'] = ret
|
||||
|
||||
if kw.get('post_check', None):
|
||||
ret = kw['post_check'](kw)
|
||||
|
||||
if ret:
|
||||
self.end_msg(kw['errmsg'], 'YELLOW', **kw)
|
||||
self.fatal('The configuration failed %r' % ret)
|
||||
else:
|
||||
self.end_msg(self.ret_msg(kw['okmsg'], kw), **kw)
|
||||
return ret
|
||||
|
||||
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
C/C++/D configuration helpers
|
||||
"""
|
||||
|
||||
import os, re, shlex, shutil, sys
|
||||
import os, re, shlex, sys
|
||||
from waflib import Build, Utils, Task, Options, Logs, Errors, ConfigSet, Runner
|
||||
from waflib.TaskGen import after_method, feature
|
||||
from waflib.Configure import conf
|
||||
@ -196,12 +196,6 @@ def parse_flags(self, line, uselib_store, env=None, force_static=False, posix=No
|
||||
elif x.endswith('.a') or x.endswith('.so') or x.endswith('.dylib') or x.endswith('.lib'):
|
||||
appu('LINKFLAGS_' + uselib, [x]) # not cool, #762
|
||||
|
||||
@conf
|
||||
def ret_msg(self, f, kw):
|
||||
if isinstance(f, str):
|
||||
return f
|
||||
return f(kw)
|
||||
|
||||
@conf
|
||||
def validate_cfg(self, kw):
|
||||
"""
|
||||
@ -404,10 +398,23 @@ def check_cfg(self, *k, **kw):
|
||||
|
||||
return ret
|
||||
|
||||
def build_fun(bld):
|
||||
if bld.kw['compile_filename']:
|
||||
node = bld.srcnode.make_node(bld.kw['compile_filename'])
|
||||
node.write(bld.kw['code'])
|
||||
|
||||
o = bld(features=bld.kw['features'], source=bld.kw['compile_filename'], target='testprog')
|
||||
|
||||
for k, v in bld.kw.items():
|
||||
setattr(o, k, v)
|
||||
|
||||
if not bld.kw.get('quiet', None):
|
||||
bld.conf.to_log("==>\n%s\n<==" % bld.kw['code'])
|
||||
|
||||
@conf
|
||||
def validate_c(self, kw):
|
||||
"""
|
||||
pre-check the parameters that will be given to run_c_code
|
||||
pre-check the parameters that will be given to :py:func:`waflib.Configure.run_build`
|
||||
|
||||
:param compiler: c or cxx (tries to guess what is best)
|
||||
:type compiler: string
|
||||
@ -433,6 +440,9 @@ def validate_c(self, kw):
|
||||
:type auto_add_header_name: bool
|
||||
"""
|
||||
|
||||
if not 'build_fun' in kw:
|
||||
kw['build_fun'] = build_fun
|
||||
|
||||
if not 'env' in kw:
|
||||
kw['env'] = self.env.derive()
|
||||
env = kw['env']
|
||||
@ -634,15 +644,15 @@ def post_check(self, *k, **kw):
|
||||
@conf
|
||||
def check(self, *k, **kw):
|
||||
"""
|
||||
Perform a configuration test by calling :py:func:`waflib.Tools.c_config.run_c_code`.
|
||||
Perform a configuration test by calling :py:func:`waflib.Configure.run_build`.
|
||||
For the complete list of parameters, see :py:func:`waflib.Tools.c_config.validate_c`.
|
||||
To force a specific compiler, prefer the methods :py:func:`waflib.Tools.c_config.check_cxx` or :py:func:`waflib.Tools.c_config.check_cc`
|
||||
To force a specific compiler, pass "compiler='c'" or "compiler='cxx'" in the arguments
|
||||
"""
|
||||
self.validate_c(kw)
|
||||
self.start_msg(kw['msg'], **kw)
|
||||
ret = None
|
||||
try:
|
||||
ret = self.run_c_code(*k, **kw)
|
||||
ret = self.run_build(*k, **kw)
|
||||
except self.errors.ConfigurationError:
|
||||
self.end_msg(kw['errmsg'], 'YELLOW', **kw)
|
||||
if Logs.verbose > 1:
|
||||
@ -695,130 +705,15 @@ def test_exec_fun(self):
|
||||
"""
|
||||
self.create_task('test_exec', self.link_task.outputs[0])
|
||||
|
||||
CACHE_RESULTS = 1
|
||||
COMPILE_ERRORS = 2
|
||||
|
||||
@conf
|
||||
def run_c_code(self, *k, **kw):
|
||||
"""
|
||||
Create a temporary build context to execute a build. A reference to that build
|
||||
context is kept on self.test_bld for debugging purposes, and you should not rely
|
||||
on it too much (read the note on the cache below).
|
||||
The parameters given in the arguments to this function are passed as arguments for
|
||||
a single task generator created in the build. Only three parameters are obligatory:
|
||||
|
||||
:param features: features to pass to a task generator created in the build
|
||||
:type features: list of string
|
||||
:param compile_filename: file to create for the compilation (default: *test.c*)
|
||||
:type compile_filename: string
|
||||
:param code: code to write in the filename to compile
|
||||
:type code: string
|
||||
|
||||
Though this function returns *0* by default, the build may set an attribute named *retval* on the
|
||||
build context object to return a particular value. See :py:func:`waflib.Tools.c_config.test_exec_fun` for example.
|
||||
|
||||
This function also provides a limited cache. To use it, provide the following option::
|
||||
|
||||
def options(opt):
|
||||
opt.add_option('--confcache', dest='confcache', default=0,
|
||||
action='count', help='Use a configuration cache')
|
||||
|
||||
And execute the configuration with the following command-line::
|
||||
|
||||
$ waf configure --confcache
|
||||
|
||||
"""
|
||||
|
||||
lst = [str(v) for (p, v) in kw.items() if p != 'env']
|
||||
h = Utils.h_list(lst)
|
||||
dir = self.bldnode.abspath() + os.sep + (not Utils.is_win32 and '.' or '') + 'conf_check_' + Utils.to_hex(h)
|
||||
|
||||
try:
|
||||
os.makedirs(dir)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
try:
|
||||
os.stat(dir)
|
||||
except OSError:
|
||||
self.fatal('cannot use the configuration test folder %r' % dir)
|
||||
|
||||
cachemode = getattr(Options.options, 'confcache', None)
|
||||
if cachemode == CACHE_RESULTS:
|
||||
try:
|
||||
proj = ConfigSet.ConfigSet(os.path.join(dir, 'cache_run_c_code'))
|
||||
except OSError:
|
||||
pass
|
||||
except IOError:
|
||||
pass
|
||||
else:
|
||||
ret = proj['cache_run_c_code']
|
||||
if isinstance(ret, str) and ret.startswith('Test does not build'):
|
||||
self.fatal(ret)
|
||||
return ret
|
||||
|
||||
bdir = os.path.join(dir, 'testbuild')
|
||||
|
||||
if not os.path.exists(bdir):
|
||||
os.makedirs(bdir)
|
||||
|
||||
self.test_bld = bld = Build.BuildContext(top_dir=dir, out_dir=bdir)
|
||||
bld.init_dirs()
|
||||
bld.progress_bar = 0
|
||||
bld.targets = '*'
|
||||
|
||||
if kw['compile_filename']:
|
||||
node = bld.srcnode.make_node(kw['compile_filename'])
|
||||
node.write(kw['code'])
|
||||
|
||||
bld.logger = self.logger
|
||||
bld.all_envs.update(self.all_envs) # not really necessary
|
||||
bld.env = kw['env']
|
||||
|
||||
o = bld(features=kw['features'], source=kw['compile_filename'], target='testprog')
|
||||
|
||||
for k, v in kw.items():
|
||||
setattr(o, k, v)
|
||||
|
||||
if not kw.get('quiet', None):
|
||||
self.to_log("==>\n%s\n<==" % kw['code'])
|
||||
|
||||
# compile the program
|
||||
bld.targets = '*'
|
||||
|
||||
ret = -1
|
||||
try:
|
||||
try:
|
||||
bld.compile()
|
||||
except Errors.WafError:
|
||||
ret = 'Test does not build: %s' % Utils.ex_stack()
|
||||
self.fatal(ret)
|
||||
else:
|
||||
ret = getattr(bld, 'retval', 0)
|
||||
finally:
|
||||
if cachemode == CACHE_RESULTS:
|
||||
# cache the results each time
|
||||
proj = ConfigSet.ConfigSet()
|
||||
proj['cache_run_c_code'] = ret
|
||||
proj.store(os.path.join(dir, 'cache_run_c_code'))
|
||||
else:
|
||||
shutil.rmtree(dir)
|
||||
|
||||
return ret
|
||||
|
||||
@conf
|
||||
def check_cxx(self, *k, **kw):
|
||||
"""
|
||||
Same as :py:func:`waflib.Tools.c_config.check` but default to the *c++* programming language
|
||||
"""
|
||||
# DO NOT USE
|
||||
kw['compiler'] = 'cxx'
|
||||
return self.check(*k, **kw)
|
||||
|
||||
@conf
|
||||
def check_cc(self, *k, **kw):
|
||||
"""
|
||||
Same as :py:func:`waflib.Tools.c_config.check` but default to the *c* programming language
|
||||
"""
|
||||
# DO NOT USE
|
||||
kw['compiler'] = 'c'
|
||||
return self.check(*k, **kw)
|
||||
|
||||
|
@ -37,7 +37,7 @@ int main(int argc, char **argv) {
|
||||
@before_method('process_source')
|
||||
def link_lib_test_fun(self):
|
||||
"""
|
||||
The configuration test :py:func:`waflib.Tools.ccroot.run_c_code` declares a unique task generator,
|
||||
The configuration test :py:func:`waflib.Configure.run_build` declares a unique task generator,
|
||||
so we need to create other task generators from here to check if the linker is able to link libraries.
|
||||
"""
|
||||
def write_test_file(task):
|
||||
|
Loading…
Reference in New Issue
Block a user